From 4811e4d97018bff93598e44e89aee1ed0e73af8d Mon Sep 17 00:00:00 2001 From: Shylie Date: Fri, 14 Jun 2024 12:20:31 -0400 Subject: [PATCH] Allow 1-tile offscreen rendering to prevent pop-in effect --- examples/atlas.cpp | 4 ++-- examples/basic.cpp | 8 +++---- examples/rogue.cpp | 14 +++++------ examples/towers.cpp | 12 +++++----- source/glerminal-main.cpp | 20 ++++++++-------- source/glerminal-private.h | 12 +++++----- source/glerminal.cpp | 49 +++++++++++++++++++------------------- tests/basic.cpp | 2 +- 8 files changed, 61 insertions(+), 60 deletions(-) diff --git a/examples/atlas.cpp b/examples/atlas.cpp index aad3932..59e076f 100644 --- a/examples/atlas.cpp +++ b/examples/atlas.cpp @@ -30,8 +30,8 @@ namespace { 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); + glerminal_set(i + 1, j + 1, k, rand() % 4); + glerminal_offset(i + 1, j + 1, k, (rand() * rand()) % 64 - 32, (rand() * rand()) % 64 - 32); } } } diff --git a/examples/basic.cpp b/examples/basic.cpp index 0e6e6d8..a28bff2 100644 --- a/examples/basic.cpp +++ b/examples/basic.cpp @@ -9,9 +9,9 @@ namespace { glerminal_load_sprites_file("resources/basic.png"); - for (int i = 0; i < GRID_WIDTH; i++) + for (int i = 0; i < GRID_WIDTH + 2; i++) { - for (int j = 0; j < GRID_HEIGHT; j++) + for (int j = 0; j < GRID_HEIGHT + 2; j++) { glerminal_set(i, j, 0, 1); } @@ -25,9 +25,9 @@ namespace time += dt; time = fmodf(time, 3.1415926f * 2); - for (int i = 0; i < GRID_WIDTH; i++) + for (int i = 0; i < GRID_WIDTH + 2; i++) { - for (int j = 0; j < GRID_HEIGHT; j++) + for (int j = 0; j < GRID_HEIGHT + 2; j++) { glerminal_offset(i, j, 0, cosf(time - i / 3.1415f), sinf(time - j / 3.1415f)); } diff --git a/examples/rogue.cpp b/examples/rogue.cpp index eaf2e37..8fd2877 100644 --- a/examples/rogue.cpp +++ b/examples/rogue.cpp @@ -18,16 +18,16 @@ namespace { glerminal_load_sprites_file("resources/rogue.png"); - for (int i = 0; i < GRID_WIDTH; i++) + for (int i = 0; i < GRID_WIDTH + 2; i++) { - for (int j = 0; j < GRID_HEIGHT; j++) + for (int j = 0; j < GRID_HEIGHT + 2; j++) { for (int k = 0; k < WALL_LAYERS; k++) { const unsigned char v = (k + 1) * (256 / WALL_LAYERS) - 1; const unsigned int c = (0xFF << 24) | (v << 16) | (v << 8) | v; - if (i == 0 || j == 0 || i == GRID_WIDTH - 1 || j == GRID_HEIGHT - 1) + if (i == 1 || j == 1 || i == GRID_WIDTH || j == GRID_HEIGHT) { glerminal_set(i, j, k, floor); } @@ -48,12 +48,12 @@ namespace static double 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; + const float cx = GRID_WIDTH / 2.0f * cosf(time / 2) + GRID_WIDTH / 2.0f + 0.5f; + const float cy = GRID_HEIGHT / 2.0f * sinf(time / 2) + GRID_HEIGHT / 2.0f + 0.5f; - for (int i = 0; i < GRID_WIDTH; i++) + for (int i = 0; i < GRID_WIDTH + 2; i++) { - for (int j = 0; j < GRID_HEIGHT; j++) + for (int j = 0; j < GRID_HEIGHT + 2; j++) { for (int k = 0; k < WALL_LAYERS; k++) { diff --git a/examples/towers.cpp b/examples/towers.cpp index ff5ee8e..6590ccf 100644 --- a/examples/towers.cpp +++ b/examples/towers.cpp @@ -12,9 +12,9 @@ namespace glerminal_load_sprites_file("resources/towers.png"); - for (int i = 0; i < GRID_WIDTH; i++) + for (int i = 0; i < GRID_WIDTH + 2; i++) { - for (int j = 0; j < GRID_HEIGHT; j++) + for (int j = 0; j < GRID_HEIGHT + 2; j++) { const int c = rand() % (LAYER_COUNT * 3 / 4) + LAYER_COUNT / 4; for (int k = 0; k < c; k++) @@ -40,12 +40,12 @@ namespace time += dt; - 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); + const float cx = (GRID_WIDTH / 2.0f) * cosf(time / 3.1415f) + (GRID_WIDTH / 2.0f) + 0.5f; + const float cy = (GRID_HEIGHT / 2.0f) * sinf(time / 3.1415f) + (GRID_HEIGHT / 2.0f) + 0.5f; - for (int i = 0; i < GRID_WIDTH; i++) + for (int i = 0; i < GRID_WIDTH + 2; i++) { - for (int j = 0; j < GRID_WIDTH; j++) + for (int j = 0; j < GRID_WIDTH + 2; j++) { for (int k = 0; k < LAYER_COUNT; k++) { diff --git a/source/glerminal-main.cpp b/source/glerminal-main.cpp index 4197ac8..10d8a9d 100644 --- a/source/glerminal-main.cpp +++ b/source/glerminal-main.cpp @@ -38,8 +38,8 @@ namespace int lglerminal_set(lua_State* L) { - const unsigned char x = luaL_checkinteger(L, 1) - 1; - const unsigned char y = luaL_checkinteger(L, 2) - 1; + const unsigned char x = luaL_checkinteger(L, 1); + const unsigned char y = luaL_checkinteger(L, 2); const unsigned char layer = luaL_checkinteger(L, 3) - 1; const unsigned short sprite = luaL_checkinteger(L, 4) - 1; glerminal_set(x, y, layer, sprite); @@ -49,8 +49,8 @@ namespace int lglerminal_get(lua_State* L) { - const unsigned char x = luaL_checkinteger(L, 1) - 1; - const unsigned char y = luaL_checkinteger(L, 2) - 1; + const unsigned char x = luaL_checkinteger(L, 1); + const unsigned char y = luaL_checkinteger(L, 2); const unsigned char layer = luaL_checkinteger(L, 3) - 1; lua_pushnumber(L, glerminal_get(x, y, layer) + 1); @@ -59,8 +59,8 @@ namespace int lglerminal_offset(lua_State* L) { - const unsigned char x = luaL_checkinteger(L, 1) - 1; - const unsigned char y = luaL_checkinteger(L, 2) - 1; + const unsigned char x = luaL_checkinteger(L, 1); + const unsigned char y = luaL_checkinteger(L, 2); const unsigned char layer = luaL_checkinteger(L, 3) - 1; const float ox = luaL_checknumber(L, 4); const float oy = luaL_checknumber(L, 5); @@ -71,8 +71,8 @@ namespace int lglerminal_layer_color(lua_State* L) { - const unsigned char x = luaL_checkinteger(L, 1) - 1; - const unsigned char y = luaL_checkinteger(L, 2) - 1; + const unsigned char x = luaL_checkinteger(L, 1); + const unsigned char y = luaL_checkinteger(L, 2); const unsigned char layer = luaL_checkinteger(L, 3) - 1; const unsigned int color = luaL_checkinteger(L, 4); glerminal_color(x, y, layer, color); @@ -82,8 +82,8 @@ namespace int lglerminal_layer_scale(lua_State* L) { - const unsigned char x = luaL_checkinteger(L, 1) - 1; - const unsigned char y = luaL_checkinteger(L, 2) - 1; + const unsigned char x = luaL_checkinteger(L, 1); + const unsigned char y = luaL_checkinteger(L, 2); const unsigned char layer = luaL_checkinteger(L, 3) - 1; const float scale = luaL_checknumber(L, 4); glerminal_scale(x, y, layer, scale); diff --git a/source/glerminal-private.h b/source/glerminal-private.h index 6aa7004..6a3ae66 100644 --- a/source/glerminal-private.h +++ b/source/glerminal-private.h @@ -24,6 +24,8 @@ namespace glerminal constexpr unsigned int SCREEN_WIDTH = GRID_WIDTH * CELL_SIZE * CELL_SCALE; constexpr unsigned int SCREEN_HEIGHT = GRID_HEIGHT * CELL_SIZE * CELL_SCALE; + constexpr unsigned int GRID_AREA_2 = (GRID_WIDTH + 2) * (GRID_HEIGHT + 2); + class glerminal { public: @@ -69,15 +71,13 @@ namespace glerminal unsigned int m_screen_framebuffer_backing_texture; unsigned int m_colors_instance_vbo; unsigned int m_scales_instance_vbo; - unsigned int m_screen_size_uniform_location; - unsigned int m_palette_uniform_location; // per-cell data - unsigned short m_cells[GRID_AREA * LAYER_COUNT]; - float m_offsets[GRID_AREA * LAYER_COUNT * 2]; - unsigned char m_colors[GRID_AREA * LAYER_COUNT * 4]; - float m_scales[GRID_AREA * LAYER_COUNT]; + unsigned short m_cells[GRID_AREA_2 * LAYER_COUNT]; + float m_offsets[GRID_AREA_2 * LAYER_COUNT * 2]; + unsigned char m_colors[GRID_AREA_2 * LAYER_COUNT * 4]; + float m_scales[GRID_AREA_2 * LAYER_COUNT]; // library state diff --git a/source/glerminal.cpp b/source/glerminal.cpp index 4e9e5f9..4184c26 100644 --- a/source/glerminal.cpp +++ b/source/glerminal.cpp @@ -49,8 +49,8 @@ namespace " vs_out.layer = layer;\n" " vs_out.layer_color = color;\n" " vs_out.texcoord = vec2(sprite % " ATLAS_WIDTH_UNIFORM_NAME " + position.x + 1, (sprite / " ATLAS_WIDTH_UNIFORM_NAME ") - position.y) / vec2(" ATLAS_WIDTH_UNIFORM_NAME ") + vec2(-(2 * position.x + 1) * " GRID_SIZE_UNIFORM_NAME ".z / 16, (2 * position.y + 1) * " GRID_SIZE_UNIFORM_NAME ".z / 16);\n" - " vec2 cell_position = vec2(scale + (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)) * scale + cell_position + vec2(0.5, -0.5)) * " GRID_SIZE_UNIFORM_NAME ".zw * 2 + vec2(-1, 1);\n" + " vec2 cell_position = vec2(scale + (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 ".x), -floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) / " GRID_SIZE_UNIFORM_NAME ".x));\n" + " vec2 temp = ((position + vec2(-0.5, 0.5)) * scale + cell_position + vec2(-0.5, 0.5)) * " GRID_SIZE_UNIFORM_NAME ".zw * 2 + vec2(-1, 1);\n" " gl_Position = vec4(scaled_offset.x + temp.x, scaled_offset.y - temp.y, 0, 1);\n" "}"; @@ -79,8 +79,8 @@ namespace " vs_out.sprite = sprite;\n" " vs_out.texcoord = vec2(sprite % " ATLAS_WIDTH_UNIFORM_NAME " + position.x + 1, (sprite / " ATLAS_WIDTH_UNIFORM_NAME ") - position.y) / vec2(" ATLAS_WIDTH_UNIFORM_NAME ") + vec2(-(2 * position.x + 1) * " GRID_SIZE_UNIFORM_NAME ".z / 16, (2 * position.y + 1) * " GRID_SIZE_UNIFORM_NAME ".z / 16);\n" " vs_out.layer_color = color;\n" - " vec2 cell_position = vec2(scale + (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)) * scale + cell_position + vec2(0.5, -0.5)) * " GRID_SIZE_UNIFORM_NAME ".zw * 2 + vec2(-1, 1);\n" + " vec2 cell_position = vec2(scale + (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 ".x), -floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) / " GRID_SIZE_UNIFORM_NAME ".x));\n" + " vec2 temp = ((position + vec2(-0.5, 0.5)) * scale + cell_position + vec2(-0.5, 0.5)) * " GRID_SIZE_UNIFORM_NAME ".zw * 2 + vec2(-1, 1);\n" " gl_Position = vec4(scaled_offset.x + temp.x, scaled_offset.y - temp.y, 0, 1);\n" "}"; @@ -221,7 +221,7 @@ namespace glerminal throw std::runtime_error("No main callback provided."); } - for (int i = 0; i < GRID_AREA * LAYER_COUNT; i++) + for (int i = 0; i < GRID_AREA_2 * LAYER_COUNT; i++) { m_colors[i * 4 + 0] = m_colors[i * 4 + 1] = m_colors[i * 4 + 2] = m_colors[i * 4 + 3] = 255; m_scales[i] = 1; @@ -294,17 +294,17 @@ namespace glerminal void glerminal::set(unsigned char x, unsigned char y, unsigned char layer, unsigned short sprite) { - if (x < GRID_WIDTH && y < GRID_HEIGHT && layer < LAYER_COUNT) + if (x < GRID_WIDTH + 2 && y < GRID_HEIGHT + 2 && layer < LAYER_COUNT) { - m_cells[x + y * GRID_WIDTH + layer * GRID_AREA] = sprite; + m_cells[x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2] = sprite; } } unsigned short glerminal::get(unsigned char x, unsigned char y, unsigned char layer) const { - if (x < GRID_WIDTH && y < GRID_HEIGHT && layer < LAYER_COUNT) + if (x < GRID_WIDTH + 2 && y < GRID_HEIGHT + 2 && layer < LAYER_COUNT) { - return m_cells[x + y * GRID_WIDTH + layer * GRID_AREA]; + return m_cells[x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2]; } else { @@ -314,24 +314,27 @@ namespace glerminal 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) + if (x < GRID_WIDTH + 2 && y < GRID_HEIGHT + 2 && layer < LAYER_COUNT) { - 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; + m_offsets[2 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 0] = x_offset; + m_offsets[2 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 1] = y_offset; } } void glerminal::color(unsigned char x, unsigned char y, unsigned char layer, unsigned int color) { - m_colors[4 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 0] = ((color >> 0) & 0xFF); - m_colors[4 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 1] = ((color >> 8) & 0xFF); - m_colors[4 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 2] = ((color >> 16) & 0xFF); - m_colors[4 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 3] = ((color >> 24) & 0xFF); + if (x < GRID_WIDTH + 2 && y < GRID_HEIGHT + 2 && layer < LAYER_COUNT) + { + m_colors[4 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 0] = (color >> 0) & 0xFF; + m_colors[4 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 1] = (color >> 8) & 0xFF; + m_colors[4 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 2] = (color >> 16) & 0xFF; + m_colors[4 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 3] = (color >> 24) & 0xFF; + } } void glerminal::scale(unsigned char x, unsigned char y, unsigned char layer, float scale) { - m_scales[x + y * GRID_WIDTH + layer * GRID_AREA] = scale; + m_scales[x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2] = scale; } void glerminal::load_atlas(unsigned char w, unsigned char h, const unsigned int* data) @@ -615,10 +618,8 @@ namespace glerminal } // setup uniforms - m_screen_size_uniform_location = glGetUniformLocation(m_program, GRID_SIZE_UNIFORM_NAME); - glUseProgram(m_program); - glUniform4f(m_screen_size_uniform_location, GRID_WIDTH, GRID_AREA, 1.0f / GRID_WIDTH, 1.0f / GRID_HEIGHT); + glUniform4f(glGetUniformLocation(m_program, GRID_SIZE_UNIFORM_NAME), GRID_WIDTH + 2, GRID_AREA_2, 1.0f / GRID_WIDTH, 1.0f / GRID_HEIGHT); glUniform1i(glGetUniformLocation(m_program, ATLAS_WIDTH_UNIFORM_NAME), MAX_SPRITES_ROW); // compile @@ -783,7 +784,7 @@ namespace glerminal void glerminal::glfw_key_handler(GLFWwindow* window, int key, int scancode, int action, int mods) { - glerminal* const self = static_cast(glfwGetWindowUserPointer(window)); + const glerminal* const self = static_cast(glfwGetWindowUserPointer(window)); if (self->m_keypressed && action == GLFW_PRESS) { @@ -798,14 +799,14 @@ namespace glerminal void glerminal::glfw_mousemoved_handler(GLFWwindow *window, double x, double y) { - glerminal* const self = static_cast(glfwGetWindowUserPointer(window)); + const glerminal* const self = static_cast(glfwGetWindowUserPointer(window)); if (self->m_mousemoved) { self->m_mousemoved(x / (CELL_SIZE * CELL_SCALE), y / (CELL_SIZE * CELL_SCALE)); } } void glerminal::glfw_mousepress_handler(GLFWwindow *window, int button, int action, int mods) { - glerminal* const self = static_cast(glfwGetWindowUserPointer(window)); + const glerminal* const self = static_cast(glfwGetWindowUserPointer(window)); double x, y; glfwGetCursorPos(window, &x, &y); @@ -896,7 +897,7 @@ int glerminal_load_sprites_file(const char* filename) stbi_uc* const buffer = stbi_load(filename, &w, &h, nullptr, 4); // verify atlas size is a multiple of CELL_SIZE in each dimension - if (w % glerminal::CELL_SIZE == 0 && h % glerminal::CELL_SIZE == 0) + if (buffer && w % glerminal::CELL_SIZE == 0 && h % glerminal::CELL_SIZE == 0) { GLERMINAL_G->load_atlas(w / glerminal::CELL_SIZE, h / glerminal::CELL_SIZE, reinterpret_cast(buffer)); diff --git a/tests/basic.cpp b/tests/basic.cpp index 0acd72f..dd27cb8 100644 --- a/tests/basic.cpp +++ b/tests/basic.cpp @@ -15,7 +15,7 @@ namespace for (int i = 0; i < GRID_HEIGHT; i++) { - glerminal_set(i, i, 0, 1); + glerminal_set(i + 1, i + 1, 0, 1); } glerminal_flush();