diff --git a/.gitignore b/.gitignore index 4115f70..b7e52df 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,10 @@ !Makefile **/*.exe +**/*.html +**/*.js +**/*.wasm +**/*.wasm.map **/*.so **/*.dll **/*.7z @@ -16,6 +20,7 @@ .idea/ .cache/ .build/ +.build-web/ build/ out/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 5296c4c..3b0bd86 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,10 @@ cmake_minimum_required(VERSION 3.21) project(townengine LANGUAGES C) # SDL dependencies -find_package(SDL2 REQUIRED GLOBAL) +# for whatever reason Emscripten has SDL2 config, but not actual SDL2 port by default +if(NOT EMSCRIPTEN) + find_package(SDL2 REQUIRED GLOBAL) +endif() # CMake actually has no default configuration and it's toolchain file dependent, set debug if not specified if(NOT CMAKE_BUILD_TYPE) @@ -19,6 +22,14 @@ set(TWN_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "") option(TWN_FEATURE_DYNLIB_GAME "Enable dynamic library loading support" ON) option(TWN_ARCHIVE_DATA "Enable archival of assets" OFF) +# todo: figure out how to compile for dynamic linking instead +if(EMSCRIPTEN) + if(TWN_FEATURE_DYNLIB_GAME) + message(WARNING "TWN_FEATURE_DYNLIB_GAME is set, but not supported - it is turned off") + set(TWN_FEATURE_DYNLIB_GAME OFF CACHE INTERNAL "") + endif() +endif() + # add -fPIC globally so that it's linked well add_compile_options($<$:-fPIC>) @@ -37,8 +48,8 @@ add_subdirectory(third-party/physfs SYSTEM) add_subdirectory(third-party/libxm SYSTEM) -if(UNIX) - set(SYSTEM_SOURCE_FILES townengine/system/linux/elf.c) +if(LINUX) + set(SYSTEM_SOURCE_FILES src/system/linux/elf.c) else() set(SYSTEM_SOURCE_FILES) endif() @@ -46,22 +57,22 @@ endif() set(TWN_THIRD_PARTY_SOURCE_FILES third-party/physfs/extras/physfsrwops.c third-party/stb/stb_vorbis.c - third-party/glad/src/glad.c) + $<$>:third-party/glad/src/glad.c>) set(TWN_SOURCE_FILES - townengine/twn_loop.c - townengine/twn_main.c - townengine/config.h - townengine/context/context.c townengine/context.h - townengine/audio/audio.c townengine/audio.h - townengine/util.c townengine/util.h - townengine/rendering.c townengine/rendering.h - townengine/input/input.c townengine/input.h - townengine/camera.c townengine/camera.h - townengine/textures/textures.c - townengine/twn_game_object.c + src/twn_loop.c + src/twn_main.c + src/twn_context.c include/twn_context.h + src/twn_audio.c include/twn_audio.h + src/twn_util.c include/twn_util.h + src/twn_rendering.c include/twn_rendering.h + src/twn_input.c include/twn_input.h + src/twn_camera.c include/twn_camera.h + src/twn_textures.c include/twn_textures.c + src/twn_game_object.c - $<$>:townengine/twn_main.c> + # for dynamic load based solution main is compiled in a separate target + $<$>:src/twn_main.c> ${SYSTEM_SOURCE_FILES}) @@ -79,13 +90,13 @@ endif() source_group(TREE ${TWN_ROOT_DIR} FILES ${TWN_SOURCE_FILES}) set_target_properties(${TWN_TARGET} PROPERTIES - C_STANDARD 11 - C_STANDARD_REQUIRED ON - C_EXTENSIONS ON) # extensions are required by stb_ds.h + C_STANDARD 11 + C_STANDARD_REQUIRED ON + C_EXTENSIONS ON) # extensions are required by stb_ds.h # precompile commonly used not-so-small headers target_precompile_headers(${TWN_TARGET} PRIVATE - third-party/glad/include/glad/glad.h + $<$>:third-party/glad/include/glad/glad.h> third-party/stb/stb_ds.h) # distribution definitions, set them with -DX=X in cli @@ -104,7 +115,8 @@ function(give_options_without_warnings target) -ffp-contract=fast -fno-signed-zeros -fno-trapping-math - -freciprocal-math) + -freciprocal-math + $<$:-sUSE_SDL=2>) set(BUILD_FLAGS_RELEASE -O3 @@ -114,8 +126,7 @@ function(give_options_without_warnings target) -fdata-sections -ffunction-sections -funroll-loops - -fomit-frame-pointer - $<$:-fallow-store-data-races>) + -fomit-frame-pointer) set(BUILD_FLAGS_DEBUG -O0 @@ -124,7 +135,8 @@ function(give_options_without_warnings target) -fno-omit-frame-pointer -fstack-protector-all -fsanitize=undefined - -fsanitize=address) + -fsanitize=address + $<$:-gsource-map>) target_compile_options(${target} PRIVATE ${BUILD_FLAGS} @@ -179,9 +191,9 @@ function(include_deps target) third-party/physfs/src third-party/physfs/extras third-party/libxm/include - third-party/glad/include third-party/stb - third-party/x-watcher) + third-party/x-watcher + $<$>:third-party/glad/include>) list(TRANSFORM THIRD_PARTY_INCLUDES PREPEND ${TWN_ROOT_DIR}/) target_include_directories(${target} SYSTEM PRIVATE ${THIRD_PARTY_INCLUDES}) @@ -193,7 +205,7 @@ endfunction() function(link_deps target) target_link_libraries(${target} PUBLIC - SDL2::SDL2 + $<$>:SDL2::SDL2> physfs-static xms) endfunction() @@ -205,14 +217,14 @@ function(use_townengine target sources output_directory data_dir) add_library(${target}_game SHARED ${sources}) give_options(${target}_game) include_deps(${target}_game) - target_link_libraries(${target}_game PUBLIC SDL2::SDL2 ${TWN_TARGET}) + target_link_libraries(${target}_game PUBLIC $<$>:SDL2::SDL2> ${TWN_TARGET}) set_target_properties(${target}_game PROPERTIES OUTPUT_NAME game LIBRARY_OUTPUT_DIRECTORY ${output_directory} RUNTIME_OUTPUT_DIRECTORY ${output_directory}) # launcher binary, loads game and engine shared library - add_executable(${target}_app ${TWN_ROOT_DIR}/townengine/twn_main.c) + add_executable(${target}_app ${TWN_ROOT_DIR}/src/twn_main.c) # todo: copy instead? # put libtownengine.so alongside the binary @@ -225,7 +237,16 @@ function(use_townengine target sources output_directory data_dir) set_target_properties(${target}_app PROPERTIES OUTPUT_NAME launcher - LIBRARY_OUTPUT_DIRECTORY ${output_directory}) + LIBRARY_OUTPUT_DIRECTORY ${output_directory} + RUNTIME_OUTPUT_DIRECTORY ${output_directory}) + + if(EMSCRIPTEN) + set_target_properties(${target}_app PROPERTIES + SUFFIX .html) + endif() + + target_compile_options(${target}_app PRIVATE + $<$:--shell-file ${TWN_ROOT_DIR}/shell_minimal.html>) # system libraries find_library(MATH_LIBRARY m) @@ -236,10 +257,8 @@ function(use_townengine target sources output_directory data_dir) give_options(${target}_app) include_deps(${target}_app) link_deps(${target}_app) - target_link_libraries(${target}_app PUBLIC ${TWN_TARGET}) - set_target_properties(${target}_app PROPERTIES - RUNTIME_OUTPUT_DIRECTORY ${output_directory}) + target_link_libraries(${target}_app PUBLIC ${TWN_TARGET}) if(WIN32) # copy dlls for baby windows add_custom_command(TARGET ${target}_app POST_BUILD @@ -297,5 +316,5 @@ endif() # move compie_commands.json into root directory so that it plays nicer with code editors without any configuration add_custom_target(copy-compile-commands ALL - ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/compile_commands.json - ${TWN_ROOT_DIR}) + ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/compile_commands.json + ${TWN_ROOT_DIR}) diff --git a/apps/testgame/build.sh b/apps/testgame/build.sh index 45ab8a7..aefa755 100755 --- a/apps/testgame/build.sh +++ b/apps/testgame/build.sh @@ -1,3 +1,7 @@ #!/bin/env sh -cmake -B .build "$@" && cmake --build .build +if [ $1 = "web" ]; then + emcmake cmake -B .build-web "${@:2}" && cmake --build .build-web +else + cmake -B .build "$@" && cmake --build .build +fi diff --git a/docs/source_directory_structure.txt b/docs/source_directory_structure.txt new file mode 100644 index 0000000..771f2a2 --- /dev/null +++ b/docs/source_directory_structure.txt @@ -0,0 +1,20 @@ +all source files are prefixed with 'twn_' + +things are categorized into two main folders: +- 'include' for any definition that are usable from townengine library +- 'src' for any private implementations + +internal headers have '_c.h' ending, so to not collide with our include style + +example of a module: +src/twn_module.c -- internal implementations +src/twn_module_c.h -- private declarations +include/twn_module.h -- public declarations + +both private and public headers are included via root: +#include "twn_module.h" +#include "twn_module_c.h" + +additional subfolders in src/ are possible when implementation permutations are in place, build system will chose the appropriate ones + +all procedures in include/ headers must have TWN_API macro applied diff --git a/townengine/audio.h b/include/twn_audio.h similarity index 96% rename from townengine/audio.h rename to include/twn_audio.h index 2e25c89..ec41e99 100644 --- a/townengine/audio.h +++ b/include/twn_audio.h @@ -1,5 +1,5 @@ -#ifndef AUDIO_H -#define AUDIO_H +#ifndef TWN_AUDIO_H +#define TWN_AUDIO_H #include "twn_engine_api.h" diff --git a/townengine/camera.h b/include/twn_camera.h similarity index 60% rename from townengine/camera.h rename to include/twn_camera.h index dc1fa38..d57a667 100644 --- a/townengine/camera.h +++ b/include/twn_camera.h @@ -1,9 +1,10 @@ -#ifndef CAMERA_H -#define CAMERA_H +#ifndef TWN_CAMERA_H +#define TWN_CAMERA_H -#include "util.h" +#include "twn_util.h" +#include "twn_engine_api.h" -/* TODO: make it cached */ +/* TODO: make it cached? */ /* for example, perspective matrix only needs recaluclation on FOV change */ /* first person camera class */ @@ -14,8 +15,8 @@ typedef struct camera { float fov; /* field of view, in radians */ } t_camera; -t_matrix4 camera_look_at(const t_camera *camera); +TWN_API t_matrix4 camera_look_at(const t_camera *camera); -t_matrix4 camera_perspective(const t_camera *const camera); +TWN_API t_matrix4 camera_perspective(const t_camera *const camera); #endif diff --git a/townengine/config.h b/include/twn_config.h similarity index 84% rename from townengine/config.h rename to include/twn_config.h index 273b8ba..d646786 100644 --- a/townengine/config.h +++ b/include/twn_config.h @@ -1,9 +1,5 @@ -#ifndef CONFIG_H -#define CONFIG_H - - -#include - +#ifndef TWN_CONFIG_H +#define TWN_CONFIG_H /* * this file is for configuration values which are to be set at @@ -34,10 +30,6 @@ #define TEXT_FONT_TEXTURE_SIZE 1024 #define TEXT_FONT_OVERSAMPLING 4 -#define TEXT_FONT_FILTERING GL_LINEAR - -/* 1024 * 1024 */ -/* #define UMKA_STACK_SIZE 1048576 */ - +#define TEXT_FONT_FILTERING TEXTURE_FILTER_LINEAR #endif diff --git a/include/twn_context.h b/include/twn_context.h new file mode 100644 index 0000000..3dfd17e --- /dev/null +++ b/include/twn_context.h @@ -0,0 +1,38 @@ +#ifndef TWN_CONTEXT_H +#define TWN_CONTEXT_H + +#include "twn_input.h" +#include "twn_engine_api.h" + +#include +#include + + +typedef struct context { + struct input_state input; + + int64_t delta_time; /* preserves real time frame delta with no manipilation */ + uint64_t tick_count; + + /* set just once on startup */ + uint64_t random_seed; + + /* this should be a multiple of TICKS_PER_SECOND */ + /* use it to simulate low framerate (e.g. at 60 tps, set to 2 for 30 fps) */ + /* it can be changed at runtime; any resulting logic anomalies are bugs */ + unsigned int update_multiplicity; + int window_w; + int window_h; + + /* you may read from and write to these from game code */ + void *udata; + + bool debug; + bool is_running; + bool window_size_has_changed; + bool initialization_needed; +} t_ctx; + +TWN_API extern t_ctx ctx; + +#endif diff --git a/townengine/twn_engine_api.h b/include/twn_engine_api.h similarity index 100% rename from townengine/twn_engine_api.h rename to include/twn_engine_api.h diff --git a/townengine/game_api.h b/include/twn_game_api.h similarity index 71% rename from townengine/game_api.h rename to include/twn_game_api.h index 9ba0650..6c2b3d1 100644 --- a/townengine/game_api.h +++ b/include/twn_game_api.h @@ -3,11 +3,11 @@ #define GAME_API_H -#include "townengine/context.h" -#include "townengine/rendering.h" -#include "townengine/audio.h" -#include "townengine/util.h" -#include "townengine/input.h" +#include "twn_context.h" +#include "twn_rendering.h" +#include "twn_audio.h" +#include "twn_util.h" +#include "twn_input.h" #include "twn_engine_api.h" diff --git a/townengine/input.h b/include/twn_input.h similarity index 96% rename from townengine/input.h rename to include/twn_input.h index 226c91a..f0e6cdc 100644 --- a/townengine/input.h +++ b/include/twn_input.h @@ -1,9 +1,9 @@ -#ifndef INPUT_H -#define INPUT_H +#ifndef TWN_INPUT_H +#define TWN_INPUT_H -#include "config.h" -#include "vec.h" -#include "util.h" +#include "twn_config.h" +#include "twn_vec.h" +#include "twn_util.h" #include "twn_engine_api.h" #include diff --git a/townengine/twn_loop.h b/include/twn_loop.h similarity index 100% rename from townengine/twn_loop.h rename to include/twn_loop.h diff --git a/townengine/rendering.h b/include/twn_rendering.h similarity index 80% rename from townengine/rendering.h rename to include/twn_rendering.h index c602ffd..9cf8451 100644 --- a/townengine/rendering.h +++ b/include/twn_rendering.h @@ -1,5 +1,5 @@ -#ifndef RENDERING_H -#define RENDERING_H +#ifndef TWN_RENDERING_H +#define TWN_RENDERING_H #include "util.h" #include "macros/option.h" @@ -35,8 +35,6 @@ TWN_API void push_rectangle(t_frect rect, t_color color); /* pushes a filled circle onto the circle render queue */ TWN_API void push_circle(t_fvec2 position, float radius, t_color color); -TWN_API void text_cache_init(struct text_cache *cache); -TWN_API void text_cache_deinit(struct text_cache *cache); TWN_API void push_text(char *string, t_fvec2 position, int height_px, t_color color, const char *font_path); TWN_API int get_text_width(char *string, int height_px, const char *font_path); @@ -44,13 +42,15 @@ TWN_API int get_text_width(char *string, int height_px, const char *font_path); /* vertices are in absolute coordinates, relative to world origin */ /* texture coordinates are in pixels */ TWN_API void unfurl_triangle(const char *path, - t_fvec3 v0, - t_fvec3 v1, - t_fvec3 v2, - t_shvec2 uv0, - t_shvec2 uv1, - t_shvec2 uv2); + t_fvec3 v0, + t_fvec3 v1, + t_fvec3 v2, + t_shvec2 uv0, + t_shvec2 uv1, + t_shvec2 uv2); +// TODO: decide whether it's needed to begin with? +// intended usage for it is baked lighting, i would think. /* pushes a colored textured 3d triangle onto the render queue */ // void unfurl_colored_triangle(const char *path, // t_fvec3 v0, @@ -66,9 +66,9 @@ TWN_API void unfurl_triangle(const char *path, // TODO: // http://www.lighthouse3d.com/opengl/billboarding/index.php?billCheat2 // void unfurl_billboard(const char *path, -// t_fvec3 position, -// t_fvec2 scaling, -// t_frect uvs); +// t_fvec3 position, +// t_fvec2 scaling, +// t_frect uvs); /* pushes a camera state to be used for all future unfurl_* commands */ TWN_API void set_camera(const t_camera *camera); diff --git a/townengine/util.h b/include/twn_util.h similarity index 99% rename from townengine/util.h rename to include/twn_util.h index bbc9a83..703ee1f 100644 --- a/townengine/util.h +++ b/include/twn_util.h @@ -1,7 +1,7 @@ #ifndef UTIL_H #define UTIL_H -#include "townengine/vec.h" +#include "twn_vec.h" #include "twn_engine_api.h" #include @@ -164,5 +164,4 @@ static inline t_fvec2 fast_cossine(float a) { }; } - #endif diff --git a/townengine/vec.h b/include/twn_vec.h similarity index 99% rename from townengine/vec.h rename to include/twn_vec.h index 3129a76..2cd8645 100644 --- a/townengine/vec.h +++ b/include/twn_vec.h @@ -1,5 +1,5 @@ -#ifndef VEC_H -#define VEC_H +#ifndef TWN_VEC_H +#define TWN_VEC_H #include #include diff --git a/shell_minimal.html b/shell_minimal.html new file mode 100644 index 0000000..871ccaf --- /dev/null +++ b/shell_minimal.html @@ -0,0 +1,143 @@ + + + + + + Emscripten-Generated Code + + + +
+
emscripten
+
Downloading...
+
+ +
+
+ +
+
+
+ Resize canvas + Lock/hide mouse pointer +     + +
+ +
+ +
+ + {{{ SCRIPT }}} + + diff --git a/townengine/game_object/twn_linux_game_object_c.h b/src/game_object/twn_linux_game_object_c.h similarity index 100% rename from townengine/game_object/twn_linux_game_object_c.h rename to src/game_object/twn_linux_game_object_c.h diff --git a/townengine/game_object/twn_static_game_object_c.h b/src/game_object/twn_static_game_object_c.h similarity index 100% rename from townengine/game_object/twn_static_game_object_c.h rename to src/game_object/twn_static_game_object_c.h diff --git a/townengine/game_object/twn_win32_game_object_c.h b/src/game_object/twn_win32_game_object_c.h similarity index 100% rename from townengine/game_object/twn_win32_game_object_c.h rename to src/game_object/twn_win32_game_object_c.h diff --git a/townengine/rendering/circles.h b/src/rendering/twn_circles.c similarity index 67% rename from townengine/rendering/circles.h rename to src/rendering/twn_circles.c index ddbe48f..2cb9bfd 100644 --- a/townengine/rendering/circles.h +++ b/src/rendering/twn_circles.c @@ -1,16 +1,10 @@ -/* a rendering.c mixin */ -#ifndef CIRCLES_H -#define CIRCLES_H - -#include "../util.h" +#include "townengine/util.h" #include "townengine/context.h" -#include "internal_api.h" +#include "twn_rendering_c.h" #include #include -#include - void push_circle(t_fvec2 position, float radius, t_color color) { struct circle_primitive circle = { @@ -29,7 +23,7 @@ void push_circle(t_fvec2 position, float radius, t_color color) { /* TODO: caching and reuse scheme */ /* vertices_out and indices_out MUST BE FREED */ -static void create_circle_geometry(t_fvec2 position, +void create_circle_geometry(t_fvec2 position, t_color color, float radius, size_t num_vertices, @@ -91,42 +85,3 @@ static void create_circle_geometry(t_fvec2 position, *vertices_out = vertices; *indices_out = indices; } - - -static void render_circle(const struct circle_primitive *circle) { - SDL_Vertex *vertices = NULL; - int *indices = NULL; - int num_vertices = (int)circle->radius; - - create_circle_geometry(circle->position, - circle->color, - circle->radius, - num_vertices, - &vertices, - &indices); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, - GL_FLOAT, - sizeof (SDL_Vertex), - &vertices->position); - - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, - GL_UNSIGNED_BYTE, - sizeof (SDL_Vertex), - &vertices->color); - - glDrawElements(GL_TRIANGLES, - num_vertices * 3, - GL_UNSIGNED_INT, - indices); - - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - - free(vertices); - free(indices); -} - -#endif diff --git a/src/rendering/twn_gl_15_gpu_texture.c b/src/rendering/twn_gl_15_gpu_texture.c new file mode 100644 index 0000000..6cf0b90 --- /dev/null +++ b/src/rendering/twn_gl_15_gpu_texture.c @@ -0,0 +1,28 @@ +static gpu_texture new_gl_texture(void) { + GLuint texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); + +#if !defined(EMSCRIPTEN) + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +#endif + + glBindTexture(GL_TEXTURE_2D, 0); + return create_gpu_texture(TEXTURE_FILTER_NEAREST, true); +} + + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA8, + surface->w, + surface->h, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + surface->pixels); diff --git a/src/rendering/twn_gl_15_rendering.c b/src/rendering/twn_gl_15_rendering.c new file mode 100644 index 0000000..b2701ad --- /dev/null +++ b/src/rendering/twn_gl_15_rendering.c @@ -0,0 +1,429 @@ +#include "twn_gl_15_rendering_c.h" +#include "twn_rendering_c.h" +#include "townengine/util.h" +#include "townengine/config.h" +#include "townengine/context.h" +#include "twn_text_c.h" + +#include + + +/* interleaved vertex array data */ +/* TODO: use int16_t for uvs */ +/* TODO: use packed types? */ +/* TODO: int16_t could be used for positioning, but we would need to have more CPU calcs */ +struct element_indexed_quad { + /* upper-left */ + t_fvec2 v0; + t_fvec2 uv0; + t_color c0; + /* bottom-left */ + t_fvec2 v1; + t_fvec2 uv1; + t_color c1; + /* bottom-right */ + t_fvec2 v2; + t_fvec2 uv2; + t_color c2; + /* upper-right */ + t_fvec2 v3; + t_fvec2 uv3; + t_color c3; +}; + + +struct element_indexed_quad_without_color { + /* upper-left */ + t_fvec2 v0; + t_fvec2 uv0; + /* bottom-left */ + t_fvec2 v1; + t_fvec2 uv1; + /* bottom-right */ + t_fvec2 v2; + t_fvec2 uv2; + /* upper-right */ + t_fvec2 v3; + t_fvec2 uv3; +}; + + +typedef enum { + PIPELINE_NO, + PIPELINE_SPACE, + PIPELINE_2D, +} pipeline; + + +static pipeline pipeline_last_used = PIPELINE_NO; + + +void use_space_pipeline(void) { + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glShadeModel(GL_SMOOTH); + + if (GLAD_GL_ARB_depth_clamp) + glDisable(GL_DEPTH_CLAMP); + + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(&camera_projection_matrix.row[0].x); + + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(&camera_look_at_matrix.row[0].x); + + glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glDepthFunc(GL_LESS); + glDepthRange(0, 1); + glDisable(GL_BLEND); + glEnable(GL_ALPHA_TEST); /* TODO: infer its usage? */ + glAlphaFunc(GL_EQUAL, 1.0f); + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + + /* solid white, no modulation */ + glColor4ub(255, 255, 255, 255); + + pipeline_last_used = PIPELINE_SPACE; +} + + +void use_2d_pipeline(void) { + if (pipeline_last_used == PIPELINE_SPACE) { + glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glFlush(); + } + + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + glShadeModel(GL_FLAT); + + /* removes near/far plane comparison and discard */ + if (GLAD_GL_ARB_depth_clamp) + glDisable(GL_DEPTH_CLAMP); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0, -1, 1); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + glDisable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + + pipeline_last_used = PIPELINE_2D; +} + + +void upload_quad_vertices(t_frect rect) { + /* client memory needs to be reachable on glDraw*, so */ + static float vertices[6 * 2]; + + vertices[0] = rect.x; vertices[1] = rect.y; + vertices[2] = rect.x; vertices[3] = rect.y + rect.h; + vertices[4] = rect.x + rect.w; vertices[5] = rect.y + rect.h; + vertices[6] = rect.x + rect.w; vertices[7] = rect.y + rect.h; + vertices[8] = rect.x + rect.w; vertices[9] = rect.y; + vertices[10] = rect.x; vertices[11] = rect.y; + + glVertexPointer(2, GL_FLOAT, 0, (void *)&vertices); +} + + +void render_rectangle(const struct rect_primitive *rectangle) { + glColor4ub(rectangle->color.r, rectangle->color.g, + rectangle->color.b, rectangle->color.a); + + glEnableClientState(GL_VERTEX_ARRAY); + upload_quad_vertices(rectangle->rect); + + glDrawArrays(GL_TRIANGLES, 0, 6); + glDisableClientState(GL_VERTEX_ARRAY); +} + + +void render_circle(const struct circle_primitive *circle) { + SDL_Vertex *vertices = NULL; + int *indices = NULL; + int num_vertices = (int)circle->radius; + + create_circle_geometry(circle->position, + circle->color, + circle->radius, + num_vertices, + &vertices, + &indices); + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(2, + GL_FLOAT, + sizeof (SDL_Vertex), + &vertices->position); + + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(4, + GL_UNSIGNED_BYTE, + sizeof (SDL_Vertex), + &vertices->color); + + glDrawElements(GL_TRIANGLES, + num_vertices * 3, + GL_UNSIGNED_INT, + indices); + + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + + free(vertices); + free(indices); +} + + +void use_texture_mode(enum texture_mode mode) { + if (mode == TEXTURE_MODE_GHOSTLY) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_FALSE); + glDisable(GL_ALPHA_TEST); + } else if (mode == TEXTURE_MODE_SEETHROUGH) { + glDisable(GL_BLEND); + glDepthFunc(GL_LEQUAL); + glDepthMask(GL_TRUE); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_EQUAL, 1.0f); + } else { + glDisable(GL_BLEND); + glDepthFunc(GL_LESS); + glDepthMask(GL_TRUE); + glDisable(GL_ALPHA_TEST); + } +} + + +vertex_buffer_builder build_vertex_buffer(vertex_buffer buffer, size_t bytes) { + glBindBuffer(GL_ARRAY_BUFFER, buffer); + void *mapping = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + if (!mapping) + CRY("build_vertex_buffer", "Error mapping a vertex array buffer"); + + return (vertex_buffer_builder) { + .mapping = mapping, + .bytes_left = bytes, + }; +} + + +bool push_to_vertex_buffer_builder(vertex_buffer_builder *builder, + void *bytes, size_t size) { + if (builder->bytes_left == 0) + return false; + + memcpy(builder->mapping, bytes, size); + builder->bytes_left -= size; + + /* trigger data send */ + if (builder->bytes_left == 0) { + glUnmapBuffer(GL_ARRAY_BUFFER); + return false; + } + + return true; +} + + +void finally_render_sprites(const struct primitive_2d primitives[], + const struct sprite_batch batch, + const vertex_buffer vertex_buffer) +{ + /* TODO: maybe do, dunno */ + // glBindBuffer(GL_VERTEX_ARRAY, vertex_buffer); + (void)vertex_buffer; + + GLsizei off; + GLsizei voff; + GLsizei uvoff; + + if (!batch.constant_colored) { + off = offsetof(struct element_indexed_quad, v1); + voff = offsetof(struct element_indexed_quad, v0); + uvoff = offsetof(struct element_indexed_quad, uv0); + } else { + off = offsetof(struct element_indexed_quad_without_color, v1); + voff = offsetof(struct element_indexed_quad_without_color, v0); + uvoff = offsetof(struct element_indexed_quad_without_color, uv0); + } + + /* vertex specification */ + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(2, + GL_FLOAT, + off, + (void *)(size_t)voff); + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + glTexCoordPointer(2, + GL_FLOAT, + off, + (void *)(size_t)uvoff); + + if (!batch.constant_colored) { + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(4, + GL_UNSIGNED_BYTE, + off, + (void *)offsetof(struct element_indexed_quad, c0)); + } else + glColor4ub(primitives[0].sprite.color.r, + primitives[0].sprite.color.g, + primitives[0].sprite.color.b, + primitives[0].sprite.color.a); + + if (!batch.repeat) + textures_bind(&ctx.texture_cache, primitives->sprite.texture_key); + else + textures_bind_repeating(&ctx.texture_cache, primitives->sprite.texture_key); + + bind_quad_element_buffer(); + + glDrawElements(GL_TRIANGLES, 6 * (GLsizei)batch.size, GL_UNSIGNED_SHORT, NULL); + + /* clear the state */ + glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + glBindTexture(GL_TEXTURE_2D, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + + +size_t get_sprite_payload_size(struct sprite_batch batch) { + if (batch.constant_colored) + return sizeof (struct element_indexed_quad_without_color); + else + return sizeof (struct element_indexed_quad); +} + + +bool push_sprite_payload_to_vertex_buffer_builder(struct sprite_batch batch, + vertex_buffer_builder *builder, + t_fvec2 v0, t_fvec2 v1, t_fvec2 v2, t_fvec2 v3, + t_fvec2 uv0, t_fvec2 uv1, t_fvec2 uv2, t_fvec2 uv3, + t_color color) +{ + if (!batch.constant_colored) { + struct element_indexed_quad buffer_element = { + .v0 = v0, + .v1 = v1, + .v2 = v2, + .v3 = v3, + + .uv0 = uv0, + .uv1 = uv1, + .uv2 = uv2, + .uv3 = uv3, + + /* equal for all (flat shaded) */ + .c0 = color, + .c1 = color, + .c2 = color, + .c3 = color, + }; + + return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element); + + } else { + struct element_indexed_quad_without_color buffer_element = { + .v0 = v0, + .v1 = v1, + .v2 = v2, + .v3 = v3, + + .uv0 = uv0, + .uv1 = uv1, + .uv2 = uv2, + .uv3 = uv3, + }; + + return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element); + } +} + + +void finally_draw_uncolored_space_traingle_batch(const struct mesh_batch *batch, + const t_texture_key texture_key, + const vertex_buffer vertex_buffer) +{ + const size_t primitives_len = arrlenu(batch->primitives); + + textures_bind(&ctx.texture_cache, texture_key); + + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); + + /* vertex specification*/ + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, + GL_FLOAT, + offsetof(struct uncolored_space_triangle_payload, v1), + (void *)offsetof(struct uncolored_space_triangle_payload, v0)); + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + glTexCoordPointer(2, + GL_FLOAT, + offsetof(struct uncolored_space_triangle_payload, v1), + (void *)offsetof(struct uncolored_space_triangle_payload, uv0)); + + /* commit for drawing */ + glDrawArrays(GL_TRIANGLES, 0, 3 * (GLint)primitives_len); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + + /* invalidate the buffer immediately */ + glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + + +bool push_text_payload_to_vertex_buffer_builder(struct font_data const *font_data, + vertex_buffer_builder *builder, + stbtt_aligned_quad quad) +{ + (void)font_data; + + glTexCoord2f(quad.s0, quad.t0); + glVertex2f(quad.x0, quad.y0); + glTexCoord2f(quad.s1, quad.t0); + glVertex2f(quad.x1, quad.y0); + glTexCoord2f(quad.s1, quad.t1); + glVertex2f(quad.x1, quad.y1); + glTexCoord2f(quad.s0, quad.t1); + glVertex2f(quad.x0, quad.y1); +} + + +void finally_draw_text(struct font_data const *font_data, + size_t len, + t_color color, + vertex_buffer buffer) +{ + use_texture_mode(TEXTURE_MODE_GHOSTLY); + + glBindTexture(GL_TEXTURE_2D, font_data->texture); + + glColor4ub(color.r, color.g, color.b, color.a); +} + + +size_t get_text_payload_size(void) { + return sizeof (struct element_indexed_quad_without_color); +} diff --git a/src/rendering/twn_gl_15_rendering_c.h b/src/rendering/twn_gl_15_rendering_c.h new file mode 100644 index 0000000..893a3ff --- /dev/null +++ b/src/rendering/twn_gl_15_rendering_c.h @@ -0,0 +1,65 @@ +#ifndef TWN_GL_15_RENDERING_H +#define TWN_GL_15_RENDERING_H + +/* + * OpenGL 1.5 and any 2.0+ compatibility version render implementation. + */ + +#include "twn_rendering_c.h" +#include "twn_gl_any_rendering_c.h" + +#ifdef EMSCRIPTEN +#include +#else +#include +#endif + +#include + + +void render_circle(const struct circle_primitive *circle); + +void render_rectangle(const struct rect_primitive *rectangle); + +void use_space_pipeline(void); + +void use_2d_pipeline(void); + +void use_texture_mode(enum texture_mode mode); + +/* uses present in 1.5 buffer mapping feature */ +vertex_buffer_builder build_vertex_buffer(vertex_buffer buffer, size_t bytes); + +/* collects bytes for sending to the gpu until all is pushed, which is when false is returned */ +bool push_to_vertex_buffer_builder(vertex_buffer_builder *builder, + void *bytes, + size_t size); + +void finally_render_sprites(struct primitive_2d const primitives[], + struct sprite_batch batch, + vertex_buffer buffer); + +size_t get_sprite_payload_size(struct sprite_batch batch); + +bool push_sprite_payload_to_vertex_buffer_builder(struct sprite_batch batch, + vertex_buffer_builder *builder, + t_fvec2 v0, t_fvec2 v1, t_fvec2 v2, t_fvec2 v3, + t_fvec2 uv0, t_fvec2 uv1, t_fvec2 uv2, t_fvec2 uv3, + t_color color); + +void finally_draw_uncolored_space_traingle_batch(struct mesh_batch const *batch, + t_texture_key texture_key, + vertex_buffer buffer); + +size_t get_text_payload_size(void); + +bool push_text_payload_to_vertex_buffer_builder(struct font_data const *font_data, + vertex_buffer_builder *builder, + stbtt_aligned_quad quad); + +void finally_draw_text(struct font_data const *font_data, + size_t len, + t_color color, + vertex_buffer buffer); + +#endif diff --git a/townengine/rendering/quad_element_buffer.h b/src/rendering/twn_gl_any_rendering.c similarity index 51% rename from townengine/rendering/quad_element_buffer.h rename to src/rendering/twn_gl_any_rendering.c index 617e094..c352de0 100644 --- a/townengine/rendering/quad_element_buffer.h +++ b/src/rendering/twn_gl_any_rendering.c @@ -1,16 +1,41 @@ -/* a rendering.c mixin */ -#ifndef QUAD_ELEMENT_BUFFER_H -#define QUAD_ELEMENT_BUFFER_H - +#include "twn_gl_any_rendering_c.h" +#include "townengine/context.h" #include "townengine/util.h" +#ifdef EMSCRIPTEN +#include +#else #include +#endif -#include -#define QUAD_ELEMENT_BUFFER_LENGTH (65536 / 6) +void setup_viewport(int x, int y, int width, int height) { + glViewport(x, y, width, height); +} -static void bind_quad_element_buffer(void) { +//////// VERTEX BUFFER //////// + +vertex_buffer create_vertex_buffer(void) { + GLuint result; + glGenBuffers(1, &result); + return result; +} + + +void delete_vertex_buffer(vertex_buffer buffer) { + glDeleteBuffers(1, &buffer); +} + + +void specify_vertex_buffer(vertex_buffer buffer, void *data, size_t bytes) { + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, bytes, data, GL_STREAM_DRAW); +} + +//////// END OF VERTEX BUFFER //////// + + +void bind_quad_element_buffer(void) { static GLuint buffer = 0; /* it's only generated once at runtime */ @@ -42,4 +67,23 @@ static void bind_quad_element_buffer(void) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer); } -#endif + +void clear_draw_buffer(void) { + glClearColor((1.0f / 255) * 230, + (1.0f / 255) * 230, + (1.0f / 255) * 230, 1); + + glClear(GL_COLOR_BUFFER_BIT | + GL_DEPTH_BUFFER_BIT | + GL_STENCIL_BUFFER_BIT); +} + + +void swap_buffers(void) { + SDL_GL_SwapWindow(ctx.window); +} + + +void set_depth_range(double low, double high) { + glDepthRange(low, high); +} diff --git a/src/rendering/twn_gl_any_rendering_c.h b/src/rendering/twn_gl_any_rendering_c.h new file mode 100644 index 0000000..a1954aa --- /dev/null +++ b/src/rendering/twn_gl_any_rendering_c.h @@ -0,0 +1,43 @@ +#ifndef TWN_GL_ANY_RENDERING_H +#define TWN_GL_ANY_RENDERING_H + +/* + * Any OpenGL version base render methods. + */ + +#ifdef EMSCRIPTEN +#include +#else +#include +#endif + +#include + + +#define QUAD_ELEMENT_BUFFER_LENGTH (65536 / 6) + +typedef GLuint vertex_buffer; + +typedef struct vertex_buffer_builder { + size_t bytes_left; + void *mapping; +} vertex_buffer_builder; + + +vertex_buffer create_vertex_buffer(void); + +void delete_vertex_buffer(vertex_buffer buffer); + +void specify_vertex_buffer(vertex_buffer buffer, void *data, size_t bytes); + +void setup_viewport(int x, int y, int width, int height); + +void bind_quad_element_buffer(void); + +void clear_draw_buffer(void); + +void swap_buffers(void); + +void set_depth_range(double low, double high); + +#endif diff --git a/src/rendering/twn_gpu_texture.h b/src/rendering/twn_gpu_texture.h new file mode 100644 index 0000000..6be52c2 --- /dev/null +++ b/src/rendering/twn_gpu_texture.h @@ -0,0 +1,29 @@ +#ifndef TWN_GPU_TEXTURE_H +#define TWN_GPU_TEXTURE_H + +#ifdef EMSCRIPTEN +#include +#else +#include +#endif + +#include + + +typedef GLuint gpu_texture; + +enum texture_filter { + TEXTURE_FILTER_NEAREAST, + TEXTURE_FILTER_LINEAR, +}; + + +gpu_texture create_gpu_texture(enum texture_filter filter, bool generate_mipmaps); + +void delete_gpu_texture(gpu_texture texture); + +void specify_gpu_texture(gpu_texture texture, void *pixels, int channels, int width, int height); + +void bind_gpu_texture(gpu_texture texture); + +#endif diff --git a/townengine/rendering.c b/src/rendering/twn_rendering.c similarity index 51% rename from townengine/rendering.c rename to src/rendering/twn_rendering.c index f163c36..01e9753 100644 --- a/townengine/rendering.c +++ b/src/rendering/twn_rendering.c @@ -1,22 +1,27 @@ -#include "rendering/internal_api.h" -#include "rendering/sprites.h" -#include "rendering/triangles.h" -#include "rendering/circles.h" -#include "rendering/text.h" -#include "textures/internal_api.h" +#include "twn_rendering_c.h" +#include "townengine/twn_rendering.h" +#include "townengine/textures/internal_api.h" #include "townengine/context.h" +#include "townengine/camera.h" + +#include "twn_rendering_platform.h" #include -#include #include +#ifdef EMSCRIPTEN +#include +#else +#include +#endif + #include #include /* TODO: have a default initialized one */ -static t_matrix4 camera_projection_matrix; -static t_matrix4 camera_look_at_matrix; +t_matrix4 camera_projection_matrix; +t_matrix4 camera_look_at_matrix; void render_queue_clear(void) { @@ -54,38 +59,8 @@ void push_rectangle(t_frect rect, t_color color) { } -static void upload_quad_vertices(t_frect rect) { - /* client memory needs to be reachable on glDraw*, so */ - static float vertices[6 * 2]; - - vertices[0] = rect.x; vertices[1] = rect.y; - vertices[2] = rect.x; vertices[3] = rect.y + rect.h; - vertices[4] = rect.x + rect.w; vertices[5] = rect.y + rect.h; - vertices[6] = rect.x + rect.w; vertices[7] = rect.y + rect.h; - vertices[8] = rect.x + rect.w; vertices[9] = rect.y; - vertices[10] = rect.x; vertices[11] = rect.y; - - glVertexPointer(2, GL_FLOAT, 0, (void *)&vertices); -} - - -static void render_rectangle(const struct rect_primitive *rectangle) { - glColor4ub(rectangle->color.r, rectangle->color.g, - rectangle->color.b, rectangle->color.a); - - glEnableClientState(GL_VERTEX_ARRAY); - upload_quad_vertices(rectangle->rect); - - glDrawArrays(GL_TRIANGLES, 0, 6); - glDisableClientState(GL_VERTEX_ARRAY); -} - - static void render_2d(void) { - glEnable(GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); - glDisable(GL_CULL_FACE); - glEnable(GL_DEPTH_TEST); + use_2d_pipeline(); const size_t render_queue_len = arrlenu(ctx.render_queue_2d); @@ -99,8 +74,8 @@ static void render_2d(void) { const struct sprite_batch batch = collect_sprite_batch(current, render_queue_len - i); - glDepthRange((double)batch_count / UINT16_MAX, 1.0); - + /* TODO: what's even the point? just use OR_EQUAL comparison */ + set_depth_range((double)batch_count / UINT16_MAX, 1.0); render_sprites(current, batch); i += batch.size - 1; ++batch_count; @@ -121,19 +96,12 @@ static void render_2d(void) { static void render_space(void) { - glEnable(GL_CULL_FACE); - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); - glDepthFunc(GL_LESS); - glDepthRange(0, 1); - glDisable(GL_BLEND); - glEnable(GL_ALPHA_TEST); /* TODO: infer its usage */ - glAlphaFunc(GL_EQUAL, 1.0f); - glEnable(GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); + /* nothing to do, abort */ + /* as space pipeline isn't used we can have fewer changes and initialization costs */ + if (hmlenu(ctx.uncolored_mesh_batches) == 0) + return; - /* solid white, no modulation */ - glColor4ub(255, 255, 255, 255); + use_space_pipeline(); for (size_t i = 0; i < hmlenu(ctx.uncolored_mesh_batches); ++i) { draw_uncolored_space_traingle_batch(&ctx.uncolored_mesh_batches[i].value, @@ -150,7 +118,7 @@ void render(void) { if ((float)ctx.window_w / (float)ctx.window_h > RENDER_BASE_RATIO) { float ratio = (float)ctx.window_h / (float)RENDER_BASE_HEIGHT; int w = (int)((float)RENDER_BASE_WIDTH * ratio); - glViewport( + setup_viewport( ctx.window_w / 2 - w / 2, 0, w, @@ -159,7 +127,7 @@ void render(void) { } else { float ratio = (float)ctx.window_w / (float)RENDER_BASE_WIDTH; int h = (int)((float)RENDER_BASE_HEIGHT * ratio); - glViewport( + setup_viewport( 0, ctx.window_h / 2 - h / 2, ctx.window_w, @@ -168,57 +136,15 @@ void render(void) { } } - glClearColor((1.0f / 255) * 230, - (1.0f / 255) * 230, - (1.0f / 255) * 230, 1); - - glClear(GL_COLOR_BUFFER_BIT | - GL_DEPTH_BUFFER_BIT | - GL_STENCIL_BUFFER_BIT); - - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - glShadeModel(GL_SMOOTH); - - if (GLAD_GL_ARB_depth_clamp) - glDisable(GL_DEPTH_CLAMP); - - { - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(&camera_projection_matrix.row[0].x); - - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(&camera_look_at_matrix.row[0].x); - - render_space(); - } - - /* TODO: only do it when transition between spaces is needed */ - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - glFlush(); - - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); - glShadeModel(GL_FLAT); - - /* removes near/far plane comparison and discard */ - if (GLAD_GL_ARB_depth_clamp) - glDisable(GL_DEPTH_CLAMP); - - { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0, -1, 1); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - render_2d(); - } - - SDL_GL_SwapWindow(ctx.window); + clear_draw_buffer(); + render_space(); + render_2d(); + swap_buffers(); } + void set_camera(const t_camera *const camera) { /* TODO: skip recaulculating if it's the same? */ camera_projection_matrix = camera_perspective(camera); - camera_look_at_matrix = camera_look_at(camera); + camera_look_at_matrix = camera_look_at(camera); } diff --git a/townengine/rendering/internal_api.h b/src/rendering/twn_rendering_c.h similarity index 60% rename from townengine/rendering/internal_api.h rename to src/rendering/twn_rendering_c.h index f3afd13..166b606 100644 --- a/townengine/rendering/internal_api.h +++ b/src/rendering/twn_rendering_c.h @@ -6,10 +6,12 @@ #include "townengine/macros/option.h" #include -#include #include +extern t_matrix4 camera_projection_matrix; +extern t_matrix4 camera_look_at_matrix; + struct sprite_primitive { t_frect rect; t_color color; @@ -86,7 +88,6 @@ union uncolored_space_triangle { /* batch of primitives with overlapping properties */ struct mesh_batch { - GLuint buffer; /* server side storage */ uint8_t *primitives; }; @@ -105,4 +106,40 @@ void render(void); /* clears all render queues */ void render_queue_clear(void); +void push_circle(t_fvec2 position, float radius, t_color color); + +void unfurl_triangle(const char *path, + t_fvec3 v0, + t_fvec3 v1, + t_fvec3 v2, + t_shvec2 uv0, + t_shvec2 uv1, + t_shvec2 uv2); + +void create_circle_geometry(t_fvec2 position, + t_color color, + float radius, + size_t num_vertices, + SDL_Vertex **vertices_out, + int **indices_out); + +struct sprite_batch { + size_t size; /* how many primitives are in current batch */ + enum texture_mode mode; + bool constant_colored; /* whether colored batch is uniformly colored */ + bool repeat; /* whether repeat is needed */ +} collect_sprite_batch(const struct primitive_2d primitives[], size_t len); + +void render_sprites(const struct primitive_2d primitives[], + const struct sprite_batch batch); + +void draw_uncolored_space_traingle_batch(struct mesh_batch *batch, + t_texture_key texture_key); + +void render_text(const struct text_primitive *text); + +void text_cache_init(struct text_cache *cache); + +void text_cache_deinit(struct text_cache *cache); + #endif diff --git a/src/rendering/twn_rendering_platform.h b/src/rendering/twn_rendering_platform.h new file mode 100644 index 0000000..5d8769e --- /dev/null +++ b/src/rendering/twn_rendering_platform.h @@ -0,0 +1,10 @@ +#ifndef TWN_RENDERING_PLATFORM_H +#define TWN_RENDERING_PLATFORM_H + +#ifdef EMSCRIPTEN +#include "twn_gl_es2_rendering_c.h" +#else +#include "twn_gl_15_rendering_c.h" +#endif + +#endif diff --git a/townengine/rendering/sprites.h b/src/rendering/twn_sprites.c similarity index 55% rename from townengine/rendering/sprites.h rename to src/rendering/twn_sprites.c index 5569200..65de357 100644 --- a/townengine/rendering/sprites.h +++ b/src/rendering/twn_sprites.c @@ -1,58 +1,15 @@ -/* a rendering.c mixin */ -#ifndef SPRITES_H -#define SPRITES_H - -#include "../rendering.h" +#include "townengine/twn_rendering.h" +#include "twn_rendering_c.h" #include "townengine/context.h" -#include "../util.h" -#include "../textures/internal_api.h" -#include "quad_element_buffer.h" -#include "internal_api.h" +#include "townengine/util.h" +#include "townengine/textures/internal_api.h" +#include "twn_rendering_platform.h" #include #include #include -/* interleaved vertex array data */ -/* TODO: use int16_t for uvs */ -/* TODO: use packed types? */ -/* TODO: int16_t could be used for positioning, but we would need to have more CPU calcs */ -struct sprite_primitive_payload { - /* upper-left */ - t_fvec2 v0; - t_fvec2 uv0; - t_color c0; - /* bottom-left */ - t_fvec2 v1; - t_fvec2 uv1; - t_color c1; - /* bottom-right */ - t_fvec2 v2; - t_fvec2 uv2; - t_color c2; - /* upper-right */ - t_fvec2 v3; - t_fvec2 uv3; - t_color c3; -}; - - -struct sprite_primitive_payload_without_color { - /* upper-left */ - t_fvec2 v0; - t_fvec2 uv0; - /* bottom-left */ - t_fvec2 v1; - t_fvec2 uv1; - /* bottom-right */ - t_fvec2 v2; - t_fvec2 uv2; - /* upper-right */ - t_fvec2 v3; - t_fvec2 uv3; -}; - /* * an implementation note: * try to avoid doing expensive work in the push functions, @@ -82,12 +39,7 @@ void push_sprite(const t_push_sprite_args args) { } -static struct sprite_batch { - size_t size; /* how many primitives are in current batch */ - enum texture_mode mode; - bool constant_colored; /* whether colored batch is uniformly colored */ - bool repeat; /* whether repeat is needed */ -} collect_sprite_batch(const struct primitive_2d *primitives, size_t len) { +struct sprite_batch collect_sprite_batch(const struct primitive_2d primitives[], size_t len) { /* assumes that first primitive is already a sprite */ const uint16_t texture_key_id = primitives[0].sprite.texture_key.id; const int atlas_id = textures_get_atlas_id(&ctx.texture_cache, primitives[0].sprite.texture_key); @@ -143,52 +95,22 @@ static struct sprite_batch { /* assumes that orthogonal matrix setup is done already */ -static void render_sprites(const struct primitive_2d primitives[], +void render_sprites(const struct primitive_2d primitives[], const struct sprite_batch batch) { /* single vertex array is used for every batch with NULL glBufferData() trick at the end */ - static GLuint vertex_array = 0; + static vertex_buffer vertex_array = 0; if (vertex_array == 0) - glGenBuffers(1, &vertex_array); + vertex_array = create_vertex_buffer(); - if (batch.mode == TEXTURE_MODE_GHOSTLY) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDepthFunc(GL_ALWAYS); - glDepthMask(GL_FALSE); - glDisable(GL_ALPHA_TEST); - } else if (batch.mode == TEXTURE_MODE_SEETHROUGH) { - glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); - glDepthMask(GL_TRUE); - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_EQUAL, 1.0f); - } else { - glDisable(GL_BLEND); - glDepthFunc(GL_LESS); - glDepthMask(GL_TRUE); - glDisable(GL_ALPHA_TEST); - } - - size_t payload_size; - if (!batch.constant_colored) - payload_size = sizeof (struct sprite_primitive_payload); - else - payload_size = sizeof (struct sprite_primitive_payload_without_color); - - glBindBuffer(GL_ARRAY_BUFFER, vertex_array); - glBufferData(GL_ARRAY_BUFFER, - payload_size * batch.size, - NULL, - GL_STREAM_DRAW); + use_sprite_blendmode(batch.mode); const t_frect dims = textures_get_dims(&ctx.texture_cache, primitives->sprite.texture_key); - /* vertex population over a mapped buffer */ + /* vertex population over a vertex buffer builder interface */ { - /* TODO: check errors, ensure alignment ? */ - void *const payload = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + vertex_buffer_builder payload = build_vertex_buffer(vertex_array, get_sprite_payload_size(batch) * batch.size); for (size_t i = 0; i < batch.size; ++i) { /* render opaques front to back */ @@ -275,100 +197,9 @@ static void render_sprites(const struct primitive_2d primitives[], v3 = (t_fvec2){ c.x + t.x * +h.x - t.y * -h.y, c.y + t.y * +h.x + t.x * -h.y }; } - if (!batch.constant_colored) - ((struct sprite_primitive_payload *)payload)[i] = (struct sprite_primitive_payload) { - .v0 = v0, - .v1 = v1, - .v2 = v2, - .v3 = v3, - - .uv0 = uv0, - .uv1 = uv1, - .uv2 = uv2, - .uv3 = uv3, - - /* equal for all (flat shaded) */ - .c0 = sprite.color, - .c1 = sprite.color, - .c2 = sprite.color, - .c3 = sprite.color, - }; - else - ((struct sprite_primitive_payload_without_color *)payload)[i] = (struct sprite_primitive_payload_without_color) { - .v0 = v0, - .v1 = v1, - .v2 = v2, - .v3 = v3, - - .uv0 = uv0, - .uv1 = uv1, - .uv2 = uv2, - .uv3 = uv3, - }; + push_sprite_payload_to_vertex_buffer_builder(batch, &payload, v0, v1, v2, v3, uv0, uv1, uv2, uv3, sprite.color); } - - glUnmapBuffer(GL_ARRAY_BUFFER); } - GLsizei off; - GLsizei voff; - GLsizei uvoff; - - if (!batch.constant_colored) { - off = offsetof(struct sprite_primitive_payload, v1); - voff = offsetof(struct sprite_primitive_payload, v0); - uvoff = offsetof(struct sprite_primitive_payload, uv0); - } else { - off = offsetof(struct sprite_primitive_payload_without_color, v1); - voff = offsetof(struct sprite_primitive_payload_without_color, v0); - uvoff = offsetof(struct sprite_primitive_payload_without_color, uv0); - } - - /* vertex specification */ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, - GL_FLOAT, - off, - (void *)(size_t)voff); - - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTexture(GL_TEXTURE0); - glTexCoordPointer(2, - GL_FLOAT, - off, - (void *)(size_t)uvoff); - - if (!batch.constant_colored) { - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, - GL_UNSIGNED_BYTE, - off, - (void *)offsetof(struct sprite_primitive_payload, c0)); - } else - glColor4ub(primitives[0].sprite.color.r, - primitives[0].sprite.color.g, - primitives[0].sprite.color.b, - primitives[0].sprite.color.a); - - if (!batch.repeat) - textures_bind(&ctx.texture_cache, primitives->sprite.texture_key, GL_TEXTURE_2D); - else - textures_bind_repeating(&ctx.texture_cache, primitives->sprite.texture_key, GL_TEXTURE_2D); - - bind_quad_element_buffer(); - - glDrawElements(GL_TRIANGLES, 6 * (GLsizei)batch.size, GL_UNSIGNED_SHORT, NULL); - - /* clear the state */ - glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - glBindTexture(GL_TEXTURE_2D, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + finally_render_sprites(primitives, batch, vertex_array); } - -#endif diff --git a/townengine/rendering/text.h b/src/rendering/twn_text.c similarity index 79% rename from townengine/rendering/text.h rename to src/rendering/twn_text.c index 2f6d962..9326f68 100644 --- a/townengine/rendering/text.h +++ b/src/rendering/twn_text.c @@ -1,13 +1,11 @@ -/* a rendering.c mixin */ -#ifndef TEXT_H -#define TEXT_H - - -#include "../util.h" +#include "twn_rendering_c.h" +#include "townengine/util.h" #include "townengine/config.h" #include "townengine/context.h" +#include "townengine/twn_rendering.h" + +#include "twn_rendering_platform.h" -#include #include @@ -24,7 +22,7 @@ struct font_data { unsigned char *file_bytes; size_t file_bytes_len; - GLuint texture; + gpu_texture texture; int height_px; float scale_factor; @@ -67,24 +65,15 @@ static struct font_data *text_load_font_data(const char *path, int height_px) { stbtt_PackEnd(&pctx); } - glGenTextures(1, &font_data->texture); - glBindTexture(GL_TEXTURE_2D, font_data->texture); - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_ALPHA, + font_data->texture = create_gpu_texture(TEXT_FONT_FILTERING, true); + specify_gpu_texture( + font_data->texture, + bitmap, + 1, TEXT_FONT_TEXTURE_SIZE, - TEXT_FONT_TEXTURE_SIZE, - 0, - GL_ALPHA, - GL_UNSIGNED_BYTE, - bitmap + TEXT_FONT_TEXTURE_SIZE ); free(bitmap); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TEXT_FONT_FILTERING); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TEXT_FONT_FILTERING); - glBindTexture(GL_TEXTURE_2D, 0); - return font_data; } @@ -92,25 +81,22 @@ static struct font_data *text_load_font_data(const char *path, int height_px) { static void text_destroy_font_data(struct font_data *font_data) { free(font_data->file_bytes); - glDeleteTextures(1, &font_data->texture); + delete_gpu_texture(font_data->texture); free(font_data); } static void text_draw_with(struct font_data* font_data, char* text, t_fvec2 position, t_color color) { - glBindTexture(GL_TEXTURE_2D, font_data->texture); + static vertex_buffer vertex_array = 0; + if (vertex_array == 0) + vertex_array = create_vertex_buffer(); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDepthFunc(GL_ALWAYS); - glDepthMask(GL_FALSE); - glDisable(GL_ALPHA_TEST); + const size_t len = SDL_strlen(text); - glColor4ub(color.r, color.g, color.b, color.a); + vertex_buffer_builder payload = build_vertex_buffer(vertex_array, get_text_payload_size() * len); - glBegin(GL_QUADS); - for (const char *p = text; *p != '\0'; ++p) { - const char c = *p; + for (size_t i = 0; i < len; ++i) { + const char c = text[i]; /* outside the range of what we want to display */ //if (c < ASCII_START || c > ASCII_END) @@ -136,20 +122,10 @@ static void text_draw_with(struct font_data* font_data, char* text, t_fvec2 posi quad.y0 += (float)font_data->ascent; quad.y1 += (float)font_data->ascent; - /* TODO: you know... */ - glTexCoord2f(quad.s0, quad.t0); - glVertex2f(quad.x0, quad.y0); - glTexCoord2f(quad.s1, quad.t0); - glVertex2f(quad.x1, quad.y0); - glTexCoord2f(quad.s1, quad.t1); - glVertex2f(quad.x1, quad.y1); - glTexCoord2f(quad.s0, quad.t1); - glVertex2f(quad.x0, quad.y1); + push_text_payload_to_vertex_buffer_builder(font_data, &payload, quad); } - glEnd(); - glColor4ub(255, 255, 255, 255); - glBindTexture(GL_TEXTURE_2D, 0); + finally_draw_text(font_data, len, color, vertex_array); } @@ -182,7 +158,7 @@ static struct font_data *get_font_data(const char *font_path, int height_px) { } -static void render_text(const struct text_primitive *text) { +void render_text(const struct text_primitive *text) { struct font_data *font_data = get_font_data(text->font, text->height_px); text_draw_with(font_data, text->text, text->position, text->color); } @@ -243,6 +219,3 @@ int get_text_width(char *string, int height_px, const char *font_path) { return (int)((float)length * font_data->scale_factor); } - - -#endif diff --git a/src/rendering/twn_text_c.h b/src/rendering/twn_text_c.h new file mode 100644 index 0000000..b828fcf --- /dev/null +++ b/src/rendering/twn_text_c.h @@ -0,0 +1,26 @@ +#include "twn_rendering_platform.h" + +#include + + +#define ASCII_START 32 +#define ASCII_END 128 +#define NUM_DISPLAY_ASCII ((ASCII_END - ASCII_START) + 1) + + +struct font_data { + stbtt_packedchar char_data[NUM_DISPLAY_ASCII]; + stbtt_fontinfo info; + + const char *file_path; + unsigned char *file_bytes; + size_t file_bytes_len; + + gpu_texture texture; + + int height_px; + float scale_factor; + int ascent; + int descent; + int line_gap; +}; diff --git a/src/rendering/twn_triangles.c b/src/rendering/twn_triangles.c new file mode 100644 index 0000000..3efa630 --- /dev/null +++ b/src/rendering/twn_triangles.c @@ -0,0 +1,81 @@ +#include "twn_rendering_c.h" +#include "twn_context.h" +#include "twn_textures_c.h" +#include "twn_rendering_platform.h" + +#include + + +/* TODO: automatic handling of repeating textures */ +/* for that we could allocate a loner texture */ +void unfurl_triangle(const char *path, + t_fvec3 v0, + t_fvec3 v1, + t_fvec3 v2, + t_shvec2 uv0, + t_shvec2 uv1, + t_shvec2 uv2) +{ + const t_texture_key texture_key = textures_get_key(&ctx.texture_cache, path); + + struct mesh_batch_item *batch_p = hmgetp_null(ctx.uncolored_mesh_batches, texture_key); + if (!batch_p) { + struct mesh_batch item = {0}; + hmput(ctx.uncolored_mesh_batches, texture_key, item); + batch_p = &ctx.uncolored_mesh_batches[hmlenu(ctx.uncolored_mesh_batches) - 1]; /* TODO: can last index be used? */ + } + + union uncolored_space_triangle triangle = { .primitive = { + .v0 = v0, + .v1 = v1, + .v2 = v2, + .uv1 = m_to_fvec2(uv1), + .uv0 = m_to_fvec2(uv0), + .uv2 = m_to_fvec2(uv2), + }}; + + union uncolored_space_triangle *triangles = (union uncolored_space_triangle *)batch_p->value.primitives; + + arrpush(triangles, triangle); + batch_p->value.primitives = (uint8_t *)triangles; +} + + +void draw_uncolored_space_traingle_batch(struct mesh_batch *batch, + t_texture_key texture_key) +{ + static vertex_buffer vertex_array = 0; + if (vertex_array == 0) + vertex_array = create_vertex_buffer(); + + const size_t primitives_len = arrlenu(batch->primitives); + + /* nothing to do */ + if (primitives_len == 0) + return; + + const t_frect srcrect = textures_get_srcrect(&ctx.texture_cache, texture_key); + const t_frect dims = textures_get_dims(&ctx.texture_cache, texture_key); + + const float wr = srcrect.w / dims.w; + const float hr = srcrect.h / dims.h; + const float xr = srcrect.x / dims.w; + const float yr = srcrect.y / dims.h; + + /* update pixel-based uvs to correspond with texture atlases */ + for (size_t i = 0; i < primitives_len; ++i) { + struct uncolored_space_triangle_payload *payload = + &((union uncolored_space_triangle *)batch->primitives)[i].payload; + + payload->uv0.x = xr + ((float)payload->uv0.x / srcrect.w) * wr; + payload->uv0.y = yr + ((float)payload->uv0.y / srcrect.h) * hr; + payload->uv1.x = xr + ((float)payload->uv1.x / srcrect.w) * wr; + payload->uv1.y = yr + ((float)payload->uv1.y / srcrect.h) * hr; + payload->uv2.x = xr + ((float)payload->uv2.x / srcrect.w) * wr; + payload->uv2.y = yr + ((float)payload->uv2.y / srcrect.h) * hr; + } + + specify_vertex_buffer(vertex_array, batch->primitives, primitives_len * sizeof (struct uncolored_space_triangle_payload)); + + finally_draw_uncolored_space_traingle_batch(batch, texture_key, vertex_array); +} diff --git a/townengine/system/linux/elf.c b/src/system/linux/twn_elf.c similarity index 100% rename from townengine/system/linux/elf.c rename to src/system/linux/twn_elf.c diff --git a/townengine/system/linux/elf.h b/src/system/linux/twn_elf.h similarity index 85% rename from townengine/system/linux/elf.h rename to src/system/linux/twn_elf.h index 583166a..68599c1 100644 --- a/townengine/system/linux/elf.h +++ b/src/system/linux/twn_elf.h @@ -1,5 +1,5 @@ -#ifndef ELF_H -#define ELF_H +#ifndef TWN_ELF_H +#define TWN_ELF_H #include diff --git a/townengine/audio/audio.c b/src/twn_audio.c similarity index 100% rename from townengine/audio/audio.c rename to src/twn_audio.c diff --git a/townengine/audio/internal_api.h b/src/twn_audio_c.h similarity index 92% rename from townengine/audio/internal_api.h rename to src/twn_audio_c.h index 696cc76..af9012f 100644 --- a/townengine/audio/internal_api.h +++ b/src/twn_audio_c.h @@ -1,7 +1,7 @@ -#ifndef PRIVATE_AUDIO_H -#define PRIVATE_AUDIO_H +#ifndef TWN_AUDIO_C_H +#define TWN_AUDIO_C_H -#include "../audio.h" +#include "twn_audio.h" #include diff --git a/townengine/camera.c b/src/twn_camera.c similarity index 96% rename from townengine/camera.c rename to src/twn_camera.c index 1ac1c26..c33812e 100644 --- a/townengine/camera.c +++ b/src/twn_camera.c @@ -1,5 +1,5 @@ -#include "camera.h" -#include "townengine/context.h" +#include "twn_camera.h" +#include "twn_context.h" #include diff --git a/townengine/macros/concatenate.h b/src/twn_concatenate_c.h similarity index 76% rename from townengine/macros/concatenate.h rename to src/twn_concatenate_c.h index 4c0040e..9bb5018 100644 --- a/townengine/macros/concatenate.h +++ b/src/twn_concatenate_c.h @@ -1,5 +1,5 @@ -#ifndef CONCATENATE_H -#define CONCATENATE_H +#ifndef TWN_CONCATENATE_H +#define TWN_CONCATENATE_H #define m_concatenate(p_a, p_b) m_concatenate_(p_a, p_b) #define m_concatenate_(p_a, p_b) m_concatenate__(p_a, p_b) diff --git a/src/twn_context.c b/src/twn_context.c new file mode 100644 index 0000000..afb3142 --- /dev/null +++ b/src/twn_context.c @@ -0,0 +1,3 @@ +#include "twn_engine_context_c.h" + +t_engine_ctx ctx = {0}; diff --git a/townengine/context.h b/src/twn_engine_context_c.h similarity index 52% rename from townengine/context.h rename to src/twn_engine_context_c.h index 5a9b524..691cc73 100644 --- a/townengine/context.h +++ b/src/twn_engine_context_c.h @@ -1,11 +1,9 @@ -#ifndef CONTEXT_H -#define CONTEXT_H +#ifndef TWN_ENGINE_CONTEXT_H +#define TWN_ENGINE_CONTEXT_H - -#include "rendering/internal_api.h" +#include "twn_context.h" #include "textures/internal_api.h" -#include "input.h" -#include "twn_engine_api.h" +#include "twn_input.h" #include @@ -13,17 +11,17 @@ #include -typedef struct context { +typedef struct engine_context { + t_ctx game_context; + /* the program's actual argc and argv */ int argc; char **argv; - struct texture_cache texture_cache; - struct input_state input; - struct primitive_2d *render_queue_2d; struct mesh_batch_item *uncolored_mesh_batches; struct text_cache text_cache; + struct texture_cache texture_cache; struct audio_channel_item *audio_channels; SDL_AudioDeviceID audio_device; @@ -38,34 +36,15 @@ typedef struct context { int64_t frame_accumulator; int64_t delta_averager_residual; int64_t time_averager[4]; - int64_t delta_time; /* preserves real time frame delta with no manipilation */ - uint64_t tick_count; - - /* set just once on startup */ - uint64_t random_seed; - - /* this should be a multiple of TICKS_PER_SECOND */ - /* use it to simulate low framerate (e.g. at 60 tps, set to 2 for 30 fps) */ - /* it can be changed at runtime; any resulting logic anomalies are bugs */ - unsigned int update_multiplicity; SDL_GLContext *gl_context; SDL_Window *window; uint32_t window_id; - int window_w; - int window_h; - /* you may read from and write to these from game code */ - void *udata; - - bool debug; - bool is_running; bool resync_flag; bool was_successful; - bool window_size_has_changed; - bool initialization_needed; -} t_ctx; +} t_engine_ctx; -TWN_API extern t_ctx ctx; +extern t_engine_ctx ctx = ; #endif diff --git a/townengine/twn_game_object.c b/src/twn_game_object.c similarity index 100% rename from townengine/twn_game_object.c rename to src/twn_game_object.c diff --git a/townengine/twn_game_object.h b/src/twn_game_object_c.h similarity index 88% rename from townengine/twn_game_object.h rename to src/twn_game_object_c.h index 47519aa..a7b54e9 100644 --- a/townengine/twn_game_object.h +++ b/src/twn_game_object_c.h @@ -1,5 +1,5 @@ -#ifndef GAME_OBJECT_H -#define GAME_OBJECT_H +#ifndef TWN_GAME_OBJECT_H +#define TWN_GAME_OBJECT_H #include diff --git a/townengine/input/input.c b/src/twn_input.c similarity index 100% rename from townengine/input/input.c rename to src/twn_input.c diff --git a/townengine/input/internal_api.h b/src/twn_input_c.h similarity index 100% rename from townengine/input/internal_api.h rename to src/twn_input_c.h diff --git a/townengine/twn_loop.c b/src/twn_loop.c similarity index 96% rename from townengine/twn_loop.c rename to src/twn_loop.c index fbbb406..6f73c38 100644 --- a/townengine/twn_loop.c +++ b/src/twn_loop.c @@ -9,10 +9,14 @@ #include "townengine/rendering/internal_api.h" #include -#include #include #include + +#ifdef EMSCRIPTEN +#include +#else #include +#endif #include #include @@ -54,6 +58,8 @@ static void poll_events(void) { } +#ifndef EMSCRIPTEN + static void APIENTRY opengl_log(GLenum source, GLenum type, GLuint id, @@ -71,6 +77,8 @@ static void APIENTRY opengl_log(GLenum source, log_info("OpenGL: %.*s\n", length, message); } +#endif + static void main_loop(void) { /* @@ -185,7 +193,7 @@ static void main_loop(void) { static bool initialize(void) { - if (SDL_Init(SDL_INIT_EVERYTHING) == -1) { + if (SDL_Init(SDL_INIT_EVERYTHING & ~SDL_INIT_HAPTIC) == -1) { CRY_SDL("SDL initialization failed."); return false; } @@ -199,8 +207,20 @@ static bool initialize(void) { ctx.debug = false; #endif +#ifdef EMSCRIPTEN + /* emscripten interpretes those as GL ES version against WebGL */ + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); +#else SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5); + + if (ctx.debug) + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); + else + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_NO_ERROR); +#endif + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); @@ -209,11 +229,6 @@ static bool initialize(void) { SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); - if (ctx.debug) - SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); - else - SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_NO_ERROR); - /* init got far enough to create a window */ ctx.window = SDL_CreateWindow("townengine", SDL_WINDOWPOS_CENTERED, @@ -242,16 +257,20 @@ static bool initialize(void) { if (SDL_GL_SetSwapInterval(-1)) SDL_GL_SetSwapInterval(1); +#ifndef EMSCRIPTEN if (gladLoadGL() == 0) { CRY("Init", "GLAD failed"); goto fail; } +#endif log_info("OpenGL context: %s\n", glGetString(GL_VERSION)); +#ifndef EMSCRIPTEN glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST); glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST); glHint(GL_FOG_HINT, GL_FASTEST); +#endif /* might need this to have multiple windows */ ctx.window_id = SDL_GetWindowID(ctx.window); @@ -295,11 +314,13 @@ static bool initialize(void) { /* you could change this at runtime if you wanted */ ctx.update_multiplicity = 1; +#ifndef EMSCRIPTEN /* hook up opengl debugging callback */ if (ctx.debug) { glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback(opengl_log, NULL); } +#endif /* random seeding */ /* SDL_GetPerformanceCounter returns some platform-dependent number. */ diff --git a/townengine/twn_main.c b/src/twn_main.c similarity index 100% rename from townengine/twn_main.c rename to src/twn_main.c diff --git a/townengine/macros/option.h b/src/twn_option_c.h similarity index 97% rename from townengine/macros/option.h rename to src/twn_option_c.h index 2f73714..22d403f 100644 --- a/townengine/macros/option.h +++ b/src/twn_option_c.h @@ -1,8 +1,8 @@ -#ifndef OPTION_H -#define OPTION_H +#ifndef TWN_OPTION_H +#define TWN_OPTION_H -#include "concatenate.h" -#include "varargcount.h" +#include "twn_concatenate_c.h" +#include "twn_varargcount_c.h" #include diff --git a/townengine/textures/modes.h b/src/twn_texture_modes_c.h similarity index 81% rename from townengine/textures/modes.h rename to src/twn_texture_modes_c.h index 78d59fd..052f331 100644 --- a/townengine/textures/modes.h +++ b/src/twn_texture_modes_c.h @@ -1,5 +1,5 @@ -#ifndef TEXTURES_MODES_H -#define TEXTURES_MODES_H +#ifndef TWN_TEXTURES_MODES_H +#define TWN_TEXTURES_MODES_H /* alpha channel information */ enum texture_mode { diff --git a/townengine/textures/textures.c b/src/twn_textures.c similarity index 89% rename from townengine/textures/textures.c rename to src/twn_textures.c index f950227..a4d1bcb 100644 --- a/townengine/textures/textures.c +++ b/src/twn_textures.c @@ -81,24 +81,6 @@ ERR_CANNOT_OPEN_FILE: } -static GLuint new_gl_texture(void) { - GLuint texture; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - glBindTexture(GL_TEXTURE_2D, 0); - return texture; -} - - static SDL_Surface *create_surface(int width, int height) { Uint32 rmask, gmask, bmask, amask; @@ -134,28 +116,16 @@ static SDL_Surface *create_surface(int width, int height) { static void add_new_atlas(struct texture_cache *cache) { SDL_Surface *new_atlas = create_surface(TEXTURE_ATLAS_SIZE, TEXTURE_ATLAS_SIZE); arrput(cache->atlas_surfaces, new_atlas); - arrput(cache->atlas_textures, new_gl_texture()); + arrput(cache->atlas_textures, create_gpu_texture(TEXTURE_FILTER_NEAREAST, true)); } -static void upload_texture_from_surface(GLuint texture, SDL_Surface *surface) { - glBindTexture(GL_TEXTURE_2D, texture); - +static void upload_texture_from_surface(gpu_texture texture, SDL_Surface *surface) { SDL_LockSurface(surface); - glTexImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA8, - surface->w, - surface->h, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - surface->pixels); + specify_gpu_texture(texture, surface->pixels, surface->w, surface->h); SDL_UnlockSurface(surface); - - glBindTexture(GL_TEXTURE_2D, 0); } @@ -285,7 +255,7 @@ void textures_cache_init(struct texture_cache *cache, SDL_Window *window) { void textures_cache_deinit(struct texture_cache *cache) { /* free atlas textures */ for (size_t i = 0; i < arrlenu(cache->atlas_textures); ++i) { - glDeleteTextures(1, &cache->atlas_textures[i]); + delete_gpu_texture(cache->atlas_textures[i]); } arrfree(cache->atlas_textures); @@ -373,7 +343,7 @@ static t_texture_key textures_load(struct texture_cache *cache, const char *path /* it's a "loner texture," it doesn't fit in an atlas so it's not in one */ if (surface->w >= TEXTURE_ATLAS_SIZE || surface->h >= TEXTURE_ATLAS_SIZE) { - new_texture.loner_texture = new_gl_texture(); + new_texture.loner_texture = create_gpu_texture(TEXTURE_FILTER_NEAREAST, true); upload_texture_from_surface(new_texture.loner_texture, surface); new_texture.srcrect = (t_frect) { .w = (float)surface->w, .h = (float)surface->h }; shput(cache->hash, path, new_texture); @@ -528,12 +498,12 @@ t_frect textures_get_dims(const struct texture_cache *cache, t_texture_key key) } -void textures_bind(const struct texture_cache *cache, t_texture_key key, GLenum target) { +void textures_bind(const struct texture_cache *cache, t_texture_key key) { if (m_texture_key_is_valid(key)) { if (cache->hash[key.id].value.loner_texture == 0) - glBindTexture(target, cache->atlas_textures[cache->hash[key.id].value.atlas_index]); + bind_gpu_texture(cache->atlas_textures[cache->hash[key.id].value.atlas_index]); else - glBindTexture(target, cache->hash[key.id].value.loner_texture); + bind_gpu_texture(cache->hash[key.id].value.loner_texture); } else if (key.id == 0) { CRY("Texture binding failed.", "Tried to get texture that isn't loaded."); @@ -542,39 +512,33 @@ void textures_bind(const struct texture_cache *cache, t_texture_key key, GLenum /* TODO: alternative schemes, such as: array texture, fragment shader and geometry division */ -void textures_bind_repeating(const struct texture_cache *cache, t_texture_key key, GLenum target) { +void textures_bind_repeating(const struct texture_cache *cache, t_texture_key key) { if (m_texture_key_is_valid(key)) { if (cache->hash[key.id].value.loner_texture == 0) { /* already allocated */ if (cache->hash[key.id].value.repeating_texture != 0) { - glBindTexture(target, cache->hash[key.id].value.repeating_texture); + bind_gpu_texture(cache->hash[key.id].value.repeating_texture); return; } const struct texture texture = cache->hash[key.id].value; - const GLuint repeating_texture = new_gl_texture(); - glBindTexture(target, repeating_texture); + const gpu_texture repeating_texture = create_gpu_texture(TEXTURE_FILTER_NEAREAST, false); SDL_LockSurface(texture.data); - glTexImage2D(target, - 0, - GL_RGBA8, - texture.data->w, - texture.data->h, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - texture.data->pixels); + specify_gpu_texture(repeating_texture, + texture.data->pixels, + texture.data->w, + texture.data->h); SDL_UnlockSurface(texture.data); cache->hash[key.id].value.repeating_texture = repeating_texture; } else - glBindTexture(target, cache->hash[key.id].value.loner_texture); + bind_gpu_texture(cache->hash[key.id].value.loner_texture); } else if (key.id == 0) { CRY("Texture binding failed.", diff --git a/townengine/textures/internal_api.h b/src/twn_textures_c.h similarity index 55% rename from townengine/textures/internal_api.h rename to src/twn_textures_c.h index a0af666..5846df0 100644 --- a/townengine/textures/internal_api.h +++ b/src/twn_textures_c.h @@ -1,13 +1,13 @@ -#ifndef TEXTURES_INTERNAL_API_H -#define TEXTURES_INTERNAL_API_H +#ifndef TWN_TEXTURES_H +#define TWN_TEXTURES_H -#include "../util.h" -#include "../textures/modes.h" -#include "../twn_engine_api.h" +#include "twn_util.h" +#include "twn_texture_modes.h" +#include "twn_engine_api.h" +#include "twn_gpu_texture.h" #include #include -#include #include @@ -15,8 +15,8 @@ struct texture { t_frect srcrect; /* position in atlas */ SDL_Surface *data; /* original image data */ int atlas_index; - GLuint loner_texture; /* stored directly for loners, == 0 means atlas_index should be used */ - GLuint repeating_texture; /* separately allocated texture, for loners == loner_texture */ + gpu_texture loner_texture; /* stored directly for loners, == 0 means atlas_index should be used */ + gpu_texture repeating_texture; /* separately allocated texture, for loners == loner_texture */ enum texture_mode mode; }; @@ -35,7 +35,7 @@ struct texture_cache { stbrp_node *node_buffer; /* used internally by stb_rect_pack */ SDL_Surface **atlas_surfaces; - GLuint *atlas_textures; /* shared by atlas textures */ + gpu_texture *atlas_textures; /* shared by atlas textures */ int atlas_index; /* atlas that is currently being built */ bool is_dirty; /* current atlas needs to be recreated */ @@ -47,11 +47,11 @@ typedef struct { uint16_t id; } t_texture_key; /* tests whether given key structure corresponds to any texture */ #define m_texture_key_is_valid(p_key) ((p_key).id != (uint16_t)-1) -TWN_API void textures_cache_init(struct texture_cache *cache, SDL_Window *window); -TWN_API void textures_cache_deinit(struct texture_cache *cache); +void textures_cache_init(struct texture_cache *cache, SDL_Window *window); +void textures_cache_deinit(struct texture_cache *cache); /* for debugging */ -TWN_API void textures_dump_atlases(struct texture_cache *cache); +void textures_dump_atlases(struct texture_cache *cache); /* loads an image if it isn't in the cache, otherwise a no-op. */ /* can be called from anywhere at any time after init, useful if you want to */ @@ -61,34 +61,32 @@ TWN_API void textures_dump_atlases(struct texture_cache *cache); /* repacks the current texture atlas based on the texture cache if needed */ /* any previously returned srcrect results are invalidated after that */ /* call it every time before rendering */ -TWN_API void textures_update_atlas(struct texture_cache *cache); +void textures_update_atlas(struct texture_cache *cache); /* returns a persistent handle to some texture in cache, loading it if needed */ /* check the result with m_texture_key_is_valid() */ -TWN_API t_texture_key textures_get_key(struct texture_cache *cache, const char *path); +t_texture_key textures_get_key(struct texture_cache *cache, const char *path); /* returns a rect in a texture cache of the given key */ -TWN_API t_frect textures_get_srcrect(const struct texture_cache *cache, t_texture_key key); +t_frect textures_get_srcrect(const struct texture_cache *cache, t_texture_key key); /* returns a rect of dimensions of the whole texture (whole atlas) */ -TWN_API t_frect textures_get_dims(const struct texture_cache *cache, t_texture_key key); +t_frect textures_get_dims(const struct texture_cache *cache, t_texture_key key); /* returns an identifier that is equal for all textures placed in the same atlas */ -TWN_API int32_t textures_get_atlas_id(const struct texture_cache *cache, t_texture_key key); +int32_t textures_get_atlas_id(const struct texture_cache *cache, t_texture_key key); -/* binds atlas texture in opengl state */ -TWN_API void textures_bind(const struct texture_cache *cache, t_texture_key key, GLenum target); +void textures_bind(const struct texture_cache *cache, t_texture_key key); -/* binds texture in opengl state, ensuring that it's usable with texture repeat */ -TWN_API void textures_bind_repeating(const struct texture_cache *cache, t_texture_key key, GLenum target); +void textures_bind_repeating(const struct texture_cache *cache, t_texture_key key); /* returns helpful information about contents of alpha channel in given texture */ -TWN_API enum texture_mode textures_get_mode(const struct texture_cache *cache, t_texture_key key); +enum texture_mode textures_get_mode(const struct texture_cache *cache, t_texture_key key); /* returns the number of atlases in the cache */ -TWN_API size_t textures_get_num_atlases(const struct texture_cache *cache); +size_t textures_get_num_atlases(const struct texture_cache *cache); /* TODO: should recieve texture_cache, get_key optimization cache should be cleared some other way */ -TWN_API void textures_reset_state(void); +void textures_reset_state(void); #endif diff --git a/townengine/util.c b/src/twn_util.c similarity index 99% rename from townengine/util.c rename to src/twn_util.c index 56cce38..3db90b2 100644 --- a/townengine/util.c +++ b/src/twn_util.c @@ -1,5 +1,5 @@ -#include "util.h" -#include "townengine/context.h" +#include "twn_util.h" +#include "twn_context.h" #include #include diff --git a/townengine/macros/varargcount.h b/src/twn_varargcount_c.h similarity index 82% rename from townengine/macros/varargcount.h rename to src/twn_varargcount_c.h index 636a9ed..fa63fed 100644 --- a/townengine/macros/varargcount.h +++ b/src/twn_varargcount_c.h @@ -1,5 +1,5 @@ -#ifndef VARARGCOUNT_H -#define VARARGCOUNT_H +#ifndef TWN_VARARGCOUNT_H +#define TWN_VARARGCOUNT_H #define m_narg(...) m_narg_(__VA_ARGS__, m_rseq_n_()) #define m_narg_(...) m_arg_n_(__VA_ARGS__) diff --git a/townengine/context/context.c b/townengine/context/context.c deleted file mode 100644 index efbbab5..0000000 --- a/townengine/context/context.c +++ /dev/null @@ -1,3 +0,0 @@ -#include "townengine/context.h" - -t_ctx ctx = {0}; diff --git a/townengine/rendering/triangles.h b/townengine/rendering/triangles.h deleted file mode 100644 index 9aa579c..0000000 --- a/townengine/rendering/triangles.h +++ /dev/null @@ -1,118 +0,0 @@ -/* a rendering.c mixin */ -#ifndef TRIANGLES_H -#define TRIANGLES_H - -#include "townengine/context.h" -#include "internal_api.h" -#include "../textures/internal_api.h" - -#include - -/* TODO: automatic handling of repeating textures */ -/* for that we could allocate a loner texture */ -void unfurl_triangle(const char *path, - t_fvec3 v0, - t_fvec3 v1, - t_fvec3 v2, - t_shvec2 uv0, - t_shvec2 uv1, - t_shvec2 uv2) -{ - const t_texture_key texture_key = textures_get_key(&ctx.texture_cache, path); - - struct mesh_batch_item *batch_p = hmgetp_null(ctx.uncolored_mesh_batches, texture_key); - if (!batch_p) { - struct mesh_batch item = {0}; - hmput(ctx.uncolored_mesh_batches, texture_key, item); - batch_p = &ctx.uncolored_mesh_batches[hmlenu(ctx.uncolored_mesh_batches) - 1]; /* TODO: can last index be used? */ - } - - union uncolored_space_triangle triangle = { .primitive = { - .v0 = v0, - .v1 = v1, - .v2 = v2, - .uv1 = m_to_fvec2(uv1), - .uv0 = m_to_fvec2(uv0), - .uv2 = m_to_fvec2(uv2), - }}; - - union uncolored_space_triangle *triangles = - (union uncolored_space_triangle *)batch_p->value.primitives; - arrpush(triangles, triangle); - batch_p->value.primitives = (uint8_t *)triangles; -} - - -static void draw_uncolored_space_traingle_batch(struct mesh_batch *batch, - t_texture_key texture_key) -{ - size_t primitives_len = arrlenu(batch->primitives); - - if (primitives_len == 0) - return; - - /* create vertex array object */ - if (batch->buffer == 0) - glGenBuffers(1, &batch->buffer); - - /* TODO: try using mapped buffers while building batches instead? */ - /* this way we could skip client side copy that is kept until commitment */ - /* alternatively we could commit glBufferSubData based on a threshold */ - - /* update pixel-based uvs to correspond with texture atlases */ - for (size_t i = 0; i < primitives_len; ++i) { - struct uncolored_space_triangle_payload *payload = - &((union uncolored_space_triangle *)batch->primitives)[i].payload; - - const t_frect srcrect = textures_get_srcrect(&ctx.texture_cache, texture_key); - const t_frect dims = textures_get_dims(&ctx.texture_cache, texture_key); - - const float wr = srcrect.w / dims.w; - const float hr = srcrect.h / dims.h; - const float xr = srcrect.x / dims.w; - const float yr = srcrect.y / dims.h; - - payload->uv0.x = xr + ((float)payload->uv0.x / srcrect.w) * wr; - payload->uv0.y = yr + ((float)payload->uv0.y / srcrect.h) * hr; - payload->uv1.x = xr + ((float)payload->uv1.x / srcrect.w) * wr; - payload->uv1.y = yr + ((float)payload->uv1.y / srcrect.h) * hr; - payload->uv2.x = xr + ((float)payload->uv2.x / srcrect.w) * wr; - payload->uv2.y = yr + ((float)payload->uv2.y / srcrect.h) * hr; - } - - textures_bind(&ctx.texture_cache, texture_key, GL_TEXTURE_2D); - - glBindBuffer(GL_ARRAY_BUFFER, batch->buffer); - - /* upload batched data */ - glBufferData(GL_ARRAY_BUFFER, - primitives_len * sizeof (struct uncolored_space_triangle_payload), - batch->primitives, - GL_STREAM_DRAW); - - /* vertex specification*/ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, - GL_FLOAT, - offsetof(struct uncolored_space_triangle_payload, v1), - (void *)offsetof(struct uncolored_space_triangle_payload, v0)); - - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTexture(GL_TEXTURE0); - glTexCoordPointer(2, - GL_FLOAT, - offsetof(struct uncolored_space_triangle_payload, v1), - (void *)offsetof(struct uncolored_space_triangle_payload, uv0)); - - /* commit for drawing */ - glDrawArrays(GL_TRIANGLES, 0, 3 * (GLint)primitives_len); - - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - - /* invalidate the buffer immediately */ - glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -#endif diff --git a/townengine/scripting.c b/townengine/scripting.c deleted file mode 100644 index 069e07b..0000000 --- a/townengine/scripting.c +++ /dev/null @@ -1,139 +0,0 @@ -#include "scripting.h" -#include "util.h" -#include "townengine/context.h" - -#include -#include -#include - -#include -#include -#include - -static void msgbox(UmkaStackSlot *params, UmkaStackSlot *result) { - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, - params[1].ptrVal, params[0].ptrVal, NULL); -} - -static void umka_log_info(UmkaStackSlot *params, UmkaStackSlot *result) { - log_info(params[0].ptrVal); -} - -static void umka_log_critical(UmkaStackSlot *params, UmkaStackSlot *result) { - log_critical(params[0].ptrVal); -} - -static void umka_log_warn(UmkaStackSlot *params, UmkaStackSlot *result) { - log_warn(params[0].ptrVal); -} - -static void is_action_pressed(UmkaStackSlot *params, UmkaStackSlot *result) { - struct state *state = params[1].ptrVal; - t_ctx *ctx = state->hidden_ptr; - - bool value = input_is_action_pressed(&ctx->input, params[0].ptrVal); - result->uintVal = value; -} - -static void is_action_just_pressed(UmkaStackSlot *params, UmkaStackSlot *result) { - struct state *state = params[1].ptrVal; - t_ctx *ctx = state->hidden_ptr; - - bool value = input_is_action_just_pressed(&ctx->input, params[0].ptrVal); - result->uintVal = value; -} - -static void is_action_just_released(UmkaStackSlot *params, UmkaStackSlot *result) { - struct state *state = params[1].ptrVal; - t_ctx *ctx = state->hidden_ptr; - - bool value = input_is_action_just_released(&ctx->input, params[0].ptrVal); - result->uintVal = value; -} - -static void get_action_position(UmkaStackSlot *params, UmkaStackSlot *result) { - struct state *state = params[2].ptrVal; - t_ctx *ctx = state->hidden_ptr; - - t_fvec2 *position = params[0].ptrVal; - *position = input_get_action_position(&ctx->input, params[1].ptrVal); - - // the result is in a hidden result pointer allocated by Umka - result->ptrVal = params[0].ptrVal; -} - -static void register_api(void *umka) { - umkaAddFunc(umka, "msgbox", msgbox); - umkaAddFunc(umka, "logInfo", umka_log_info); - umkaAddFunc(umka, "logCritical", umka_log_critical); - umkaAddFunc(umka, "logWarn", umka_log_warn); - umkaAddFunc(umka, "cImplIsActionPressed", is_action_pressed); - umkaAddFunc(umka, "cImplIsActionJustPressed", is_action_just_pressed); - umkaAddFunc(umka, "cImplIsActionJustReleased", is_action_just_released); - umkaAddFunc(umka, "getActionPosition", get_action_position); -} - -bool scripting_init(t_ctx *ctx) { - if (!PHYSFS_exists("/scripts/main.um")) { - CRY("Failed to initialize scripting", "Could not find a main.um (we need it)"); - return false; - } - - ctx->umka = umkaAlloc(); - - char *main_script = file_to_str("/scripts/main.um"); - bool umka_ok = umkaInit(ctx->umka, - "main.um", - main_script, - UMKA_STACK_SIZE, - NULL, - ctx->argc, - ctx->argv, - false, - false, - NULL); - free(main_script); - - if (!umka_ok) { - CRY("Failed to initialize scripting", "Unknown Umka error"); - return false; - } - - /* all Umka files are compiled even if they're never used */ - char **dir_file_names = PHYSFS_enumerateFiles("/scripts"); - for (char **i = dir_file_names; *i != NULL; ++i) { - char *file_name = *i; - - if (!strends(file_name, ".um")) - continue; - - /* got this one already */ - if (strcmp(file_name, "main.um") == 0) - continue; - - /* need to figure out the actual path (as opposed to the lone file name) */ - const char *path_prefix = "/scripts/"; - size_t path_size = snprintf(NULL, 0, "%s%s", path_prefix, file_name) + 1; - char *path = cmalloc(path_size); - snprintf(path, path_size, "%s%s", path_prefix, file_name); - - char *contents = file_to_str(path); - umkaAddModule(ctx->umka, file_name, contents); - - free(path); - free(contents); - } - PHYSFS_freeList(dir_file_names); - - register_api(ctx->umka); - if (!umkaCompile(ctx->umka)) { - cry_umka(ctx->umka); - return false; - } - - return true; -} - -void scripting_deinit(t_ctx *ctx) { - umkaFree(ctx->umka); -} diff --git a/townengine/scripting.h b/townengine/scripting.h deleted file mode 100644 index 700ec80..0000000 --- a/townengine/scripting.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef SCRIPTING_H -#define SCRIPTING_H - -#include - -#include -#include - -typedef struct context t_ctx; - -struct state { - t_ctx *hidden_ptr; - uint64_t tick_count; -}; - -bool scripting_init(void); - -#endif diff --git a/untitled.sublime-project b/untitled.sublime-project new file mode 100644 index 0000000..24db303 --- /dev/null +++ b/untitled.sublime-project @@ -0,0 +1,8 @@ +{ + "folders": + [ + { + "path": "." + } + ] +} diff --git a/untitled.sublime-workspace b/untitled.sublime-workspace new file mode 100644 index 0000000..9891a22 --- /dev/null +++ b/untitled.sublime-workspace @@ -0,0 +1,1609 @@ +{ + "auto_complete": + { + "selected_items": + [ + [ + "twn", + "twn_rendering_platform.h\"" + ], + [ + "twn_", + "twn_text_c.h\"" + ], + [ + "pus", + "push_sprite_payload_to_vertex_buffer_builder" + ], + [ + "verte", + "vertex_buffer_builder" + ], + [ + "crea", + "create_gpu_texture" + ], + [ + "TEXTURE_FIL", + "TEXTURE_FILTER_NEAREAST" + ], + [ + "text", + "texture_filter" + ], + [ + "create_", + "create_gpu_texture" + ], + [ + "GLui", + "GLuint" + ], + [ + "texture", + "texture_key" + ], + [ + "GL_VER", + "GL_VERTEX_ARRAY" + ], + [ + "push", + "push_sprite_payload_to_vertex_buffer_builder" + ], + [ + "ve", + "vertex_buffer" + ], + [ + "b", + "bytes" + ], + [ + "glMap", + "glMapBuffer" + ], + [ + "bu", + "buffer_element" + ], + [ + "PIPE", + "PIPELINE_SPACE" + ], + [ + "con", + "context.h\"" + ], + [ + "co", + "config.h\"" + ], + [ + "to", + "townengine/" + ], + [ + "TWN_", + "TWN_ROOT_DIR" + ], + [ + "p", + "pixels" + ], + [ + "SDL_Free", + "SDL_FreeRW" + ], + [ + "SDL_assert", + "SDL_assert_always" + ], + [ + "file_", + "file_mem" + ], + [ + "SDL_al", + "SDL_assert_always" + ], + [ + "file", + "file_mem" + ], + [ + "memc", + "memccpy" + ], + [ + "SDL_CreateSurfa", + "SDL_CreateRGBSurfaceFrom" + ], + [ + "stbi_lo", + "stbi_load_from_memory" + ], + [ + "SDL_Surface", + "SDL_CreateRGBSurfaceWithFormat" + ], + [ + "end", + "endfunction" + ], + [ + "CMAKE_CURRENT", + "CMAKE_CURRENT_SOURCE_DIR" + ], + [ + "TOWNENGINE_AR", + "TOWNENGINE_ARCHIVE_DATA" + ], + [ + "TOWNENGINE_", + "TOWNENGINE_ARCHIVE_DATA" + ], + [ + "TO", + "TOWNENGINE_BOOTSTRAP" + ], + [ + "TOW", + "TOWNENGINE_HOT_RELOAD" + ], + [ + "sh", + "shfree" + ], + [ + "game", + "game_end" + ], + [ + "load", + "load_game_shared_object" + ], + [ + "gan", + "game_object_loaded_after_modification" + ], + [ + "CURRENT", + "CMAKE_CURRENT_SOURCE_DIR" + ], + [ + "RUNTI", + "RUNTIME_OUTPUT_DIRECTORY" + ], + [ + "CMAEK_CURRENT", + "CMAKE_CURRENT_SOURCE_DIR" + ], + [ + "compile_op", + "add_compile_options" + ], + [ + "RUNTIME_OUTPUT", + "RUNTIME_OUTPUT_NAME" + ], + [ + "TOWN", + "TOWNENGINE_HOT_RELOAD" + ], + [ + "game_", + "game_tick" + ], + [ + "CMAKE_PROJE", + "CMAKE_PROJECT_NAME" + ], + [ + "so", + "sources" + ], + [ + "int", + "int64_t" + ], + [ + "stb_per", + "stb_perlin_noise3_seed" + ], + [ + "uin", + "uint8_t" + ], + [ + "uint", + "uint8_t" + ], + [ + "sl", + "slice_descs" + ], + [ + "arr", + "arrlenu" + ], + [ + "all", + "allocated_str" + ], + [ + "mallo", + "malloc" + ], + [ + "tabela_push_int32_", + "tabela_push_int32_at_key" + ], + [ + "t", + "tree_view_size" + ], + [ + "tre", + "tree_view_size" + ], + [ + "arrlen", + "arrlenu" + ], + [ + "tree", + "tree_view" + ], + [ + "s", + "slice_descs_view_size" + ], + [ + "sli", + "slice_descs_view" + ], + [ + "shget", + "shgetp_null" + ], + [ + "ali", + "alignof" + ], + [ + "TABE", + "TABELA_TYPE_NONE" + ], + [ + "ta", + "tabela_variant" + ], + [ + "table", + "tabela_current" + ], + [ + "tabela", + "tabela_save" + ], + [ + "tabela_p", + "tabela_push_int32" + ], + [ + "tabel", + "tabela_open" + ], + [ + "str", + "struct" + ], + [ + "arrp", + "arrput" + ], + [ + "tr", + "tree" + ], + [ + "sta", + "stack_index" + ], + [ + "no", + "node_count" + ], + [ + "n", + "node_count" + ], + [ + "re", + "return" + ], + [ + "fw", + "fwrite" + ], + [ + "pt", + "ptrdiff_t" + ], + [ + "t_", + "t_fvec2" + ], + [ + "m", + "m_opt" + ], + [ + "te", + "texture_origin_opt" + ], + [ + "t_f", + "t_fvec2" + ], + [ + "repeat", + "repeating_texture" + ], + [ + "TEXT", + "TEXTURE_ATLAS_SIZE" + ], + [ + "SDL_", + "SDL_Surface" + ], + [ + "glCopy", + "glCopyTexSubImage2D" + ], + [ + "SDL_Assert", + "SDL_assert" + ], + [ + "malo", + "malloc.h>" + ], + [ + "stb_d", + "stb_ds.h>" + ], + [ + "tabe", + "tabela_type" + ], + [ + "GLAD_GL_", + "GLAD_GL_ARB_depth_clamp" + ], + [ + "w", + "window" + ], + [ + "SDL_GL_Get", + "SDL_GL_GetDrawableSize" + ], + [ + "glDe", + "glDepthRange" + ], + [ + "SDL_GL_CONTEXT_", + "SDL_GL_CONTEXT_NO_ERROR" + ], + [ + "GL_LINE", + "GL_LINEAR" + ], + [ + "m_vec", + "m_vec_norm" + ], + [ + "render", + "rendering.h\"" + ], + [ + "p_", + "p_member" + ], + [ + "_", + "_opt" + ], + [ + "m_op", + "m_option_list" + ], + [ + "_op", + "_opt_set" + ], + [ + "pp", + "push_sprite_ex" + ], + [ + "phy", + "physfs" + ], + [ + "camera_lo", + "camera_look_at_matrix" + ], + [ + "aud", + "audio/" + ], + [ + "TOWNENGINE", + "TOWNENGINE_DIR" + ], + [ + "PRO", + "PROJECT_NAME" + ], + [ + "M_PI", + "M_PI_2" + ], + [ + "wind", + "window_h" + ], + [ + "win", + "window_w" + ], + [ + "glClear", + "glClearDepth" + ], + [ + "GL_LE", + "GL_LEQUAL" + ], + [ + "camera", + "camera_projection" + ], + [ + "glLoad", + "glLoadMatrixf" + ], + [ + "came", + "camera_look_at" + ], + [ + "cam", + "camera_projection" + ], + [ + "fvec3", + "fvec3_scale" + ], + [ + "t_fvec", + "t_fvec3" + ], + [ + "t_fve", + "t_fvec3" + ], + [ + "wi", + "window_size_has_changed" + ], + [ + "SDL_WINDOWEVENT_", + "SDL_WINDOWEVENT_MINIMIZED" + ], + [ + "GL_ALPHA_", + "GL_ALPHA_TEST" + ], + [ + "TEXTURE", + "TEXTURE_MODE_SEETHROUGH" + ] + ] + }, + "buffers": + [ + { + "file": "include/twn_config.h", + "settings": + { + "buffer_size": 972, + "encoding": "UTF-8", + "line_ending": "Unix" + }, + "undo_stack": + [ + [ + 12, + 4, + "cut", + null, + "BAAAAMQDAAAAAAAAxAMAAAAAAAABAAAACsQDAAAAAAAAxAMAAAAAAAASAAAALyogMTAyNCAqIDEwMjQgKi8KxAMAAAAAAADEAwAAAAAAACYAAAAvKiAjZGVmaW5lIFVNS0FfU1RBQ0tfU0laRSAxMDQ4NTc2ICovCsQDAAAAAAAAxAMAAAAAAAABAAAACg", + "AwAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAMQDAAAAAAAAxAMAAAAAAAAAAAAAAADwvw" + ] + ] + }, + { + "file": "src/rendering/twn_triangles.c", + "settings": + { + "buffer_size": 2969, + "encoding": "UTF-8", + "line_ending": "Unix" + }, + "undo_stack": + [ + [ + 23, + 1, + "insert", + { + "characters": "twn_" + }, + "BQAAACcAAAAAAAAAKAAAAAAAAAAAAAAAKAAAAAAAAAAoAAAAAAAAAAsAAAB0b3duZW5naW5lLygAAAAAAAAAKQAAAAAAAAAAAAAAKQAAAAAAAAAqAAAAAAAAAAAAAAAqAAAAAAAAACsAAAAAAAAAAAAAAA", + "AwAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAADIAAAAAAAAAJwAAAAAAAAAAAAAAAADwvw" + ], + [ + 27, + 1, + "insert", + { + "characters": "wn" + }, + "AwAAAEAAAAAAAAAAQQAAAAAAAAAAAAAAQQAAAAAAAABBAAAAAAAAACAAAAB0b3duZW5naW5lL3RleHR1cmVzL2ludGVybmFsX2FwaUEAAAAAAAAAQgAAAAAAAAAAAAAA", + "AwAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAEAAAAAAAAAAYAAAAAAAAAAAAAAAAADwvw" + ], + [ + 28, + 2, + "left_delete", + null, + "AgAAAEEAAAAAAAAAQQAAAAAAAAABAAAAbkAAAAAAAAAAQAAAAAAAAAABAAAAdw", + "AwAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAEIAAAAAAAAAQgAAAAAAAAAAAAAAAADwvw" + ], + [ + 29, + 1, + "insert", + { + "characters": "twn_texture" + }, + "CwAAAEAAAAAAAAAAQQAAAAAAAAAAAAAAQQAAAAAAAABCAAAAAAAAAAAAAABCAAAAAAAAAEMAAAAAAAAAAAAAAEMAAAAAAAAARAAAAAAAAAAAAAAARAAAAAAAAABFAAAAAAAAAAAAAABFAAAAAAAAAEYAAAAAAAAAAAAAAEYAAAAAAAAARwAAAAAAAAAAAAAARwAAAAAAAABIAAAAAAAAAAAAAABIAAAAAAAAAEkAAAAAAAAAAAAAAEkAAAAAAAAASgAAAAAAAAAAAAAASgAAAAAAAABLAAAAAAAAAAAAAAA", + "AwAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAEAAAAAAAAAAQAAAAAAAAAAAAAAAAADwvw" + ], + [ + 30, + 1, + "insert", + { + "characters": "s_c" + }, + "AwAAAEsAAAAAAAAATAAAAAAAAAAAAAAATAAAAAAAAABNAAAAAAAAAAAAAABNAAAAAAAAAE4AAAAAAAAAAAAAAA", + "AwAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPC/AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8L8AAAAAAQAAAEsAAAAAAAAASwAAAAAAAAAAAAAAAADwvw" + ] + ] + }, + { + "file": "include/twn_vec.h", + "settings": + { + "buffer_size": 4341, + "line_ending": "Unix" + } + } + ], + "build_system": "", + "build_system_choices": + [ + ], + "build_varint": "", + "command_palette": + { + "height": 0.0, + "last_filter": "", + "selected_items": + [ + [ + "move", + "File: Move" + ], + [ + "rena", + "Rename File" + ], + [ + "mo", + "File: Move" + ], + [ + "du", + "File: Duplicate" + ], + [ + "dupli", + "File: Duplicate" + ], + [ + "defit", + "LSP: Goto Definition" + ], + [ + "rename", + "Rename File" + ], + [ + "dupl", + "File: Duplicate" + ], + [ + "toggle si", + "View: Toggle Side Bar" + ], + [ + "toggle", + "View: Toggle Side Bar" + ], + [ + "toggle pane", + "LSP: Toggle Log Panel" + ], + [ + "hex", + "HexViewer: Toggle Hex View" + ], + [ + "instal", + "Package Control: Install Package" + ], + [ + "unfo", + "Code Folding: Unfold All" + ], + [ + "colla", + "Code Folding: Fold All" + ], + [ + "restart", + "LSP: Restart Server" + ], + [ + "inga", + "Code Folding: Fold All" + ], + [ + "res", + "LSP: Restart Server" + ], + [ + "cmake", + "Set Syntax: CMake" + ], + [ + "git push", + "Git: Push Current Branch" + ], + [ + "push", + "Git: Push" + ], + [ + "git che", + "Git: Change Branch" + ], + [ + "git", + "Git: Push" + ], + [ + "install", + "Package Control: Install Package" + ], + [ + "blame", + "Sublime Merge: Blame File" + ], + [ + "diff", + "FileDiffs: Menu" + ], + [ + "lsp eba", + "LSP: Enable Language Server in Project" + ], + [ + "rea", + "Rename File" + ], + [ + "syntax c", + "Set Syntax: C" + ], + [ + "enable", + "LSP: Enable Language Server in Project" + ], + [ + "trob", + "LSP: Troubleshoot Server" + ], + [ + "insta", + "Package Control: Install Package" + ], + [ + "tro", + "LSP: Troubleshoot Server" + ], + [ + "diag", + "LSP: Toggle Diagnostics Panel" + ], + [ + "select", + "UI: Select Color Scheme" + ], + [ + "theme", + "UI: Select Theme" + ] + ], + "width": 0.0 + }, + "console": + { + "height": 0.0, + "history": + [ + ] + }, + "distraction_free": + { + "menu_visible": true, + "show_minimap": false, + "show_open_files": false, + "show_tabs": false, + "side_bar_visible": false, + "status_bar_visible": false + }, + "expanded_folders": + [ + "/home/tochie/Code/townengine", + "/home/tochie/Code/townengine/docs", + "/home/tochie/Code/townengine/include", + "/home/tochie/Code/townengine/src", + "/home/tochie/Code/townengine/src/system" + ], + "file_history": + [ + "/home/tochie/Code/townengine/src/twn_engine_context_c.h", + "/home/tochie/Code/townengine/src/twn_varargcount.h", + "/home/tochie/Code/townengine/docs/source_directory_structure.txt", + "/home/tochie/Code/townengine/src/system/linux/twn_elf.h", + "/home/tochie/Code/townengine/src/twn_context.c", + "/home/tochie/Code/townengine/src/twn_audio_c.h", + "/home/tochie/Code/townengine/src/twn_concatenate_c.h", + "/home/tochie/Code/townengine/src/twn_option_c.h", + "/home/tochie/Code/townengine/include/twn_context.h", + "/home/tochie/Code/townengine/include/twn_camera.h", + "/home/tochie/Code/townengine/include/twn_vec.h", + "/home/tochie/Code/townengine/include/twn_util.h", + "/home/tochie/Code/townengine/src/twn_textures_c.h", + "/home/tochie/Code/townengine/src/twn_util.c", + "/home/tochie/Code/townengine/src/twn_camera.c", + "/home/tochie/Code/townengine/src/twn_texture_modes_c.h", + "/home/tochie/Code/townengine/src/rendering/twn_gl_15_rendering.c", + "/home/tochie/Code/townengine/include/twn_config.h", + "/home/tochie/Code/townengine/include/twn_game_api.h", + "/home/tochie/Code/townengine/src/twn_engine_context.h", + "/home/tochie/Code/townengine/include/readme.txt", + "/home/tochie/Code/townengine/include/twn_audio.h", + "/home/tochie/Code/townengine/src/camera.h", + "/home/tochie/Code/townengine/include/twn_input.h", + "/home/tochie/Code/townengine/townengine/rendering/twn_gl_any_rendering_c.h", + "/home/tochie/Code/townengine/townengine/rendering/twn_rendering_c.h", + "/home/tochie/Code/townengine/townengine/rendering/twn_text.c", + "/home/tochie/Code/townengine/townengine/rendering/twn_text_c.h", + "/home/tochie/Code/townengine/townengine/rendering/twn_triangles.c", + "/home/tochie/Code/townengine/townengine/rendering/twn_sprites.c", + "/home/tochie/Code/townengine/townengine/rendering/twn_rendering_platform.h", + "/home/tochie/Code/townengine/townengine/rendering/twn_rendering.c", + "/home/tochie/Code/townengine/townengine/textures/textures.c", + "/home/tochie/Code/townengine/townengine/twn_rendering.h", + "/home/tochie/Code/townengine/townengine/rendering/twn_gpu_texture.h", + "/home/tochie/Code/townengine/townengine/rendering/twn_gl_15_gpu_texture.c", + "/home/tochie/Code/townengine/townengine/rendering/twn_gl_15_rendering.c", + "/home/tochie/Code/townengine/townengine/rendering/twn_gl_15_rendering_c.h", + "/home/tochie/Code/townengine/townengine/textures/internal_api.h", + "/home/tochie/Code/townengine/third-party/stb/stb_truetype.h", + "/home/tochie/Code/townengine/townengine/util.h", + "/home/tochie/Code/townengine/townengine/config.h", + "/home/tochie/Code/townengine/townengine/rendering/twn_gl_any_rendering.c", + "/home/tochie/Code/townengine/townengine/main.c", + "/home/tochie/Code/townengine/townengine/twn_engine_api.h", + "/home/tochie/Code/townengine/townengine/twn_game_object.h", + "/home/tochie/Code/townengine/townengine/rendering/twn_circles.c", + "/home/tochie/Code/townengine/townengine/textures/modes.h", + "/home/tochie/Code/townengine/townengine/rendering/circles.h", + "/home/tochie/Code/townengine/townengine/context.h", + "/home/tochie/Code/townengine/townengine/rendering/internal_api.h", + "/home/tochie/Code/townengine/townengine/rendering.c", + "/home/tochie/Code/townengine/townengine/rendering/sprites.h", + "/home/tochie/Code/townengine/townengine/rendering/twn_triangles_c.h", + "/home/tochie/Code/townengine/townengine/rendering/quad_element_buffer.h", + "/home/tochie/Code/townengine/third-party/glad/include/glad/glad.h", + "/home/tochie/Code/townengine/.gitignore", + "/home/tochie/Code/townengine/townengine/twn_loop.c", + "/home/tochie/Code/townengine/CMakeLists.txt", + "/home/tochie/Code/townengine/apps/testgame/build.sh", + "/home/tochie/Code/townengine/townengine/input/input.c", + "/home/tochie/Code/townengine/townengine/input.h", + "/home/tochie/Code/townengine/townengine/rendering/triangles.h", + "/home/tochie/Code/townengine/townengine/rendering/text.h", + "/usr/include/EGL/egl.h", + "/usr/include/SDL2/SDL.h", + "/home/tochie/Code/townengine/third-party/physfs/CMakeLists.txt", + "/home/tochie/Code/townengine/third-party/stb/stb_image.h", + "/home/tochie/Code/townengine/apps/template/game.c", + "/home/tochie/Code/townengine/apps/testgame/game.c", + "/home/tochie/Code/townengine/apps/testgame/scenes/ingame.c", + "/home/tochie/Code/townengine/apps/testgame/scenes/title.c", + "/home/tochie/Code/townengine/townengine/game_object/twn_linux_game_object_c.h", + "/home/tochie/Code/townengine/townengine/game_object/twn_win32_game_object_c.h", + "/home/tochie/Code/townengine/apps/testgame/.build/CMakeFiles/testgame_app.dir/build.make", + "/home/tochie/Code/townengine/apps/testgame/CMakeLists.txt", + "/home/tochie/Code/townengine/apps/template/CMakeLists.txt", + "/home/tochie/Code/townengine/townengine/rendering.h", + "/home/tochie/Code/townengine/townengine/game_api.h", + "/home/tochie/Code/townengine/apps/testgame/scenes/scene.c", + "/home/tochie/Code/townengine/apps/testgame/world.c", + "/home/tochie/Code/townengine/apps/testgame/player.h", + "/home/tochie/Code/townengine/townengine/scripting.c", + "/home/tochie/Code/townengine/townengine/camera.c", + "/home/tochie/Code/townengine/townengine/util.c", + "/home/tochie/Code/townengine/townengine/audio/audio.c", + "/home/tochie/Code/townengine/apps/testgame/player.c", + "/home/tochie/Code/townengine/apps/testgame/state.h", + "/home/tochie/Code/townengine/townengine/input/internal_api.h", + "/home/tochie/Code/townengine/apps/testgame/scenes/ingame.h", + "/home/tochie/Code/townengine/third-party/stb/stb_ds.h", + "/home/tochie/Code/townengine/townengine/context/internal_api.h", + "/home/tochie/Code/townengine/apps/testgame/game.h", + "/home/tochie/Code/townengine/townengine/context/context.c", + "/home/tochie/Code/townengine/townengine/audio.c", + "/home/tochie/Code/townengine/townengine/input.c", + "/home/tochie/Code/townengine/null.c", + "/home/tochie/Code/townengine/third-party/x-watcher.h", + "/home/tochie/Code/townengine/townengine/tabela.c", + "/home/tochie/Code/townengine/townengine/tabela.h", + "/home/tochie/Code/salesman/townengine/game_api.h", + "/home/tochie/Code/salesman/third-party/stb/stb_perlin.h", + "/home/tochie/Code/salesman/apps/testgame/scenes/ingame.c", + "/home/tochie/Code/salesman/townengine/context.c", + "/home/tochie/Code/salesman/townengine/context.h", + "/home/tochie/Code/salesman/apps/template/state.h", + "/home/tochie/Code/salesman/CMakeLists.txt", + "/home/tochie/Code/salesman/apps/testgame/game.c", + "/home/tochie/Code/salesman/townengine/tabela.h", + "/home/tochie/Code/salesman/third-party/stb/stb_truetype.h", + "/home/tochie/Code/salesman/third-party/stb/stb_ds.h", + "/home/tochie/Code/salesman/townengine/camera.h", + "/home/tochie/Code/salesman/townengine/util.h", + "/home/tochie/Code/salesman/townengine/macros/inout.h", + "/home/tochie/Code/salesman/townengine/camera/internal_api.h", + "/home/tochie/Code/salesman/townengine/textures/textures.c", + "/home/tochie/Code/salesman/.build/test.tbl", + "/home/tochie/Code/salesman/townengine/rendering/sprites.h", + "/home/tochie/Code/salesman/townengine/rendering.h", + "/home/tochie/Code/salesman/townengine/macros/option.h", + "/usr/include/SDL2/SDL_surface.h", + "/home/tochie/Code/salesman/townengine/rendering/internal_api.h", + "/home/tochie/Code/salesman/townengine/macros/varargcount.h", + "/home/tochie/Code/salesman/townengine/textures/internal_api.h", + "/usr/include/SDL2/SDL_rect.h", + "/home/tochie/Code/salesman/townengine/vec.h", + "/home/tochie/Code/salesman/townengine/tabela.c", + "/usr/lib/clang/17/include/stddef.h" + ], + "find": + { + "height": 32.0 + }, + "find_in_files": + { + "height": 194.0, + "where_history": + [ + "/home/tochie/Code/townengine/townengine", + "/home/tochie/Code/townengine/", + "/home/tochie/Code/townengine/townengine", + "/home/tochie/Code/townengine/", + "/home/tochie/Code/townengine/apps", + "/home/tochie/Code/townengine/townengine", + "/home/tochie/Code/townengine/apps", + "/home/tochie/Code/townengine/townengine", + "/home/tochie/Code/townengine/apps", + "/home/tochie/Code/townengine/townengine", + "/home/tochie/Code/salesman/apps/", + "/home/tochie/Code/salesman/townengine", + "/home/tochie/Code/salesman/", + "/home/tochie/Code/salesman/src", + "/home/tochie/Code/salesman", + "/home/tochie/Code/salesman/apps", + "/home/tochie/Code/salesman/src", + "/home/tochie/Code/salesman", + "/home/tochie/Code/salesman/src", + "/home/tochie/Code/salesman/", + "/home/tochie/Code/salesman/src", + "/home/tochie/Code/salesman/", + "/home/tochie/Code/salesman/src" + ] + }, + "find_state": + { + "case_sensitive": false, + "find_history": + [ + "ELF_H", + "VARARGCOUNT_H", + "OPTION_H", + "CONCATENATE_H", + "definitions", + "PRIVATE_AUDIO_H", + "TEXTURES_INTERNAL_API_H", + "VEC_H", + "CONTEXT_H", + "townengine/", + "CONFIG_H", + "INPUT_H", + "AUDIO_H", + "CAMERA_H", + "#ifdef EMSCRIPTEN\n#include \"twn_gl_es2_rendering_c.h\"\n#else\n#include \"twn_gl_15_rendering_c.h\"\n#endif", + "RENDERING_INTERNAL_API_H", + "finally_draw_text", + " ", + " ", + "TWN_API ", + "vertex_buffer", + "_primitive_payload", + "sprite_primitive_payload", + "ASCII_START", + "ASCII_END", + "gl", + ", GLenum target", + "GL", + "target, ", + "gl", + "g;", + "GL_15_RENDERING", + "ANY_RENDERING", + "TWN_API ", + "GLuint", + "gl", + "GAME_OBJECT_H", + "const ", + "mesh_batch_item", + "buffer", + "GL", + "payload", + "sprite.", + "sprite", + "v", + "uv0", + "glBindBuffer", + "payload_size", + "push_to_vertex_buffer", + "batch.", + "dims", + "vertex_buffer", + "payload", + "..", + "TWN_GL_ANY_RENDERING_H", + "RENDERING_CIRCLES_H", + "RENDERING_H", + "set_camera", + "RENDER_BASE_WIDTH", + "static ", + "static t_matrix4 camera_projection_matrix;\n", + "font_data", + "static ", + "RENDERING_GL_GENERIC", + "static ", + "upload_quad_vertices", + "enum", + "утгь", + "render_rectangle", + "upload_quad_vertices", + "opengl_lo", + "opengl_log", + "glad", + "#if defined(EMSCRIPTEN)", + "#if defeined(EMSCRIPTEN)", + "EMSCRIPTEN", + "emscri", + "glad", + "CMAKE_EXECUTABLE_SUFFIX", + "unix", + "use", + "SDL2", + "include", + "sdl", + "textures_cache_deinit", + "Save", + "result", + "rmask", + "SDL_CreateRGBSurfaceFrom", + "CRY", + "#define STB", + "image_", + "TTF", + "SDL2", + "SDL2_ttf", + "TWN_TARGET", + "twn_third_parties", + "add_library", + "add_subdirectory", + "20", + "TWN_ARCHIVE_DATA", + "copy_if", + "TEXT_FONT_OVERSAMPLING", + "TEXT_FONT_FILTERING", + "linux", + "data", + "btw", + "TOWNENGINE_ARCHIVE_DATA", + "PACKAGE_EXTENSION", + "TOWNENGINE_DIR", + "compile", + "TOWNENGINE_BOOTSTRAP", + "bootstrap", + "set", + "bootstrap", + "_shared", + "_SHA", + "_shared", + "UNIX", + "link_deps", + "${target}", + "bind_quad_element_buffer", + "grass.gif", + "ptr_to_texture", + "textures_get_key", + "GAME_OBJECT_PATH", + "libgame", + "SOURCE_DIR" + ], + "highlight": true, + "in_selection": false, + "preserve_case": false, + "regex": false, + "replace_history": + [ + "#include \"twn_rendering_platform.h\"", + "#ifdef EMSCRIPTEN", + "state->ctx->", + "\"townengine/context.h\"", + "ctx.", + "use_tawnengine", + "\"internal_api.h\"", + "t_shvec", + "t_ushvec", + "_item" + ], + "reverse": false, + "scrollbar_highlights": true, + "show_context": true, + "use_buffer2": true, + "use_gitignore": true, + "whole_word": false, + "wrap": true + }, + "groups": + [ + { + "sheets": + [ + { + "buffer": 0, + "file": "include/twn_config.h", + "selected": true, + "semi_transient": false, + "settings": + { + "buffer_size": 972, + "regions": + { + }, + "selection": + [ + [ + 972, + 972 + ] + ], + "settings": + { + "auto_complete_triggers": + [ + { + "characters": "<", + "selector": "text.html, text.xml" + }, + { + "rhs_empty": true, + "selector": "punctuation.accessor" + }, + { + "characters": ".<>:\"/*", + "selector": "meta.tag, source - comment - string.quoted.double.block - string.quoted.single.block - string.unquoted.heredoc", + "server": "clangd" + } + ], + "lsp_active": true, + "lsp_uri": "file:///home/tochie/Code/townengine/include/twn_config.h", + "show_definitions": false, + "syntax": "Packages/C++/C++.sublime-syntax" + }, + "translation.x": 0.0, + "translation.y": 345.0, + "zoom_level": 1.0 + }, + "stack_index": 0, + "stack_multiselect": false, + "type": "text" + } + ] + }, + { + "sheets": + [ + { + "buffer": 1, + "file": "src/rendering/twn_triangles.c", + "semi_transient": false, + "settings": + { + "buffer_size": 2969, + "regions": + { + }, + "selection": + [ + [ + 118, + 118 + ] + ], + "settings": + { + "auto_complete_triggers": + [ + { + "characters": "<", + "selector": "text.html, text.xml" + }, + { + "rhs_empty": true, + "selector": "punctuation.accessor" + }, + { + "characters": ".<>:\"/*", + "selector": "meta.tag, source - comment - string.quoted.double.block - string.quoted.single.block - string.unquoted.heredoc", + "server": "clangd" + } + ], + "lsp_active": true, + "lsp_uri": "file:///home/tochie/Code/townengine/src/rendering/twn_triangles.c", + "show_definitions": false, + "syntax": "Packages/C++/C.sublime-syntax", + "tab_size": 4, + "translate_tabs_to_spaces": true + }, + "translation.x": 0.0, + "translation.y": 0.0, + "zoom_level": 1.0 + }, + "stack_index": 1, + "stack_multiselect": false, + "type": "text" + }, + { + "buffer": 2, + "file": "include/twn_vec.h", + "selected": true, + "semi_transient": true, + "settings": + { + "buffer_size": 4341, + "regions": + { + }, + "selection": + [ + [ + 0, + 0 + ] + ], + "settings": + { + "auto_complete_triggers": + [ + { + "characters": "<", + "selector": "text.html, text.xml" + }, + { + "rhs_empty": true, + "selector": "punctuation.accessor" + }, + { + "characters": ".<>:\"/*", + "selector": "meta.tag, source - comment - string.quoted.double.block - string.quoted.single.block - string.unquoted.heredoc", + "server": "clangd" + } + ], + "lsp_active": true, + "lsp_uri": "file:///home/tochie/Code/townengine/include/twn_vec.h", + "show_definitions": false, + "syntax": "Packages/C++/C++.sublime-syntax", + "tab_size": 4, + "translate_tabs_to_spaces": true + }, + "translation.x": 0.0, + "translation.y": 2952.0, + "zoom_level": 1.0 + }, + "stack_index": 0, + "stack_multiselect": false, + "type": "text" + } + ] + } + ], + "incremental_find": + { + "height": 32.0 + }, + "input": + { + "height": 70.0 + }, + "layout": + { + "cells": + [ + [ + 0, + 0, + 1, + 1 + ], + [ + 1, + 0, + 2, + 1 + ] + ], + "cols": + [ + 0.0, + 0.37740401568, + 1.0 + ], + "rows": + [ + 0.0, + 1.0 + ] + }, + "menu_visible": true, + "output.LSP Log Panel": + { + "height": 186.0 + }, + "output.diagnostics": + { + "height": 0.0 + }, + "output.find_results": + { + "height": 0.0 + }, + "output.mdpopups": + { + "height": 0.0 + }, + "pinned_build_system": "", + "project": "untitled.sublime-project", + "replace": + { + "height": 60.0 + }, + "save_all_on_build": true, + "select_file": + { + "height": 0.0, + "last_filter": "", + "selected_items": + [ + [ + "texture.c", + "townengine/textures/textures.c" + ], + [ + "loop", + "townengine/twn_loop.c" + ], + [ + "texture", + "townengine/textures/textures.c" + ], + [ + "input", + "townengine/input/input.c" + ], + [ + "twn_lo", + "townengine/twn_loop.c" + ], + [ + "twn", + "townengine/twn_loop.c" + ], + [ + "stb_image", + "third-party/stb/stb_image.h" + ], + [ + "ingame", + "apps/testgame/scenes/ingame.c" + ], + [ + "game", + "apps/testgame/game.c" + ], + [ + "title", + "apps/testgame/scenes/title.c" + ], + [ + "context", + "townengine/context.h" + ], + [ + "main", + "townengine/main.c" + ], + [ + "inga", + "apps/testgame/scenes/ingame.c" + ], + [ + "stb_ds", + "third-party/stb/stb_ds.h" + ], + [ + "ren", + "townengine/rendering.h" + ], + [ + "op", + "townengine/macros/option.h" + ], + [ + "var", + "townengine/macros/varargcount.h" + ], + [ + "sprite", + "townengine/rendering/sprites.h" + ], + [ + "vec", + "townengine/vec.h" + ], + [ + "internal", + "townengine/textures/internal_api.h" + ], + [ + "rendering", + "townengine/rendering.h" + ], + [ + "std_", + "third-party/stb/stb_ds.h" + ], + [ + "stb_per", + "third-party/stb/stb_perlin.h" + ], + [ + "phys", + "third-party/physfs/src/physfs.h" + ], + [ + "stb", + "third-party/stb/stb_truetype.h" + ], + [ + "text", + "src/textures/textures.c" + ], + [ + "render", + "src/rendering.c" + ], + [ + "camera", + "src/camera.h" + ], + [ + "camea", + "src/camera.c" + ], + [ + "rener", + "src/rendering.c" + ], + [ + "triang", + "src/rendering/triangles.h" + ], + [ + "textures", + "src/textures/textures.c" + ], + [ + "spri", + "src/rendering/sprites.h" + ], + [ + "config", + "src/config.h" + ], + [ + "cam.", + "third-party/cglm/src/cam.c" + ], + [ + "o", + "src/option.h" + ], + [ + "au", + "src/audio.h" + ], + [ + "mat", + "third-party/cglm/src/mat4.c" + ], + [ + "util", + "src/util.h" + ], + [ + "textu", + "src/textures.c" + ], + [ + "sprites", + "src/rendering/sprites.h" + ], + [ + "audio", + "src/audio.c" + ], + [ + "uti", + "src/util.h" + ], + [ + "contex", + "src/context.h" + ], + [ + "titl", + "src/game/scenes/title.c" + ], + [ + "glad", + "third-party/glad/include/glad/glad.h" + ], + [ + "in", + "src/input.c" + ], + [ + "con", + "src/context.h" + ], + [ + "ut", + "src/util.h" + ], + [ + "co", + "src/context.h" + ], + [ + "u", + "src/util.h" + ], + [ + "cmak", + "CMakeLists.txt" + ], + [ + "rende", + "src/rendering.c" + ], + [ + "cmake", + "CMakeLists.txt" + ], + [ + "conte", + "src/context.h" + ], + [ + "main.c", + "src/main.c" + ], + [ + "ma", + ".build/.cache/clangd/index/malloc.h.92A730905333FB35.idx" + ] + ], + "width": 0.0 + }, + "select_project": + { + "height": 0.0, + "last_filter": "", + "selected_items": + [ + ], + "width": 0.0 + }, + "select_symbol": + { + "height": 350.0, + "last_filter": "", + "selected_items": + [ + ], + "width": 592.0 + }, + "selected_group": 1, + "settings": + { + }, + "show_minimap": false, + "show_open_files": true, + "show_tabs": true, + "side_bar_visible": true, + "side_bar_width": 286.0, + "status_bar_visible": true, + "template_settings": + { + } +}