Kajetan Johannes Hammerle 5 years ago
commit
5a7c7d02b4

+ 4 - 0
.gitignore

@@ -0,0 +1,4 @@
+/nbproject
+game_client
+game_server
+*.o

+ 11 - 0
MainClient.cpp

@@ -0,0 +1,11 @@
+#include <iostream>
+#include "client/Client.h"
+
+using namespace std;
+
+int main(int argc, char** argv) 
+{
+    Client::start();
+    return 0;
+}
+

+ 11 - 0
MainServer.cpp

@@ -0,0 +1,11 @@
+#include <iostream>
+#include "Texture.h"
+
+using namespace std;
+
+int main(int argc, char** argv)
+{
+    cout << "server" << endl;
+    return 0;
+}
+

+ 29 - 0
Makefile

@@ -0,0 +1,29 @@
+VERSION = -std=c++14
+CFLAGS = $(shell pkg-config --cflags glfw3)
+LDFLAGS = $(shell pkg-config --static --libs glfw3) -lGL -lGLEW -lpng
+
+all: game
+
+run_client: game_client
+	vblank_mode=0 optirun ./game_client
+	
+game_client: MainClient.cpp engine math client *.o
+	g++ $(VERSION) -o $@ MainClient.cpp *.o $(LDFLAGS)
+	
+engine: engine/*.cpp engine/*.h
+	g++ $(VERSION) -c engine/*.cpp $(LDFLAGS)
+	
+math: math/*.cpp math/*.h
+	g++ $(VERSION) -c math/*.cpp $(LDFLAGS)
+	
+client: client/*.cpp client/*.h
+	g++ $(VERSION) -c client/*.cpp $(LDFLAGS)
+	
+run_server: game_server
+	./game_server
+	
+game_server: MainServer.cpp Image.cpp Image.h
+	g++ $(VERSION) -o $@ MainServer.cpp Image.cpp -lpng
+	
+clean:
+	rm -f game_server game_client

+ 250 - 0
client/Client.cpp

@@ -0,0 +1,250 @@
+#include "Client.h"
+#include "../engine/Mouse.h"
+#include "../math/Matrix3D.h"
+#include "../math/Matrix3DStack.h"
+#include "../engine/Key.h"
+
+Mesh Client::mesh;
+TextureMesh Client::tmesh;
+Vector3D Client::position;
+Texture Client::texture;
+Texture Client::texture2;
+float Client::lengthAngle = 0;
+float Client::widthAngle = 0;
+
+Client::Client()
+{
+}
+
+void Client::init()
+{
+    if(texture.load("resources/textures.png"))
+    {
+        cout << "texture success" << endl;
+    }
+    else
+    {
+        cout << "texture fail" << endl;
+    }
+    if(texture2.load("resources/font8x8.png"))
+    {
+        cout << "texture2 success" << endl;
+    }
+    else
+    {
+        cout << "texture2 fail" << endl;
+    }
+    
+    cout << "init" << endl;
+    mesh.init();
+    
+    // bottom
+    mesh.addPoint(0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
+    mesh.addPoint(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
+    mesh.addPoint(0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f);
+    mesh.addPoint(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
+    mesh.addPoint(1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f);
+    mesh.addPoint(0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f);
+    
+    // top
+    mesh.addPoint(0.0f, 1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f);
+    mesh.addPoint(0.0f, 1.0f, 1.0f, 0.5f, 0.0f, 0.0f, 1.0f);
+    mesh.addPoint(1.0f, 1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f);
+    mesh.addPoint(1.0f, 1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f);
+    mesh.addPoint(0.0f, 1.0f, 1.0f, 0.5f, 0.0f, 0.0f, 1.0f);
+    mesh.addPoint(1.0f, 1.0f, 1.0f, 0.5f, 0.0f, 0.0f, 1.0f);
+    
+    // right
+    mesh.addPoint(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f);
+    mesh.addPoint(1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
+    mesh.addPoint(1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
+    mesh.addPoint(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f);
+    mesh.addPoint(1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f);
+    mesh.addPoint(1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
+    
+    // left
+    mesh.addPoint(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 1.0f);
+    mesh.addPoint(0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.0f);
+    mesh.addPoint(0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.0f);
+    mesh.addPoint(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 1.0f);
+    mesh.addPoint(0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.0f);
+    mesh.addPoint(0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.5f, 1.0f);
+    
+    // back
+    mesh.addPoint(0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
+    mesh.addPoint(1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
+    mesh.addPoint(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
+    mesh.addPoint(0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
+    mesh.addPoint(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
+    mesh.addPoint(0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
+    
+    // front
+    mesh.addPoint(0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 1.0f);
+    mesh.addPoint(1.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.0f, 1.0f);
+    mesh.addPoint(1.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 1.0f);
+    mesh.addPoint(0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 1.0f);
+    mesh.addPoint(0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.0f, 1.0f);
+    mesh.addPoint(1.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.0f, 1.0f);
+    
+    mesh.build();
+    
+    tmesh.init();
+    
+    // bottom
+    tmesh.addPoint(0.0f, 0.0f, 0.0f, 0.125f, 0.0f);
+    tmesh.addPoint(1.0f, 0.0f, 0.0f, 0.1875f, 0.0f);
+    tmesh.addPoint(0.0f, 0.0f, 1.0f, 0.125f, 0.0625f);
+    tmesh.addPoint(1.0f, 0.0f, 0.0f, 0.1875f, 0.0f);
+    tmesh.addPoint(1.0f, 0.0f, 1.0f, 0.1875f, 0.0625f);
+    tmesh.addPoint(0.0f, 0.0f, 1.0f, 0.125f, 0.0625f);
+    
+    // top
+    tmesh.addPoint(0.0f, 1.0f, 0.0f, 0.25f, 0.0f);
+    tmesh.addPoint(0.0f, 1.0f, 1.0f, 0.25f, 0.0625f);
+    tmesh.addPoint(1.0f, 1.0f, 0.0f, 0.3125f, 0.0f);
+    tmesh.addPoint(1.0f, 1.0f, 0.0f, 0.3125f, 0.0f);
+    tmesh.addPoint(0.0f, 1.0f, 1.0f, 0.25f, 0.0625f);
+    tmesh.addPoint(1.0f, 1.0f, 1.0f, 0.3125f, 0.0625f);
+    
+    // right
+    tmesh.addPoint(1.0f, 0.0f, 0.0f, 0.1875f, 0.0625f);
+    tmesh.addPoint(1.0f, 1.0f, 1.0f, 0.25f, 0.0f);
+    tmesh.addPoint(1.0f, 0.0f, 1.0f, 0.25f, 0.0625f);
+    tmesh.addPoint(1.0f, 0.0f, 0.0f, 0.1875f, 0.0625f);
+    tmesh.addPoint(1.0f, 1.0f, 0.0f, 0.1875f, 0.0f);
+    tmesh.addPoint(1.0f, 1.0f, 1.0f, 0.25f, 0.0f);
+    
+    // left
+    tmesh.addPoint(0.0f, 0.0f, 0.0f, 0.1875f, 0.0625f);
+    tmesh.addPoint(0.0f, 0.0f, 1.0f, 0.25f, 0.0625f);
+    tmesh.addPoint(0.0f, 1.0f, 1.0f, 0.25f, 0.0f);
+    tmesh.addPoint(0.0f, 0.0f, 0.0f, 0.1875f, 0.0625f);
+    tmesh.addPoint(0.0f, 1.0f, 1.0f, 0.25f, 0.0f);
+    tmesh.addPoint(0.0f, 1.0f, 0.0f, 0.1875f, 0.0f);
+    
+    // back
+    tmesh.addPoint(0.0f, 0.0f, 1.0f, 0.1875f, 0.0625f);
+    tmesh.addPoint(1.0f, 0.0f, 1.0f, 0.25f, 0.0625f);
+    tmesh.addPoint(1.0f, 1.0f, 1.0f, 0.25f, 0.0f);
+    tmesh.addPoint(0.0f, 0.0f, 1.0f, 0.1875f, 0.0625f);
+    tmesh.addPoint(1.0f, 1.0f, 1.0f, 0.25f, 0.0f);
+    tmesh.addPoint(0.0f, 1.0f, 1.0f, 0.1875f, 0.0f);
+    
+    // front
+    tmesh.addPoint(0.0f, 0.0f, 0.0f, 0.1875f, 0.0625f);
+    tmesh.addPoint(1.0f, 1.0f, 0.0f, 0.25f, 0.0f);
+    tmesh.addPoint(1.0f, 0.0f, 0.0f, 0.25f, 0.0625f);
+    tmesh.addPoint(0.0f, 0.0f, 0.0f, 0.1875f, 0.0625f);
+    tmesh.addPoint(0.0f, 1.0f, 0.0f, 0.1875f, 0.0f);
+    tmesh.addPoint(1.0f, 1.0f, 0.0f, 0.25f, 0.0f);
+    
+    tmesh.build();
+    
+    position.set(0, 0, -2);
+    GameEngine::getCamera().setPosition(position.getX(), position.getY(), position.getZ());
+    GameEngine::getCamera().storePosition();
+    
+    Key::map(KEY_LEFT, GLFW_KEY_A);
+    Key::map(KEY_RIGHT, GLFW_KEY_D);
+    Key::map(KEY_UP, GLFW_KEY_W);
+    Key::map(KEY_DOWN, GLFW_KEY_S);
+    Key::map(KEY_JUMP, GLFW_KEY_SPACE);
+    Key::map(KEY_SNEAK, GLFW_KEY_LEFT_SHIFT);
+    
+    Key::map(KEY_CAM_LEFT, GLFW_KEY_H);
+    Key::map(KEY_CAM_RIGHT, GLFW_KEY_K);
+    Key::map(KEY_CAM_UP, GLFW_KEY_U);
+    Key::map(KEY_CAM_DOWN, GLFW_KEY_J);
+}
+
+uint64_t oldTime = -1;
+
+uint64_t count = 0;
+uint64_t sum = 0;
+
+void Client::tick()
+{
+    Camera& c = GameEngine::getCamera();
+    
+    c.storePosition();
+    c.storeAngles();
+    
+    float factor = 0.125f;
+    if(Key::isDown(KEY_LEFT))
+    {
+        position.addMul(c.getLeft(), factor);
+    }
+    if(Key::isDown(KEY_RIGHT))
+    {
+        position.addMul(c.getRight(), factor);
+    }
+    if(Key::isDown(KEY_UP))
+    {
+        position.addMul(c.getFront(), factor);
+    }
+    if(Key::isDown(KEY_DOWN))
+    {
+        position.addMul(c.getBack(), factor);
+    }
+    if(Key::isDown(KEY_JUMP))
+    {
+        position.addMul(c.getUp(), factor);
+    }
+    if(Key::isDown(KEY_SNEAK))
+    {
+        position.addMul(c.getDown(), factor);
+    }
+    
+    if(Key::isDown(KEY_CAM_LEFT))
+    {
+        lengthAngle += 2;
+    }
+    if(Key::isDown(KEY_CAM_RIGHT))
+    {
+        lengthAngle -= 2;
+    }
+    if(Key::isDown(KEY_CAM_UP))
+    {
+        widthAngle += 2;
+    }
+    if(Key::isDown(KEY_CAM_DOWN))
+    {
+        widthAngle -= 2;
+    }
+    
+    c.setPosition(position.getX(), position.getY(), position.getZ());
+    c.setAngles(lengthAngle, widthAngle);
+    //cout << "tick" << endl;
+    
+    cout << (1000000000.0 * count ) / sum << endl;
+}
+
+void Client::renderTick(float lag)
+{
+    uint64_t t = glfwGetTimerValue();
+    if(oldTime == -1)
+    {
+        oldTime = t;
+    }
+    else
+    {
+        sum += t - oldTime;
+        count++;
+        oldTime = t;
+    }
+    
+    GameEngine::getCamera().updateView(lag);
+    texture.bind();
+    GameEngine::setTextureEnabled(true);
+    //GameEngine::setColorEnabled(true);
+    GameEngine::getDirectRenderer().prepare();
+    GameEngine::getDirectRenderer().drawRectangle(0, 0, 300, 300, 0, 0, 1, 1, 1, 0, 0, 1);
+    //tmesh.draw();
+    //cout << "renderTick" << endl;
+}
+
+void Client::start()
+{
+    GameEngine::start(640, 480, "Test Game", init, tick, renderTick);
+}
+

+ 45 - 0
client/Client.h

@@ -0,0 +1,45 @@
+#ifndef CLIENT_H
+#define CLIENT_H
+
+#include "../engine/Mesh.h"
+#include "../engine/TextureMesh.h"
+#include "../math/Vector3D.h"
+#include "../engine/Texture.h"
+
+class Client
+{
+public:
+    static void start();
+    
+private:
+    Client();
+
+    static void init();
+    static void tick();
+    static void renderTick(float lag);
+    
+    static Texture texture;
+    static Texture texture2;
+    static Mesh mesh;
+    static TextureMesh tmesh;
+    
+    static Vector3D position;
+    static float lengthAngle;
+    static float widthAngle;
+    
+    static const int KEY_LEFT = 0;
+    static const int KEY_RIGHT = 1;
+    static const int KEY_UP = 2;
+    static const int KEY_DOWN = 3;
+    static const int KEY_JUMP = 4;
+    static const int KEY_SNEAK = 5;
+    
+    static const int KEY_CAM_LEFT = 6;
+    static const int KEY_CAM_RIGHT = 7;
+    static const int KEY_CAM_UP = 8;
+    static const int KEY_CAM_DOWN = 9;
+    
+};
+
+#endif
+

+ 146 - 0
engine/Camera.cpp

@@ -0,0 +1,146 @@
+#include "Camera.h"
+#include "GameEngine.h"
+#include "Utils.h"
+#include <cmath>
+
+Camera::Camera()
+{
+}
+
+Camera::Camera(const Camera& orig)
+{
+}
+
+Camera::~Camera()
+{
+}
+
+void Camera::storePosition()
+{
+    oldCamera.set(camera);
+}
+
+void Camera::storeAngles()
+{
+    oldLengthAngle = lengthAngle;
+    oldWidthAngle = widthAngle;
+}
+
+void Camera::setPosition(float x, float y, float z)
+{
+    camera.set(x, y, z);
+}
+
+void Camera::setAngles(float length, float width)
+{
+    lengthAngle = length;
+    widthAngle = width;
+}
+
+void Camera::updateView(float lag)
+{
+    // -------------------------------------------------------------------------
+    // calculate vectors for the view matrix
+    // -------------------------------------------------------------------------
+    
+    // front
+    front.setAngles(interpolate(lag, oldLengthAngle, lengthAngle), interpolate(lag, oldWidthAngle, widthAngle));
+
+    // back
+    back.setInverse(front);
+
+    // right
+    right.set(front);
+    right.cross(0.0f, 1.0f, 0.0f);
+    right.normalize();
+    
+    // left
+    left.setInverse(right);
+    
+    // up
+    up.set(front);
+    up.cross(left);
+    up.normalize();
+    
+    interCamera.set(oldCamera);
+    interCamera.addMul(camera, lag);
+    interCamera.addMul(oldCamera, -lag);
+    
+    view.set(0, 0, right.getX());
+    view.set(0, 1, right.getY());
+    view.set(0, 2, right.getZ());
+    view.set(0, 3, right.dotInverse(interCamera));
+    
+    view.set(1, 0, up.getX());
+    view.set(1, 1, up.getY());
+    view.set(1, 2, up.getZ());
+    view.set(1, 3, up.dotInverse(interCamera));
+    
+    view.set(2, 0, back.getX());
+    view.set(2, 1, back.getY());
+    view.set(2, 2, back.getZ());
+    view.set(2, 3, back.dotInverse(interCamera));
+    
+    view.set(3, 0, 0.0f);
+    view.set(3, 1, 0.0f);
+    view.set(3, 0, 0.0f);
+    view.set(3, 3, 1.0f);
+   
+    // -------------------------------------------------------------------------
+    // calculate vectors for movement
+    // -------------------------------------------------------------------------
+    
+    // front
+    front.setY(0.0f);
+    front.normalize();
+
+    // back
+    back.setInverse(front);
+
+    // right
+    right.set(front);
+    right.cross(0.0f, 1.0f, 0.0f);
+    right.normalize();
+    
+    // left
+    left.setInverse(right);
+
+    // up
+    up.set(0.0f, 1.0f, 0.0f);
+    
+    // down
+    down.setInverse(up);
+    
+    GameEngine::updateView(view);
+}
+
+const Vector3D& Camera::getFront()
+{
+    return front;
+}
+
+const Vector3D& Camera::getBack()
+{
+    return back;
+}
+
+const Vector3D& Camera::getRight()
+{
+    return right;
+}
+
+const Vector3D& Camera::getLeft()
+{
+    return left;
+}
+
+const Vector3D& Camera::getUp()
+{
+    return up;
+}
+
+const Vector3D& Camera::getDown()
+{
+    return down;
+}
+

+ 49 - 0
engine/Camera.h

@@ -0,0 +1,49 @@
+#ifndef CAMERA_H
+#define CAMERA_H
+
+#include "../math/Vector3D.h"
+#include "../math/Matrix3D.h"
+
+class Camera
+{
+public:
+    Camera();
+    Camera(const Camera& orig);
+    virtual ~Camera();
+    
+    void storePosition();
+    void storeAngles();
+    
+    void setPosition(float x, float y, float z);
+    void setAngles(float length, float width);
+    void updateView(float lag);
+    
+    const Vector3D& getFront();
+    const Vector3D& getBack();
+    const Vector3D& getRight();
+    const Vector3D& getLeft();
+    const Vector3D& getUp();
+    const Vector3D& getDown();
+private:
+    Vector3D camera;
+    float lengthAngle;
+    float widthAngle;
+    
+    Vector3D oldCamera;
+    float oldLengthAngle;
+    float oldWidthAngle;
+    
+    Vector3D interCamera;
+    
+    Vector3D front;
+    Vector3D back;
+    Vector3D right;
+    Vector3D left;
+    Vector3D up;
+    Vector3D down;
+    
+    Matrix3D view;
+};
+
+#endif
+

+ 123 - 0
engine/DirectRenderer.cpp

@@ -0,0 +1,123 @@
+#include "GameEngine.h"
+
+DirectRenderer::DirectRenderer()
+{
+}
+
+DirectRenderer::DirectRenderer(const DirectRenderer& orig)
+{
+}
+
+DirectRenderer::~DirectRenderer()
+{
+    glDeleteVertexArrays(1, &vba);
+    glDeleteBuffers(1, &vbo);
+}
+
+void DirectRenderer::init()
+{
+    glGenVertexArrays(1, &vba);
+    glGenBuffers(1, &vbo);
+
+    glBindVertexArray(vba);
+    glBindBuffer(GL_ARRAY_BUFFER, vbo);
+
+    glEnableVertexAttribArray(0);
+    glVertexAttribPointer(0, 3, GL_FLOAT, false, 36, (GLvoid*) 0);
+
+    glEnableVertexAttribArray(1);  
+    glVertexAttribPointer(1, 4, GL_FLOAT, false, 36, (GLvoid*) 12);
+    
+    glEnableVertexAttribArray(2);  
+    glVertexAttribPointer(2, 2, GL_FLOAT, false, 36, (GLvoid*) 28);
+}
+
+void DirectRenderer::prepare()
+{
+    int scale = GameEngine::scale;
+    view.set(0, 0, (2.0f * scale) / GameEngine::width);
+    view.set(1, 1, (-2.0f * scale) / GameEngine::height);
+    view.set(2, 2, (-1.0f * scale) / GameEngine::height);
+    
+    view.set(0, 3, -1.0f);
+    view.set(1, 3, 1.0f);
+    view.set(2, 3, 0.5f);
+    view.set(3, 3, 1.0f);
+
+    GameEngine::updateView(view);
+    glUniformMatrix4fv(GameEngine::unifProjMatrix, 1, 0, proj.getValues());
+}
+
+void DirectRenderer::drawRectangle(float minX, float minY, float maxX, float maxY,
+            float tMinX, float tMinY, float tMaxX, float tMaxY,
+            float r, float g, float b, float a)
+{
+    glBindBuffer(GL_ARRAY_BUFFER, vbo);
+        
+    offset += OBJECT_LENGTH;
+    if(offset + OBJECT_LENGTH >= BUFFER_LENGTH)
+    {
+        offset = 0;
+        glBufferData(GL_ARRAY_BUFFER, BUFFER_LENGTH, NULL, GL_STREAM_DRAW);
+    }
+    float* buffer = (float*) glMapBufferRange(GL_ARRAY_BUFFER, offset, OBJECT_LENGTH, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
+    if(buffer == NULL)
+    {
+        return;
+    }
+
+    buffer[0] = minX;
+    buffer[1] = maxY;
+    buffer[2] = 0.0f;
+    buffer[3] = r;
+    buffer[4] = g;
+    buffer[5] = b;
+    buffer[6] = a;
+    buffer[7] = tMinX;
+    buffer[8] = tMaxY;
+    
+    buffer[9] = maxX;
+    buffer[10] = maxY;
+    buffer[11] = 0.0f;
+    buffer[12] = r;
+    buffer[13] = g;
+    buffer[14] = b;
+    buffer[15] = a;
+    buffer[16] = tMaxX;
+    buffer[17] = tMaxY;
+    
+    buffer[18] = minX;
+    buffer[19] = minY;
+    buffer[20] = 0.0f;
+    buffer[21] = r;
+    buffer[22] = g;
+    buffer[23] = b;
+    buffer[24] = a;
+    buffer[25] = tMinX;
+    buffer[26] = tMinY;
+    
+    buffer[27] = maxX;
+    buffer[28] = minY;
+    buffer[29] = 0.0f;
+    buffer[30] = r;
+    buffer[31] = g;
+    buffer[32] = b;
+    buffer[33] = a;
+    buffer[34] = tMaxX;
+    buffer[35] = tMinY;
+
+    glUnmapBuffer(GL_ARRAY_BUFFER);
+
+    glBindVertexArray(vba);
+    glDrawArrays(GL_TRIANGLE_STRIP, offset / (OBJECT_LENGTH / 4), 4);
+}
+
+void DirectRenderer::drawColoredRectangle(float minX, float minY, float maxX, float maxY, float r, float g, float b, float a)
+{
+    drawRectangle(minX, minY, maxX, maxY, 0.0f, 0.0f, 0.0f, 0.0f, r, g, b, a);
+}
+
+void DirectRenderer::drawTexturedRectangle(float minX, float minY, float maxX, float maxY, float tMinX, float tMinY, float tMaxX, float tMaxY)
+{
+    drawRectangle(minX, minY, maxX, maxY, tMinX, tMinY, tMaxX, tMaxY, 0.0f, 0.0f, 0.0f, 0.0f);
+}

+ 493 - 0
engine/GameEngine.cpp

@@ -0,0 +1,493 @@
+#include "GameEngine.h"
+#include "Key.h"
+#include "Mouse.h"
+#include <cmath>
+
+InitFunction GameEngine::init = nullptr;
+TickFunction GameEngine::tick = nullptr;
+RenderTickFunction GameEngine::renderTick = nullptr;
+
+GLuint GameEngine::vShader = 0;
+GLuint GameEngine::fShader = 0;
+
+GLFWwindow* GameEngine::window = nullptr;
+GLuint GameEngine::program = 0;
+
+int GameEngine::scale = 1;
+int GameEngine::width = 0;
+int GameEngine::height = 0;
+float GameEngine::fovY = 60;
+float GameEngine::nearClip = 0.1f;
+float GameEngine::farClip = 1000.0f;
+Matrix3D GameEngine::proj;
+
+Camera GameEngine::camera;
+
+DirectRenderer GameEngine::directRenderer;
+
+GLint GameEngine::unifProjMatrix = 0;
+GLint GameEngine::unifViewMatrix = 0;
+GLint GameEngine::unifUseTexture = 0;
+GLint GameEngine::unifUseColor = 0;
+GLint GameEngine::unifUseMixColor = 0;
+GLint GameEngine::unifMixColorLoc = 0;
+
+Camera& GameEngine::getCamera()
+{
+    return camera;
+}
+
+DirectRenderer& GameEngine::getDirectRenderer()
+{
+    return directRenderer;
+}
+
+void GameEngine::onKeyEvent(GLFWwindow* w, int key, int scancode, int action, int mods)
+{
+    if(action == GLFW_RELEASE)
+    {
+        if(key == GLFW_KEY_ESCAPE)
+        {
+            //activeFocus = 0;
+            glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+        }
+        Key::release(key);
+    }
+    else if(action == GLFW_PRESS)
+    {
+        Key::press(key);
+    }
+}
+
+void GameEngine::onMouseClick(GLFWwindow* w, int button, int action, int mods)
+{
+    if(action == GLFW_PRESS)
+    {
+        /*if(!activeFocus)
+        {
+            glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
+            oldMouseX = 0;
+            oldMouseY = 0;
+            activeFocus = 1;
+        }
+        else
+        {*/
+            Mouse::press(button);
+        //}
+    }
+    else if(action == GLFW_RELEASE)
+    {
+        Mouse::release(button);
+    }
+}
+
+/*static void onMouseMove(GLFWwindow* w, double x, double y)
+{
+    if(activeFocus)
+    {
+        if(oldMouseX == 0 && oldMouseY == 0)
+        {
+            oldMouseX = x;
+            oldMouseY = y;
+        }
+        else
+        {
+            mouseMove(x - oldMouseX, y - oldMouseY);
+            oldMouseX = x;
+            oldMouseY = y;
+        }
+    }
+}*/
+
+void GameEngine::onWindowResize(GLFWwindow* w, int width, int height)
+{
+    glViewport(0, 0, width, height);
+    GameEngine::width = width;
+    GameEngine::height = height;
+    updateScale();
+}
+
+GLchar* GameEngine::readFile(const char* name)
+{
+    ifstream in;
+    in.open(name);
+    if(!in.fail())
+    {
+        int size = 128;
+        int index = 0;
+        GLchar* content = new GLchar[size];
+        
+        while(true)
+        {
+            GLchar c = in.get();
+            if(in.eof())
+            {
+                break;
+            }
+            if(index >= size - 1)
+            {
+                GLchar* newContent = new GLchar[size * 2];
+                memcpy(newContent, content, size);
+                size *= 2;
+                delete[] content;
+                content = newContent;
+            }
+            content[index] = c;
+            index++;
+        }
+        
+        content[index] = '\0';
+        index++;
+        
+        in.close();
+        return content;
+    }
+    return nullptr;
+}
+
+bool GameEngine::checkShaderErrors(const char* name, GLuint shader)
+{
+    bool returnValue = false;
+    
+    cout << "compiling " << name << " shader ..." << endl;
+    GLenum error = glGetError();
+    if(error)
+    {
+        cout << "error: " << glGetError() << endl;
+        returnValue = true;
+    }
+    else
+    {
+        cout << "no error occured ..." << endl;
+    }
+    
+    GLint compiled[1];
+    glGetShaderiv(shader, GL_COMPILE_STATUS, compiled);
+    if(compiled[0])
+    {
+        cout << name << " shader successfully compiled" << endl;
+    }
+    else
+    {
+        cout << name << "compiling of " << name << " failed:" << endl;
+        GLchar buffer[512];
+        GLsizei bufferSize = 512;
+        GLsizei charsUsed = 0;
+        glGetShaderInfoLog(shader, bufferSize, &charsUsed, buffer);
+        // glGetProgramInfoLog should be null terminated ...
+        buffer[bufferSize - 1] = '\0';
+        cout << buffer << endl;
+        returnValue = true;
+    }
+    return returnValue;
+}
+
+GLuint GameEngine::compileProgram(const GLchar* vertex, const GLchar* fragment)
+{
+    vShader = glCreateShader(GL_VERTEX_SHADER);
+    glShaderSource(vShader, 1, &vertex, nullptr);
+    glCompileShader(vShader);
+
+    if(checkShaderErrors("vertex", vShader))
+    {
+        return 0;
+    }    
+    
+    fShader = glCreateShader(GL_FRAGMENT_SHADER);
+    glShaderSource(fShader, 1, &fragment, nullptr);
+    glCompileShader(fShader);
+
+    if(checkShaderErrors("fragment", fShader))
+    {
+        return 0;
+    }    
+
+    GLuint program = glCreateProgram();
+    glAttachShader(program, vShader);
+    glAttachShader(program, fShader);
+    glLinkProgram(program);
+    
+    cout << "linking shaders to program ..." << endl;
+
+    GLenum error = glGetError();
+    if(error)
+    {
+        cout << "error: " << glGetError() << endl;
+        return 0;
+    }
+    else
+    {
+        cout << "no error occured ..." << endl;
+    }
+
+    GLint compiled[1];
+    glGetProgramiv(program, GL_LINK_STATUS, compiled);
+    if(compiled[0])
+    {
+        cout << "shaders successfully linked" << endl;
+    }
+    else
+    {
+        cout << "linking of shaders failed:" << endl;
+        GLchar buffer[512];
+        GLsizei bufferSize = 512;
+        GLsizei charsUsed = 0;
+        glGetProgramInfoLog(program, bufferSize, &charsUsed, buffer);
+        // glGetProgramInfoLog should be null terminated ...
+        buffer[bufferSize - 1] = '\0';
+        cout << buffer << endl;
+        return 0;
+    }
+    
+    glUseProgram(program);
+    return program;
+}
+
+GLuint GameEngine::createProgram()
+{
+    GLchar* vertex = readFile("shader/vertex.vs");
+    if(vertex == nullptr)
+    {
+        cout << "cannot read vertex.vs" << endl;
+        return 0;
+    }
+    GLchar* fragment = readFile("shader/fragment.fs");
+    if(fragment == nullptr)
+    {
+        cout << "cannot read fragment.fs" << endl;
+        delete[] vertex;
+        return 0;
+    }
+    
+    GLuint program = compileProgram(vertex, fragment);
+    delete[] vertex;
+    delete[] fragment;
+    return program;
+}
+
+void GameEngine::updateProjection()
+{
+    float q = 1.0f / tanf((0.5f * fovY) * M_PI / 180.0f);
+
+    proj.set(0, 0, (q * height) / width);
+    proj.set(1, 1, q);
+    proj.set(2, 2, (nearClip + farClip) / (nearClip - farClip));
+    proj.set(3, 2, -1.0f);
+    proj.set(2, 3, (2.0f * nearClip * farClip) / (nearClip - farClip));
+    proj.set(3, 3, 0);   
+    
+    glUniformMatrix4fv(unifProjMatrix, 1, 0, proj.getValues());
+}
+
+void GameEngine::updateView(Matrix3D& m)
+{
+    glUniformMatrix4fv(unifViewMatrix, 1, 0, m.getValues());
+}
+
+void GameEngine::onInit()
+{
+    Key::init();
+    Mouse::init();
+    init();
+    
+    unifProjMatrix = glGetUniformLocation(program, "projMatrix");
+    unifViewMatrix = glGetUniformLocation(program, "viewMatrix");
+    unifUseTexture = glGetUniformLocation(program, "useTexture");
+    unifUseColor = glGetUniformLocation(program, "useColor");
+    unifUseMixColor = glGetUniformLocation(program, "useMixColor");
+    unifMixColorLoc = glGetUniformLocation(program, "mixColor");
+    
+    directRenderer.init();
+}
+
+void GameEngine::onTick()
+{
+    tick();
+    Key::tick();
+    Mouse::tick();
+}
+
+void GameEngine::start(int width, int height, const char* name, InitFunction init, TickFunction tick, RenderTickFunction renderTick)
+{    
+    GameEngine::width = width;
+    GameEngine::height = height;
+    GameEngine::init = init;
+    GameEngine::tick = tick;
+    GameEngine::renderTick = renderTick;
+    updateScale();
+    
+    if(!glfwInit())
+    {
+        cout << "could not initialize GLFW" << endl;
+        return;
+    }
+
+    glfwDefaultWindowHints();
+    glfwWindowHint(GLFW_VISIBLE, 0);
+    glfwWindowHint(GLFW_RESIZABLE, 1);
+    window = glfwCreateWindow(width, height, name, nullptr, nullptr);
+    if(!window)
+    {
+        cout << "could not create window" << endl;
+        glfwTerminate();
+        return;
+    }
+
+    glfwSetKeyCallback(window, onKeyEvent);
+    glfwSetFramebufferSizeCallback(window, onWindowResize);
+    glfwSetMouseButtonCallback(window, onMouseClick);
+    //glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
+    //glfwSetCursorPosCallback(window, onMouseMove);
+
+    glfwMakeContextCurrent(window);
+    glfwSwapInterval(1);
+
+    glfwShowWindow(window);
+
+    GLenum err = glewInit();
+    if(GLEW_OK != err)
+    {
+        cout << "could not initialize GLEW: " << glewGetErrorString(err) << endl;
+        return;
+    }
+    cout << "Status: Using GLEW " << glewGetString(GLEW_VERSION) << endl;
+
+    program = createProgram();
+    if(program == 0)
+    {
+        onTerm();
+        return;
+    }
+
+    glEnable(GL_CULL_FACE);
+    glEnable(GL_DEPTH_TEST);
+    glDepthFunc(GL_LEQUAL);
+    onInit();
+    
+    uint64_t newTime = glfwGetTimerValue();
+    uint64_t oldTime = newTime;
+    uint64_t lag = 0;
+    while(!glfwWindowShouldClose(window))
+    {
+        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+        oldTime = newTime;
+        newTime = glfwGetTimerValue();
+        lag += newTime - oldTime;
+
+        int ticksPerFrame = 0;
+        while(lag >= NANOS_PER_TICK)
+        {
+            lag -= NANOS_PER_TICK;
+
+            onTick();
+            ticksPerFrame++;
+
+            if(ticksPerFrame >= MAX_TICKS_PER_FRAME)
+            {
+                long skip = lag / NANOS_PER_TICK;
+                lag -= skip * NANOS_PER_TICK;
+                if(skip > 0)
+                {
+                    cout << "skipped " << skip << " game ticks " << lag << endl;
+                }
+                break;
+            }
+        }
+
+        updateProjection();
+        renderTick((float) lag / NANOS_PER_TICK);
+
+        glfwSwapBuffers(window);
+        glfwPollEvents();
+    }
+    
+    onTerm();
+}
+
+void GameEngine::onTerm()
+{
+    if(vShader != 0)
+    {
+        glDeleteShader(vShader);
+    }
+    if(fShader != 0)
+    {
+        glDeleteShader(fShader);
+    }
+    if(program != 0)
+    {
+        glDeleteProgram(program);
+    }
+    glfwDestroyWindow(window);
+    glfwTerminate();
+}
+
+void GameEngine::setTextureEnabled(bool use)
+{
+    glUniform1i(unifUseTexture, use);
+}
+
+void GameEngine::setColorEnabled(bool use)
+{
+    glUniform1i(unifUseColor, use);
+}
+
+void GameEngine::setMixColorEnabled(bool use)
+{
+    glUniform1i(unifUseMixColor, use);
+}
+
+void GameEngine::setMixColor(float r, float g, float b, float a)
+{
+    glUniform4f(unifMixColorLoc, r, g, b, a);
+}
+
+void GameEngine::printError()
+{
+    GLenum error = glGetError();
+    switch(error)
+    {
+        case GL_NO_ERROR: 
+            cout << "> No error has been recorded." << endl;
+            break;
+        case GL_INVALID_ENUM: 
+            cout << "> An unacceptable value is specified for an enumerated argument." << endl;
+            break;
+        case GL_INVALID_VALUE: 
+            cout << "> A numeric argument is out of range." << endl;
+            break;
+        case GL_INVALID_OPERATION: 
+            cout << "> The specified operation is not allowed in the current state." << endl;
+            break;
+        case GL_INVALID_FRAMEBUFFER_OPERATION: 
+            cout << "> The framebuffer object is not complete." << endl;
+            break;
+        case GL_OUT_OF_MEMORY: 
+            cout << "> There is not enough memory left to execute the command." << endl;
+            break;
+        case GL_STACK_UNDERFLOW: 
+            cout << "> An attempt has been made to perform an operation that would cause an internal stack to underflow." << endl;
+            break;
+        case GL_STACK_OVERFLOW: 
+            cout << "> An attempt has been made to perform an operation that would cause an internal stack to overflow." << endl;
+            break;
+        default:
+            cout << "> Unknown OpenGL error: " << error << endl;
+    }
+}
+
+void GameEngine::stop()
+{
+    glfwSetWindowShouldClose(window, 1);
+}
+
+void GameEngine::updateScale()
+{
+    scale = 1;
+    while(width / (scale + 1) >= 400 && height / (scale + 1) >= 300)
+    {
+        scale++;
+    }
+}
+

