Properly fixed texture bleeding

This commit is contained in:
Shylie 2024-06-02 14:34:07 -04:00
parent 71c052b38f
commit da1f32a014
4 changed files with 65 additions and 34 deletions

View File

@ -35,7 +35,7 @@ void glerminal_flush();
* @param layer layer of the cell in the range [0, 8) * @param layer layer of the cell in the range [0, 8)
* @param sprite sprite's index in the range [0, 256) * @param sprite sprite's index in the range [0, 256)
*/ */
void glerminal_set(unsigned char x, unsigned char y, unsigned char layer, unsigned char sprite); void glerminal_set(unsigned char x, unsigned char y, unsigned char layer, unsigned short sprite);
/** /**
* @brief Get a cell's sprite * @brief Get a cell's sprite
* @param x position of the cell in the range [0, 40) * @param x position of the cell in the range [0, 40)
@ -43,7 +43,7 @@ void glerminal_set(unsigned char x, unsigned char y, unsigned char layer, unsign
* @param layer layer of the cell in the range [0, 8) * @param layer layer of the cell in the range [0, 8)
* @return sprite index currently assigned to the cell * @return sprite index currently assigned to the cell
*/ */
unsigned char glerminal_get(unsigned char x, unsigned char y, unsigned char layer); unsigned char glerminal_get(unsigned char x, unsigned char y, unsigned short layer);
/** /**
* @brief Set a cell's offset * @brief Set a cell's offset
* @param x position of the cell in the range [0, 40) * @param x position of the cell in the range [0, 40)

View File

@ -41,7 +41,7 @@ namespace
const unsigned char x = luaL_checkinteger(L, 1) - 1; const unsigned char x = luaL_checkinteger(L, 1) - 1;
const unsigned char y = luaL_checkinteger(L, 2) - 1; const unsigned char y = luaL_checkinteger(L, 2) - 1;
const unsigned char layer = luaL_checkinteger(L, 3) - 1; const unsigned char layer = luaL_checkinteger(L, 3) - 1;
const unsigned char sprite = luaL_checkinteger(L, 4) - 1; const unsigned short sprite = luaL_checkinteger(L, 4) - 1;
glerminal_set(x, y, layer, sprite); glerminal_set(x, y, layer, sprite);
return 0; return 0;
@ -108,31 +108,50 @@ namespace
{ nullptr, nullptr } { nullptr, nullptr }
}; };
int message_handler(lua_State* L)
{
const char* error_message = lua_tostring(L, -1);
luaL_traceback(L, L, error_message, 0);
const char* err = lua_tostring(L, -1);
lua_remove(L, -2);
return true;
}
lua_State* L; lua_State* L;
void init() void init()
{ {
lua_pushcfunction(L, message_handler);
const int handler = lua_gettop(L);
lua_getglobal(L, "glerminal"); lua_getglobal(L, "glerminal");
lua_getfield(L, -1, "init"); lua_getfield(L, -1, "init");
lua_remove(L, -2); lua_remove(L, -2);
if (lua_pcall(L, 0, 0, 0) != LUA_OK) if (lua_pcall(L, 0, 0, handler) != LUA_OK)
{ {
// ignore error for now std::cout << lua_tostring(L, -1) << std::endl;
lua_pop(L, 1); lua_pop(L, 1);
} }
lua_remove(L, handler);
} }
void mainloop(float dt) void mainloop(float dt)
{ {
lua_pushcfunction(L, message_handler);
const int handler = lua_gettop(L);
lua_getglobal(L, "glerminal"); lua_getglobal(L, "glerminal");
lua_getfield(L, -1, "main"); lua_getfield(L, -1, "main");
lua_remove(L, -2); lua_remove(L, -2);
lua_pushnumber(L, dt); lua_pushnumber(L, dt);
if (lua_pcall(L, 1, 0, 0) != LUA_OK) if (lua_pcall(L, 1, 0, handler) != LUA_OK)
{ {
// ignore error for now std::cout << lua_tostring(L, -1) << std::endl;
lua_pop(L, 1); lua_pop(L, 1);
} }
lua_remove(L, handler);
} }
void pressed(int key) void pressed(int key)
@ -140,15 +159,18 @@ namespace
const char* const name = glfwGetKeyName(key, 0); const char* const name = glfwGetKeyName(key, 0);
if (name) if (name)
{ {
lua_pushcfunction(L, message_handler);
const int handler = lua_gettop(L);
lua_getglobal(L, "glerminal"); lua_getglobal(L, "glerminal");
lua_getfield(L, -1, "pressed"); lua_getfield(L, -1, "pressed");
lua_remove(L, -2); lua_remove(L, -2);
lua_pushstring(L, name); lua_pushstring(L, name);
if (lua_pcall(L, 1, 0, 0) != LUA_OK) if (lua_pcall(L, 1, 0, handler) != LUA_OK)
{ {
// ignore error for now std::cout << lua_tostring(L, -1) << std::endl;
lua_pop(L, 1); lua_pop(L, 1);
} }
lua_remove(L, handler);
} }
} }
@ -157,15 +179,18 @@ namespace
const char* const name = glfwGetKeyName(key, 0); const char* const name = glfwGetKeyName(key, 0);
if (name) if (name)
{ {
lua_pushcfunction(L, message_handler);
const int handler = lua_gettop(L);
lua_getglobal(L, "glerminal"); lua_getglobal(L, "glerminal");
lua_getfield(L, -1, "released"); lua_getfield(L, -1, "released");
lua_remove(L, -2); lua_remove(L, -2);
lua_pushstring(L, name); lua_pushstring(L, name);
if (lua_pcall(L, 1, 0, 0) != LUA_OK) if (lua_pcall(L, 1, 0, handler) != LUA_OK)
{ {
// ignore error for now std::cout << lua_tostring(L, -1) << std::endl;
lua_pop(L, 1); lua_pop(L, 1);
} }
lua_remove(L, handler);
} }
} }
} }

View File

@ -41,8 +41,8 @@ namespace glerminal
void flush(); void flush();
void set(unsigned char x, unsigned char y, unsigned char layer, unsigned char sprite); void set(unsigned char x, unsigned char y, unsigned char layer, unsigned short sprite);
unsigned char get(unsigned char x, unsigned char y, unsigned char layer) const; unsigned short get(unsigned char x, unsigned char y, unsigned char layer) const;
void offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset); void offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset);
void layer_color(unsigned char layer, unsigned int color); void layer_color(unsigned char layer, unsigned int color);
void layer_scale(unsigned char layer, float scale); void layer_scale(unsigned char layer, float scale);
@ -84,7 +84,7 @@ namespace glerminal
// library state // library state
unsigned int m_sprites[CELL_SIZE * CELL_SIZE * MAX_SPRITES]; unsigned int m_sprites[(CELL_SIZE + 2) * (CELL_SIZE + 2) * MAX_SPRITES];
glerminal_main_cb m_main; glerminal_main_cb m_main;
glerminal_keys_cb m_pressed, m_released; glerminal_keys_cb m_pressed, m_released;

View File

@ -54,7 +54,7 @@ namespace
" vs_out.sprite = sprite;\n" " vs_out.sprite = sprite;\n"
" vs_out.layer = layer;\n" " vs_out.layer = layer;\n"
" vs_out.layer_color = lcs.colors[layer];\n" " vs_out.layer_color = lcs.colors[layer];\n"
" vs_out.texcoord = (vec2((sprite + int(position.x + 1)) % " ATLAS_WIDTH_UNIFORM_NAME ", (sprite / " ATLAS_WIDTH_UNIFORM_NAME ") - position.y) + vec2((position.x + 0.5) / -32, (position.y + 0.5) / 32)) / vec2(" ATLAS_WIDTH_UNIFORM_NAME ");\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(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 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" " 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(scaled_offset.x + temp.x, scaled_offset.y - temp.y, 0, 1);\n" " gl_Position = vec4(scaled_offset.x + temp.x, scaled_offset.y - temp.y, 0, 1);\n"
@ -89,7 +89,7 @@ namespace
" gl_Layer = layer;\n" " gl_Layer = layer;\n"
" vec2 scaled_offset = 2 * offset * " GRID_SIZE_UNIFORM_NAME ".zw;\n" " vec2 scaled_offset = 2 * offset * " GRID_SIZE_UNIFORM_NAME ".zw;\n"
" vs_out.sprite = sprite;\n" " vs_out.sprite = sprite;\n"
" vs_out.texcoord = (vec2((sprite + int(position.x + 1)) % " ATLAS_WIDTH_UNIFORM_NAME ", (sprite / " ATLAS_WIDTH_UNIFORM_NAME ") - position.y) + vec2((position.x + 0.5) / -32, (position.y + 0.5) / 32)) / vec2(" ATLAS_WIDTH_UNIFORM_NAME ");\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 = lcs.colors[layer];\n" " vs_out.layer_color = lcs.colors[layer];\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 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" " 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"
@ -294,10 +294,13 @@ namespace glerminal
glBlitNamedFramebuffer(m_screen_framebuffer, 0, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitNamedFramebuffer(m_screen_framebuffer, 0, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glfwSwapInterval(0);
glfwSwapBuffers(m_window);
glfwSwapInterval(1);
glfwSwapBuffers(m_window); glfwSwapBuffers(m_window);
} }
void glerminal::set(unsigned char x, unsigned char y, unsigned char layer, unsigned char sprite) 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 && y < GRID_HEIGHT && layer < LAYER_COUNT)
{ {
@ -305,7 +308,7 @@ namespace glerminal
} }
} }
unsigned char glerminal::get(unsigned char x, unsigned char y, unsigned char layer) const 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 && y < GRID_HEIGHT && layer < LAYER_COUNT)
{ {
@ -341,21 +344,25 @@ namespace glerminal
void glerminal::load_atlas(unsigned char w, unsigned char h, const unsigned int* data) void glerminal::load_atlas(unsigned char w, unsigned char h, const unsigned int* data)
{ {
// each row of the atlas for (int src_atlas_row = 0; src_atlas_row < h; src_atlas_row++)
for (int j = 0; j < h; j++)
{ {
// each column of the atlas for (int src_atlas_col = 0; src_atlas_col < w; src_atlas_col++)
for (int i = 0; i < w; i++)
{ {
// each row of the individual sprite for (int sprite_row = 0; sprite_row < CELL_SIZE; sprite_row++)
for (int k = 0; k < CELL_SIZE; k++)
{ {
// offset from base address in source atlas layout const unsigned int sprite_index = src_atlas_col + src_atlas_row * w;
const unsigned int src_offset = i + k * w + j * w * CELL_SIZE; const unsigned int dst_atlas_row = sprite_index / MAX_SPRITES_ROW;
// offset from base address in glerminal atlas layout const unsigned int dst_atlas_col = sprite_index % MAX_SPRITES_ROW;
const unsigned int dst_offset = i + k * MAX_SPRITES_ROW + j * MAX_SPRITES_ROW * CELL_SIZE;
memcpy(m_sprites + CELL_SIZE * dst_offset, data + CELL_SIZE * src_offset, CELL_SIZE * sizeof(unsigned int)); // offset from base address in source atlas layout
const unsigned int src_offset = CELL_SIZE * (src_atlas_col + sprite_row * w + src_atlas_row * w * CELL_SIZE);
const unsigned int dst_column = dst_atlas_col * (CELL_SIZE + 2) + 1;
const unsigned int dst_row = MAX_SPRITES_ROW * (CELL_SIZE + 2) * ((sprite_row + 1) + dst_atlas_row * (CELL_SIZE + 2));
// offset from base address in glerminal atlas layout
const unsigned int dst_offset = dst_column + dst_row;
memcpy(m_sprites + dst_offset, data + src_offset, CELL_SIZE * sizeof(unsigned int));
} }
} }
} }
@ -365,7 +372,6 @@ namespace glerminal
{ {
glfwInit(); glfwInit();
glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
@ -691,7 +697,7 @@ namespace glerminal
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTextureStorage2D(m_sprites_texture, 1, GL_RGBA8, MAX_SPRITES_ROW * CELL_SIZE, MAX_SPRITES_ROW * CELL_SIZE); glTextureStorage2D(m_sprites_texture, 1, GL_RGBA8, MAX_SPRITES_ROW * (CELL_SIZE + 2), MAX_SPRITES_ROW * (CELL_SIZE + 2));
update_sprites(); update_sprites();
@ -765,7 +771,7 @@ namespace glerminal
void glerminal::update_sprites() void glerminal::update_sprites()
{ {
glTextureSubImage2D(m_sprites_texture, 0, 0, 0, CELL_SIZE * MAX_SPRITES_ROW, CELL_SIZE * MAX_SPRITES_ROW, GL_RGBA, GL_UNSIGNED_BYTE, m_sprites); glTextureSubImage2D(m_sprites_texture, 0, 0, 0, (CELL_SIZE + 2) * MAX_SPRITES_ROW, (CELL_SIZE + 2) * MAX_SPRITES_ROW, GL_RGBA, GL_UNSIGNED_BYTE, m_sprites);
} }
void glerminal::update_layer_colors() void glerminal::update_layer_colors()
@ -822,14 +828,14 @@ void glerminal_flush()
GLERMINAL_G->flush(); GLERMINAL_G->flush();
} }
void glerminal_set(unsigned char x, unsigned char y, unsigned char layer, unsigned char sprite) void glerminal_set(unsigned char x, unsigned char y, unsigned char layer, unsigned short sprite)
{ {
if (!GLERMINAL_G) { return; } if (!GLERMINAL_G) { return; }
GLERMINAL_G->set(x, y, layer, sprite); GLERMINAL_G->set(x, y, layer, sprite);
} }
unsigned char glerminal_get(unsigned char x, unsigned char y, unsigned char layer) unsigned char glerminal_get(unsigned char x, unsigned char y, unsigned short layer)
{ {
if (!GLERMINAL_G) { return 0; } if (!GLERMINAL_G) { return 0; }