Kajetan Johannes Hammerle 3 years ago
commit
1ef90aff69
59 changed files with 2250 additions and 0 deletions
  1. 18 0
      Game.cpp
  2. 23 0
      Game.h
  3. 113 0
      Main.cpp
  4. 75 0
      input/Controller.cpp
  5. 75 0
      input/Controller.h
  6. 136 0
      math/Matrix.cpp
  7. 34 0
      math/Matrix.h
  8. 23 0
      math/MatrixStack.cpp
  9. 20 0
      math/MatrixStack.h
  10. 141 0
      math/Vector.cpp
  11. 50 0
      math/Vector.h
  12. 15 0
      meson.build
  13. 15 0
      rendering/FileTexture.cpp
  14. 16 0
      rendering/FileTexture.h
  15. 50 0
      rendering/FontRenderer.cpp
  16. 20 0
      rendering/FontRenderer.h
  17. 26 0
      rendering/Mesh.cpp
  18. 34 0
      rendering/Mesh.h
  19. 76 0
      rendering/Renderer.cpp
  20. 42 0
      rendering/Renderer.h
  21. 4 0
      rendering/WindowSize.cpp
  22. 11 0
      rendering/WindowSize.h
  23. 31 0
      rendering/wrapper/GLFWWrapper.cpp
  24. 11 0
      rendering/wrapper/GLFWWrapper.h
  25. 59 0
      rendering/wrapper/GLWrapper.cpp
  26. 13 0
      rendering/wrapper/GLWrapper.h
  27. 85 0
      rendering/wrapper/Shader.cpp
  28. 30 0
      rendering/wrapper/Shader.h
  29. 28 0
      rendering/wrapper/StreamBuffer.cpp
  30. 26 0
      rendering/wrapper/StreamBuffer.h
  31. 29 0
      rendering/wrapper/Texture.cpp
  32. 26 0
      rendering/wrapper/Texture.h
  33. 37 0
      rendering/wrapper/VertexBuffer.cpp
  34. 31 0
      rendering/wrapper/VertexBuffer.h
  35. 64 0
      rendering/wrapper/Window.cpp
  36. 33 0
      rendering/wrapper/Window.h
  37. BIN
      resources/font.png
  38. 23 0
      resources/shader/fragment.fs
  39. 19 0
      resources/shader/vertex.vs
  40. BIN
      resources/textures.png
  41. 59 0
      utils/Array.h
  42. 23 0
      utils/Clock.cpp
  43. 23 0
      utils/Clock.h
  44. 97 0
      utils/HashMap.h
  45. 29 0
      utils/HashedString.cpp
  46. 24 0
      utils/HashedString.h
  47. 67 0
      utils/List.h
  48. 85 0
      utils/PNGReader.cpp
  49. 10 0
      utils/PNGReader.h
  50. 26 0
      utils/Random.cpp
  51. 21 0
      utils/Random.h
  52. 31 0
      utils/RingBuffer.h
  53. 44 0
      utils/SplitString.cpp
  54. 19 0
      utils/SplitString.h
  55. 62 0
      utils/String.cpp
  56. 27 0
      utils/String.h
  57. 30 0
      utils/Types.h
  58. 5 0
      utils/Utils.cpp
  59. 6 0
      utils/Utils.h

+ 18 - 0
Game.cpp

@@ -0,0 +1,18 @@
+#include "Game.h"
+#include "rendering/Renderer.h"
+
+Game::Game(const Controller& c, const Clock& fps, const Clock& tps) : controller(c), fps(fps), tps(tps) {
+}
+
+void Game::tick() {
+}
+
+void Game::render(float lag, Renderer& renderer) const {
+    renderer.translateTo(0.0f, 0.0f).scale(2.0f).update();
+    renderer.drawString(0, 0, "Das is&037t ein Test.");
+    (void) lag;
+}
+
+bool Game::isRunning() const {
+    return true;
+}

+ 23 - 0
Game.h

@@ -0,0 +1,23 @@
+#ifndef GAME_H
+#define GAME_H
+
+#include "input/Controller.h"
+#include "utils/Clock.h"
+#include "rendering/Renderer.h"
+
+class Game final {
+public:
+    Game(const Controller& c, const Clock& fps, const Clock& tps);
+
+    void tick();
+    void render(float lag, Renderer& renderer) const;
+    
+    bool isRunning() const;
+
+private:
+    const Controller& controller;
+    const Clock& fps;
+    const Clock& tps;
+};
+
+#endif

+ 113 - 0
Main.cpp

@@ -0,0 +1,113 @@
+#include <iostream>
+
+#include "rendering/wrapper/GLFWWrapper.h"
+#include "rendering/wrapper/GLWrapper.h"
+#include "rendering/WindowSize.h"
+#include "rendering/wrapper/Window.h"
+#include "utils/Clock.h"
+#include "rendering/wrapper/Shader.h"
+#include "input/Controller.h"
+#include "rendering/Renderer.h"
+#include "Game.h"
+
+bool initGLEW() {
+    GLenum err = glewInit();
+    if(err != GLEW_OK) {
+        std::cout << "could not initialize GLEW: " << glewGetErrorString(err) << "\n";
+        return true;
+    }
+    std::cout << "using GLEW " << glewGetString(GLEW_VERSION) << "\n";
+    return false;
+}
+
+void initCallbacks(Window& w, WindowSize& size, Controller& controller) {
+    static WindowSize& cSize = size;
+    static Controller& cController = controller;
+    (void) cController;
+    w.setFramebufferSizeCallback([](GLFWwindow*, int newWidth, int newHeight) {
+        glViewport(0, 0, newWidth, newHeight);
+        cSize.width = newWidth;
+        cSize.height = newHeight;
+    });
+    /*w.setKeyCallback([](GLFWwindow*, int key, int, int action, int) {
+        if(action == GLFW_PRESS) {
+            cControl.keys.press(key);
+        } else if(action == GLFW_RELEASE) {
+            cControl.keys.release(key);
+        }
+    });
+    w.setMouseButtonCallback([](GLFWwindow*, int button, int action, int) {
+        if(action == GLFW_PRESS) {
+            cControl.buttons.press(button);
+        } else if(action == GLFW_RELEASE) {
+            cControl.buttons.release(button);
+        }
+    });*/
+}
+
+int main() {
+    if(GLFWWrapper::hasError()) {
+        return 0;
+    }
+    
+    WindowSize size(800, 480);
+    Window window(size, "Test");
+    if(window.hasError() || initGLEW()) {
+        return 0;
+    }
+    
+    Shader shader("resources/shader/vertex.vs", "resources/shader/fragment.fs");
+    if(shader.hasError()) {
+        return 0;
+    }
+    
+    Renderer renderer(size, shader);
+    
+    Controller controller;
+    Clock fps;
+    Clock tps;
+    
+    static Game game(controller, fps, tps);
+    
+    initCallbacks(window, size, controller);
+    window.show();
+    
+    const u64 nanosPerTick = 50000000;
+    u64 lag = 0;
+    while(!window.shouldClose() && game.isRunning()) {
+        GLWrapper::checkAndPrintError("GL-Error");
+        
+        Matrix view;
+        view.translate(-1.0f, 1.0f);
+        view.scale(2.0f / size.width, -2.0f / size.height);
+        shader.setMatrix("view", view.getValues());
+        
+        game.render((float) lag / nanosPerTick, renderer);
+        window.swapBuffers();
+        
+        lag += fps.update();
+        while(lag >= nanosPerTick) {
+            lag -= nanosPerTick;
+            tps.update();
+            controller.tick();
+            game.tick();
+        }
+        glfwPollEvents();
+    }
+    
+    /*for(int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; i++) {
+        String s("Joystick ");
+        int present = glfwJoystickPresent(i);
+        s.append(i).append(": ").append(present);
+        if(present) {
+            s.append("  ");
+            int count = 0;
+            const u8* buttons = glfwGetJoystickButtons(i, &count);
+            for(int k = 0; k < count; k++) {
+                s.append(buttons[k] ? '1' : '0');
+            }
+        }
+        r.drawString(0, i * 10 + 10, s);
+    }*/
+    return 0;
+}

+ 75 - 0
input/Controller.cpp