+ 128 - 0
engine/GameEngine.h

@@ -0,0 +1,128 @@
+#ifndef GAMEENGINE_H
+#define GAMEENGINE_H
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+#include <iostream>
+#include <string>
+#include <fstream>
+#include <cstring>
+#include "../math/Matrix3D.h"
+#include "Camera.h"
+#include "Texture.h"
+
+using namespace std;
+
+static const uint64_t NANOS_PER_TICK = 50000000;
+static const int MAX_TICKS_PER_FRAME = 5;
+
+typedef void (*InitFunction) ();
+typedef void (*TickFunction) ();
+typedef void (*RenderTickFunction) (float);
+
+class DirectRenderer;
+
+class GameEngine
+{
+public:
+    static void start(int width, int height, const char* name, InitFunction init, TickFunction tick, RenderTickFunction renderTick);
+    static Camera& getCamera();
+    static DirectRenderer& getDirectRenderer();
+
+    static void setTextureEnabled(bool use);
+    static void setColorEnabled(bool use);
+    static void setMixColorEnabled(bool use);
+    static void setMixColor(float r, float g, float b, float a);
+
+    static void printError();
+    static void stop();
+
+    friend Camera;
+    friend Texture;
+    friend DirectRenderer;
+private:
+    GameEngine();
+
+    static void onKeyEvent(GLFWwindow* w, int key, int scancode, int action, int mods);
+    static void onMouseClick(GLFWwindow* w, int button, int action, int mods);
+    static void onWindowResize(GLFWwindow* w, int width, int height);
+
+    static GLchar* readFile(const char* name);
+    static bool checkShaderErrors(const char* name, GLuint shader);
+    static GLuint compileProgram(const GLchar* vertex, const GLchar* fragment);
+    static GLuint createProgram();
+
+    static void updateProjection();
+    static void updateView(Matrix3D& m);
+
+    static void onInit();
+    static void onTick();
+    static void onTerm();
+
+    static void updateScale();
+
+    static InitFunction init;
+    static TickFunction tick;
+    static RenderTickFunction renderTick;
+
+    static GLuint vShader;
+    static GLuint fShader;
+
+    static GLFWwindow* window;
+    static GLuint program;
+
+    static int scale;
+    static int width;
+    static int height;
+    static float fovY;
+    static float nearClip;
+    static float farClip;
+    static Matrix3D proj;
+
+    static Camera camera;
+
+    static DirectRenderer directRenderer;
+
+    // uniforms
+    static GLint unifProjMatrix;
+    static GLint unifViewMatrix;
+    static GLint unifUseTexture;
+    static GLint unifUseColor;
+    static GLint unifUseMixColor;
+    static GLint unifMixColorLoc;
+};
+
+class DirectRenderer
+{
+public:
+    DirectRenderer();
+    DirectRenderer(const DirectRenderer& orig);
+    virtual ~DirectRenderer();
+
+    void prepare();
+    void drawRectangle(float minX, float minY, float maxX, float maxY,
+            float tMinX, float tMinY, float tMaxX, float tMaxY,
+            float r, float g, float b, float a);
+    void drawColoredRectangle(float minX, float minY, float maxX, float maxY,
+            float r, float g, float b, float a);
+    void drawTexturedRectangle(float minX, float minY, float maxX, float maxY,
+            float tMinX, float tMinY, float tMaxX, float tMaxY);
+
+    friend GameEngine;
+private:
+    void init();
+
+    static const int OBJECT_LENGTH = 144;
+    static const int BUFFER_LENGTH = 256 * 1024 * OBJECT_LENGTH;
+
+    GLuint vba = 0;
+    GLuint vbo = 0;
+
+    unsigned int offset = BUFFER_LENGTH - OBJECT_LENGTH;
+
+    Matrix3D view;
+    Matrix3D proj;
+};
+
+#endif
+

