Kajetan Johannes Hammerle il y a 4 ans
commit
7dab936f00
19 fichiers modifiés avec 701 ajouts et 0 suppressions
  1. 37 0
      Game.cpp
  2. 19 0
      Game.h
  3. 82 0
      Main.cpp
  4. 50 0
      input/Keys.cpp
  5. 31 0
      input/Keys.h
  6. 14 0
      meson.build
  7. 45 0
      rendering/GL.cpp
  8. 10 0
      rendering/GL.h
  9. 29 0
      rendering/GLFW.cpp
  10. 11 0
      rendering/GLFW.h
  11. 72 0
      rendering/Renderer.cpp
  12. 37 0
      rendering/Renderer.h
  13. 83 0
      rendering/Shader.cpp
  14. 27 0
      rendering/Shader.h
  15. 53 0
      rendering/Window.cpp
  16. 28 0
      rendering/Window.h
  17. 26 0
      utils/Random.cpp
  18. 21 0
      utils/Random.h
  19. 26 0
      utils/Types.h

+ 37 - 0
Game.cpp

@@ -0,0 +1,37 @@
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+#include <iostream>
+
+#include "Game.h"
+#include "utils/Random.h"
+
+Game::Game(Keys& keys) : keys(keys) {
+    std::cout << "register on " << keys.add(GLFW_KEY_W) << "\n";
+}
+
+void Game::tick() {
+    std::cout << keys.getDownTime(0) << " - 0 \n";
+    std::cout << keys.getDownTime(1) << " - 1 \n";
+    std::cout << keys.getDownTime(5335) << " - 5335\n";
+}
+
+void Game::render(float lag, Renderer& renderer) const {
+    (void) lag;
+    renderer.setPointSize(4);
+    renderer.drawPoint(0.5f, 0.5f, 0xFF0000);
+    renderer.drawPoint(0.0f, 0.5f, 0x00FF00);
+    renderer.drawPoint(0.5f, 0.0f, 0x0000FF);
+    renderer.drawLine(0.5f, 0.0f, 1.0f, 1.0f, 0xFFFF00);
+
+    Random r(0);
+    for(uint i = 0; i < 1000; i++) {
+        renderer.drawPoint(
+                r.nextFloat() * 2.0f - 1.0f,
+                r.nextFloat() * 2.0f - 1.0f,
+                0xFF0000);
+    }
+}
+
+bool Game::isRunning() const {
+    return true;
+}

+ 19 - 0
Game.h

@@ -0,0 +1,19 @@
+#ifndef GAME_H
+#define GAME_H
+
+#include "input/Keys.h"
+#include "rendering/Renderer.h"
+
+class Game final {
+public:
+    Game(Keys& control);
+
+    void tick();
+    void render(float lag, Renderer& renderer) const;
+    bool isRunning() const;
+
+private:
+    Keys& keys;
+};
+
+#endif

+ 82 - 0
Main.cpp

@@ -0,0 +1,82 @@
+#include <iostream>
+
+#include "rendering/GLFW.h"
+#include "rendering/Window.h"
+#include "rendering/Shader.h"
+#include "input/Keys.h"
+#include "rendering/GL.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, Keys& keys) {
+    static Keys& cKeys = keys;
+    w.setFramebufferSizeCallback([](GLFWwindow*, int newWidth, int newHeight) {
+        glViewport(0, 0, newWidth, newHeight);
+    });
+    w.setKeyCallback([](GLFWwindow*, int key, int, int action, int) {
+        if(action == GLFW_PRESS) {
+            cKeys.press(key);
+        } else if(action == GLFW_RELEASE) {
+            cKeys.release(key);
+        }
+    });
+}
+
+int main() {
+    if(GLFW::hasError()) {
+        return 0;
+    }
+
+    Window window(1024, 620, "Test");
+    if(window.hasError() || initGLEW()) {
+        return 0;
+    }
+
+    Shader shader;
+    if(shader.hasError()) {
+        return 0;
+    }
+
+    Keys keys;
+    Game game(keys);
+    
+    initCallbacks(window, keys);
+    window.show();
+    
+    GL::enableDepthTesting();
+    GL::checkAndPrintError("setup error");
+
+    const u64 nanosPerTick = 50000000;
+    u64 lastTime = GLFW::getTimeNanos();
+    u64 lag = 0;
+    while(!window.shouldClose() && game.isRunning()) {
+        GL::checkAndPrintError("loop error");
+        
+        GL::prepareMainFramebuffer();
+        shader.use();
+        Renderer renderer;
+        game.render(static_cast<float> (lag) / nanosPerTick, renderer);
+        
+        window.swapBuffers();
+        u64 currentTime = GLFW::getTimeNanos();
+        lag += currentTime - lastTime;
+        lastTime = currentTime;
+        while(lag >= nanosPerTick) {
+            lag -= nanosPerTick;
+            keys.tick();
+            game.tick();
+        }
+        glfwPollEvents();
+    }
+    return 0;
+}

