Kajetan Johannes Hammerle 2 giorni fa
parent
commit
202753e35e
4 ha cambiato i file con 235 aggiunte e 3 eliminazioni
  1. 1 1
      CMakeLists.txt
  2. 1 1
      src/Error.h
  3. 227 1
      src/Window.c
  4. 6 0
      src/Window.h

+ 1 - 1
CMakeLists.txt

@@ -66,7 +66,7 @@ endif()
 
 add_executable(${PROJECT_NAME} ${SRC})
 add_subdirectory(thirdparty/glfw)
-target_link_libraries(${PROJECT_NAME} PRIVATE glfw GL)
+target_link_libraries(${PROJECT_NAME} PRIVATE glfw GL GLEW)
 target_compile_options(${PROJECT_NAME} PUBLIC ${COMPILER_ARGUMENTS})
 
 add_executable(test test/Test.c)

+ 1 - 1
src/Error.h

@@ -2,7 +2,7 @@
 #define BASIC_ERROR_H
 
 typedef struct {
-    char text[256];
+    char text[1024];
 } Error;
 
 bool hasError(const Error* e);

+ 227 - 1
src/Window.c

@@ -1,12 +1,157 @@
 #include "Window.h"
 
+#include <GL/glew.h>
 #include <GLFW/glfw3.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #define SET_ERROR(format, ...)                                           \
     snprintf(e.text, sizeof(e.text), format __VA_OPT__(, ) __VA_ARGS__);
 
+#define WIDTH 240
+#define HEIGHT 160
+#define STR(x) STR2(x)
+#define STR2(x) #x
+
+typedef struct {
+    i32 key;
+    i32 downTime;
+    bool isDown;
+    char name[7];
+} ButtonData;
+
+static_assert(sizeof(ButtonData) == 16);
+
 static GLFWwindow* window = nullptr;