+ 75 - 0
engine/Key.cpp

@@ -0,0 +1,75 @@
+#include "Key.h"
+
+Key Key::keyArray[Key::NUMBER_OF_KEYS];
+int Key::mappingArray[Key::NUMBER_OF_KEYS];
+
+Key::Key()
+{
+}
+
+bool Key::isDown(int mapping)
+{
+    return isInRange(mapping) && keyArray[mappingArray[mapping]].down;
+}
+
+bool Key::isReleased(int mapping)
+{
+    return isInRange(mapping) && keyArray[mappingArray[mapping]].shouldRelease;
+}
+
+unsigned int Key::getDownTime(int mapping)
+{
+    bool m = isInRange(mapping);
+    return m * keyArray[mappingArray[mapping * m]].downTime;
+}
+
+void Key::resetDownTime(int mapping)
+{
+    keyArray[mappingArray[mapping * isInRange(mapping)]].downTime = 0;
+}
+
+bool Key::map(int mapping, int key)
+{
+    bool b = isInRange(mapping) && isInRange(key);
+    mappingArray[mapping * b] = b * key;
+}
+
+bool Key::isInRange(int i)
+{
+    return i >= 0 && i < NUMBER_OF_KEYS;
+}
+
+void Key::init()
+{
+    for(int i = 0; i < NUMBER_OF_KEYS; i++)
+    {
+        mappingArray[i] = 0;
+    }
+}
+
+void Key::tick()
+{
+    for(int i = 0; i < NUMBER_OF_KEYS; i++)
+    {
+        keyArray[i].downTime += keyArray[i].down;
+        
+        keyArray[i].down = keyArray[i].down && !keyArray[i].shouldRelease;
+        keyArray[i].downTime *= !keyArray[i].shouldRelease;
+        keyArray[i].shouldRelease = false;
+    }
+}
+
+bool Key::press(int key)
+{
+    int index = isInRange(key) * key;
+    keyArray[index].down = true;
+    keyArray[index].shouldRelease = false;
+}
+
+bool Key::release(int key)
+{
+    int index = isInRange(key) * key;
+    keyArray[index].shouldRelease = true;
+}
+
+