+ 50 - 0
input/Keys.cpp

@@ -0,0 +1,50 @@
+#include <GLFW/glfw3.h>
+
+#include "input/Keys.h"
+
+Keys::Key::Key() : glfwKey(-1), down(false), downTime(0) {
+}
+
+uint Keys::searchKey(int glfwKey) const {
+    for(uint i = 1; i < keys.size(); i++) {
+        if(keys[i].glfwKey == glfwKey) {
+            return i;
+        }
+    }
+    return 0;
+}
+
+uint Keys::getIndex(uint key) const {
+    return key * (key < keys.size());
+}
+
+uint Keys::add(int glfwKey) {
+    uint index = searchKey(-1);
+    keys[index].glfwKey = glfwKey;
+    return index;
+}
+
+bool Keys::isDown(uint key) const {
+    return keys[getIndex(key)].down;
+}
+
+uint Keys::getDownTime(uint key) const {
+    return keys[getIndex(key)].downTime;
+}
+
+void Keys::release(int glfwKey) {
+    uint index = searchKey(glfwKey);
+    keys[index].down = false;
+    keys[index].downTime = 0;
+}
+
+void Keys::press(int glfwKey) {
+    uint index = searchKey(glfwKey);
+    keys[index].down = true;
+}
+
+void Keys::tick() {
+    for(uint i = 1; i < keys.size(); i++) {
+        keys[i].downTime += keys[i].down;
+    }
+}

+ 31 - 0
input/Keys.h

@@ -0,0 +1,31 @@
+#ifndef KEYS_H
+#define KEYS_H
+
+#include <array>
+
+#include "utils/Types.h"
+
+struct Keys final {
+    uint add(int glfwKey);
+    bool isDown(uint key) const;
+    uint getDownTime(uint key) const;
+
+    void release(int glfwKey);
+    void press(int glfwKey);
+    void tick();
+
+private:
+    uint searchKey(int glfwKey) const;
+    uint getIndex(uint key) const;
+
+    struct Key {
+        Key();
+        int glfwKey;
+        bool down;
+        uint downTime;
+    };
+
+    std::array<Key, 20> keys;
+};
+
+#endif

+ 14 - 0
meson.build

@@ -0,0 +1,14 @@
+project('convex hull', 'cpp')
+
+sources = ['utils/Random.cpp', 'Main.cpp', 'rendering/GLFW.cpp', 'rendering/Window.cpp', 'input/Keys.cpp', 'rendering/Shader.cpp', 'Game.cpp', 'rendering/GL.cpp', 'rendering/Renderer.cpp']
+
+glewDep = dependency('glew')
+glfwDep = dependency('glfw3')
+
+executable('game_client', 
+    sources: sources,
+    dependencies : [glewDep, glfwDep],
+    cpp_args: ['-Wall', '-Wextra', '-pedantic', '-Werror'])
+    
+
+	

+ 45 - 0
rendering/GL.cpp

@@ -0,0 +1,45 @@
+#include <GL/glew.h>
+#include <iostream>
+
+#include "rendering/GL.h"
+
+bool GL::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 GL::enableDepthTesting() {
+    glEnable(GL_DEPTH_TEST);
+}
+
+void GL::prepareMainFramebuffer() {
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+}

+ 10 - 0
rendering/GL.h

@@ -0,0 +1,10 @@
+#ifndef GL_H
+#define GL_H
+
+namespace GL {
+    bool checkAndPrintError(const char* message);
+    void enableDepthTesting();
+    void prepareMainFramebuffer();
+}
+
+#endif

