Browse Source

updated header dependencies in Makefile, clean up of shadow mapping,
integration of server / client network, base for GUIs in client, test start menu
GUI

Kajetan Johannes Hammerle 4 years ago
parent
commit
36414bab65

+ 3 - 0
.gitignore

@@ -3,3 +3,6 @@ game_client
 game_server
 *.o
 LineCounter.jar
+test
+README
+start.sh

+ 3 - 0
MainServer.cpp

@@ -1,9 +1,12 @@
 #include <iostream>
+#include "server/GameServer.h"
 
 using namespace std;
 
 int main(int argc, char** argv)
 {
+    GameServer server;
+    server.start(25565, 10);
     return 0;
 }
 

+ 93 - 35
Makefile

@@ -2,22 +2,32 @@ VERSION = -std=c++14
 CFLAGS = $(shell pkg-config --cflags glfw3)
 LDFLAGS = $(shell pkg-config --static --libs glfw3) -lGL -lGLEW -lpng
 
-all: run_client
+all: game_client game_server
+
+test_client: game_client
+	optirun ./game_client
 
 run_client: game_client
 	#vblank_mode=0 optirun ./game_client
 	optirun ./game_client
-	
+
 game_client: MainClient.cpp\
 	Clock.o DirectRenderer.o KeyManager.o Mesh.o MouseManager.o Shader.o\
 	Texture.o Utils.o Wrapper.o ShaderProgram.o WorldShader.o FramebufferRectangle.o\
-	SSAOShader.o SSAOBlurShader.o WorldPostShader.o OverlayShader.o WorldShadowShader.o\
+	SSAOShader.o SSAOBlurShader.o WorldPostShader.o OverlayShader.o\
 	Matrix3D.o Matrix3DStack.o StackOverflow.o StackUnderflow.o Vector3D.o Plane3D.o Camera3D.o\
 	Client.o\
 	Block.o Blocks.o BlockAir.o\
-	Face.o\
+	Face.o GUI.o StartMenu.o\
 	Chunk.o World.o ChunkRenderer.o ClientChunkProvider.o BlockRenderer.o BlockRenderers.o EntityRenderer.o
-	g++ $(VERSION) -o $@ MainClient.cpp *.o $(LDFLAGS)
+	g++ $(VERSION) -o $@ MainClient.cpp Clock.o DirectRenderer.o KeyManager.o Mesh.o MouseManager.o Shader.o\
+		Texture.o Utils.o Wrapper.o ShaderProgram.o WorldShader.o FramebufferRectangle.o\
+		SSAOShader.o SSAOBlurShader.o WorldPostShader.o OverlayShader.o\
+		Matrix3D.o Matrix3DStack.o StackOverflow.o StackUnderflow.o Vector3D.o Plane3D.o Camera3D.o\
+		Client.o\
+		Block.o Blocks.o BlockAir.o\
+		Face.o GUI.o StartMenu.o\
+		Chunk.o World.o ChunkRenderer.o ClientChunkProvider.o BlockRenderer.o BlockRenderers.o EntityRenderer.o $(LDFLAGS)
 
 # ------------------------------------------------------------------------------	
 # Engine
@@ -26,7 +36,8 @@ game_client: MainClient.cpp\
 Clock.o: engine/Clock.cpp engine/Clock.h
 	g++ $(VERSION) -c engine/Clock.cpp -o $@
 
-DirectRenderer.o: engine/DirectRenderer.cpp engine/DirectRenderer.h
+DirectRenderer.o: engine/DirectRenderer.cpp engine/DirectRenderer.h\
+	math/Matrix3D.h engine/Texture.h engine/Utils.h engine/Wrapper.h
 	g++ $(VERSION) -c engine/DirectRenderer.cpp -o $@
 	
 KeyManager.o: engine/KeyManager.cpp engine/KeyManager.h
@@ -38,7 +49,9 @@ Mesh.o: engine/Mesh.cpp engine/Mesh.h
 MouseManager.o: engine/MouseManager.cpp engine/MouseManager.h
 	g++ $(VERSION) -c engine/MouseManager.cpp -o $@
 	
-Shader.o: engine/Shader.cpp engine/Shader.h
+Shader.o: engine/Shader.cpp engine/Shader.h\
+	math/Plane3D.h math/Vector3D.h math/Matrix3D.h math/Matrix3DStack.h\
+	engine/Utils.h engine/Wrapper.h
 	g++ $(VERSION) -c engine/Shader.cpp -o $@
 	
 Texture.o: engine/Texture.cpp engine/Texture.h
@@ -47,55 +60,80 @@ Texture.o: engine/Texture.cpp engine/Texture.h
 Utils.o: engine/Utils.cpp engine/Utils.h
 	g++ $(VERSION) -c engine/Utils.cpp -o $@
 	
-Wrapper.o: engine/Wrapper.cpp engine/Wrapper.h
+Wrapper.o: engine/Wrapper.cpp engine/Wrapper.h\
+	engine/shader/ShaderProgram.h math/Vector3D.h math/Matrix3D.h\
+	engine/shader/WorldShader.h engine/Shader.h\
+	engine/shader/SSAOShader.h engine/shader/SSAOBlurShader.h\
+	engine/shader/FramebufferRectangle.h engine/shader/WorldPostShader.h\
+	engine/shader/OverlayShader.h engine/Mesh.h
 	g++ $(VERSION) -c engine/Wrapper.cpp -o $@
 	
 ShaderProgram.o: engine/shader/ShaderProgram.cpp engine/shader/ShaderProgram.h
 	g++ $(VERSION) -c engine/shader/ShaderProgram.cpp -o $@
 	
-WorldShader.o: engine/shader/WorldShader.cpp engine/shader/WorldShader.h
+WorldShader.o: engine/shader/WorldShader.cpp engine/shader/WorldShader.h\
+	engine/shader/ShaderProgram.h engine/Wrapper.h
 	g++ $(VERSION) -c engine/shader/WorldShader.cpp -o $@
 	
-FramebufferRectangle.o: engine/shader/FramebufferRectangle.cpp engine/shader/FramebufferRectangle.h
+FramebufferRectangle.o: engine/shader/FramebufferRectangle.cpp engine/shader/FramebufferRectangle.h\
+	engine/Wrapper.h
 	g++ $(VERSION) -c engine/shader/FramebufferRectangle.cpp -o $@
 	
-SSAOShader.o: engine/shader/SSAOShader.cpp engine/shader/SSAOShader.h
+SSAOShader.o: engine/shader/SSAOShader.cpp engine/shader/SSAOShader.h\
+	engine/shader/ShaderProgram.h engine/Wrapper.h
 	g++ $(VERSION) -c engine/shader/SSAOShader.cpp -o $@
 	
-SSAOBlurShader.o: engine/shader/SSAOBlurShader.cpp engine/shader/SSAOBlurShader.h
+SSAOBlurShader.o: engine/shader/SSAOBlurShader.cpp engine/shader/SSAOBlurShader.h\
+	engine/shader/ShaderProgram.h engine/Wrapper.h
 	g++ $(VERSION) -c engine/shader/SSAOBlurShader.cpp -o $@
 	
-WorldPostShader.o: engine/shader/WorldPostShader.cpp engine/shader/WorldPostShader.h
+WorldPostShader.o: engine/shader/WorldPostShader.cpp engine/shader/WorldPostShader.h\
+	engine/shader/ShaderProgram.h engine/Wrapper.h
 	g++ $(VERSION) -c engine/shader/WorldPostShader.cpp -o $@
 	
-OverlayShader.o: engine/shader/OverlayShader.cpp engine/shader/OverlayShader.h
+OverlayShader.o: engine/shader/OverlayShader.cpp engine/shader/OverlayShader.h\
+	engine/shader/ShaderProgram.h math/Matrix3D.h engine/Wrapper.h
 	g++ $(VERSION) -c engine/shader/OverlayShader.cpp -o $@
 	
-WorldShadowShader.o: engine/shader/WorldShadowShader.cpp engine/shader/WorldShadowShader.h
-	g++ $(VERSION) -c engine/shader/WorldShadowShader.cpp -o $@
-	
 # ------------------------------------------------------------------------------	
 # Client
 # ------------------------------------------------------------------------------
 	
-Client.o: client/Client.h client/Client.cpp
+Client.o: client/Client.h client/Client.cpp\
+	engine/KeyManager.h engine/MouseManager.h engine/Clock.h\
+	engine/Shader.h engine/DirectRenderer.h\
+	client/rendering/gui/GUIs.h client/rendering/gui/GUI.h client/rendering/gui/StartMenu.h
 	g++ $(VERSION) -c client/Client.cpp -o $@
 	