@@ -0,0 +1,75 @@
+#include "input/Controller.h"
+
+void Controller::tick() {
+}
+
+/*#include <GLFW/glfw3.h>
+
+#include "client/input/Keys.h"
+
+Keys::Key::Key() : down(false), shouldRelease(false), downTime(0) {
+}
+
+bool Keys::Key::isDown() const {
+    return down;
+}
+
+bool Keys::Key::isReleased() const {
+    return shouldRelease;
+}
+
+u32 Keys::Key::getDownTime() const {
+    return downTime;
+}
+
+std::ostream& operator<<(std::ostream& os, const Keys::Key& k) {
+    os << "Key(down: " << k.isDown() << ", release: " << k.isReleased() <<
+            ", time: " << k.getDownTime() << ")";
+    return os;
+}
+
+Keys::Keys() : left(keys[0]), right(keys[1]), up(keys[2]), down(keys[3]), jump(keys[4]), sneak(keys[5]),
+camLeft(keys[6]), camRight(keys[7]), camUp(keys[8]), camDown(keys[9]), test(keys[10]), test2(keys[11]), test3(keys[12]),
+test4(keys[13]), test5(keys[14]) {
+    keys[0].glfwKey = GLFW_KEY_A;
+    keys[1].glfwKey = GLFW_KEY_D;
+    keys[2].glfwKey = GLFW_KEY_W;
+    keys[3].glfwKey = GLFW_KEY_S;
+    keys[4].glfwKey = GLFW_KEY_SPACE;
+    keys[5].glfwKey = GLFW_KEY_LEFT_SHIFT;
+    keys[6].glfwKey = GLFW_KEY_LEFT;
+    keys[7].glfwKey = GLFW_KEY_RIGHT;
+    keys[8].glfwKey = GLFW_KEY_UP;
+    keys[9].glfwKey = GLFW_KEY_DOWN;
+    keys[10].glfwKey = GLFW_KEY_T;
+    keys[11].glfwKey = GLFW_KEY_Y;
+    keys[12].glfwKey = GLFW_KEY_U;
+    keys[13].glfwKey = GLFW_KEY_I;
+    keys[14].glfwKey = GLFW_KEY_R;
+}
+
+void Keys::release(int key) {
+    for(Key& k : keys) {
+        if(k.glfwKey == key) {
+            k.shouldRelease = true;
+        }
+    }
+}
+
+void Keys::press(int key) {
+    for(Key& k : keys) {
+        if(k.glfwKey == key) {
+            k.down = true;
+            k.shouldRelease = false;
+        }
+    }
+}
+
+void Keys::tick() {
+    for(Key& k : keys) {
+        k.downTime += k.down;
+        k.down = k.down && !k.shouldRelease;
+        k.downTime *= !k.shouldRelease;
+        k.shouldRelease = false;
+    }
+}*/

+ 75 - 0
input/Controller.h

@@ -0,0 +1,75 @@
+#ifndef CONTROLLER_H
+#define CONTROLLER_H
+
+struct Controller final {
+    void tick();
+};
+
+#endif
+/*#ifndef KEYS_H
+#define KEYS_H
+
+#include <iostream>
+#include <array>
+
+#include "common/utils/Types.h"
+
+class Keys final {
+public:
+
+    class Key final {
+    public:
+        friend class Keys;
+
+        bool isDown() const;
+        bool isReleased() const;
+        u32 getDownTime() const;
+
+    private:
+        Key();
+        Key(const Key&) = delete;
+        Key(Key&&) = delete;
+        Key& operator=(const Key&) = delete;
+        Key& operator=(Key&&) = delete;
+
+        int glfwKey;
+        bool down;
+        bool shouldRelease;
+        u32 downTime;
+    };
+
+private:
+    Key keys[15];
+
+public:
+    Keys();
+    const Key& left;
+    const Key& right;
+    const Key& up;
+    const Key& down;
+    const Key& jump;
+    const Key& sneak;
+    const Key& camLeft;
+    const Key& camRight;
+    const Key& camUp;
+    const Key& camDown;
+    const Key& test;
+    const Key& test2;
+    const Key& test3;
+    const Key& test4;
+    const Key& test5;
+
+    void release(int key);
+    void press(int key);
+    void tick();
+
+private:
+    Keys(const Keys&) = delete;
+    Keys& operator=(const Keys&) = delete;
+    Keys(Key&&) = delete;
+    Keys& operator=(Keys&&) = delete;
+};
+
+std::ostream& operator<<(std::ostream& os, const Keys::Key& k);
+
+#endif*/

+ 136 - 0
math/Matrix.cpp

@@ -0,0 +1,136 @@
+#include <cmath>
+#include <iomanip>
+#include <cstring>
+
+#include "math/Matrix.h"
+
+Matrix::Matrix() {
+    setToIdentity();
+}
+
+Matrix& Matrix::set(const Matrix& other) {
+    *this = other;
+    return *this;
+}
+
+Matrix& Matrix::setToIdentity() {
+    data[0] = 1.0f;
+    data[1] = 0.0f;
+    data[2] = 0.0f;
+    data[3] = 0.0f;
+    data[4] = 1.0f;
+    data[5] = 0.0f;
+    data[6] = 0.0f;
+    data[7] = 0.0f;
+    data[8] = 1.0f;
+    return *this;
+}
+
+Matrix& Matrix::set(uint index, float f) {
+    data[index] = f;
+    return *this;
+}
+
+const float* Matrix::getValues() const {
+    return data;
+}
+
+Matrix& Matrix::mul(const Matrix& m) {
+    float mNew[9];
+    mNew[0] = data[0] * m.data[0] + data[3] * m.data[1] + data[6] * m.data[2];
+    mNew[1] = data[1] * m.data[0] + data[4] * m.data[1] + data[7] * m.data[2];
+    mNew[2] = data[2] * m.data[0] + data[5] * m.data[1] + data[8] * m.data[2];
+    mNew[3] = data[0] * m.data[3] + data[3] * m.data[4] + data[6] * m.data[5];
+    mNew[4] = data[1] * m.data[3] + data[4] * m.data[4] + data[7] * m.data[5];
+    mNew[5] = data[2] * m.data[3] + data[5] * m.data[4] + data[8] * m.data[5];
+    mNew[6] = data[0] * m.data[6] + data[3] * m.data[7] + data[6] * m.data[8];
+    mNew[7] = data[1] * m.data[6] + data[4] * m.data[7] + data[7] * m.data[8];
+    mNew[8] = data[2] * m.data[6] + data[5] * m.data[7] + data[8] * m.data[8];
+    memcpy(data, mNew, sizeof (float) * 9);
+    return *this;
+}
+
+Matrix& Matrix::scale(float sx, float sy) {
+    data[0] *= sx;
+    data[1] *= sx;
+    data[2] *= sx;
+    data[3] *= sy;
+    data[4] *= sy;
+    data[5] *= sy;
+    return *this;
+}
+
+Matrix& Matrix::scale(float s) {
+    return scale(s, s);
+}
+
+Matrix& Matrix::translate(float tx, float ty) {
+    return translateX(tx).translateY(ty);
+}
+
+Matrix& Matrix::translateX(float tx) {
+    data[6] += data[0] * tx;
+    data[7] += data[1] * tx;
+    data[8] += data[2] * tx;
+    return *this;
+}
+
+Matrix& Matrix::translateY(float ty) {
+    data[6] += data[3] * ty;
+    data[7] += data[4] * ty;
+    data[8] += data[5] * ty;
+    return *this;
+}
+
+Matrix& Matrix::translateTo(float tx, float ty) {
+    data[0] = 1.0f;
+    data[1] = 0.0f;
+    data[2] = 0.0f;
+    data[3] = 0.0f;
+    data[4] = 1.0f;
+    data[5] = 0.0f;
+    data[6] = tx;
+    data[7] = ty;
+    data[8] = 1.0f;
+    return *this;
+}
+
+Matrix& Matrix::rotate(float degrees) {
+    degrees *= M_PIf32 / 180.0f;
+    float sin;
+    float cos;
+    sincosf(degrees, &sin, &cos);
+     
+    float a = data[0];
+    float b = data[3];
+    data[0] = a * cos + b * sin;
+    data[3] = b * cos - a * sin;
+    
+    a = data[1];
+    b = data[4];
+    data[1] = a * cos + b * sin;
+    data[4] = b * cos - a * sin;
+    
+    a = data[2];
+    b = data[5];
+    data[2] = a * cos + b * sin;
+    data[5] = b * cos - a * sin;
+    return *this;
+}
+
+std::ostream& operator<<(std::ostream& os, const Matrix& m) {
+    const float* data = m.getValues();
+    os << "Matrix\n(\n";
+    os << std::fixed << std::setprecision(5);
+    for(int i = 0; i < 3; i++) {
+        os << std::setw(15);
+        os << data[i] << ", ";
+        os << std::setw(15);
+        os << data[i + 3] << ", ";
+        os << std::setw(15);
+        os << data[i + 6] << "\n";
+    }
+    os << std::defaultfloat;
+    os << ")";
+    return os;
+}

+ 34 - 0
math/Matrix.h