+ 29 - 0
rendering/GLFW.cpp

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

+ 11 - 0
rendering/GLFW.h

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

+ 72 - 0
rendering/Renderer.cpp

@@ -0,0 +1,72 @@
+#include <cassert>
+
+#include "rendering/Renderer.h"
+
+static void 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);
+}
+
+Renderer::Renderer() : vertexArray(0), vertexBuffer(0), bufferSize(8 * 1024 * 1024), offset(bufferSize), index(0),
+buffer(nullptr) {
+    glGenVertexArrays(1, &vertexArray);
+    glGenBuffers(1, &vertexBuffer);
+    bind();
+    setFloatAttribute(0, 2, 0, 5);
+    setFloatAttribute(1, 3, 2, 5);
+}
+
+Renderer::~Renderer() {
+    glDeleteBuffers(1, &vertexBuffer);
+    glDeleteVertexArrays(1, &vertexArray);
+}
+
+void Renderer::setPointSize(float size) {
+    glPointSize(size);
+}
+
+void Renderer::drawPoint(float x, float y, uint color) {
+    bind();
+    reset(sizeof (float) * 5);
+    add(x).add(y).add(getColorChannel(color, 16)).add(getColorChannel(color, 8)).add(getColorChannel(color, 0));
+    draw(GL_POINTS);
+}
+
+void Renderer::drawLine(float x, float y, float x2, float y2, uint color) {
+    bind();
+    reset(sizeof (float) * 10);
+    add(x).add(y).add(getColorChannel(color, 16)).add(getColorChannel(color, 8)).add(getColorChannel(color, 0));
+    add(x2).add(y2).add(getColorChannel(color, 16)).add(getColorChannel(color, 8)).add(getColorChannel(color, 0));
+    draw(GL_LINES);
+}
+
+void Renderer::bind() {
+    glBindVertexArray(vertexArray);
+    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
+}
+
+void Renderer::reset(u64 size) {
+    if(offset + size >= bufferSize) {
+        offset = 0;
+        glBufferData(GL_ARRAY_BUFFER, bufferSize, nullptr, GL_STREAM_DRAW);
+    }
+    constexpr uint bits = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
+    buffer = static_cast<float*> (glMapBufferRange(GL_ARRAY_BUFFER, offset, size, bits));
+    assert(buffer != nullptr);
+    index = 0;
+}
+
+Renderer& Renderer::add(float f) {
+    buffer[index++] = f;
+    return *this;
+}
+
+void Renderer::draw(uint type) {
+    glUnmapBuffer(GL_ARRAY_BUFFER);
+    glDrawArrays(type, offset / (sizeof (float) * 5), index / 5);
+    offset += index * sizeof (float);
+}
+
+float Renderer::getColorChannel(uint color, uint shifts) const {
+    return ((color >> shifts) & 0xFF) * (1.0f / 255.0f);
+}

+ 37 - 0
rendering/Renderer.h

@@ -0,0 +1,37 @@
+#ifndef RENDERER_H
+#define RENDERER_H
+
+#include <GL/glew.h>
+
+#include "utils/Types.h"
+
+class Renderer final {
+public:
+    Renderer();
+    ~Renderer();
+    Renderer(const Renderer& other) = delete;
+    Renderer(Renderer&& other) = delete;
+    Renderer& operator=(const Renderer& other) = delete;
+    Renderer& operator=(Renderer&& other) = delete;
+    
+    void setPointSize(float size);
+    void drawPoint(float x, float y, uint color);
+    void drawLine(float x, float y, float x2, float y2, uint color);
+
+private:
+    void bind();
+    void reset(u64 size);
+    Renderer& add(float f);
+    void draw(uint floatPerVertex);
+    float getColorChannel(uint color, uint shifts) const;
+    
+    GLuint vertexArray;
+    GLuint vertexBuffer;
+    
+    u64 bufferSize;
+    u64 offset;
+    u64 index;
+    float* buffer;
+};
+
+#endif

+ 83 - 0
rendering/Shader.cpp

