Allow 1-tile offscreen rendering to prevent pop-in effect

This commit is contained in:
Shylie 2024-06-14 12:20:31 -04:00
parent e402b5f5a3
commit 4811e4d970
8 changed files with 61 additions and 60 deletions

View File

@ -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);
}
}
}

View File

@ -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));
}

View File

@ -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++)
{

View File

@ -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++)
{

View File

@ -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);

View File

@ -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

View File

@ -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<glerminal*>(glfwGetWindowUserPointer(window));
const glerminal* const self = static_cast<glerminal*>(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<glerminal*>(glfwGetWindowUserPointer(window));
const glerminal* const self = static_cast<glerminal*>(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<glerminal*>(glfwGetWindowUserPointer(window));
const glerminal* const self = static_cast<glerminal*>(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<unsigned int*>(buffer));

View File

@ -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();