+ 35 - 0
engine/Key.h

@@ -0,0 +1,35 @@
+#ifndef KEY_H
+#define KEY_H
+
+#include "GameEngine.h"
+
+class Key
+{
+public:
+    static bool isDown(int mapping);
+    static bool isReleased(int mapping);
+    static unsigned int getDownTime(int mapping);
+    static void resetDownTime(int mapping);
+    static bool map(int mapping, int key);
+    
+    friend GameEngine;
+private:
+    Key();
+    
+    static const int NUMBER_OF_KEYS = GLFW_KEY_LAST + 1;
+    static bool isInRange(int i);
+    static void init();
+    static void tick();
+    static bool press(int key);
+    static bool release(int key);
+    
+    bool down = false;
+    bool shouldRelease = false;
+    unsigned int downTime = 0;
+    
+    static Key keyArray[NUMBER_OF_KEYS];
+    static int mappingArray[NUMBER_OF_KEYS];
+};
+
+#endif
+

+ 81 - 0
engine/Mesh.cpp

@@ -0,0 +1,81 @@
+#include "Mesh.h"
+#include <cstring>
+#include <iostream>
+
+using namespace std;
+
+Mesh::Mesh()
+{
+    data = new float[dataSize * 7];
+}
+
+Mesh::Mesh(const Mesh& orig)
+{
+}
+
+Mesh::~Mesh()
+{
+    delete[] data;
+    glDeleteVertexArrays(1, &vba);
+    glDeleteBuffers(1, &vbo);
+}
+
+void Mesh::init()
+{
+    glGenVertexArrays(1, &vba);
+    glBindVertexArray(vba);
+    
+    glGenBuffers(1, &vbo);
+    glBindBuffer(GL_ARRAY_BUFFER, vbo);
+
+    glVertexAttribPointer(0, 3, GL_FLOAT, 0, 28, (GLvoid*) 0);
+    glEnableVertexAttribArray(0);
+
+    glVertexAttribPointer(1, 4, GL_FLOAT, 0, 28, (GLvoid*) 12);
+    glEnableVertexAttribArray(1);       
+}
+
+void Mesh::addPoint(float x, float y, float z, float r, float g, float b, float a)
+{
+    if(vertices >= dataSize)
+    {
+        float* newData = new float[dataSize * 2 * 7];
+        memcpy(newData, data, sizeof(float) * dataSize * 7);
+        delete[] data;
+        data = newData;
+        dataSize *= 2;
+    }
+    unsigned int index = vertices * 7;
+    data[index] = x;
+    data[index + 1] = y;
+    data[index + 2] = z;
+    data[index + 3] = r;
+    data[index + 4] = g;
+    data[index + 5] = b;
+    data[index + 6] = a;
+    
+    vertices++;
+}
+
+void Mesh::build()
+{
+    glBindBuffer(GL_ARRAY_BUFFER, vbo);
+   
+    /*for(int i = 0; i < vertices; i++)
+    {
+        int index = i * 7;
+        cout << data[index] << " " << data[index + 1] << " " << data[index + 2] 
+                << " " << data[index + 3] << " " << data[index + 4]  << " " 
+                << data[index + 5] << " " << data[index + 6] << endl;
+    }*/
+    
+    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 7 * vertices, data, GL_STATIC_DRAW);
+}
+
+void Mesh::draw()
+{
+    glBindVertexArray(vba);
+    glBindBuffer(GL_ARRAY_BUFFER, vbo);
+    glDrawArrays(GL_TRIANGLES, 0, vertices);
+}
+