-ChunkRenderer.o: client/rendering/ChunkRenderer.h client/rendering/ChunkRenderer.cpp world/IChunkListener.h
+ChunkRenderer.o: client/rendering/ChunkRenderer.h client/rendering/ChunkRenderer.cpp world/IChunkListener.h\
+	client/rendering/block/BlockRenderers.h client/rendering/block/BlockRenderer.h\
+	engine/Mesh.h engine/Shader.h engine/Texture.h engine/DirectRenderer.h\
+	world/IChunkListener.h math/Camera3D.h
 	g++ $(VERSION) -c client/rendering/ChunkRenderer.cpp -o $@
-	
-ClientChunkProvider.o: client/rendering/ClientChunkProvider.h client/rendering/ClientChunkProvider.cpp world/IChunkProvider.h
+		
+ClientChunkProvider.o: client/rendering/ClientChunkProvider.h client/rendering/ClientChunkProvider.cpp world/IChunkProvider.h\
+	world/IChunkProvider.h
 	g++ $(VERSION) -c client/rendering/ClientChunkProvider.cpp -o $@
 	
-BlockRenderer.o: client/rendering/block/BlockRenderer.h client/rendering/block/BlockRenderer.cpp
+BlockRenderer.o: client/rendering/block/BlockRenderer.h client/rendering/block/BlockRenderer.cpp engine/Mesh.h utils/Face.h
 	g++ $(VERSION) -c client/rendering/block/BlockRenderer.cpp -o $@
 	
-BlockRenderers.o: client/rendering/block/BlockRenderers.h client/rendering/block/BlockRenderers.cpp
+BlockRenderers.o: client/rendering/block/BlockRenderers.h client/rendering/block/BlockRenderers.cpp block/Block.h client/rendering/block/BlockRenderer.h
 	g++ $(VERSION) -c client/rendering/block/BlockRenderers.cpp -o $@
 	
-EntityRenderer.o: client/rendering/entity/EntityRenderer.h client/rendering/entity/EntityRenderer.cpp
+EntityRenderer.o: client/rendering/entity/EntityRenderer.h client/rendering/entity/EntityRenderer.cpp\
+	engine/Shader.h math/Camera3D.h engine/DirectRenderer.h engine/Mesh.h\
+	engine/Texture.h engine/Utils.h
 	g++ $(VERSION) -c client/rendering/entity/EntityRenderer.cpp -o $@
-
+	
+GUI.o: client/rendering/gui/GUI.h client/rendering/gui/GUI.cpp\
+	engine/KeyManager.h engine/MouseManager.h engine/Shader.h engine/DirectRenderer.h
+	g++ $(VERSION) -c client/rendering/gui/GUI.cpp -o $@
+	
+StartMenu.o: client/rendering/gui/StartMenu.h client/rendering/gui/StartMenu.cpp\
+	client/rendering/gui/GUI.h
+	g++ $(VERSION) -c client/rendering/gui/StartMenu.cpp -o $@
+	
 # ------------------------------------------------------------------------------	
 # Utils
 # ------------------------------------------------------------------------------
@@ -107,23 +145,25 @@ Face.o: utils/Face.h utils/Face.cpp
 # Block
 # ------------------------------------------------------------------------------
 	
-Block.o: block/Block.h block/Block.cpp
+Block.o: block/Block.h block/Block.cpp utils/Face.h
 	g++ $(VERSION) -c block/Block.cpp -o $@
 	
-Blocks.o: block/Blocks.h block/Blocks.cpp
+Blocks.o: block/Blocks.h block/Blocks.cpp block/Block.h block/BlockAir.h
 	g++ $(VERSION) -c block/Blocks.cpp -o $@
 	
-BlockAir.o: block/BlockAir.h block/BlockAir.cpp
+BlockAir.o: block/BlockAir.h block/BlockAir.cpp block/Block.h
 	g++ $(VERSION) -c block/BlockAir.cpp -o $@
 	
 # ------------------------------------------------------------------------------	
 # World
 # ------------------------------------------------------------------------------
 	
-Chunk.o: world/Chunk.h world/Chunk.cpp
+Chunk.o: world/Chunk.h world/Chunk.cpp\
+	block/Block.h block/Blocks.h
 	g++ $(VERSION) -c world/Chunk.cpp -o $@
 	
-World.o: world/World.h world/World.cpp data/UnsortedArrayList.h
+World.o: world/World.h world/World.cpp\
+	world/Chunk.h world/IChunkProvider.h world/IChunkListener.h data/UnsortedArrayList.h
 	g++ $(VERSION) -c world/World.cpp -o $@
 
 # ------------------------------------------------------------------------------	
@@ -133,7 +173,8 @@ World.o: world/World.h world/World.cpp data/UnsortedArrayList.h
 Matrix3D.o: math/Matrix3D.h math/Matrix3D.cpp
 	g++ $(VERSION) -c math/Matrix3D.cpp -o $@
 	
-Matrix3DStack.o: math/Matrix3DStack.h math/Matrix3DStack.cpp
+Matrix3DStack.o: math/Matrix3DStack.h math/Matrix3DStack.cpp\
+	math/Matrix3D.h math/StackOverflow.h math/StackUnderflow.h
 	g++ $(VERSION) -c math/Matrix3DStack.cpp -o $@
 	
 StackOverflow.o: math/StackOverflow.h math/StackOverflow.cpp
@@ -145,10 +186,13 @@ StackUnderflow.o: math/StackUnderflow.h math/StackUnderflow.cpp
 Vector3D.o: math/Vector3D.h math/Vector3D.cpp
 	g++ $(VERSION) -c math/Vector3D.cpp -o $@
 	
-Plane3D.o: math/Plane3D.h math/Plane3D.cpp
+Plane3D.o: math/Plane3D.h math/Plane3D.cpp\
+	math/Vector3D.h
 	g++ $(VERSION) -c math/Plane3D.cpp -o $@
 	
-Camera3D.o: math/Camera3D.h math/Camera3D.cpp
+Camera3D.o: math/Camera3D.h math/Camera3D.cpp\
+	math/Vector3D.h math/Matrix3D.h math/Plane3D.h math/Camera3D.h\
+	engine/Wrapper.h engine/Utils.h
 	g++ $(VERSION) -c math/Camera3D.cpp -o $@
 	
 # ------------------------------------------------------------------------------	
@@ -158,8 +202,22 @@ Camera3D.o: math/Camera3D.h math/Camera3D.cpp
 run_server: game_server
 	./game_server
 	
-game_server: MainServer.cpp
-	g++ $(VERSION) -o $@ MainServer.cpp
+game_server: MainServer.cpp GameServer.o Stream.o Server.o
+	g++ $(VERSION) -o $@ MainServer.cpp GameServer.o Stream.o Server.o -lpthread
+	
+GameServer.o: server/GameServer.h server/GameServer.cpp network/server/Server.h
+	g++ $(VERSION) -c server/GameServer.cpp -o $@
+	
+# ------------------------------------------------------------------------------	
+# network
+# ------------------------------------------------------------------------------
+	
+Server.o: network/server/Server.h network/server/Server.cpp\
+	network/server/IServerListener.h network/stream/Stream.h
+	g++ $(VERSION) -c network/server/Server.cpp -o $@
+	
+Stream.o: network/stream/Stream.h network/stream/Stream.cpp
+	g++ $(VERSION) -c network/stream/Stream.cpp -o $@
 	
 # ------------------------------------------------------------------------------	
 # tests

+ 23 - 84
client/Client.cpp

@@ -4,21 +4,15 @@
 #include "../client/rendering/block/BlockRenderers.h"
 #include "rendering/entity/EntityRenderer.h"
 #include <cmath>
+#include "rendering/gui/StartMenu.h"
 
 using namespace std;
 
