From 17ea6a7f0a4644cbbc950b07aab3c8127bd5aa00 Mon Sep 17 00:00:00 2001 From: Shylie Date: Thu, 23 May 2024 10:53:07 -0400 Subject: [PATCH] Fix a bug with glerminal_layer_scale that caused unintended behavior --- CMakeLists.txt | 2 +- examples/atlas.cpp | 6 +-- examples/basic.cpp | 30 ++++++------- examples/resources/rogue.png | 3 ++ examples/rogue.cpp | 87 ++++++++++++++++++++++++++++++++++++ examples/towers.cpp | 34 +++++++------- include/glerminal.h | 17 +++++++ source/glerminal-private.h | 7 ++- source/glerminal.cpp | 33 ++++++++------ 9 files changed, 164 insertions(+), 55 deletions(-) create mode 100644 examples/resources/rogue.png create mode 100644 examples/rogue.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 699772b..295149c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ target_include_directories(glerminal ) target_link_libraries(glerminal - PUBLIC + PRIVATE glfw ) diff --git a/examples/atlas.cpp b/examples/atlas.cpp index e87b1de..71031bb 100644 --- a/examples/atlas.cpp +++ b/examples/atlas.cpp @@ -24,11 +24,11 @@ namespace time = 0; } - for (int i = 0; i < 40; i++) + for (int i = 0; i < GRID_WIDTH; i++) { - for (int j = 0; j < 25; j++) + for (int j = 0; j < GRID_HEIGHT; j++) { - for (int k = 0; k < 256; k++) + for (int k = 0; k < LAYER_COUNT; k++) { glerminal_set(i, j, k, rand() % 4); glerminal_offset(i, j, k, (rand() * rand()) % 64 - 32, (rand() * rand()) % 64 - 32); diff --git a/examples/basic.cpp b/examples/basic.cpp index bb97ef2..899fc0b 100644 --- a/examples/basic.cpp +++ b/examples/basic.cpp @@ -7,32 +7,28 @@ namespace void init() { glerminal_load_sprites_file("resources/basic.png"); + + for (int i = 0; i < GRID_WIDTH; i++) + { + for (int j = 0; j < GRID_HEIGHT; j++) + { + glerminal_set(i, j, 0, 1); + } + } } void mainloop(float dt) { - static float time = 1; + static float time = 0; time += dt; + time = fmodf(time, 3.1415926f * 2); - if (time < 0.2f) + for (int i = 0; i < GRID_WIDTH; i++) { - return; - } - else - { - time = 0; - } - - for (int i = 0; i < 40; i++) - { - for (int j = 0; j < 25; j++) + for (int j = 0; j < GRID_HEIGHT; j++) { - for (int k = 0; k < 256; k++) - { - glerminal_set(i, j, k, rand() % 3 == 0); - glerminal_offset(i, j, k, (rand() * rand()) % 64 - 32, (rand() * rand()) % 64 - 32); - } + glerminal_offset(i, j, 0, cosf(time - i / 3.1415f), sinf(time - j / 3.1415f)); } } diff --git a/examples/resources/rogue.png b/examples/resources/rogue.png new file mode 100644 index 0000000..8c704ca --- /dev/null +++ b/examples/resources/rogue.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8a4d4e778300d34287688779faefbff8114bf20fd3519368fe250b6f8d2c1313 +size 173 diff --git a/examples/rogue.cpp b/examples/rogue.cpp new file mode 100644 index 0000000..7c77451 --- /dev/null +++ b/examples/rogue.cpp @@ -0,0 +1,87 @@ +#include + +#include + +namespace +{ + enum : unsigned char + { + empty, + player, + floor, + wall + }; + + constexpr unsigned int WALL_LAYERS = LAYER_COUNT - 1; + + void init() + { + glerminal_load_sprites_file("resources/rogue.png"); + + for (int i = 0; i < WALL_LAYERS; i++) + { + const unsigned char v = (i + 1) * (256 / WALL_LAYERS) - 1; + const unsigned int j = (0xFF << 24) | (v << 16) | (v << 8) | v; + glerminal_layer_color(i, j); + + glerminal_layer_scale(i, (i / static_cast(WALL_LAYERS)) + 1); + } + + for (int i = 0; i < GRID_WIDTH; i++) + { + for (int j = 0; j < GRID_HEIGHT; j++) + { + for (int k = 0; k < WALL_LAYERS; k++) + { + if (i == 0 || j == 0 || i == GRID_WIDTH - 1 || j == GRID_HEIGHT - 1) + { + glerminal_set(i, j, k, floor); + } + else + { + glerminal_set(i, j, k, wall); + } + } + } + } + } + + void mainloop(float dt) + { + static float time = 0; + time += dt; + + const float cx = GRID_WIDTH / 2.0f * cosf(time / 2) + GRID_WIDTH / 2.0f; + const float cy = GRID_HEIGHT / 2.0f * sinf(time / 2) + GRID_HEIGHT / 2.0f; + + for (int i = 0; i < GRID_WIDTH; i++) + { + for (int j = 0; j < GRID_HEIGHT; j++) + { + for (int k = 0; k < WALL_LAYERS; k++) + { + const float dx = (i - cx); + const float dy = (j - cy); + const float dist = sqrtf(dx * dx + dy * dy); + const float angle = atan2f(dy, dx); + + const float ox = dist * k / WALL_LAYERS * cosf(angle); + const float oy = dist * k / WALL_LAYERS * sinf(angle); + + glerminal_offset(i, j, k, ox * 2, oy * 2); + } + + glerminal_set(i, j, WALL_LAYERS, empty); + } + } + + glerminal_set(cx, cy, WALL_LAYERS, player); + + glerminal_flush(); + } +} + +int main(int argc, char** argv) +{ + glerminal_run(init, mainloop); +} \ No newline at end of file diff --git a/examples/towers.cpp b/examples/towers.cpp index aa74ce3..d1b353d 100644 --- a/examples/towers.cpp +++ b/examples/towers.cpp @@ -9,20 +9,20 @@ namespace { glerminal_load_sprites_file("resources/towers.png"); - for (int i = 0; i < 256; i++) + for (int i = 0; i < LAYER_COUNT; i++) { - constexpr unsigned char c = 0; - const unsigned char v = (255 - c) * powf((i - 1) / 256.0f, 2.0f) + c; - const unsigned int j = (0x7F << 24) | (v << 16) | (v << 8) | v; + constexpr unsigned char c = 16; + const unsigned char v = (255 - c) * powf((256 / LAYER_COUNT * i - 1) / 256.0f, 2.0f) + c; + const unsigned int j = (0xFF << 24) | (v << 16) | (v << 8) | v; glerminal_layer_color(i, j); - glerminal_layer_scale(i, i / 256.0f + 1); + glerminal_layer_scale(i, i / static_cast(LAYER_COUNT) + 1); } - for (int i = 0; i < 40; i++) + for (int i = 0; i < GRID_WIDTH; i++) { - for (int j = 0; j < 25; j++) + for (int j = 0; j < GRID_HEIGHT; j++) { - const int c = rand() % 224 + 32; + const int c = rand() % (LAYER_COUNT * 3 / 4) + LAYER_COUNT / 4; for (int k = 0; k < c; k++) { glerminal_set(i, j, k, 1); @@ -37,18 +37,20 @@ namespace time += dt; - const float cx = 20.0f * cosf(time / 3.1415f) + 20.0f; - const float cy = 12.5f * sinf(time / 3.1415f) + 12.5f; + const float cx = (GRID_WIDTH / 2.0f) * cosf(time / 3.1415f) + (GRID_WIDTH / 2.0f); + const float cy = (GRID_HEIGHT / 2.0f) * sinf(time / 3.1415f) + (GRID_HEIGHT / 2.0f); - for (int i = 0; i < 40; i++) + for (int i = 0; i < GRID_WIDTH; i++) { - for (int j = 0; j < 25; j++) + for (int j = 0; j < GRID_WIDTH; j++) { - for (int k = 0; k < 256; k++) + for (int k = 0; k < LAYER_COUNT; k++) { - const float ox = 0.01f * k * (i - cx); - const float oy = 0.01f * k * (j - cy); - glerminal_offset(i, j, k, ox + (1 + 0.004f * k) * cosf(i + k * 6.2832f / 128.0f + 3.1415f * time), oy + (1 + 0.004f * k) * sinf(j + k * 6.2832f / 128.0f + 3.1415f * time)); + const float ox = (256.0f / LAYER_COUNT) * 0.0025f * k * (i - cx); + const float oy = (256.0f / LAYER_COUNT) * 0.0025f * k * (j - cy); + const float sx = (1 + (256.0f / LAYER_COUNT) * 0.002f * k) * cosf(i + k * 6.2832f / 128.0f + 3.1415f * time / 1.5f); + const float sy = (1 + (256.0f / LAYER_COUNT) * 0.002f * k) * sinf(j + k * 6.2832f / 128.0f + 3.1415f * time / 1.5f); + glerminal_offset(i, j, k, ox + sx, oy + sy); } } } diff --git a/include/glerminal.h b/include/glerminal.h index 4f7cf67..e3a9bc9 100644 --- a/include/glerminal.h +++ b/include/glerminal.h @@ -6,6 +6,13 @@ extern "C" { #endif +enum +{ + GRID_WIDTH = 40, + GRID_HEIGHT = 25, + LAYER_COUNT = 64 +}; + typedef void (*glerminal_init_cb)(); typedef void (*glerminal_main_cb)(float dt); @@ -60,8 +67,18 @@ void glerminal_layer_color(unsigned char layer, unsigned int color); */ void glerminal_layer_scale(unsigned char layer, float scale); +/** + * @brief Load sprites from a png file + * @param filename Name of the png file + */ void glerminal_load_sprites_file(const char* filename); +/** + * @brief Load sprites from memory + * @param width width of the atlas in sprites + * @param height height of the atlas in sprites + * @param buffer the in-memory atlas + */ void glerminal_load_sprites_buffer(unsigned char width, unsigned char height, const unsigned int* buffer); #ifdef __cplusplus diff --git a/source/glerminal-private.h b/source/glerminal-private.h index 13d10b2..24947de 100644 --- a/source/glerminal-private.h +++ b/source/glerminal-private.h @@ -15,10 +15,9 @@ namespace glerminal constexpr unsigned int SCREEN_WIDTH = 1280; constexpr unsigned int SCREEN_HEIGHT = 800; constexpr unsigned int CELL_SIZE = 8; - constexpr unsigned int CELL_SCALE = 4; - constexpr unsigned int LAYER_COUNT = 256; - constexpr unsigned int GRID_WIDTH = SCREEN_WIDTH / (CELL_SIZE * CELL_SCALE); - constexpr unsigned int GRID_HEIGHT = SCREEN_HEIGHT / (CELL_SIZE * CELL_SCALE); + constexpr unsigned int LAYER_COUNT = ::LAYER_COUNT; + constexpr unsigned int GRID_WIDTH = ::GRID_WIDTH; + constexpr unsigned int GRID_HEIGHT = ::GRID_HEIGHT; constexpr unsigned int GRID_AREA = GRID_WIDTH * GRID_HEIGHT; class glerminal diff --git a/source/glerminal.cpp b/source/glerminal.cpp index 6dcfcf9..f1e07bd 100644 --- a/source/glerminal.cpp +++ b/source/glerminal.cpp @@ -6,6 +6,7 @@ #define GRID_SIZE_UNIFORM_NAME "grid_size" #define SPRITES_UNIFORM_NAME "sprites" #define LAYERS_UNIFORM_NAME "layers" +#define LAYER_COUNT_UNIFORM_NAME "layer_count" namespace { @@ -30,6 +31,10 @@ namespace "layout (location = 1) in vec2 offset;\n" "layout (location = 2) in int sprite;\n" "uniform vec4 " GRID_SIZE_UNIFORM_NAME ";\n" + "layout (std430, binding = 0) buffer LayerScales" + "{\n" + " float scales[];\n" + "} lss;\n" "out VS_OUT {\n" " flat vec2 offset;\n" " flat int sprite;\n" @@ -38,12 +43,13 @@ namespace "} vs_out;\n" "void main()\n" "{\n" + " const int layer = int(floor(gl_InstanceID / " GRID_SIZE_UNIFORM_NAME ".y));\n" " vs_out.sprite = sprite;\n" " vs_out.offset = offset * " GRID_SIZE_UNIFORM_NAME ".zw;\n" - " vs_out.layer = int(floor(gl_InstanceID / 1000));\n" + " vs_out.layer = layer;\n" " vs_out.texcoord = vec2(position.x + 1, -position.y);\n" - " vec2 cell_position = vec2(1 + (gl_InstanceID % 1000) - " GRID_SIZE_UNIFORM_NAME ".x * floor((gl_InstanceID % 1000) * " GRID_SIZE_UNIFORM_NAME ".z), -floor((gl_InstanceID % 1000) * " GRID_SIZE_UNIFORM_NAME ".z));\n" - " vec2 temp = vec2((position + cell_position) * " GRID_SIZE_UNIFORM_NAME ".zw * 2 + vec2(-1, 1));\n" + " vec2 cell_position = vec2(lss.scales[layer] + (gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) - " GRID_SIZE_UNIFORM_NAME ".x * floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) * " GRID_SIZE_UNIFORM_NAME ".z), -floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) * " GRID_SIZE_UNIFORM_NAME ".z));\n" + " vec2 temp = ((position + vec2(-0.5, 0.5)) * lss.scales[layer] + cell_position + vec2(0.5, -0.5)) * " GRID_SIZE_UNIFORM_NAME ".zw * 2 + vec2(-1, 1);\n" " gl_Position = vec4(temp.x, -temp.y, 0, 1);\n" "}"; @@ -58,25 +64,21 @@ namespace " vec2 texcoord;\n" "} gs_in[];\n" "flat out int sprite;\n" - "layout (std430, binding = 0) buffer LayerScales" - "{\n" - " float scales[];\n" - "} lss;\n" "out vec2 texcoord;\n" "void main()\n" "{\n" " gl_Layer = gs_in[0].layer;\n" - " gl_Position = vec4(gl_in[0].gl_Position.xy * lss.scales[gs_in[0].layer] + gs_in[0].offset, 0, 1);\n" + " gl_Position = vec4(gl_in[0].gl_Position.xy + gs_in[0].offset * 2, 0, 1);\n" " sprite = gs_in[0].sprite;\n" " texcoord = gs_in[0].texcoord;\n" " EmitVertex();\n" " gl_Layer = gs_in[1].layer;\n" - " gl_Position = vec4(gl_in[1].gl_Position.xy * lss.scales[gs_in[1].layer] + gs_in[1].offset, 0, 1);\n" + " gl_Position = vec4(gl_in[1].gl_Position.xy + gs_in[1].offset * 2, 0, 1);\n" " sprite = gs_in[1].sprite;\n" " texcoord = gs_in[1].texcoord;\n" " EmitVertex();\n" " gl_Layer = gs_in[2].layer;\n" - " gl_Position = vec4(gl_in[2].gl_Position.xy * lss.scales[gs_in[2].layer] + gs_in[2].offset, 0, 1);\n" + " gl_Position = vec4(gl_in[2].gl_Position.xy + gs_in[2].offset * 2, 0, 1);\n" " sprite = gs_in[2].sprite;\n" " texcoord = gs_in[2].texcoord;\n" " EmitVertex();\n" @@ -112,11 +114,12 @@ namespace "{\n" " vec4 colors[];\n" "} lcs;\n" + "uniform int " LAYER_COUNT_UNIFORM_NAME ";\n" "out vec4 FragColor;\n" "void main()\n" "{\n" " vec3 current_color = vec3(0);\n" - " for (int i = 0; i < 256; i++)\n" + " for (int i = 0; i < " LAYER_COUNT_UNIFORM_NAME "; i++)\n" " {\n" " vec4 texsample = lcs.colors[i] * texture(" LAYERS_UNIFORM_NAME ", vec3(texcoord, i));\n" " current_color = mix(current_color, texsample.rgb, texsample.a);\n" @@ -199,7 +202,7 @@ namespace glerminal update_layer_colors(); update_layer_scales(); - glViewport(0, 0, GRID_WIDTH * CELL_SIZE, GRID_HEIGHT * CELL_SIZE); + glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); glUseProgram(m_program); glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); glBindVertexArray(m_vao); @@ -511,7 +514,7 @@ namespace glerminal m_screen_size_uniform_location = glGetUniformLocation(m_program, GRID_SIZE_UNIFORM_NAME); glUseProgram(m_program); - glUniform4f(m_screen_size_uniform_location, GRID_WIDTH, GRID_HEIGHT, 1.0f / GRID_WIDTH, 1.0f / GRID_HEIGHT); + glUniform4f(m_screen_size_uniform_location, GRID_WIDTH, GRID_AREA, 1.0f / GRID_WIDTH, 1.0f / GRID_HEIGHT); // compile const unsigned int screen_vertex_shader = glCreateShader(GL_VERTEX_SHADER); @@ -597,13 +600,15 @@ namespace glerminal glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0); - glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, GRID_WIDTH * CELL_SIZE, GRID_HEIGHT * CELL_SIZE, LAYER_COUNT); + glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, SCREEN_WIDTH, SCREEN_HEIGHT, LAYER_COUNT); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_framebuffer_backing_texture, 0); glBindTextureUnit(1, m_framebuffer_backing_texture); // setup uniforms for screen shader glUseProgram(m_screen_program); + + glUniform1i(glGetUniformLocation(m_screen_program, LAYER_COUNT_UNIFORM_NAME), LAYER_COUNT); } void glerminal::deinit_glfw()