+ 28 - 0
engine/Mesh.h

@@ -0,0 +1,28 @@
+#ifndef MESH_H
+#define MESH_H
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+
+class Mesh
+{
+public:
+    Mesh();
+    Mesh(const Mesh& orig);
+    virtual ~Mesh();
+    
+    void init();
+    void addPoint(float x, float y, float z, float r, float g, float b, float a);
+    void build();
+    void draw();
+private:
+    GLuint vba = 0;
+    GLuint vbo = 0;
+    
+    unsigned int vertices = 0;
+    unsigned int dataSize = 3;
+    float* data = nullptr;
+};
+
+#endif
+

+ 75 - 0
engine/Mouse.cpp

@@ -0,0 +1,75 @@
+#include "Mouse.h"
+
+Mouse Mouse::mouseArray[Mouse::NUMBER_OF_BUTTONS];
+int Mouse::mappingArray[Mouse::NUMBER_OF_BUTTONS];
+
+Mouse::Mouse()
+{
+}
+
+bool Mouse::isDown(int mapping)
+{
+    return isInRange(mapping) && mouseArray[mappingArray[mapping]].down;
+}
+
+bool Mouse::isReleased(int mapping)
+{
+    return isInRange(mapping) && mouseArray[mappingArray[mapping]].shouldRelease;
+}
+
+unsigned int Mouse::getDownTime(int mapping)
+{
+    bool m = isInRange(mapping);
+    return m * mouseArray[mappingArray[mapping * m]].downTime;
+}
+
+void Mouse::resetDownTime(int mapping)
+{
+    mouseArray[mappingArray[mapping * isInRange(mapping)]].downTime = 0;
+}
+
+bool Mouse::map(int mapping, int mouse)
+{
+    bool b = isInRange(mapping) && isInRange(mouse);
+    mappingArray[mapping * b] = b * mouse;
+}
+
+bool Mouse::isInRange(int i)
+{
+    return i >= 0 && i < NUMBER_OF_BUTTONS;
+}
+
+void Mouse::init()
+{
+    for(int i = 0; i < NUMBER_OF_BUTTONS; i++)
+    {
+        mappingArray[i] = 0;
+    }
+}
+
+void Mouse::tick()
+{
+    for(int i = 0; i < NUMBER_OF_BUTTONS; i++)
+    {
+        mouseArray[i].downTime += mouseArray[i].down;
+        
+        mouseArray[i].down = mouseArray[i].down && !mouseArray[i].shouldRelease;
+        mouseArray[i].downTime *= !mouseArray[i].shouldRelease;
+        mouseArray[i].shouldRelease = false;
+    }
+}
+
+bool Mouse::press(int mouse)
+{
+    int index = isInRange(mouse) * mouse;
+    mouseArray[index].down = true;
+    mouseArray[index].shouldRelease = false;
+}
+
+bool Mouse::release(int mouse)
+{
+    int index = isInRange(mouse) * mouse;
+    mouseArray[index].shouldRelease = true;
+}
+
+