-Client::Client() : world(&chunkProvider)
+Client::Client()
 {    
     BlockRegistry::registerBlocks();
     BlockRenderers::init();
 
-    position.set(16, 16, 16);
-    lengthAngle = 60;
-    widthAngle = 60;
-    
-    camera.setPosition(position.getX(), position.getY(), position.getZ(), 0, 0);
-    camera.storePosition();
-    
     keyManager.map(KEY_LEFT, GLFW_KEY_A);
     keyManager.map(KEY_RIGHT, GLFW_KEY_D);
     keyManager.map(KEY_UP, GLFW_KEY_W);
@@ -30,108 +24,53 @@ Client::Client() : world(&chunkProvider)
     
     mouseManager.map(MOUSE_LEFT, GLFW_MOUSE_BUTTON_1);
     
-    world.registerChunkListener(&chunkRenderer);
-    world.updateDirtyChunks();
-    
-    Engine::setMouseTrapped(mouseTrapped);
+    activeGUI = new StartMenu();
 }
 
 Client::~Client()
 {
+    if(activeGUI != nullptr)
+    {
+        delete activeGUI;
+    }
 }
 
 void Client::tick()
 {
-    if(keyManager.isReleased(KEY_TEST))
-    {
-        mouseTrapped = !mouseTrapped;
-        Engine::setMouseTrapped(mouseTrapped);
-    }
-    
     tps.update();
     
-    camera.storePosition();
-    
-    float factor = 0.5f;
-    if(keyManager.isDown(KEY_LEFT))
-    {
-        position.addMul(camera.getFlatLeft(), factor);
-    }
-    if(keyManager.isDown(KEY_RIGHT))
-    {
-        position.addMul(camera.getFlatRight(), factor);
-    }
-    if(keyManager.isDown(KEY_UP))
-    {
-        position.addMul(camera.getFlatFront(), factor);
-    }
-    if(keyManager.isDown(KEY_DOWN))
-    {
-        position.addMul(camera.getFlatBack(), factor);
-    }
-    if(keyManager.isDown(KEY_JUMP))
-    {
-        position.addMul(camera.getFlatUp(), factor);
-    }
-    if(keyManager.isDown(KEY_SNEAK))
-    {
-        position.addMul(camera.getFlatDown(), factor);
-    }
-       
-    widthAngle += diffMouseY;
-    if(widthAngle < -89)
-    {
-        widthAngle = -89;
-    }
-    else if(widthAngle > 89)
-    {
-        widthAngle = 89;
-    }
     diffMouseY = 0;
-    
-    lengthAngle += diffMouseX;
-    if(lengthAngle < 0)
-    {
-        lengthAngle += 360;
-        camera.addToOldLengthAngle(360);
-    }
-    else if(lengthAngle > 360)
-    {
-        lengthAngle -= 360;
-        camera.addToOldLengthAngle(-360);
-    }
     diffMouseX = 0;
     
-    camera.setPosition(position.getX(), position.getY(), position.getZ(), lengthAngle, widthAngle);
-    
-    entity.tick();
-    
     mouseManager.tick();
     keyManager.tick();
-}
-
-void Client::render3DShadowTick(float lag)
-{
-    camera.update(lag);
-    Engine::setWorldViewMatrix(camera.getViewMatrix());
-    
-    shader.setToIdentity();
-    Engine::setWorldModelMatrix(shader.getModelMatrix());    
-    chunkRenderer.renderTick(shader, camera, directRenderer, lag);
     
-    entity.renderTick(shader, camera, directRenderer, lag);
+    if(activeGUI != nullptr)
+    {
+        GUI* newGUI = activeGUI->tick(keyManager, mouseManager);
+        if(newGUI != activeGUI)
+        {
+            delete activeGUI;
+            activeGUI = newGUI;
+        }
+    }
 }
 
 void Client::render3DTick(float lag)
 {
     fps.update();
-    render3DShadowTick(lag);
 }
 
 void Client::render2DTick(float lag)
 {
+    if(activeGUI != nullptr)
+    {
+        activeGUI->render2DTick(shader, directRenderer, lag);
+    }
+    
+    Engine::setMixMode();
     shader.setToIdentity();
-    Engine::setOverlayModelMatrix(shader.getModelMatrix());
+    shader.updateModelMatrix();
     
     string wusi;
     wusi = "FPS: " + to_string(fps.getUpdatesPerSecond());

+ 7 - 17
client/Client.h

@@ -1,18 +1,18 @@
 #ifndef CLIENT_H
 #define CLIENT_H
 
-#include "../engine/Wrapper.h"
+// these two are not needed here but prevent further errors
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+
 #include "../engine/KeyManager.h"
 #include "../engine/MouseManager.h"
 #include "../engine/Clock.h"
 #include "../engine/Shader.h"
 #include "../engine/DirectRenderer.h"
-#include "../math/Camera3D.h"
-#include "../world/World.h"
 #include "../world/IChunkProvider.h"
-#include "rendering/ClientChunkProvider.h"
-#include "rendering/ChunkRenderer.h"
-#include "rendering/entity/EntityRenderer.h"
+#include "rendering/gui/GUIs.h"
+#include "rendering/gui/GUI.h"
 
 using namespace std;
 
@@ -23,7 +23,6 @@ public:
     virtual ~Client();
     
     void tick() override;
-    void render3DShadowTick(float lag) override;
     void render3DTick(float lag) override;
     void render2DTick(float lag) override;
     
@@ -57,19 +56,10 @@ private:
     KeyManager keyManager;
     MouseManager mouseManager;
     
-    ChunkRenderer chunkRenderer;
-    ClientChunkProvider chunkProvider;
-    World world;
-    
-    Camera3D camera;
     Shader shader;
     DirectRenderer directRenderer;
-
-    Vector3D position;
-    float lengthAngle = 0;
-    float widthAngle = 0;
     
-    EntityRenderer entity;
+    GUI* activeGUI = nullptr;
 };
 
 #endif

+ 1 - 2
client/rendering/ChunkRenderer.cpp

@@ -1,5 +1,4 @@
 #include "ChunkRenderer.h"
-#include "../../engine/Wrapper.h"
 #include "block/BlockRenderers.h"
 #include "block/BlockRenderer.h"
 
