diff --git a/.gitmodules b/.gitmodules index c98937d..babdc79 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "glfw"] path = glfw url = https://git.shylie.info/shylie/glfw.git +[submodule "Lua"] + path = Lua + url = https://git.shylie.info/shylie/Lua.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e43d26..e9e730e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,11 +15,13 @@ set(GLERMINAL_CELL_SCALE 4 CACHE STRING "") configure_file(source/glerminal-config.h.in glerminal-config.h @ONLY) add_subdirectory(glfw) +add_subdirectory(Lua) -add_library(glerminal STATIC +add_library(glerminallib STATIC ${CMAKE_CURRENT_BINARY_DIR}/glerminal-config.h include/glerminal.h + source/stb_image.h source/glerminal-private.h source/glerminal.cpp @@ -28,12 +30,12 @@ add_library(glerminal STATIC source/glad.c ) -set_target_properties(glerminal +set_target_properties(glerminallib PROPERTIES CXX_STANDARD 11 ) -target_include_directories(glerminal +target_include_directories(glerminallib PUBLIC include ${CMAKE_CURRENT_BINARY_DIR} @@ -41,12 +43,12 @@ target_include_directories(glerminal source ) -target_link_libraries(glerminal - PRIVATE +target_link_libraries(glerminallib + PUBLIC glfw ) -target_compile_definitions(glerminal +target_compile_definitions(glerminallib PUBLIC GLERMINAL_VERSION=${PROJECT_VERSION} GLERMINAL_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} @@ -55,12 +57,22 @@ target_compile_definitions(glerminal ) if (MSVC) - target_link_options(glerminal + target_link_options(glerminallib PUBLIC "/ENTRY:mainCRTStartup" ) endif() +add_executable(glerminal WIN32 + source/glerminal-main.cpp +) + +target_link_libraries(glerminal + PRIVATE + glerminallib + lua_static +) + if (PROJECT_IS_TOP_LEVEL) add_subdirectory(examples examples) endif() diff --git a/Lua b/Lua new file mode 160000 index 0000000..88246d6 --- /dev/null +++ b/Lua @@ -0,0 +1 @@ +Subproject commit 88246d621abf7b6fba9332f49229d507f020e450 diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index a34a389..b7a248b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -12,10 +12,12 @@ file(GLOB_RECURSE foreach(RESOURCE_FILE ${EXAMPLE_RESOURCES}) add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${RESOURCE_FILE} - COMMAND ${CMAKE_COMMAND} -E copy - ${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_FILE} + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${RESOURCE_FILE} + COMMAND + ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_FILE} + ${CMAKE_CURRENT_BINARY_DIR}/${RESOURCE_FILE} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_FILE} ) @@ -34,5 +36,5 @@ list(TRANSFORM EXAMPLE_RESOURCES PREPEND ${CMAKE_CURRENT_BINARY_DIR}/) foreach(SOURCE_FILE ${EXAMPLE_SOURCES}) get_filename_component(SOURCE_FILENAME ${SOURCE_FILE} NAME_WLE) add_executable(${SOURCE_FILENAME} WIN32 ${SOURCE_FILE} ${EXAMPLE_RESOURCES}) - target_link_libraries(${SOURCE_FILENAME} PRIVATE glerminal) + target_link_libraries(${SOURCE_FILENAME} PRIVATE glerminallib) endforeach() \ No newline at end of file diff --git a/lua-examples/basic/main.lua b/lua-examples/basic/main.lua new file mode 100644 index 0000000..c871817 --- /dev/null +++ b/lua-examples/basic/main.lua @@ -0,0 +1,29 @@ +local time = 0 + +function glerminal.init() + if not glerminal.sprites('sprites.png') then + print('failed to load sprites') + end + + for i = 1, 40 do + for j = 1, 25 do + glerminal.set(i, j, 1, 2) + end + end + + glerminal.tint(1, 0xA0FFFFFF) + + glerminal.flush() +end + +function glerminal.main(dt) + time = time + dt / 2 + + for i = 1, 40 do + for j = 1, 25 do + glerminal.offset(i, j, 1, math.cos(time * i / math.pi), math.sin(time * j / math.pi)) + end + end + + glerminal.flush() +end \ No newline at end of file diff --git a/lua-examples/basic/sprites.png b/lua-examples/basic/sprites.png new file mode 100644 index 0000000..4758f7b --- /dev/null +++ b/lua-examples/basic/sprites.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6dee3efcdfa72e54a602f69643907bb8e8a3328d2b40c2116dce22ff179d8892 +size 182 diff --git a/source/glerminal-main.cpp b/source/glerminal-main.cpp new file mode 100644 index 0000000..6708668 --- /dev/null +++ b/source/glerminal-main.cpp @@ -0,0 +1,163 @@ +#include + +extern "C" +{ +#include +#include +} + +#include + +#ifdef _WIN32 +#define WINDOWS_LEAN_AND_MEAN +#include +#define CHANGE_WORKING_DIRECTORY(path) !(SetCurrentDirectory(path)) +#else +#include +#define CHANGE_WORKING_DIRECTORY(path) chdir(path) +#endif + +namespace +{ + int lglerminal_quit(lua_State* L) + { + glerminal_quit(); + + return 0; + } + + int lglerminal_flush(lua_State* L) + { + glerminal_flush(); + + return 0; + } + + 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 layer = luaL_checkinteger(L, 3) - 1; + const unsigned char sprite = luaL_checkinteger(L, 4) - 1; + glerminal_set(x, y, layer, sprite); + + return 0; + } + + 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 layer = luaL_checkinteger(L, 3) - 1; + lua_pushnumber(L, glerminal_get(x, y, layer) + 1); + + return 1; + } + + 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 layer = luaL_checkinteger(L, 3) - 1; + const float ox = luaL_checknumber(L, 4); + const float oy = luaL_checknumber(L, 5); + glerminal_offset(x, y, layer, ox, oy); + + return 0; + } + + int lglerminal_layer_color(lua_State* L) + { + const unsigned char layer = luaL_checkinteger(L, 1) - 1; + const unsigned int color = luaL_checkinteger(L, 2); + glerminal_layer_color(layer, color); + + return 0; + } + + int lglerminal_layer_scale(lua_State* L) + { + const unsigned char layer = luaL_checkinteger(L, 1) - 1; + const float scale = luaL_checknumber(L, 2); + glerminal_layer_scale(layer, scale); + + return 0; + } + + int lglerminal_load_sprites_file(lua_State* L) + { + const char* path = luaL_checkstring(L, 1); + lua_pushboolean(L, glerminal_load_sprites_file(path)); + + return 1; + } + + const luaL_Reg lglerminal_methods[] = + { + { "quit", lglerminal_quit }, + { "flush", lglerminal_flush }, + { "set", lglerminal_set }, + { "get", lglerminal_get }, + { "offset", lglerminal_offset }, + { "tint", lglerminal_layer_color }, + { "scale", lglerminal_layer_scale }, + { "sprites", lglerminal_load_sprites_file }, + { nullptr, nullptr } + }; + + lua_State* L; + + void init() + { + lua_getglobal(L, "glerminal"); + lua_getfield(L, -1, "init"); + lua_remove(L, -2); + if (lua_pcall(L, 0, 0, 0) != LUA_OK) + { + // ignore error for now + lua_remove(L, -1); + } + } + + void mainloop(float dt) + { + lua_getglobal(L, "glerminal"); + lua_getfield(L, -1, "main"); + lua_remove(L, -2); + lua_pushnumber(L, dt); + if (lua_pcall(L, 1, 0, 0) != LUA_OK) + { + // ignore error for now + lua_remove(L, -1); + } + } +} + +int main(int argc, char** argv) +{ + if (argc == 1) + { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return 0; + } + + if (CHANGE_WORKING_DIRECTORY(argv[1])) + { + std::cout << "Failed to find project directory" << std::endl; + return 1; + } + + L = luaL_newstate(); + luaL_openlibs(L); + + luaL_newlib(L, lglerminal_methods); + lua_setglobal(L, "glerminal"); + + luaL_dofile(L, "main.lua"); + + glerminal_run(init, mainloop); + + lua_close(L); + + return 0; +} \ No newline at end of file diff --git a/source/glerminal.cpp b/source/glerminal.cpp index a4d2fd9..ff7a5a0 100644 --- a/source/glerminal.cpp +++ b/source/glerminal.cpp @@ -35,9 +35,14 @@ namespace "{\n" " float scales[];\n" "} lss;\n" + "layout (std430, binding = 1) buffer LayerColors" + "{\n" + " vec4 colors[];\n" + "} lcs;\n" "out VS_OUT {\n" " flat int sprite;\n" " flat int layer;\n" + " flat vec4 layer_color;\n" " vec2 texcoord;\n" "} vs_out;\n" "void main()\n" @@ -46,6 +51,7 @@ namespace " vec2 scaled_offset = 2 * offset * " GRID_SIZE_UNIFORM_NAME ".zw;\n" " vs_out.sprite = sprite;\n" " vs_out.layer = layer;\n" + " vs_out.layer_color = lcs.colors[layer];\n" " vs_out.texcoord = vec2(position.x + 1, -position.y);\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" @@ -65,8 +71,13 @@ namespace "{\n" " float scales[];\n" "} lss;\n" + "layout (std430, binding = 1) buffer LayerColors" + "{\n" + " vec4 colors[];\n" + "} lcs;\n" "out VS_OUT {\n" " flat int sprite;\n" + " flat vec4 layer_color;\n" " vec2 texcoord;\n" "} vs_out;\n" "void main()\n" @@ -76,6 +87,7 @@ namespace " vec2 scaled_offset = 2 * offset * " GRID_SIZE_UNIFORM_NAME ".zw;\n" " vs_out.sprite = sprite;\n" " vs_out.texcoord = vec2(position.x + 1, -position.y);\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 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" @@ -91,25 +103,30 @@ namespace "in VS_OUT {\n" " flat int sprite;\n" " flat int layer;\n" + " flat vec4 layer_color;\n" " vec2 texcoord;\n" "} gs_in[];\n" "flat out int sprite;\n" + "flat vec4 layer_color;\n" "out vec2 texcoord;\n" "void main()\n" "{\n" " gl_Layer = gs_in[0].layer;\n" " gl_Position = gl_in[0].gl_Position;\n" " sprite = gs_in[0].sprite;\n" + " layer_color = gs_in[0].layer_color;\n" " texcoord = gs_in[0].texcoord;\n" " EmitVertex();\n" " gl_Layer = gs_in[1].layer;\n" " gl_Position = gl_in[1].gl_Position;\n" " sprite = gs_in[1].sprite;\n" + " layer_color = gs_in[1].layer_color;\n" " texcoord = gs_in[1].texcoord;\n" " EmitVertex();\n" " gl_Layer = gs_in[2].layer;\n" " gl_Position = gl_in[2].gl_Position;\n" " sprite = gs_in[2].sprite;\n" + " layer_color = gs_in[2].layer_color;\n" " texcoord = gs_in[2].texcoord;\n" " EmitVertex();\n" " EndPrimitive();\n" @@ -119,13 +136,14 @@ namespace constexpr char FRAGMENT_SHADER_SOURCE[] = "#version 450 core\n" - "in vec2 texcoord;\n" "flat in int sprite;\n" + "flat vec4 layer_color;\n" + "in vec2 texcoord;\n" "layout (binding = 0) uniform sampler2DArray " SPRITES_UNIFORM_NAME ";\n" "out vec4 FragColor;\n" "void main()\n" "{\n" - " FragColor = texture(" SPRITES_UNIFORM_NAME ", vec3(texcoord, sprite));\n" + " FragColor = layer_color * texture(" SPRITES_UNIFORM_NAME ", vec3(texcoord, sprite));\n" "}"; // note: AMD_vertex_shader_layer support required @@ -133,13 +151,14 @@ namespace "#version 450 core\n" "in VS_OUT {\n" " flat int sprite;\n" + " flat vec4 layer_color;\n" " vec2 texcoord;\n" "} fs_in;\n" "layout (binding = 0) uniform sampler2DArray " SPRITES_UNIFORM_NAME ";\n" "out vec4 FragColor;\n" "void main()\n" "{\n" - " FragColor = texture(" SPRITES_UNIFORM_NAME ", vec3(fs_in.texcoord, fs_in.sprite));\n" + " FragColor = fs_in.layer_color * texture(" SPRITES_UNIFORM_NAME ", vec3(fs_in.texcoord, fs_in.sprite));\n" "}"; constexpr const char* FRAGMENT_SHADER_SOURCE_PTR = FRAGMENT_SHADER_SOURCE; @@ -161,10 +180,6 @@ namespace "#version 450 core\n" "in vec2 texcoord;\n" "layout (binding = 1) uniform sampler2DArray " LAYERS_UNIFORM_NAME ";\n" - "layout (std430, binding = 1) buffer LayerColors" - "{\n" - " vec4 colors[];\n" - "} lcs;\n" "uniform int " LAYER_COUNT_UNIFORM_NAME ";\n" "out vec4 FragColor;\n" "void main()\n" @@ -172,7 +187,7 @@ namespace " vec3 current_color = vec3(0);\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" + " vec4 texsample = texture(" LAYERS_UNIFORM_NAME ", vec3(texcoord, i));\n" " current_color = mix(current_color, texsample.rgb, texsample.a);\n" " }\n" " FragColor = vec4(current_color, 1);\n" @@ -222,6 +237,8 @@ namespace glerminal GLERMINAL_G = this; init(); + + glerminal_flush(); } glerminal::~glerminal() @@ -527,8 +544,8 @@ namespace glerminal glDeleteShader(geometry_shader); glDeleteShader(fragment_shader); - log(GL_DEBUG_TYPE_ERROR, 0, 0, "Could not compile vertex shader."); - log(GL_DEBUG_TYPE_ERROR, 0, 0, info_log); + log(GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, "Could not compile vertex shader."); + log(GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, info_log); throw std::runtime_error("Could not compile vertex shader."); } @@ -541,8 +558,8 @@ namespace glerminal glDeleteShader(geometry_shader); glDeleteShader(fragment_shader); - log(GL_DEBUG_TYPE_ERROR, 1, 0, "Could not compile geometry shader."); - log(GL_DEBUG_TYPE_ERROR, 1, 0, info_log); + log(GL_DEBUG_TYPE_ERROR, 1, GL_DEBUG_SEVERITY_HIGH, "Could not compile geometry shader."); + log(GL_DEBUG_TYPE_ERROR, 1, GL_DEBUG_SEVERITY_HIGH, info_log); throw std::runtime_error("Could not compile geometry shader."); } @@ -555,8 +572,8 @@ namespace glerminal glDeleteShader(geometry_shader); glDeleteShader(fragment_shader); - log(GL_DEBUG_TYPE_ERROR, 2, 0, "Could not compile fragment shader."); - log(GL_DEBUG_TYPE_ERROR, 2, 0, info_log); + log(GL_DEBUG_TYPE_ERROR, 2, GL_DEBUG_SEVERITY_HIGH, "Could not compile fragment shader."); + log(GL_DEBUG_TYPE_ERROR, 2, GL_DEBUG_SEVERITY_HIGH, info_log); throw std::runtime_error("Could not compile fragment shader."); } @@ -582,8 +599,8 @@ namespace glerminal glDeleteProgram(m_program); - log(GL_DEBUG_TYPE_ERROR, 3, 0, "Could not link shader program."); - log(GL_DEBUG_TYPE_ERROR, 3, 0, info_log); + log(GL_DEBUG_TYPE_ERROR, 3, GL_DEBUG_SEVERITY_HIGH, "Could not link shader program."); + log(GL_DEBUG_TYPE_ERROR, 3, GL_DEBUG_SEVERITY_HIGH, info_log); throw std::runtime_error("Could not link shader program."); } @@ -611,8 +628,8 @@ namespace glerminal glDeleteShader(screen_vertex_shader); glDeleteShader(screen_fragment_shader); - log(GL_DEBUG_TYPE_ERROR, 4, 0, "Could not compile screen vertex shader."); - log(GL_DEBUG_TYPE_ERROR, 4, 0, info_log); + log(GL_DEBUG_TYPE_ERROR, 4, GL_DEBUG_SEVERITY_HIGH, "Could not compile screen vertex shader."); + log(GL_DEBUG_TYPE_ERROR, 4, GL_DEBUG_SEVERITY_HIGH, info_log); throw std::runtime_error("Could not compile screen vertex shader."); } @@ -624,8 +641,8 @@ namespace glerminal glDeleteShader(screen_vertex_shader); glDeleteShader(screen_fragment_shader); - log(GL_DEBUG_TYPE_ERROR, 5, 0, "Could not compile screen fragment shader."); - log(GL_DEBUG_TYPE_ERROR, 5, 0, info_log); + log(GL_DEBUG_TYPE_ERROR, 5, GL_DEBUG_SEVERITY_HIGH, "Could not compile screen fragment shader."); + log(GL_DEBUG_TYPE_ERROR, 5, GL_DEBUG_SEVERITY_HIGH, info_log); throw std::runtime_error("Could not compile screen fragment shader."); } @@ -643,8 +660,8 @@ namespace glerminal { glDeleteProgram(m_screen_program); - log(GL_DEBUG_TYPE_ERROR, 6, 0, "Could not link screen shader program."); - log(GL_DEBUG_TYPE_ERROR, 6, 0, info_log); + log(GL_DEBUG_TYPE_ERROR, 6, GL_DEBUG_SEVERITY_HIGH, "Could not link screen shader program."); + log(GL_DEBUG_TYPE_ERROR, 6, GL_DEBUG_SEVERITY_HIGH, info_log); throw std::runtime_error("Could not link screen shader program."); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 38006cc..500d129 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -52,5 +52,5 @@ list(TRANSFORM TEST_RESOURCES PREPEND ${CMAKE_CURRENT_BINARY_DIR}/) foreach(SOURCE_FILE ${TEST_SOURCES}) get_filename_component(SOURCE_FILENAME ${SOURCE_FILE} NAME_WLE) add_executable(test-${SOURCE_FILENAME} WIN32 ${SOURCE_FILE} ${TEST_RESOURCES}) - target_link_libraries(test-${SOURCE_FILENAME} PRIVATE glerminal test-common) + target_link_libraries(test-${SOURCE_FILENAME} PRIVATE glerminallib test-common) endforeach() \ No newline at end of file