+ 35 - 0
engine/Mouse.h

@@ -0,0 +1,35 @@
+#ifndef MOUSE_H
+#define MOUSE_H
+
+#include "GameEngine.h"
+
+class Mouse
+{
+public:
+    static bool isDown(int mapping);
+    static bool isReleased(int mapping);
+    static unsigned int getDownTime(int mapping);
+    static void resetDownTime(int mapping);
+    static bool map(int mapping, int key);
+    
+    friend GameEngine;
+private:
+    Mouse();
+    
+    static const int NUMBER_OF_BUTTONS = GLFW_MOUSE_BUTTON_LAST + 1;
+    static bool isInRange(int i);
+    static void init();
+    static void tick();
+    static bool press(int button);
+    static bool release(int button);
+    
+    bool down = false;
+    bool shouldRelease = false;
+    unsigned int downTime = 0;
+    
+    static Mouse mouseArray[NUMBER_OF_BUTTONS];
+    static int mappingArray[NUMBER_OF_BUTTONS];
+};
+
+#endif
+

+ 167 - 0
engine/Texture.cpp

@@ -0,0 +1,167 @@
+#include "Texture.h"
+#include "GameEngine.h"
+#include <png.h>
+
+using namespace std;
+
+GLuint Texture::boundTexture = 0; 
+
+Texture::Texture()
+{
+}
+
+Texture::Texture(const Texture& orig)
+{
+}
+
+Texture::~Texture()
+{
+    if(data != nullptr)
+    {
+        delete[] data;
+    }
+    if(texture != 0)
+    {
+        glDeleteTextures(1, &texture);
+    }
+}
+
+bool Texture::load(const char* path)
+{
+    if(isLoaded)
+    {
+        return false;
+    }
+    isLoaded = true;
+    FILE* file = fopen(path, "r");
+    if(file == NULL)
+    {
+        cerr << "image '" << path << "' does not exist" << endl;
+        return false;
+    }
+    bool b = load(path, file);
+    fclose(file);
+    if(b)
+    {
+        initGL();
+    }
+    return b;
+}
+
+bool Texture::load(const char* path, FILE* file)
+{
+    // check signature of png
+    unsigned char buffer[8];
+    if(fread(buffer, sizeof(char), 8, file) != 8)
+    {
+        cerr << "cannot read signature of image '" << path << "'" << endl;
+        return false;
+    }
+    
+    if(png_sig_cmp(buffer, 0, 8))        
+    {
+        cerr << "file '" << path << "' is not an image" << endl;
+        return false;
+    }
+    
+    // create structures for data
+    png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if(png == NULL)
+    {
+        cerr << "cannot create image data structure" << endl;
+        return false;
+    }
+    
+    png_infop info = png_create_info_struct(png);
+    if(info == NULL)
+    {
+       cerr << "cannot create image info structure" << endl;
+       return false;
+    }
+
+    unsigned int** rowPointers = NULL;
+    
+    // set callback for errors
+    if(setjmp(png_jmpbuf(png)))
+    {
+        if(rowPointers != NULL)
+        {
+            png_free(png, rowPointers);
+        }
+        png_destroy_read_struct(&png, &info, NULL);
+        cerr << "image '" << path << "' has used error callback" << endl;
+        return false;
+    }
+
+    // set reading function
+    png_init_io(png, file);
+    // notify about already used signature bytes
+    png_set_sig_bytes(png, 8);
+    
+    // read info data
+    png_read_info(png, info);
+    width = png_get_image_width(png, info);
+    height = png_get_image_height(png, info);
+    
+    // read image data
+    data = new unsigned int[width * height];
+    
+    // allocate and set row pointer to correct places in block
+    rowPointers = (unsigned int**) png_malloc(png, height * (sizeof(unsigned int*)));
+    for(int i = 0; i < height; i++)
+    {
+        rowPointers[i] = (data + i * width);
+    }
+    png_set_rows(png, info, (png_bytepp) rowPointers);
+    
+    png_read_image(png, (png_bytepp) rowPointers);
+    
+    png_free(png, rowPointers);
+    png_destroy_read_struct(&png, &info, NULL);
+    return true;
+}
+
+void Texture::initGL()
+{
+    glActiveTexture(GL_TEXTURE0);
+    glGenTextures(1, &texture);
+    glBindTexture(GL_TEXTURE_2D, texture);
+    
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    
+    /*for(int i = 0; i < width * height; i++)
+    {
+        if(data[i] != 0)
+        {
+            cout << "X";
+        }
+        else
+        {
+            cout << " ";
+        }
+        
+        if(i != 0 && i % width == 0)
+        {
+            cout << endl;
+        }
+    }*/
+    
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
+    delete[] data;
+    data = nullptr;
+
+    glGenerateMipmap(GL_TEXTURE_2D);
+}
+
+void Texture::bind()
+{
+    if(boundTexture != texture)
+    {
+        boundTexture = texture;
+        glBindTexture(GL_TEXTURE_2D, texture);
+    }
+}
+

+ 33 - 0
engine/Texture.h

@@ -0,0 +1,33 @@
+#ifndef TEXTURE_H
+#define TEXTURE_H
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+#include <iostream>
+
+class Texture
+{
+public:
+    Texture();
+    Texture(const Texture& orig);
+    virtual ~Texture();
+    
+    bool load(const char* path);
+    void bind();
+private:
+    bool load(const char* path, FILE* file);
+    void initGL();
+    
+    bool isLoaded = false;
+    
+    unsigned int width = 0;
+    unsigned int height = 0;
+    unsigned int* data = nullptr;
+    
+    static GLuint boundTexture; 
+    GLuint texture = 0;
+};
+
+#endif
+
+

+ 79 - 0
engine/TextureMesh.cpp

@@ -0,0 +1,79 @@
+#include "TextureMesh.h"
+#include <cstring>
+#include <iostream>
+
+using namespace std;
+
+TextureMesh::TextureMesh()
+{
+    data = new float[dataSize * 5];
+}
+
+TextureMesh::TextureMesh(const TextureMesh& orig)
+{
+}
+
+TextureMesh::~TextureMesh()
+{
+    delete[] data;
+    glDeleteVertexArrays(1, &vba);
+    glDeleteBuffers(1, &vbo);
+}
+
+void TextureMesh::init()
+{
+    glGenVertexArrays(1, &vba);
+    glBindVertexArray(vba);
+    
+    glGenBuffers(1, &vbo);
+    glBindBuffer(GL_ARRAY_BUFFER, vbo);
+
+    glVertexAttribPointer(0, 3, GL_FLOAT, 0, 20, (GLvoid*) 0);
+    glEnableVertexAttribArray(0);
+
+    glVertexAttribPointer(2, 2, GL_FLOAT, 0, 20, (GLvoid*) 12);
+    glEnableVertexAttribArray(2);       
+}
+
+void TextureMesh::addPoint(float x, float y, float z, float tx, float ty)
+{
+    if(vertices >= dataSize)
+    {
+        float* newData = new float[dataSize * 2 * 5];
+        memcpy(newData, data, sizeof(float) * dataSize * 5);
+        delete[] data;
+        data = newData;
+        dataSize *= 2;
+    }
+    unsigned int index = vertices * 5;
+    data[index] = x;
+    data[index + 1] = y;
+    data[index + 2] = z;
+    data[index + 3] = tx;
+    data[index + 4] = ty;
+    
+    vertices++;
+}
+
+void TextureMesh::build()
+{
+    glBindBuffer(GL_ARRAY_BUFFER, vbo);
+   
+    /*for(int i = 0; i < vertices; i++)
+    {
+        int index = i * 7;
+        cout << data[index] << " " << data[index + 1] << " " << data[index + 2] 
+                << " " << data[index + 3] << " " << data[index + 4]  << " " 
+                << data[index + 5] << " " << data[index + 6] << endl;
+    }*/
+    
+    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 5 * vertices, data, GL_STATIC_DRAW);
+}
+
+void TextureMesh::draw()
+{
+    glBindVertexArray(vba);
+    glBindBuffer(GL_ARRAY_BUFFER, vbo);
+    glDrawArrays(GL_TRIANGLES, 0, vertices);
+}
+

+ 30 - 0
engine/TextureMesh.h

@@ -0,0 +1,30 @@
+#ifndef TEXTUREMESH_H
+#define TEXTUREMESH_H
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+
+class TextureMesh
+{
+public:
+    TextureMesh();
+    TextureMesh(const TextureMesh& orig);
+    virtual ~TextureMesh();
+    
+    void init();
+    void addPoint(float x, float y, float z, float tx, float ty);
+    void build();
+    void draw();
+private:
+    GLuint vba = 0;
+    GLuint vbo = 0;
+    
+    unsigned int vertices = 0;
+    unsigned int dataSize = 3;
+    float* data = nullptr;
+};
+
+#endif
+
+
+

+ 7 - 0
engine/Utils.cpp

@@ -0,0 +1,7 @@
+#include "Utils.h"
+
+float interpolate(float lag, float from, float to)
+{
+    return from + lag * (to - from);
+}
+

+ 7 - 0
engine/Utils.h

@@ -0,0 +1,7 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+float interpolate(float lag, float from, float to);
+
+#endif
+

+ 245 - 0
math/Matrix3D.cpp

