mirror of
				https://git.shylie.info/shylie/glerminal.git
				synced 2025-10-31 01:00:20 +00:00 
			
		
		
		
	Compare commits
	
		
			20 Commits
		
	
	
		
			139681a3fd
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| fb3eeb6ec9 | |||
| 263cf68ca2 | |||
| b8e616c8d6 | |||
| 1bfbab7a96 | |||
| d156005441 | |||
| 82389b8c12 | |||
| 0a9d211942 | |||
| 937693ce6a | |||
| 365cad551b | |||
| 5fbeb1e4e9 | |||
| 11ffc40bbb | |||
| db46885ee9 | |||
| 20fad92e4f | |||
| 7c0c02b9af | |||
| 1a1f4e8b13 | |||
|   | 6663804c88 | ||
|   | 9d88ebbb3b | ||
|   | 76bfd67f4e | ||
|   | 4811e4d970 | ||
|   | e402b5f5a3 | 
| @@ -5,7 +5,7 @@ on: push | |||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   build-app: |   build-app: | ||||||
|     runs-on: linux_amd64 |     runs-on: shy-server | ||||||
|     steps: |     steps: | ||||||
|       - name: Checkout current |       - name: Checkout current | ||||||
|         uses: actions/checkout@v4 |         uses: actions/checkout@v4 | ||||||
| @@ -20,7 +20,7 @@ jobs: | |||||||
|           fetch-depth: 0 |           fetch-depth: 0 | ||||||
|           submodules: recursive |           submodules: recursive | ||||||
|           lfs: true |           lfs: true | ||||||
|       - run: cd prev && git checkout 10a90a5f6a |       - run: cd prev && git checkout 263cf68ca2 | ||||||
|       - name: Build current |       - name: Build current | ||||||
|         run: cmake -S curr -B curr/build -DGLERMINAL_TEST=ON && cmake --build curr/build |         run: cmake -S curr -B curr/build -DGLERMINAL_TEST=ON && cmake --build curr/build | ||||||
|       - name: Build previous |       - name: Build previous | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,4 @@ | |||||||
| build/ | build/ | ||||||
| cmake-build-*/ | cmake-build-*/ | ||||||
| .idea/ | .idea/ | ||||||
|  | .cache/ | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,3 @@ | |||||||
| [submodule "glfw"] | [submodule "glfw"] | ||||||
| 	path = glfw | 	path = glfw | ||||||
| 	url = https://git.shylie.info/shylie/glfw.git | 	url = https://github.com/glfw/glfw.git | ||||||
| [submodule "Lua"] |  | ||||||
| 	path = Lua |  | ||||||
| 	url = https://git.shylie.info/shylie/Lua.git |  | ||||||
|   | |||||||
| @@ -11,13 +11,13 @@ set(GLERMINAL_GRID_WIDTH 40 CACHE STRING "") | |||||||
| set(GLERMINAL_GRID_HEIGHT 25 CACHE STRING "") | set(GLERMINAL_GRID_HEIGHT 25 CACHE STRING "") | ||||||
| set(GLERMINAL_LAYER_COUNT 64 CACHE STRING "") | set(GLERMINAL_LAYER_COUNT 64 CACHE STRING "") | ||||||
| set(GLERMINAL_CELL_SCALE 4 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) | configure_file(source/glerminal-config.h.in glerminal-config.h @ONLY) | ||||||
|  |  | ||||||
| add_subdirectory(glfw) | add_subdirectory(glfw) | ||||||
| add_subdirectory(Lua) |  | ||||||
|  |  | ||||||
| add_library(glerminallib STATIC | add_library(glerminal STATIC | ||||||
|   ${CMAKE_CURRENT_BINARY_DIR}/glerminal-config.h |   ${CMAKE_CURRENT_BINARY_DIR}/glerminal-config.h | ||||||
|   include/glerminal.h |   include/glerminal.h | ||||||
|  |  | ||||||
| @@ -28,14 +28,17 @@ add_library(glerminallib STATIC | |||||||
|   source/glad/glad.h |   source/glad/glad.h | ||||||
|   source/KHR/khrplatform.h |   source/KHR/khrplatform.h | ||||||
|   source/glad.c |   source/glad.c | ||||||
|  |  | ||||||
|  |   source/miniaudio.h | ||||||
|  |   source/miniaudio.c | ||||||
| ) | ) | ||||||
|  |  | ||||||
| set_target_properties(glerminallib | set_target_properties(glerminal | ||||||
|   PROPERTIES |   PROPERTIES | ||||||
|     CXX_STANDARD 11 |     CXX_STANDARD 11 | ||||||
| ) | ) | ||||||
|  |  | ||||||
| target_include_directories(glerminallib | target_include_directories(glerminal | ||||||
|   PUBLIC |   PUBLIC | ||||||
|     include |     include | ||||||
|     ${CMAKE_CURRENT_BINARY_DIR} |     ${CMAKE_CURRENT_BINARY_DIR} | ||||||
| @@ -43,12 +46,12 @@ target_include_directories(glerminallib | |||||||
|     source |     source | ||||||
| ) | ) | ||||||
|  |  | ||||||
| target_link_libraries(glerminallib | target_link_libraries(glerminal | ||||||
|   PUBLIC |   PUBLIC | ||||||
|     glfw |     glfw | ||||||
| ) | ) | ||||||
|  |  | ||||||
| target_compile_definitions(glerminallib | target_compile_definitions(glerminal | ||||||
|   PUBLIC |   PUBLIC | ||||||
|     GLERMINAL_VERSION=${PROJECT_VERSION} |     GLERMINAL_VERSION=${PROJECT_VERSION} | ||||||
|     GLERMINAL_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} |     GLERMINAL_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} | ||||||
| @@ -56,23 +59,6 @@ target_compile_definitions(glerminallib | |||||||
|     GLERMINAL_VERSION_PATCH=${PROJECT_VERSION_PATCH} |     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_link_libraries(glerminal |  | ||||||
| 	PRIVATE |  | ||||||
| 		glerminallib |  | ||||||
| 		lua_static |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| if(PROJECT_IS_TOP_LEVEL) | if(PROJECT_IS_TOP_LEVEL) | ||||||
|   add_subdirectory(examples examples) |   add_subdirectory(examples examples) | ||||||
| endif() | 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}) | foreach(SOURCE_FILE ${EXAMPLE_SOURCES}) | ||||||
| 	get_filename_component(SOURCE_FILENAME ${SOURCE_FILE} NAME_WLE) | 	get_filename_component(SOURCE_FILENAME ${SOURCE_FILE} NAME_WLE) | ||||||
| 	add_executable(${SOURCE_FILENAME} WIN32 ${SOURCE_FILE} ${EXAMPLE_RESOURCES}) | 	add_executable(${SOURCE_FILENAME} WIN32 ${SOURCE_FILE} ${EXAMPLE_RESOURCES}) | ||||||
| 	target_link_libraries(${SOURCE_FILENAME} PRIVATE glerminallib) | 	target_link_libraries(${SOURCE_FILENAME} PRIVATE glerminal) | ||||||
| endforeach() | endforeach() | ||||||
| @@ -30,8 +30,8 @@ namespace | |||||||
| 			{ | 			{ | ||||||
| 				for (int k = 0; k < LAYER_COUNT; k++) | 				for (int k = 0; k < LAYER_COUNT; k++) | ||||||
| 				{ | 				{ | ||||||
| 					glerminal_set(i, j, k, rand() % 4); | 					glerminal_set(i + 1, j + 1, k, rand() % 4); | ||||||
| 					glerminal_offset(i, j, k, (rand() * rand()) % 64 - 32, (rand() * rand()) % 64 - 32); | 					glerminal_offset(i + 1, j + 1, k, (rand() * rand()) % 64 - 32, (rand() * rand()) % 64 - 32); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -9,9 +9,9 @@ namespace | |||||||
| 	{ | 	{ | ||||||
| 		glerminal_load_sprites_file("resources/basic.png"); | 		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); | 				glerminal_set(i, j, 0, 1); | ||||||
| 			} | 			} | ||||||
| @@ -25,9 +25,9 @@ namespace | |||||||
| 		time += dt; | 		time += dt; | ||||||
| 		time = fmodf(time, 3.1415926f * 2); | 		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)); | 				glerminal_offset(i, j, 0, cosf(time - i / 3.1415f), sinf(time - j / 3.1415f)); | ||||||
| 			} | 			} | ||||||
|   | |||||||
| @@ -18,16 +18,16 @@ namespace | |||||||
| 	{ | 	{ | ||||||
| 		glerminal_load_sprites_file("resources/rogue.png"); | 		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++) | 				for (int k = 0; k < WALL_LAYERS; k++) | ||||||
| 				{ | 				{ | ||||||
| 					const unsigned char v = (k + 1) * (256 / WALL_LAYERS) - 1; | 					const unsigned char v = (k + 1) * (256 / WALL_LAYERS) - 1; | ||||||
| 					const unsigned int c = (0xFF << 24) | (v << 16) | (v << 8) | v; | 					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); | 						glerminal_set(i, j, k, floor); | ||||||
| 					} | 					} | ||||||
| @@ -48,12 +48,12 @@ namespace | |||||||
| 		static double time = 0; | 		static double time = 0; | ||||||
| 		time += dt; | 		time += dt; | ||||||
|  |  | ||||||
| 		const float cx = GRID_WIDTH / 2.0f * cosf(time / 2) + GRID_WIDTH / 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; | 		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++) | 				for (int k = 0; k < WALL_LAYERS; k++) | ||||||
| 				{ | 				{ | ||||||
|   | |||||||
| @@ -12,9 +12,9 @@ namespace | |||||||
| 		glerminal_load_sprites_file("resources/towers.png"); | 		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; | 				const int c = rand() % (LAYER_COUNT * 3 / 4) + LAYER_COUNT / 4; | ||||||
| 				for (int k = 0; k < c; k++) | 				for (int k = 0; k < c; k++) | ||||||
| @@ -40,12 +40,12 @@ namespace | |||||||
|  |  | ||||||
| 		time += dt; | 		time += dt; | ||||||
|  |  | ||||||
| 		const float cx = (GRID_WIDTH / 2.0f) * cosf(time / 3.1415f) + (GRID_WIDTH / 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); | 		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++) | 				for (int k = 0; k < LAYER_COUNT; k++) | ||||||
| 				{ | 				{ | ||||||
|   | |||||||
| @@ -42,7 +42,7 @@ void glerminal_flush(); | |||||||
|  * @param layer layer of the cell in the range [0, LAYER_COUNT) |  * @param layer layer of the cell in the range [0, LAYER_COUNT) | ||||||
|  * @param sprite sprite's index in the range [0, 4096) |  * @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 |  * @brief Get a cell's sprite | ||||||
|  * @param x position of the cell in the range [0, GRID_WIDTH) |  * @param x position of the cell in the range [0, GRID_WIDTH) | ||||||
| @@ -50,7 +50,7 @@ void glerminal_set(unsigned char x, unsigned char y, unsigned char layer, unsign | |||||||
|  * @param layer layer of the cell in the range [0, LAYER_COUNT) |  * @param layer layer of the cell in the range [0, LAYER_COUNT) | ||||||
|  * @return sprite index currently assigned to the cell |  * @return sprite index currently assigned to the cell | ||||||
|  */ |  */ | ||||||
| unsigned char glerminal_get(unsigned char x, unsigned char y, unsigned short layer); | unsigned short glerminal_get(int x, int y, int layer); | ||||||
| /** | /** | ||||||
|  * @brief Set a cell's offset |  * @brief Set a cell's offset | ||||||
|  * @param x position of the cell in the range [0, GRID_WIDTH) |  * @param x position of the cell in the range [0, GRID_WIDTH) | ||||||
| @@ -59,7 +59,7 @@ unsigned char glerminal_get(unsigned char x, unsigned char y, unsigned short lay | |||||||
|  * @param x_offset offset of the cell on the x axis in cells |  * @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 |  * @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 cell's color |  * @brief Set a cell's color | ||||||
| @@ -68,7 +68,7 @@ void glerminal_offset(unsigned char x, unsigned char y, unsigned char layer, flo | |||||||
|  * @param layer layer of the cell in the range [0, LAYER_COUNT) |  * @param layer layer of the cell in the range [0, LAYER_COUNT) | ||||||
|  * @param color The new color |  * @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 cell's scale |  * @brief Set a cell's scale | ||||||
|  * @param x position of the cell in the range [0, GRID_WIDTH) |  * @param x position of the cell in the range [0, GRID_WIDTH) | ||||||
| @@ -76,7 +76,7 @@ void glerminal_color(unsigned char x, unsigned char y, unsigned char layer, unsi | |||||||
|  * @param layer layer of the cell in the range [0, LAYER_COUNT) |  * @param layer layer of the cell in the range [0, LAYER_COUNT) | ||||||
|  * @param scale The new scale |  * @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 |  * @brief Load sprites from a png file | ||||||
| @@ -92,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); | int glerminal_load_sprites_buffer(unsigned char width, unsigned char height, const unsigned int* buffer); | ||||||
|  |  | ||||||
|  | void glerminal_sound(const char* name); | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -1,35 +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 |  | ||||||
|  |  | ||||||
| function glerminal.keypresse(key) end |  | ||||||
| function glerminal.keyrelease(key) end |  | ||||||
| function glerminal.mousemove(x, y) end |  | ||||||
| function glerminal.mousepress(button, x, y) end |  | ||||||
| function glerminal.mouserelease(button, x, y) 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_WIDTH = @GLERMINAL_GRID_WIDTH@, | ||||||
| 	GRID_HEIGHT = @GLERMINAL_GRID_HEIGHT@, | 	GRID_HEIGHT = @GLERMINAL_GRID_HEIGHT@, | ||||||
| 	LAYER_COUNT = @GLERMINAL_LAYER_COUNT@, | 	LAYER_COUNT = @GLERMINAL_LAYER_COUNT@, | ||||||
| 	CELL_SCALE = @GLERMINAL_CELL_SCALE@ | 	CELL_SCALE = @GLERMINAL_CELL_SCALE@, | ||||||
|  | 	CELL_SIZE = @GLERMINAL_CELL_SIZE@ | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
|   | |||||||
| @@ -1,340 +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(double 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 keypressed(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, "keypress"); |  | ||||||
| 			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 keyrelease(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, "keyrelease"); |  | ||||||
| 			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 mousemove(double x, double y) |  | ||||||
| 	{ |  | ||||||
| 		lua_pushcfunction(L, message_handler); |  | ||||||
| 		const int handler = lua_gettop(L); |  | ||||||
| 		lua_getglobal(L, "glerminal"); |  | ||||||
| 		lua_getfield(L, -1, "mousemove"); |  | ||||||
| 		lua_remove(L, -2); |  | ||||||
| 		lua_pushnumber(L, x); |  | ||||||
| 		lua_pushnumber(L, y); |  | ||||||
| 		if (lua_pcall(L, 2, 0, handler) != LUA_OK) |  | ||||||
| 		{ |  | ||||||
| 			std::cout << lua_tostring(L, -1) << std::endl; |  | ||||||
| 			lua_pop(L, 1); |  | ||||||
| 		} |  | ||||||
| 		lua_remove(L, handler); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	void mousepress(int button, double x, double y) |  | ||||||
| 	{ |  | ||||||
| 		const char* button_name = nullptr; |  | ||||||
| 		switch (button) |  | ||||||
| 		{ |  | ||||||
| 			case GLFW_MOUSE_BUTTON_LEFT: |  | ||||||
| 				button_name = "left"; |  | ||||||
| 			break; |  | ||||||
|  |  | ||||||
| 			case GLFW_MOUSE_BUTTON_RIGHT: |  | ||||||
| 				button_name = "right"; |  | ||||||
| 			break; |  | ||||||
|  |  | ||||||
| 			case GLFW_MOUSE_BUTTON_MIDDLE: |  | ||||||
| 				button_name = "middle"; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (button_name) |  | ||||||
| 		{ |  | ||||||
| 			lua_pushcfunction(L, message_handler); |  | ||||||
| 			const int handler = lua_gettop(L); |  | ||||||
| 			lua_getglobal(L, "glerminal"); |  | ||||||
| 			lua_getfield(L, -1, "mousepress"); |  | ||||||
| 			lua_remove(L, -2); |  | ||||||
| 			lua_pushstring(L, button_name); |  | ||||||
| 			lua_pushnumber(L, x); |  | ||||||
| 			lua_pushnumber(L, y); |  | ||||||
| 			if (lua_pcall(L, 3, 0, handler) != LUA_OK) |  | ||||||
| 			{ |  | ||||||
| 				std::cout << lua_tostring(L, -1) << std::endl; |  | ||||||
| 				lua_pop(L, 1); |  | ||||||
| 			} |  | ||||||
| 			lua_remove(L, handler); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	void mouserelease(int button, double x, double y) |  | ||||||
| 	{ |  | ||||||
| 		const char* button_name = nullptr; |  | ||||||
| 		switch (button) |  | ||||||
| 		{ |  | ||||||
| 			case GLFW_MOUSE_BUTTON_LEFT: |  | ||||||
| 				button_name = "left"; |  | ||||||
| 			break; |  | ||||||
|  |  | ||||||
| 			case GLFW_MOUSE_BUTTON_RIGHT: |  | ||||||
| 				button_name = "right"; |  | ||||||
| 			break; |  | ||||||
|  |  | ||||||
| 			case GLFW_MOUSE_BUTTON_MIDDLE: |  | ||||||
| 				button_name = "middle"; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (button_name) |  | ||||||
| 		{ |  | ||||||
| 			lua_pushcfunction(L, message_handler); |  | ||||||
| 			const int handler = lua_gettop(L); |  | ||||||
| 			lua_getglobal(L, "glerminal"); |  | ||||||
| 			lua_getfield(L, -1, "mouserelease"); |  | ||||||
| 			lua_remove(L, -2); |  | ||||||
| 			lua_pushstring(L, button_name); |  | ||||||
| 			lua_pushnumber(L, x); |  | ||||||
| 			lua_pushnumber(L, y); |  | ||||||
| 			if (lua_pcall(L, 3, 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_init_params params; |  | ||||||
| 		params.init = init; |  | ||||||
| 		params.main = mainloop; |  | ||||||
| 		params.keypress = keypressed; |  | ||||||
| 		params.keyrelease = keyrelease; |  | ||||||
| 		params.moved = mousemove; |  | ||||||
| 		params.mousepress = mousepress; |  | ||||||
| 		params.mouserelease = mouserelease; |  | ||||||
| 		glerminal_run(params); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	lua_close(L); |  | ||||||
|  |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| @@ -2,27 +2,31 @@ | |||||||
| #define GLERMINAL_PRIVATE_H | #define GLERMINAL_PRIVATE_H | ||||||
|  |  | ||||||
| #include "glerminal.h" | #include "glerminal.h" | ||||||
|  | #include "miniaudio.h" | ||||||
|  |  | ||||||
| #include <stb_image.h> | #include <stb_image.h> | ||||||
| #include <glad/glad.h> | #include <glad/glad.h> | ||||||
| #include <GLFW/glfw3.h> | #include <GLFW/glfw3.h> | ||||||
|  |  | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <fstream> | #include <map> | ||||||
| #include <stdexcept> | #include <string> | ||||||
|  |  | ||||||
| namespace glerminal | namespace glerminal | ||||||
| { | { | ||||||
| 	constexpr unsigned int CELL_SIZE = 8; |  | ||||||
| 	constexpr unsigned int MAX_SPRITES_ROW = 64; | 	constexpr unsigned int MAX_SPRITES_ROW = 64; | ||||||
| 	constexpr unsigned int MAX_SPRITES = MAX_SPRITES_ROW * MAX_SPRITES_ROW; | 	constexpr unsigned int MAX_SPRITES = MAX_SPRITES_ROW * MAX_SPRITES_ROW; | ||||||
| 	constexpr unsigned int GRID_WIDTH = ::GRID_WIDTH; | 	constexpr unsigned int GRID_WIDTH = ::GRID_WIDTH; | ||||||
| 	constexpr unsigned int GRID_HEIGHT = ::GRID_HEIGHT; | 	constexpr unsigned int GRID_HEIGHT = ::GRID_HEIGHT; | ||||||
| 	constexpr unsigned int LAYER_COUNT = ::LAYER_COUNT; | 	constexpr unsigned int LAYER_COUNT = ::LAYER_COUNT; | ||||||
| 	constexpr unsigned int CELL_SCALE = ::CELL_SCALE; | 	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 GRID_AREA = GRID_WIDTH * GRID_HEIGHT; | ||||||
| 	constexpr unsigned int SCREEN_WIDTH = GRID_WIDTH * CELL_SIZE * CELL_SCALE; | 	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 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 | 	class glerminal | ||||||
| 	{ | 	{ | ||||||
| @@ -41,12 +45,14 @@ namespace glerminal | |||||||
|  |  | ||||||
| 		void flush(); | 		void flush(); | ||||||
|  |  | ||||||
| 		void set(unsigned char x, unsigned char y, unsigned char layer, unsigned short sprite); | 		void set(int x, int y, int layer, unsigned short sprite); | ||||||
| 		unsigned short get(unsigned char x, unsigned char y, unsigned char layer) const; | 		unsigned short get(int x, int y, int layer) const; | ||||||
| 		void offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset); | 		void offset(int x, int y, int layer, float x_offset, float y_offset); | ||||||
| 		void color(unsigned char x, unsigned char y, unsigned char layer, unsigned int color); | 		void color(int x, int y, int layer, unsigned int color); | ||||||
| 		void scale(unsigned char x, unsigned char y, unsigned char layer, float scale); | 		void scale(int x,int y, int layer, float scale); | ||||||
| 		void load_atlas(unsigned char w, unsigned char h, const unsigned int* data); | 		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: | 	private: | ||||||
| 		// glfw data | 		// glfw data | ||||||
| @@ -69,15 +75,13 @@ namespace glerminal | |||||||
| 		unsigned int m_screen_framebuffer_backing_texture; | 		unsigned int m_screen_framebuffer_backing_texture; | ||||||
| 		unsigned int m_colors_instance_vbo; | 		unsigned int m_colors_instance_vbo; | ||||||
| 		unsigned int m_scales_instance_vbo; | 		unsigned int m_scales_instance_vbo; | ||||||
| 		unsigned int m_screen_size_uniform_location; |  | ||||||
| 		unsigned int m_palette_uniform_location; |  | ||||||
|  |  | ||||||
| 		// per-cell data | 		// per-cell data | ||||||
|  |  | ||||||
| 		unsigned short m_cells[GRID_AREA * LAYER_COUNT]; | 		unsigned short m_cells[GRID_AREA_2 * LAYER_COUNT]; | ||||||
| 		float m_offsets[GRID_AREA * LAYER_COUNT * 2]; | 		float m_offsets[GRID_AREA_2 * LAYER_COUNT * 2]; | ||||||
| 		unsigned char m_colors[GRID_AREA * LAYER_COUNT * 4]; | 		unsigned char m_colors[GRID_AREA_2 * LAYER_COUNT * 4]; | ||||||
| 		float m_scales[GRID_AREA * LAYER_COUNT]; | 		float m_scales[GRID_AREA_2 * LAYER_COUNT]; | ||||||
|  |  | ||||||
| 		// library state | 		// library state | ||||||
|  |  | ||||||
| @@ -87,6 +91,9 @@ namespace glerminal | |||||||
| 		glerminal_mousemoved_cb m_mousemoved; | 		glerminal_mousemoved_cb m_mousemoved; | ||||||
| 		glerminal_mousepress_cb m_mousepressed, m_mousereleased; | 		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 | #ifdef GLERMINAL_OPENGL_DEBUG_CONTEXT | ||||||
| 		mutable std::ofstream m_log; | 		mutable std::ofstream m_log; | ||||||
| #endif | #endif | ||||||
| @@ -95,9 +102,13 @@ namespace glerminal | |||||||
| 		void init_glfw(); | 		void init_glfw(); | ||||||
| 		void init_gl(); | 		void init_gl(); | ||||||
|  |  | ||||||
|  | 		void init_audio(); | ||||||
|  |  | ||||||
| 		void deinit_glfw(); | 		void deinit_glfw(); | ||||||
| 		void deinit_gl(); | 		void deinit_gl(); | ||||||
|  |  | ||||||
|  | 		void deinit_audio(); | ||||||
|  |  | ||||||
| 		void update_sprites(); | 		void update_sprites(); | ||||||
| 		void update_colors(); | 		void update_colors(); | ||||||
| 		void update_scales(); | 		void update_scales(); | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| #define STB_IMAGE_IMPLEMENTATION | #define STB_IMAGE_IMPLEMENTATION | ||||||
| #define STBI_ONLY_PNG | #define STBI_ONLY_PNG | ||||||
| #define STBI_MAX_DIMENSIONS 512 | #define STBI_MAX_DIMENSIONS 2048 | ||||||
| #include "glerminal-private.h" | #include "glerminal-private.h" | ||||||
|  |  | ||||||
| #define GRID_SIZE_UNIFORM_NAME "grid_size" | #define GRID_SIZE_UNIFORM_NAME "grid_size" | ||||||
| @@ -8,6 +8,7 @@ | |||||||
| #define LAYERS_UNIFORM_NAME "layers" | #define LAYERS_UNIFORM_NAME "layers" | ||||||
| #define LAYER_COUNT_UNIFORM_NAME "layer_count" | #define LAYER_COUNT_UNIFORM_NAME "layer_count" | ||||||
| #define ATLAS_WIDTH_UNIFORM_NAME "atlas_width" | #define ATLAS_WIDTH_UNIFORM_NAME "atlas_width" | ||||||
|  | #define CELL_SIZE_UNIFORM_NAME "cell_size" | ||||||
|  |  | ||||||
| namespace | namespace | ||||||
| { | { | ||||||
| @@ -33,6 +34,7 @@ namespace | |||||||
| 		"layout (location = 2) in int sprite;\n" | 		"layout (location = 2) in int sprite;\n" | ||||||
| 		"layout (location = 3) in vec4 color;\n" | 		"layout (location = 3) in vec4 color;\n" | ||||||
| 		"layout (location = 4) in float scale;\n" | 		"layout (location = 4) in float scale;\n" | ||||||
|  | 		"uniform float " CELL_SIZE_UNIFORM_NAME ";\n" | ||||||
| 		"uniform vec4 " GRID_SIZE_UNIFORM_NAME ";\n" | 		"uniform vec4 " GRID_SIZE_UNIFORM_NAME ";\n" | ||||||
| 		"uniform int " ATLAS_WIDTH_UNIFORM_NAME ";\n" | 		"uniform int " ATLAS_WIDTH_UNIFORM_NAME ";\n" | ||||||
| 		"out VS_OUT {\n" | 		"out VS_OUT {\n" | ||||||
| @@ -48,9 +50,9 @@ namespace | |||||||
| 		"	vs_out.sprite = sprite;\n" | 		"	vs_out.sprite = sprite;\n" | ||||||
| 		"	vs_out.layer = layer;\n" | 		"	vs_out.layer = layer;\n" | ||||||
| 		"	vs_out.layer_color = color;\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" | 		"	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 ".z), -floor((gl_InstanceID % int(" GRID_SIZE_UNIFORM_NAME ".y)) * " GRID_SIZE_UNIFORM_NAME ".z));\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" | 		"	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" | 		"	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 = 2) in int sprite;\n" | ||||||
| 		"layout (location = 3) in vec4 color;\n" | 		"layout (location = 3) in vec4 color;\n" | ||||||
| 		"layout (location = 4) in float scale;\n" | 		"layout (location = 4) in float scale;\n" | ||||||
|  | 		"uniform float " CELL_SIZE_UNIFORM_NAME ";\n" | ||||||
| 		"uniform vec4 " GRID_SIZE_UNIFORM_NAME ";\n" | 		"uniform vec4 " GRID_SIZE_UNIFORM_NAME ";\n" | ||||||
| 		"uniform int " ATLAS_WIDTH_UNIFORM_NAME ";\n" | 		"uniform int " ATLAS_WIDTH_UNIFORM_NAME ";\n" | ||||||
| 		"out VS_OUT {\n" | 		"out VS_OUT {\n" | ||||||
| @@ -77,10 +80,10 @@ namespace | |||||||
| 		"	gl_Layer = layer;\n" | 		"	gl_Layer = layer;\n" | ||||||
| 		"	vec2 scaled_offset = 2 * offset * " GRID_SIZE_UNIFORM_NAME ".zw;\n" | 		"	vec2 scaled_offset = 2 * offset * " GRID_SIZE_UNIFORM_NAME ".zw;\n" | ||||||
| 		"	vs_out.sprite = sprite;\n" | 		"	vs_out.sprite = sprite;\n" | ||||||
| 		"	vs_out.texcoord = vec2(sprite % " 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" | 		"	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 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" | 		"	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" | 		"	gl_Position = vec4(scaled_offset.x + temp.x, scaled_offset.y - temp.y, 0, 1);\n" | ||||||
| 		"}"; | 		"}"; | ||||||
|  |  | ||||||
| @@ -221,7 +224,7 @@ namespace glerminal | |||||||
| 			throw std::runtime_error("No main callback provided."); | 			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_colors[i * 4 + 0] = m_colors[i * 4 + 1] = m_colors[i * 4 + 2] = m_colors[i * 4 + 3] = 255; | ||||||
| 			m_scales[i] = 1; | 			m_scales[i] = 1; | ||||||
| @@ -229,6 +232,7 @@ namespace glerminal | |||||||
|  |  | ||||||
| 		init_glfw(); | 		init_glfw(); | ||||||
| 		init_gl(); | 		init_gl(); | ||||||
|  | 		init_audio(); | ||||||
|  |  | ||||||
| 		GLERMINAL_G = this; | 		GLERMINAL_G = this; | ||||||
|  |  | ||||||
| @@ -237,6 +241,7 @@ namespace glerminal | |||||||
|  |  | ||||||
| 	glerminal::~glerminal() | 	glerminal::~glerminal() | ||||||
| 	{ | 	{ | ||||||
|  | 		deinit_audio(); | ||||||
| 		deinit_gl(); | 		deinit_gl(); | ||||||
| 		deinit_glfw(); | 		deinit_glfw(); | ||||||
|  |  | ||||||
| @@ -275,7 +280,7 @@ namespace glerminal | |||||||
| 		glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); | 		glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); | ||||||
| 		glBindVertexArray(m_vao); | 		glBindVertexArray(m_vao); | ||||||
| 		glClear(GL_COLOR_BUFFER_BIT); | 		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); | 		glUseProgram(m_screen_program); | ||||||
| 		glBindFramebuffer(GL_FRAMEBUFFER, m_screen_framebuffer); | 		glBindFramebuffer(GL_FRAMEBUFFER, m_screen_framebuffer); | ||||||
| @@ -283,28 +288,25 @@ namespace glerminal | |||||||
| 		glClear(GL_COLOR_BUFFER_BIT); | 		glClear(GL_COLOR_BUFFER_BIT); | ||||||
| 		glDrawArrays(GL_TRIANGLES, 0, 6); | 		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); | 		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); | 		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 | 		else | ||||||
| 		{ | 		{ | ||||||
| @@ -312,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 + 2) + layer * GRID_AREA_2) + 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) + 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); | 		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 + 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 + 2) + layer * GRID_AREA_2) + 0] = (color >>  0) & 0xFF; | ||||||
| 		m_colors[4 * (x + y * GRID_WIDTH + layer * GRID_AREA) + 3] = ((color >> 24) & 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) | 	void glerminal::load_atlas(unsigned char w, unsigned char h, const unsigned int* data) | ||||||
| @@ -360,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() | 	void glerminal::init_glfw() | ||||||
| 	{ | 	{ | ||||||
| 		glfwInit(); | 		glfwInit(); | ||||||
| @@ -615,10 +656,9 @@ namespace glerminal | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// setup uniforms | 		// setup uniforms | ||||||
| 		m_screen_size_uniform_location = glGetUniformLocation(m_program, GRID_SIZE_UNIFORM_NAME); |  | ||||||
|  |  | ||||||
| 		glUseProgram(m_program); | 		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); | 		glUniform1i(glGetUniformLocation(m_program, ATLAS_WIDTH_UNIFORM_NAME), MAX_SPRITES_ROW); | ||||||
|  |  | ||||||
| 		// compile | 		// compile | ||||||
| @@ -699,7 +739,6 @@ namespace glerminal | |||||||
| 		update_sprites(); | 		update_sprites(); | ||||||
|  |  | ||||||
| 		glBindTextureUnit(2, m_sprites_texture); | 		glBindTextureUnit(2, m_sprites_texture); | ||||||
| 		const auto err = glGetError(); |  | ||||||
|  |  | ||||||
| 		// -- setup framebuffer -- | 		// -- setup framebuffer -- | ||||||
| 		glGenFramebuffers(1, &m_framebuffer); | 		glGenFramebuffers(1, &m_framebuffer); | ||||||
| @@ -742,6 +781,18 @@ namespace glerminal | |||||||
| 		glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_screen_framebuffer_backing_texture, 0); | 		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() | 	void glerminal::deinit_glfw() | ||||||
| 	{ | 	{ | ||||||
| 		glfwDestroyWindow(m_window); | 		glfwDestroyWindow(m_window); | ||||||
| @@ -766,6 +817,15 @@ namespace glerminal | |||||||
| 		glDeleteProgram(m_program); | 		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() | 	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); | 		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); | ||||||
| @@ -783,7 +843,7 @@ namespace glerminal | |||||||
|  |  | ||||||
| 	void glerminal::glfw_key_handler(GLFWwindow* window, int key, int scancode, int action, int mods) | 	void glerminal::glfw_key_handler(GLFWwindow* window, int key, int scancode, int action, int mods) | ||||||
| 	{ | 	{ | ||||||
| 		glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window)); | 		const glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window)); | ||||||
|  |  | ||||||
| 		if (self->m_keypressed && action == GLFW_PRESS) | 		if (self->m_keypressed && action == GLFW_PRESS) | ||||||
| 		{ | 		{ | ||||||
| @@ -798,26 +858,26 @@ namespace glerminal | |||||||
|  |  | ||||||
| 	void glerminal::glfw_mousemoved_handler(GLFWwindow *window, double x, double y) | 	void glerminal::glfw_mousemoved_handler(GLFWwindow *window, double x, double y) | ||||||
| 	{ | 	{ | ||||||
| 		glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window)); | 		const glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window)); | ||||||
|  |  | ||||||
| 		if (self->m_mousemoved) { self->m_mousemoved(x / CELL_SIZE, y / CELL_SIZE); } | 		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) | 	void glerminal::glfw_mousepress_handler(GLFWwindow *window, int button, int action, int mods) | ||||||
| 	{ | 	{ | ||||||
| 		glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window)); | 		const glerminal* const self = static_cast<glerminal*>(glfwGetWindowUserPointer(window)); | ||||||
|  |  | ||||||
| 		double x, y; | 		double x, y; | ||||||
| 		glfwGetCursorPos(window, &x, &y); | 		glfwGetCursorPos(window, &x, &y); | ||||||
|  |  | ||||||
| 		if (self->m_mousepressed && action == GLFW_PRESS) | 		if (self->m_mousepressed && action == GLFW_PRESS) | ||||||
| 		{ | 		{ | ||||||
| 			self->m_mousepressed(button, x / CELL_SIZE, y / CELL_SIZE); | 			self->m_mousepressed(button, x / (CELL_SIZE * CELL_SCALE), y / (CELL_SIZE * CELL_SCALE)); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (self->m_mousereleased && action == GLFW_RELEASE) | 		if (self->m_mousereleased && action == GLFW_RELEASE) | ||||||
| 		{ | 		{ | ||||||
| 			self->m_mousereleased(button, x / CELL_SIZE, y / CELL_SIZE); | 			self->m_mousereleased(button, x / (CELL_SIZE * CELL_SCALE), y / (CELL_SIZE * CELL_SCALE)); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -851,39 +911,39 @@ void glerminal_flush() | |||||||
| 	GLERMINAL_G->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; } | 	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; } | 	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; } | 	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; } | 	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; } | 	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) | int glerminal_load_sprites_file(const char* filename) | ||||||
| @@ -896,7 +956,7 @@ int glerminal_load_sprites_file(const char* filename) | |||||||
| 	stbi_uc* const buffer = stbi_load(filename, &w, &h, nullptr, 4); | 	stbi_uc* const buffer = stbi_load(filename, &w, &h, nullptr, 4); | ||||||
|  |  | ||||||
| 	// verify atlas size is a multiple of CELL_SIZE in each dimension | 	// 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)); | 		GLERMINAL_G->load_atlas(w / glerminal::CELL_SIZE, h / glerminal::CELL_SIZE, reinterpret_cast<unsigned int*>(buffer)); | ||||||
|  |  | ||||||
| @@ -924,3 +984,10 @@ int glerminal_load_sprites_buffer(unsigned char width, unsigned char height, con | |||||||
| 		return false; | 		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 | 		${CMAKE_SOURCE_DIR}/source | ||||||
| ) | ) | ||||||
|  |  | ||||||
| target_link_libraries(test-common PRIVATE glerminallib) | target_link_libraries(test-common PRIVATE glerminal) | ||||||
|  |  | ||||||
| file(GLOB_RECURSE | file(GLOB_RECURSE | ||||||
| 	TEST_RESOURCES | 	TEST_RESOURCES | ||||||
| @@ -52,5 +52,5 @@ list(TRANSFORM TEST_RESOURCES PREPEND ${CMAKE_CURRENT_BINARY_DIR}/) | |||||||
| foreach(SOURCE_FILE ${TEST_SOURCES}) | foreach(SOURCE_FILE ${TEST_SOURCES}) | ||||||
| 	get_filename_component(SOURCE_FILENAME ${SOURCE_FILE} NAME_WLE) | 	get_filename_component(SOURCE_FILENAME ${SOURCE_FILE} NAME_WLE) | ||||||
| 	add_executable(test-${SOURCE_FILENAME} WIN32 ${SOURCE_FILE} ${TEST_RESOURCES}) | 	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() | endforeach() | ||||||
| @@ -8,7 +8,7 @@ | |||||||
|  |  | ||||||
| namespace | 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() | 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); | 	glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels); | ||||||
|  |  | ||||||
| 	stbi_flip_vertically_on_write(true); | 	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