@@ -29,7 +28,7 @@ void ChunkRenderer::renderTick(Shader& shader, Camera3D camera, DirectRenderer&
             if(camera.isInFrustum(sx, 0, sz, ex, Chunk::HEIGHT, ez))
             {
                 shader.translateTo(x * Chunk::WIDTH, 0, z * Chunk::DEPTH);
-                Engine::setWorldModelMatrix(shader.getModelMatrix());
+                shader.updateModelMatrix();
 
                 for(int l = 0; l < Chunk::HEIGHT_PARTIONS; l++)
                 {

+ 2 - 2
client/rendering/ChunkRenderer.h

@@ -19,8 +19,8 @@ public:
 private:
     void buildChunk(int partionY, Chunk& c, Chunk* north, Chunk* east, Chunk* south, Chunk* west);
     
-    const int chunkX = 2;
-    const int chunkZ = 2;
+    const int chunkX = 32;
+    const int chunkZ = 32;
     NormalTextureMesh* mesh;
     
     Texture blockTexture;

+ 2 - 2
client/rendering/ClientChunkProvider.h

@@ -14,8 +14,8 @@ public:
     void forEachLoadedChunk(void* data, void (*fun) (Chunk&, void*)) const override;
     
 private:
-    const int chunkX = 2;
-    const int chunkZ = 2;
+    const int chunkX = 32;
+    const int chunkZ = 32;
     Chunk** chunks;
 };
 

+ 6 - 7
client/rendering/entity/EntityRenderer.cpp

@@ -1,5 +1,4 @@
 #include "EntityRenderer.h"
-#include "../../../engine/Wrapper.h"
 #include "../../../engine/Utils.h"
 
 EntityRenderer::EntityRenderer() : texture("resources/skin.png")
@@ -94,7 +93,7 @@ void EntityRenderer::renderTick(Shader& shader, Camera3D camera, DirectRenderer&
     shader.translate(0.25f + 0.25f, 1.5f, 0.0f + 0.25f);
     shader.rotateY(inter * 0.25f - 22.5f);
     shader.translate(-0.25f, 0.0f, -0.25f);
-    Engine::setWorldModelMatrix(shader.getModelMatrix()); 
+    shader.updateModelMatrix(); 
     mesh.draw(0, 36);
     shader.pop();
     
@@ -102,7 +101,7 @@ void EntityRenderer::renderTick(Shader& shader, Camera3D camera, DirectRenderer&
     shader.translate(0.0f, 1.375f, 0.25f);
     shader.rotateX(inter / 6 - 15);
     shader.translate(0.0f, -0.625f, -0.125f);
-    Engine::setWorldModelMatrix(shader.getModelMatrix()); 
+    shader.updateModelMatrix();  
     mesh.draw(36, 36);
     shader.pop();
     
@@ -110,25 +109,25 @@ void EntityRenderer::renderTick(Shader& shader, Camera3D camera, DirectRenderer&
     shader.translate(0.75f, 1.375f, 0.25f);
     shader.rotateX(- inter / 6 + 15);
     shader.translate(0.0f, -0.625f, -0.125f);
-    Engine::setWorldModelMatrix(shader.getModelMatrix()); 
+    shader.updateModelMatrix(); 
     mesh.draw(72, 36);
     shader.pop();
     
     shader.push();
     shader.translate(0.25f, 0.75f, 0.125f);
-    Engine::setWorldModelMatrix(shader.getModelMatrix()); 
+    shader.updateModelMatrix(); 
     mesh.draw(108, 36);
     shader.pop();
     
     shader.push();
     shader.translate(0.25f, 0.0f, 0.125f);
-    Engine::setWorldModelMatrix(shader.getModelMatrix()); 
+    shader.updateModelMatrix(); 
     mesh.draw(144, 36);
     shader.pop();
     
     shader.push();
     shader.translate(0.5f, 0.0f, 0.125f);
-    Engine::setWorldModelMatrix(shader.getModelMatrix()); 
+    shader.updateModelMatrix(); 
     mesh.draw(180, 36);
     shader.pop();
 }

+ 20 - 0
client/rendering/gui/GUI.cpp

@@ -0,0 +1,20 @@
+#include "GUI.h"
+
+GUI::GUI()
+{
+}
+
+GUI::~GUI()
+{
+}
+
+GUI* GUI::tick(KeyManager& keyManager, MouseManager& mouseManager)
+{
+    return this;
+}
+
+void GUI::render2DTick(Shader& shader, DirectRenderer& dr, float lag)
+{
+    
+}
+

+ 26 - 0
client/rendering/gui/GUI.h

@@ -0,0 +1,26 @@
+#ifndef GUI_H
+#define GUI_H
+
+// these two are not needed here but prevent further errors
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+
+#include "../../../engine/KeyManager.h"
+#include "../../../engine/MouseManager.h"
+#include "../../../engine/Shader.h"
+#include "../../../engine/DirectRenderer.h"
+
+class GUI
+{
+public:
+    GUI();
+    virtual ~GUI();
+    
+    virtual GUI* tick(KeyManager& keyManager, MouseManager& mouseManager);
+    virtual void render2DTick(Shader& shader, DirectRenderer& dr, float lag);
+private:
+
+};
+
+#endif
+

+ 10 - 0
client/rendering/gui/GUIs.h

@@ -0,0 +1,10 @@
+#ifndef GUIS_H
+#define GUIS_H
+
+enum GUIs 
+{ 
+    START_MENU
+};
+
+#endif
+

+ 38 - 0
client/rendering/gui/StartMenu.cpp

@@ -0,0 +1,38 @@
+#include "StartMenu.h"
+
+StartMenu::StartMenu()
+{
+}
+
+StartMenu::~StartMenu()
+{
+}
+
+void StartMenu::render2DTick(Shader& shader, DirectRenderer& dr, float lag)
+{
+    shader.setToIdentity();
+    shader.updateModelMatrix();
+    
+    float w = Engine::getScaledWidth();
+    float h = Engine::getScaledHeight();
+    
+    Engine::setColorMode();
+    dr.drawRectangle(0, 0, w, h, 0xFF004B96);
+    
+    float halfW = w * 0.5;
+    float halfH = h * 0.5;
+    
+    float startHalfW = w * 0.25;
+    float startHalfH = h * 0.25;
+    
+    dr.drawRectangle(startHalfW, startHalfH, startHalfW + halfW, startHalfH + halfH, 0x30000000);
+    
+    float textWidth;
+    float textHeight;
+    
+    string title = "Cubes Plus Plus";
+    dr.getStringSize(textWidth, textHeight, title);
+    Engine::setMixMode();
+    dr.drawString(startHalfW + (halfW - textWidth) * 0.5, startHalfH + 10, true, title);
+}
+

+ 18 - 0
client/rendering/gui/StartMenu.h

@@ -0,0 +1,18 @@
+#ifndef STARTMENU_H
+#define STARTMENU_H
+
+#include "GUI.h"
+
+class StartMenu : public GUI
+{
+public:
+    StartMenu();
+    virtual ~StartMenu();
+    
+    void render2DTick(Shader& shader, DirectRenderer& dr, float lag) override;
+private:
+
+};
+
+#endif
+

+ 27 - 31
engine/DirectRenderer.cpp

@@ -1,5 +1,4 @@
 #include "DirectRenderer.h"
-#include "Wrapper.h"
 #include <cmath>
 
 DirectRenderer::DirectRenderer()
@@ -198,42 +197,39 @@ float DirectRenderer::addString(float x, float y, int& index, float* data, const
     return y + FONT_SIZE + LINE_STEP;
 }
 
-/*  
-    public Rectangle getSize(String s)
+void DirectRenderer::getStringSize(float& width, float& height, string& s)
+{
+    int l = min((int) s.length(), static_cast<int>(MAX_STRING_LENGTH));
+    
+    width = 0.0f;
+    height = FONT_SIZE + LINE_STEP;
+        
+    float currentWidth = 0.0f;
+
+    for(int pos = 0; pos < l; pos++)
     {
-        int length = 0;
-        int counter = 0;
-        for(int i = 0; i < s.length(); i++)
+        char c = s[pos];
+        if(c == COLOR_CHAR)
         {
-            switch(s.charAt(i))
+            pos++;
+            continue;
+        }
+        else if(c == '\n')
+        {
+            if(currentWidth > width)
             {
-                case '\n':
-                    counter++;
-                    break;
-                case COLOR_CHAR:
-                    i++;
-                    break;
-                default:
-                    length++;
+                width = currentWidth;
             }
+            height += FONT_SIZE + LINE_STEP;
+            currentWidth = 0.0f;
+            continue;
         }
-        return new Rectangle(FONT_SIZE * length, (FONT_SIZE + LINE_STEP) * counter);
-    }
-    
-    public Rectangle getSize(int w, int h)
-    {
-        return new Rectangle(FONT_SIZE * w, (FONT_SIZE + LINE_STEP) * h);
-    }
-    
-    public float getHeight()
-    {
-        return FONT_SIZE + LINE_STEP;
+
+        currentWidth += FONT_SIZE;
     }
     
-    public float getWidth()
+    if(currentWidth > width)
     {
-        return FONT_SIZE;
+        width = currentWidth;
     }
- 
- 
- */
+}

+ 3 - 0
engine/DirectRenderer.h

@@ -1,6 +1,7 @@
 #ifndef DIRECTRENDERER_H
 #define DIRECTRENDERER_H
 
+#include "Wrapper.h"
 #include "../math/Matrix3D.h"
 #include "Texture.h"
 #include "Utils.h"
@@ -19,6 +20,8 @@ public:
     void drawRectangle(float minX, float minY, float maxX, float maxY, float tMinX, float tMinY, float tMaxX, float tMaxY);
     
     float drawString(float x, float y, bool shadow, string& s);
+    void getStringSize(float& width, float& height, string& s);
+    
 private:
     float addString(float x, float y, int& index, float* data, const IntColor* color, string& s);
     

+ 2 - 55
engine/Shader.cpp

@@ -3,59 +3,6 @@
 #include <cmath>
 #include "Wrapper.h"
 
-Shader::Shader()
-{
-}
-
-/*
-void Shader::setTextureEnabled(bool use)
-{
-    Engine::setInt(unifUseTexture, use);
-}
-
-void Shader::setColorEnabled(bool use)
-{
-    Engine::setInt(unifUseColor, use);
-}
-
-void Shader::setMixColorEnabled(bool use)
-{
-    Engine::setInt(unifUseMixColor, use);
-}
-
-void Shader::setMixColor(float r, float g, float b, float a)
-{
-    Engine::setFloat(unifUseMixColor, r, g, b, a);
-}
-
-void Shader::setTextMode()
-{
-    setTextureEnabled(true);
-    setColorEnabled(true);
-    setUseBlending(true);
-    setMixColorEnabled(false);
-    setNormalsEnabled(false);
-}
-
-void Shader::setNormalsEnabled(bool use)
-{
-    Engine::setInt(unifUseNormals, use);
-}
-
-void Shader::setUseBlending(bool use)
-{
-    if(use)
-    {
-        glEnable(GL_BLEND);
-        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-        glBlendEquation(GL_FUNC_ADD);
-    }
-    else
-    {
-        glDisable(GL_BLEND);
-    }
-}*/
-
 void Shader::pop()
 {
     model.pop();
@@ -116,7 +63,7 @@ void Shader::rotateZ(float degrees)
     model.get().rotateZ(degrees);
 }
 
-const float* Shader::getModelMatrix()
+void Shader::updateModelMatrix()
 {
-    return model.get().getValues();
+    Engine::setModelMatrix(model.get().getValues());
 }

+ 1 - 3
engine/Shader.h

@@ -9,8 +9,6 @@
 class Shader
 {
 public:
-    Shader();
-    
     void pop();
     void push();
     void setToIdentity();
@@ -24,7 +22,7 @@ public:
     void rotateY(float degrees);
     void rotateZ(float degrees);
     
-    const float* getModelMatrix();
+    void updateModelMatrix();
 
 private:
     Matrix3DStack model;

+ 60 - 76
engine/Wrapper.cpp

@@ -23,8 +23,7 @@ Matrix3D Engine::projMatrix;
 // rectangle for framebuffer drawing
 FramebufferRectangle Engine::rectangle;
 
-// shader stage 0 - world shadow mapping
-WorldShadowShader Engine::worldShadowShader;
+int Engine::stage = 0;
 // shader stage 1 - world
 WorldShader Engine::worldShader;
 // shader stage 2 - world ssao
@@ -78,8 +77,7 @@ bool Engine::init(int width, int height, const char* name)
     cout << "Status: Using GLEW " << glewGetString(GLEW_VERSION) << endl;
 
     if(!worldShader.init() || !ssaoShader.init() || !ssaoBlurShader.init() || 
-            !worldPostShader.init() || !overlayShader.init() || !rectangle.init() || 
-            !worldShadowShader.init())
+            !worldPostShader.init() || !overlayShader.init() || !rectangle.init())
     {
         glfwDestroyWindow(window);
         glfwTerminate();
@@ -151,7 +149,6 @@ void Engine::start(IClient* client)
                     ssaoShader.resize();
                     ssaoBlurShader.resize();
                     worldPostShader.resize();
-                    worldShadowShader.resize();
                 }
 
                 if(ticksPerFrame >= MAX_TICKS_PER_FRAME)
@@ -247,6 +244,16 @@ int Engine::getHeight()
     return height;
 }
 
+float Engine::getScaledWidth()
+{
+    return (float) width / scale;
+}
+
+float Engine::getScaledHeight()
+{
+    return (float) height / scale;
+}
+
 float Engine::getFieldOfView()
 {
     return fovY;
@@ -310,64 +317,10 @@ void Engine::onRenderTick(float lag)
     projMatrix.set(2, 3, (2.0f * nearClip * farClip) / (nearClip - farClip));
     projMatrix.set(3, 3, 0); 
     
-    // -------------------------------------------------------------------------
-    // shader stage 0 - world shadow mapping
-    // -------------------------------------------------------------------------
-    /*worldShadowShader.preRender(projMatrix.getValues());
-    
-    Matrix3D sunView;
-    Vector3D front;
-    front.setAngles(60, 60);
-    
-    // back
-    Vector3D back;
-    back.setInverse(front);
-
-    // right
-    Vector3D right;
-    right.set(front);
-    right.cross(0.0f, 1.0f, 0.0f);
-    right.normalize();
-    
-    // left
-    Vector3D left;
-    left.setInverse(right);
-    
-    // up
-    Vector3D up;
-    up.set(front);
-    up.cross(left);
-    up.normalize();
-    
-    Vector3D interCamera(16, 16, 16);
-    
-    sunView.set(0, 0, right.getX());
-    sunView.set(0, 1, right.getY());
-    sunView.set(0, 2, right.getZ());
-    sunView.set(0, 3, right.dotInverse(interCamera));
-    
-    sunView.set(1, 0, up.getX());
-    sunView.set(1, 1, up.getY());
-    sunView.set(1, 2, up.getZ());
-    sunView.set(1, 3, up.dotInverse(interCamera));
-    
-    sunView.set(2, 0, back.getX());
-    sunView.set(2, 1, back.getY());
-    sunView.set(2, 2, back.getZ());
-    sunView.set(2, 3, back.dotInverse(interCamera));
-    
-    sunView.set(3, 0, 0.0f);
-    sunView.set(3, 1, 0.0f);
-    sunView.set(3, 0, 0.0f);
-    sunView.set(3, 3, 1.0f);
-        
-    worldShadowShader.setViewMatrix(sunView.getValues());
-    
-    client->render3DShadowTick(lag);*/
-    
     // -------------------------------------------------------------------------
     // shader stage 1 - world
     // -------------------------------------------------------------------------
+    stage = 1;
     worldShader.preRender(projMatrix.getValues());
     // call render tick for further drawing
     client->render3DTick(lag);
@@ -375,6 +328,7 @@ void Engine::onRenderTick(float lag)
     // -------------------------------------------------------------------------
     // shader stage 2 - world ssao
     // -------------------------------------------------------------------------
+    stage = 2;
     ssaoShader.preRender(projMatrix.getValues());
  
     // bind previously generated texture data buffers
@@ -383,13 +337,13 @@ void Engine::onRenderTick(float lag)
     worldShader.bindColorTexture(3);
     worldShader.bindDepthTexture(4);
     ssaoShader.bindNoiseTexture(5);
-    worldShadowShader.bindDepthTexture(6);
     
     rectangle.draw();
     
     // -------------------------------------------------------------------------
     // shader stage 3 - world ssao blur
     // -------------------------------------------------------------------------
+    stage = 3;
     ssaoBlurShader.preRender();
     ssaoShader.bindTexture(6);
     rectangle.draw();
@@ -397,6 +351,7 @@ void Engine::onRenderTick(float lag)
     // -------------------------------------------------------------------------
     // shader stage 4 - world post
     // -------------------------------------------------------------------------
+    stage = 4;
     worldPostShader.preRender();
     ssaoBlurShader.bindTexture(7);
     rectangle.draw();
@@ -404,15 +359,13 @@ void Engine::onRenderTick(float lag)
     // -------------------------------------------------------------------------
     // shader stage 5 - 2D overlay
     // -------------------------------------------------------------------------
-    
+    stage = 5;
     overlayShader.preRender();
     worldPostShader.bindTexture(0);
     rectangle.draw();
     overlayShader.setViewMatrix();
     
-    overlayShader.setUseColor(true);
-    overlayShader.setUseTexture(true);
-    
+    setMixMode();
     glEnable(GL_BLEND);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     glBlendEquation(GL_FUNC_ADD);
@@ -420,20 +373,24 @@ void Engine::onRenderTick(float lag)
     glDisable(GL_BLEND);
 }
 
-void Engine::setWorldViewMatrix(const float* data)
+void Engine::setViewMatrix(const float* data)
 {
-    worldShader.setViewMatrix(data);
-}
-
-void Engine::setWorldModelMatrix(const float* data)
-{
-    worldShader.setModelMatrix(data);
-    worldShadowShader.setModelMatrix(data);
+    if(stage == 1)
+    {
+        worldShader.setViewMatrix(data);
+    }
 }
 
-void Engine::setOverlayModelMatrix(const float* data)
+void Engine::setModelMatrix(const float* data)
 {
-    overlayShader.setModelMatrix(data);
+    if(stage == 1)
+    {
+        worldShader.setModelMatrix(data);
+    }
+    else if(stage == 5)
+    {
+        overlayShader.setModelMatrix(data);
+    }
 }
 
 void Engine::setMouseTrapped(bool mode)
@@ -446,4 +403,31 @@ void Engine::setMouseTrapped(bool mode)
     {
         glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
     }
-}
+}
+
+void Engine::setMixMode()
+{
+    if(stage == 5)
+    {
+        overlayShader.setUseColor(true);
+        overlayShader.setUseTexture(true);
+    }
+}
+
+void Engine::setColorMode()
+{
+    if(stage == 5)
+    {
+        overlayShader.setUseColor(true);
+        overlayShader.setUseTexture(false);
+    }
+}
+
+void Engine::setTextureMode()
+{
+    if(stage == 5)
+    {
+        overlayShader.setUseColor(false);
+        overlayShader.setUseTexture(true);
+    }
+}

