From 4b7991a3a6861aa223fe07ae39a6ef90d86f18a4 Mon Sep 17 00:00:00 2001 From: Shylie Date: Wed, 15 May 2024 13:33:18 -0500 Subject: [PATCH] Layer count increased to 256, palette size increased to 256 --- examples/CMakeLists.txt | 9 +++ examples/towers.cpp | 83 +++++++++++++++++++++++++++ include/glerminal.h | 2 +- source/glerminal-private.h | 9 +-- source/glerminal.cpp | 114 +++++++++++++++---------------------- 5 files changed, 144 insertions(+), 73 deletions(-) create mode 100644 examples/towers.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index d61f21a..b98cd85 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -9,4 +9,13 @@ add_executable(basic WIN32 target_link_libraries(basic PRIVATE glerminal +) + +add_executable(towers WIN32 + towers.cpp +) + +target_link_libraries(towers + PRIVATE + glerminal ) \ No newline at end of file diff --git a/examples/towers.cpp b/examples/towers.cpp new file mode 100644 index 0000000..4c418fe --- /dev/null +++ b/examples/towers.cpp @@ -0,0 +1,83 @@ +#include + +#include +#include + +namespace +{ + void init() + { + for (int i = 1; i < 256; i++) + { + constexpr unsigned char c = 0; + const unsigned char v = (255 - c) * powf((i - 1) / 256.0f, 4.0f) + c; + glerminal_update_palette(i, (v << 24) | (v << 16) | (v << 8) | 0xE0); + } + + for (int i = 1; i < 256; i++) + { + const unsigned char j = i; + glerminal_update_sprite(i, + { + 0,j,0,0,0,0,j,0, + j,j,j,j,j,j,j,j, + 0,j,0,0,0,0,j,0, + 0,j,0,0,0,0,j,0, + 0,j,0,0,0,0,j,0, + 0,j,0,0,0,0,j,0, + j,j,j,j,j,j,j,j, + 0,j,0,0,0,0,j,0, + }); + } + + for (int i = 0; i < 40; i++) + { + for (int j = 0; j < 25; j++) + { + for (int k = 0; k < 256; k++) + { + glerminal_set(i, j, k, k); + } + } + } + } + + void mainloop(float dt) + { + static float time = 1; + + time += dt; + + if (time < 1.0f) + { + return; + } + else + { + time = 0; + } + + const int cx = rand() % 40; + const int cy = rand() % 25; + + for (int i = 0; i < 40; i++) + { + for (int j = 0; j < 25; j++) + { + for (int k = 0; k < 256; k++) + { + const float ox = 0.05f * powf(k, 0.55f) * copysignf(sqrtf((i - cx) * (i - cx)), i - cx); + const float oy = 0.05f * powf(k, 0.55f) * copysignf(sqrtf((j - cy) * (j - cy)), j - cy); + glerminal_offset(i, j, k, ox, oy); + } + } + } + + glerminal_flush(); + } +} + +int main(int argc, char** argv) +{ + glerminal_run(init, mainloop); +} \ No newline at end of file diff --git a/include/glerminal.h b/include/glerminal.h index bb48d9e..3d4b6ac 100644 --- a/include/glerminal.h +++ b/include/glerminal.h @@ -55,7 +55,7 @@ unsigned char glerminal_get(unsigned char x, unsigned char y, unsigned char laye * @param x_offset offset of the cell on the x axis in the range [-128, 127], where 0 is no offset * @param y_offset offset of the cell on the y axis in the range [-128, 127], where 0 is no offset */ -void glerminal_offset(unsigned char x, unsigned char y, unsigned char layer, char x_offset, char y_offset); +void glerminal_offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset); /** * @brief Upload sprite to the given sprite ID diff --git a/source/glerminal-private.h b/source/glerminal-private.h index 5dc9afb..039af74 100644 --- a/source/glerminal-private.h +++ b/source/glerminal-private.h @@ -20,7 +20,7 @@ namespace glerminal 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 GRID_AREA = GRID_WIDTH * GRID_HEIGHT; - constexpr unsigned int LAYER_COUNT = 8; + constexpr unsigned int LAYER_COUNT = 256; class glerminal { @@ -40,7 +40,7 @@ namespace glerminal void set(unsigned char x, unsigned char y, unsigned char layer, unsigned char sprite); unsigned char get(unsigned char x, unsigned char y, unsigned char layer) const; - void offset(unsigned char x, unsigned char y, unsigned char layer, char x_offset, char y_offset); + void offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset); void update_sprite(unsigned char id, glerminal_sprite sprite); void update_palette_color(unsigned char id, unsigned int color); @@ -62,9 +62,10 @@ namespace glerminal unsigned int m_palette_uniform_location; unsigned char m_cells[GRID_AREA * LAYER_COUNT]; - char m_offsets[GRID_AREA * LAYER_COUNT * 2]; + float m_offsets[GRID_AREA * LAYER_COUNT * 2]; + unsigned char m_sprites[CELL_SIZE * CELL_SIZE * 256]; - float m_palette[64]; + float m_palette[256 * 4]; glerminal_main_cb m_main; diff --git a/source/glerminal.cpp b/source/glerminal.cpp index 866bc42..2008fed 100644 --- a/source/glerminal.cpp +++ b/source/glerminal.cpp @@ -1,6 +1,6 @@ #include "glerminal-private.h" -#define SCREEN_SIZE_UNIFORM_NAME "screen_size" +#define GRID_SIZE_UNIFORM_NAME "grid_size" #define PALETTE_UNIFORM_NAME "palette" #define SPRITES_UNIFORM_NAME "sprites" #define LAYERS_UNIFORM_NAME "layers" @@ -25,54 +25,53 @@ namespace constexpr char* VERTEX_SHADER_SOURCE = "#version 400 core\n" "layout (location = 0) in vec2 position;\n" - "layout (location = 1) in vec2 offset[8];\n" - "layout (location = 9) in ivec4 sprite[2];\n" - "uniform vec4 " SCREEN_SIZE_UNIFORM_NAME ";\n" + "layout (location = 1) in vec2 offset;\n" + "layout (location = 2) in int sprite;\n" + "uniform vec4 " GRID_SIZE_UNIFORM_NAME ";\n" "out VS_OUT {\n" - " flat vec2 offset[8];\n" - " flat ivec4 sprite[2];\n" + " flat vec2 offset;\n" + " flat int sprite;\n" + " flat int layer;\n" " vec2 texcoord;\n" "} vs_out;\n" "void main()\n" "{\n" " vs_out.sprite = sprite;\n" - " for (int i = 0; i < 8; i++)\n" - " {\n" - " vs_out.offset[i] = offset[i] * " SCREEN_SIZE_UNIFORM_NAME ".zw;\n" - " }\n" + " vs_out.offset = offset * " GRID_SIZE_UNIFORM_NAME ".zw;\n" + " vs_out.layer = int(floor(gl_InstanceID / 1000));\n" " vs_out.texcoord = vec2(position.x + 1, -position.y);\n" - " vec2 cell_position = vec2(1 + gl_InstanceID - " SCREEN_SIZE_UNIFORM_NAME ".x * floor(gl_InstanceID * " SCREEN_SIZE_UNIFORM_NAME ".z), -floor((gl_InstanceID) * " SCREEN_SIZE_UNIFORM_NAME ".z));\n" - " vec2 temp = vec2((position + cell_position) * " SCREEN_SIZE_UNIFORM_NAME ".zw * 2 + vec2(-1, 1));\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" " gl_Position = vec4(temp.x, -temp.y, 0, 1);\n" "}"; constexpr char* GEOMETRY_SHADER_SOURCE = "#version 400 core\n" "layout (triangles) in;\n" - "layout (triangle_strip, max_vertices = 24) out;\n" - "layout (invocations = 8) in;\n" + "layout (triangle_strip, max_vertices = 3) out;\n" "in VS_OUT {\n" - " flat vec2 offset[8];\n" - " flat ivec4 sprite[2];\n" + " flat vec2 offset;\n" + " flat int sprite;\n" + " flat int layer;\n" " vec2 texcoord;\n" "} gs_in[];\n" "flat out int sprite;\n" "out vec2 texcoord;\n" "void main()\n" "{\n" - " gl_Layer = gl_InvocationID;\n" - " gl_Position = vec4(gl_in[0].gl_Position.xy + gs_in[0].offset[gl_InvocationID], 0, 1);\n" - " sprite = gs_in[0].sprite[gl_InvocationID / 8][gl_InvocationID % 8];\n" + " gl_Layer = gs_in[0].layer;\n" + " gl_Position = vec4(gl_in[0].gl_Position.xy + gs_in[0].offset, 0, 1);\n" + " sprite = gs_in[0].sprite;\n" " texcoord = gs_in[0].texcoord;\n" " EmitVertex();\n" - " gl_Layer = gl_InvocationID;\n" - " gl_Position = vec4(gl_in[1].gl_Position.xy + gs_in[0].offset[gl_InvocationID], 0, 1);\n" - " sprite = gs_in[1].sprite[gl_InvocationID / 8][gl_InvocationID % 8];\n" + " gl_Layer = gs_in[1].layer;\n" + " gl_Position = vec4(gl_in[1].gl_Position.xy + gs_in[1].offset, 0, 1);\n" + " sprite = gs_in[1].sprite;\n" " texcoord = gs_in[1].texcoord;\n" " EmitVertex();\n" - " gl_Layer = gl_InvocationID;\n" - " gl_Position = vec4(gl_in[2].gl_Position.xy + gs_in[0].offset[gl_InvocationID], 0, 1);\n" - " sprite = gs_in[2].sprite[gl_InvocationID / 8][gl_InvocationID % 8];\n" + " gl_Layer = gs_in[2].layer;\n" + " gl_Position = vec4(gl_in[2].gl_Position.xy + gs_in[2].offset, 0, 1);\n" + " sprite = gs_in[2].sprite;\n" " texcoord = gs_in[2].texcoord;\n" " EmitVertex();\n" " EndPrimitive();\n" @@ -83,7 +82,7 @@ namespace "in vec2 texcoord;\n" "flat in int sprite;\n" "uniform usampler2DArray " SPRITES_UNIFORM_NAME ";\n" - "uniform vec4 " PALETTE_UNIFORM_NAME "[16];\n" + "uniform vec4 " PALETTE_UNIFORM_NAME "[256];\n" "out vec4 FragColor;\n" "void main()\n" "{\n" @@ -108,7 +107,7 @@ namespace "void main()\n" "{\n" " vec3 current_color = vec3(0);\n" - " for (int i = 0; i < 8; i++)\n" + " for (int i = 0; i < 256; i++)\n" " {\n" " vec4 texsample = texture(" LAYERS_UNIFORM_NAME ", vec3(texcoord, i));\n" " current_color = mix(current_color, texsample.rgb, texsample.a);\n" @@ -184,13 +183,15 @@ namespace glerminal update_sprites(); update_palette(); + glViewport(0, 0, GRID_WIDTH * CELL_SIZE, GRID_HEIGHT * CELL_SIZE); glUseProgram(m_program); glBindTexture(GL_TEXTURE_2D_ARRAY, m_sprites_texture); glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); glBindVertexArray(m_vao); glClear(GL_COLOR_BUFFER_BIT); - glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_AREA); + glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_AREA * LAYER_COUNT); + glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); glUseProgram(m_screen_program); glBindTexture(GL_TEXTURE_2D_ARRAY, m_framebuffer_backing_texture); glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -205,7 +206,7 @@ namespace glerminal { if (x < GRID_WIDTH && y < GRID_HEIGHT && layer < LAYER_COUNT) { - m_cells[layer + x * LAYER_COUNT + y * LAYER_COUNT * GRID_WIDTH] = sprite; + m_cells[x + y * GRID_WIDTH + layer * GRID_AREA] = sprite; } } @@ -221,12 +222,12 @@ namespace glerminal } } - void glerminal::offset(unsigned char x, unsigned char y, unsigned char layer, char x_offset, char y_offset) + void glerminal::offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset) { if (x < GRID_WIDTH && y < GRID_HEIGHT && layer < LAYER_COUNT) { - m_offsets[2 * (layer + x * LAYER_COUNT + y * LAYER_COUNT * GRID_WIDTH) + 0] = x_offset; - m_offsets[2 * (layer + x * LAYER_COUNT + y * LAYER_COUNT * GRID_WIDTH) + 1] = y_offset; + m_offsets[2 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 0] = x_offset; + m_offsets[2 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 1] = y_offset; } } @@ -238,7 +239,7 @@ namespace glerminal void glerminal::update_palette_color(unsigned char id, unsigned int color) { - if (id < 16) + if (id < 256) { m_palette[4 * id + 0] = ((color >> 24) & 0xFF) / 255.0f; m_palette[4 * id + 1] = ((color >> 16) & 0xFF) / 255.0f; @@ -347,7 +348,6 @@ namespace glerminal }, this); #endif - glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -372,39 +372,14 @@ namespace glerminal glBindBuffer(GL_ARRAY_BUFFER, m_offsets_instance_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(m_offsets), m_offsets, GL_STREAM_DRAW); glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_BYTE, GL_TRUE, 16 * sizeof(*m_offsets), reinterpret_cast(0 * sizeof(*m_offsets))); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(*m_offsets), reinterpret_cast(0)); glVertexAttribDivisor(1, 1); - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 2, GL_BYTE, GL_TRUE, 16 * sizeof(*m_offsets), reinterpret_cast(2 * sizeof(*m_offsets))); - glVertexAttribDivisor(2, 1); - glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 2, GL_BYTE, GL_TRUE, 16 * sizeof(*m_offsets), reinterpret_cast(4 * sizeof(*m_offsets))); - glVertexAttribDivisor(3, 1); - glEnableVertexAttribArray(4); - glVertexAttribPointer(4, 2, GL_BYTE, GL_TRUE, 16 * sizeof(*m_offsets), reinterpret_cast(6 * sizeof(*m_offsets))); - glVertexAttribDivisor(4, 1); - glEnableVertexAttribArray(5); - glVertexAttribPointer(5, 2, GL_BYTE, GL_TRUE, 16 * sizeof(*m_offsets), reinterpret_cast(8 * sizeof(*m_offsets))); - glVertexAttribDivisor(5, 1); - glEnableVertexAttribArray(6); - glVertexAttribPointer(6, 2, GL_BYTE, GL_TRUE, 16 * sizeof(*m_offsets), reinterpret_cast(10 * sizeof(*m_offsets))); - glVertexAttribDivisor(6, 1); - glEnableVertexAttribArray(7); - glVertexAttribPointer(7, 2, GL_BYTE, GL_TRUE, 16 * sizeof(*m_offsets), reinterpret_cast(12 * sizeof(*m_offsets))); - glVertexAttribDivisor(7, 1); - glEnableVertexAttribArray(8); - glVertexAttribPointer(8, 2, GL_BYTE, GL_TRUE, 16 * sizeof(*m_offsets), reinterpret_cast(14 * sizeof(*m_offsets))); - glVertexAttribDivisor(8, 1); glBindBuffer(GL_ARRAY_BUFFER, m_sprites_instance_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(m_cells), m_cells, GL_STREAM_DRAW); - glEnableVertexAttribArray(9); - glVertexAttribIPointer(9, 4, GL_UNSIGNED_BYTE, 8 * sizeof(*m_cells), reinterpret_cast(0 * sizeof(*m_cells))); - glVertexAttribDivisor(9, 1); - glEnableVertexAttribArray(10); - glVertexAttribIPointer(10, 4, GL_UNSIGNED_BYTE, 8 * sizeof(*m_cells), reinterpret_cast(4 * sizeof(*m_cells))); - glVertexAttribDivisor(10, 1); - + glEnableVertexAttribArray(2); + glVertexAttribIPointer(2, 1, GL_UNSIGNED_BYTE, 1 * sizeof(*m_cells), reinterpret_cast(0)); + glVertexAttribDivisor(2, 1); // set up static vertex attributes glGenVertexArrays(1, &m_screen_vao); @@ -481,7 +456,7 @@ namespace glerminal } // setup uniforms - m_screen_size_uniform_location = glGetUniformLocation(m_program, SCREEN_SIZE_UNIFORM_NAME); + m_screen_size_uniform_location = glGetUniformLocation(m_program, GRID_SIZE_UNIFORM_NAME); m_palette_uniform_location = glGetUniformLocation(m_program, PALETTE_UNIFORM_NAME); glUseProgram(m_program); @@ -569,7 +544,7 @@ namespace glerminal glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, SCREEN_WIDTH, SCREEN_HEIGHT, LAYER_COUNT, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, GRID_WIDTH * CELL_SIZE, GRID_HEIGHT * CELL_SIZE, LAYER_COUNT, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_framebuffer_backing_texture, 0); // setup uniforms for screen shader @@ -605,7 +580,7 @@ namespace glerminal void glerminal::update_palette() { glUseProgram(m_program); - glUniform4fv(m_palette_uniform_location, 16, m_palette); + glUniform4fv(m_palette_uniform_location, 256, m_palette); } } @@ -613,10 +588,13 @@ void glerminal_run(glerminal_init_cb init, glerminal_main_cb main) { try { - glerminal::glerminal(init, main).run(); + glerminal::glerminal* g = new glerminal::glerminal(init, main); + g->run(); + delete g; } catch (const std::runtime_error& e) { + e.what(); } } @@ -641,7 +619,7 @@ unsigned char glerminal_get(unsigned char x, unsigned char y, unsigned char laye return GLERMINAL_G->get(x, y, layer); } -void glerminal_offset(unsigned char x, unsigned char y, unsigned char layer, char x_offset, char y_offset) +void glerminal_offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset) { if (!GLERMINAL_G) { return; }