@@ -0,0 +1,34 @@
+#ifndef MATRIX_H
+#define MATRIX_H
+
+#include <iostream>
+
+class Matrix final {
+public:
+    Matrix();
+
+    Matrix& set(const Matrix& other);
+    Matrix& setToIdentity();
+    Matrix& set(uint index, float f);
+
+    const float* getValues() const;
+
+    Matrix& mul(const Matrix& m);
+
+    Matrix& scale(float sx, float sy);
+    Matrix& scale(float s);
+
+    Matrix& translate(float tx, float ty);
+    Matrix& translateX(float tx);
+    Matrix& translateY(float ty);
+    Matrix& translateTo(float tx, float ty);
+
+    Matrix& rotate(float degrees);
+
+private:
+    float data[9];
+};
+
+std::ostream& operator<<(std::ostream& os, const Matrix& m);
+
+#endif

+ 23 - 0
math/MatrixStack.cpp

@@ -0,0 +1,23 @@
+#include <cassert>
+
+#include "math/MatrixStack.h"
+
+void MatrixStack::pop() {
+    assert(index > 0);
+    index--;
+}
+
+void MatrixStack::push() {
+    assert(index < stack.size() - 1);
+    index++;
+    stack[index] = stack[index - 1];
+}
+
+Matrix& MatrixStack::get() {
+    return stack[index];
+}
+
+void MatrixStack::clear() {
+    index = 0;
+    stack[0].setToIdentity();
+}

+ 20 - 0
math/MatrixStack.h

@@ -0,0 +1,20 @@
+#ifndef MATRIXSTACK_H
+#define MATRIXSTACK_H
+
+#include <array>
+
+#include "math/Matrix.h"
+
+class MatrixStack final {
+public:
+    void pop();
+    void push();
+    Matrix& get();
+    void clear();
+
+private:
+    std::array<Matrix, 10> stack;
+    size_t index = 0;
+};
+
+#endif

+ 141 - 0
math/Vector.cpp