+ 13 - 9
engine/Wrapper.h

@@ -7,13 +7,13 @@
 #include "../math/Vector3D.h"
 #include "../math/Matrix3D.h"
 #include "shader/WorldShader.h"
-#include "shader/WorldShadowShader.h"
 #include "shader/SSAOShader.h"
 #include "shader/SSAOBlurShader.h"
 #include "shader/FramebufferRectangle.h"
 #include "shader/WorldPostShader.h"
 #include "shader/OverlayShader.h"
 #include "Mesh.h"
+#include "../engine/Shader.h"
 #include <iostream>
 
 using namespace std;
@@ -22,7 +22,6 @@ class IClient
 {
 public:
     virtual void tick() = 0;
-    virtual void render3DShadowTick(float lag) = 0;
     virtual void render3DTick(float lag) = 0;
     virtual void render2DTick(float lag) = 0;
     virtual void onKeyEvent(int key, int scancode, int action, int mods) = 0;
@@ -36,7 +35,6 @@ public:
     static DummyClient dummy;
     
     void tick() override { cout << "Dummy tick" << endl; };
-    void render3DShadowTick(float lag) override { cout << "Dummy render3DShadowTick" << endl; };
     void render3DTick(float lag) override { cout << "Dummy render3DTick" << endl; };
     void render2DTick(float lag) override { cout << "Dummy render3DTick" << endl; };
     void onKeyEvent(int key, int scancode, int action, int mods) override { cout << "Dummy onKeyEvent" << endl; };
@@ -58,18 +56,22 @@ public:
     static int getScale();
     static int getWidth();
     static int getHeight();
+    static float getScaledWidth();
+    static float getScaledHeight();
     
     static float getFieldOfView();
     static float getNearClip();
     static float getFarClip();
     
-    static void setWorldViewMatrix(const float* data);
-    static void setWorldModelMatrix(const float* data);
-    static void setOverlayModelMatrix(const float* data);
-    
     static void setMouseTrapped(bool mode);
+    
+    static void setMixMode();
+    static void setColorMode();
+    static void setTextureMode();
 
 private:
+    friend void Shader::updateModelMatrix();
+    
     static const uint64_t NANOS_PER_FRAME = 1000000000 / 60;
     static const uint64_t NANOS_PER_TICK = 50000000;
     static const int MAX_TICKS_PER_FRAME = 1;
@@ -83,6 +85,9 @@ private:
     static void onMouseMove(GLFWwindow* w, double x, double y);
     static void onMouseClick(GLFWwindow* w, int button, int action, int mods);
     static void onWindowResize(GLFWwindow* w, int width, int height);
+    
+    static void setViewMatrix(const float* data);
+    static void setModelMatrix(const float* data);
 
     static void updateScale();
     
@@ -104,8 +109,7 @@ private:
     // rectangle for framebuffer drawing
     static FramebufferRectangle rectangle;
     
-    // shader stage 0 - world shadow mapping
-    static WorldShadowShader worldShadowShader;
+    static int stage;
     // shader stage 1 - world
     static WorldShader worldShader;
     // shader stage 2 - world ssao

+ 0 - 95
engine/shader/WorldShadowShader.cpp

@@ -1,95 +0,0 @@
-#include "WorldShadowShader.h"
-#include "../Wrapper.h"
-
-WorldShadowShader::WorldShadowShader()
-{
-}
-
-WorldShadowShader::~WorldShadowShader()
-{
-    glDeleteFramebuffers(1, &framebuffer);
-    glDeleteTextures(1, &depthTexture);
-}
-
-bool WorldShadowShader::init()
-{
-    program.compile("shader/worldShadowVertex.vs", "shader/worldShadowFragment.fs");
-    if(!program.isValid())
-    {
-        return false;
-    }
-    
-    // generate framebuffer
-    glGenFramebuffers(1, &framebuffer);
-    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
-    glDrawBuffer(GL_NONE);
-    glReadBuffer(GL_NONE);
-        
-    // depth texture
-    glGenTextures(1, &depthTexture);
-    glBindTexture(GL_TEXTURE_2D, depthTexture);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, Engine::getWidth(), Engine::getHeight(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
-    // attache depth texture to framebuffer
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0); 
-    
-    // check if framebuffer is okay
-    if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
-    {
-	cout << "world shadow frame buffer is not complete!" << endl;
-        return false;
-    }
-    // unbind framebuffer
-    glBindFramebuffer(GL_FRAMEBUFFER, 0);
-    
-    // get uniform locations
-    unifProjMatrix = glGetUniformLocation(program.getProgram(), "projMatrix");
-    unifViewMatrix = glGetUniformLocation(program.getProgram(), "viewMatrix");
-    unifModelMatrix = glGetUniformLocation(program.getProgram(), "modelMatrix");
-    
-    return true;
-}
-
-void WorldShadowShader::resize()
-{
-    glBindTexture(GL_TEXTURE_2D, depthTexture);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, Engine::getWidth(), Engine::getHeight(), 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
-}
-
-void WorldShadowShader::preRender(const float* projMatrix)
-{
-    // bind world shadow shader program
-    glUseProgram(program.getProgram());
-    
-    // set projection matrix uniform
-    glUniformMatrix4fv(unifProjMatrix, 1, 0, projMatrix);
-
-    // bind world framebuffer
-    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
-    
-    // clear color, depth and stencil buffer
-    glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-    
-    // no color, depth testing is needed
-    glEnable(GL_DEPTH_TEST);
-}
-
-void WorldShadowShader::bindDepthTexture(unsigned int textureUnit)
-{
-    glActiveTexture(GL_TEXTURE0 + textureUnit);
-    glBindTexture(GL_TEXTURE_2D, depthTexture);
-}
-
-void WorldShadowShader::setViewMatrix(const float* data)
-{
-    glUniformMatrix4fv(unifViewMatrix, 1, 0, data);
-}
-
-void WorldShadowShader::setModelMatrix(const float* data)
-{
-    glUniformMatrix4fv(unifModelMatrix, 1, 0, data);
-}
-

+ 0 - 38
engine/shader/WorldShadowShader.h

@@ -1,38 +0,0 @@
-#ifndef WORLDSHADOWMAPPINGSHADER_H
-#define WORLDSHADOWMAPPINGSHADER_H
-
-#include "ShaderProgram.h"
-
-class WorldShadowShader
-{
-public:
-    WorldShadowShader();
-    virtual ~WorldShadowShader();
-    
-    bool init();
-    void resize();
-
-    void preRender(const float* projMatrix);
-    
-    void bindDepthTexture(unsigned int textureUnit);
-    
-    void setViewMatrix(const float* data);
-    void setModelMatrix(const float* data);
-    
-private:
-    // shader
-    ShaderProgram program;
-    // framebuffer
-    GLuint framebuffer = 0;
-    // textures
-    GLuint depthTexture = 0;
-    // uniforms locations
-    GLint unifProjMatrix = 0;
-    GLint unifViewMatrix = 0;
-    GLint unifModelMatrix = 0;
-};
-
-#endif
-
-
-

+ 90 - 0
network/client/Client.cpp

@@ -0,0 +1,90 @@
+#include "Client.h"
+#include <iostream>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <cstring>
+#include <stdexcept>
+#include <unistd.h>
+#include <poll.h>
+#include "../stream/Stream.h"
+
+Client::Client()
+{
+}
+
+Client::~Client()
+{
+    if(connectionSocket != -1)
+    {
+        close(connectionSocket);
+    }
+}
+
+bool Client::start(const string& ip, unsigned short port, IClientListener* listener)
+{
+    connectionSocket = socket(AF_INET, SOCK_STREAM, 0);
+    if(connectionSocket == -1)
+    {
+        throw runtime_error(string("cannot create socket: ") + strerror(errno));
+    }
+
+    struct sockaddr_in socketData;
+    memset(&socketData, 0, sizeof(struct sockaddr_in));
+    socketData.sin_family = AF_INET;
+    socketData.sin_port = htons(port);
+    if(inet_aton(ip.data(), &socketData.sin_addr) == 0)
+    {
+        throw runtime_error(ip + " is not a valid ip");
+    }
+
+    if(connect(connectionSocket, (struct sockaddr*) &socketData, sizeof(struct sockaddr_in)) == 0)
+    {
+        clientListener = listener;
+        shouldRun = true;
+        serverListenThread = thread(&Client::listenOnServer, this);
+        return true;
+    }
+    return false;
+}
+
+void Client::stop()
+{
+    shouldRun = false;
+    serverListenThread.join();
+}
+
+void Client::listenOnServer()
+{
+    struct pollfd fds;
+    fds.fd = connectionSocket;
+    fds.events = POLLIN;
+    fds.revents = 0;
+    
+    clientListener->onServerJoin(connectionSocket);
+    
+    Stream st;
+    
+    while(shouldRun)
+    {
+        int pollData = poll(&fds, 1, 100);
+        if(pollData > 0)
+        {
+            st.readSocket(connectionSocket);
+            if(st.hasData())
+            {
+                clientListener->onServerPackage(connectionSocket, st);
+            }
+            else
+            {
+                // server closed connection
+                clientListener->onServerClose(connectionSocket);
+                break;
+            }
+        }
+        else if(pollData == -1)
+        {
+            cout << "poll error: " << strerror(errno) << endl;
+        }
+    }
+}
+

+ 31 - 0
network/client/Client.h

@@ -0,0 +1,31 @@
+#ifndef CLIENT_H
+#define CLIENT_H
+
+#include <string>
+#include <thread>
+#include "IClientListener.h"
+
+using namespace std;
+
+class Client
+{
+public:
+    Client();
+    virtual ~Client();
+    
+    bool start(const string& ip, unsigned short port, IClientListener* listener);
+    void stop();
+    
+private:
+    void listenOnServer();
+    
+    int connectionSocket = -1;
+    volatile bool shouldRun = false;
+    
+    thread serverListenThread;
+    
+    IClientListener* clientListener;
+};
+
+#endif
+

+ 16 - 0
network/client/ClientListener.cpp

@@ -0,0 +1,16 @@
+#include "ClientListener.h"
+#include <iostream>
+
+void ClientListener::onServerJoin(int serverSocket)
+{
+}
+
+void ClientListener::onServerPackage(int serverSocket, Stream& in)
+{
+}
+
+void ClientListener::onServerClose(int socket)
+{
+}
+
+

+ 15 - 0
network/client/ClientListener.h

@@ -0,0 +1,15 @@
+#ifndef CLIENTLISTENER_H
+#define CLIENTLISTENER_H
+
+#include "IClientListener.h"
+
+class ClientListener : public IClientListener
+{
+public:
+    void onServerJoin(int serverSocket) override;
+    void onServerPackage(int serverSocket, Stream& in) override;
+    void onServerClose(int socket) override;
+};
+
+#endif
+

+ 15 - 0
network/client/IClientListener.h

@@ -0,0 +1,15 @@
+#ifndef ICLIENTLISTENER_H
+#define ICLIENTLISTENER_H
+
+#include "../stream/Stream.h"
+
+class IClientListener
+{
+public:
+    virtual void onServerJoin(int serverSocket) = 0;
+    virtual void onServerPackage(int serverSocket, Stream& in) = 0;
+    virtual void onServerClose(int socket) = 0;
+};
+
+#endif
+

+ 16 - 0
network/server/IServerListener.h

@@ -0,0 +1,16 @@
+#ifndef ISERVERLISTENER_H
+#define ISERVERLISTENER_H
+
+#include "../stream/Stream.h"
+
+class IServerListener
+{
+public:
+    virtual void onFullServerClientConnect(int socket) = 0;
+    virtual void onClientConnect(int socket) = 0;
+    virtual void onClientPackage(int socket, Stream& in) = 0;
+    virtual void onClientDisconnect(int socket) = 0;
+};
+
+#endif
+

+ 250 - 0
network/server/Server.cpp

@@ -0,0 +1,250 @@
+#include "Server.h"
+#include <iostream>
+#include <sys/socket.h>
+#include <cstdio>
+#include <cstring>
+#include <stdexcept>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <poll.h>
+#include <time.h>
+#include <signal.h>
+#include "../stream/Stream.h"
+
+using namespace std;
+
+Server::Server(unsigned short port, unsigned short maxClients) : port(port), maxClients(maxClients) 
+{
+    try
+    {
+        // create socket for incoming connections
+        listenerSocket = socket(AF_INET, SOCK_STREAM, 0);
+        if(listenerSocket == -1)
+        {
+            throw runtime_error(string("cannot create socket: ") + strerror(errno));
+        }
+
+        // prevents clients from blocking the port if the server exits
+        struct linger sl;
+        sl.l_onoff = 1;
+        sl.l_linger = 0;
+        if(setsockopt(listenerSocket, SOL_SOCKET, SO_LINGER, &sl, sizeof(struct linger)) == -1)
+        {
+            throw runtime_error(string("cannot set non lingering: ") + strerror(errno));
+        }
+
+        // specifies data of the port ...
+        struct sockaddr_in connectSocketData;
+        memset(&connectSocketData, 0, sizeof(struct sockaddr_in));
+        connectSocketData.sin_family = AF_INET;
+        connectSocketData.sin_addr.s_addr = INADDR_ANY;
+        connectSocketData.sin_port = htons(port);
+        // ... and binds it
+        if(bind(listenerSocket, (struct sockaddr*) &connectSocketData, sizeof(struct sockaddr_in)) == -1)
+        {
+            throw runtime_error(string("cannot bind socket: ") + strerror(errno));
+        }
+
+        // mark this socket as handler for connection requests
+        if(listen(listenerSocket, 5) != 0)
+        {
+            throw runtime_error(string("cannot start listening: ") + strerror(errno));
+        }
+        
+        // array for client connections, pointer to pointer to change placement
+        clients = new ConnectedClient*[maxClients];
+        for(int i = 0; i < maxClients; i++)
+        {
+            clients[i] = nullptr;
+        }
+    }
+    catch(runtime_error& err)
+    {
+        clean();
+        throw err; 
+    }
+}
+
+Server::~Server()
+{
+    clean();
+}
+
+void Server::clean()
+{
+    if(listenerSocket != -1)
+    {
+        // ignore error
+        close(listenerSocket);
+    }
+    if(clients != nullptr)
+    {
+        for(int i = 0; i < maxClients; i++)
+        {
+            if(clients[i] != nullptr)
+            {
+                if(clients[i]->socket != -1)
+                {
+                    close(clients[i]->socket);
+                }
+                delete clients[i];
+            }
+        }
+        delete[] clients;
+    }
+}
+
+void Server::start(IServerListener* listener)
+{
+    serverListener = listener;
+    shouldRun = true;
+    listenerThread = thread(&Server::listenForClients, this);
+}
+
+void Server::stop()
+{
+    shouldRun = false;
+    
+    listenerThread.join();
+    for(int i = 0; i < maxClients; i++)
+    {
+        if(clients[i] != nullptr)
+        {
+            clients[i]->th.join();
+        }
+    }
+}
+
+void Server::listenForClients()
+{
+    while(shouldRun)
+    {
+        struct pollfd fds;
+        fds.fd = listenerSocket;
+        fds.events = POLLIN;
+        fds.revents = 0;
+        int pollData = poll(&fds, 1, 100);
+        if(pollData > 0)
+        {
+            struct sockaddr_in clientSocketData;
+            socklen_t addrlen = sizeof(struct sockaddr_in);
+            int clientSocket = accept(listenerSocket, (struct sockaddr*) &clientSocketData, &addrlen);
+            if(clientSocket >= 0)
+            {
+                //cout << "Client connected from " << inet_ntoa(clientSocketData.sin_addr) << ":" << (int) ntohs(clientSocketData.sin_port) << endl;
+                
+                clientMutex.lock();
+                addClient(clientSocket);
+                clientMutex.unlock();
+            }
+            else
+            {
+                break;
+            }
+        }
+        else if(pollData == -1)
+        {
+            cerr << "poll error: " << strerror(errno) << endl;
+        }
+    }
+}
+
+void Server::addClient(int clientSocket)
+{
+    if(clientIndex >= maxClients)
+    {
+        serverListener->onFullServerClientConnect(clientSocket);
+        close(clientSocket);
+    }
+    else
+    {
+        if(clients[clientIndex] == nullptr)
+        {
+            clients[clientIndex] = new ConnectedClient();
+        }
+        else
+        {
+            //ensure old thread has ended
+            if(!clients[clientIndex]->th.joinable())
+            {
+                cerr << "cannot join thread of non used client connection" << endl;
+                close(clientSocket);
+                return;
+            }
+            clients[clientIndex]->th.join();
+        }
+        
+        clients[clientIndex]->index = clientIndex;
+        clients[clientIndex]->socket = clientSocket;
+        clients[clientIndex]->th = thread(&Server::listenOnClient, this, clients[clientIndex]);
+
+        clientIndex++;
+    }
+}
+
+void Server::listenOnClient(ConnectedClient* cc)
+{
+    struct pollfd fds;
+    fds.fd = cc->socket;
+    fds.events = POLLIN;
+    fds.revents = 0;
+    
+    serverListener->onClientConnect(cc->socket);
+    
+    Stream st;
+    
+    while(shouldRun)
+    {
+        int pollData = poll(&fds, 1, 100);
+        if(pollData > 0)
+        {
+            st.readSocket(cc->socket);
+            if(st.hasData())
+            {
+                serverListener->onClientPackage(cc->socket, st);
+            }
+            else
+            {
+                // client closed connection
+                break;
+            }
+        }
+        else if(pollData == -1)
+        {
+            cout << "poll error: " << strerror(errno) << endl;
+        }
+    }
+    
+    serverListener->onClientDisconnect(cc->socket);
+    
+    // do not swap on server shutdown
+    if(!shouldRun)
+    {
+        return;
+    }
+    
+    // remove client from list, move last client to empty slot
+    clientMutex.lock();
+    
+    clientIndex--;
+    if(cc->index != clientIndex) // client is not the last connected client
+    {
+        // move last element to empty slot
+        ConnectedClient* tmp = clients[clientIndex];
+        clients[clientIndex] = clients[cc->index];
+        clients[cc->index] = tmp;
+        // set indices
+        int i = cc->index;
+        clients[i]->index = i;
+        clients[clientIndex]->index = clientIndex;
+    }
+    
+    if(close(cc->socket) == -1)
+    {
+        cerr << "cannot close socket of client: " << strerror(errno) << endl;
+    }
+    cc->socket = -1;
+    
+    clientMutex.unlock();
+}

+ 47 - 0
network/server/Server.h

@@ -0,0 +1,47 @@
+#ifndef SERVER_H
+#define SERVER_H
+
+#include <thread>
+#include <mutex>
+#include "IServerListener.h"
+
+using namespace std;
+
+class Server
+{
+public:
+    Server(unsigned short port, unsigned short maxClients);
+    virtual ~Server();
+    
+    void start(IServerListener* listener);
+    void stop();
+    
+private:
+    void listenForClients();
+    void clean();
+    void addClient(int clientSocket);
+    
+    unsigned short port;
+    unsigned short maxClients;
+    
+    struct ConnectedClient
+    {
+        thread th;
+        int socket;
+        unsigned int index;
+    };
+    unsigned int clientIndex = 0;
+    mutex clientMutex;
+    ConnectedClient** clients = nullptr;
+    
+    void listenOnClient(ConnectedClient* cc);
+    
+    volatile bool shouldRun = false;
+    int listenerSocket;
+    thread listenerThread;
+    
+    IServerListener* serverListener = nullptr;
+};
+
+#endif
+

+ 214 - 0
network/stream/Stream.cpp

@@ -0,0 +1,214 @@
+#include "Stream.h"
+#include <stdexcept>
+#include <iostream>
+#include <cstring>
+#include <sys/socket.h>
+
+Stream::Stream(size_t minSize)
+{
+    dataLength = getSize(minSize);
+    data = new unsigned char[dataLength];
+}
+
+Stream::~Stream()
+{
+    delete[] data;
+}
+
+size_t Stream::getSize(size_t minSize)
+{
+    size_t size = 1;
+    while(size < minSize && size != 0)
+    {
+        size <<= 1;
+    }
+    if(size == 0)
+    {
+        throw runtime_error("size exceeds max possible size");
+    }
+}
+
+bool Stream::hasData() const
+{
+    return readIndex < writeIndex;
+}
+
+void Stream::resize(size_t minSize)
+{
+    size_t newSize = getSize(minSize);
+    //cout << "resize from " << dataLength << " to " << newSize << endl;
+    unsigned char* newData = new unsigned char[newSize];
+    memcpy(newData, data, writeIndex);
+    delete[] data;
+    data = newData;
+    dataLength = newSize;
+}
+
+void Stream::write(const void* writeData, size_t length)
+{
+    if(writeIndex + length > dataLength)
+    {
+        resize(writeIndex + length);
+    }
+    for(size_t i = 0; i < length; i++)
+    {
+        data[writeIndex] = ((unsigned char*) writeData)[i];
+        writeIndex++;
+    }
+}
+
+void Stream::writeChar(char c)
+{
+    write(&c, sizeof(char));
+}
+
+void Stream::writeShort(short s)
+{
+    write(&s, sizeof(short));
+}
+
+void Stream::writeInt(int i)
+{
+    write(&i, sizeof(int));
+}
+
+void Stream::writeLong(long l)
+{
+    write(&l, sizeof(long));
+}
+
+void Stream::writeUnsignedChar(unsigned char uc)
+{
+    write(&uc, sizeof(unsigned char));
+}
+
+void Stream::writeUnsignedShort(unsigned short us)
+{
+    write(&us, sizeof(unsigned short));
+}
+
+void Stream::writeUnsignedInt(unsigned int ui)
+{
+    write(&ui, sizeof(unsigned int));
+}
+
+void Stream::writeUnsignedLong(unsigned long ul)
+{
+    write(&ul, sizeof(unsigned long));
+}
+
+void Stream::read(void* buffer, size_t length)
+{
+    if(readIndex + length > writeIndex)
+    {
+        throw runtime_error("stream read over data length");
+    }
+    for(size_t i = 0; i < length; i++)
+    {
+        ((unsigned char*) buffer)[i] = data[readIndex];
+        readIndex++;
+    }
+}
+
+char Stream::readChar()
+{
+    char c;
+    read(&c, sizeof(char));
+    return c;
+}
+
+short Stream::readShort()
+{
+    short s;
+    read(&s, sizeof(short));
+    return s;
+}
+
+int Stream::readInt()
+{
+    int i;
+    read(&i, sizeof(int));
+    return i;
+}
+
+long Stream::readLong()
+{
+    long l;
+    read(&l, sizeof(long));
+    return l;
+}
+
+unsigned char Stream::readUnsignedChar()
+{
+    unsigned char uc;
+    read(&uc, sizeof(unsigned char));
+    return uc;
+}
+
+unsigned short Stream::readUnsignedShort()
+{
+    unsigned short us;
+    read(&us, sizeof(unsigned short));
+    return us;
+}
+
+unsigned int Stream::readUnsignedInt()
+{
+    unsigned int ui;
+    read(&ui, sizeof(unsigned int));
+    return ui;
+}
+
+unsigned long Stream::readUnsignedLong()
+{
+    unsigned long ul;
+    read(&ul, sizeof(unsigned long));
+    return ul;
+}
+
+void Stream::readSocket(int socket)
+{
+    writeIndex = 0;
+    readIndex = 0;
+    
+    size_t bufferOffset = 0;
+    size_t freeSpace = dataLength - writeIndex;
+    
+    while(true)
+    {
+        ssize_t readLength = recv(socket, data + bufferOffset, freeSpace, MSG_DONTWAIT);        
+        if(readLength <= 0)
+        {
+            break;
+        }
+        writeIndex += readLength;
+        if(readLength < freeSpace)
+        {    
+            break;
+        }
+        else
+        {
+            resize(dataLength + 1);
+            freeSpace = dataLength - writeIndex;
+            bufferOffset += readLength;
+        }
+    }
+}
+
+void Stream::sendToSocket(int socket)
+{
+    size_t bufferOffset = 0;
+    size_t sendLength = writeIndex;
+    
+    while(sendLength > 0)
+    {
+        ssize_t writtenLength = send(socket, data + bufferOffset, sendLength, MSG_NOSIGNAL);
+        if(writtenLength == -1)
+        {
+            perror("Cannot send data");
+            return;
+        }
+        sendLength -= writtenLength;
+        bufferOffset += writtenLength;
+    }
+}

+ 51 - 0
network/stream/Stream.h

@@ -0,0 +1,51 @@
+#ifndef STREAM_H
+#define STREAM_H
+
+#include <cstddef>
+
+using namespace std;
+
+class Stream
+{
+public:
+    Stream(size_t minSize = 1);
+    virtual ~Stream();
+
+    void readSocket(int socket);
+    void sendToSocket(int socket);
+    
+    bool hasData() const;
+    
+    void write(const void* writeData, size_t length);
+    void writeChar(char c);
+    void writeShort(short s);
+    void writeInt(int i);
+    void writeLong(long l);
+    void writeUnsignedChar(unsigned char uc);
+    void writeUnsignedShort(unsigned short us);
+    void writeUnsignedInt(unsigned int ui);
+    void writeUnsignedLong(unsigned long ul);
+    
+    void read(void* buffer, size_t length);
+    char readChar();
+    short readShort();
+    int readInt();
+    long readLong();
+    unsigned char readUnsignedChar();
+    unsigned short readUnsignedShort();
+    unsigned int readUnsignedInt();
+    unsigned long readUnsignedLong();
+    
+private:
+    void resize(size_t minSize);
+    size_t getSize(size_t minSize);
+    
+    size_t dataLength = 0; 
+    unsigned char* data = nullptr;
+    
+    size_t writeIndex = 0;
+    size_t readIndex = 0;
+};
+
+#endif
+

+ 75 - 0
server/GameServer.cpp

@@ -0,0 +1,75 @@
+#include "GameServer.h"
+#include "../network/server/Server.h"
+
+GameServer::GameServer()
+{
+}
+
+GameServer::~GameServer()
+{
+}
+
+void GameServer::start(unsigned short port, unsigned short maxClients)
+{
+    std::cout << port << std::endl;
+    Server server(port, maxClients);
+    server.start(this);
+    
+    while(true)
+    {
+        string in;
+        cin >> in;
+        if(onServerCommand(in))
+        {
+            break;
+        }
+    }
+    
+    server.stop();
+}
+
+bool GameServer::onServerCommand(string& command)
+{
+    return command == "q";
+}
+
+void GameServer::onFullServerClientConnect(int socket)
+{
+    string s = "sorry, the server is full";
+    Stream answer;
+    answer.write(s.data(), s.length());
+    answer.sendToSocket(socket);
+}
+
+void GameServer::onClientConnect(int socket)
+{
+    cout << socket << " has connected" << endl;
+    
+    string s = "Welcome to the server.";
+    Stream answer;
+    answer.write(s.data(), s.length());
+    answer.sendToSocket(socket);
+}
+
+void GameServer::onClientPackage(int socket, Stream& in)
+{
+    string s = "";
+    while(in.hasData())
+    {
+        s = in.readChar() + s;
+    }
+
+    Stream answer;
+    answer.write(s.data(), s.length());
+    answer.sendToSocket(socket);
+}
+
+void GameServer::onClientDisconnect(int socket)
+{
+    cout << socket << " has disconnected" << endl;
+    
+    string s = "Bye.";
+    Stream answer;
+    answer.write(s.data(), s.length());
+    answer.sendToSocket(socket);
+}

+ 26 - 0
server/GameServer.h

@@ -0,0 +1,26 @@
+#ifndef GAMESERVER_H
+#define GAMESERVER_H
+
+#include <iostream>
+#include "../network/server/IServerListener.h"
+
+using namespace std;
+
+class GameServer : public IServerListener
+{
+public:
+    GameServer();
+    virtual ~GameServer();
+    
+    void start(unsigned short port, unsigned short maxClients);
+    
+    void onFullServerClientConnect(int socket) override;
+    void onClientConnect(int socket) override;
+    void onClientPackage(int socket, Stream& in) override;
+    void onClientDisconnect(int socket) override;
+private:
+    bool onServerCommand(string& command);
+};
+
+#endif
+