@@ -0,0 +1,83 @@
+#include <iostream>
+
+#include "rendering/Shader.h"
+#include "rendering/GL.h"
+
+static const GLchar* vertexShader =
+        "#version 430\n"
+        "layout (location = 0) in vec2 position;\n"
+        "layout (location = 1) in vec3 color;\n"
+        "out vec3 varColor;\n"
+        "void main() {\n"
+        "gl_Position = vec4(position, 0.0, 1.0);\n"
+        "varColor = color;\n"
+        "}";
+static const GLchar* fragmentShader =
+        "#version 430\n"
+        "in vec3 varColor;\n"
+        "out vec4 color;"
+        "void main() {\n"
+        "color = vec4(varColor, 1.0);"
+        "}";
+
+Shader::Shader() : vShader(0), fShader(0), program(0) {
+    if(compile(vShader, vertexShader, GL_VERTEX_SHADER) || compile(fShader, fragmentShader, GL_FRAGMENT_SHADER)) {
+        return;
+    }
+    program = glCreateProgram();
+    glAttachShader(program, vShader);
+    glAttachShader(program, fShader);
+    glLinkProgram(program);
+    if(GL::checkAndPrintError("shader linking error")) {
+        clean();
+        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";
+        clean();
+        return;
+    }
+}
+
+Shader::~Shader() {
+    clean();
+}
+
+void Shader::clean() {
+    glDeleteProgram(program);
+    glDeleteShader(vShader);
+    glDeleteShader(fShader);
+    program = 0;
+    vShader = 0;
+    fShader = 0;
+}
+
+bool Shader::hasError() const {
+    return vShader == 0 || fShader == 0 || program == 0;
+}
+
+bool Shader::compile(GLuint& shader, const GLchar* code, GLenum shaderType) {
+    shader = glCreateShader(shaderType);
+    glShaderSource(shader, 1, &code, nullptr);
+    glCompileShader(shader);
+    if(GL::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);
+}

+ 27 - 0
rendering/Shader.h

@@ -0,0 +1,27 @@
+#ifndef SHADER_H
+#define SHADER_H
+
+#include <GL/glew.h>
+
+class Shader final {
+public:
+    Shader();
+    ~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;
+
+private:
+    void clean();
+    bool compile(GLuint& shader, const GLchar* code, GLenum shaderType);
+
+    GLuint vShader;
+    GLuint fShader;
+    GLuint program;
+};
+
+#endif

+ 53 - 0
rendering/Window.cpp

@@ -0,0 +1,53 @@
+#include <iostream>
+
+#include "rendering/Window.h"
+
+Window::Window(int width, int height, const char* windowName) : window(nullptr) {
+    glfwDefaultWindowHints();
+    glfwWindowHint(GLFW_VISIBLE, 0);
+    glfwWindowHint(GLFW_RESIZABLE, 1);
+
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
+    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+
+    window = glfwCreateWindow(width, height, windowName, nullptr, nullptr);
+    if(window == nullptr) {
+        std::cout << "could not create window\n";
+        return;
+    }
+    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);
+}
+
+void Window::setFramebufferSizeCallback(GLFWframebuffersizefun f) {
+    glfwSetFramebufferSizeCallback(window, f);
+}
+
+void Window::setKeyCallback(GLFWkeyfun f) {
+    glfwSetKeyCallback(window, f);
+}

+ 28 - 0
rendering/Window.h

@@ -0,0 +1,28 @@
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+
+class Window final {
+public:
+    Window(int width, int height, 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);
+
+private:
+    GLFWwindow* window;
+};
+
+#endif

+ 26 - 0
utils/Random.cpp

@@ -0,0 +1,26 @@
+#include <chrono>
+
+#include "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 "utils/Types.h"
+
+class Random {
+public:
+    Random();
+    Random(u64 seed);
+
+    u32 next();
+    u32 next(uint bound);
+    float nextFloat();
+
+private:
+    u64 nextSeed();
+
+    u64 seed;
+};
+
+#endif

+ 26 - 0
utils/Types.h

@@ -0,0 +1,26 @@
+#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 u64;
+
+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");
+
+typedef char s8;
+typedef short s16;
+typedef int s32;
+typedef long s64;
+
+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 32 bit");
+static_assert(sizeof(s64) == 8, "s64 is not 64 bit");
+
+#endif