@@ -0,0 +1,141 @@
+#include <cmath>
+
+#include "math/Vector.h"
+
+Vector::Vector() : x(0), y(0), z(0) {
+}
+
+Vector::Vector(float ix, float iy, float iz) : x(ix), y(iy), z(iz) {
+}
+
+float Vector::getX() const {
+    return x;
+}
+
+float Vector::getY() const {
+    return y;
+}
+
+float Vector::getZ() const {
+    return z;
+}
+
+Vector& Vector::setX(float ix) {
+    x = ix;
+    return *this;
+}
+
+Vector& Vector::setY(float iy) {
+    y = iy;
+    return *this;
+}
+
+Vector& Vector::setZ(float iz) {
+    z = iz;
+    return *this;
+}
+
+Vector& Vector::set(const Vector& v) {
+    return set(v.x, v.y, v.z);
+}
+
+Vector& Vector::set(float ix, float iy, float iz) {
+    x = ix;
+    y = iy;
+    z = iz;
+    return *this;
+}
+
+Vector& Vector::setInverse(const Vector& v) {
+    x = -v.x;
+    y = -v.y;
+    z = -v.z;
+    return *this;
+}
+
+Vector& Vector::setMul(const Vector& v, float f) {
+    x = v.x * f;
+    y = v.y * f;
+    z = v.z * f;
+    return *this;
+}
+
+Vector& Vector::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);
+    return *this;
+}
+
+Vector& Vector::add(const Vector& v) {
+    x += v.x;
+    y += v.y;
+    z += v.z;
+    return *this;
+}
+
+Vector& Vector::sub(const Vector& v) {
+    x -= v.x;
+    y -= v.y;
+    z -= v.z;
+    return *this;
+}
+
+Vector& Vector::mul(float f) {
+    x *= f;
+    y *= f;
+    z *= f;
+    return *this;
+}
+
+Vector& Vector::mul(const Matrix& m) {
+    const float* d = m.getValues();
+    const float w = 1.0f;
+    float nx = x * d[0] + y * d[4] + z * d[8] + w * d[12];
+    float ny = x * d[1] + y * d[5] + z * d[9] + w * d[13];
+    float nz = x * d[2] + y * d[6] + z * d[10] + w * d[14];
+    float nw = x * d[3] + y * d[7] + z * d[11] + w * d[15];
+    set(nx / nw, ny / nw, nz / nw);
+    return *this;
+}
+
+Vector& Vector::addMul(const Vector& v, float f) {
+    x += v.x * f;
+    y += v.y * f;
+    z += v.z * f;
+    return *this;
+}
+
+Vector& Vector::cross(float ix, float iy, float iz) {
+    return set(y * iz - z * iy, z * ix - x * iz, x * iy - y * ix);
+}
+
+Vector& Vector::cross(const Vector& v) {
+    return set(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
+}
+
+Vector& Vector::normalize() {
+    float f = 1.0f / sqrtf(squareLength());
+    x *= f;
+    y *= f;
+    z *= f;
+    return *this;
+}
+
+float Vector::squareLength() const {
+    return x * x + y * y + z * z;
+}
+
+float Vector::dot(const Vector& v) const {
+    return x * v.x + y * v.y + z * v.z;
+}
+
+float Vector::dotInverse(const Vector& v) const {
+    return x * (-v.x) + y * (-v.y) + z * (-v.z);
+}
+
+std::ostream& operator<<(std::ostream& os, const Vector& v) {
+    return os << "Vector(x = " << v.getX() << ", y = " << v.getY() << ", z = " << v.getZ() << ")";
+}

+ 50 - 0
math/Vector.h

@@ -0,0 +1,50 @@
+#ifndef VECTOR_H
+#define VECTOR_H
+
+#include <iostream>
+
+#include "math/Matrix.h"
+
+class Vector final {
+public:
+    Vector();
+    Vector(float ix, float iy, float iz);
+
+    float getX() const;
+    float getY() const;
+    float getZ() const;
+
+    Vector& setX(float ix);
+    Vector& setY(float iy);
+    Vector& setZ(float iz);
+
+    Vector& set(const Vector& v);
+    Vector& set(float ix, float iy, float iz);
+    Vector& setInverse(const Vector& v);
+    Vector& setMul(const Vector& v, float f);
+    Vector& setAngles(float lengthAngle, float widthAngle);
+
+    Vector& add(const Vector& v);
+    Vector& sub(const Vector& v);
+    Vector& mul(float f);
+    Vector& mul(const Matrix& m);
+    Vector& addMul(const Vector& v, float f);
+
+    Vector& cross(float ix, float iy, float iz);
+    Vector& cross(const Vector& v);
+
+    Vector& normalize();
+    float squareLength() const;
+
+    float dot(const Vector& v) const;
+    float dotInverse(const Vector& v) const;
+
+private:
+    float x;
+    float y;
+    float z;
+};
+
+std::ostream& operator<<(std::ostream& os, const Vector& v);
+
+#endif

+ 15 - 0
meson.build

@@ -0,0 +1,15 @@
+project('pigine', 'cpp')
+
+sources = ['Main.cpp', 'rendering/wrapper/GLFWWrapper.cpp', 'rendering/WindowSize.cpp', 'rendering/wrapper/Window.cpp', 'utils/Clock.cpp', 'rendering/wrapper/Shader.cpp', 'rendering/wrapper/GLWrapper.cpp', 'Game.cpp', 'input/Controller.cpp', 'rendering/Renderer.cpp', 'math/Vector.cpp', 'math/Matrix.cpp', 'math/MatrixStack.cpp', 'utils/PNGReader.cpp', 'utils/Utils.cpp', 'rendering/wrapper/StreamBuffer.cpp', 'rendering/wrapper/Texture.cpp', 'rendering/wrapper/VertexBuffer.cpp', 'rendering/FileTexture.cpp', 'rendering/FontRenderer.cpp', 'rendering/Mesh.cpp', 'utils/String.cpp']
+
+glewDep = dependency('glew')
+glfwDep = dependency('glfw3')
+pngDep = dependency('libpng')
+
+executable('pigine', 
+    sources: sources,
+    dependencies : [glewDep, glfwDep, pngDep],
+    cpp_args: ['-Wall', '-Wextra', '-pedantic', '-Werror'])
+    
+
+	

+ 15 - 0
rendering/FileTexture.cpp

@@ -0,0 +1,15 @@
+#include "rendering/FileTexture.h"
+#include "utils/PNGReader.h"
+
+FileTexture::FileTexture(const char* path) {
+    u32 maxWidth = 128;
+    u32 maxHeight = 128;
+    u32 buffer[128 * 128];
+    if(PNGReader::load(path, buffer, maxWidth, maxHeight)) {
+        texture.setRGBAData(maxWidth, maxHeight, buffer);
+    }
+}
+
+void FileTexture::bind() const {
+    texture.bind();
+}

+ 16 - 0
rendering/FileTexture.h

@@ -0,0 +1,16 @@
+#ifndef FILE_TEXTURE_H
+#define FILE_TEXTURE_H
+
+#include "rendering/wrapper/Texture.h"
+
+class FileTexture final {
+public:
+    FileTexture(const char* path);
+
+    void bind() const;
+
+private:
+    Texture texture;
+};
+
+#endif

+ 50 - 0
rendering/FontRenderer.cpp

@@ -0,0 +1,50 @@
+#include "rendering/FontRenderer.h"
+
+FontRenderer::FontRenderer() : buffer(8 * 1024 * 1024), tex("resources/font.png") {
+    vertexBuffer.bind();
+    vertexBuffer.setFloatAttribute(0, 2, 0, 8);
+    vertexBuffer.setFloatAttribute(1, 2, 2, 8);
+    vertexBuffer.setFloatAttribute(2, 4, 4, 8);
+}
+
+void FontRenderer::drawString(float x, float y, const char* text) {
+    vertexBuffer.bind();
+
+    const u64 maxIndex = 256;
+    buffer.reset(maxIndex * 4 * sizeof (float) * 8);
+
+    u64 index = 0;
+    float r = 1.0f;
+    float g = 1.0f;
+    float b = 1.0f;
+
+    while(text[index] != '\0' && index < maxIndex) {
+        char c = text[index];
+        if(c == '&') {
+            if(text[index + 1] == '\0' || text[index + 2] == '\0' || text[index + 3] == '\0') {
+                break;
+            }
+            r = (text[index + 1] - '0') * (1.0f / 9.0f);
+            g = (text[index + 2] - '0') * (1.0f / 9.0f);
+            b = (text[index + 3] - '0') * (1.0f / 9.0f);
+            index += 4;
+            continue;
+        }
+
+        float minX = (c & 0xF) * (1.0f / 16.0f) + 1.0f / 128.0f;
+        float minY = (c >> 4) * (1.0f / 16.0f);
+        float maxX = minX + (1.0f / 16.0f) - 2.0f / 128.0f;
+        float maxY = minY + (1.0f / 16.0f);
+
+        buffer.add(x).add(y).add(minX).add(minY).add(r).add(g).add(b).add(1.0f);
+        buffer.add(x).add(y + 8).add(minX).add(maxY).add(r).add(g).add(b).add(1.0f);
+        buffer.add(x + 6).add(y).add(maxX).add(minY).add(r).add(g).add(b).add(1.0f);
+        buffer.add(x + 6).add(y + 8).add(maxX).add(maxY).add(r).add(g).add(b).add(1.0f);
+        
+        x += 6;
+        index++;
+    }
+    
+    tex.bind();
+    buffer.draw(8);
+}

+ 20 - 0
rendering/FontRenderer.h

@@ -0,0 +1,20 @@
+#ifndef FONTRENDERER_H
+#define FONTRENDERER_H
+
+#include "rendering/wrapper/VertexBuffer.h"
+#include "rendering/wrapper/StreamBuffer.h"
+#include "rendering/FileTexture.h"
+
+class FontRenderer final {
+public:
+    FontRenderer();
+
+    void drawString(float x, float y, const char* text);
+
+private:
+    VertexBuffer vertexBuffer;
+    StreamBuffer buffer;
+    FileTexture tex;
+};
+
+#endif

+ 26 - 0
rendering/Mesh.cpp

@@ -0,0 +1,26 @@
+#include "rendering/Mesh.h"
+
+Mesh::Mesh() {
+    vertexBuffer.bind();
+    vertexBuffer.setFloatAttribute(0, 3, 0, 8);
+    vertexBuffer.setFloatAttribute(1, 2, 3, 8);
+    vertexBuffer.setFloatAttribute(2, 3, 5, 8);
+}
+
+void Mesh::add(const VertexData& data) {
+    buffer.add(data);
+}
+
+void Mesh::clear() {
+    buffer.clear();
+}
+
+void Mesh::build() {
+    vertexBuffer.bindBuffer();
+    vertexBuffer.setData(sizeof (VertexData) * buffer.getLength(), buffer.getData());
+}
+
+void Mesh::draw() const {
+    vertexBuffer.bindArray();
+    vertexBuffer.draw(buffer.getLength());
+}

+ 34 - 0
rendering/Mesh.h

@@ -0,0 +1,34 @@
+#ifndef MESH_H
+#define MESH_H
+
+#include "rendering/wrapper/VertexBuffer.h"
+#include "utils/List.h"
+
+class Mesh final {
+public:
+
+    struct VertexData final {
+        float x;
+        float y;
+        float z;
+        float tx;
+        float ty;
+        float nx;
+        float ny;
+        float nz;
+    };
+
+    Mesh();
+
+    void add(const VertexData& data);
+
+    void clear();
+    void build();
+    void draw() const;
+
+private:
+    VertexBuffer vertexBuffer;
+    List<VertexData, 65536 * 2> buffer;
+};
+
+#endif

+ 76 - 0
rendering/Renderer.cpp

@@ -0,0 +1,76 @@
+#include "rendering/Renderer.h"
+#include "rendering/wrapper/GLWrapper.h"
+
+Renderer::Renderer(const WindowSize& size, Shader& shader) : size(size), shader(shader), texture(true), color(true) {
+    shader.use();
+    GLWrapper::enableBlending();
+    setTextureMode(false);
+    setColorMode(false);
+}
+
+void Renderer::pop() {
+    stack.pop();
+}
+
+void Renderer::push() {
+    stack.push();
+}
+
+void Renderer::update() {
+    shader.setMatrix("model", stack.get().getValues());
+}
+
+Renderer& Renderer::scale(float sx, float sy) {
+    stack.get().scale(sx, sy);
+    return *this;
+}
+
+Renderer& Renderer::scale(float s) {
+    stack.get().scale(s);
+    return *this;
+}
+
+Renderer& Renderer::translate(float tx, float ty) {
+    stack.get().translate(tx, ty);
+    return *this;
+}
+
+Renderer& Renderer::translateX(float tx) {
+    stack.get().translateX(tx);
+    return *this;
+}
+
+Renderer& Renderer::translateY(float ty) {
+    stack.get().translateY(ty);
+    return *this;
+}
+
+Renderer& Renderer::translateTo(float tx, float ty) {
+    stack.get().translateTo(tx, ty);
+    return *this;
+}
+
+Renderer& Renderer::rotate(float degrees) {
+    stack.get().rotate(degrees);
+    return *this;
+}
+
+void Renderer::setTextureMode(bool b) {
+    if(b != texture) {
+        texture = b;
+        shader.setInt("useTexture", b);
+    }
+}
+
+void Renderer::setColorMode(bool b) {
+    if(b != color) {
+        color = b;
+        shader.setInt("useColor", b);
+    }
+}
+
+void Renderer::drawString(float x, float y, const char* text) {
+    setTextureMode(true);
+    setColorMode(true);
+    fontRenderer.drawString(x, y, text);
+}

+ 42 - 0
rendering/Renderer.h

@@ -0,0 +1,42 @@
+#ifndef RENDERER_H
+#define RENDERER_H
+
+#include "rendering/wrapper/Shader.h"
+#include "rendering/WindowSize.h"
+#include "math/MatrixStack.h"
+#include "rendering/FontRenderer.h"
+
+class Renderer final {
+public:
+    Renderer(const WindowSize& size, Shader& shader);
+
+    void pop();
+    void push();
+
+    void update();
+
+    Renderer& scale(float sx, float sy);
+    Renderer& scale(float s);
+
+    Renderer& translate(float tx, float ty);
+    Renderer& translateX(float tx);
+    Renderer& translateY(float ty);
+    Renderer& translateTo(float tx, float ty);
+
+    Renderer& rotate(float degrees);
+
+    void drawString(float x, float y, const char* text);
+
+private:
+    void setTextureMode(bool b);
+    void setColorMode(bool b);
+    
+    const WindowSize& size;
+    Shader& shader;
+    bool texture;
+    bool color;
+    MatrixStack stack;
+    FontRenderer fontRenderer;
+};
+
+#endif

+ 4 - 0
rendering/WindowSize.cpp

@@ -0,0 +1,4 @@
+#include "rendering/WindowSize.h"
+
+WindowSize::WindowSize(int width, int height) : width(width), height(height) {
+}

+ 11 - 0
rendering/WindowSize.h

@@ -0,0 +1,11 @@
+#ifndef WINDOWSIZE_H
+#define WINDOWSIZE_H
+
+struct WindowSize final {
+    WindowSize(int width, int height);
+    
+    int width;
+    int height;
+};
+
+#endif

+ 31 - 0
rendering/wrapper/GLFWWrapper.cpp

@@ -0,0 +1,31 @@
+#include <iostream>
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+
+#include "rendering/wrapper/GLFWWrapper.h"
+
+struct GLFWInit final {
+    bool error;
+
+    GLFWInit() : error(glfwInit() == GLFW_FALSE) {
+        if(error) {
+            std::cout << "could not initialize GLFW\n";
+        }
+    }
+
+    ~GLFWInit() {
+        if(!error) {
+            glfwTerminate();
+        }
+    }
+};
+
+static GLFWInit init;
+
+bool GLFWWrapper::hasError() {
+    return init.error;
+}
+
+u64 GLFWWrapper::getTimeNanos() {
+    return glfwGetTimerValue() * (1000000000 / glfwGetTimerFrequency());
+}

+ 11 - 0
rendering/wrapper/GLFWWrapper.h

@@ -0,0 +1,11 @@
+#ifndef GLFWWRAPPER_H
+#define GLFWWRAPPER_H
+
+#include "utils/Types.h"
+
+namespace GLFWWrapper {
+    bool hasError();
+    u64 getTimeNanos();
+}
+
+#endif

+ 59 - 0
rendering/wrapper/GLWrapper.cpp

@@ -0,0 +1,59 @@
+#include <GL/glew.h>
+#include <iostream>
+
+#include "rendering/wrapper/GLWrapper.h"
+
+bool GLWrapper::checkAndPrintError(const char* message) {
+    GLenum error = glGetError();
+    switch(error) {
+        case GL_NO_ERROR:
+            return false;
+        case GL_INVALID_ENUM:
+            std::cout << message << ": an unacceptable value is specified for an enumerated argument.\n";
+            break;
+        case GL_INVALID_VALUE:
+            std::cout << message << ": a numeric argument is out of range.\n";
+            break;
+        case GL_INVALID_OPERATION:
+            std::cout << message << ": the specified operation is not allowed in the current state.\n";
+            break;
+        case GL_INVALID_FRAMEBUFFER_OPERATION:
+            std::cout << message << ": the framebuffer object is not complete.\n";
+            break;
+        case GL_OUT_OF_MEMORY:
+            std::cout << message << ": there is not enough memory left to execute the command.\n";
+            break;
+        case GL_STACK_UNDERFLOW:
+            std::cout << message << ": an attempt has been made to perform an operation that would cause an internal stack to underflow.\n";
+            break;
+        case GL_STACK_OVERFLOW:
+            std::cout << message << ": an attempt has been made to perform an operation that would cause an internal stack to overflow.\n";
+            break;
+        default:
+            std::cout << message << ": unknown OpenGL error: " << error << "\n";
+    }
+    return true;
+}
+
+void GLWrapper::enableDepthTesting() {
+    glEnable(GL_DEPTH_TEST);
+}
+
+void GLWrapper::disableDepthTesting() {
+    glDisable(GL_DEPTH_TEST);
+}
+
+void GLWrapper::prepareMainFramebuffer() {
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+}
+
+void GLWrapper::enableBlending() {
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glBlendEquation(GL_FUNC_ADD);
+}
+
+void GLWrapper::disableBlending() {
+    glDisable(GL_BLEND);
+}

+ 13 - 0
rendering/wrapper/GLWrapper.h

@@ -0,0 +1,13 @@
+#ifndef GLWRAPPER_H
+#define GLWRAPPER_H
+
+namespace GLWrapper {
+    bool checkAndPrintError(const char* message);
+    void enableDepthTesting();
+    void disableDepthTesting();
+    void prepareMainFramebuffer();
+    void enableBlending();
+    void disableBlending();
+}
+
+#endif

+ 85 - 0
rendering/wrapper/Shader.cpp

@@ -0,0 +1,85 @@
+#include <fstream>
+#include <iostream>
+
+#include "rendering/wrapper/Shader.h"
+#include "rendering/wrapper/GLWrapper.h"
+
+Shader::Shader(const GLchar* vPath, const GLchar* fPath) : vShader(0), fShader(0), program(0) {
+    if(readFileAndCompile(vPath, vShader, GL_VERTEX_SHADER) || readFileAndCompile(fPath, fShader, GL_FRAGMENT_SHADER)) {
+        return;
+    }
+    program = glCreateProgram();
+    glAttachShader(program, vShader);
+    glAttachShader(program, fShader);
+    glLinkProgram(program);
+    if(GLWrapper::checkAndPrintError("shader linking error")) {
+        return;
+    }
+    GLint linked;
+    glGetProgramiv(program, GL_LINK_STATUS, &linked);
+    if(linked == GL_FALSE) {
+        GLchar buffer[512];
+        glGetProgramInfoLog(program, 512, nullptr, buffer);
+        std::cout << "programm linking info log: " << buffer << "\n";
+        return;
+    }
+}
+
+Shader::~Shader() {
+    glDeleteProgram(program);
+    glDeleteShader(vShader);
+    glDeleteShader(fShader);
+}
+
+bool Shader::hasError() const {
+    return vShader == 0 || fShader == 0 || program == 0;
+}
+
+bool Shader::readFileAndCompile(const GLchar* path, GLuint& shader, GLenum shaderType) {
+    GLchar buffer[8192];
+    if(readFile(buffer, 8192, path)) {
+        return true;
+    }
+    return compile(shader, buffer, shaderType);
+}
+
+bool Shader::readFile(GLchar* buffer, size_t bufferSize, const GLchar* path) const {
+    std::ifstream in;
+    in.open(path);
+    if(in.fail()) {
+        std::cout << "cannot read shader file: '" << path << "'\n";
+        return true;
+    }
+    in.get(buffer, bufferSize, EOF);
+    return false;
+}
+
+bool Shader::compile(GLuint& shader, const GLchar* code, GLenum shaderType) {
+    shader = glCreateShader(shaderType);
+    glShaderSource(shader, 1, &code, nullptr);
+    glCompileShader(shader);
+    if(GLWrapper::checkAndPrintError("shader error")) {
+        return true;
+    }
+    GLint compiled;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+    if(compiled == GL_FALSE) {
+        GLchar buffer[512];
+        glGetShaderInfoLog(shader, 512, nullptr, buffer);
+        std::cout << "shader info log: " << buffer << "\n";
+        return true;
+    }
+    return false;
+}
+
+void Shader::use() const {
+    glUseProgram(program);
+}
+
+void Shader::setMatrix(const GLchar* name, const GLfloat* data) const {
+    glUniformMatrix3fv(glGetUniformLocation(program, name), 1, GL_FALSE, data);
+}
+
+void Shader::setInt(const GLchar* name, GLint data) const {
+    glUniform1i(glGetUniformLocation(program, name), data);
+}

+ 30 - 0
rendering/wrapper/Shader.h

@@ -0,0 +1,30 @@
+#ifndef SHADER_H
+#define SHADER_H
+
+#include <GL/glew.h>
+
+class Shader final {
+public:
+    Shader(const GLchar* vPath, const GLchar* fPath);
+    ~Shader();
+    Shader(const Shader& other) = delete;
+    Shader(Shader&& other) = delete;
+    Shader& operator=(const Shader& other) = delete;
+    Shader& operator=(Shader&& other) = delete;
+
+    bool hasError() const;
+    void use() const;
+    void setMatrix(const GLchar* name, const GLfloat* data) const;
+    void setInt(const GLchar* name, GLint data) const;
+
+private:
+    bool readFileAndCompile(const GLchar* path, GLuint& shader, GLenum shaderType);
+    bool readFile(GLchar* buffer, size_t bufferSize, const GLchar* path) const;
+    bool compile(GLuint& shader, const GLchar* code, GLenum shaderType);
+
+    GLuint vShader;
+    GLuint fShader;
+    GLuint program;
+};
+
+#endif

+ 28 - 0
rendering/wrapper/StreamBuffer.cpp

@@ -0,0 +1,28 @@
+#include <GL/glew.h>
+#include <cassert>
+
+#include "rendering/wrapper/StreamBuffer.h"
+
+StreamBuffer::StreamBuffer(u64 size) : bufferSize(size), offset(size), index(0), buffer(nullptr) {
+}
+
+void StreamBuffer::reset(u64 size) {
+    if(offset + size >= bufferSize) {
+        offset = 0;
+        glBufferData(GL_ARRAY_BUFFER, bufferSize, nullptr, GL_STREAM_DRAW);
+    }
+    buffer = static_cast<float*> (glMapBufferRange(GL_ARRAY_BUFFER, offset, size, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT));
+    assert(buffer != nullptr);
+    index = 0;
+}
+
+StreamBuffer& StreamBuffer::add(float f) {
+    buffer[index++] = f;
+    return *this;
+}
+
+void StreamBuffer::draw(uint floatPerVertex) {
+    glUnmapBuffer(GL_ARRAY_BUFFER);
+    glDrawArrays(GL_TRIANGLE_STRIP, offset / (sizeof (float) * floatPerVertex), index / floatPerVertex);
+    offset += index * sizeof(float);
+}

+ 26 - 0
rendering/wrapper/StreamBuffer.h

@@ -0,0 +1,26 @@
+#ifndef STREAMBUFFER_H
+#define STREAMBUFFER_H
+
+#include "utils/Types.h"
+
+class StreamBuffer final {
+public:
+    StreamBuffer(u64 size);
+    StreamBuffer(const StreamBuffer& other) = delete;
+    StreamBuffer(StreamBuffer&& other) = delete;
+    StreamBuffer& operator=(const StreamBuffer& other) = delete;
+    StreamBuffer& operator=(StreamBuffer&& other) = delete;
+
+    void reset(u64 size);
+    StreamBuffer& add(float f);
+    void draw(uint floatPerVertex);
+
+private:
+    u64 bufferSize;
+    u64 offset;
+
+    u64 index;
+    float* buffer;
+};
+
+#endif

+ 29 - 0
rendering/wrapper/Texture.cpp

@@ -0,0 +1,29 @@
+#include "rendering/wrapper/Texture.h"
+#include "rendering/wrapper/GLWrapper.h"
+
+Texture::Texture() : texture(0) {
+    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);
+}
+
+Texture::~Texture() {
+    glDeleteTextures(1, &texture);
+}
+
+void Texture::setRGBAData(int width, int height, const u32* data) {
+    glBindTexture(GL_TEXTURE_2D, texture);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+}
+
+void Texture::setRGBFloatData(int width, int height, const float* data) {
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_FLOAT, data);
+}
+
+void Texture::bind() const {
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, texture);
+}

