mirror of
				https://git.shylie.info/shylie/glerminal.git
				synced 2025-10-31 01:00:20 +00:00 
			
		
		
		
	Compare commits
	
		
			22 Commits
		
	
	
		
			996d14c93c
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| fb3eeb6ec9 | |||
| 263cf68ca2 | |||
| b8e616c8d6 | |||
| 1bfbab7a96 | |||
| d156005441 | |||
| 82389b8c12 | |||
| 0a9d211942 | |||
| 937693ce6a | |||
| 365cad551b | |||
| 5fbeb1e4e9 | |||
| 11ffc40bbb | |||
| db46885ee9 | |||
| 20fad92e4f | |||
| 7c0c02b9af | |||
| 1a1f4e8b13 | |||
|   | 6663804c88 | ||
|   | 9d88ebbb3b | ||
|   | 76bfd67f4e | ||
|   | 4811e4d970 | ||
|   | e402b5f5a3 | ||
|   | 139681a3fd | ||
|   | 45ec13db45 | 
| @@ -5,7 +5,7 @@ on: push | ||||
|  | ||||
| jobs: | ||||
|   build-app: | ||||
|     runs-on: linux_amd64 | ||||
|     runs-on: shy-server | ||||
|     steps: | ||||
|       - name: Checkout current | ||||
|         uses: actions/checkout@v4 | ||||
| @@ -20,7 +20,7 @@ jobs: | ||||
|           fetch-depth: 0 | ||||
|           submodules: recursive | ||||
|           lfs: true | ||||
|       - run: cd prev && git checkout 10a90a5f6a | ||||
|       - run: cd prev && git checkout 263cf68ca2 | ||||
|       - name: Build current | ||||
|         run: cmake -S curr -B curr/build -DGLERMINAL_TEST=ON && cmake --build curr/build | ||||
|       - name: Build previous | ||||
|   | ||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +1,4 @@ | ||||
| build/ | ||||
| cmake-build-*/ | ||||
| .idea/ | ||||
| .cache/ | ||||
|   | ||||
							
								
								
									
										5
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,3 @@ | ||||
| [submodule "glfw"] | ||||
| 	path = glfw | ||||
| 	url = https://git.shylie.info/shylie/glfw.git | ||||
| [submodule "Lua"] | ||||
| 	path = Lua | ||||
| 	url = https://git.shylie.info/shylie/Lua.git | ||||
| 	url = https://github.com/glfw/glfw.git | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| cmake_minimum_required(VERSION 3.28) | ||||
|  | ||||
| project(glerminal | ||||
| 	VERSION 0.1.0 | ||||
| 	LANGUAGES C CXX | ||||
|   VERSION 0.1.0 | ||||
|   LANGUAGES C CXX | ||||
| ) | ||||
|  | ||||
| option(GLERMINAL_OPENGL_DEBUG_CONTEXT "" OFF) | ||||
| @@ -11,72 +11,58 @@ set(GLERMINAL_GRID_WIDTH 40 CACHE STRING "") | ||||
| set(GLERMINAL_GRID_HEIGHT 25 CACHE STRING "") | ||||
| set(GLERMINAL_LAYER_COUNT 64 CACHE STRING "") | ||||
| set(GLERMINAL_CELL_SCALE 4 CACHE STRING "") | ||||
| set(GLERMINAL_CELL_SIZE 8 CACHE STRING "") | ||||
|  | ||||
| configure_file(source/glerminal-config.h.in glerminal-config.h @ONLY) | ||||
|  | ||||
| add_subdirectory(glfw) | ||||
| add_subdirectory(Lua) | ||||
|  | ||||
| add_library(glerminallib STATIC | ||||
| 	${CMAKE_CURRENT_BINARY_DIR}/glerminal-config.h | ||||
| 	include/glerminal.h | ||||
| add_library(glerminal STATIC | ||||
|   ${CMAKE_CURRENT_BINARY_DIR}/glerminal-config.h | ||||
|   include/glerminal.h | ||||
|  | ||||
| 	source/stb_image.h | ||||
| 	source/glerminal-private.h | ||||
| 	source/glerminal.cpp | ||||
|   source/stb_image.h | ||||
|   source/glerminal-private.h | ||||
|   source/glerminal.cpp | ||||
|  | ||||
| 	source/glad/glad.h | ||||
| 	source/KHR/khrplatform.h | ||||
| 	source/glad.c | ||||
|   source/glad/glad.h | ||||
|   source/KHR/khrplatform.h | ||||
|   source/glad.c | ||||
|  | ||||
|   source/miniaudio.h | ||||
|   source/miniaudio.c | ||||
| ) | ||||
|  | ||||
| set_target_properties(glerminallib | ||||
| 	PROPERTIES | ||||
| 		CXX_STANDARD 11 | ||||
| set_target_properties(glerminal | ||||
|   PROPERTIES | ||||
|     CXX_STANDARD 11 | ||||
| ) | ||||
|  | ||||
| target_include_directories(glerminallib | ||||
| 	PUBLIC | ||||
| 		include | ||||
| 		${CMAKE_CURRENT_BINARY_DIR} | ||||
| 	PRIVATE | ||||
| 		source | ||||
| ) | ||||
|  | ||||
| target_link_libraries(glerminallib | ||||
| 	PUBLIC | ||||
| 		glfw | ||||
| ) | ||||
|  | ||||
| target_compile_definitions(glerminallib | ||||
| 	PUBLIC | ||||
| 		GLERMINAL_VERSION=${PROJECT_VERSION} | ||||
| 		GLERMINAL_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} | ||||
| 		GLERMINAL_VERSION_MINOR=${PROJECT_VERSION_MINOR} | ||||
| 		GLERMINAL_VERSION_PATCH=${PROJECT_VERSION_PATCH} | ||||
| ) | ||||
|  | ||||
| if (MSVC) | ||||
| 	target_link_options(glerminallib | ||||
| 		PUBLIC | ||||
| 			"/ENTRY:mainCRTStartup" | ||||
| 	) | ||||
| endif() | ||||
|  | ||||
| add_executable(glerminal WIN32 | ||||
| 	source/glerminal-main.cpp | ||||
| target_include_directories(glerminal | ||||
|   PUBLIC | ||||
|     include | ||||
|     ${CMAKE_CURRENT_BINARY_DIR} | ||||
|   PRIVATE | ||||
|     source | ||||
| ) | ||||
|  | ||||
| target_link_libraries(glerminal | ||||
| 	PRIVATE | ||||
| 		glerminallib | ||||
| 		lua_static | ||||
|   PUBLIC | ||||
|     glfw | ||||
| ) | ||||
|  | ||||
| if (PROJECT_IS_TOP_LEVEL) | ||||
| 	add_subdirectory(examples examples) | ||||
| target_compile_definitions(glerminal | ||||
|   PUBLIC | ||||
|     GLERMINAL_VERSION=${PROJECT_VERSION} | ||||
|     GLERMINAL_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} | ||||
|     GLERMINAL_VERSION_MINOR=${PROJECT_VERSION_MINOR} | ||||
|     GLERMINAL_VERSION_PATCH=${PROJECT_VERSION_PATCH} | ||||
| ) | ||||
|  | ||||
| if(PROJECT_IS_TOP_LEVEL) | ||||
|   add_subdirectory(examples examples) | ||||
| endif() | ||||
|  | ||||
| if (GLERMINAL_TEST) | ||||
| 	add_subdirectory(tests tests) | ||||
| if(GLERMINAL_TEST) | ||||
|   add_subdirectory(tests tests) | ||||
| endif() | ||||
							
								
								
									
										1
									
								
								Lua
									
									
									
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								Lua
									
									
									
									
									
								
							 Submodule Lua deleted from 88246d621a
									
								
							
							
								
								
									
										37
									
								
								PROJECT_RETROSPECTIVE.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								PROJECT_RETROSPECTIVE.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| # A look back on what I learned | ||||
|  | ||||
| ## why? | ||||
|  | ||||
| I came across an art/rendering style called "sprite stacking". | ||||
| I found sprite stacking very interesting in comparison to traditional methods, | ||||
| and wanted to experiment with the style. | ||||
|  | ||||
| ## challenge | ||||
|  | ||||
| This was my first big graphics-based project. Computer graphics | ||||
| at the low-level was new to me. I took this as an opportunity to | ||||
| learn the basics of OpenGL. This learning process was the most | ||||
| difficult part of the project, especially the domain-specific | ||||
| rendering techniques used. | ||||
|  | ||||
| ## how? | ||||
|  | ||||
| I found some [great tutorials](https://learnopengl.com) to get started, | ||||
| and though these helped, I also did a lot of individual | ||||
| learning through experimentation and discussion with peers. | ||||
|  | ||||
| ## results | ||||
|  | ||||
| In the end, the library had most of the functionality | ||||
| I originally wanted. The library can draw up to 256 layers of icons in a grid, | ||||
| with optional offsets and tints per icon. Here's an example with only 7 library calls: | ||||
|  | ||||
|  | ||||
|  | ||||
| ## evaluation | ||||
|  | ||||
| Besides learning the basics of OpenGL, I also learned | ||||
| how to use CMake to help build the library. Also, I set up | ||||
| continuous integration for automated testing on a git commit. | ||||
| If I were to rewrite this library, I would definitely invest more | ||||
| into the automated testing process. | ||||
| @@ -1,2 +1,4 @@ | ||||
| # termg | ||||
| # glerminal | ||||
|  | ||||
| glerminal is a tile-based graphics library created | ||||
| with the intent to use a sprite-stacking art style. | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								example.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								example.gif
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 6.1 MiB | 
| @@ -36,5 +36,5 @@ list(TRANSFORM EXAMPLE_RESOURCES PREPEND ${CMAKE_CURRENT_BINARY_DIR}/) | ||||
| foreach(SOURCE_FILE ${EXAMPLE_SOURCES}) | ||||
| 	get_filename_component(SOURCE_FILENAME ${SOURCE_FILE} NAME_WLE) | ||||
| 	add_executable(${SOURCE_FILENAME} WIN32 ${SOURCE_FILE} ${EXAMPLE_RESOURCES}) | ||||
| 	target_link_libraries(${SOURCE_FILENAME} PRIVATE glerminallib) | ||||
| 	target_link_libraries(${SOURCE_FILENAME} PRIVATE glerminal) | ||||
| endforeach() | ||||
| @@ -9,9 +9,9 @@ namespace | ||||
| 		glerminal_load_sprites_file("resources/atlas.png"); | ||||
| 	} | ||||
|  | ||||
| 	void mainloop(float dt) | ||||
| 	void mainloop(double dt) | ||||
| 	{ | ||||
| 		static float time = 1; | ||||
| 		static double time = 1; | ||||
|  | ||||
| 		time += dt; | ||||
|  | ||||
| @@ -30,8 +30,8 @@ namespace | ||||
| 			{ | ||||
| 				for (int k = 0; k < LAYER_COUNT; k++) | ||||
| 				{ | ||||
| 					glerminal_set(i, j, k, rand() % 4); | ||||
| 					glerminal_offset(i, j, k, (rand() * rand()) % 64 - 32, (rand() * rand()) % 64 - 32); | ||||
| 					glerminal_set(i + 1, j + 1, k, rand() % 4); | ||||
| 					glerminal_offset(i + 1, j + 1, k, (rand() * rand()) % 64 - 32, (rand() * rand()) % 64 - 32); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| @@ -42,5 +42,5 @@ namespace | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
| 	glerminal_run(init, mainloop, nullptr, nullptr); | ||||
| 	glerminal_run({init, mainloop}); | ||||
| } | ||||
| @@ -9,25 +9,25 @@ namespace | ||||
| 	{ | ||||
| 		glerminal_load_sprites_file("resources/basic.png"); | ||||
|  | ||||
| 		for (int i = 0; i < GRID_WIDTH; i++) | ||||
| 		for (int i = 0; i < GRID_WIDTH + 2; i++) | ||||
| 		{ | ||||
| 			for (int j = 0; j < GRID_HEIGHT; j++) | ||||
| 			for (int j = 0; j < GRID_HEIGHT + 2; j++) | ||||
| 			{ | ||||
| 				glerminal_set(i, j, 0, 1); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void mainloop(float dt) | ||||
| 	void mainloop(double dt) | ||||
| 	{ | ||||
| 		static float time = 0; | ||||
| 		static double time = 0; | ||||
|  | ||||
| 		time += dt; | ||||
| 		time = fmodf(time, 3.1415926f * 2); | ||||
|  | ||||
| 		for (int i = 0; i < GRID_WIDTH; i++) | ||||
| 		for (int i = 0; i < GRID_WIDTH + 2; i++) | ||||
| 		{ | ||||
| 			for (int j = 0; j < GRID_HEIGHT; j++) | ||||
| 			for (int j = 0; j < GRID_HEIGHT + 2; j++) | ||||
| 			{ | ||||
| 				glerminal_offset(i, j, 0, cosf(time - i / 3.1415f), sinf(time - j / 3.1415f)); | ||||
| 			} | ||||
| @@ -39,5 +39,5 @@ namespace | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
| 	glerminal_run(init, mainloop, nullptr, nullptr); | ||||
| 	glerminal_run({init, mainloop}); | ||||
| } | ||||
| @@ -18,16 +18,16 @@ namespace | ||||
| 	{ | ||||
| 		glerminal_load_sprites_file("resources/rogue.png"); | ||||
|  | ||||
| 		for (int i = 0; i < GRID_WIDTH; i++) | ||||
| 		for (int i = 0; i < GRID_WIDTH + 2; i++) | ||||
| 		{ | ||||
| 			for (int j = 0; j < GRID_HEIGHT; j++) | ||||
| 			for (int j = 0; j < GRID_HEIGHT + 2; j++) | ||||
| 			{ | ||||
| 				for (int k = 0; k < WALL_LAYERS; k++) | ||||
| 				{ | ||||
| 					const unsigned char v = (k + 1) * (256 / WALL_LAYERS) - 1; | ||||
| 					const unsigned int c = (0xFF << 24) | (v << 16) | (v << 8) | v; | ||||
|  | ||||
| 					if (i == 0 || j == 0 || i == GRID_WIDTH - 1 || j == GRID_HEIGHT - 1) | ||||
| 					if (i == 1 || j == 1 || i == GRID_WIDTH || j == GRID_HEIGHT) | ||||
| 					{ | ||||
| 						glerminal_set(i, j, k, floor); | ||||
| 					} | ||||
| @@ -43,17 +43,17 @@ namespace | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void mainloop(float dt) | ||||
| 	void mainloop(double dt) | ||||
| 	{ | ||||
| 		static float time = 0; | ||||
| 		static double time = 0; | ||||
| 		time += dt; | ||||
|  | ||||
| 		const float cx = GRID_WIDTH / 2.0f * cosf(time / 2) + GRID_WIDTH / 2.0f; | ||||
| 		const float cy = GRID_HEIGHT / 2.0f * sinf(time / 2) + GRID_HEIGHT / 2.0f; | ||||
| 		const float cx = GRID_WIDTH / 2.0f * cosf(time / 2) + GRID_WIDTH / 2.0f + 0.5f; | ||||
| 		const float cy = GRID_HEIGHT / 2.0f * sinf(time / 2) + GRID_HEIGHT / 2.0f + 0.5f; | ||||
|  | ||||
| 		for (int i = 0; i < GRID_WIDTH; i++) | ||||
| 		for (int i = 0; i < GRID_WIDTH + 2; i++) | ||||
| 		{ | ||||
| 			for (int j = 0; j < GRID_HEIGHT; j++) | ||||
| 			for (int j = 0; j < GRID_HEIGHT + 2; j++) | ||||
| 			{ | ||||
| 				for (int k = 0; k < WALL_LAYERS; k++) | ||||
| 				{ | ||||
| @@ -80,5 +80,5 @@ namespace | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
| 	glerminal_run(init, mainloop, nullptr, nullptr); | ||||
| 	glerminal_run({init, mainloop}); | ||||
| } | ||||
| @@ -12,9 +12,9 @@ namespace | ||||
| 		glerminal_load_sprites_file("resources/towers.png"); | ||||
|  | ||||
|  | ||||
| 		for (int i = 0; i < GRID_WIDTH; i++) | ||||
| 		for (int i = 0; i < GRID_WIDTH + 2; i++) | ||||
| 		{ | ||||
| 			for (int j = 0; j < GRID_HEIGHT; j++) | ||||
| 			for (int j = 0; j < GRID_HEIGHT + 2; j++) | ||||
| 			{ | ||||
| 				const int c = rand() % (LAYER_COUNT * 3 / 4) + LAYER_COUNT / 4; | ||||
| 				for (int k = 0; k < c; k++) | ||||
| @@ -34,18 +34,18 @@ namespace | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void mainloop(float dt) | ||||
| 	void mainloop(double dt) | ||||
| 	{ | ||||
| 		static float time = 0; | ||||
| 		static double time = 0; | ||||
|  | ||||
| 		time += dt; | ||||
|  | ||||
| 		const float cx = (GRID_WIDTH / 2.0f) * cosf(time / 3.1415f) + (GRID_WIDTH / 2.0f); | ||||
| 		const float cy = (GRID_HEIGHT / 2.0f) * sinf(time / 3.1415f) + (GRID_HEIGHT / 2.0f); | ||||
| 		const float cx = (GRID_WIDTH / 2.0f) * cosf(time / 3.1415f) + (GRID_WIDTH / 2.0f) + 0.5f; | ||||
| 		const float cy = (GRID_HEIGHT / 2.0f) * sinf(time / 3.1415f) + (GRID_HEIGHT / 2.0f) + 0.5f; | ||||
|  | ||||
| 		for (int i = 0; i < GRID_WIDTH; i++) | ||||
| 		for (int i = 0; i < GRID_WIDTH + 2; i++) | ||||
| 		{ | ||||
| 			for (int j = 0; j < GRID_WIDTH; j++) | ||||
| 			for (int j = 0; j < GRID_WIDTH + 2; j++) | ||||
| 			{ | ||||
| 				for (int k = 0; k < LAYER_COUNT; k++) | ||||
| 				{ | ||||
| @@ -64,5 +64,5 @@ namespace | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
| 	glerminal_run(init, mainloop, nullptr, nullptr); | ||||
| 	glerminal_run({init, mainloop}); | ||||
| } | ||||
| @@ -9,17 +9,24 @@ extern "C" | ||||
| #endif | ||||
|  | ||||
| typedef void (*glerminal_init_cb)(); | ||||
| typedef void (*glerminal_main_cb)(float dt); | ||||
| typedef void (*glerminal_main_cb)(double dt); | ||||
| typedef void (*glerminal_keys_cb)(int key); | ||||
| typedef void (*glerminal_mousemoved_cb)(double x, double y); | ||||
| typedef void (*glerminal_mousepress_cb)(int button, double x, double y); | ||||
|  | ||||
| typedef struct { | ||||
|  glerminal_init_cb init; | ||||
|  glerminal_main_cb main; | ||||
|  glerminal_keys_cb keypress, keyrelease; | ||||
|  glerminal_mousemoved_cb moved; | ||||
|  glerminal_mousepress_cb mousepress, mouserelease; | ||||
| } glerminal_init_params; | ||||
|  | ||||
| /** | ||||
|  * @brief Call init once, then run the application's mainloop | ||||
|  * @param init initialization callback | ||||
|  * @param main main calllback | ||||
|  * @param pressed key pressed callback (can be null) | ||||
|  * @param released key released callback (can be null) | ||||
|  * @param params Initialization parameters | ||||
|  */ | ||||
| void glerminal_run(glerminal_init_cb init, glerminal_main_cb main, glerminal_keys_cb pressed, glerminal_keys_cb released); | ||||
| void glerminal_run(glerminal_init_params params); | ||||
|  | ||||
| void glerminal_quit(); | ||||
|  | ||||
| @@ -30,42 +37,46 @@ void glerminal_flush(); | ||||
|  | ||||
| /** | ||||
|  * @brief Set a cell's sprite | ||||
|  * @param x position of the cell in the range [0, 40) | ||||
|  * @param y position of the cell in the range [0, 25) | ||||
|  * @param layer layer of the cell in the range [0, 8) | ||||
|  * @param sprite sprite's index in the range [0, 256) | ||||
|  * @param x position of the cell in the range [0, GRID_WIDTH) | ||||
|  * @param y position of the cell in the range [0, GRID_HEIGHT) | ||||
|  * @param layer layer of the cell in the range [0, LAYER_COUNT) | ||||
|  * @param sprite sprite's index in the range [0, 4096) | ||||
|  */ | ||||
| void glerminal_set(unsigned char x, unsigned char y, unsigned char layer, unsigned short sprite); | ||||
| void glerminal_set(int x, int y, int layer, unsigned short sprite); | ||||
| /** | ||||
|  * @brief Get a cell's sprite | ||||
|  * @param x position of the cell in the range [0, 40) | ||||
|  * @param y position of the cell in the range [0, 25) | ||||
|  * @param layer layer of the cell in the range [0, 8) | ||||
|  * @param x position of the cell in the range [0, GRID_WIDTH) | ||||
|  * @param y position of the cell in the range [0, GRID_HEIGHT) | ||||
|  * @param layer layer of the cell in the range [0, LAYER_COUNT) | ||||
|  * @return sprite index currently assigned to the cell | ||||
|  */ | ||||
| unsigned char glerminal_get(unsigned char x, unsigned char y, unsigned short layer); | ||||
| unsigned short glerminal_get(int x, int y, int layer); | ||||
| /** | ||||
|  * @brief Set a cell's offset | ||||
|  * @param x position of the cell in the range [0, 40) | ||||
|  * @param y position of the cell in the range [0, 25) | ||||
|  * @param layer layer of the cell in the range [0, 8) | ||||
|  * @param x_offset offset of the cell on the x axis in the range [-128, 127], where 0 is no offset | ||||
|  * @param y_offset offset of the cell on the y axis in the range [-128, 127], where 0 is no offset | ||||
|  * @param x position of the cell in the range [0, GRID_WIDTH) | ||||
|  * @param y position of the cell in the range [0, GRID_HEIGHT) | ||||
|  * @param layer layer of the cell in the range [0, LAYER_COUNT) | ||||
|  * @param x_offset offset of the cell on the x axis in cells | ||||
|  * @param y_offset offset of the cell on the y axis in cells | ||||
|  */ | ||||
| void glerminal_offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset); | ||||
| void glerminal_offset(int x, int y, int layer, float x_offset, float y_offset); | ||||
|  | ||||
| /** | ||||
|  * @brief Set a layer's color | ||||
|  * @param layer The layer to modify | ||||
|  * @brief Set a cell's color | ||||
|  * @param x position of the cell in the range [0, GRID_WIDTH) | ||||
|  * @param y position of the cell in the range [0, GRID_HEIGHT) | ||||
|  * @param layer layer of the cell in the range [0, LAYER_COUNT) | ||||
|  * @param color The new color | ||||
|  */ | ||||
| void glerminal_color(unsigned char x, unsigned char y, unsigned char layer, unsigned int color); | ||||
| void glerminal_color(int x, int y, int layer, unsigned int color); | ||||
| /** | ||||
|  * @brief Set a layer's scale | ||||
|  * @param layer The layer to modify | ||||
|  * @brief Set a cell's scale | ||||
|  * @param x position of the cell in the range [0, GRID_WIDTH) | ||||
|  * @param y position of the cell in the range [0, GRID_HEIGHT) | ||||
|  * @param layer layer of the cell in the range [0, LAYER_COUNT) | ||||
|  * @param scale The new scale | ||||
|  */ | ||||
| void glerminal_scale(unsigned char x, unsigned char y, unsigned char layer, float scale); | ||||
| void glerminal_scale(int x, int y, int layer, float scale); | ||||
|  | ||||
| /** | ||||
|  * @brief Load sprites from a png file | ||||
| @@ -81,6 +92,8 @@ int glerminal_load_sprites_file(const char* filename); | ||||
|  */ | ||||
| int glerminal_load_sprites_buffer(unsigned char width, unsigned char height, const unsigned int* buffer); | ||||
|  | ||||
| void glerminal_sound(const char* name); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|   | ||||
| @@ -1,29 +0,0 @@ | ||||
| local time = 0 | ||||
|  | ||||
| function glerminal.init() | ||||
|     if not glerminal.sprites('sprites.png') then | ||||
|         print('failed to load sprites') | ||||
|     end | ||||
|  | ||||
|     for i = 1, 40 do | ||||
|         for j = 1, 25 do | ||||
|             glerminal.set(i, j, 1, 2) | ||||
|         end | ||||
|     end | ||||
|  | ||||
|     glerminal.tint(1, 0xA0FFFFFF) | ||||
|  | ||||
|     glerminal.flush() | ||||
| end | ||||
|  | ||||
| function glerminal.main(dt) | ||||
|     time = time + dt / 2 | ||||
|  | ||||
|     for i = 1, 40 do | ||||
|         for j = 1, 25 do | ||||
|             glerminal.offset(i, j, 1, math.cos(time * i / math.pi), math.sin(time * j / math.pi)) | ||||
|         end | ||||
|     end | ||||
|  | ||||
|     glerminal.flush() | ||||
| end | ||||
| @@ -1,3 +0,0 @@ | ||||
| version https://git-lfs.github.com/spec/v1 | ||||
| oid sha256:6dee3efcdfa72e54a602f69643907bb8e8a3328d2b40c2116dce22ff179d8892 | ||||
| size 182 | ||||
| @@ -16,7 +16,8 @@ enum | ||||
| 	GRID_WIDTH = @GLERMINAL_GRID_WIDTH@, | ||||
| 	GRID_HEIGHT = @GLERMINAL_GRID_HEIGHT@, | ||||
| 	LAYER_COUNT = @GLERMINAL_LAYER_COUNT@, | ||||
| 	CELL_SCALE = @GLERMINAL_CELL_SCALE@ | ||||
| 	CELL_SCALE = @GLERMINAL_CELL_SCALE@, | ||||
| 	CELL_SIZE = @GLERMINAL_CELL_SIZE@ | ||||
| }; | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|   | ||||
| @@ -1,241 +0,0 @@ | ||||
| #include <glerminal.h> | ||||
| #define GLFW_INCLUDE_NONE | ||||
| #include <GLFW/glfw3.h> | ||||
|  | ||||
| extern "C" | ||||
| { | ||||
| #include <lualib.h> | ||||
| #include <lauxlib.h> | ||||
| } | ||||
|  | ||||
| #include <iostream> | ||||
| #include <string> | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| #define WINDOWS_LEAN_AND_MEAN | ||||
| #include <Windows.h> | ||||
| #define CHANGE_WORKING_DIRECTORY(path) !(SetCurrentDirectory(path)) | ||||
| #else | ||||
| #include <unistd.h> | ||||
| #define CHANGE_WORKING_DIRECTORY(path) chdir(path) | ||||
| #endif | ||||
|  | ||||
| namespace | ||||
| { | ||||
| 	int lglerminal_quit(lua_State* L) | ||||
| 	{ | ||||
| 		glerminal_quit(); | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	int lglerminal_flush(lua_State* L) | ||||
| 	{ | ||||
| 		glerminal_flush(); | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	int lglerminal_set(lua_State* L) | ||||
| 	{ | ||||
| 		const unsigned char x = luaL_checkinteger(L, 1) - 1; | ||||
| 		const unsigned char y = luaL_checkinteger(L, 2) - 1; | ||||
| 		const unsigned char layer = luaL_checkinteger(L, 3) - 1; | ||||
| 		const unsigned short sprite = luaL_checkinteger(L, 4) - 1; | ||||
| 		glerminal_set(x, y, layer, sprite); | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	int lglerminal_get(lua_State* L) | ||||
| 	{ | ||||
| 		const unsigned char x = luaL_checkinteger(L, 1) - 1; | ||||
| 		const unsigned char y = luaL_checkinteger(L, 2) - 1; | ||||
| 		const unsigned char layer = luaL_checkinteger(L, 3) - 1; | ||||
| 		lua_pushnumber(L, glerminal_get(x, y, layer) + 1); | ||||
|  | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	int lglerminal_offset(lua_State* L) | ||||
| 	{ | ||||
| 		const unsigned char x = luaL_checkinteger(L, 1) - 1; | ||||
| 		const unsigned char y = luaL_checkinteger(L, 2) - 1; | ||||
| 		const unsigned char layer = luaL_checkinteger(L, 3) - 1; | ||||
| 		const float ox = luaL_checknumber(L, 4); | ||||
| 		const float oy = luaL_checknumber(L, 5); | ||||
| 		glerminal_offset(x, y, layer, ox, oy); | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	int lglerminal_layer_color(lua_State* L) | ||||
| 	{ | ||||
| 		const unsigned char x = luaL_checkinteger(L, 1) - 1; | ||||
| 		const unsigned char y = luaL_checkinteger(L, 2) - 1; | ||||
| 		const unsigned char layer = luaL_checkinteger(L, 3) - 1; | ||||
| 		const unsigned int color = luaL_checkinteger(L, 4); | ||||
| 		glerminal_color(x, y, layer, color); | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	int lglerminal_layer_scale(lua_State* L) | ||||
| 	{ | ||||
| 		const unsigned char x = luaL_checkinteger(L, 1) - 1; | ||||
| 		const unsigned char y = luaL_checkinteger(L, 2) - 1; | ||||
| 		const unsigned char layer = luaL_checkinteger(L, 3) - 1; | ||||
| 		const float scale = luaL_checknumber(L, 4); | ||||
| 		glerminal_scale(x, y, layer, scale); | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	int lglerminal_load_sprites_file(lua_State* L) | ||||
| 	{ | ||||
| 		const char* path = luaL_checkstring(L, 1); | ||||
| 		lua_pushboolean(L, glerminal_load_sprites_file(path)); | ||||
|  | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	const luaL_Reg lglerminal_methods[] = | ||||
| 	{ | ||||
| 		{ "quit",    lglerminal_quit }, | ||||
| 		{ "flush",   lglerminal_flush }, | ||||
| 		{ "set",     lglerminal_set }, | ||||
| 		{ "get",     lglerminal_get }, | ||||
| 		{ "offset",  lglerminal_offset }, | ||||
| 		{ "tint",    lglerminal_layer_color }, | ||||
| 		{ "scale",   lglerminal_layer_scale }, | ||||
| 		{ "sprites", lglerminal_load_sprites_file }, | ||||
| 		{ nullptr,   nullptr } | ||||
| 	}; | ||||
|  | ||||
| 	int message_handler(lua_State* L) | ||||
| 	{ | ||||
| 		luaL_traceback(L, L, lua_tostring(L, -1), 1); | ||||
| 		lua_remove(L, -2); | ||||
|  | ||||
| 		glerminal_quit(); | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	lua_State* L; | ||||
|  | ||||
| 	void init() | ||||
| 	{ | ||||
| 		lua_pushcfunction(L, message_handler); | ||||
| 		const int handler = lua_gettop(L); | ||||
| 		lua_getglobal(L, "glerminal"); | ||||
| 		lua_getfield(L, -1, "init"); | ||||
| 		lua_remove(L, -2); | ||||
| 		if (lua_pcall(L, 0, 0, handler) != LUA_OK) | ||||
| 		{ | ||||
| 			std::cout << lua_tostring(L, -1) << std::endl; | ||||
| 			lua_pop(L, 1); | ||||
| 		} | ||||
| 		lua_remove(L, handler); | ||||
| 	} | ||||
|  | ||||
| 	void mainloop(float dt) | ||||
| 	{ | ||||
| 		lua_pushcfunction(L, message_handler); | ||||
| 		const int handler = lua_gettop(L); | ||||
| 		lua_getglobal(L, "glerminal"); | ||||
| 		lua_getfield(L, -1, "main"); | ||||
| 		lua_remove(L, -2); | ||||
| 		lua_pushnumber(L, dt); | ||||
| 		if (lua_pcall(L, 1, 0, handler) != LUA_OK) | ||||
| 		{ | ||||
| 			std::cout << lua_tostring(L, -1) << std::endl; | ||||
| 			lua_pop(L, 1); | ||||
| 		} | ||||
| 		lua_remove(L, handler); | ||||
| 	} | ||||
|  | ||||
| 	void pressed(int key) | ||||
| 	{ | ||||
| 		const char* const name = glfwGetKeyName(key, 0); | ||||
| 		if (name) | ||||
| 		{ | ||||
| 			lua_pushcfunction(L, message_handler); | ||||
| 			const int handler = lua_gettop(L); | ||||
| 			lua_getglobal(L, "glerminal"); | ||||
| 			lua_getfield(L, -1, "pressed"); | ||||
| 			lua_remove(L, -2); | ||||
| 			lua_pushstring(L, name); | ||||
| 			if (lua_pcall(L, 1, 0, handler) != LUA_OK) | ||||
| 			{ | ||||
| 				std::cout << lua_tostring(L, -1) << std::endl; | ||||
| 				lua_pop(L, 1); | ||||
| 			} | ||||
| 			lua_remove(L, handler); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void released(int key) | ||||
| 	{ | ||||
| 		const char* const name = glfwGetKeyName(key, 0); | ||||
| 		if (name) | ||||
| 		{ | ||||
| 			lua_pushcfunction(L, message_handler); | ||||
| 			const int handler = lua_gettop(L); | ||||
| 			lua_getglobal(L, "glerminal"); | ||||
| 			lua_getfield(L, -1, "released"); | ||||
| 			lua_remove(L, -2); | ||||
| 			lua_pushstring(L, name); | ||||
| 			if (lua_pcall(L, 1, 0, handler) != LUA_OK) | ||||
| 			{ | ||||
| 				std::cout << lua_tostring(L, -1) << std::endl; | ||||
| 				lua_pop(L, 1); | ||||
| 			} | ||||
| 			lua_remove(L, handler); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
| 	if (argc == 1) | ||||
| 	{ | ||||
| 		std::cout << "Usage: " << argv[0] << " <project directory>" << std::endl; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (CHANGE_WORKING_DIRECTORY(argv[1])) | ||||
| 	{ | ||||
| 		std::cout << "Failed to find project directory" << std::endl; | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	L = luaL_newstate(); | ||||
| 	luaL_openlibs(L); | ||||
|  | ||||
| 	luaL_newlib(L, lglerminal_methods); | ||||
| 	lua_setglobal(L, "glerminal"); | ||||
|  | ||||
| 	lua_pushcfunction(L, message_handler); | ||||
| 	const int handler = lua_gettop(L); | ||||
| 	if (luaL_loadfile(L, "main.lua") != LUA_OK) | ||||
| 	{ | ||||
| 		const char* str = lua_tostring(L, -1); | ||||
| 		std::cout << str << std::endl; | ||||
| 		lua_pop(L, 1); | ||||
| 	} | ||||
| 	else if (lua_pcall(L, 0, LUA_MULTRET, handler) != LUA_OK) | ||||
| 	{ | ||||
| 		const char* str = lua_tostring(L, -1); | ||||
| 		std::cout << str << std::endl; | ||||
| 		lua_pop(L, 1); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		glerminal_run(init, mainloop, pressed, released); | ||||
| 	} | ||||
|  | ||||
| 	lua_close(L); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -2,32 +2,36 @@ | ||||
| #define GLERMINAL_PRIVATE_H | ||||
|  | ||||
| #include "glerminal.h" | ||||
| #include "miniaudio.h" | ||||
|  | ||||
| #include <stb_image.h> | ||||
| #include <glad/glad.h> | ||||
| #include <GLFW/glfw3.h> | ||||
|  | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| #include <stdexcept> | ||||
| #include <map> | ||||
| #include <string> | ||||
|  | ||||
| namespace glerminal | ||||
| { | ||||
| 	constexpr unsigned int CELL_SIZE = 8; | ||||
| 	constexpr unsigned int MAX_SPRITES_ROW = 64; | ||||
| 	constexpr unsigned int MAX_SPRITES = MAX_SPRITES_ROW * MAX_SPRITES_ROW; | ||||
| 	constexpr unsigned int GRID_WIDTH = ::GRID_WIDTH; | ||||
| 	constexpr unsigned int GRID_HEIGHT = ::GRID_HEIGHT; | ||||
| 	constexpr unsigned int LAYER_COUNT = ::LAYER_COUNT; | ||||
| 	constexpr unsigned int CELL_SCALE = ::CELL_SCALE; | ||||
| 	constexpr unsigned int CELL_SIZE = ::CELL_SIZE; | ||||
| 	constexpr unsigned int GRID_AREA = GRID_WIDTH * GRID_HEIGHT; | ||||
| 	constexpr unsigned int SCREEN_WIDTH = GRID_WIDTH * CELL_SIZE * CELL_SCALE; | ||||
| 	constexpr unsigned int SCREEN_HEIGHT = GRID_HEIGHT * CELL_SIZE * CELL_SCALE; | ||||
| 	constexpr unsigned int SOUND_CHANNELS = 8; | ||||
|  | ||||
| 	constexpr unsigned int GRID_AREA_2 = (GRID_WIDTH + 2) * (GRID_HEIGHT + 2); | ||||
|  | ||||
| 	class glerminal | ||||
| 	{ | ||||
| 	public: | ||||
| 		glerminal(glerminal_init_cb init, glerminal_main_cb main, glerminal_keys_cb pressed, glerminal_keys_cb released); | ||||
| 		explicit glerminal(glerminal_init_params params); | ||||
| 		~glerminal(); | ||||
|  | ||||
| 		glerminal(const glerminal&) = delete; | ||||
| @@ -41,12 +45,14 @@ namespace glerminal | ||||
|  | ||||
| 		void flush(); | ||||
|  | ||||
| 		void set(unsigned char x, unsigned char y, unsigned char layer, unsigned short sprite); | ||||
| 		unsigned short get(unsigned char x, unsigned char y, unsigned char layer) const; | ||||
| 		void offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset); | ||||
| 		void color(unsigned char x, unsigned char y, unsigned char layer, unsigned int color); | ||||
| 		void scale(unsigned char x, unsigned char y, unsigned char layer, float scale); | ||||
| 		void set(int x, int y, int layer, unsigned short sprite); | ||||
| 		unsigned short get(int x, int y, int layer) const; | ||||
| 		void offset(int x, int y, int layer, float x_offset, float y_offset); | ||||
| 		void color(int x, int y, int layer, unsigned int color); | ||||
| 		void scale(int x,int y, int layer, float scale); | ||||
| 		void load_atlas(unsigned char w, unsigned char h, const unsigned int* data); | ||||
| 		bool load_sound(const char* name); | ||||
| 		void play_sound(const char* name); | ||||
|  | ||||
| 	private: | ||||
| 		// glfw data | ||||
| @@ -69,21 +75,24 @@ namespace glerminal | ||||
| 		unsigned int m_screen_framebuffer_backing_texture; | ||||
| 		unsigned int m_colors_instance_vbo; | ||||
| 		unsigned int m_scales_instance_vbo; | ||||
| 		unsigned int m_screen_size_uniform_location; | ||||
| 		unsigned int m_palette_uniform_location; | ||||
|  | ||||
| 		// per-cell data | ||||
|  | ||||
| 		unsigned short m_cells[GRID_AREA * LAYER_COUNT]; | ||||
| 		float m_offsets[GRID_AREA * LAYER_COUNT * 2]; | ||||
| 		unsigned char m_colors[GRID_AREA * LAYER_COUNT * 4]; | ||||
| 		float m_scales[GRID_AREA * LAYER_COUNT]; | ||||
| 		unsigned short m_cells[GRID_AREA_2 * LAYER_COUNT]; | ||||
| 		float m_offsets[GRID_AREA_2 * LAYER_COUNT * 2]; | ||||
| 		unsigned char m_colors[GRID_AREA_2 * LAYER_COUNT * 4]; | ||||
| 		float m_scales[GRID_AREA_2 * LAYER_COUNT]; | ||||
|  | ||||
| 		// library state | ||||
|  | ||||
| 		unsigned int m_sprites[(CELL_SIZE + 2) * (CELL_SIZE + 2) * MAX_SPRITES]; | ||||
| 		glerminal_main_cb m_main; | ||||
| 		glerminal_keys_cb m_pressed, m_released; | ||||
| 		glerminal_keys_cb m_keypressed, m_keyreleased; | ||||
| 		glerminal_mousemoved_cb m_mousemoved; | ||||
| 		glerminal_mousepress_cb m_mousepressed, m_mousereleased; | ||||
|  | ||||
| 		ma_engine m_audio_engine; | ||||
| 		std::map<std::string, ma_sound> m_sounds; | ||||
|  | ||||
| #ifdef GLERMINAL_OPENGL_DEBUG_CONTEXT | ||||
| 		mutable std::ofstream m_log; | ||||
| @@ -93,14 +102,20 @@ namespace glerminal | ||||
| 		void init_glfw(); | ||||
| 		void init_gl(); | ||||
|  | ||||
| 		void init_audio(); | ||||
|  | ||||
| 		void deinit_glfw(); | ||||
| 		void deinit_gl(); | ||||
|  | ||||
| 		void deinit_audio(); | ||||
|  | ||||
| 		void update_sprites(); | ||||
| 		void update_colors(); | ||||
| 		void update_scales(); | ||||
|  | ||||
| 		static void glfw_key_handler(GLFWwindow* window, int key, int scancode, int action, int mods); | ||||
| 		static void glfw_mousemoved_handler(GLFWwindow* window, double x, double y); | ||||
| 		static void glfw_mousepress_handler(GLFWwindow* window, int button, int action, int mods); | ||||
| 	}; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| #define STB_IMAGE_IMPLEMENTATION | ||||
| #define STBI_ONLY_PNG | ||||
| #define STBI_MAX_DIMENSIONS 512 | ||||
| #define STBI_MAX_DIMENSIONS 2048 | ||||
| #include "glerminal-private.h" | ||||
|  | ||||
| #define GRID_SIZE_UNIFORM_NAME "grid_size" | ||||
| @@ -8,6 +8,7 @@ | ||||
| #define LAYERS_UNIFORM_NAME "layers" | ||||
| #define LAYER_COUNT_UNIFORM_NAME "layer_count" | ||||
| #define ATLAS_WIDTH_UNIFORM_NAME "atlas_width" | ||||
| #define CELL_SIZE_UNIFORM_NAME "cell_size" | ||||
|  | ||||
| namespace | ||||
| { | ||||
| @@ -33,6 +34,7 @@ namespace | ||||
| 		"layout (location = 2) in int sprite;\n" | ||||
| 		"layout (location = 3) in vec4 color;\n" | ||||
| 		"layout (location = 4) in float scale;\n" | ||||
| 		"uniform float " CELL_SIZE_UNIFORM_NAME ";\n" | ||||
| 		"uniform vec4 " GRID_SIZE_UNIFORM_NAME ";\n" | ||||
| 		"uniform int " ATLAS_WIDTH_UNIFORM_NAME ";\n" | ||||
| 		"out VS_OUT {\n" | ||||
| @@ -48,9 +50,9 @@ namespace | ||||
| 		"	vs_out.sprite = sprite;\n" | ||||
| 		"	vs_out.layer = layer;\n" | ||||
| 		"	vs_out.layer_color = color;\n" | ||||
| 		"	vs_out.texcoord = vec2(sprite % " ATLAS_WIDTH_UNIFORM_NAME " + position.x + 1, (sprite / " ATLAS_WIDTH_UNIFORM_NAME ") - position.y) / vec2(" ATLAS_WIDTH_UNIFORM_NAME ") + vec2(-(2 * position.x + 1) * " GRID_SIZE_UNIFORM_NAME ".z / 16, (2 * position.y + 1) * " GRID_SIZE_UNIFORM_NAME ".z / 16);\n" | ||||
| 		"	vec2 cell_position = vec2(scale + (gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) - " GRID_SIZE_UNIFORM_NAME ".x * floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) * " GRID_SIZE_UNIFORM_NAME ".z), -floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) * " GRID_SIZE_UNIFORM_NAME ".z));\n" | ||||
| 		"	vec2 temp = ((position + vec2(-0.5, 0.5)) * scale + cell_position + vec2(0.5, -0.5)) * " GRID_SIZE_UNIFORM_NAME ".zw * 2 + vec2(-1, 1);\n" | ||||
| 		"	vs_out.texcoord = vec2(sprite % " ATLAS_WIDTH_UNIFORM_NAME " + position.x + 1, (sprite / " ATLAS_WIDTH_UNIFORM_NAME ") - position.y) / vec2(" ATLAS_WIDTH_UNIFORM_NAME ") + vec2(-(2 * position.x + 1) * " GRID_SIZE_UNIFORM_NAME ".z / (2 * " CELL_SIZE_UNIFORM_NAME "), (2 * position.y + 1) * " GRID_SIZE_UNIFORM_NAME ".z / (2 * " CELL_SIZE_UNIFORM_NAME "));\n" | ||||
| 		"	vec2 cell_position = vec2(scale + (gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) - " GRID_SIZE_UNIFORM_NAME ".x * floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) / " GRID_SIZE_UNIFORM_NAME ".x), -floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) / " GRID_SIZE_UNIFORM_NAME ".x));\n" | ||||
| 		"	vec2 temp = ((position + vec2(-0.5, 0.5)) * scale + cell_position + vec2(-0.5, 0.5)) * " GRID_SIZE_UNIFORM_NAME ".zw * 2 + vec2(-1, 1);\n" | ||||
| 		"	gl_Position = vec4(scaled_offset.x + temp.x, scaled_offset.y - temp.y, 0, 1);\n" | ||||
| 		"}"; | ||||
|  | ||||
| @@ -64,6 +66,7 @@ namespace | ||||
| 		"layout (location = 2) in int sprite;\n" | ||||
| 		"layout (location = 3) in vec4 color;\n" | ||||
| 		"layout (location = 4) in float scale;\n" | ||||
| 		"uniform float " CELL_SIZE_UNIFORM_NAME ";\n" | ||||
| 		"uniform vec4 " GRID_SIZE_UNIFORM_NAME ";\n" | ||||
| 		"uniform int " ATLAS_WIDTH_UNIFORM_NAME ";\n" | ||||
| 		"out VS_OUT {\n" | ||||
| @@ -77,10 +80,10 @@ namespace | ||||
| 		"	gl_Layer = layer;\n" | ||||
| 		"	vec2 scaled_offset = 2 * offset * " GRID_SIZE_UNIFORM_NAME ".zw;\n" | ||||
| 		"	vs_out.sprite = sprite;\n" | ||||
| 		"	vs_out.texcoord = vec2(sprite % " ATLAS_WIDTH_UNIFORM_NAME " + position.x + 1, (sprite / " ATLAS_WIDTH_UNIFORM_NAME ") - position.y) / vec2(" ATLAS_WIDTH_UNIFORM_NAME ") + vec2(-(2 * position.x + 1) * " GRID_SIZE_UNIFORM_NAME ".z / 16, (2 * position.y + 1) * " GRID_SIZE_UNIFORM_NAME ".z / 16);\n" | ||||
| 		"	vs_out.texcoord = vec2(sprite % " ATLAS_WIDTH_UNIFORM_NAME " + position.x + 1, (sprite / " ATLAS_WIDTH_UNIFORM_NAME ") - position.y) / vec2(" ATLAS_WIDTH_UNIFORM_NAME ") + vec2(-(2 * position.x + 1) * " GRID_SIZE_UNIFORM_NAME ".z / (2 * " CELL_SIZE_UNIFORM_NAME "), (2 * position.y + 1) * " GRID_SIZE_UNIFORM_NAME ".z / (2 * " CELL_SIZE_UNIFORM_NAME "));\n" | ||||
| 		"	vs_out.layer_color = color;\n" | ||||
| 		"	vec2 cell_position = vec2(scale + (gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) - " GRID_SIZE_UNIFORM_NAME ".x * floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) * " GRID_SIZE_UNIFORM_NAME ".z), -floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) * " GRID_SIZE_UNIFORM_NAME ".z));\n" | ||||
| 		"	vec2 temp = ((position + vec2(-0.5, 0.5)) * scale + cell_position + vec2(0.5, -0.5)) * " GRID_SIZE_UNIFORM_NAME ".zw * 2 + vec2(-1, 1);\n" | ||||
| 		"	vec2 cell_position = vec2(scale + (gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) - " GRID_SIZE_UNIFORM_NAME ".x * floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) / " GRID_SIZE_UNIFORM_NAME ".x), -floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) / " GRID_SIZE_UNIFORM_NAME ".x));\n" | ||||
| 		"	vec2 temp = ((position + vec2(-0.5, 0.5)) * scale + cell_position + vec2(-0.5, 0.5)) * " GRID_SIZE_UNIFORM_NAME ".zw * 2 + vec2(-1, 1);\n" | ||||
| 		"	gl_Position = vec4(scaled_offset.x + temp.x, scaled_offset.y - temp.y, 0, 1);\n" | ||||
| 		"}"; | ||||
|  | ||||
| @@ -189,10 +192,13 @@ namespace | ||||
|  | ||||
| namespace glerminal | ||||
| { | ||||
| 	glerminal::glerminal(glerminal_init_cb init, glerminal_main_cb main, glerminal_keys_cb pressed, glerminal_keys_cb released) : | ||||
| 		m_main(main), | ||||
| 		m_pressed(pressed), | ||||
| 		m_released(released), | ||||
| 	glerminal::glerminal(glerminal_init_params params) : | ||||
| 		m_main(params.main), | ||||
| 		m_keypressed(params.keypress), | ||||
| 		m_keyreleased(params.keyrelease), | ||||
| 		m_mousemoved(params.moved), | ||||
| 		m_mousepressed(params.mousepress), | ||||
| 		m_mousereleased(params.mouserelease), | ||||
| 		m_cells{ }, | ||||
| 		m_offsets{ }, | ||||
| 		m_sprites{ }, | ||||
| @@ -208,7 +214,7 @@ namespace glerminal | ||||
| 		} | ||||
|  | ||||
| 		// unsure if this should be an error | ||||
| 		if (!init) | ||||
| 		if (!params.init) | ||||
| 		{ | ||||
| 			throw std::runtime_error("No init callback provided."); | ||||
| 		} | ||||
| @@ -218,7 +224,7 @@ namespace glerminal | ||||
| 			throw std::runtime_error("No main callback provided."); | ||||
| 		} | ||||
|  | ||||
| 		for (int i = 0; i < GRID_AREA * LAYER_COUNT; i++) | ||||
| 		for (int i = 0; i < GRID_AREA_2 * LAYER_COUNT; i++) | ||||
| 		{ | ||||
| 			m_colors[i * 4 + 0] = m_colors[i * 4 + 1] = m_colors[i * 4 + 2] = m_colors[i * 4 + 3] = 255; | ||||
| 			m_scales[i] = 1; | ||||
| @@ -226,14 +232,16 @@ namespace glerminal | ||||
|  | ||||
| 		init_glfw(); | ||||
| 		init_gl(); | ||||
| 		init_audio(); | ||||
|  | ||||
| 		GLERMINAL_G = this; | ||||
|  | ||||
| 		init(); | ||||
| 		params.init(); | ||||
| 	} | ||||
|  | ||||
| 	glerminal::~glerminal() | ||||
| 	{ | ||||
| 		deinit_audio(); | ||||
| 		deinit_gl(); | ||||
| 		deinit_glfw(); | ||||
|  | ||||
| @@ -242,12 +250,12 @@ namespace glerminal | ||||
|  | ||||
| 	void glerminal::run() | ||||
| 	{ | ||||
| 		float last = glfwGetTime(); | ||||
| 		double last = glfwGetTime(); | ||||
| 		while (!glfwWindowShouldClose(m_window)) | ||||
| 		{ | ||||
| 			glfwPollEvents(); | ||||
|  | ||||
| 			const float current = glfwGetTime(); | ||||
| 			const double current = glfwGetTime(); | ||||
|  | ||||
| 			m_main(current - last); | ||||
|  | ||||
| @@ -272,7 +280,7 @@ namespace glerminal | ||||
| 		glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); | ||||
| 		glBindVertexArray(m_vao); | ||||
| 		glClear(GL_COLOR_BUFFER_BIT); | ||||
| 		glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_AREA * LAYER_COUNT); | ||||
| 		glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_AREA_2 * LAYER_COUNT); | ||||
|  | ||||
| 		glUseProgram(m_screen_program); | ||||
| 		glBindFramebuffer(GL_FRAMEBUFFER, m_screen_framebuffer); | ||||
| @@ -280,28 +288,25 @@ namespace glerminal | ||||
| 		glClear(GL_COLOR_BUFFER_BIT); | ||||
| 		glDrawArrays(GL_TRIANGLES, 0, 6); | ||||
|  | ||||
|     glBindFramebuffer(GL_FRAMEBUFFER, 0); | ||||
|     glClear(GL_COLOR_BUFFER_BIT); | ||||
| 		glBlitNamedFramebuffer(m_screen_framebuffer, 0, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST); | ||||
|  | ||||
| 		glfwSwapInterval(0); | ||||
| 		glfwSwapBuffers(m_window); | ||||
| 		glBlitNamedFramebuffer(m_screen_framebuffer, 0, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST); | ||||
| 		glfwSwapInterval(1); | ||||
| 		glfwSwapBuffers(m_window); | ||||
| 	} | ||||
|  | ||||
| 	void glerminal::set(unsigned char x, unsigned char y, unsigned char layer, unsigned short sprite) | ||||
| 	void glerminal::set(int x, int y, int layer, unsigned short sprite) | ||||
| 	{ | ||||
| 		if (x < GRID_WIDTH && y < GRID_HEIGHT && layer < LAYER_COUNT) | ||||
| 		if (x >= 0 && x < GRID_WIDTH + 2 && y >= 0 && y < GRID_HEIGHT + 2 && layer >= 0 && layer < LAYER_COUNT) | ||||
| 		{ | ||||
| 			m_cells[x + y * GRID_WIDTH + layer * GRID_AREA] = sprite; | ||||
| 			m_cells[x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2] = sprite; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	unsigned short glerminal::get(unsigned char x, unsigned char y, unsigned char layer) const | ||||
| 	unsigned short glerminal::get(int x, int y, int layer) const | ||||
| 	{ | ||||
| 		if (x < GRID_WIDTH && y < GRID_HEIGHT && layer < LAYER_COUNT) | ||||
| 		if (x >= 0 && x < GRID_WIDTH + 2 && y >= 0 && y < GRID_HEIGHT + 2 && layer >= 0 && layer < LAYER_COUNT) | ||||
| 		{ | ||||
| 			return m_cells[x + y * GRID_WIDTH + layer * GRID_AREA]; | ||||
| 			return m_cells[x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2]; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| @@ -309,26 +314,32 @@ namespace glerminal | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void glerminal::offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset) | ||||
| 	void glerminal::offset(int x, int y, int layer, float x_offset, float y_offset) | ||||
| 	{ | ||||
| 		if (x < GRID_WIDTH && y < GRID_HEIGHT && layer < LAYER_COUNT) | ||||
| 		if (x >= 0 && x < GRID_WIDTH + 2 && y >= 0 && y < GRID_HEIGHT + 2 && layer >= 0 && layer < LAYER_COUNT) | ||||
| 		{ | ||||
| 			m_offsets[2 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 0] = x_offset; | ||||
| 			m_offsets[2 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 1] = y_offset; | ||||
| 			m_offsets[2 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 0] = x_offset; | ||||
| 			m_offsets[2 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 1] = y_offset; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void glerminal::color(unsigned char x, unsigned char y, unsigned char layer, unsigned int color) | ||||
| 	void glerminal::color(int x, int y, int layer, unsigned int color) | ||||
| 	{ | ||||
| 		m_colors[4 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 0] = ((color >>  0) & 0xFF); | ||||
| 		m_colors[4 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 1] = ((color >>  8) & 0xFF); | ||||
| 		m_colors[4 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 2] = ((color >> 16) & 0xFF); | ||||
| 		m_colors[4 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 3] = ((color >> 24) & 0xFF); | ||||
| 		if (x >= 0 && x < GRID_WIDTH + 2 && y >= 0 && y < GRID_HEIGHT + 2 && layer >= 0 && layer < LAYER_COUNT) | ||||
| 		{ | ||||
| 			m_colors[4 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 0] = (color >>  0) & 0xFF; | ||||
| 			m_colors[4 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 1] = (color >>  8) & 0xFF; | ||||
| 			m_colors[4 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 2] = (color >> 16) & 0xFF; | ||||
| 			m_colors[4 * (x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2) + 3] = (color >> 24) & 0xFF; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void glerminal::scale(unsigned char x, unsigned char y, unsigned char layer, float scale) | ||||
| 	void glerminal::scale(int x, int y, int layer, float scale) | ||||
| 	{ | ||||
| 		m_scales[x + y * GRID_WIDTH + layer * GRID_AREA] = scale; | ||||
| 		if (x >= 0 && x < GRID_WIDTH + 2 && y >= 0 && y < GRID_HEIGHT + 2 && layer >= 0 && layer < LAYER_COUNT) | ||||
| 		{ | ||||
| 			m_scales[x + y * (GRID_WIDTH + 2) + layer * GRID_AREA_2] = scale; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void glerminal::load_atlas(unsigned char w, unsigned char h, const unsigned int* data) | ||||
| @@ -357,6 +368,39 @@ namespace glerminal | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	bool glerminal::load_sound(const char* name) | ||||
| 	{ | ||||
| 		if (m_sounds.find(name) == m_sounds.end()) | ||||
| 		{ | ||||
| 			ma_sound& ref = m_sounds[name]; | ||||
| 			const ma_result result = ma_sound_init_from_file( | ||||
| 				&m_audio_engine, | ||||
| 				name, | ||||
| 				MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_NO_SPATIALIZATION, | ||||
| 				nullptr, | ||||
| 				nullptr, | ||||
| 				&ref | ||||
| 			); | ||||
|  | ||||
| 			if (result != MA_SUCCESS) | ||||
| 			{ | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	void glerminal::play_sound(const char* name) | ||||
| 	{ | ||||
| 		load_sound(name); | ||||
| 		const ma_result result = ma_engine_play_sound(&m_audio_engine, name, nullptr); | ||||
| 		if (result != MA_SUCCESS) | ||||
| 		{ | ||||
|  | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void glerminal::init_glfw() | ||||
| 	{ | ||||
| 		glfwInit(); | ||||
| @@ -382,7 +426,9 @@ namespace glerminal | ||||
| 		} | ||||
|  | ||||
| 		glfwSetWindowUserPointer(m_window, this); | ||||
| 		glfwSetKeyCallback(m_window, glerminal::glfw_key_handler); | ||||
| 		glfwSetKeyCallback(m_window, glfw_key_handler); | ||||
| 		glfwSetCursorPosCallback(m_window, glfw_mousemoved_handler); | ||||
| 		glfwSetMouseButtonCallback(m_window, glfw_mousepress_handler); | ||||
| 	} | ||||
| 	 | ||||
| 	void glerminal::log(GLenum type, GLuint id, GLenum severity, const char* message) const | ||||
| @@ -610,10 +656,9 @@ namespace glerminal | ||||
| 		} | ||||
|  | ||||
| 		// setup uniforms | ||||
| 		m_screen_size_uniform_location = glGetUniformLocation(m_program, GRID_SIZE_UNIFORM_NAME); | ||||
|  | ||||
| 		glUseProgram(m_program); | ||||
| 		glUniform4f(m_screen_size_uniform_location, GRID_WIDTH, GRID_AREA, 1.0f / GRID_WIDTH, 1.0f / GRID_HEIGHT); | ||||
| 		glUniform1f(glGetUniformLocation(m_program, CELL_SIZE_UNIFORM_NAME), CELL_SIZE); | ||||
| 		glUniform4f(glGetUniformLocation(m_program, GRID_SIZE_UNIFORM_NAME), GRID_WIDTH + 2, GRID_AREA_2, 1.0f / GRID_WIDTH, 1.0f / GRID_HEIGHT); | ||||
| 		glUniform1i(glGetUniformLocation(m_program, ATLAS_WIDTH_UNIFORM_NAME), MAX_SPRITES_ROW); | ||||
|  | ||||
| 		// compile | ||||
| @@ -694,7 +739,6 @@ namespace glerminal | ||||
| 		update_sprites(); | ||||
|  | ||||
| 		glBindTextureUnit(2, m_sprites_texture); | ||||
| 		const auto err = glGetError(); | ||||
|  | ||||
| 		// -- setup framebuffer -- | ||||
| 		glGenFramebuffers(1, &m_framebuffer); | ||||
| @@ -737,6 +781,18 @@ namespace glerminal | ||||
| 		glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_screen_framebuffer_backing_texture, 0); | ||||
| 	} | ||||
|  | ||||
| 	void glerminal::init_audio() | ||||
| 	{ | ||||
| 		const ma_result result = ma_engine_init(nullptr, &m_audio_engine); | ||||
|  | ||||
| 		if (result != MA_SUCCESS) | ||||
| 		{ | ||||
| 			throw std::runtime_error("Failed to initialize audio engine"); | ||||
| 		} | ||||
|  | ||||
| 		ma_engine_set_volume(&m_audio_engine, 1); | ||||
| 	} | ||||
|  | ||||
| 	void glerminal::deinit_glfw() | ||||
| 	{ | ||||
| 		glfwDestroyWindow(m_window); | ||||
| @@ -761,6 +817,15 @@ namespace glerminal | ||||
| 		glDeleteProgram(m_program); | ||||
| 	} | ||||
|  | ||||
| 	void glerminal::deinit_audio() | ||||
| 	{ | ||||
| 		for (auto& elem : m_sounds) | ||||
| 		{ | ||||
| 			ma_sound_uninit(&elem.second); | ||||
| 		} | ||||
| 		ma_engine_uninit(&m_audio_engine); | ||||
| 	} | ||||
|  | ||||
| 	void glerminal::update_sprites() | ||||
| 	{ | ||||
| 		glTextureSubImage2D(m_sprites_texture, 0, 0, 0, (CELL_SIZE + 2) * MAX_SPRITES_ROW, (CELL_SIZE + 2) * MAX_SPRITES_ROW, GL_RGBA, GL_UNSIGNED_BYTE, m_sprites); | ||||
| @@ -778,25 +843,51 @@ namespace glerminal | ||||
|  | ||||
| 	void glerminal::glfw_key_handler(GLFWwindow* window, int key, int scancode, int action, int mods) | ||||
| 	{ | ||||
| 		glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window)); | ||||
| 		const glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window)); | ||||
|  | ||||
| 		if (self->m_pressed && action == GLFW_PRESS) | ||||
| 		if (self->m_keypressed && action == GLFW_PRESS) | ||||
| 		{ | ||||
| 			self->m_pressed(key); | ||||
| 			self->m_keypressed(key); | ||||
| 		} | ||||
|  | ||||
| 		if (self->m_released && action == GLFW_RELEASE) | ||||
| 		if (self->m_keyreleased && action == GLFW_RELEASE) | ||||
| 		{ | ||||
| 			self->m_released(key); | ||||
| 			self->m_keyreleased(key); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void glerminal::glfw_mousemoved_handler(GLFWwindow *window, double x, double y) | ||||
| 	{ | ||||
| 		const glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window)); | ||||
|  | ||||
| 		if (self->m_mousemoved) { self->m_mousemoved(x / (CELL_SIZE * CELL_SCALE), y / (CELL_SIZE * CELL_SCALE)); } | ||||
| 	} | ||||
|  | ||||
| 	void glerminal::glfw_mousepress_handler(GLFWwindow *window, int button, int action, int mods) | ||||
| 	{ | ||||
| 		const glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window)); | ||||
|  | ||||
| 		double x, y; | ||||
| 		glfwGetCursorPos(window, &x, &y); | ||||
|  | ||||
| 		if (self->m_mousepressed && action == GLFW_PRESS) | ||||
| 		{ | ||||
| 			self->m_mousepressed(button, x / (CELL_SIZE * CELL_SCALE), y / (CELL_SIZE * CELL_SCALE)); | ||||
| 		} | ||||
|  | ||||
| 		if (self->m_mousereleased && action == GLFW_RELEASE) | ||||
| 		{ | ||||
| 			self->m_mousereleased(button, x / (CELL_SIZE * CELL_SCALE), y / (CELL_SIZE * CELL_SCALE)); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| void glerminal_run(glerminal_init_cb init, glerminal_main_cb main, glerminal_keys_cb pressed, glerminal_keys_cb released) | ||||
| void glerminal_run(glerminal_init_params params) | ||||
| { | ||||
| 	try | ||||
| 	{ | ||||
| 		glerminal::glerminal* g = new glerminal::glerminal(init, main, pressed, released); | ||||
| 		glerminal::glerminal* g = new glerminal::glerminal(params); | ||||
| 		g->run(); | ||||
| 		delete g; | ||||
| 	} | ||||
| @@ -820,39 +911,39 @@ void glerminal_flush() | ||||
| 	GLERMINAL_G->flush(); | ||||
| } | ||||
|  | ||||
| void glerminal_set(unsigned char x, unsigned char y, unsigned char layer, unsigned short sprite) | ||||
| void glerminal_set(int x, int y, int layer, unsigned short sprite) | ||||
| { | ||||
| 	if (!GLERMINAL_G) { return; } | ||||
|  | ||||
| 	GLERMINAL_G->set(x, y, layer, sprite); | ||||
| 	GLERMINAL_G->set(x + 1, y + 1, layer, sprite); | ||||
| } | ||||
|  | ||||
| unsigned char glerminal_get(unsigned char x, unsigned char y, unsigned short layer) | ||||
| unsigned short glerminal_get(int x, int y, int layer) | ||||
| { | ||||
| 	if (!GLERMINAL_G) { return 0; } | ||||
|  | ||||
| 	return GLERMINAL_G->get(x, y, layer); | ||||
| 	return GLERMINAL_G->get(x + 1, y + 1, layer); | ||||
| } | ||||
|  | ||||
| void glerminal_offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset) | ||||
| void glerminal_offset(int x, int y, int layer, float x_offset, float y_offset) | ||||
| { | ||||
| 	if (!GLERMINAL_G) { return; } | ||||
|  | ||||
| 	GLERMINAL_G->offset(x, y, layer, x_offset, y_offset); | ||||
| 	GLERMINAL_G->offset(x + 1, y + 1, layer, x_offset, y_offset); | ||||
| } | ||||
|  | ||||
| void glerminal_color(unsigned char x, unsigned char y, unsigned char layer, unsigned int color) | ||||
| void glerminal_color(int x, int y, int layer, unsigned int color) | ||||
| { | ||||
| 	if (!GLERMINAL_G) { return; } | ||||
|  | ||||
| 	GLERMINAL_G->color(x, y, layer, color); | ||||
| 	GLERMINAL_G->color(x + 1, y + 1, layer, color); | ||||
| } | ||||
|  | ||||
| void glerminal_scale(unsigned char x, unsigned char y, unsigned char layer, float scale) | ||||
| void glerminal_scale(int x, int y, int layer, float scale) | ||||
| { | ||||
| 	if (!GLERMINAL_G) { return; } | ||||
|  | ||||
| 	GLERMINAL_G->scale(x, y, layer, scale); | ||||
| 	GLERMINAL_G->scale(x + 1, y + 1, layer, scale); | ||||
| } | ||||
|  | ||||
| int glerminal_load_sprites_file(const char* filename) | ||||
| @@ -865,7 +956,7 @@ int glerminal_load_sprites_file(const char* filename) | ||||
| 	stbi_uc* const buffer = stbi_load(filename, &w, &h, nullptr, 4); | ||||
|  | ||||
| 	// verify atlas size is a multiple of CELL_SIZE in each dimension | ||||
| 	if (w % glerminal::CELL_SIZE == 0 && h % glerminal::CELL_SIZE == 0) | ||||
| 	if (buffer && w % glerminal::CELL_SIZE == 0 && h % glerminal::CELL_SIZE == 0) | ||||
| 	{ | ||||
| 		GLERMINAL_G->load_atlas(w / glerminal::CELL_SIZE, h / glerminal::CELL_SIZE, reinterpret_cast<unsigned int*>(buffer)); | ||||
|  | ||||
| @@ -893,3 +984,10 @@ int glerminal_load_sprites_buffer(unsigned char width, unsigned char height, con | ||||
| 		return false; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void glerminal_sound(const char* name) | ||||
| { | ||||
| 	if (!GLERMINAL_G) { return; } | ||||
|  | ||||
| 	GLERMINAL_G->play_sound(name); | ||||
| } | ||||
|   | ||||
							
								
								
									
										7
									
								
								source/miniaudio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								source/miniaudio.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #ifndef GLERMINAL_MINIAUDIO_H | ||||
| #define GLERMINAL_MINIAUDIO_H | ||||
|  | ||||
| #define MINIAUDIO_IMPLEMENTATION | ||||
| #include "miniaudio.h" | ||||
|  | ||||
| #endif//GLERMINAL_MINIAUDIO_H | ||||
							
								
								
									
										92621
									
								
								source/miniaudio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92621
									
								
								source/miniaudio.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -17,7 +17,7 @@ target_include_directories(test-common | ||||
| 		${CMAKE_SOURCE_DIR}/source | ||||
| ) | ||||
|  | ||||
| target_link_libraries(test-common PRIVATE glerminallib) | ||||
| target_link_libraries(test-common PRIVATE glerminal) | ||||
|  | ||||
| file(GLOB_RECURSE | ||||
| 	TEST_RESOURCES | ||||
| @@ -52,5 +52,5 @@ list(TRANSFORM TEST_RESOURCES PREPEND ${CMAKE_CURRENT_BINARY_DIR}/) | ||||
| foreach(SOURCE_FILE ${TEST_SOURCES}) | ||||
| 	get_filename_component(SOURCE_FILENAME ${SOURCE_FILE} NAME_WLE) | ||||
| 	add_executable(test-${SOURCE_FILENAME} WIN32 ${SOURCE_FILE} ${TEST_RESOURCES}) | ||||
| 	target_link_libraries(test-${SOURCE_FILENAME} PRIVATE glerminallib test-common) | ||||
| 	target_link_libraries(test-${SOURCE_FILENAME} PRIVATE glerminal test-common) | ||||
| endforeach() | ||||
| @@ -25,12 +25,12 @@ namespace | ||||
| 		glerminal_quit(); | ||||
| 	} | ||||
|  | ||||
| 	void mainloop(float) {} | ||||
| 	void mainloop(double) {} | ||||
| } | ||||
|  | ||||
| int main() | ||||
| { | ||||
| 	glerminal_run(init, mainloop, nullptr, nullptr); | ||||
| 	glerminal_run({init, mainloop}); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -8,7 +8,7 @@ | ||||
|  | ||||
| namespace | ||||
| { | ||||
| 	unsigned char pixels[(GRID_WIDTH * CELL_SCALE * 8) * (GRID_HEIGHT * CELL_SCALE * 8) * 3]; | ||||
| 	unsigned char pixels[(GRID_WIDTH * CELL_SIZE * CELL_SCALE) * (GRID_HEIGHT * CELL_SIZE * CELL_SCALE) * 3]; | ||||
| } | ||||
|  | ||||
| void glerminal_test_save_image() | ||||
| @@ -21,5 +21,5 @@ void glerminal_test_save_image() | ||||
| 	glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels); | ||||
|  | ||||
| 	stbi_flip_vertically_on_write(true); | ||||
| 	stbi_write_png("image.png", GRID_WIDTH * CELL_SCALE * 8, GRID_HEIGHT * CELL_SCALE * 8, 3, pixels, GRID_WIDTH * CELL_SCALE * 8 * 3); | ||||
| 	stbi_write_png("image.png", GRID_WIDTH * CELL_SIZE * CELL_SCALE, GRID_HEIGHT * CELL_SIZE * CELL_SCALE, 3, pixels, GRID_WIDTH * CELL_SIZE * CELL_SCALE * 3); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user