@@ -0,0 +1,245 @@
+#include "Matrix3D.h"
+#include <cstring>
+#include <cmath>
+
+Matrix3D::Matrix3D()
+{
+    setToIdentity();
+}
+
+Matrix3D::Matrix3D(const Matrix3D& orig)
+{
+}
+
+Matrix3D::~Matrix3D()
+{
+}
+
+void Matrix3D::setToIdentity()
+{
+    data[0] = 1.0f;
+    data[1] = 0.0f;
+    data[2] = 0.0f;
+    data[3] = 0.0f;
+    data[4] = 0.0f;
+    data[5] = 1.0f;
+    data[6] = 0.0f;
+    data[7] = 0.0f;
+    data[8] = 0.0f;
+    data[9] = 0.0f;
+    data[10] = 1.0f;
+    data[11] = 0.0f;
+    data[12] = 0.0f;
+    data[13] = 0.0f;
+    data[14] = 0.0f;
+    data[15] = 1.0f;
+}
+
+void Matrix3D::set(const Matrix3D& m)
+{
+    memcpy(data, m.data, sizeof(float) * 16);
+}
+
+void Matrix3D::set(int row, int col, float value)
+{
+    data[row + (col << 2)] = value;
+}
+
+float Matrix3D::get(int row, int col) const
+{
+    return data[row + (col << 2)];
+}
+
+const float* Matrix3D::getValues() const
+{
+    return data;
+}
+
+void Matrix3D::mul(const Matrix3D& m)
+{
+    float mNew[16];
+    mNew[0] = data[0] * m.data[0] + data[4] * m.data[1] + data[8] * m.data[2] + data[12] * m.data[3];
+    mNew[1] = data[1] * m.data[0] + data[5] * m.data[1] + data[9] * m.data[2] + data[13] * m.data[3];
+    mNew[2] = data[2] * m.data[0] + data[6] * m.data[1] + data[10] * m.data[2] + data[14] * m.data[3];
+    mNew[3] = data[3] * m.data[0] + data[7] * m.data[1] + data[11] * m.data[2] + data[15] * m.data[3];
+    mNew[4] = data[0] * m.data[4] + data[4] * m.data[5] + data[8] * m.data[6] + data[12] * m.data[7];
+    mNew[5] = data[1] * m.data[4] + data[5] * m.data[5] + data[9] * m.data[6] + data[13] * m.data[7];
+    mNew[6] = data[2] * m.data[4] + data[6] * m.data[5] + data[10] * m.data[6] + data[14] * m.data[7];
+    mNew[7] = data[3] * m.data[4] + data[7] * m.data[5] + data[11] * m.data[6] + data[15] * m.data[7];
+    mNew[8] = data[0] * m.data[8] + data[4] * m.data[9] + data[8] * m.data[10] + data[12] * m.data[11];
+    mNew[9] = data[1] * m.data[8] + data[5] * m.data[9] + data[9] * m.data[10] + data[13] * m.data[11];
+    mNew[10] = data[2] * m.data[8] + data[6] * m.data[9] + data[10] * m.data[10] + data[14] * m.data[11];
+    mNew[11] = data[3] * m.data[8] + data[7] * m.data[9] + data[11] * m.data[10] + data[15] * m.data[11];
+    mNew[12] = data[0] * m.data[12] + data[4] * m.data[13] + data[8] * m.data[14] + data[12] * m.data[15];
+    mNew[13] = data[1] * m.data[12] + data[5] * m.data[13] + data[9] * m.data[14] + data[13] * m.data[15];
+    mNew[14] = data[2] * m.data[12] + data[6] * m.data[13] + data[10] * m.data[14] + data[14] * m.data[15];
+    mNew[15] = data[3] * m.data[12] + data[7] * m.data[13] + data[11] * m.data[14] + data[15] * m.data[15];
+    memcpy(data, mNew, sizeof(float) * 16);
+}
+
+void Matrix3D::scale(float sx, float sy, float sz)
+{
+    data[0] *= sx;
+    data[1] *= sx;
+    data[2] *= sx;
+    data[3] *= sx;
+    data[4] *= sy;
+    data[5] *= sy;
+    data[6] *= sy;
+    data[7] *= sy;
+    data[8] *= sz;
+    data[9] *= sz;
+    data[10] *= sz;
+    data[11] *= sz;
+}
+
+void Matrix3D::translate(float tx, float ty, float tz) 
+{
+    data[12] += data[0] * tx + data[4] * ty + data[8] * tz;
+    data[13] += data[1] * tx + data[5] * ty + data[9] * tz;
+    data[14] += data[2] * tx + data[6] * ty + data[10] * tz;
+    data[15] += data[3] * tx + data[7] * ty + data[11] * tz;
+}
+
+void Matrix3D::translateX(float tx) 
+{
+    data[12] += data[0] * tx;
+    data[13] += data[1] * tx;
+    data[14] += data[2] * tx;
+    data[15] += data[3] * tx;
+}
+
+void Matrix3D::translateY(float ty) 
+{
+    data[12] += data[4] * ty;
+    data[13] += data[5] * ty;
+    data[14] += data[6] * ty;
+    data[15] += data[7] * ty;
+}
+
+void Matrix3D::translateZ(float tz) 
+{
+    data[12] += data[8] * tz;
+    data[13] += data[9] * tz;
+    data[14] += data[10] * tz;
+    data[15] += data[11] * tz;
+}
+
+void Matrix3D::translateTo(float tx, float ty, float tz) 
+{
+    data[0] = 1.0f;
+    data[1] = 0.0f;
+    data[2] = 0.0f;
+    data[3] = 0.0f;
+    data[4] = 0.0f;
+    data[5] = 1.0f;
+    data[6] = 0.0f;
+    data[7] = 0.0f;
+    data[8] = 0.0f;
+    data[9] = 0.0f;
+    data[10] = 1.0f;
+    data[11] = 0.0f;
+    data[12] = tx;
+    data[13] = ty;
+    data[14] = tz;
+    data[15] = 1.0f;
+}
+
+void Matrix3D::rotate(float xDegrees, float yDegrees, float zDegrees) 
+{
+    rotateX(xDegrees);
+    rotateY(yDegrees);
+    rotateZ(zDegrees);
+}
+
+void Matrix3D::rotateX(float degrees) 
+{
+    degrees *= M_PI / 180.0f;
+    float sin = sinf(degrees);
+    float cos =  cosf(degrees);
+    
+    float a = data[4];
+    float b = data[8];
+    data[4] = a * cos + b * sin;
+    data[8] = a * -sin + b * cos;
+
+    a = data[5];
+    b = data[9];
+    data[5] = a * cos + b * sin;
+    data[9] = a * -sin + b * cos;
+
+    a = data[6];
+    b = data[10];
+    data[6] = a * cos + b * sin;
+    data[10] = a * -sin + b * cos;
+
+    a = data[7];
+    b = data[11];
+    data[7] = a * cos + b * sin;
+    data[11] = a * -sin + b * cos;
+}
+
+void Matrix3D::rotateY(float degrees) 
+{
+    degrees *= M_PI / 180.0f;
+    float sin = sinf(degrees);
+    float cos =  cosf(degrees);
+    
+    float a = data[0];
+    float b = data[8];
+    data[0] = a * cos + b * -sin;
+    data[8] = a * sin + b * cos;
+
+    a = data[1];
+    b = data[9];
+    data[1] = a * cos + b * -sin;
+    data[9] = a * sin + b * cos;
+
+    a = data[2];
+    b = data[10];
+    data[2] = a * cos + b * -sin;
+    data[10] = a * sin + b * cos;
+
+    a = data[3];
+    b = data[11];
+    data[3] = a * cos + b * -sin;
+    data[11] = a * sin + b * cos;
+}
+
+void Matrix3D::rotateZ(float degrees) 
+{
+    degrees *= M_PI / 180.0f;
+    float sin = sinf(degrees);
+    float cos =  cosf(degrees);
+    
+    float a = data[0];
+    float b = data[4];
+    data[0] = a * cos + b * sin;
+    data[4] = a * -sin + b * cos;
+
+    a = data[1];
+    b = data[5];
+    data[1] = a * cos + b * sin;
+    data[5] = a * -sin + b * cos;
+
+    a = data[2];
+    b = data[6];
+    data[2] = a * cos + b * sin;
+    data[6] = a * -sin + b * cos;
+
+    a = data[3];
+    b = data[7];
+    data[3] = a * cos + b * sin;
+    data[7] = a * -sin + b * cos;
+}
+
+std::ostream& operator<<(std::ostream& os, const Matrix3D& m)
+{
+    os << "Matrix3D\n(\n";
+    os << m.get(0, 0) << ", " << m.get(0, 1) << ", " << m.get(0, 2) << ", " << m.get(0, 3) << "\n";
+    os << m.get(1, 0) << ", " << m.get(1, 1) << ", " << m.get(1, 2) << ", " << m.get(1, 3) << "\n";
+    os << m.get(2, 0) << ", " << m.get(2, 1) << ", " << m.get(2, 2) << ", " << m.get(2, 3) << "\n";
+    os << m.get(3, 0) << ", " << m.get(3, 1) << ", " << m.get(3, 2) << ", " << m.get(3, 3) << "\n";
+    os << ")";
+    return os;
+}

+ 42 - 0
math/Matrix3D.h

@@ -0,0 +1,42 @@
+#ifndef MATRIX3D_H
+#define MATRIX3D_H
+
+#include <iostream>
+
+class Matrix3D
+{
+public:
+    Matrix3D();
+    Matrix3D(const Matrix3D& orig);
+    virtual ~Matrix3D();
+    
+    void setToIdentity();
+    void set(const Matrix3D& m);
+    
+    void set(int row, int col, float value);
+    float get(int row, int col) const;
+    
+    const float* getValues() const;
+    
+    void mul(const Matrix3D& m);
+    
+    void scale(float sx, float sy, float sz);
+    
+    void translate(float tx, float ty, float tz);
+    void translateX(float tx);
+    void translateY(float ty);
+    void translateZ(float tz);
+    void translateTo(float tx, float ty, float tz);
+    
+    void rotate(float xDegrees, float yDegrees, float zDegrees);
+    void rotateX(float degrees);
+    void rotateY(float degrees);
+    void rotateZ(float degrees);
+private:
+    float data[16];
+};
+
+std::ostream& operator<<(std::ostream& os, const Matrix3D& m);
+
+#endif
+

+ 40 - 0
math/Matrix3DStack.cpp