+ 26 - 0
rendering/wrapper/Texture.h

@@ -0,0 +1,26 @@
+#ifndef TEXTURE_H
+#define TEXTURE_H
+
+#include <GL/glew.h>
+
+#include "utils/Types.h"
+
+class Texture final {
+public:
+    Texture();
+    ~Texture();
+    Texture(const Texture& other) = delete;
+    Texture(Texture&& other) = delete;
+    Texture& operator=(const Texture& other) = delete;
+    Texture& operator=(Texture&& other) = delete;
+    
+    void setRGBAData(int width, int height, const u32* data);
+    void setRGBFloatData(int width, int height, const float* data);
+    
+    void bind() const;
+
+private:
+    GLuint texture;
+};
+
+#endif

+ 37 - 0
rendering/wrapper/VertexBuffer.cpp

@@ -0,0 +1,37 @@
+#include "rendering/wrapper/VertexBuffer.h"
+
+VertexBuffer::VertexBuffer() : vertexArray(0), vertexBuffer(0) {
+    glGenVertexArrays(1, &vertexArray);
+    glGenBuffers(1, &vertexBuffer);
+}
+
+VertexBuffer::~VertexBuffer() {
+    glDeleteBuffers(1, &vertexBuffer);
+    glDeleteVertexArrays(1, &vertexArray);
+}
+
+void VertexBuffer::setFloatAttribute(uint index, uint length, uint offset, uint step) {
+    glVertexAttribPointer(index, length, GL_FLOAT, false, sizeof (float) * step, static_cast<float*> (0) + offset);
+    glEnableVertexAttribArray(index);
+}
+
+void VertexBuffer::setData(u64 size, const void* data) {
+    glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
+}
+
+void VertexBuffer::bindArray() const {
+    glBindVertexArray(vertexArray);
+}
+
+void VertexBuffer::bindBuffer() const {
+    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
+}
+
+void VertexBuffer::bind() const {
+    bindArray();
+    bindBuffer();
+}
+
+void VertexBuffer::draw(uint vertices) const {
+    glDrawArrays(GL_TRIANGLES, 0, vertices);
+}