+static GLuint program = 0;
+static GLuint vShader = 0;
+static GLuint fShader = 0;
+static GLuint vbo = 0;
+static GLuint vba = 0;
+static GLuint texture = 0;
+static int width = 0;
+static int height = 0;
+static u8 pixels[HEIGHT][WIDTH][3] = {};
+
+static ButtonData buttons[] = {
+    [LEFT] = {0, 0, 0, "Left"},     [RIGHT] = {0, 0, 0, "Right"},
+    [UP] = {0, 0, 0, "Up"},         [DOWN] = {0, 0, 0, "Down"},
+    [SELECT] = {0, 0, 0, "Select"}, [START] = {0, 0, 0, "Start"},
+    [A] = {0, 0, 0, "A"},           [B] = {0, 0, 0, "B"},
+    [X] = {0, 0, 0, "X"},           [Y] = {0, 0, 0, "Y"},
+    [L] = {0, 0, 0, "L"},           [R] = {0, 0, 0, "R"}};
+static constexpr size_t BUTTONS = sizeof(buttons) / sizeof(ButtonData);
+
+// clang-format off
+static const GLchar* VERTEX_SHADER_CODE =
+    "#version 430\n"
+    "layout (location = 0) in vec2 pos;\n"
+    "uniform vec2 size;\n"
+    "out vec2 tex;\n"
+    "void main(void) {\n"
+    "    tex = pos;\n"
+    "    vec2 w = vec2(" STR(WIDTH) ", " STR(HEIGHT) ");\n"
+    "    ivec2 f = ivec2(size / w);\n"
+    "    f = ivec2(min(f.x, f.y), min(f.x, f.y));\n"
+    "    vec2 f2 = (f * w) / size;\n"
+    "    gl_Position = vec4(pos * f2, 0.0, 1.0);\n"
+    "}\n";
+// clang-format on
+
+static const GLchar* FRAGMENT_SHADER_CODE =
+    "#version 430\n"
+    "layout (binding = 0) uniform sampler2D image;\n"
+    "in vec2 tex;\n"
+    "out vec4 color;\n"
+    "void main(void) {\n"
+    "   vec2 c = (tex + vec2(1)) * 0.5;\n"
+    "   color = texture(image, vec2(c.x, 1 - c.y));\n"
+    "}\n";
+
+static void onKeyEvent(GLFWwindow*, int key, int, int action, int) {
+    if(action == GLFW_RELEASE) {
+        ButtonData* end = buttons + BUTTONS;
+        for(ButtonData* c = buttons; c != end; c++) {
+            if(c->key == key) {
+                c->isDown = false;
+                c->downTime = 0;
+            }
+        }
+    } else if(action == GLFW_PRESS) {
+        ButtonData* end = buttons + BUTTONS;
+        for(ButtonData* c = buttons; c != end; c++) {
+            if(c->key == key) {
+                c->isDown = true;
+            }
+        }
+    }
+}
+
+static void onWindowResize(GLFWwindow*, int w, int h) {
+    width = w;
+    height = h;
+}
+
+static void tickButtons() {
+    ButtonData* end = buttons + BUTTONS;
+    for(ButtonData* c = buttons; c != end; c++) {
+        c->downTime += c->isDown;
+    }
+}
+
+i32 isButtonDown(Button b) {
+    return buttons[b].isDown;
+}
+
+i32 getButtonDownTime(Button b) {
+    return buttons[b].downTime;
+}
+
+static Error checkShaderErrors(const char* name, GLuint shader) {
+    Error e = {};
+    GLint compiled = 0;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+    if(compiled == 0) {
+        GLchar buffer[512];
+        glGetShaderInfoLog(shader, sizeof(buffer), nullptr, buffer);
+        SET_ERROR("Failed %s shader compilation: %s\n", name, buffer);
+    }
+    return e;
+}
+
+static Error compileProgram() {
+    vShader = glCreateShader(GL_VERTEX_SHADER);
+    glShaderSource(vShader, 1, &VERTEX_SHADER_CODE, NULL);
+    glCompileShader(vShader);
+    Error e = checkShaderErrors("vertex", vShader);
+    if(hasError(&e)) {
+        return e;
+    }
+
+    fShader = glCreateShader(GL_FRAGMENT_SHADER);
+    glShaderSource(fShader, 1, &FRAGMENT_SHADER_CODE, NULL);
+    glCompileShader(fShader);
+    e = checkShaderErrors("fragment", fShader);
+    if(hasError(&e)) {
+        return e;
+    }
+
+    program = glCreateProgram();
+    glAttachShader(program, vShader);
+    glAttachShader(program, fShader);
+    glLinkProgram(program);
+    GLint compiled = 0;
+    glGetProgramiv(program, GL_LINK_STATUS, &compiled);
+    if(compiled == 0) {
+        GLchar buffer[512];
+        glGetProgramInfoLog(program, sizeof(buffer), nullptr, buffer);
+        SET_ERROR("Failed program linking: %s\n", buffer);
+        return e;
+    }
+    glUseProgram(program);
+    return e;
+}
 
 Error windowInit(const WindowSettings* ws) {
     Error e = {};
@@ -14,26 +159,107 @@ Error windowInit(const WindowSettings* ws) {
         SET_ERROR("Init window failed");
         return e;
     }
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
     window =
         glfwCreateWindow(ws->width, ws->height, ws->title, nullptr, nullptr);
     if(window == nullptr) {
         glfwTerminate();
-        SET_ERROR("Create window failed\n");
+        SET_ERROR("Create window failed");
         return e;
     }
+    glfwSetKeyCallback(window, onKeyEvent);
     glfwMakeContextCurrent(window);
+    glfwSwapInterval(1);
+
+    GLenum err = glewInit();
+    if(GLEW_OK != err) {
+        const char* error = (const char*)glewGetErrorString(err);
+        if(err != GLEW_ERROR_NO_GLX_DISPLAY ||
+           strcmp(error, "Unknown error") != 0) {
+            SET_ERROR("Could not initialize GLEW: %s", error);
+            return e;
+        }
+    }
+    glfwSetFramebufferSizeCallback(window, onWindowResize);
+
+    e = compileProgram();
+    if(hasError(&e)) {
+        return e;
+    }
+    glGenBuffers(1, &vbo);
+    glGenVertexArrays(1, &vba);
+
+    glBindBuffer(GL_ARRAY_BUFFER, vbo);
+    glBindVertexArray(vba);
+
+    glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(float) * 2, (GLvoid*)0);
+    glEnableVertexAttribArray(0);
+
+    float data[][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {-1.0f, 1.0f},
+                       {-1.0f, 1.0f},  {1.0f, 1.0f},  {1.0f, -1.0f}};
+    glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
+
+    glGenTextures(1, &texture);
+    glBindTexture(GL_TEXTURE_2D, texture);
+    glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, WIDTH, HEIGHT);
+    glTextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     return e;
 }
 
 void windowDestroy() {
+    glDeleteBuffers(1, &vbo);
+    glDeleteVertexArrays(1, &vba);
+    glDeleteShader(vShader);
+    glDeleteShader(fShader);
+    glDeleteProgram(program);
     glfwDestroyWindow(window);
     glfwTerminate();
 }
 
 void windowNextFrame() {
     glClear(GL_COLOR_BUFFER_BIT);
+    glViewport(0, 0, width, height);
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, texture);
+    pixels[5][5][0] = 255;
+    pixels[5][5][1] = 255;
+    pixels[5][5][2] = 255;
+    for(int x = 0; x < WIDTH; x++) {
+        for(int y = 0; y < HEIGHT; y++) {
+            pixels[y][x][0] = 255;
+            pixels[y][x][1] = 255;
+            pixels[y][x][2] = 255;
+        }
+    }
+    for(int y = 0; y < HEIGHT; y++) {
+        pixels[y][WIDTH / 2][0] = 128;
+        pixels[y][WIDTH / 2][1] = 0;
+        pixels[y][WIDTH / 2][2] = 255;
+    }
+    pixels[0][0][0] = 0;
+    pixels[0][0][1] = 0;
+    pixels[0][0][2] = 255;
+
+    glTexSubImage2D(
+        GL_TEXTURE_2D, 0, 0, 0, WIDTH, HEIGHT, GL_RGB, GL_UNSIGNED_BYTE,
+        pixels);
+
+    GLint size = glGetUniformLocation(program, "size");
+    glUniform2f(size, (float)width, (float)height);
+
+    glBindBuffer(GL_ARRAY_BUFFER, vbo);
+    glBindVertexArray(vba);
+    glDrawArrays(GL_TRIANGLES, 0, 6);
     glfwSwapBuffers(window);
     glfwPollEvents();
+    tickButtons();
+
+    auto i = glGetError();
+    if(i != 0) {
+        printf("GL-Error: %u\n", i);
+    }
 }
 
 bool windowShouldClose() {

+ 6 - 0
src/Window.h

@@ -2,6 +2,7 @@
 #define BASIC_WINDOW_H
 
 #include "Error.h"
+#include "Types.h"
 
 typedef struct {
     int width;
@@ -9,10 +10,15 @@ typedef struct {
     char title[64];
 } WindowSettings;
 
+typedef enum { LEFT, RIGHT, UP, DOWN, SELECT, START, A, B, X, Y, L, R } Button;
+
 Error windowInit(const WindowSettings* ws);
 void windowDestroy();
 
 void windowNextFrame();
 bool windowShouldClose();
 
+i32 isButtonDown(Button b);
+i32 getButtonDownTime(Button b);
+
 #endif