@@ -0,0 +1,40 @@
+#include "Matrix3DStack.h"
+#include "StackOverflow.h"
+#include "StackUnderflow.h"
+
+Matrix3DStack::Matrix3DStack()
+{
+}
+
+Matrix3DStack::Matrix3DStack(const Matrix3DStack& orig)
+{
+}
+
+Matrix3DStack::~Matrix3DStack()
+{
+}
+
+void Matrix3DStack::pop()
+{
+    if(index <= 0)
+    {
+        throw StackUnderflow();
+    }
+    index--;
+}
+
+void Matrix3DStack::push()
+{
+    if(index >= STACK_SIZE - 1)
+    {
+        throw StackOverflow();
+    }
+    index++;
+    stack[index].set(stack[index - 1]);
+}
+
+Matrix3D& Matrix3DStack::get()
+{
+    return stack[index];
+}
+

+ 23 - 0
math/Matrix3DStack.h

@@ -0,0 +1,23 @@
+#ifndef MATRIX3DSTACK_H
+#define MATRIX3DSTACK_H
+
+#include "Matrix3D.h"
+
+class Matrix3DStack
+{
+public:
+    Matrix3DStack();
+    Matrix3DStack(const Matrix3DStack& orig);
+    virtual ~Matrix3DStack();
+    
+    void pop();
+    void push();
+    Matrix3D& get();
+private:
+    static const int STACK_SIZE = 10;
+    Matrix3D stack[STACK_SIZE];
+    int index = 0;
+};
+
+#endif
+

+ 19 - 0
math/StackOverflow.cpp

@@ -0,0 +1,19 @@
+#include "StackOverflow.h"
+
+StackOverflow::StackOverflow()
+{
+}
+
+StackOverflow::StackOverflow(const StackOverflow& orig)
+{
+}
+
+StackOverflow::~StackOverflow()
+{
+}
+
+const char* StackOverflow::what() const throw()
+{
+    return "push used on full matrix stack";
+}
+

+ 19 - 0
math/StackOverflow.h

@@ -0,0 +1,19 @@
+#ifndef STACKOVERFLOW_H
+#define STACKOVERFLOW_H
+
+#include <exception>
+
+class StackOverflow : public std::exception
+{
+public:
+    StackOverflow();
+    StackOverflow(const StackOverflow& orig);
+    virtual ~StackOverflow();
+    
+    virtual const char* what() const throw();
+private:
+
+};
+
+#endif
+

+ 19 - 0
math/StackUnderflow.cpp

@@ -0,0 +1,19 @@
+#include "StackUnderflow.h"
+
+StackUnderflow::StackUnderflow()
+{
+}
+
+StackUnderflow::StackUnderflow(const StackUnderflow& orig)
+{
+}
+
+StackUnderflow::~StackUnderflow()
+{
+}
+
+const char* StackUnderflow::what() const throw()
+{
+    return "pop used on matrix stack of index 0";
+}
+

+ 19 - 0
math/StackUnderflow.h

@@ -0,0 +1,19 @@
+#ifndef STACKUNDERFLOW_H
+#define STACKUNDERFLOW_H
+
+#include <exception>
+
+class StackUnderflow : public std::exception
+{
+public:
+    StackUnderflow();
+    StackUnderflow(const StackUnderflow& orig);
+    virtual ~StackUnderflow();
+    
+    virtual const char* what() const throw();
+private:
+
+};
+
+#endif
+

+ 159 - 0
math/Vector3D.cpp

@@ -0,0 +1,159 @@
+#include "Vector3D.h"
+#include <cmath>
+
+Vector3D::Vector3D() : x(0), y(0), z(0)
+{
+}
+
+Vector3D::Vector3D(float ix, float iy, float iz) : x(ix), y(iy), z(iz)
+{
+}
+
+Vector3D::Vector3D(const Vector3D& orig)
+{
+    x = orig.x;
+    y = orig.y;
+    z = orig.z;
+}
+
+Vector3D::~Vector3D()
+{
+}
+
+float Vector3D::getX() const
+{
+    return x;
+}
+
+float Vector3D::getY() const
+{
+    return y;
+}
+
+float Vector3D::getZ() const
+{
+    return z;
+}
+
+void Vector3D::setX(float ix)
+{
+    x = ix;
+}
+
+void Vector3D::setY(float iy)
+{
+    y = iy;
+}
+
+void Vector3D::setZ(float iz)
+{
+    z = iz;
+}
+
+void Vector3D::set(float ix, float iy, float iz)
+{
+    x = ix;
+    y = iy;
+    z = iz;
+}
+
+void Vector3D::set(const Vector3D& v)
+{
+    x = v.x;
+    y = v.y;
+    z = v.z;
+}
+
+void Vector3D::setInverse(const Vector3D& v)
+{
+    x = -v.x;
+    y = -v.y;
+    z = -v.z;
+}
+
+void Vector3D::setMul(const Vector3D& v, float f)
+{
+    x = v.x * f;
+    y = v.y * f;
+    z = v.z * f;
+}
+
+void Vector3D::setAngles(float lengthAngle, float widthAngle)
+{
+    lengthAngle = lengthAngle * M_PI / 180.0f;
+    widthAngle = widthAngle * M_PI / 180.0f;
+    x = cosf(widthAngle) * sinf(lengthAngle);
+    y = sinf(widthAngle);
+    z = cosf(widthAngle) * cosf(lengthAngle); 
+}
+
+
+void Vector3D::add(const Vector3D& v)
+{
+    x += v.x;
+    y += v.y;
+    z += v.z;
+}
+
+void Vector3D::sub(const Vector3D& v)
+{
+    x -= v.x;
+    y -= v.y;
+    z -= v.z;
+}
+
+void Vector3D::mul(float f)
+{
+    x *= f;
+    y *= f;
+    z *= f;
+}
+
+void Vector3D::addMul(const Vector3D& v, float f)
+{
+    x += v.x * f;
+    y += v.y * f;
+    z += v.z * f;
+}
+
+
+void Vector3D::cross(float ix, float iy, float iz)
+{
+    set(y * iz - z * iy, z * ix - x * iz, x * iy - y * ix);
+}
+
+void Vector3D::cross(const Vector3D& v)
+{
+    set(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
+}
+
+
+void Vector3D::normalize()
+{
+    float f = length();
+    x /= f;
+    y /= f;
+    z /= f;
+}
+
+float Vector3D::length() const
+{
+    return sqrtf(x * x + y * y + z * z);
+}
+
+float Vector3D::dot(const Vector3D& v) const
+{
+    return x * v.x + y * v.y + z * v.z;
+}
+
+float Vector3D::dotInverse(const Vector3D& v) const
+{
+    return x * (-v.x) + y * (-v.y) + z * (-v.z);
+}
+
+std::ostream& operator<<(std::ostream& os, const Vector3D& v)
+{
+    return os << "Vector3D(x = " << v.getX() << ", y = " << v.getY() << ", z = " << v.getZ() << ")";
+}
+
+

+ 50 - 0
math/Vector3D.h

@@ -0,0 +1,50 @@
+#ifndef VECTOR3D_H
+#define VECTOR3D_H
+
+#include <iostream>
+
+class Vector3D
+{
+public:
+    Vector3D();
+    Vector3D(float ix, float iy, float iz);
+    Vector3D(const Vector3D& orig);
+    virtual ~Vector3D();
+    
+    float getX() const;
+    float getY() const;
+    float getZ() const;
+    
+    void setX(float ix);
+    void setY(float iy);
+    void setZ(float iz);
+    
+    void set(float ix, float iy, float iz);
+    void set(const Vector3D& v);
+    void setInverse(const Vector3D& v);
+    void setMul(const Vector3D& v, float f);
+    void setAngles(float lengthAngle, float widthAngle);
+    
+    void add(const Vector3D& v);
+    void sub(const Vector3D& v);
+    void mul(float f);
+    void addMul(const Vector3D& v, float f);
+    
+    void cross(float ix, float iy, float iz);
+    void cross(const Vector3D& v);
+    
+    void normalize();
+    float length() const;
+    
+    float dot(const Vector3D& v) const;
+    float dotInverse(const Vector3D& v) const;
+private:
+    float x;
+    float y;
+    float z;
+};
+
+std::ostream& operator<<(std::ostream& os, const Vector3D& v);
+
+#endif
+

BIN
resources/font16x16.png


BIN
resources/font24x24.png


BIN
resources/font8x8.png


BIN
resources/textures.png


+ 38 - 0
shader/fragment.fs

@@ -0,0 +1,38 @@
+#version 430
+
+uniform sampler2D samp;
+
+uniform mat4 projMatrix;
+uniform mat4 viewMatrix;
+
+uniform bool useTexture;
+uniform bool useColor;
+uniform bool useMixColor;
+uniform vec4 mixColor;
+
+in vec2 tc;
+in vec4 outColor;
+out vec4 color;
+
+void main(void)
+{
+    if(useTexture)
+    {
+        color = texture(samp, tc);
+        if(useColor)
+        {
+            if(useMixColor)
+            {
+                color = (color + mixColor) * 0.5;
+            }
+            else
+            {
+                color = vec4(outColor.xyz, color.w);
+            }
+        }
+    }
+    else
+    {
+        color = outColor;
+    }
+}

+ 25 - 0
shader/vertex.vs

@@ -0,0 +1,25 @@
+#version 430
+
+layout (location = 0) in vec3 pos;
+layout (location = 1) in vec4 color;
+layout (location = 2) in vec2 tex;
+
+uniform sampler2D samp;
+
+uniform mat4 projMatrix;
+uniform mat4 viewMatrix;
+
+uniform bool useTexture;
+uniform bool useColor;
+uniform bool useMixColor;
+uniform vec4 mixColor;
+
+out vec2 tc;
+out vec4 outColor;
+
+void main(void)
+{ 
+    tc = tex; 
+    outColor = color;
+    gl_Position = projMatrix * viewMatrix * vec4(pos, 1.0);
+}