+ 31 - 0
rendering/wrapper/VertexBuffer.h

@@ -0,0 +1,31 @@
+#ifndef VERTEXBUFFER_H
+#define VERTEXBUFFER_H
+
+#include <GL/glew.h>
+
+#include "utils/Types.h"
+
+class VertexBuffer final {
+public:
+    VertexBuffer();
+    ~VertexBuffer();
+    VertexBuffer(const VertexBuffer& other) = delete;
+    VertexBuffer(VertexBuffer&& other) = delete;
+    VertexBuffer& operator=(const VertexBuffer& other) = delete;
+    VertexBuffer& operator=(VertexBuffer&& other) = delete;
+    
+    void setFloatAttribute(uint index, uint length, uint offset, uint step);
+    void setData(u64 size, const void* data);
+    
+    void bindArray() const;
+    void bindBuffer() const;
+    void bind() const;
+    
+    void draw(uint vertices) const;
+
+private:
+    GLuint vertexArray;
+    GLuint vertexBuffer;
+};
+
+#endif

+ 64 - 0
rendering/wrapper/Window.cpp

@@ -0,0 +1,64 @@
+#include <iostream>
+
+#include "rendering/wrapper/Window.h"
+
+Window::Window(const WindowSize& size, const char* windowName) : window(nullptr) {
+    glfwDefaultWindowHints();
+    glfwWindowHint(GLFW_VISIBLE, 0);
+    glfwWindowHint(GLFW_RESIZABLE, 1);
+    glfwWindowHint(GLFW_DECORATED, 0);
+    
+    glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
+
+    window = glfwCreateWindow(size.width, size.height, windowName, glfwGetPrimaryMonitor(), nullptr);
+    if(window == nullptr) {
+        std::cout << "could not create window\n";
+        return;
+    }
+    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
+    glfwMakeContextCurrent(window);
+    glfwSwapInterval(1);
+
+    glfwSetWindowUserPointer(window, this);
+}
+
+Window::~Window() {
+    if(window != nullptr) {
+        glfwDestroyWindow(window);
+    }
+}
+
+bool Window::hasError() const {
+    return window == nullptr;
+}
+
+void Window::show() {
+    glfwShowWindow(window);
+}
+
+bool Window::shouldClose() const {
+    return glfwWindowShouldClose(window);
+}
+
+void Window::swapBuffers() {
+    glfwSwapBuffers(window);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void Window::setFramebufferSizeCallback(GLFWframebuffersizefun f) {
+    glfwSetFramebufferSizeCallback(window, f);
+}
+
+void Window::setKeyCallback(GLFWkeyfun f) {
+    glfwSetKeyCallback(window, f);
+}
+
+void Window::setMouseButtonCallback(GLFWmousebuttonfun f) {
+    glfwSetMouseButtonCallback(window, f);
+}
+
+void Window::setCursorPosCallback(GLFWcursorposfun f) {
+    glfwSetCursorPosCallback(window, f);
+}

+ 33 - 0
rendering/wrapper/Window.h

@@ -0,0 +1,33 @@
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+
+#include "rendering/WindowSize.h"
+
+class Window final {
+public:
+    Window(const WindowSize& size, const char* windowName);
+    ~Window();
+
+    Window(const Window&) = delete;
+    Window& operator=(const Window&) = delete;
+    Window(Window&&) = delete;
+    Window& operator=(Window&&) = delete;
+
+    bool hasError() const;
+    void show();
+    bool shouldClose() const;
+    void swapBuffers();
+
+    void setFramebufferSizeCallback(GLFWframebuffersizefun f);
+    void setKeyCallback(GLFWkeyfun f);
+    void setMouseButtonCallback(GLFWmousebuttonfun f);
+    void setCursorPosCallback(GLFWcursorposfun f);
+
+private:
+    GLFWwindow* window;
+};
+
+#endif

BIN
resources/font.png


+ 23 - 0
resources/shader/fragment.fs

@@ -0,0 +1,23 @@
+#version 300 es
+
+precision highp float;
+
+uniform sampler2D samp;
+
+uniform bool useTexture;
+uniform bool useColor;
+
+in vec2 varTex;
+in vec4 varColor;
+out vec4 color;
+
+void main() {
+    if(useTexture) {
+        color = texture2D(samp, varTex);
+        if(useColor) {
+            color = vec4(varColor.xyz, color.w);
+        }
+    } else {
+        color = varColor;
+    }
+}

+ 19 - 0
resources/shader/vertex.vs

@@ -0,0 +1,19 @@
+#version 300 es
+
+precision highp float;
+
+layout (location = 0) in vec2 position;
+layout (location = 1) in vec2 tex;
+layout (location = 2) in vec4 color;
+
+uniform mat3 view;
+uniform mat3 model;
+
+out vec2 varTex;
+out vec4 varColor;
+
+void main() { 
+    varTex = tex; 
+    varColor = color; 
+    gl_Position = vec4(view * model * vec3(position, 1.0), 1.0);
+}

BIN
resources/textures.png


+ 59 - 0
utils/Array.h

@@ -0,0 +1,59 @@
+#ifndef ARRAY_H
+#define ARRAY_H
+
+#include "utils/Types.h"
+
+template<typename T, uint N>
+class Array final {
+public:
+
+    Array() {
+    }
+
+    Array(const T& t) {
+        for(uint i = 0; i < N; i++) {
+            data[i] = t;
+        }
+    }
+
+    const T& operator[](uint index) const {
+        return data[index];
+    }
+
+    T& operator[](uint index) {
+        return data[index];
+    }
+
+    const T* operator+(uint index) const {
+        return data + index;
+    }
+
+    T* operator+(uint index) {
+        return data + index;
+    }
+
+    T* begin() {
+        return data;
+    }
+
+    const T* begin() const {
+        return data;
+    }
+
+    T* end() {
+        return data + N;
+    }
+
+    const T* end() const {
+        return data + N;
+    }
+
+    uint getLength() const {
+        return N;
+    }
+
+private:
+    T data[N];
+};
+
+#endif

+ 23 - 0
utils/Clock.cpp

@@ -0,0 +1,23 @@
+#include "utils/Clock.h"
+#include "rendering/wrapper/GLFWWrapper.h"
+
+Clock::Clock() : last(GLFWWrapper::getTimeNanos()), index(0), sum(0), time(0) {
+}
+
+u64 Clock::update() {
+    index = (index + 1) & (length - 1);
+    u64 current = GLFWWrapper::getTimeNanos();
+    sum -= time[index];
+    time[index] = current - last;
+    sum += time[index];
+    last = current;
+    return time[index];
+}
+
+u64 Clock::getLength() const {
+    return length;
+}
+
+float Clock::getUpdatesPerSecond() const {
+    return length * (1000000000.0f / sum);
+}

+ 23 - 0
utils/Clock.h

@@ -0,0 +1,23 @@
+#ifndef CLOCK_H
+#define CLOCK_H
+
+#include "utils/Types.h"
+#include "utils/Array.h"
+
+class Clock final {
+public:
+    Clock();
+    u64 update();
+    u64 getLength() const;
+    float getUpdatesPerSecond() const;
+
+private:
+    static constexpr u64 bits = 7;
+    static constexpr u64 length = 1 << bits;
+    u64 last;
+    u64 index;
+    s64 sum;
+    Array<u64, length> time;
+};
+
+#endif

+ 97 - 0
utils/HashMap.h

@@ -0,0 +1,97 @@
+#ifndef HASHMAP_H
+#define HASHMAP_H
+
+#include "common/utils/Types.h"
+
+template<typename K, typename V, uint L>
+class HashMap final {
+public:
+
+    HashMap(K emptyKey, V emptyValue) : entries(0), emptyKey(emptyKey), emptyValue(emptyValue) {
+        for(uint i = 0; i < LENGTH; i++) {
+            data[i].key = emptyKey;
+            data[i].value = emptyValue;
+        }
+    }
+
+    static constexpr uint getCapacity() {
+        return LENGTH;
+    }
+
+    void add(const K key, const V value) {
+        if(entries >= L) {
+            return;
+        }
+        uint hash = hashCode(key) % LENGTH;
+        while(true) {
+            if(data[hash].key == key) {
+                data[hash].value = value;
+                return;
+            } else if(data[hash].key == emptyKey) {
+                data[hash].key = key;
+                data[hash].value = value;
+                entries++;
+                return;
+            }
+            hash = (hash + 1) % LENGTH;
+        }
+    }
+
+    V search(const K key) const {
+        uint hash = hashCode(key) % LENGTH;
+        while(true) {
+            if(data[hash].key == key) {
+                return data[hash].value;
+            } else if(data[hash].key == emptyKey) {
+                return emptyValue;
+            }
+            hash = (hash + 1) % LENGTH;
+        }
+    }
+
+    void forEach(void (*f)(const K&, V&)) {
+        for(uint i = 0; i < LENGTH; i++) {
+            if(data[i].key != emptyKey) {
+                f(data[i].key, data[i].value);
+            }
+        }
+    }
+
+private:
+
+    static constexpr uint getLength() {
+        constexpr uint SIZE_TABLE[] = {
+            2, 3, 7, 11, 23, 43, 89, 173, 347, 683, 1367, 2731, 5471, 10937, 21851, 43691, 87383, 174763, 349529, 699053,
+            1398107, 2796203, 5592407, 11184829, 22369661, 44739259, 89478503, 178956983, 357913951, 715827883, 1431655777,
+            2863311551
+        };
+        uint i = 0;
+        while(SIZE_TABLE[i] < L) {
+            i++;
+        }
+        return SIZE_TABLE[i];
+    }
+
+    template<typename H>
+    uint hashCode(const H& h) const {
+        return h.hashCode();
+    }
+
+    uint hashCode(const uint& h) const {
+        return h;
+    }
+
+    static constexpr uint LENGTH = getLength();
+
+    uint entries;
+    K emptyKey;
+    V emptyValue;
+
+    struct KeyValuePair {
+        K key;
+        V value;
+    };
+    KeyValuePair data[LENGTH];
+};
+
+#endif

+ 29 - 0
utils/HashedString.cpp

@@ -0,0 +1,29 @@
+#include "common/utils/HashedString.h"
+
+HashedString::HashedString() : length(0), hash(0) {
+    data[length] = '\0';
+}
+
+HashedString::HashedString(const char* str) : length(0), hash(0) {
+    for(; length < LENGTH - 1 && str[length] != '\0'; length++) {
+        data[length] = str[length];
+        hash = hash * 257 + str[length];
+    }
+    data[length] = '\0';
+}
+
+bool HashedString::operator==(const HashedString& other) const {
+    return hash == other.hash && length == other.length;
+}
+
+bool HashedString::operator!=(const HashedString& other) const {
+    return !(*this == other);
+}
+
+HashedString::operator const char*() const {
+    return data;
+}
+
+u32 HashedString::hashCode() const {
+    return hash;
+}

+ 24 - 0
utils/HashedString.h

@@ -0,0 +1,24 @@
+#ifndef HASHEDSTRING_H
+#define HASHEDSTRING_H
+
+#include "common/utils/Types.h"
+
+class HashedString final {
+public:
+    HashedString();
+    HashedString(const char* str);
+
+    bool operator==(const HashedString& other) const;
+    bool operator!=(const HashedString& other) const;
+    operator const char*() const;
+
+    u32 hashCode() const;
+
+private:
+    static constexpr uint LENGTH = 32 - sizeof (u8) - sizeof (u32);
+    char data[LENGTH];
+    u8 length;
+    u32 hash;
+};
+
+#endif

+ 67 - 0
utils/List.h

@@ -0,0 +1,67 @@
+#ifndef LIST_H
+#define LIST_H
+
+#include "utils/Types.h"
+
+template<typename T, uint L>
+class List final {
+public:
+
+    List() : entries(0) {
+    }
+
+    List& add(const T& t) {
+        if(entries >= L) {
+            return *this;
+        }
+        data[entries++] = t;
+        return *this;
+    }
+
+    List& clear() {
+        entries = 0;
+        return *this;
+    }
+
+    uint getLength() const {
+        return entries;
+    }
+
+    uint getCapacity() const {
+        return L;
+    }
+
+    T& operator[](uint index) {
+        return data[index];
+    }
+
+    const T& operator[](uint index) const {
+        return data[index];
+    }
+
+    const T* getData() {
+        return data;
+    }
+
+    T* begin() {
+        return data;
+    }
+
+    const T* begin() const {
+        return data;
+    }
+
+    T* end() {
+        return data + entries;
+    }
+
+    const T* end() const {
+        return data + entries;
+    }
+
+private:
+    uint entries;
+    T data[L];
+};
+
+#endif

+ 85 - 0
utils/PNGReader.cpp

@@ -0,0 +1,85 @@
+#include <iostream>
+#include <png.h>
+#include <cstring>
+
+#include "utils/PNGReader.h"
+
+static bool checkSignature(const char* path, FILE* file) {
+    unsigned char buffer[8];
+    if(fread(buffer, sizeof (char), 8, file) != 8) {
+        std::cout << "cannot read signature of texture '" << path << "'\n";
+        return true;
+    }
+    if(png_sig_cmp(buffer, 0, 8)) {
+        std::cout << "file '" << path << "' is not a texture\n";
+        return true;
+    }
+    return false;
+}
+
+static bool load(const char* path, FILE* file, u32* buffer, u32& maxWidth, u32& maxHeight) {
+    if(checkSignature(path, file)) {
+        return false;
+    }
+
+    png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
+    if(png == nullptr) {
+        std::cout << "cannot create texture data structure\n";
+        return false;
+    }
+
+    png_infop info = png_create_info_struct(png);
+    if(info == nullptr) {
+        std::cout << "cannot create image info structure\n";
+        return false;
+    }
+
+    u32** rowPointers = nullptr;
+
+    if(setjmp(png_jmpbuf(png))) { // set callback for errors
+        if(rowPointers != nullptr) {
+            png_free(png, rowPointers);
+        }
+        png_destroy_read_struct(&png, &info, nullptr);
+        std::cout << "texture '" << path << "' has used error callback\n";
+        return false;
+    }
+
+    png_init_io(png, file); // set reading function
+    png_set_sig_bytes(png, 8); // notify about already used signature bytes
+
+    png_read_info(png, info); // read info data
+    
+    u32 width = png_get_image_width(png, info);
+    u32 height = png_get_image_height(png, info);
+    if(width > maxWidth || height > maxHeight) {
+        std::cout << "texture '" << path << "' is too big: " << maxWidth << " x " << maxHeight << " allowed\n";
+        return false;
+    }
+    maxWidth = width;
+    maxHeight = height;
+    
+    // allocate and set row pointer to correct places in block
+    rowPointers = static_cast<u32**> (png_malloc(png, height * (sizeof (u32*))));
+    for(uint i = 0; i < height; i++) {
+        rowPointers[i] = (buffer + i * width);
+    }
+    png_set_rows(png, info, reinterpret_cast<png_bytepp> (rowPointers));
+
+    png_read_image(png, reinterpret_cast<png_bytepp> (rowPointers));
+
+    png_free(png, rowPointers);
+    png_destroy_read_struct(&png, &info, nullptr);
+    return true;
+}
+
+bool PNGReader::load(const char* path, u32* buffer, u32& maxWidth, u32& maxHeight) {
+    FILE* file = fopen(path, "r");
+    if(file == nullptr) {
+        std::cout << "texture '" << path << "' cannot be read: " << strerror(errno) << "\n";
+        return false;
+    }
+    bool result = load(path, file, buffer, maxWidth, maxHeight);
+    fclose(file);
+    return result;
+}

+ 10 - 0
utils/PNGReader.h

@@ -0,0 +1,10 @@
+#ifndef PNGREADER_H
+#define PNGREADER_H
+
+#include "utils/Types.h"
+
+namespace PNGReader {
+    bool load(const char* path, u32* buffer, u32& maxWidth, u32& maxHeight);
+}
+
+#endif

+ 26 - 0
utils/Random.cpp

@@ -0,0 +1,26 @@
+#include <chrono>
+
+#include "common/utils/Random.h"
+
+Random::Random() : seed(std::chrono::steady_clock::now().time_since_epoch().count()) {
+}
+
+Random::Random(u64 seed) : seed(seed) {
+}
+
+u32 Random::next() {
+    return nextSeed() >> 24;
+}
+
+u32 Random::next(uint bound) {
+    return next() % bound;
+}
+
+float Random::nextFloat() {
+    return next() * (1.0f / (0xFFFFFF + 1.0f));
+}
+
+u64 Random::nextSeed() {
+    seed = (seed * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFFFFF;
+    return seed;
+}

+ 21 - 0
utils/Random.h

@@ -0,0 +1,21 @@
+#ifndef RANDOM_H
+#define RANDOM_H
+
+#include "common/utils/Types.h"
+
+class Random {
+public:
+    Random();
+    Random(u64 seed);
+
+    u32 next();
+    u32 next(uint bound);
+    float nextFloat();
+
+private:
+    u64 nextSeed();
+
+    u64 seed;
+};
+
+#endif

+ 31 - 0
utils/RingBuffer.h

@@ -0,0 +1,31 @@
+#ifndef RINGBUFFER_H
+#define RINGBUFFER_H
+
+#include "common/utils/Array.h"
+
+template<typename T, uint N>
+class RingBuffer final {
+public:
+
+    void write(const T& t) {
+        data[writeIndex] = t;
+        writeIndex = (writeIndex + 1) % N;
+    }
+
+    bool canRead() const {
+        return writeIndex != readIndex;
+    }
+
+    T read() {
+        T& t = data[readIndex];
+        readIndex = (readIndex + 1) % N;
+        return t;
+    }
+
+private:
+    Array<T, N> data;
+    uint writeIndex = 0;
+    uint readIndex = 0;
+};
+
+#endif

+ 44 - 0
utils/SplitString.cpp

@@ -0,0 +1,44 @@
+#include "common/utils/SplitString.h"
+
+SplitString::SplitString(const char* str) : entries(0) {
+    for(uint i = 0; str[i] != '\0'; i++) {
+        if(str[i] == '"') {
+            if(i >= 1 && str[i - 1] != ' ') {
+                return;
+            }
+            data += '"';
+            i++;
+            while(str[i] != '"') {
+                if(str[i] == '\0') {
+                    return;
+                }
+                data += str[i++];
+            }
+            if(str[i + 1] != '\0' && str[i + 1] != ' ') {
+                return;
+            }
+            data += '\0';
+            continue;
+        }
+        data += (str[i] == ' ' ? '\0' : str[i]);
+    }
+    uint last = 0;
+    for(uint i = 0; i < data.getLength() + 1; i++) {
+        if(data[i] != '\0' && data[i] != '"') {
+            continue;
+        }
+        if(i - last > 0 || (i >= 1 && data[i - 1] == '"')) {
+            starts[entries++] = last;
+        }
+        last = i + 1;
+    }
+}
+
+uint SplitString::getLength() const {
+    return entries;
+}
+
+const char* SplitString::operator[](uint index) const {
+    return data + starts[index];
+}
+

+ 19 - 0
utils/SplitString.h

@@ -0,0 +1,19 @@
+#ifndef SPLITSTRING_H
+#define SPLITSTRING_H
+
+#include "common/utils/String.h"
+
+class SplitString final {
+public:
+    SplitString(const char* str);
+    
+    uint getLength() const;
+    const char* operator[](uint index) const;
+
+private:
+    String data;
+    uint entries;
+    u8 starts[String::MAX_LENGTH];
+};
+
+#endif

+ 62 - 0
utils/String.cpp

@@ -0,0 +1,62 @@
+#include <cstring>
+#include <cstdio>
+
+#include "utils/String.h"
+
+String::String() : length(0) {
+    data[0] = '\0';
+}
+
+String::String(const char* str) : length(0) {
+    for(; length < MAX_LENGTH - 1 && str[length] != '\0'; length++) {
+        data[length] = str[length];
+    }
+    data[length] = '\0';
+}
+
+bool String::operator==(const String& other) const {
+    return length == other.length && strcmp(data, other.data) == 0;
+}
+
+bool String::operator!=(const String& other) const {
+    return !(*this == other);
+}
+
+String::operator const char*() const {
+    return data;
+}
+
+char String::operator[](uint index) const {
+    return data[index];
+}
+
+uint String::getLength() const {
+    return length;
+}
+
+String& String::append(char c) {
+    if(length < MAX_LENGTH - 1) {
+        data[length++] = c;
+        data[length] = '\0';
+    }
+    return *this;
+}
+
+String& String::append(const char* str) {
+    for(uint i = 0; length < MAX_LENGTH - 1 && str[i] != '\0'; length++, i++) {
+        data[length] = str[i];
+    }
+    data[length] = '\0';
+    return *this;
+}
+
+String& String::append(int i) {
+    uint left = MAX_LENGTH - length;
+    uint written = snprintf(data + length, left, "%d", i);
+    if(written < left) {
+        length += written;
+    } else {
+        length = MAX_LENGTH;
+    }
+    return *this;
+}

+ 27 - 0
utils/String.h

@@ -0,0 +1,27 @@
+#ifndef STRING_H
+#define STRING_H
+
+#include "utils/Types.h"
+
+class String final {
+public:
+    String();
+    String(const char* str);
+    
+    bool operator==(const String& other) const;
+    bool operator!=(const String& other) const;
+    operator const char*() const;
+    char operator[](uint index) const;
+    uint getLength() const;
+    
+    String& append(char c);
+    String& append(const char* str);
+    String& append(int i);
+
+private:
+    static constexpr uint MAX_LENGTH = 255;
+    char data[MAX_LENGTH];
+    u8 length;
+};
+
+#endif

+ 30 - 0
utils/Types.h

@@ -0,0 +1,30 @@
+#ifndef TYPES_H
+#define TYPES_H
+
+typedef unsigned int uint;
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+typedef unsigned long long u64;
+
+typedef char s8;
+typedef short s16;
+typedef int s32;
+typedef long long s64;
+
+typedef u32 size;
+
+static_assert(sizeof(u8) == 1, "u8 is not 8 bit");
+static_assert(sizeof(u16) == 2, "u16 is not 16 bit");
+static_assert(sizeof(u32) == 4, "u32 is not 32 bit");
+static_assert(sizeof(u64) == 8, "u64 is not 64 bit");
+
+static_assert(sizeof(s8) == 1, "s8 is not 8 bit");
+static_assert(sizeof(s16) == 2, "s16 is not 16 bit");
+static_assert(sizeof(s32) == 4, "s32 is not 64 bit");
+static_assert(sizeof(s64) == 8, "s64 is not 64 bit");
+
+static_assert(sizeof(size) == sizeof(nullptr), "size has not the same size as a nullpointer");
+
+#endif

+ 5 - 0
utils/Utils.cpp

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

+ 6 - 0
utils/Utils.h

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