opengl moment #1
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,7 @@ | |||||||
| .vs/ | .vs/ | ||||||
| .vscode/ | .vscode/ | ||||||
| .idea/ | .idea/ | ||||||
|  | .cache/ | ||||||
| .build/ | .build/ | ||||||
| build/ | build/ | ||||||
| out/ | out/ | ||||||
|   | |||||||
| @@ -23,6 +23,14 @@ add_subdirectory(third-party/physfs) | |||||||
| add_subdirectory(third-party/libxm) | add_subdirectory(third-party/libxm) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | if(UNIX) | ||||||
|  |         set(SYSTEM_SOURCE_FILES | ||||||
|  |                 src/system/linux/elf.c | ||||||
|  |         ) | ||||||
|  | else() | ||||||
|  |         set(SYSTEM_SOURCE_FILES) | ||||||
|  | endif() | ||||||
|  |  | ||||||
| set(SOURCE_FILES | set(SOURCE_FILES | ||||||
|         third-party/physfs/extras/physfsrwops.c |         third-party/physfs/extras/physfsrwops.c | ||||||
|         third-party/stb/stb_vorbis.c |         third-party/stb/stb_vorbis.c | ||||||
| @@ -49,6 +57,8 @@ set(SOURCE_FILES | |||||||
|         src/game/scenes/scene.c src/game/scenes/scene.h |         src/game/scenes/scene.c src/game/scenes/scene.h | ||||||
|         src/game/scenes/title.c src/game/scenes/title.h |         src/game/scenes/title.c src/game/scenes/title.h | ||||||
|         src/game/scenes/ingame.c src/game/scenes/ingame.h |         src/game/scenes/ingame.c src/game/scenes/ingame.h | ||||||
|  |  | ||||||
|  |         ${SYSTEM_SOURCE_FILES} | ||||||
| ) | ) | ||||||
|  |  | ||||||
| # target | # target | ||||||
| @@ -58,7 +68,7 @@ source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCE_FILES}) | |||||||
| set_target_properties(${PROJECT_NAME} PROPERTIES | set_target_properties(${PROJECT_NAME} PROPERTIES | ||||||
|                                       C_STANDARD 11 |                                       C_STANDARD 11 | ||||||
|                                       C_STANDARD_REQUIRED ON |                                       C_STANDARD_REQUIRED ON | ||||||
|                                       C_EXTENSIONS OFF) |                                       C_EXTENSIONS ON) # extensions are required by stb_ds.h | ||||||
|  |  | ||||||
| # distribution definitions | # distribution definitions | ||||||
| set(ORGANIZATION_NAME "wanp" CACHE STRING | set(ORGANIZATION_NAME "wanp" CACHE STRING | ||||||
| @@ -94,11 +104,22 @@ else() | |||||||
|                 -fno-trapping-math |                 -fno-trapping-math | ||||||
|                 -freciprocal-math) |                 -freciprocal-math) | ||||||
|         set(BUILD_FLAGS_RELEASE |         set(BUILD_FLAGS_RELEASE | ||||||
|                 -flto) |                 -O3 | ||||||
|  |                 -flto | ||||||
|  |                 -Wl,-gc-sections | ||||||
|  |                 -fdata-sections | ||||||
|  |                 -ffunction-sections | ||||||
|  |                 -funroll-loops | ||||||
|  |                 -fomit-frame-pointer | ||||||
|  |                 -fallow-store-data-races) | ||||||
|         set(BUILD_FLAGS_DEBUG |         set(BUILD_FLAGS_DEBUG | ||||||
|  |                 -O0 | ||||||
|                 -g3 |                 -g3 | ||||||
|                 -gdwarf |                 -gdwarf | ||||||
|                 -fsanitize-trap=undefined) |                 -fno-omit-frame-pointer | ||||||
|  |                 -fstack-protector-all | ||||||
|  |                 -fsanitize=undefined | ||||||
|  |                 -fsanitize=address) | ||||||
|         target_compile_options(${PROJECT_NAME} PRIVATE |         target_compile_options(${PROJECT_NAME} PRIVATE | ||||||
|                                                ${WARNING_FLAGS} |                                                ${WARNING_FLAGS} | ||||||
|                                                ${BUILD_FLAGS} |                                                ${BUILD_FLAGS} | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								data/assets/big-violet.png
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/assets/big-violet.png
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/assets/light.png
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/assets/light.png
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -57,7 +57,7 @@ static int64_t get_audio_data(const char *path, unsigned char **data) { | |||||||
|  |  | ||||||
|  |  | ||||||
| void play_audio(const char *path, const char *channel) { | void play_audio(const char *path, const char *channel) { | ||||||
|     const struct audio_channel_pair *pair = shgetp_null(ctx.audio_channels, channel); |     const struct audio_channel_item *pair = shgetp_null(ctx.audio_channels, channel); | ||||||
|     if (!pair) |     if (!pair) | ||||||
|         play_audio_ex(path, channel, get_default_audio_args()); |         play_audio_ex(path, channel, get_default_audio_args()); | ||||||
|     else |     else | ||||||
| @@ -166,7 +166,7 @@ static void repeat_audio(struct audio_channel *channel) { | |||||||
|  |  | ||||||
|  |  | ||||||
| void play_audio_ex(const char *path, const char *channel, t_play_audio_args args) { | void play_audio_ex(const char *path, const char *channel, t_play_audio_args args) { | ||||||
|     struct audio_channel_pair *pair = shgetp_null(ctx.audio_channels, channel); |     struct audio_channel_item *pair = shgetp_null(ctx.audio_channels, channel); | ||||||
|  |  | ||||||
|     /* create a channel if it doesn't exist */ |     /* create a channel if it doesn't exist */ | ||||||
|     if (!pair) { |     if (!pair) { | ||||||
| @@ -191,7 +191,7 @@ void play_audio_ex(const char *path, const char *channel, t_play_audio_args args | |||||||
|  |  | ||||||
|  |  | ||||||
| t_play_audio_args *get_audio_args(const char *channel) { | t_play_audio_args *get_audio_args(const char *channel) { | ||||||
|     struct audio_channel_pair *pair = shgetp_null(ctx.audio_channels, channel); |     struct audio_channel_item *pair = shgetp_null(ctx.audio_channels, channel); | ||||||
|     if (!pair) |     if (!pair) | ||||||
|         return NULL; |         return NULL; | ||||||
|  |  | ||||||
| @@ -244,7 +244,7 @@ static void audio_sample_and_mixin_channel(const struct audio_channel *channel, | |||||||
|     static uint8_t buffer[16384]; |     static uint8_t buffer[16384]; | ||||||
|     const int int16_buffer_frames = sizeof (buffer) / sizeof (int16_t); |     const int int16_buffer_frames = sizeof (buffer) / sizeof (int16_t); | ||||||
|     const int float_buffer_frames = sizeof (buffer) / sizeof (float); |     const int float_buffer_frames = sizeof (buffer) / sizeof (float); | ||||||
|     const int stream_frames = len / sizeof (int16_t); |     const int stream_frames = len / (int)(sizeof (int16_t)); | ||||||
|  |  | ||||||
|     switch (channel->file_type) { |     switch (channel->file_type) { | ||||||
|     case audio_file_type_ogg: { |     case audio_file_type_ogg: { | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ | |||||||
|  |  | ||||||
| #define RENDER_BASE_WIDTH 640 | #define RENDER_BASE_WIDTH 640 | ||||||
| #define RENDER_BASE_HEIGHT 360 | #define RENDER_BASE_HEIGHT 360 | ||||||
|  | #define RENDER_BASE_RATIO ((float)RENDER_BASE_WIDTH / (float)RENDER_BASE_HEIGHT) | ||||||
|  |  | ||||||
| #define TEXTURE_ATLAS_SIZE 2048 | #define TEXTURE_ATLAS_SIZE 2048 | ||||||
| #define TEXTURE_ATLAS_BIT_DEPTH 32 | #define TEXTURE_ATLAS_BIT_DEPTH 32 | ||||||
|   | |||||||
| @@ -20,11 +20,10 @@ typedef struct context { | |||||||
|     struct texture_cache texture_cache; |     struct texture_cache texture_cache; | ||||||
|     struct input_state input; |     struct input_state input; | ||||||
|  |  | ||||||
|     struct sprite_primitive *render_queue_sprites; |     struct primitive_2d *render_queue_2d; | ||||||
|     struct rect_primitive *render_queue_rectangles; |     struct mesh_batch_item *uncolored_mesh_batches; | ||||||
|     struct circle_primitive *render_queue_circles; |  | ||||||
|  |  | ||||||
|     struct audio_channel_pair *audio_channels; |     struct audio_channel_item *audio_channels; | ||||||
|     SDL_AudioDeviceID audio_device; |     SDL_AudioDeviceID audio_device; | ||||||
|     int audio_stream_frequency; |     int audio_stream_frequency; | ||||||
|     SDL_AudioFormat audio_stream_format; |     SDL_AudioFormat audio_stream_format; | ||||||
| @@ -51,7 +50,6 @@ typedef struct context { | |||||||
|     unsigned int update_multiplicity; |     unsigned int update_multiplicity; | ||||||
|  |  | ||||||
|     SDL_GLContext *gl_context; |     SDL_GLContext *gl_context; | ||||||
|     SDL_Renderer *renderer; |  | ||||||
|     SDL_Window *window; |     SDL_Window *window; | ||||||
|     uint32_t window_id; |     uint32_t window_id; | ||||||
|     int window_w; |     int window_w; | ||||||
| @@ -64,6 +62,8 @@ typedef struct context { | |||||||
|     bool debug; |     bool debug; | ||||||
|     bool is_running; |     bool is_running; | ||||||
|     bool resync_flag; |     bool resync_flag; | ||||||
|  |  | ||||||
|  |     bool window_size_has_changed; | ||||||
| } t_ctx; | } t_ctx; | ||||||
|  |  | ||||||
| extern t_ctx ctx; | extern t_ctx ctx; | ||||||
|   | |||||||
| @@ -11,7 +11,54 @@ static void ingame_tick(struct state *state) { | |||||||
|     world_drawdef(scn->world); |     world_drawdef(scn->world); | ||||||
|     player_calc(scn->player); |     player_calc(scn->player); | ||||||
|  |  | ||||||
|     get_audio_args("soundtrack")->volume -= 0.01f; |     for (size_t i = 100000; --i;) | ||||||
|  |         push_sprite_ex((t_frect){ .x = 32, .y = 64, .w = 64, .h = 64 }, (t_push_sprite_args){ | ||||||
|  |             .path = "/assets/light.png", | ||||||
|  |             .color = (t_color){255, 0, 0, 255}, | ||||||
|  |             .blend = false }); | ||||||
|  |  | ||||||
|  |     push_sprite_ex((t_frect){ .x = 48, .y = 64, .w = 64, .h = 64 }, (t_push_sprite_args){ | ||||||
|  |         .path = "/assets/light.png", | ||||||
|  |         .color = (t_color){0, 255, 0, 255}, | ||||||
|  |         .blend = true }); | ||||||
|  |  | ||||||
|  |     push_sprite_ex((t_frect){ .x = 64, .y = 64, .w = 64, .h = 64 }, (t_push_sprite_args){ | ||||||
|  |         .path = "/assets/light.png", | ||||||
|  |         .color = (t_color){0, 0, 255, 255}, | ||||||
|  |         .blend = true }); | ||||||
|  |  | ||||||
|  |     push_sprite_ex((t_frect){ .x = 32, .y = 32, .w = 64, .h = 64 }, (t_push_sprite_args){ | ||||||
|  |         .path = "/assets/player/baron-walk.png", | ||||||
|  |         .color = (t_color){255, 255, 255, 255}, | ||||||
|  |         .rotation = (float)M_PI * 2 * (float)(ctx.tick_count % 64) / 64, | ||||||
|  |         .blend = true }); | ||||||
|  |  | ||||||
|  |     push_sprite_ex((t_frect){ .x = 64, .y = 32, .w = 64, .h = 64 }, (t_push_sprite_args){ | ||||||
|  |         .path = "/assets/player/baron-walk.png", | ||||||
|  |         .color = (t_color){255, 255, 255, 255}, | ||||||
|  |         .rotation = (float)M_PI / 64, | ||||||
|  |         .blend = true }); | ||||||
|  |  | ||||||
|  |     push_sprite_ex((t_frect){ .x = 96, .y = 32, .w = 64, .h = 64 }, (t_push_sprite_args){ | ||||||
|  |         .path = "/assets/player/baron-walk.png", | ||||||
|  |         .color = (t_color){255, 255, 255, 255}, | ||||||
|  |         .blend = true }); | ||||||
|  |  | ||||||
|  |     unfurl_triangle("/assets/big-violet.png", | ||||||
|  |                     (t_fvec3){ -1, -1, 0 }, | ||||||
|  |                     (t_fvec3){ 1, -1, 0 }, | ||||||
|  |                     (t_fvec3){ 1, 1, 0 }, | ||||||
|  |                     (t_shvec2){ 0, 2048 }, | ||||||
|  |                     (t_shvec2){ 2048, 2048 }, | ||||||
|  |                     (t_shvec2){ 2048, 0 }); | ||||||
|  |  | ||||||
|  |     unfurl_triangle("/assets/big-violet.png", | ||||||
|  |                     (t_fvec3){ 1, 1, 0 }, | ||||||
|  |                     (t_fvec3){ -1, 1, 0 }, | ||||||
|  |                     (t_fvec3){ -1, -1, 0 }, | ||||||
|  |                     (t_shvec2){ 2048, 0 }, | ||||||
|  |                     (t_shvec2){ 0, 0 }, | ||||||
|  |                     (t_shvec2){ 0, 2048 }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -19,6 +66,7 @@ static void ingame_end(struct state *state) { | |||||||
|     struct scene_ingame *scn = (struct scene_ingame *)state->scene; |     struct scene_ingame *scn = (struct scene_ingame *)state->scene; | ||||||
|     player_destroy(scn->player); |     player_destroy(scn->player); | ||||||
|     world_destroy(scn->world); |     world_destroy(scn->world); | ||||||
|  |     free(state->scene); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ static void title_end(struct state *state) { | |||||||
|     struct scene_title *scn = (struct scene_title *)state->scene; |     struct scene_title *scn = (struct scene_title *)state->scene; | ||||||
|     player_destroy(scn->player); |     player_destroy(scn->player); | ||||||
|     world_destroy(scn->world); |     world_destroy(scn->world); | ||||||
|  |     free(state->scene); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
|  |  | ||||||
| #include "context.h" | #include "context.h" | ||||||
| #include "rendering.h" | #include "rendering.h" | ||||||
|  | #include "audio.h" | ||||||
| #include "util.h" | #include "util.h" | ||||||
|  |  | ||||||
| #include <SDL2/SDL.h> | #include <SDL2/SDL.h> | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								src/input.c
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/input.c
									
									
									
									
									
								
							| @@ -36,18 +36,21 @@ static void update_action_pressed_state(struct input_state *input, struct action | |||||||
|             else { |             else { | ||||||
|                 action->just_changed = !action->is_pressed; |                 action->just_changed = !action->is_pressed; | ||||||
|                 action->is_pressed = true; |                 action->is_pressed = true; | ||||||
|  |                 action->position.x = (float)input->mouse_window_position.x; | ||||||
|  |                 action->position.x = (float)input->mouse_window_position.x; | ||||||
|  |  | ||||||
|  |                 /* TODO: */ | ||||||
|                 /* |                 /* | ||||||
|                  * SDL_RenderWindowToLogical will turn window mouse |                  * SDL_RenderWindowToLogical will turn window mouse | ||||||
|                  * coords into a position inside the logical render |                  * coords into a position inside the logical render | ||||||
|                  * area. this has to be done to get an accurate point |                  * area. this has to be done to get an accurate point | ||||||
|                  * that can actually be used in game logic |                  * that can actually be used in game logic | ||||||
|                  */ |                  */ | ||||||
|                 SDL_RenderWindowToLogical(input->renderer, |                 // SDL_RenderWindowToLogical(input->renderer, | ||||||
|                                           input->mouse_window_position.x, |                 //                           input->mouse_window_position.x, | ||||||
|                                           input->mouse_window_position.y, |                 //                           input->mouse_window_position.y, | ||||||
|                                           &action->position.x, |                 //                           &action->position.x, | ||||||
|                                           &action->position.y); |                 //                           &action->position.y); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
| @@ -172,9 +175,8 @@ static void input_unbind_code_from_action(struct input_state *input, | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void input_state_init(struct input_state *input, SDL_Renderer *renderer) { | void input_state_init(struct input_state *input) { | ||||||
|     sh_new_strdup(input->action_hash); |     sh_new_strdup(input->action_hash); | ||||||
|     input->renderer = renderer; |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -54,7 +54,6 @@ struct action_hash_item { | |||||||
|  |  | ||||||
| struct input_state { | struct input_state { | ||||||
|     struct action_hash_item *action_hash; |     struct action_hash_item *action_hash; | ||||||
|     SDL_Renderer *renderer; /* some input relates to the screen in some way */ |  | ||||||
|     const uint8_t *keyboard_state; /* array of booleans indexed by scancode */ |     const uint8_t *keyboard_state; /* array of booleans indexed by scancode */ | ||||||
|     uint32_t mouse_state;          /* SDL mouse button bitmask */ |     uint32_t mouse_state;          /* SDL mouse button bitmask */ | ||||||
|     t_vec2 mouse_window_position; |     t_vec2 mouse_window_position; | ||||||
| @@ -63,7 +62,7 @@ struct input_state { | |||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
| void input_state_init(struct input_state *input, SDL_Renderer *renderer); | void input_state_init(struct input_state *input); | ||||||
| void input_state_deinit(struct input_state *input); | void input_state_deinit(struct input_state *input); | ||||||
| void input_state_update(struct input_state *input); | void input_state_update(struct input_state *input); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										61
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								src/main.c
									
									
									
									
									
								
							| @@ -23,6 +23,8 @@ | |||||||
| static void poll_events(void) { | static void poll_events(void) { | ||||||
|     SDL_Event e; |     SDL_Event e; | ||||||
|  |  | ||||||
|  |     ctx.window_size_has_changed = false; | ||||||
|  |  | ||||||
|     while (SDL_PollEvent(&e)) { |     while (SDL_PollEvent(&e)) { | ||||||
|         switch (e.type) { |         switch (e.type) { | ||||||
|         case SDL_QUIT: |         case SDL_QUIT: | ||||||
| @@ -35,6 +37,10 @@ static void poll_events(void) { | |||||||
|  |  | ||||||
|             switch (e.window.event) { |             switch (e.window.event) { | ||||||
|             case SDL_WINDOWEVENT_RESIZED: |             case SDL_WINDOWEVENT_RESIZED: | ||||||
|  |             case SDL_WINDOWEVENT_SIZE_CHANGED: | ||||||
|  |                 ctx.window_w = e.window.data1; | ||||||
|  |                 ctx.window_h = e.window.data2; | ||||||
|  |                 ctx.window_size_has_changed = true; | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -44,6 +50,24 @@ static void poll_events(void) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void APIENTRY opengl_log(GLenum source, | ||||||
|  |                                 GLenum type, | ||||||
|  |                                 GLuint id, | ||||||
|  |                                 GLenum severity, | ||||||
|  |                                 GLsizei length, | ||||||
|  |                                 const GLchar* message, | ||||||
|  |                                 const void* userParam) | ||||||
|  | { | ||||||
|  |     (void)source; | ||||||
|  |     (void)type; | ||||||
|  |     (void)id; | ||||||
|  |     (void)severity; | ||||||
|  |     (void)userParam; | ||||||
|  |  | ||||||
|  |     log_info("OpenGL: %.*s\n", length, message); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void main_loop(void) { | void main_loop(void) { | ||||||
|     /* |     /* | ||||||
|     if (!ctx.is_running) { |     if (!ctx.is_running) { | ||||||
| @@ -145,10 +169,12 @@ static bool initialize(void) { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); |  | ||||||
|  |  | ||||||
|     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); |     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); | ||||||
|     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5); |     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5); | ||||||
|  |     SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); | ||||||
|  |     SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); | ||||||
|  |     SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8); | ||||||
|  |     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | ||||||
|  |  | ||||||
|     /* init got far enough to create a window */ |     /* init got far enough to create a window */ | ||||||
|     ctx.window = SDL_CreateWindow("emerald", |     ctx.window = SDL_CreateWindow("emerald", | ||||||
| @@ -156,7 +182,7 @@ static bool initialize(void) { | |||||||
|                                    SDL_WINDOWPOS_CENTERED, |                                    SDL_WINDOWPOS_CENTERED, | ||||||
|                                    RENDER_BASE_WIDTH, |                                    RENDER_BASE_WIDTH, | ||||||
|                                    RENDER_BASE_HEIGHT, |                                    RENDER_BASE_HEIGHT, | ||||||
|                                    SDL_WINDOW_ALLOW_HIGHDPI | |                                    // SDL_WINDOW_ALLOW_HIGHDPI | | ||||||
|                                         SDL_WINDOW_RESIZABLE | |                                         SDL_WINDOW_RESIZABLE | | ||||||
|                                         SDL_WINDOW_OPENGL); |                                         SDL_WINDOW_OPENGL); | ||||||
|     if (ctx.window == NULL) { |     if (ctx.window == NULL) { | ||||||
| @@ -171,6 +197,7 @@ static bool initialize(void) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     SDL_GL_MakeCurrent(ctx.window, ctx.gl_context); |     SDL_GL_MakeCurrent(ctx.window, ctx.gl_context); | ||||||
|  |     SDL_GL_SetSwapInterval(1); | ||||||
|  |  | ||||||
|     int glad_status = gladLoadGL(); |     int glad_status = gladLoadGL(); | ||||||
|     if (glad_status == 0) { |     if (glad_status == 0) { | ||||||
| @@ -178,16 +205,17 @@ static bool initialize(void) { | |||||||
|         goto fail; |         goto fail; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     log_info("OpenGL context: %s\n", glGetString(GL_VERSION)); | ||||||
|  |  | ||||||
|     /* might need this to have multiple windows */ |     /* might need this to have multiple windows */ | ||||||
|     ctx.window_id = SDL_GetWindowID(ctx.window); |     ctx.window_id = SDL_GetWindowID(ctx.window); | ||||||
|  |  | ||||||
|     /* now that we have a window, we know a renderer can be created */ |     glViewport(0, 0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT); | ||||||
|     ctx.renderer = SDL_CreateRenderer(ctx.window, -1, SDL_RENDERER_PRESENTVSYNC); |  | ||||||
|  |  | ||||||
|     /* SDL_SetHint(SDL_HINT_RENDER_LOGICAL_SIZE_MODE, "overscan"); */ |     /* TODO: */ | ||||||
|     /* SDL_RenderSetIntegerScale(ctx.renderer, SDL_TRUE); */ |     // SDL_GetRendererOutputSize(ctx.renderer, &ctx.window_w, &ctx.window_h); | ||||||
|     SDL_RenderSetLogicalSize(ctx.renderer, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT); |     ctx.window_w = RENDER_BASE_WIDTH; | ||||||
|     SDL_GetRendererOutputSize(ctx.renderer, &ctx.window_w, &ctx.window_h); |     ctx.window_h = RENDER_BASE_HEIGHT; | ||||||
|  |  | ||||||
|     /* audio initialization */ |     /* audio initialization */ | ||||||
|     { |     { | ||||||
| @@ -235,6 +263,12 @@ static bool initialize(void) { | |||||||
|     ctx.debug = false; |     ctx.debug = false; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |     /* hook up opengl debugging callback */ | ||||||
|  |     if (ctx.debug) { | ||||||
|  |         glEnable(GL_DEBUG_OUTPUT); | ||||||
|  |         glDebugMessageCallback(opengl_log, NULL); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /* random seeding */ |     /* random seeding */ | ||||||
|     /* SDL_GetPerformanceCounter returns some platform-dependent number. */ |     /* SDL_GetPerformanceCounter returns some platform-dependent number. */ | ||||||
|     /* it should vary between game instances. i checked! random enough for me. */ |     /* it should vary between game instances. i checked! random enough for me. */ | ||||||
| @@ -259,9 +293,7 @@ static bool initialize(void) { | |||||||
|  |  | ||||||
|     /* rendering */ |     /* rendering */ | ||||||
|     /* these are dynamic arrays and will be allocated lazily by stb_ds */ |     /* these are dynamic arrays and will be allocated lazily by stb_ds */ | ||||||
|     ctx.render_queue_sprites = NULL; |     ctx.render_queue_2d = NULL; | ||||||
|     ctx.render_queue_rectangles = NULL; |  | ||||||
|     ctx.render_queue_circles = NULL; |  | ||||||
|     ctx.circle_radius_hash = NULL; |     ctx.circle_radius_hash = NULL; | ||||||
|  |  | ||||||
|     textures_cache_init(&ctx.texture_cache, ctx.window); |     textures_cache_init(&ctx.texture_cache, ctx.window); | ||||||
| @@ -271,7 +303,7 @@ static bool initialize(void) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* input */ |     /* input */ | ||||||
|     input_state_init(&ctx.input, ctx.renderer); |     input_state_init(&ctx.input); | ||||||
|  |  | ||||||
|     /* scripting */ |     /* scripting */ | ||||||
|     /* |     /* | ||||||
| @@ -296,8 +328,7 @@ static void clean_up(void) { | |||||||
|  |  | ||||||
|     input_state_deinit(&ctx.input); |     input_state_deinit(&ctx.input); | ||||||
|  |  | ||||||
|     arrfree(ctx.render_queue_sprites); |     arrfree(ctx.render_queue_2d); | ||||||
|     arrfree(ctx.render_queue_rectangles); |  | ||||||
|     textures_cache_deinit(&ctx.texture_cache); |     textures_cache_deinit(&ctx.texture_cache); | ||||||
|  |  | ||||||
|     PHYSFS_deinit(); |     PHYSFS_deinit(); | ||||||
|   | |||||||
| @@ -44,7 +44,7 @@ struct audio_channel { | |||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
| struct audio_channel_pair { | struct audio_channel_item { | ||||||
|     char *key; |     char *key; | ||||||
|     struct audio_channel value; |     struct audio_channel value; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -2,22 +2,22 @@ | |||||||
| #define PRIVATE_RENDERING_H | #define PRIVATE_RENDERING_H | ||||||
|  |  | ||||||
| #include "../rendering.h" | #include "../rendering.h" | ||||||
|  | #include "../textures.h" | ||||||
| #include "../util.h" | #include "../util.h" | ||||||
|  |  | ||||||
| #include <SDL2/SDL.h> | #include <SDL2/SDL.h> | ||||||
|  | #include <glad/glad.h> | ||||||
|  |  | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  |  | ||||||
| struct sprite_primitive { | struct sprite_primitive { | ||||||
|     t_frect rect; |     t_frect rect; | ||||||
|     t_color color; |     t_color color; | ||||||
|     double rotation; |     float rotation; | ||||||
|     char *path; |     t_texture_key texture_key; | ||||||
|     SDL_BlendMode blend_mode; |  | ||||||
|     int atlas_index; |  | ||||||
|     int layer; |  | ||||||
|     bool flip_x; |     bool flip_x; | ||||||
|     bool flip_y; |     bool flip_y; | ||||||
|  |     bool blend; /* must be explicitly stated, textures having alpha channel isn't enough */ | ||||||
| }; | }; | ||||||
|  |  | ||||||
| struct rect_primitive { | struct rect_primitive { | ||||||
| @@ -31,4 +31,54 @@ struct circle_primitive { | |||||||
|     t_fvec2 position; |     t_fvec2 position; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | enum primitive_2d_type { | ||||||
|  |     PRIMITIVE_2D_SPRITE, | ||||||
|  |     PRIMITIVE_2D_RECT, | ||||||
|  |     PRIMITIVE_2D_CIRCLE, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct primitive_2d { | ||||||
|  |     enum primitive_2d_type type; | ||||||
|  |  | ||||||
|  |     union { | ||||||
|  |         struct sprite_primitive sprite; | ||||||
|  |         struct rect_primitive rect; | ||||||
|  |         struct circle_primitive circle; | ||||||
|  |     }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* union for in-place recalculation of texture coordinates */ | ||||||
|  | union uncolored_space_triangle { | ||||||
|  |     /* pending for sending, uvs are not final as texture atlases could update */ | ||||||
|  |     struct uncolored_space_triangle_primitive { | ||||||
|  |         t_fvec3 v0; | ||||||
|  |         t_fvec2 uv0; /* in pixels */ | ||||||
|  |         t_fvec3 v1; | ||||||
|  |         t_fvec2 uv1; /* in pixels */ | ||||||
|  |         t_fvec3 v2; | ||||||
|  |         t_fvec2 uv2; /* in pixels */ | ||||||
|  |     } primitive; | ||||||
|  |  | ||||||
|  |     /* structure that is passed in opengl vertex array */ | ||||||
|  |     struct uncolored_space_triangle_payload { | ||||||
|  |         t_fvec3 v0; | ||||||
|  |         t_fvec2 uv0; | ||||||
|  |         t_fvec3 v1; | ||||||
|  |         t_fvec2 uv1; | ||||||
|  |         t_fvec3 v2; | ||||||
|  |         t_fvec2 uv2; | ||||||
|  |     } payload; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* batch of primitives with overlapping properties */ | ||||||
|  | struct mesh_batch { | ||||||
|  |     GLuint buffer;          /* server side storage */ | ||||||
|  |     uint8_t *primitives; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct mesh_batch_item { | ||||||
|  |     t_texture_key key; | ||||||
|  |     struct mesh_batch value; | ||||||
|  | }; | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								src/private/textures.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/private/textures.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | #ifndef PRIVATE_TEXTURES_H | ||||||
|  | #define PRIVATE_TEXTURES_H | ||||||
|  |  | ||||||
|  | #include "../util.h" | ||||||
|  |  | ||||||
|  | #include <SDL2/SDL.h> | ||||||
|  | #include <stb_rect_pack.h> | ||||||
|  | #include <glad/glad.h> | ||||||
|  |  | ||||||
|  | #include <stdbool.h> | ||||||
|  |  | ||||||
|  | struct texture { | ||||||
|  |     t_rect srcrect;             /* position in atlas */ | ||||||
|  |     SDL_Surface *data;          /* original image data */ | ||||||
|  |     int atlas_index; | ||||||
|  |     GLuint loner_texture;       /* stored directly for loners, == 0 means atlas_index should be used*/ | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | struct texture_cache_item { | ||||||
|  |     char *key; | ||||||
|  |     struct texture value; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | struct texture_cache { | ||||||
|  |     SDL_Window *window;          /* from context */ | ||||||
|  |  | ||||||
|  |     struct texture_cache_item *hash; | ||||||
|  |  | ||||||
|  |     stbrp_node *node_buffer;     /* used internally by stb_rect_pack */ | ||||||
|  |  | ||||||
|  |     SDL_Surface **atlas_surfaces; | ||||||
|  |     GLuint *atlas_textures;      /* shared by atlas textures */ | ||||||
|  |     int atlas_index;             /* atlas that is currently being built */ | ||||||
|  |  | ||||||
|  |     bool is_dirty;               /* current atlas needs to be recreated */ | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										425
									
								
								src/rendering.c
									
									
									
									
									
								
							
							
						
						
									
										425
									
								
								src/rendering.c
									
									
									
									
									
								
							| @@ -1,12 +1,15 @@ | |||||||
| #include "private/rendering.h" | #include "private/rendering.h" | ||||||
|  | #include "rendering/sprites.h" | ||||||
|  | #include "rendering/triangles.h" | ||||||
|  | #include "rendering/circles.h" | ||||||
| #include "context.h" | #include "context.h" | ||||||
| #include "textures.h" | #include "textures.h" | ||||||
|  |  | ||||||
| #include <SDL2/SDL.h> | #include <SDL2/SDL.h> | ||||||
| #include <stb_ds.h> |  | ||||||
| #include <glad/glad.h> | #include <glad/glad.h> | ||||||
|  | #include <stb_ds.h> | ||||||
|  |  | ||||||
| #include <stdlib.h> | #include <stddef.h> | ||||||
| #include <tgmath.h> | #include <tgmath.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -14,57 +17,10 @@ void render_queue_clear(void) { | |||||||
|     /* since i don't intend to free the queues, */ |     /* since i don't intend to free the queues, */ | ||||||
|     /* it's faster and simpler to just "start over" */ |     /* it's faster and simpler to just "start over" */ | ||||||
|     /* and start overwriting the existing data */ |     /* and start overwriting the existing data */ | ||||||
|     arrsetlen(ctx.render_queue_sprites, 0); |     arrsetlen(ctx.render_queue_2d, 0); | ||||||
|     arrsetlen(ctx.render_queue_rectangles, 0); |  | ||||||
|     arrsetlen(ctx.render_queue_circles, 0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; i < hmlenu(ctx.uncolored_mesh_batches); ++i) | ||||||
| /* |         arrsetlen(ctx.uncolored_mesh_batches[i].value.primitives, 0); | ||||||
|  * an implementation note: |  | ||||||
|  * try to avoid doing expensive work in the push functions, |  | ||||||
|  * because they will be called multiple times in the main loop |  | ||||||
|  * before anything is really rendered |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| /* sprite */ |  | ||||||
| void push_sprite(char *path, t_frect rect) { |  | ||||||
|     textures_load(&ctx.texture_cache, path); |  | ||||||
|  |  | ||||||
|     struct sprite_primitive sprite = { |  | ||||||
|         .rect = rect, |  | ||||||
|         .color = (t_color) { 255, 255, 255, 255 }, |  | ||||||
|         .path = path, |  | ||||||
|         .rotation = 0.0, |  | ||||||
|         .blend_mode = SDL_BLENDMODE_BLEND, |  | ||||||
|         .atlas_index = |  | ||||||
|             textures_get_atlas_index(&ctx.texture_cache, path), |  | ||||||
|         .layer = 0, |  | ||||||
|         .flip_x = false, |  | ||||||
|         .flip_y = false, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     arrput(ctx.render_queue_sprites, sprite); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void push_sprite_ex(t_frect rect, t_push_sprite_args args) { |  | ||||||
|     textures_load(&ctx.texture_cache, args.path); |  | ||||||
|  |  | ||||||
|     struct sprite_primitive sprite = { |  | ||||||
|         .rect = rect, |  | ||||||
|         .color = args.color, |  | ||||||
|         .path = args.path, |  | ||||||
|         .rotation = args.rotation, |  | ||||||
|         .blend_mode = args.blend_mode, |  | ||||||
|         .atlas_index =  |  | ||||||
|             textures_get_atlas_index(&ctx.texture_cache, args.path), |  | ||||||
|         .layer = args.layer, |  | ||||||
|         .flip_x = args.flip_x, |  | ||||||
|         .flip_y = args.flip_y, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     arrput(ctx.render_queue_sprites, sprite); |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -75,298 +31,153 @@ void push_rectangle(t_frect rect, t_color color) { | |||||||
|         .color = color, |         .color = color, | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     arrput(ctx.render_queue_rectangles, rectangle); |     struct primitive_2d primitive = { | ||||||
| } |         .type = PRIMITIVE_2D_RECT, | ||||||
|  |         .rect = rectangle, | ||||||
|  |  | ||||||
| /* circle */ |  | ||||||
| void push_circle(t_fvec2 position, float radius, t_color color) { |  | ||||||
|     struct circle_primitive circle = { |  | ||||||
|         .radius = radius, |  | ||||||
|         .color = color, |  | ||||||
|         .position = position, |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     arrput(ctx.render_queue_circles, circle); |     arrput(ctx.render_queue_2d, primitive); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /* compare functions for the sort in render_sprites */ | static void upload_quad_vertices(t_frect rect) { | ||||||
| static int cmp_atlases(const void *a, const void *b) { |     /* client memory needs to be reachable on glDraw*, so */ | ||||||
|     int index_a = ((const struct sprite_primitive *)a)->atlas_index; |     static float vertices[6 * 2]; | ||||||
|     int index_b = ((const struct sprite_primitive *)b)->atlas_index; |  | ||||||
|  |  | ||||||
|     return (index_a > index_b) - (index_a < index_b); |     vertices[0]  = rect.x;          vertices[1]  = rect.y; | ||||||
|  |     vertices[2]  = rect.x;          vertices[3]  = rect.y + rect.h; | ||||||
|  |     vertices[4]  = rect.x + rect.w; vertices[5]  = rect.y + rect.h; | ||||||
|  |     vertices[6]  = rect.x + rect.w; vertices[7]  = rect.y + rect.h; | ||||||
|  |     vertices[8]  = rect.x + rect.w; vertices[9]  = rect.y; | ||||||
|  |     vertices[10] = rect.x;          vertices[11] = rect.y; | ||||||
|  |  | ||||||
|  |     glVertexPointer(2, GL_FLOAT, 0, (void *)&vertices); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static int cmp_blend_modes(const void *a, const void *b) { | static void render_rectangle(const struct rect_primitive *rectangle) { | ||||||
|     SDL_BlendMode mode_a = ((const struct sprite_primitive *)a)->blend_mode; |     glColor4ub(rectangle->color.r, rectangle->color.g, | ||||||
|     SDL_BlendMode mode_b = ((const struct sprite_primitive *)b)->blend_mode; |                rectangle->color.b, rectangle->color.a); | ||||||
|  |  | ||||||
|     return (mode_a > mode_b) - (mode_a < mode_b); |     glEnableClientState(GL_VERTEX_ARRAY); | ||||||
|  |     upload_quad_vertices(rectangle->rect); | ||||||
|  |  | ||||||
|  |     glDrawArrays(GL_TRIANGLES, 0, 6); | ||||||
|  |     glDisableClientState(GL_VERTEX_ARRAY); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static int cmp_colors(const void *a, const void *b) { | static void render_2d(void) { | ||||||
|     t_color color_a = ((const struct sprite_primitive *)a)->color; |     glEnable(GL_TEXTURE_2D); | ||||||
|     t_color color_b = ((const struct sprite_primitive *)b)->color; |     glActiveTexture(GL_TEXTURE0); | ||||||
|  |     glDisable(GL_CULL_FACE); | ||||||
|  |     glDisable(GL_ALPHA_TEST); | ||||||
|  |     glEnable(GL_DEPTH_TEST); | ||||||
|  |  | ||||||
|     /* check reds */ |     const size_t render_queue_len = arrlenu(ctx.render_queue_2d); | ||||||
|     if (color_a.r < color_b.r) |  | ||||||
|         return -1; |  | ||||||
|     else if (color_a.r > color_b.r) |  | ||||||
|         return 1; |  | ||||||
|  |  | ||||||
|     /* reds were equal, check greens */ |     size_t batch_count = 0; | ||||||
|     else if (color_a.g < color_b.g) |  | ||||||
|         return -1; |  | ||||||
|     else if (color_a.g > color_b.g) |  | ||||||
|         return 1; |  | ||||||
|  |  | ||||||
|     /* greens were equal, check blues */ |     for (size_t i = 0; i < render_queue_len; ++i) { | ||||||
|     else if (color_a.b < color_b.b) |         const struct primitive_2d *current = &ctx.render_queue_2d[i]; | ||||||
|         return -1; |  | ||||||
|     else if (color_a.b > color_b.b) |  | ||||||
|         return 1; |  | ||||||
|  |  | ||||||
|     /* blues were equal, check alphas */ |         switch (current->type) { | ||||||
|     else if (color_a.a < color_b.a) |             case PRIMITIVE_2D_SPRITE: { | ||||||
|         return -1; |                 const struct sprite_batch batch = | ||||||
|     else if (color_a.a > color_b.a) |                     collect_sprite_batch(current, render_queue_len - i); | ||||||
|         return 1; |  | ||||||
|  |  | ||||||
|     /* entirely equal */ |                 glDepthRange((double)batch_count / UINT16_MAX, 1.0); | ||||||
|     else |  | ||||||
|         return 0; |                 render_sprites(current, batch); | ||||||
|  |  | ||||||
|  |                 i += batch.size - 1; ++batch_count; | ||||||
|  |                 break; | ||||||
|             } |             } | ||||||
|  |             case PRIMITIVE_2D_RECT: | ||||||
|  |                 render_rectangle(¤t->rect); | ||||||
| static int cmp_layers(const void *a, const void *b) { |                 break; | ||||||
|     int layer_a = ((const struct sprite_primitive *)a)->layer; |             case PRIMITIVE_2D_CIRCLE: | ||||||
|     int layer_b = ((const struct sprite_primitive *)b)->layer; |                 render_circle(¤t->circle); | ||||||
|  |                 break; | ||||||
|     return (layer_a > layer_b) - (layer_a < layer_b); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
| /* necessary to allow the renderer to draw in batches in the best case */ |  | ||||||
| static void sort_sprites(struct sprite_primitive *sprites) { |  | ||||||
|     size_t sprites_len = arrlenu(sprites); |  | ||||||
|     qsort(sprites, sprites_len, sizeof *sprites, cmp_atlases); |  | ||||||
|     qsort(sprites, sprites_len, sizeof *sprites, cmp_blend_modes); |  | ||||||
|     qsort(sprites, sprites_len, sizeof *sprites, cmp_colors); |  | ||||||
|     qsort(sprites, sprites_len, sizeof *sprites, cmp_layers); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void render_sprite(struct sprite_primitive *sprite) { |  | ||||||
|     SDL_Rect srcrect_value = { 0 }; |  | ||||||
|     SDL_Rect *srcrect = &srcrect_value; |  | ||||||
|     SDL_Texture *texture = NULL; |  | ||||||
|  |  | ||||||
|     /* loner */ |  | ||||||
|     if (sprite->atlas_index == -1) { |  | ||||||
|         srcrect = NULL; |  | ||||||
|         texture = textures_get_loner(&ctx.texture_cache, sprite->path); |  | ||||||
|     } else { |  | ||||||
|         *srcrect = textures_get_srcrect(&ctx.texture_cache, sprite->path); |  | ||||||
|         texture = textures_get_atlas(&ctx.texture_cache, sprite->atlas_index); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     SDL_RendererFlip flip = SDL_FLIP_NONE; |  | ||||||
|     if (sprite->flip_x) |  | ||||||
|         flip |= SDL_FLIP_HORIZONTAL; |  | ||||||
|     if (sprite->flip_y) |  | ||||||
|         flip |= SDL_FLIP_VERTICAL; |  | ||||||
|  |  | ||||||
|     SDL_SetTextureColorMod(texture, |  | ||||||
|                            sprite->color.r, |  | ||||||
|                            sprite->color.g, |  | ||||||
|                            sprite->color.b); |  | ||||||
|     SDL_SetTextureAlphaMod(texture, sprite->color.a); |  | ||||||
|     SDL_SetTextureBlendMode(texture, sprite->blend_mode); |  | ||||||
|  |  | ||||||
|     SDL_Rect rect = { |  | ||||||
|         (int)sprite->rect.x, |  | ||||||
|         (int)sprite->rect.y, |  | ||||||
|         (int)sprite->rect.w, |  | ||||||
|         (int)sprite->rect.h |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     SDL_RenderCopyEx(ctx.renderer, |  | ||||||
|                      texture, |  | ||||||
|                      srcrect, |  | ||||||
|                      &rect, |  | ||||||
|                      sprite->rotation, |  | ||||||
|                      NULL, |  | ||||||
|                      flip); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void render_rectangle(struct rect_primitive *rectangle) { |  | ||||||
|     SDL_SetRenderDrawColor(ctx.renderer, |  | ||||||
|                            rectangle->color.r, |  | ||||||
|                            rectangle->color.g, |  | ||||||
|                            rectangle->color.b, |  | ||||||
|                            rectangle->color.a); |  | ||||||
|  |  | ||||||
|     SDL_Rect rect = { |  | ||||||
|         (int)rectangle->rect.x, |  | ||||||
|         (int)rectangle->rect.y, |  | ||||||
|         (int)rectangle->rect.w, |  | ||||||
|         (int)rectangle->rect.h |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     SDL_RenderFillRect(ctx.renderer, &rect); |  | ||||||
|     SDL_SetRenderDrawColor(ctx.renderer, 255, 255, 255, 255); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* vertices_out and indices_out MUST BE FREED */ |  | ||||||
| static void create_circle_geometry(t_fvec2 position, |  | ||||||
|                                    t_color color, |  | ||||||
|                                    float radius, |  | ||||||
|                                    size_t num_vertices, |  | ||||||
|                                    SDL_Vertex **vertices_out, |  | ||||||
|                                    int **indices_out) |  | ||||||
| { |  | ||||||
|     SDL_Vertex *vertices = cmalloc(sizeof *vertices * (num_vertices + 1)); |  | ||||||
|     int *indices = cmalloc(sizeof *indices * (num_vertices * 3)); |  | ||||||
|  |  | ||||||
|     /* the angle (in radians) to rotate by on each iteration */ |  | ||||||
|     float seg_rotation_angle = (360.0f / (float)num_vertices) * ((float)M_PI / 180); |  | ||||||
|      |  | ||||||
|     vertices[0].position.x = (float)position.x; |  | ||||||
|     vertices[0].position.y = (float)position.y; |  | ||||||
|     vertices[0].color.r = color.r; |  | ||||||
|     vertices[0].color.g = color.g; |  | ||||||
|     vertices[0].color.b = color.b; |  | ||||||
|     vertices[0].color.a = color.a; |  | ||||||
|     vertices[0].tex_coord = (SDL_FPoint){ 0, 0 }; |  | ||||||
|  |  | ||||||
|     /* this point will rotate around the center */ |  | ||||||
|     float start_x = 0.0f - radius; |  | ||||||
|     float start_y = 0.0f; |  | ||||||
|  |  | ||||||
|     for (size_t i = 1; i < num_vertices + 1; ++i) { |  | ||||||
|         float final_seg_rotation_angle = (float)i * seg_rotation_angle; |  | ||||||
|  |  | ||||||
|         vertices[i].position.x = |  | ||||||
|             cos(final_seg_rotation_angle) * start_x - |  | ||||||
|             sin(final_seg_rotation_angle) * start_y; |  | ||||||
|         vertices[i].position.y = |  | ||||||
|             cos(final_seg_rotation_angle) * start_y + |  | ||||||
|             sin(final_seg_rotation_angle) * start_x; |  | ||||||
|  |  | ||||||
|         vertices[i].position.x += position.x; |  | ||||||
|         vertices[i].position.y += position.y; |  | ||||||
|  |  | ||||||
|         vertices[i].color.r = color.r; |  | ||||||
|         vertices[i].color.g = color.g; |  | ||||||
|         vertices[i].color.b = color.b; |  | ||||||
|         vertices[i].color.a = color.a; |  | ||||||
|  |  | ||||||
|         vertices[i].tex_coord = (SDL_FPoint){ 0, 0 }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         size_t triangle_offset = 3 * (i - 1); |  | ||||||
|  |  | ||||||
|         /* center point index */ |  | ||||||
|         indices[triangle_offset] = 0; |  | ||||||
|         /* generated point index */ |  | ||||||
|         indices[triangle_offset + 1] = (int)i; |  | ||||||
|  |  | ||||||
|         size_t index = (i + 1) % num_vertices; |  | ||||||
|         if (index == 0) |  | ||||||
|             index = num_vertices; |  | ||||||
|         indices[triangle_offset + 2] = (int)index; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     *vertices_out = vertices; |  | ||||||
|     *indices_out = indices; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void render_circle(struct circle_primitive *circle) { |  | ||||||
|     SDL_Vertex *vertices = NULL; |  | ||||||
|     int *indices = NULL; |  | ||||||
|     int num_vertices = (int)circle->radius; |  | ||||||
|  |  | ||||||
|     create_circle_geometry(circle->position, |  | ||||||
|                            circle->color, |  | ||||||
|                            circle->radius, |  | ||||||
|                            num_vertices, |  | ||||||
|                            &vertices, |  | ||||||
|                            &indices); |  | ||||||
|  |  | ||||||
|     SDL_RenderGeometry(ctx.renderer, NULL, |  | ||||||
|                        vertices, |  | ||||||
|                        num_vertices + 1, /* vertices + center vertex */ |  | ||||||
|                        indices, |  | ||||||
|                        num_vertices * 3); |  | ||||||
|  |  | ||||||
|     free(vertices); |  | ||||||
|     free(indices); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void render_sprites(void) { |  | ||||||
|     if (ctx.texture_cache.is_dirty) |  | ||||||
|         textures_update_current_atlas(&ctx.texture_cache); |  | ||||||
|  |  | ||||||
|     sort_sprites(ctx.render_queue_sprites); |  | ||||||
|  |  | ||||||
|     for (size_t i = 0; i < arrlenu(ctx.render_queue_sprites); ++i) { |  | ||||||
|         render_sprite(&ctx.render_queue_sprites[i]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void render_rectangles(void) { |  | ||||||
|     for (size_t i = 0; i < arrlenu(ctx.render_queue_rectangles); ++i) { |  | ||||||
|         render_rectangle(&ctx.render_queue_rectangles[i]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| static void render_circles(void) { |  | ||||||
|     for (size_t i = 0; i < arrlenu(ctx.render_queue_circles); ++i) { |  | ||||||
|         render_circle(&ctx.render_queue_circles[i]); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void render_space(void) { | static void render_space(void) { | ||||||
|     glMatrixMode(GL_PROJECTION); |     glEnable(GL_CULL_FACE); | ||||||
|     glPushMatrix(); |     glEnable(GL_DEPTH_TEST); | ||||||
|     glLoadIdentity(); |     glDisable(GL_ALPHA_TEST); | ||||||
|     glOrtho(0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0, -1, 1); |     glDepthFunc(GL_LESS); | ||||||
|  |     glEnable(GL_BLEND); | ||||||
|  |     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||||
|  |     glEnable(GL_TEXTURE_2D); | ||||||
|  |     glActiveTexture(GL_TEXTURE0); | ||||||
|  |  | ||||||
|     glBegin(GL_TRIANGLES); |     /* solid white, no modulation */ | ||||||
|     glColor4f(0.0, 1.0, 1.0, 1.0); |     glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | ||||||
|     glVertex2f(300.0,210.0); |  | ||||||
|     glVertex2f(340.0,215.0); |  | ||||||
|     glVertex2f(320.0,250.0); |  | ||||||
|     glEnd(); |  | ||||||
|  |  | ||||||
|     glPopMatrix(); |     for (size_t i = 0; i < hmlenu(ctx.uncolored_mesh_batches); ++i) { | ||||||
|  |         draw_uncolored_space_traingle_batch(&ctx.uncolored_mesh_batches[i].value, | ||||||
|  |                                             ctx.uncolored_mesh_batches[i].key); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void render(void) { | void render(void) { | ||||||
|  |     textures_update_atlas(&ctx.texture_cache); | ||||||
|  |  | ||||||
|  |     /* fit rendering context onto the resizable screen */ | ||||||
|  |     if (ctx.window_size_has_changed) { | ||||||
|  |         if ((float)ctx.window_w / (float)ctx.window_h > RENDER_BASE_RATIO) { | ||||||
|  |             float ratio = (float)ctx.window_h / (float)RENDER_BASE_HEIGHT; | ||||||
|  |             int w = (int)((float)RENDER_BASE_WIDTH * ratio); | ||||||
|  |             glViewport( | ||||||
|  |                 ctx.window_w / 2 - w / 2, | ||||||
|  |                 0, | ||||||
|  |                 w, | ||||||
|  |                 ctx.window_h | ||||||
|  |             ); | ||||||
|  |         } else { | ||||||
|  |             float ratio = (float)ctx.window_w / (float)RENDER_BASE_WIDTH; | ||||||
|  |             int h = (int)((float)RENDER_BASE_HEIGHT * ratio); | ||||||
|  |             glViewport( | ||||||
|  |                 0, | ||||||
|  |                 ctx.window_h / 2 - h / 2, | ||||||
|  |                 ctx.window_w, | ||||||
|  |                 h | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     glClearColor((1.0f / 255) * 230, |     glClearColor((1.0f / 255) * 230, | ||||||
|                  (1.0f / 255) * 230, |                  (1.0f / 255) * 230, | ||||||
|                  (1.0f / 255) * 230, 1); |                  (1.0f / 255) * 230, 1); | ||||||
|  |  | ||||||
|     glClear(GL_COLOR_BUFFER_BIT); |     glClear(GL_COLOR_BUFFER_BIT | | ||||||
|  |             GL_DEPTH_BUFFER_BIT | | ||||||
|  |             GL_STENCIL_BUFFER_BIT); | ||||||
|  |  | ||||||
|  |     { | ||||||
|  |         glMatrixMode(GL_PROJECTION); | ||||||
|  |         glLoadIdentity(); | ||||||
|  |  | ||||||
|  |         glMatrixMode(GL_MODELVIEW); | ||||||
|  |         glLoadIdentity(); | ||||||
|  |  | ||||||
|         render_space(); |         render_space(); | ||||||
|     render_sprites(); |     } | ||||||
|     render_rectangles(); |  | ||||||
|     render_circles(); |     { | ||||||
|  |         glMatrixMode(GL_PROJECTION); | ||||||
|  |         glLoadIdentity(); | ||||||
|  |         glOrtho(0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0, -1, 1); | ||||||
|  |  | ||||||
|  |         glMatrixMode(GL_MODELVIEW); | ||||||
|  |         glLoadIdentity(); | ||||||
|  |  | ||||||
|  |         render_2d(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // SDL_RenderPresent(ctx.renderer); |  | ||||||
|     SDL_RenderFlush(ctx.renderer); |  | ||||||
|     SDL_GL_SwapWindow(ctx.window); |     SDL_GL_SwapWindow(ctx.window); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,12 +9,11 @@ | |||||||
|  |  | ||||||
| typedef struct push_sprite_args { | typedef struct push_sprite_args { | ||||||
|     char *path; |     char *path; | ||||||
|     int layer; |  | ||||||
|     t_color color; |     t_color color; | ||||||
|     double rotation; |     float rotation; | ||||||
|     SDL_BlendMode blend_mode; |  | ||||||
|     bool flip_x; |     bool flip_x; | ||||||
|     bool flip_y; |     bool flip_y; | ||||||
|  |     bool blend; | ||||||
| } t_push_sprite_args; | } t_push_sprite_args; | ||||||
|  |  | ||||||
| /* clears all render queues */ | /* clears all render queues */ | ||||||
| @@ -35,6 +34,36 @@ void push_rectangle(t_frect rect, t_color color); | |||||||
| /* pushes a filled circle onto the circle render queue */ | /* pushes a filled circle onto the circle render queue */ | ||||||
| void push_circle(t_fvec2 position, float radius, t_color color); | void push_circle(t_fvec2 position, float radius, t_color color); | ||||||
|  |  | ||||||
|  | /* pushes a textured 3d triangle onto the render queue */ | ||||||
|  | /* vertices are in absolute coordinates, relative to world origin */ | ||||||
|  | /* texture coordinates are in pixels */ | ||||||
|  | void unfurl_triangle(const char *path, | ||||||
|  |                      t_fvec3 v0, | ||||||
|  |                      t_fvec3 v1, | ||||||
|  |                      t_fvec3 v2, | ||||||
|  |                      t_shvec2 uv0, | ||||||
|  |                      t_shvec2 uv1, | ||||||
|  |                      t_shvec2 uv2); | ||||||
|  |  | ||||||
|  | /* pushes a colored textured 3d triangle onto the render queue */ | ||||||
|  | // void unfurl_colored_triangle(const char *path, | ||||||
|  | //                              t_fvec3 v0, | ||||||
|  | //                              t_fvec3 v1, | ||||||
|  | //                              t_fvec3 v2, | ||||||
|  | //                              t_shvec2 uv0, | ||||||
|  | //                              t_shvec2 uv1, | ||||||
|  | //                              t_shvec2 uv2, | ||||||
|  | //                              t_color c0, | ||||||
|  | //                              t_color c1, | ||||||
|  | //                              t_color c2); | ||||||
|  |  | ||||||
|  | // TODO: | ||||||
|  | // http://www.lighthouse3d.com/opengl/billboarding/index.php?billCheat2 | ||||||
|  | // void unfurl_billboard(const char *path, | ||||||
|  | //                      t_fvec3 position, | ||||||
|  | //                      t_fvec2 scaling, | ||||||
|  | //                      t_frect uvs); | ||||||
|  |  | ||||||
| /* renders the background, then the primitives in all render queues */ | /* renders the background, then the primitives in all render queues */ | ||||||
| void render(void); | void render(void); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										132
									
								
								src/rendering/circles.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								src/rendering/circles.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,132 @@ | |||||||
|  | /* a rendering.c mixin */ | ||||||
|  | #ifndef CIRCLES_H | ||||||
|  | #define CIRCLES_H | ||||||
|  |  | ||||||
|  | #include "../util.h" | ||||||
|  | #include "../private/rendering.h" | ||||||
|  | #include "../context.h" | ||||||
|  |  | ||||||
|  | #include <SDL2/SDL.h> | ||||||
|  | #include <stb_ds.h> | ||||||
|  |  | ||||||
|  | #include <stdlib.h> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void push_circle(t_fvec2 position, float radius, t_color color) { | ||||||
|  |     struct circle_primitive circle = { | ||||||
|  |         .radius = radius, | ||||||
|  |         .color = color, | ||||||
|  |         .position = position, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct primitive_2d primitive = { | ||||||
|  |         .type = PRIMITIVE_2D_CIRCLE, | ||||||
|  |         .circle = circle, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     arrput(ctx.render_queue_2d, primitive); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* TODO: caching and reuse scheme */ | ||||||
|  | /* vertices_out and indices_out MUST BE FREED */ | ||||||
|  | static void create_circle_geometry(t_fvec2 position, | ||||||
|  |                                    t_color color, | ||||||
|  |                                    float radius, | ||||||
|  |                                    size_t num_vertices, | ||||||
|  |                                    SDL_Vertex **vertices_out, | ||||||
|  |                                    int **indices_out) | ||||||
|  | { | ||||||
|  |     SDL_Vertex *vertices = cmalloc(sizeof *vertices * (num_vertices + 1)); | ||||||
|  |     int *indices = cmalloc(sizeof *indices * (num_vertices * 3)); | ||||||
|  |  | ||||||
|  |     /* the angle (in radians) to rotate by on each iteration */ | ||||||
|  |     float seg_rotation_angle = (360.0f / (float)num_vertices) * ((float)M_PI / 180); | ||||||
|  |  | ||||||
|  |     vertices[0].position.x = (float)position.x; | ||||||
|  |     vertices[0].position.y = (float)position.y; | ||||||
|  |     vertices[0].color.r = color.r; | ||||||
|  |     vertices[0].color.g = color.g; | ||||||
|  |     vertices[0].color.b = color.b; | ||||||
|  |     vertices[0].color.a = color.a; | ||||||
|  |     vertices[0].tex_coord = (SDL_FPoint){ 0, 0 }; | ||||||
|  |  | ||||||
|  |     /* this point will rotate around the center */ | ||||||
|  |     float start_x = 0.0f - radius; | ||||||
|  |     float start_y = 0.0f; | ||||||
|  |  | ||||||
|  |     for (size_t i = 1; i < num_vertices + 1; ++i) { | ||||||
|  |         float final_seg_rotation_angle = (float)i * seg_rotation_angle; | ||||||
|  |  | ||||||
|  |         vertices[i].position.x = | ||||||
|  |             cosf(final_seg_rotation_angle) * start_x - | ||||||
|  |             sinf(final_seg_rotation_angle) * start_y; | ||||||
|  |         vertices[i].position.y = | ||||||
|  |             cosf(final_seg_rotation_angle) * start_y + | ||||||
|  |             sinf(final_seg_rotation_angle) * start_x; | ||||||
|  |  | ||||||
|  |         vertices[i].position.x += position.x; | ||||||
|  |         vertices[i].position.y += position.y; | ||||||
|  |  | ||||||
|  |         vertices[i].color.r = color.r; | ||||||
|  |         vertices[i].color.g = color.g; | ||||||
|  |         vertices[i].color.b = color.b; | ||||||
|  |         vertices[i].color.a = color.a; | ||||||
|  |  | ||||||
|  |         vertices[i].tex_coord = (SDL_FPoint){ 0, 0 }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         size_t triangle_offset = 3 * (i - 1); | ||||||
|  |  | ||||||
|  |         /* center point index */ | ||||||
|  |         indices[triangle_offset] = 0; | ||||||
|  |         /* generated point index */ | ||||||
|  |         indices[triangle_offset + 1] = (int)i; | ||||||
|  |  | ||||||
|  |         size_t index = (i + 1) % num_vertices; | ||||||
|  |         if (index == 0) | ||||||
|  |             index = num_vertices; | ||||||
|  |         indices[triangle_offset + 2] = (int)index; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     *vertices_out = vertices; | ||||||
|  |     *indices_out = indices; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void render_circle(const struct circle_primitive *circle) { | ||||||
|  |     SDL_Vertex *vertices = NULL; | ||||||
|  |     int *indices = NULL; | ||||||
|  |     int num_vertices = (int)circle->radius; | ||||||
|  |  | ||||||
|  |     create_circle_geometry(circle->position, | ||||||
|  |                            circle->color, | ||||||
|  |                            circle->radius, | ||||||
|  |                            num_vertices, | ||||||
|  |                            &vertices, | ||||||
|  |                            &indices); | ||||||
|  |  | ||||||
|  |     glEnableClientState(GL_VERTEX_ARRAY); | ||||||
|  |     glVertexPointer(2, | ||||||
|  |                     GL_FLOAT, | ||||||
|  |                     sizeof (SDL_Vertex), | ||||||
|  |                     &vertices->position); | ||||||
|  |  | ||||||
|  |     glEnableClientState(GL_COLOR_ARRAY); | ||||||
|  |     glColorPointer(4, | ||||||
|  |                    GL_UNSIGNED_BYTE, | ||||||
|  |                    sizeof (SDL_Vertex), | ||||||
|  |                    &vertices->color); | ||||||
|  |  | ||||||
|  |     glDrawElements(GL_TRIANGLES, | ||||||
|  |                    num_vertices * 3, | ||||||
|  |                    GL_UNSIGNED_INT, | ||||||
|  |                    indices); | ||||||
|  |  | ||||||
|  |     glDisableClientState(GL_COLOR_ARRAY); | ||||||
|  |     glDisableClientState(GL_VERTEX_ARRAY); | ||||||
|  |  | ||||||
|  |     free(vertices); | ||||||
|  |     free(indices); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										41
									
								
								src/rendering/quad_element_buffer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/rendering/quad_element_buffer.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | /* a rendering.c mixin */ | ||||||
|  | #ifndef QUAD_ELEMENT_BUFFER_H | ||||||
|  | #define QUAD_ELEMENT_BUFFER_H | ||||||
|  |  | ||||||
|  | #include <glad/glad.h> | ||||||
|  |  | ||||||
|  | #include <stddef.h> | ||||||
|  |  | ||||||
|  | #define QUAD_ELEMENT_BUFFER_LENGTH (65536 / 6) | ||||||
|  |  | ||||||
|  | static void bind_quad_element_buffer(void) { | ||||||
|  |     static GLuint buffer = 0; | ||||||
|  |  | ||||||
|  |     /* it's only generated once at runtime */ | ||||||
|  |     if (buffer == 0) { | ||||||
|  |         glGenBuffers(1, &buffer); | ||||||
|  |         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer); | ||||||
|  |         glBufferData(GL_ELEMENT_ARRAY_BUFFER, | ||||||
|  |                      QUAD_ELEMENT_BUFFER_LENGTH * 6, | ||||||
|  |                      NULL, | ||||||
|  |                      GL_STATIC_DRAW); | ||||||
|  |  | ||||||
|  |         uint16_t *const indices = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, | ||||||
|  |                                               GL_WRITE_ONLY); | ||||||
|  |  | ||||||
|  |         for (uint16_t i = 0; i < QUAD_ELEMENT_BUFFER_LENGTH; ++i) { | ||||||
|  |             indices[i * 6 + 0] = (uint16_t)(i * 4 + 0); | ||||||
|  |             indices[i * 6 + 1] = (uint16_t)(i * 4 + 1); | ||||||
|  |             indices[i * 6 + 2] = (uint16_t)(i * 4 + 2); | ||||||
|  |             indices[i * 6 + 3] = (uint16_t)(i * 4 + 2); | ||||||
|  |             indices[i * 6 + 4] = (uint16_t)(i * 4 + 3); | ||||||
|  |             indices[i * 6 + 5] = (uint16_t)(i * 4 + 0); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); | ||||||
|  |  | ||||||
|  |     } else | ||||||
|  |         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										332
									
								
								src/rendering/sprites.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										332
									
								
								src/rendering/sprites.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,332 @@ | |||||||
|  | /* a rendering.c mixin */ | ||||||
|  | #ifndef SPRITES_H | ||||||
|  | #define SPRITES_H | ||||||
|  |  | ||||||
|  | #include "../textures.h" | ||||||
|  | #include "../rendering.h" | ||||||
|  | #include "../context.h" | ||||||
|  | #include "../util.h" | ||||||
|  | #include "quad_element_buffer.h" | ||||||
|  |  | ||||||
|  | #include <stb_ds.h> | ||||||
|  |  | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stddef.h> | ||||||
|  |  | ||||||
|  | /* interleaved vertex array data */ | ||||||
|  | /* TODO: use int16_t for uvs */ | ||||||
|  | /* TODO: int16_t could be used for positioning, but we would need to have more CPU calcs */ | ||||||
|  | struct sprite_primitive_payload { | ||||||
|  |     /* upper-left */ | ||||||
|  |     t_fvec2 v0; | ||||||
|  |     t_fvec2 uv0; | ||||||
|  |     t_color c0; | ||||||
|  |     /* bottom-left */ | ||||||
|  |     t_fvec2 v1; | ||||||
|  |     t_fvec2 uv1; | ||||||
|  |     t_color c1; | ||||||
|  |     /* bottom-right */ | ||||||
|  |     t_fvec2 v2; | ||||||
|  |     t_fvec2 uv2; | ||||||
|  |     t_color c2; | ||||||
|  |     /* upper-right */ | ||||||
|  |     t_fvec2 v3; | ||||||
|  |     t_fvec2 uv3; | ||||||
|  |     t_color c3; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | struct sprite_primitive_payload_without_color { | ||||||
|  |     /* upper-left */ | ||||||
|  |     t_fvec2 v0; | ||||||
|  |     t_fvec2 uv0; | ||||||
|  |     /* bottom-left */ | ||||||
|  |     t_fvec2 v1; | ||||||
|  |     t_fvec2 uv1; | ||||||
|  |     /* bottom-right */ | ||||||
|  |     t_fvec2 v2; | ||||||
|  |     t_fvec2 uv2; | ||||||
|  |     /* upper-right */ | ||||||
|  |     t_fvec2 v3; | ||||||
|  |     t_fvec2 uv3; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * an implementation note: | ||||||
|  |  * try to avoid doing expensive work in the push functions, | ||||||
|  |  * because they will be called multiple times in the main loop | ||||||
|  |  * before anything is really rendered | ||||||
|  |  */ | ||||||
|  | /* TODO: it might make sense to infer alpha channel presence / meaningfulness for textures in atlas */ | ||||||
|  | /*          so that they are rendered with no blend / batched in a way to reduce overdraw automatically */ | ||||||
|  | void push_sprite(char *path, t_frect rect) { | ||||||
|  |     struct sprite_primitive sprite = { | ||||||
|  |         .rect = rect, | ||||||
|  |         .color = (t_color) { 255, 255, 255, 255 }, | ||||||
|  |         .rotation = 0.0, | ||||||
|  |         .texture_key = textures_get_key(&ctx.texture_cache, path), | ||||||
|  |         .flip_x = false, | ||||||
|  |         .flip_y = false, | ||||||
|  |         .blend = true, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct primitive_2d primitive = { | ||||||
|  |         .type = PRIMITIVE_2D_SPRITE, | ||||||
|  |         .sprite = sprite, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     arrput(ctx.render_queue_2d, primitive); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void push_sprite_ex(t_frect rect, t_push_sprite_args args) { | ||||||
|  |     struct sprite_primitive sprite = { | ||||||
|  |         .rect = rect, | ||||||
|  |         .color = args.color, | ||||||
|  |         .rotation = args.rotation, | ||||||
|  |         .texture_key = textures_get_key(&ctx.texture_cache, args.path), | ||||||
|  |         .flip_x = args.flip_x, | ||||||
|  |         .flip_y = args.flip_y, | ||||||
|  |         .blend = args.blend, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct primitive_2d primitive = { | ||||||
|  |         .type = PRIMITIVE_2D_SPRITE, | ||||||
|  |         .sprite = sprite, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     arrput(ctx.render_queue_2d, primitive); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static struct sprite_batch { | ||||||
|  |     int atlas_id; | ||||||
|  |     size_t size;             /* how many primitives are in current batch */ | ||||||
|  |     bool blend;              /* whether it's blended or not */ | ||||||
|  |     bool constant_colored;   /* whether colored batch is uniformly colored */ | ||||||
|  | } collect_sprite_batch(const struct primitive_2d *primitives, size_t len) { | ||||||
|  |     /* assumes that first primitive is already a sprite */ | ||||||
|  |     struct sprite_batch batch = { | ||||||
|  |         .atlas_id = | ||||||
|  |             textures_get_atlas_id(&ctx.texture_cache, primitives[0].sprite.texture_key), | ||||||
|  |         .blend = primitives[0].sprite.blend, | ||||||
|  |         .constant_colored = true, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     const t_color uniform_color = primitives[0].sprite.color; | ||||||
|  |  | ||||||
|  |     /* batch size is clamped so that reallocated short indices could be used */ | ||||||
|  |     if (len >= QUAD_ELEMENT_BUFFER_LENGTH) | ||||||
|  |         len = QUAD_ELEMENT_BUFFER_LENGTH; | ||||||
|  |  | ||||||
|  |     for (size_t i = 0; i < len; ++i) { | ||||||
|  |         const struct primitive_2d *const current = &primitives[i]; | ||||||
|  |  | ||||||
|  |         /* don't touch things other than sprites */ | ||||||
|  |         if (current->type != PRIMITIVE_2D_SPRITE) | ||||||
|  |             break; | ||||||
|  |  | ||||||
|  |         /* only collect the same blend modes */ | ||||||
|  |         if (current->sprite.blend != batch.blend) | ||||||
|  |             break; | ||||||
|  |  | ||||||
|  |         /* only collect the same texture atlases */ | ||||||
|  |         if (textures_get_atlas_id(&ctx.texture_cache, current->sprite.texture_key) | ||||||
|  |                 != batch.atlas_id) | ||||||
|  |             break; | ||||||
|  |  | ||||||
|  |         /* if all are modulated the same we can skip sending the color data */ | ||||||
|  |         if (batch.constant_colored && (current->sprite.color.r != uniform_color.r || | ||||||
|  |                                        current->sprite.color.g != uniform_color.g || | ||||||
|  |                                        current->sprite.color.b != uniform_color.b || | ||||||
|  |                                        current->sprite.color.a != uniform_color.a )) | ||||||
|  |             batch.constant_colored = false; | ||||||
|  |  | ||||||
|  |         ++batch.size; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return batch; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* assumes that orthogonal matrix setup is done already */ | ||||||
|  | static void render_sprites(const struct primitive_2d primitives[], | ||||||
|  |                            const struct sprite_batch batch) | ||||||
|  | { | ||||||
|  |     /* single vertex array is used for every batch with NULL glBufferData() trick at the end */ | ||||||
|  |     static GLuint vertex_array = 0; | ||||||
|  |     if (vertex_array == 0) | ||||||
|  |         glGenBuffers(1, &vertex_array); | ||||||
|  |  | ||||||
|  |     if (batch.blend) { | ||||||
|  |         glEnable(GL_BLEND); | ||||||
|  |         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||||
|  |         glDepthFunc(GL_ALWAYS); | ||||||
|  |     } else { | ||||||
|  |         glDisable(GL_BLEND); | ||||||
|  |         glDepthFunc(GL_LESS); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     size_t payload_size; | ||||||
|  |     if (!batch.constant_colored) | ||||||
|  |         payload_size = sizeof (struct sprite_primitive_payload); | ||||||
|  |     else | ||||||
|  |         payload_size = sizeof (struct sprite_primitive_payload_without_color); | ||||||
|  |  | ||||||
|  |     glBindBuffer(GL_ARRAY_BUFFER, vertex_array); | ||||||
|  |     glBufferData(GL_ARRAY_BUFFER, | ||||||
|  |                  payload_size * batch.size, | ||||||
|  |                  NULL, | ||||||
|  |                  GL_STREAM_DRAW); | ||||||
|  |  | ||||||
|  |     const t_rect dims = | ||||||
|  |         textures_get_dims(&ctx.texture_cache, primitives->sprite.texture_key); | ||||||
|  |  | ||||||
|  |     /* vertex population over a mapped buffer */ | ||||||
|  |     { | ||||||
|  |         /* TODO: check errors, ensure alignment ? */ | ||||||
|  |         void *const payload = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); | ||||||
|  |  | ||||||
|  |         for (size_t i = 0; i < batch.size; ++i) { | ||||||
|  |             const size_t cur = !batch.blend ? batch.size - i - 1: i; /* render opaques front to back */ | ||||||
|  |             const struct sprite_primitive sprite = primitives[cur].sprite; | ||||||
|  |  | ||||||
|  |             const t_rect srcrect = | ||||||
|  |                 textures_get_srcrect(&ctx.texture_cache, primitives[cur].sprite.texture_key); | ||||||
|  |  | ||||||
|  |             const float wr = (float)srcrect.w / (float)dims.w; | ||||||
|  |             const float hr = (float)srcrect.h / (float)dims.h; | ||||||
|  |             const float xr = (float)srcrect.x / (float)dims.w; | ||||||
|  |             const float yr = (float)srcrect.y / (float)dims.h; | ||||||
|  |  | ||||||
|  |             t_fvec2 uv0 = { xr + wr *  sprite.flip_x, yr + hr *  sprite.flip_y }; | ||||||
|  |             t_fvec2 uv1 = { xr + wr *  sprite.flip_x, yr + hr * !sprite.flip_y }; | ||||||
|  |             t_fvec2 uv2 = { xr + wr * !sprite.flip_x, yr + hr * !sprite.flip_y }; | ||||||
|  |             t_fvec2 uv3 = { xr + wr * !sprite.flip_x, yr + hr *  sprite.flip_y }; | ||||||
|  |  | ||||||
|  |             t_fvec2 v0, v1, v2, v3; | ||||||
|  |  | ||||||
|  |             /* todo: fast PI/2 degree divisible rotations? */ | ||||||
|  |             if (sprite.rotation == 0.0f) { | ||||||
|  |                 /* non-rotated case */ | ||||||
|  |  | ||||||
|  |                 v0 = (t_fvec2){ sprite.rect.x,                 sprite.rect.y }; | ||||||
|  |                 v1 = (t_fvec2){ sprite.rect.x,                 sprite.rect.y + sprite.rect.h }; | ||||||
|  |                 v2 = (t_fvec2){ sprite.rect.x + sprite.rect.w, sprite.rect.y + sprite.rect.h }; | ||||||
|  |                 v3 = (t_fvec2){ sprite.rect.x + sprite.rect.w, sprite.rect.y }; | ||||||
|  |  | ||||||
|  |             } else if (sprite.rect.w == sprite.rect.h) { | ||||||
|  |                 /* rotated square case */ | ||||||
|  |  | ||||||
|  |                 const t_fvec2 c = frect_center(sprite.rect); | ||||||
|  |                 const t_fvec2 t = fast_cossine(sprite.rotation + (float)M_PI_4); | ||||||
|  |                 const t_fvec2 d = { | ||||||
|  |                     .x = t.x * sprite.rect.w * (float)M_SQRT1_2, | ||||||
|  |                     .y = t.y * sprite.rect.h * (float)M_SQRT1_2, | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 v0 = (t_fvec2){ c.x - d.x, c.y - d.y }; | ||||||
|  |                 v1 = (t_fvec2){ c.x - d.y, c.y + d.x }; | ||||||
|  |                 v2 = (t_fvec2){ c.x + d.x, c.y + d.y }; | ||||||
|  |                 v3 = (t_fvec2){ c.x + d.y, c.y - d.x }; | ||||||
|  |  | ||||||
|  |             } else { | ||||||
|  |                 /* rotated non-square case*/ | ||||||
|  |  | ||||||
|  |                 CRY("Rotation", "Unimplemented"); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (!batch.constant_colored) | ||||||
|  |                 ((struct sprite_primitive_payload *)payload)[i] = (struct sprite_primitive_payload) { | ||||||
|  |                     .v0 = v0, | ||||||
|  |                     .v1 = v1, | ||||||
|  |                     .v2 = v2, | ||||||
|  |                     .v3 = v3, | ||||||
|  |  | ||||||
|  |                     .uv0 = uv0, | ||||||
|  |                     .uv1 = uv1, | ||||||
|  |                     .uv2 = uv2, | ||||||
|  |                     .uv3 = uv3, | ||||||
|  |  | ||||||
|  |                     /* equal for all (flat shaded) */ | ||||||
|  |                     .c0 = sprite.color, | ||||||
|  |                     .c1 = sprite.color, | ||||||
|  |                     .c2 = sprite.color, | ||||||
|  |                     .c3 = sprite.color, | ||||||
|  |                 }; | ||||||
|  |             else | ||||||
|  |                 ((struct sprite_primitive_payload_without_color *)payload)[i] = (struct sprite_primitive_payload_without_color) { | ||||||
|  |                     .v0 = v0, | ||||||
|  |                     .v1 = v1, | ||||||
|  |                     .v2 = v2, | ||||||
|  |                     .v3 = v3, | ||||||
|  |  | ||||||
|  |                     .uv0 = uv0, | ||||||
|  |                     .uv1 = uv1, | ||||||
|  |                     .uv2 = uv2, | ||||||
|  |                     .uv3 = uv3, | ||||||
|  |                 }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         glUnmapBuffer(GL_ARRAY_BUFFER); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     GLsizei off; | ||||||
|  |     GLsizei voff; | ||||||
|  |     GLsizei uvoff; | ||||||
|  |  | ||||||
|  |     if (!batch.constant_colored) { | ||||||
|  |         off   = offsetof(struct sprite_primitive_payload, v1); | ||||||
|  |         voff  = offsetof(struct sprite_primitive_payload, v0); | ||||||
|  |         uvoff = offsetof(struct sprite_primitive_payload, uv0); | ||||||
|  |     } else { | ||||||
|  |         off   = offsetof(struct sprite_primitive_payload_without_color, v1); | ||||||
|  |         voff  = offsetof(struct sprite_primitive_payload_without_color, v0); | ||||||
|  |         uvoff = offsetof(struct sprite_primitive_payload_without_color, uv0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* vertex specification */ | ||||||
|  |     glEnableClientState(GL_VERTEX_ARRAY); | ||||||
|  |     glVertexPointer(2, | ||||||
|  |                     GL_FLOAT, | ||||||
|  |                     off, | ||||||
|  |                     (void *)(size_t)voff); | ||||||
|  |  | ||||||
|  |     glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||||||
|  |     glClientActiveTexture(GL_TEXTURE0); | ||||||
|  |     glTexCoordPointer(2, | ||||||
|  |                       GL_FLOAT, | ||||||
|  |                       off, | ||||||
|  |                       (void *)(size_t)uvoff); | ||||||
|  |  | ||||||
|  |     if (!batch.constant_colored) { | ||||||
|  |         glEnableClientState(GL_COLOR_ARRAY); | ||||||
|  |         glColorPointer(4, | ||||||
|  |                        GL_UNSIGNED_BYTE, | ||||||
|  |                        off, | ||||||
|  |                        (void *)offsetof(struct sprite_primitive_payload, c0)); | ||||||
|  |     } else | ||||||
|  |         glColor4ub(primitives[0].sprite.color.r, | ||||||
|  |                    primitives[0].sprite.color.g, | ||||||
|  |                    primitives[0].sprite.color.b, | ||||||
|  |                    primitives[0].sprite.color.a); | ||||||
|  |  | ||||||
|  |     textures_bind(&ctx.texture_cache, primitives->sprite.texture_key, GL_TEXTURE_2D); | ||||||
|  |  | ||||||
|  |     bind_quad_element_buffer(); | ||||||
|  |  | ||||||
|  |     glDrawElements(GL_TRIANGLES, 6 * (GLsizei)batch.size, GL_UNSIGNED_SHORT, NULL); | ||||||
|  |  | ||||||
|  |     /* clear the state */ | ||||||
|  |     glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW); | ||||||
|  |     glBindBuffer(GL_ARRAY_BUFFER, 0); | ||||||
|  |  | ||||||
|  |     glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||||||
|  |     glDisableClientState(GL_VERTEX_ARRAY); | ||||||
|  |     glDisableClientState(GL_COLOR_ARRAY); | ||||||
|  |  | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, 0); | ||||||
|  |     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										117
									
								
								src/rendering/triangles.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								src/rendering/triangles.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | |||||||
|  | /* a rendering.c mixin */ | ||||||
|  | #ifndef TRIANGLES_H | ||||||
|  | #define TRIANGLES_H | ||||||
|  |  | ||||||
|  | #include "../textures.h" | ||||||
|  | #include "../context.h" | ||||||
|  |  | ||||||
|  | #include <stb_ds.h> | ||||||
|  |  | ||||||
|  | /* TODO: automatic handling of repeating textures */ | ||||||
|  | /*       for that we could allocate a loner texture */ | ||||||
|  | void unfurl_triangle(const char *path, | ||||||
|  |                      t_fvec3 v0, | ||||||
|  |                      t_fvec3 v1, | ||||||
|  |                      t_fvec3 v2, | ||||||
|  |                      t_shvec2 uv0, | ||||||
|  |                      t_shvec2 uv1, | ||||||
|  |                      t_shvec2 uv2) | ||||||
|  | { | ||||||
|  |     const t_texture_key texture_key = textures_get_key(&ctx.texture_cache, path); | ||||||
|  |  | ||||||
|  |     struct mesh_batch_item *batch_p = hmgetp_null(ctx.uncolored_mesh_batches, texture_key); | ||||||
|  |     if (!batch_p) { | ||||||
|  |         struct mesh_batch item = {0}; | ||||||
|  |         hmput(ctx.uncolored_mesh_batches, texture_key, item); | ||||||
|  |         batch_p = &ctx.uncolored_mesh_batches[hmlenu(ctx.uncolored_mesh_batches) - 1]; /* TODO: can last index be used? */ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     union uncolored_space_triangle triangle = { .primitive = { | ||||||
|  |         .v0 = v0, | ||||||
|  |         .v1 = v1, | ||||||
|  |         .v2 = v2, | ||||||
|  |         .uv1 = m_to_fvec2(uv1), | ||||||
|  |         .uv0 = m_to_fvec2(uv0), | ||||||
|  |         .uv2 = m_to_fvec2(uv2), | ||||||
|  |     }}; | ||||||
|  |  | ||||||
|  |     union uncolored_space_triangle *triangles = | ||||||
|  |         (union uncolored_space_triangle *)batch_p->value.primitives; | ||||||
|  |     arrpush(triangles, triangle); | ||||||
|  |     batch_p->value.primitives = (uint8_t *)triangles; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void draw_uncolored_space_traingle_batch(struct mesh_batch *batch, | ||||||
|  |                                                 t_texture_key texture_key) | ||||||
|  | { | ||||||
|  |     size_t primitives_len = arrlenu(batch->primitives); | ||||||
|  |  | ||||||
|  |     if (primitives_len == 0) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|  |     /* create vertex array object */ | ||||||
|  |     if (batch->buffer == 0) | ||||||
|  |         glGenBuffers(1, &batch->buffer); | ||||||
|  |  | ||||||
|  |     /* TODO: try using mapped buffers while building batches instead? */ | ||||||
|  |     /*       this way we could skip client side copy that is kept until commitment */ | ||||||
|  |     /*       alternatively we could commit glBufferSubData based on a threshold */ | ||||||
|  |  | ||||||
|  |     /* update pixel-based uvs to correspond with texture atlases */ | ||||||
|  |     for (size_t i = 0; i < primitives_len; ++i) { | ||||||
|  |         struct uncolored_space_triangle_payload *payload = | ||||||
|  |             &((union uncolored_space_triangle *)batch->primitives)[i].payload; | ||||||
|  |  | ||||||
|  |         t_rect srcrect = textures_get_srcrect(&ctx.texture_cache, texture_key); | ||||||
|  |         t_rect dims    = textures_get_dims(&ctx.texture_cache, texture_key); | ||||||
|  |  | ||||||
|  |         const float wr = (float)srcrect.w / (float)dims.w; | ||||||
|  |         const float hr = (float)srcrect.h / (float)dims.h; | ||||||
|  |         const float xr = (float)srcrect.x / (float)dims.w; | ||||||
|  |         const float yr = (float)srcrect.y / (float)dims.h; | ||||||
|  |  | ||||||
|  |         payload->uv0.x = xr + ((float)payload->uv0.x / (float)srcrect.w) * wr; | ||||||
|  |         payload->uv0.y = yr + ((float)payload->uv0.y / (float)srcrect.h) * hr; | ||||||
|  |         payload->uv1.x = xr + ((float)payload->uv1.x / (float)srcrect.w) * wr; | ||||||
|  |         payload->uv1.y = yr + ((float)payload->uv1.y / (float)srcrect.h) * hr; | ||||||
|  |         payload->uv2.x = xr + ((float)payload->uv2.x / (float)srcrect.w) * wr; | ||||||
|  |         payload->uv2.y = yr + ((float)payload->uv2.y / (float)srcrect.h) * hr; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     textures_bind(&ctx.texture_cache, texture_key, GL_TEXTURE_2D); | ||||||
|  |  | ||||||
|  |     glBindBuffer(GL_ARRAY_BUFFER, batch->buffer); | ||||||
|  |  | ||||||
|  |     /* upload batched data */ | ||||||
|  |     glBufferData(GL_ARRAY_BUFFER, | ||||||
|  |                  primitives_len * sizeof (struct uncolored_space_triangle_payload), | ||||||
|  |                  batch->primitives, | ||||||
|  |                  GL_STREAM_DRAW); | ||||||
|  |  | ||||||
|  |     /* vertex specification*/ | ||||||
|  |     glEnableClientState(GL_VERTEX_ARRAY); | ||||||
|  |     glVertexPointer(3, | ||||||
|  |                     GL_FLOAT, | ||||||
|  |                     offsetof(struct uncolored_space_triangle_payload, v1), | ||||||
|  |                     (void *)offsetof(struct uncolored_space_triangle_payload, v0)); | ||||||
|  |  | ||||||
|  |     glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||||||
|  |     glClientActiveTexture(GL_TEXTURE0); | ||||||
|  |     glTexCoordPointer(2, | ||||||
|  |                       GL_FLOAT, | ||||||
|  |                       offsetof(struct uncolored_space_triangle_payload, v1), | ||||||
|  |                       (void *)offsetof(struct uncolored_space_triangle_payload, uv0)); | ||||||
|  |  | ||||||
|  |     /* commit for drawing */ | ||||||
|  |     glDrawArrays(GL_TRIANGLES, 0, 3 * (int)primitives_len); | ||||||
|  |  | ||||||
|  |     glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||||||
|  |     glDisableClientState(GL_VERTEX_ARRAY); | ||||||
|  |  | ||||||
|  |     /* invalidate the buffer immediately */ | ||||||
|  |     glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW); | ||||||
|  |     glBindBuffer(GL_ARRAY_BUFFER, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										68
									
								
								src/system/linux/elf.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/system/linux/elf.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | |||||||
|  | #include "elf.h" | ||||||
|  |  | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <sys/auxv.h> | ||||||
|  | #include <elf.h> | ||||||
|  | #include <linux/limits.h> | ||||||
|  |  | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | bool infer_elf_section_bounds(const char *const restrict name, | ||||||
|  |                               const char **restrict vm_start, | ||||||
|  |                               const char **restrict vm_end) | ||||||
|  | { | ||||||
|  |     bool result = false; | ||||||
|  |     char buf[PATH_MAX]; | ||||||
|  |     ssize_t l = readlink("/proc/self/exe", buf, PATH_MAX); | ||||||
|  |     if (l == -1) | ||||||
|  |         goto ERR_CANT_READLINK; | ||||||
|  |     buf[l] = 0; /* readlink() doesn't write a terminator */ | ||||||
|  |  | ||||||
|  |     int elf = open(buf, O_RDONLY); | ||||||
|  |     if (elf == -1) | ||||||
|  |         goto ERR_CANT_OPEN_SELF; | ||||||
|  |  | ||||||
|  |     /* elf header */ | ||||||
|  |     Elf64_Ehdr ehdr; | ||||||
|  |     read(elf, &ehdr, sizeof ehdr); | ||||||
|  |     if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || | ||||||
|  |             ehdr.e_ident[EI_MAG1] != ELFMAG1 || | ||||||
|  |             ehdr.e_ident[EI_MAG2] != ELFMAG2 || | ||||||
|  |             ehdr.e_ident[EI_MAG3] != ELFMAG3) | ||||||
|  |         goto ERR_NOT_ELF; | ||||||
|  |  | ||||||
|  |     /* section header string table */ | ||||||
|  |     Elf64_Shdr shstrdr; | ||||||
|  |     lseek(elf, ehdr.e_shoff + ehdr.e_shstrndx * sizeof (Elf64_Shdr), SEEK_SET); | ||||||
|  |     read(elf, &shstrdr, sizeof shstrdr); | ||||||
|  |     char *sh = malloc(shstrdr.sh_size); | ||||||
|  |     lseek(elf, shstrdr.sh_offset, SEEK_SET); | ||||||
|  |     read(elf, sh, shstrdr.sh_size); | ||||||
|  |  | ||||||
|  |     /* walk sections searching for needed name */ | ||||||
|  |     lseek(elf, ehdr.e_shoff, SEEK_SET); | ||||||
|  |     for (size_t s = 0; s < ehdr.e_shnum; ++s) { | ||||||
|  |         Elf64_Shdr shdr; | ||||||
|  |         read(elf, &shdr, sizeof shdr); | ||||||
|  |  | ||||||
|  |         if (strcmp(&sh[shdr.sh_name], name) == 0) { | ||||||
|  |             result = true; | ||||||
|  |             *vm_start = getauxval(AT_ENTRY) - ehdr.e_entry + (char *)shdr.sh_addr; | ||||||
|  |             *vm_end   = getauxval(AT_ENTRY) - ehdr.e_entry + (char *)shdr.sh_addr + shdr.sh_size; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     free(sh); | ||||||
|  |  | ||||||
|  | ERR_NOT_ELF: | ||||||
|  |     close(elf); | ||||||
|  |  | ||||||
|  | ERR_CANT_OPEN_SELF: | ||||||
|  | ERR_CANT_READLINK: | ||||||
|  |     return result; | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								src/system/linux/elf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/system/linux/elf.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | #ifndef ELF_H | ||||||
|  | #define ELF_H | ||||||
|  |  | ||||||
|  | #include <stdbool.h> | ||||||
|  |  | ||||||
|  | bool infer_elf_section_bounds(const char *restrict name, | ||||||
|  | 							  const char **restrict vm_start, | ||||||
|  | 							  const char **restrict vm_end); | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										274
									
								
								src/textures.c
									
									
									
									
									
								
							
							
						
						
									
										274
									
								
								src/textures.c
									
									
									
									
									
								
							| @@ -1,6 +1,7 @@ | |||||||
| #include "textures.h" | #include "private/textures.h" | ||||||
| #include "config.h" | #include "config.h" | ||||||
| #include "util.h" | #include "util.h" | ||||||
|  | #include "textures.h" | ||||||
|  |  | ||||||
| #include <SDL2/SDL.h> | #include <SDL2/SDL.h> | ||||||
| #include <SDL2/SDL_image.h> | #include <SDL2/SDL_image.h> | ||||||
| @@ -9,13 +10,12 @@ | |||||||
| #include <stb_ds.h> | #include <stb_ds.h> | ||||||
| #include <stb_rect_pack.h> | #include <stb_rect_pack.h> | ||||||
|  |  | ||||||
| #include <limits.h> |  | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| static SDL_Surface *image_to_surface(char *path) { | static SDL_Surface *image_to_surface(const char *path) { | ||||||
|     SDL_RWops *handle = PHYSFSRWOPS_openRead(path); |     SDL_RWops *handle = PHYSFSRWOPS_openRead(path); | ||||||
|     if (handle == NULL) |     if (handle == NULL) | ||||||
|         goto fail; |         goto fail; | ||||||
| @@ -35,6 +35,24 @@ fail: | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static GLuint new_gl_texture(void) { | ||||||
|  |     GLuint texture; | ||||||
|  |     glGenTextures(1, &texture); | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, texture); | ||||||
|  |  | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||||||
|  |     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,     GL_REPEAT); | ||||||
|  |     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,     GL_REPEAT); | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP,    GL_TRUE); | ||||||
|  |  | ||||||
|  |     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); | ||||||
|  |  | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, 0); | ||||||
|  |     return texture; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /* adds a new, blank atlas surface to the cache */ | /* adds a new, blank atlas surface to the cache */ | ||||||
| static void add_new_atlas(struct texture_cache *cache) { | static void add_new_atlas(struct texture_cache *cache) { | ||||||
|     SDL_PixelFormat *native_format = |     SDL_PixelFormat *native_format = | ||||||
| @@ -57,17 +75,58 @@ static void add_new_atlas(struct texture_cache *cache) { | |||||||
|                                                   a_mask); |                                                   a_mask); | ||||||
|     SDL_FreeFormat(native_format); |     SDL_FreeFormat(native_format); | ||||||
|  |  | ||||||
|  |     SDL_SetSurfaceBlendMode(new_atlas, SDL_BLENDMODE_NONE); | ||||||
|     SDL_SetSurfaceRLE(new_atlas,  true); |     SDL_SetSurfaceRLE(new_atlas,  true); | ||||||
|     arrput(cache->atlas_surfaces, new_atlas); |     arrput(cache->atlas_surfaces, new_atlas); | ||||||
|  |     arrput(cache->atlas_textures, new_gl_texture()); | ||||||
|  | } | ||||||
|  |  | ||||||
|     SDL_Texture *new_atlas_texture = |  | ||||||
|         SDL_CreateTextureFromSurface(cache->renderer, new_atlas);  | static void upload_texture_from_surface(GLuint texture, SDL_Surface *surface) { | ||||||
|     arrput(cache->atlas_textures, new_atlas_texture); |     Uint32 rmask, gmask, bmask, amask; | ||||||
|  |  | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, texture); | ||||||
|  |  | ||||||
|  |     // glPixelStorei(GL_PACK_ALIGNMENT, 1); | ||||||
|  |  | ||||||
|  |     #if SDL_BYTEORDER == SDL_BIG_ENDIAN | ||||||
|  |         rmask = 0xff000000; | ||||||
|  |         gmask = 0x00ff0000; | ||||||
|  |         bmask = 0x0000ff00; | ||||||
|  |         amask = 0x000000ff; | ||||||
|  |     #else | ||||||
|  |         rmask = 0x000000ff; | ||||||
|  |         gmask = 0x0000ff00; | ||||||
|  |         bmask = 0x00ff0000; | ||||||
|  |         amask = 0xff000000; | ||||||
|  |     #endif | ||||||
|  |  | ||||||
|  |     /* TODO: don't do it if format is compatible */ | ||||||
|  |     SDL_Surface* intermediate = SDL_CreateRGBSurface(0, | ||||||
|  |         surface->w, surface->h, 32, rmask, gmask, bmask, amask); | ||||||
|  |     SDL_BlitSurface(surface, NULL, intermediate, NULL); | ||||||
|  |     SDL_LockSurface(intermediate); | ||||||
|  |  | ||||||
|  |     glTexImage2D(GL_TEXTURE_2D, | ||||||
|  |                  0, | ||||||
|  |                  GL_RGBA8, | ||||||
|  |                  surface->w, | ||||||
|  |                  surface->h, | ||||||
|  |                  0, | ||||||
|  |                  GL_RGBA, | ||||||
|  |                  GL_UNSIGNED_BYTE, | ||||||
|  |                  intermediate->pixels); | ||||||
|  |  | ||||||
|  |     SDL_UnlockSurface(intermediate); | ||||||
|  |     SDL_FreeSurface(intermediate); | ||||||
|  |  | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, 0); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void recreate_current_atlas_texture(struct texture_cache *cache) { | static void recreate_current_atlas_texture(struct texture_cache *cache) { | ||||||
|     /* TODO: figure out if SDL_UpdateTexture alone is faster than blitting */ |     /* TODO: figure out if SDL_UpdateTexture alone is faster than blitting */ | ||||||
|  |     /* TODO: should surfaces be freed after they cannot be referenced in atlas builing? */ | ||||||
|     SDL_Surface *atlas_surface = cache->atlas_surfaces[cache->atlas_index]; |     SDL_Surface *atlas_surface = cache->atlas_surfaces[cache->atlas_index]; | ||||||
|  |  | ||||||
|     /* clear */ |     /* clear */ | ||||||
| @@ -75,22 +134,27 @@ static void recreate_current_atlas_texture(struct texture_cache *cache) { | |||||||
|  |  | ||||||
|     /* blit the texture surfaces onto the atlas */ |     /* blit the texture surfaces onto the atlas */ | ||||||
|     for (size_t i = 0; i < shlenu(cache->hash); ++i) { |     for (size_t i = 0; i < shlenu(cache->hash); ++i) { | ||||||
|  |         /* skip all that aren't part of currently built one */ | ||||||
|         if (cache->hash[i].value.atlas_index != cache->atlas_index) |         if (cache->hash[i].value.atlas_index != cache->atlas_index) | ||||||
|             continue; |             continue; | ||||||
|  |  | ||||||
|  |         /* skip loners */ | ||||||
|  |         if (cache->hash[i].value.loner_texture != 0) | ||||||
|  |             continue; | ||||||
|  |  | ||||||
|         SDL_BlitSurface(cache->hash[i].value.data, |         SDL_BlitSurface(cache->hash[i].value.data, | ||||||
|                         NULL, |                         NULL, | ||||||
|                         atlas_surface, |                         atlas_surface, | ||||||
|                         &cache->hash[i].value.srcrect); |                         &(SDL_Rect){ | ||||||
|  |                             .x = cache->hash[i].value.srcrect.x, | ||||||
|  |                             .y = cache->hash[i].value.srcrect.y, | ||||||
|  |                             .w = cache->hash[i].value.srcrect.w, | ||||||
|  |                             .h = cache->hash[i].value.srcrect.h, | ||||||
|  |                         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* texturize it! */ |     /* texturize it! */ | ||||||
|     SDL_LockSurface(atlas_surface); |     upload_texture_from_surface(cache->atlas_textures[cache->atlas_index], atlas_surface); | ||||||
|     SDL_UpdateTexture(cache->atlas_textures[cache->atlas_index], |  | ||||||
|                       NULL, |  | ||||||
|                       atlas_surface->pixels, |  | ||||||
|                       atlas_surface->pitch); |  | ||||||
|     SDL_UnlockSurface(atlas_surface); |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -98,7 +162,10 @@ static void recreate_current_atlas_texture(struct texture_cache *cache) { | |||||||
| static stbrp_rect *create_rects_from_cache(struct texture_cache *cache) { | static stbrp_rect *create_rects_from_cache(struct texture_cache *cache) { | ||||||
|     stbrp_rect *rects = NULL; |     stbrp_rect *rects = NULL; | ||||||
|     for (size_t i = 0; i < shlenu(cache->hash); ++i) { |     for (size_t i = 0; i < shlenu(cache->hash); ++i) { | ||||||
|         SDL_Surface *surface_data = cache->hash[i].value.data; |         if (cache->hash[i].value.loner_texture != 0) | ||||||
|  |             continue; | ||||||
|  |  | ||||||
|  |         const SDL_Surface *surface_data = cache->hash[i].value.data; | ||||||
|         stbrp_rect new_rect = { |         stbrp_rect new_rect = { | ||||||
|             .w = surface_data->w, |             .w = surface_data->w, | ||||||
|             .h = surface_data->h, |             .h = surface_data->h, | ||||||
| @@ -159,7 +226,7 @@ static bool update_rects(struct texture_cache *cache, stbrp_rect *rects, stbrp_r | |||||||
| /* updates the atlas location of every rect in the cache */ | /* updates the atlas location of every rect in the cache */ | ||||||
| static void update_texture_rects_in_atlas(struct texture_cache *cache, stbrp_rect *rects) { | static void update_texture_rects_in_atlas(struct texture_cache *cache, stbrp_rect *rects) { | ||||||
|     for (size_t i = 0; i < arrlenu(rects); ++i) { |     for (size_t i = 0; i < arrlenu(rects); ++i) { | ||||||
|         cache->hash[i].value.srcrect = (SDL_Rect) { |         cache->hash[i].value.srcrect = (t_rect) { | ||||||
|             .x = rects[i].x, |             .x = rects[i].x, | ||||||
|             .y = rects[i].y, |             .y = rects[i].y, | ||||||
|             .w = rects[i].w, |             .w = rects[i].w, | ||||||
| @@ -171,9 +238,7 @@ static void update_texture_rects_in_atlas(struct texture_cache *cache, stbrp_rec | |||||||
|  |  | ||||||
| void textures_cache_init(struct texture_cache *cache, SDL_Window *window) { | void textures_cache_init(struct texture_cache *cache, SDL_Window *window) { | ||||||
|     cache->window = window; |     cache->window = window; | ||||||
|     cache->renderer = SDL_GetRenderer(window); |  | ||||||
|     sh_new_arena(cache->hash); |     sh_new_arena(cache->hash); | ||||||
|     sh_new_arena(cache->loner_hash); |  | ||||||
|  |  | ||||||
|     cache->node_buffer = cmalloc(sizeof *cache->node_buffer * TEXTURE_ATLAS_SIZE); |     cache->node_buffer = cmalloc(sizeof *cache->node_buffer * TEXTURE_ATLAS_SIZE); | ||||||
|  |  | ||||||
| @@ -185,7 +250,7 @@ void textures_cache_init(struct texture_cache *cache, SDL_Window *window) { | |||||||
| void textures_cache_deinit(struct texture_cache *cache) { | void textures_cache_deinit(struct texture_cache *cache) { | ||||||
|     /* free atlas textures */ |     /* free atlas textures */ | ||||||
|     for (size_t i = 0; i < arrlenu(cache->atlas_textures); ++i) { |     for (size_t i = 0; i < arrlenu(cache->atlas_textures); ++i) { | ||||||
|         SDL_DestroyTexture(cache->atlas_textures[i]); |         glDeleteTextures(1, &cache->atlas_textures[i]); | ||||||
|     } |     } | ||||||
|     arrfree(cache->atlas_textures); |     arrfree(cache->atlas_textures); | ||||||
|  |  | ||||||
| @@ -201,11 +266,6 @@ void textures_cache_deinit(struct texture_cache *cache) { | |||||||
|     } |     } | ||||||
|     shfree(cache->hash); |     shfree(cache->hash); | ||||||
|  |  | ||||||
|     for (size_t i = 0; i < shlenu(cache->loner_hash); ++i) { |  | ||||||
|         SDL_FreeSurface(cache->loner_hash[i].value.data); |  | ||||||
|     } |  | ||||||
|     shfree(cache->loner_hash); |  | ||||||
|  |  | ||||||
|     free(cache->node_buffer); |     free(cache->node_buffer); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -230,35 +290,39 @@ void textures_dump_atlases(struct texture_cache *cache) { | |||||||
|         IMG_SavePNG_RW(cache->atlas_surfaces[i], handle, true); |         IMG_SavePNG_RW(cache->atlas_surfaces[i], handle, true); | ||||||
|         log_info("Dumped atlas %s", buf); |         log_info("Dumped atlas %s", buf); | ||||||
|     } |     } | ||||||
|      |  | ||||||
|     size_t num_loners = shlenu(cache->loner_hash); |  | ||||||
|     log_info("%zd atlases dumped. %zd loners left undumped.", i, num_loners); |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void textures_load(struct texture_cache *cache, char *path) { | static t_texture_key textures_load(struct texture_cache *cache, const char *path) { | ||||||
|     /* no need to do anything if it was loaded already */ |     /* no need to do anything if it was loaded already */ | ||||||
|     if (shgeti(cache->hash, path) >= 0 || shgeti(cache->loner_hash, path) >= 0) |     const ptrdiff_t i = shgeti(cache->hash, path); | ||||||
|         return; |     if (i >= 0) | ||||||
|  |         return (t_texture_key){ (uint16_t)i }; | ||||||
|  |  | ||||||
|     SDL_Surface *surface = image_to_surface(path); |     SDL_Surface *surface = image_to_surface(path); | ||||||
|     struct texture new_texture; |     struct texture new_texture = {0}; | ||||||
|     new_texture.data = surface; |     new_texture.data = surface; | ||||||
|  |  | ||||||
|     /* it's a "loner texture," it doesn't fit in an atlas so it's not in one */ |     /* it's a "loner texture," it doesn't fit in an atlas so it's not in one */ | ||||||
|     if (surface->w > TEXTURE_ATLAS_SIZE || surface->h > TEXTURE_ATLAS_SIZE) { |     if (surface->w >= TEXTURE_ATLAS_SIZE || surface->h >= TEXTURE_ATLAS_SIZE) { | ||||||
|         new_texture.loner_data = SDL_CreateTextureFromSurface(cache->renderer, surface);  |         new_texture.loner_texture = new_gl_texture(); | ||||||
|         new_texture.atlas_index = -1; |         upload_texture_from_surface(new_texture.loner_texture, surface);  | ||||||
|         shput(cache->loner_hash, path, new_texture); |         new_texture.srcrect = (t_rect) { .w = surface->w, .h = surface->h }; | ||||||
|  |         shput(cache->hash, path, new_texture); | ||||||
|  |         return (t_texture_key){ (uint16_t)shgeti(cache->hash, path) }; | ||||||
|     } else { |     } else { | ||||||
|         new_texture.atlas_index = cache->atlas_index; |         new_texture.atlas_index = cache->atlas_index; | ||||||
|         shput(cache->hash, path, new_texture); |         shput(cache->hash, path, new_texture); | ||||||
|         cache->is_dirty = true; |         cache->is_dirty = true; | ||||||
|  |         return (t_texture_key){ (uint16_t)shgeti(cache->hash, path) }; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void textures_update_current_atlas(struct texture_cache *cache) { | void textures_update_atlas(struct texture_cache *cache) { | ||||||
|  |     if (!cache->is_dirty) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|     /* this function makes a lot more sense if you read stb_rect_pack.h */ |     /* this function makes a lot more sense if you read stb_rect_pack.h */ | ||||||
|     stbrp_context pack_ctx; /* target info */ |     stbrp_context pack_ctx; /* target info */ | ||||||
|     stbrp_init_target(&pack_ctx, |     stbrp_init_target(&pack_ctx, | ||||||
| @@ -299,59 +363,115 @@ void textures_update_current_atlas(struct texture_cache *cache) { | |||||||
|     arrfree(rects); |     arrfree(rects); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* EXPERIMANTAL: LIKELY TO BE REMOVED! */ | ||||||
|  | #ifdef __linux__ /* use rodata elf section for fast lookups of repeating textures */ | ||||||
|  |  | ||||||
| SDL_Rect textures_get_srcrect(struct texture_cache *cache, char *path) { | #include "system/linux/elf.h" | ||||||
|     struct texture_cache_item *texture = shgetp_null(cache->hash, path); |  | ||||||
|     if (texture == NULL) { | static const char *rodata_start; | ||||||
|  | static const char *rodata_stop; | ||||||
|  |  | ||||||
|  | t_texture_key textures_get_key(struct texture_cache *cache, const char *path) { | ||||||
|  |     static const char *last_path = NULL; | ||||||
|  |     static t_texture_key last_texture; | ||||||
|  |     static struct ptr_to_texture { | ||||||
|  |         const void *key; | ||||||
|  |         t_texture_key value; | ||||||
|  |     } *ptr_to_texture; | ||||||
|  |  | ||||||
|  |     if (rodata_stop == NULL) | ||||||
|  |         if (!infer_elf_section_bounds(".rodata", &rodata_start, &rodata_stop)) | ||||||
|  |             CRY("Section inference", ".rodata section lookup failed"); | ||||||
|  |  | ||||||
|  |     /* the fastest path */ | ||||||
|  |     if (path == last_path) | ||||||
|  |         return last_texture; | ||||||
|  |     else { | ||||||
|  |         /* moderately fast path, by pointer hashing */ | ||||||
|  |         const ptrdiff_t texture = hmgeti(ptr_to_texture, path); | ||||||
|  |         if (texture != -1) { | ||||||
|  |             if (path >= rodata_start && path < rodata_stop) | ||||||
|  |                 last_path = path; | ||||||
|  |             last_texture = ptr_to_texture[texture].value; | ||||||
|  |             return last_texture; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* try loading */ | ||||||
|  |     last_texture = textures_load(cache, path); | ||||||
|  |     hmput(ptr_to_texture, path, last_texture); | ||||||
|  |  | ||||||
|  |     if (path >= rodata_start && path < rodata_stop) | ||||||
|  |         last_path = path; | ||||||
|  |  | ||||||
|  |     return last_texture; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #else | ||||||
|  | t_texture_key textures_get_key(struct texture_cache *cache, const char *path) { | ||||||
|  |     /* hash tables are assumed to be stable, so we just return indices */ | ||||||
|  |     const ptrdiff_t texture = shgeti(cache->hash, path); | ||||||
|  |  | ||||||
|  |     /* load it if it isn't */ | ||||||
|  |     if (texture == -1) { | ||||||
|  |         return textures_load(cache, path); | ||||||
|  |     } else | ||||||
|  |         return (t_texture_key){ (uint16_t)texture }; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif /* generic implementation of textures_get_key() */ | ||||||
|  |  | ||||||
|  | int32_t textures_get_atlas_id(const struct texture_cache *cache, t_texture_key key) { | ||||||
|  |     if (m_texture_key_is_valid(key)) { | ||||||
|  |         if (cache->hash[key.id].value.loner_texture != 0) | ||||||
|  |             return -cache->hash[key.id].value.loner_texture; | ||||||
|  |         else | ||||||
|  |             return cache->hash[key.id].value.atlas_index; | ||||||
|  |     } else { | ||||||
|  |         CRY("Texture lookup failed.", | ||||||
|  |             "Tried to get atlas id that isn't loaded."); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | t_rect textures_get_srcrect(const struct texture_cache *cache, t_texture_key key) { | ||||||
|  |     if (m_texture_key_is_valid(key)) { | ||||||
|  |         return cache->hash[key.id].value.srcrect; | ||||||
|  |     } else { | ||||||
|         CRY("Texture lookup failed.", |         CRY("Texture lookup failed.", | ||||||
|             "Tried to get texture that isn't loaded."); |             "Tried to get texture that isn't loaded."); | ||||||
|         return (SDL_Rect){ 0, 0, 0, 0 }; |         return (t_rect){ 0, 0, 0, 0 }; | ||||||
|     } |  | ||||||
|     return texture->value.srcrect; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| int textures_get_atlas_index(struct texture_cache *cache, char *path) { |  | ||||||
|     struct texture_cache_item *texture = shgetp_null(cache->hash, path); |  | ||||||
|  |  | ||||||
|     /* it might be a loner texture */ |  | ||||||
|     if (texture == NULL) { |  | ||||||
|         texture = shgetp_null(cache->loner_hash, path); |  | ||||||
|  |  | ||||||
|         /* never mind it's just not there at all */ |  | ||||||
|         if (texture == NULL) { |  | ||||||
|             CRY("Texture atlas index lookup failed.", |  | ||||||
|                 "Tried to get atlas index of texture that isn't loaded."); |  | ||||||
|             return INT_MIN; |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|     return texture->value.atlas_index; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | t_rect textures_get_dims(const struct texture_cache *cache, t_texture_key key) { | ||||||
| SDL_Texture *textures_get_atlas(struct texture_cache *cache, int index) { |     if (m_texture_key_is_valid(key)) { | ||||||
|     /* out of bounds */ |         if (cache->hash[key.id].value.loner_texture != 0) | ||||||
|     if (arrlen(cache->atlas_textures) < index + 1 || index < 0) |             return cache->hash[key.id].value.srcrect; | ||||||
|         return NULL; |         else | ||||||
|  |             return (t_rect){ .w = TEXTURE_ATLAS_SIZE, .h = TEXTURE_ATLAS_SIZE }; | ||||||
|     return cache->atlas_textures[index]; |     } else { | ||||||
| } |         CRY("Texture lookup failed.", | ||||||
|  |  | ||||||
|  |  | ||||||
| SDL_Texture *textures_get_loner(struct texture_cache *cache, char *path) { |  | ||||||
|     struct texture_cache_item *texture = shgetp_null(cache->loner_hash, path); |  | ||||||
|  |  | ||||||
|     if (texture == NULL) { |  | ||||||
|         CRY("Loner texture lookup failed.", |  | ||||||
|             "Tried to get texture that isn't loaded."); |             "Tried to get texture that isn't loaded."); | ||||||
|         return NULL; |         return (t_rect){ 0, 0, 0, 0 }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return texture->value.loner_data; |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| size_t textures_get_num_atlases(struct texture_cache *cache) { | void textures_bind(const struct texture_cache *cache, t_texture_key key, GLenum target) { | ||||||
|  |     if (m_texture_key_is_valid(key)) { | ||||||
|  |         if (cache->hash[key.id].value.loner_texture == 0) | ||||||
|  |             glBindTexture(target, cache->atlas_textures[cache->hash[key.id].value.atlas_index]); | ||||||
|  |         else | ||||||
|  |             glBindTexture(target, cache->hash[key.id].value.loner_texture); | ||||||
|  |     } else if (key.id == 0) { | ||||||
|  |         CRY("Texture binding failed.", | ||||||
|  |             "Tried to get texture that isn't loaded."); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | size_t textures_get_num_atlases(const struct texture_cache *cache) { | ||||||
|     return cache->atlas_index + 1;     |     return cache->atlas_index + 1;     | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,46 +1,17 @@ | |||||||
| #ifndef TEXTURES_H | #ifndef TEXTURES_H | ||||||
| #define TEXTURES_H | #define TEXTURES_H | ||||||
|  |  | ||||||
|  | #include "private/textures.h" | ||||||
|  | #include "util.h" | ||||||
|  |  | ||||||
| #include <SDL2/SDL.h> | #include <SDL2/SDL.h> | ||||||
| #include <stb_rect_pack.h> | #include <glad/glad.h> | ||||||
|  |  | ||||||
| #include <stdbool.h> | /* type safe structure for persistent texture handles */ | ||||||
|  | typedef struct { uint16_t id; } t_texture_key; | ||||||
|  |  | ||||||
| struct texture { |  | ||||||
|     SDL_Rect srcrect;           /* position in atlas */ |  | ||||||
|     SDL_Surface *data;          /* original image data */ |  | ||||||
|     SDL_Texture *loner_data;    /* loner textures store their data directly */ |  | ||||||
|     int atlas_index;            /* which atlas the texture is in */ |  | ||||||
|     int8_t layer; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| struct texture_cache_item { |  | ||||||
|     char *key; |  | ||||||
|     struct texture value; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* use the public API to create and manipulate instances of this structure */ |  | ||||||
| struct texture_cache { |  | ||||||
|     /* from context */ |  | ||||||
|     SDL_Window *window; |  | ||||||
|     SDL_Renderer *renderer; |  | ||||||
|  |  | ||||||
|     struct texture_cache_item *hash; |  | ||||||
|     struct texture_cache_item *loner_hash; |  | ||||||
|  |  | ||||||
|     stbrp_node *node_buffer; /* used internally by stb_rect_pack */ |  | ||||||
|  |  | ||||||
|     SDL_Surface **atlas_surfaces; |  | ||||||
|     SDL_Texture **atlas_textures; |  | ||||||
|     int atlas_index; |  | ||||||
|  |  | ||||||
|     bool is_dirty;              /* current atlas needs to be recreated */ |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  | /* tests whether given key structure corresponds to any texture */ | ||||||
|  | #define m_texture_key_is_valid(p_key) ((p_key).id != (uint16_t)-1) | ||||||
|  |  | ||||||
| void textures_cache_init(struct texture_cache *cache, SDL_Window *window); | void textures_cache_init(struct texture_cache *cache, SDL_Window *window); | ||||||
| void textures_cache_deinit(struct texture_cache *cache); | void textures_cache_deinit(struct texture_cache *cache); | ||||||
| @@ -51,28 +22,30 @@ void textures_dump_atlases(struct texture_cache *cache); | |||||||
| /* loads an image if it isn't in the cache, otherwise a no-op. */ | /* loads an image if it isn't in the cache, otherwise a no-op. */ | ||||||
| /* can be called from anywhere at any time after init, useful if you want to */ | /* can be called from anywhere at any time after init, useful if you want to */ | ||||||
| /* preload textures you know will definitely be used */ | /* preload textures you know will definitely be used */ | ||||||
| void textures_load(struct texture_cache *cache, char *path); | // void textures_load(struct texture_cache *cache, const char *path); | ||||||
|  |  | ||||||
| /* repacks the current texture atlas based on the texture cache */ | /* repacks the current texture atlas based on the texture cache if needed */ | ||||||
| void textures_update_current_atlas(struct texture_cache *cache); | /* any previously returned srcrect results are invalidated after that */ | ||||||
|  | /* call it every time before rendering */ | ||||||
|  | void textures_update_atlas(struct texture_cache *cache); | ||||||
|  |  | ||||||
| /* returns a rect in a texture cache atlas based on a path, for drawing */ | /* returns a persistent handle to some texture in cache, loading it if needed */ | ||||||
| /* if the texture is not found, returns a zero-filled rect (so check w or h) */ | /* check the result with m_texture_key_is_valid() */ | ||||||
| SDL_Rect textures_get_srcrect(struct texture_cache *cache, char *path); | t_texture_key textures_get_key(struct texture_cache *cache, const char *path); | ||||||
|  |  | ||||||
| /* returns which atlas the texture in the path is in, starting from 0 */ | /* returns a rect in a texture cache of the given key */ | ||||||
| /* if the texture is not found, returns INT_MIN */ | t_rect textures_get_srcrect(const struct texture_cache *cache, t_texture_key key); | ||||||
| int textures_get_atlas_index(struct texture_cache *cache, char *path); |  | ||||||
|  |  | ||||||
| /* returns a pointer to the atlas at `index` */ | /* returns a rect of dimensions of the whole texture (whole atlas) */ | ||||||
| /* if the index is out of bounds, returns NULL. */ | t_rect textures_get_dims(const struct texture_cache *cache, t_texture_key key); | ||||||
| /* you can get the index via texture_get_atlas_index */ |  | ||||||
| SDL_Texture *textures_get_atlas(struct texture_cache *cache, int index); |  | ||||||
|  |  | ||||||
| SDL_Texture *textures_get_loner(struct texture_cache *cache, char *path); | /* returns an identifier that is equal for all textures placed in the same atlas */ | ||||||
|  | int32_t textures_get_atlas_id(const struct texture_cache *cache, t_texture_key key); | ||||||
|  |  | ||||||
|  | /* binds atlas texture in opengl state */ | ||||||
|  | void textures_bind(const struct texture_cache *cache, t_texture_key key, GLenum target); | ||||||
|  |  | ||||||
| /* returns the number of atlases in the cache */ | /* returns the number of atlases in the cache */ | ||||||
| size_t textures_get_num_atlases(struct texture_cache *cache); | size_t textures_get_num_atlases(const struct texture_cache *cache); | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								src/util.c
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								src/util.c
									
									
									
									
									
								
							| @@ -186,6 +186,29 @@ t_frect to_frect(t_rect rect) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | t_fvec2 frect_center(t_frect rect) { | ||||||
|  |     return (t_fvec2){ | ||||||
|  |         .x = rect.x + rect.w / 2, | ||||||
|  |         .y = rect.y + rect.h / 2, | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | t_fvec2 fvec2_from_vec2(t_vec2 vec) { | ||||||
|  |     return (t_fvec2) { | ||||||
|  |         .x = (float)vec.x, | ||||||
|  |         .y = (float)vec.y, | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | t_fvec2 fvec2_from_shvec2(t_shvec2 vec) { | ||||||
|  |     return (t_fvec2) { | ||||||
|  |         .x = (float)vec.x, | ||||||
|  |         .y = (float)vec.y, | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void tick_timer(int *value) { | void tick_timer(int *value) { | ||||||
|     *value = MAX(*value - 1, 0); |     *value = MAX(*value - 1, 0); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										96
									
								
								src/util.h
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								src/util.h
									
									
									
									
									
								
							| @@ -48,7 +48,9 @@ void *ccalloc(size_t num, size_t size); | |||||||
| #define MAX SDL_max | #define MAX SDL_max | ||||||
| #define MIN SDL_min | #define MIN SDL_min | ||||||
|  |  | ||||||
|  | #ifndef M_PI | ||||||
| #define M_PI 3.14159265358979323846264338327950288   /**< pi */ | #define M_PI 3.14159265358979323846264338327950288   /**< pi */ | ||||||
|  | #endif | ||||||
|  |  | ||||||
| /* sets buf_out to a pointer to a byte buffer which must be freed. */ | /* sets buf_out to a pointer to a byte buffer which must be freed. */ | ||||||
| /* returns the size of this buffer. */ | /* returns the size of this buffer. */ | ||||||
| @@ -75,28 +77,6 @@ typedef struct color { | |||||||
| } t_color; | } t_color; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* a rectangle with the origin at the upper left (integer) */ |  | ||||||
| typedef struct rect { |  | ||||||
|     int x, y; |  | ||||||
|     int w, h; |  | ||||||
| } t_rect; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| bool intersect_rect(const t_rect *a, const t_rect *b, t_rect *result); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* a rectangle with the origin at the upper left (floating point) */ |  | ||||||
| typedef struct frect { |  | ||||||
|     float x, y; |  | ||||||
|     float w, h; |  | ||||||
| } t_frect; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| bool intersect_frect(const t_frect *a, const t_frect *b, t_frect *result); |  | ||||||
|  |  | ||||||
| t_frect to_frect(t_rect rect); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* a point in some space (integer) */ | /* a point in some space (integer) */ | ||||||
| typedef struct vec2 { | typedef struct vec2 { | ||||||
|     int x, y; |     int x, y; | ||||||
| @@ -109,6 +89,54 @@ typedef struct fvec2 { | |||||||
| } t_fvec2; | } t_fvec2; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* a point in some three dimension space (floating point) */ | ||||||
|  | /* y goes up, x goes to the right */ | ||||||
|  | typedef struct fvec3 { | ||||||
|  |     float x, y, z; | ||||||
|  | } t_fvec3; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* a point in some space (short) */ | ||||||
|  | typedef struct shvec2 { | ||||||
|  |     short x, y; | ||||||
|  | } t_shvec2; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* a rectangle with the origin at the upper left (integer) */ | ||||||
|  | typedef struct rect { | ||||||
|  |     int x, y; | ||||||
|  |     int w, h; | ||||||
|  | } t_rect; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* a rectangle with the origin at the upper left (floating point) */ | ||||||
|  | typedef struct frect { | ||||||
|  |     float x, y; | ||||||
|  |     float w, h; | ||||||
|  | } t_frect; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool intersect_rect(const t_rect *a, const t_rect *b, t_rect *result); | ||||||
|  |  | ||||||
|  | bool intersect_frect(const t_frect *a, const t_frect *b, t_frect *result); | ||||||
|  |  | ||||||
|  | /* TODO: generics and specials (see m_to_fvec2() for an example)*/ | ||||||
|  | t_frect to_frect(t_rect rect); | ||||||
|  |  | ||||||
|  | t_fvec2 frect_center(t_frect rect); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* aren't macros to prevent double evaluation with side effects */ | ||||||
|  | /* maybe could be inlined? i hope LTO will resolve this */ | ||||||
|  | t_fvec2 fvec2_from_vec2(t_vec2 vec); | ||||||
|  | t_fvec2 fvec2_from_shvec2(t_shvec2 vec); | ||||||
|  |  | ||||||
|  | #define m_to_fvec2(p_any_vec2) (_Generic((p_any_vec2),          \ | ||||||
|  |                                     t_vec2:   fvec2_from_vec2,  \ | ||||||
|  |                                     t_shvec2: fvec2_from_shvec2 \ | ||||||
|  |                                 )(p_any_vec2)) | ||||||
|  |  | ||||||
|  |  | ||||||
| /* decrements an lvalue (which should be an int), stopping at 0 */ | /* decrements an lvalue (which should be an int), stopping at 0 */ | ||||||
| /* meant for tick-based timers in game logic */ | /* meant for tick-based timers in game logic */ | ||||||
| /* | /* | ||||||
| @@ -117,7 +145,6 @@ typedef struct fvec2 { | |||||||
|  */ |  */ | ||||||
| void tick_timer(int *value); | void tick_timer(int *value); | ||||||
|  |  | ||||||
|  |  | ||||||
| /* decrements a floating point second-based timer, stopping at 0.0 */ | /* decrements a floating point second-based timer, stopping at 0.0 */ | ||||||
| /* meant for poll based real time logic in game logic */ | /* meant for poll based real time logic in game logic */ | ||||||
| /* note that it should be decremented only on the next tick after its creation */ | /* note that it should be decremented only on the next tick after its creation */ | ||||||
| @@ -127,5 +154,28 @@ void tick_ftimer(float *value); | |||||||
| /* returns true if value was cycled */ | /* returns true if value was cycled */ | ||||||
| bool repeat_ftimer(float *value, float at); | bool repeat_ftimer(float *value, float at); | ||||||
|  |  | ||||||
|  | /* http://www.azillionmonkeys.com/qed/sqroot.html */ | ||||||
|  | static inline float fast_sqrt(float x) | ||||||
|  | { | ||||||
|  |     union { | ||||||
|  |         float f; | ||||||
|  |         uint32_t u; | ||||||
|  |     } pun = {.f = x}; | ||||||
|  |  | ||||||
|  |     pun.u += 127 << 23; | ||||||
|  |     pun.u >>= 1; | ||||||
|  |  | ||||||
|  |     return pun.f; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static inline t_fvec2 fast_cossine(float a) { | ||||||
|  |     const float s = sinf(a); | ||||||
|  |     return (t_fvec2){ | ||||||
|  |         .x = fast_sqrt(1.0f - s * s) * (a >= (float)M_PI_2 && a < (float)(M_PI + M_PI_2) ? -1 : 1), | ||||||
|  |         .y = s | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										309
									
								
								third-party/glad/include/glad/glad.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										309
									
								
								third-party/glad/include/glad/glad.h
									
									
									
									
										vendored
									
									
								
							| @@ -1,22 +1,23 @@ | |||||||
| /* | /* | ||||||
|  |  | ||||||
|     OpenGL loader generated by glad 0.1.36 on Tue Jul  9 02:07:20 2024. |     OpenGL loader generated by glad 0.1.36 on Wed Jul 10 12:56:38 2024. | ||||||
|  |  | ||||||
|     Language/Generator: C/C++ |     Language/Generator: C/C++ | ||||||
|     Specification: gl |     Specification: gl | ||||||
|     APIs: gl=1.5 |     APIs: gl=1.5 | ||||||
|     Profile: compatibility |     Profile: compatibility | ||||||
|     Extensions: |     Extensions: | ||||||
|          |         GL_ARB_shader_objects, | ||||||
|  |         GL_KHR_debug | ||||||
|     Loader: True |     Loader: True | ||||||
|     Local files: False |     Local files: False | ||||||
|     Omit khrplatform: False |     Omit khrplatform: False | ||||||
|     Reproducible: False |     Reproducible: False | ||||||
|  |  | ||||||
|     Commandline: |     Commandline: | ||||||
|         --profile="compatibility" --api="gl=1.5" --generator="c" --spec="gl" --extensions="" |         --profile="compatibility" --api="gl=1.5" --generator="c" --spec="gl" --extensions="GL_ARB_shader_objects,GL_KHR_debug" | ||||||
|     Online: |     Online: | ||||||
|         https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D1.5 |         https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D1.5&extensions=GL_ARB_shader_objects&extensions=GL_KHR_debug | ||||||
| */ | */ | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -2278,6 +2279,306 @@ typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, | |||||||
| GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; | GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; | ||||||
| #define glGetBufferPointerv glad_glGetBufferPointerv | #define glGetBufferPointerv glad_glGetBufferPointerv | ||||||
| #endif | #endif | ||||||
|  | #define GL_PROGRAM_OBJECT_ARB 0x8B40 | ||||||
|  | #define GL_SHADER_OBJECT_ARB 0x8B48 | ||||||
|  | #define GL_OBJECT_TYPE_ARB 0x8B4E | ||||||
|  | #define GL_OBJECT_SUBTYPE_ARB 0x8B4F | ||||||
|  | #define GL_FLOAT_VEC2_ARB 0x8B50 | ||||||
|  | #define GL_FLOAT_VEC3_ARB 0x8B51 | ||||||
|  | #define GL_FLOAT_VEC4_ARB 0x8B52 | ||||||
|  | #define GL_INT_VEC2_ARB 0x8B53 | ||||||
|  | #define GL_INT_VEC3_ARB 0x8B54 | ||||||
|  | #define GL_INT_VEC4_ARB 0x8B55 | ||||||
|  | #define GL_BOOL_ARB 0x8B56 | ||||||
|  | #define GL_BOOL_VEC2_ARB 0x8B57 | ||||||
|  | #define GL_BOOL_VEC3_ARB 0x8B58 | ||||||
|  | #define GL_BOOL_VEC4_ARB 0x8B59 | ||||||
|  | #define GL_FLOAT_MAT2_ARB 0x8B5A | ||||||
|  | #define GL_FLOAT_MAT3_ARB 0x8B5B | ||||||
|  | #define GL_FLOAT_MAT4_ARB 0x8B5C | ||||||
|  | #define GL_SAMPLER_1D_ARB 0x8B5D | ||||||
|  | #define GL_SAMPLER_2D_ARB 0x8B5E | ||||||
|  | #define GL_SAMPLER_3D_ARB 0x8B5F | ||||||
|  | #define GL_SAMPLER_CUBE_ARB 0x8B60 | ||||||
|  | #define GL_SAMPLER_1D_SHADOW_ARB 0x8B61 | ||||||
|  | #define GL_SAMPLER_2D_SHADOW_ARB 0x8B62 | ||||||
|  | #define GL_SAMPLER_2D_RECT_ARB 0x8B63 | ||||||
|  | #define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 | ||||||
|  | #define GL_OBJECT_DELETE_STATUS_ARB 0x8B80 | ||||||
|  | #define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 | ||||||
|  | #define GL_OBJECT_LINK_STATUS_ARB 0x8B82 | ||||||
|  | #define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 | ||||||
|  | #define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 | ||||||
|  | #define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 | ||||||
|  | #define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 | ||||||
|  | #define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 | ||||||
|  | #define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 | ||||||
|  | #define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 | ||||||
|  | #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 | ||||||
|  | #define GL_DEBUG_CALLBACK_FUNCTION 0x8244 | ||||||
|  | #define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 | ||||||
|  | #define GL_DEBUG_SOURCE_API 0x8246 | ||||||
|  | #define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 | ||||||
|  | #define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 | ||||||
|  | #define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 | ||||||
|  | #define GL_DEBUG_SOURCE_APPLICATION 0x824A | ||||||
|  | #define GL_DEBUG_SOURCE_OTHER 0x824B | ||||||
|  | #define GL_DEBUG_TYPE_ERROR 0x824C | ||||||
|  | #define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D | ||||||
|  | #define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E | ||||||
|  | #define GL_DEBUG_TYPE_PORTABILITY 0x824F | ||||||
|  | #define GL_DEBUG_TYPE_PERFORMANCE 0x8250 | ||||||
|  | #define GL_DEBUG_TYPE_OTHER 0x8251 | ||||||
|  | #define GL_DEBUG_TYPE_MARKER 0x8268 | ||||||
|  | #define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 | ||||||
|  | #define GL_DEBUG_TYPE_POP_GROUP 0x826A | ||||||
|  | #define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B | ||||||
|  | #define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C | ||||||
|  | #define GL_DEBUG_GROUP_STACK_DEPTH 0x826D | ||||||
|  | #define GL_BUFFER 0x82E0 | ||||||
|  | #define GL_SHADER 0x82E1 | ||||||
|  | #define GL_PROGRAM 0x82E2 | ||||||
|  | #define GL_QUERY 0x82E3 | ||||||
|  | #define GL_PROGRAM_PIPELINE 0x82E4 | ||||||
|  | #define GL_SAMPLER 0x82E6 | ||||||
|  | #define GL_MAX_LABEL_LENGTH 0x82E8 | ||||||
|  | #define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 | ||||||
|  | #define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 | ||||||
|  | #define GL_DEBUG_LOGGED_MESSAGES 0x9145 | ||||||
|  | #define GL_DEBUG_SEVERITY_HIGH 0x9146 | ||||||
|  | #define GL_DEBUG_SEVERITY_MEDIUM 0x9147 | ||||||
|  | #define GL_DEBUG_SEVERITY_LOW 0x9148 | ||||||
|  | #define GL_DEBUG_OUTPUT 0x92E0 | ||||||
|  | #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 | ||||||
|  | #define GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR 0x8242 | ||||||
|  | #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR 0x8243 | ||||||
|  | #define GL_DEBUG_CALLBACK_FUNCTION_KHR 0x8244 | ||||||
|  | #define GL_DEBUG_CALLBACK_USER_PARAM_KHR 0x8245 | ||||||
|  | #define GL_DEBUG_SOURCE_API_KHR 0x8246 | ||||||
|  | #define GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR 0x8247 | ||||||
|  | #define GL_DEBUG_SOURCE_SHADER_COMPILER_KHR 0x8248 | ||||||
|  | #define GL_DEBUG_SOURCE_THIRD_PARTY_KHR 0x8249 | ||||||
|  | #define GL_DEBUG_SOURCE_APPLICATION_KHR 0x824A | ||||||
|  | #define GL_DEBUG_SOURCE_OTHER_KHR 0x824B | ||||||
|  | #define GL_DEBUG_TYPE_ERROR_KHR 0x824C | ||||||
|  | #define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR 0x824D | ||||||
|  | #define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR 0x824E | ||||||
|  | #define GL_DEBUG_TYPE_PORTABILITY_KHR 0x824F | ||||||
|  | #define GL_DEBUG_TYPE_PERFORMANCE_KHR 0x8250 | ||||||
|  | #define GL_DEBUG_TYPE_OTHER_KHR 0x8251 | ||||||
|  | #define GL_DEBUG_TYPE_MARKER_KHR 0x8268 | ||||||
|  | #define GL_DEBUG_TYPE_PUSH_GROUP_KHR 0x8269 | ||||||
|  | #define GL_DEBUG_TYPE_POP_GROUP_KHR 0x826A | ||||||
|  | #define GL_DEBUG_SEVERITY_NOTIFICATION_KHR 0x826B | ||||||
|  | #define GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR 0x826C | ||||||
|  | #define GL_DEBUG_GROUP_STACK_DEPTH_KHR 0x826D | ||||||
|  | #define GL_BUFFER_KHR 0x82E0 | ||||||
|  | #define GL_SHADER_KHR 0x82E1 | ||||||
|  | #define GL_PROGRAM_KHR 0x82E2 | ||||||
|  | #define GL_VERTEX_ARRAY_KHR 0x8074 | ||||||
|  | #define GL_QUERY_KHR 0x82E3 | ||||||
|  | #define GL_PROGRAM_PIPELINE_KHR 0x82E4 | ||||||
|  | #define GL_SAMPLER_KHR 0x82E6 | ||||||
|  | #define GL_MAX_LABEL_LENGTH_KHR 0x82E8 | ||||||
|  | #define GL_MAX_DEBUG_MESSAGE_LENGTH_KHR 0x9143 | ||||||
|  | #define GL_MAX_DEBUG_LOGGED_MESSAGES_KHR 0x9144 | ||||||
|  | #define GL_DEBUG_LOGGED_MESSAGES_KHR 0x9145 | ||||||
|  | #define GL_DEBUG_SEVERITY_HIGH_KHR 0x9146 | ||||||
|  | #define GL_DEBUG_SEVERITY_MEDIUM_KHR 0x9147 | ||||||
|  | #define GL_DEBUG_SEVERITY_LOW_KHR 0x9148 | ||||||
|  | #define GL_DEBUG_OUTPUT_KHR 0x92E0 | ||||||
|  | #define GL_CONTEXT_FLAG_DEBUG_BIT_KHR 0x00000002 | ||||||
|  | #define GL_STACK_OVERFLOW_KHR 0x0503 | ||||||
|  | #define GL_STACK_UNDERFLOW_KHR 0x0504 | ||||||
|  | #define GL_DISPLAY_LIST 0x82E7 | ||||||
|  | #ifndef GL_ARB_shader_objects | ||||||
|  | #define GL_ARB_shader_objects 1 | ||||||
|  | GLAPI int GLAD_GL_ARB_shader_objects; | ||||||
|  | typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC)(GLhandleARB obj); | ||||||
|  | GLAPI PFNGLDELETEOBJECTARBPROC glad_glDeleteObjectARB; | ||||||
|  | #define glDeleteObjectARB glad_glDeleteObjectARB | ||||||
|  | typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC)(GLenum pname); | ||||||
|  | GLAPI PFNGLGETHANDLEARBPROC glad_glGetHandleARB; | ||||||
|  | #define glGetHandleARB glad_glGetHandleARB | ||||||
|  | typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC)(GLhandleARB containerObj, GLhandleARB attachedObj); | ||||||
|  | GLAPI PFNGLDETACHOBJECTARBPROC glad_glDetachObjectARB; | ||||||
|  | #define glDetachObjectARB glad_glDetachObjectARB | ||||||
|  | typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC)(GLenum shaderType); | ||||||
|  | GLAPI PFNGLCREATESHADEROBJECTARBPROC glad_glCreateShaderObjectARB; | ||||||
|  | #define glCreateShaderObjectARB glad_glCreateShaderObjectARB | ||||||
|  | typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC)(GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length); | ||||||
|  | GLAPI PFNGLSHADERSOURCEARBPROC glad_glShaderSourceARB; | ||||||
|  | #define glShaderSourceARB glad_glShaderSourceARB | ||||||
|  | typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC)(GLhandleARB shaderObj); | ||||||
|  | GLAPI PFNGLCOMPILESHADERARBPROC glad_glCompileShaderARB; | ||||||
|  | #define glCompileShaderARB glad_glCompileShaderARB | ||||||
|  | typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC)(void); | ||||||
|  | GLAPI PFNGLCREATEPROGRAMOBJECTARBPROC glad_glCreateProgramObjectARB; | ||||||
|  | #define glCreateProgramObjectARB glad_glCreateProgramObjectARB | ||||||
|  | typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC)(GLhandleARB containerObj, GLhandleARB obj); | ||||||
|  | GLAPI PFNGLATTACHOBJECTARBPROC glad_glAttachObjectARB; | ||||||
|  | #define glAttachObjectARB glad_glAttachObjectARB | ||||||
|  | typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC)(GLhandleARB programObj); | ||||||
|  | GLAPI PFNGLLINKPROGRAMARBPROC glad_glLinkProgramARB; | ||||||
|  | #define glLinkProgramARB glad_glLinkProgramARB | ||||||
|  | typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC)(GLhandleARB programObj); | ||||||
|  | GLAPI PFNGLUSEPROGRAMOBJECTARBPROC glad_glUseProgramObjectARB; | ||||||
|  | #define glUseProgramObjectARB glad_glUseProgramObjectARB | ||||||
|  | typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC)(GLhandleARB programObj); | ||||||
|  | GLAPI PFNGLVALIDATEPROGRAMARBPROC glad_glValidateProgramARB; | ||||||
|  | #define glValidateProgramARB glad_glValidateProgramARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC)(GLint location, GLfloat v0); | ||||||
|  | GLAPI PFNGLUNIFORM1FARBPROC glad_glUniform1fARB; | ||||||
|  | #define glUniform1fARB glad_glUniform1fARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC)(GLint location, GLfloat v0, GLfloat v1); | ||||||
|  | GLAPI PFNGLUNIFORM2FARBPROC glad_glUniform2fARB; | ||||||
|  | #define glUniform2fARB glad_glUniform2fARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); | ||||||
|  | GLAPI PFNGLUNIFORM3FARBPROC glad_glUniform3fARB; | ||||||
|  | #define glUniform3fARB glad_glUniform3fARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); | ||||||
|  | GLAPI PFNGLUNIFORM4FARBPROC glad_glUniform4fARB; | ||||||
|  | #define glUniform4fARB glad_glUniform4fARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC)(GLint location, GLint v0); | ||||||
|  | GLAPI PFNGLUNIFORM1IARBPROC glad_glUniform1iARB; | ||||||
|  | #define glUniform1iARB glad_glUniform1iARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC)(GLint location, GLint v0, GLint v1); | ||||||
|  | GLAPI PFNGLUNIFORM2IARBPROC glad_glUniform2iARB; | ||||||
|  | #define glUniform2iARB glad_glUniform2iARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC)(GLint location, GLint v0, GLint v1, GLint v2); | ||||||
|  | GLAPI PFNGLUNIFORM3IARBPROC glad_glUniform3iARB; | ||||||
|  | #define glUniform3iARB glad_glUniform3iARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); | ||||||
|  | GLAPI PFNGLUNIFORM4IARBPROC glad_glUniform4iARB; | ||||||
|  | #define glUniform4iARB glad_glUniform4iARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC)(GLint location, GLsizei count, const GLfloat *value); | ||||||
|  | GLAPI PFNGLUNIFORM1FVARBPROC glad_glUniform1fvARB; | ||||||
|  | #define glUniform1fvARB glad_glUniform1fvARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC)(GLint location, GLsizei count, const GLfloat *value); | ||||||
|  | GLAPI PFNGLUNIFORM2FVARBPROC glad_glUniform2fvARB; | ||||||
|  | #define glUniform2fvARB glad_glUniform2fvARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC)(GLint location, GLsizei count, const GLfloat *value); | ||||||
|  | GLAPI PFNGLUNIFORM3FVARBPROC glad_glUniform3fvARB; | ||||||
|  | #define glUniform3fvARB glad_glUniform3fvARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC)(GLint location, GLsizei count, const GLfloat *value); | ||||||
|  | GLAPI PFNGLUNIFORM4FVARBPROC glad_glUniform4fvARB; | ||||||
|  | #define glUniform4fvARB glad_glUniform4fvARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC)(GLint location, GLsizei count, const GLint *value); | ||||||
|  | GLAPI PFNGLUNIFORM1IVARBPROC glad_glUniform1ivARB; | ||||||
|  | #define glUniform1ivARB glad_glUniform1ivARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC)(GLint location, GLsizei count, const GLint *value); | ||||||
|  | GLAPI PFNGLUNIFORM2IVARBPROC glad_glUniform2ivARB; | ||||||
|  | #define glUniform2ivARB glad_glUniform2ivARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC)(GLint location, GLsizei count, const GLint *value); | ||||||
|  | GLAPI PFNGLUNIFORM3IVARBPROC glad_glUniform3ivARB; | ||||||
|  | #define glUniform3ivARB glad_glUniform3ivARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC)(GLint location, GLsizei count, const GLint *value); | ||||||
|  | GLAPI PFNGLUNIFORM4IVARBPROC glad_glUniform4ivARB; | ||||||
|  | #define glUniform4ivARB glad_glUniform4ivARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); | ||||||
|  | GLAPI PFNGLUNIFORMMATRIX2FVARBPROC glad_glUniformMatrix2fvARB; | ||||||
|  | #define glUniformMatrix2fvARB glad_glUniformMatrix2fvARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); | ||||||
|  | GLAPI PFNGLUNIFORMMATRIX3FVARBPROC glad_glUniformMatrix3fvARB; | ||||||
|  | #define glUniformMatrix3fvARB glad_glUniformMatrix3fvARB | ||||||
|  | typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); | ||||||
|  | GLAPI PFNGLUNIFORMMATRIX4FVARBPROC glad_glUniformMatrix4fvARB; | ||||||
|  | #define glUniformMatrix4fvARB glad_glUniformMatrix4fvARB | ||||||
|  | typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC)(GLhandleARB obj, GLenum pname, GLfloat *params); | ||||||
|  | GLAPI PFNGLGETOBJECTPARAMETERFVARBPROC glad_glGetObjectParameterfvARB; | ||||||
|  | #define glGetObjectParameterfvARB glad_glGetObjectParameterfvARB | ||||||
|  | typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC)(GLhandleARB obj, GLenum pname, GLint *params); | ||||||
|  | GLAPI PFNGLGETOBJECTPARAMETERIVARBPROC glad_glGetObjectParameterivARB; | ||||||
|  | #define glGetObjectParameterivARB glad_glGetObjectParameterivARB | ||||||
|  | typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC)(GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); | ||||||
|  | GLAPI PFNGLGETINFOLOGARBPROC glad_glGetInfoLogARB; | ||||||
|  | #define glGetInfoLogARB glad_glGetInfoLogARB | ||||||
|  | typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC)(GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); | ||||||
|  | GLAPI PFNGLGETATTACHEDOBJECTSARBPROC glad_glGetAttachedObjectsARB; | ||||||
|  | #define glGetAttachedObjectsARB glad_glGetAttachedObjectsARB | ||||||
|  | typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC)(GLhandleARB programObj, const GLcharARB *name); | ||||||
|  | GLAPI PFNGLGETUNIFORMLOCATIONARBPROC glad_glGetUniformLocationARB; | ||||||
|  | #define glGetUniformLocationARB glad_glGetUniformLocationARB | ||||||
|  | typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC)(GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); | ||||||
|  | GLAPI PFNGLGETACTIVEUNIFORMARBPROC glad_glGetActiveUniformARB; | ||||||
|  | #define glGetActiveUniformARB glad_glGetActiveUniformARB | ||||||
|  | typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC)(GLhandleARB programObj, GLint location, GLfloat *params); | ||||||
|  | GLAPI PFNGLGETUNIFORMFVARBPROC glad_glGetUniformfvARB; | ||||||
|  | #define glGetUniformfvARB glad_glGetUniformfvARB | ||||||
|  | typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC)(GLhandleARB programObj, GLint location, GLint *params); | ||||||
|  | GLAPI PFNGLGETUNIFORMIVARBPROC glad_glGetUniformivARB; | ||||||
|  | #define glGetUniformivARB glad_glGetUniformivARB | ||||||
|  | typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC)(GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); | ||||||
|  | GLAPI PFNGLGETSHADERSOURCEARBPROC glad_glGetShaderSourceARB; | ||||||
|  | #define glGetShaderSourceARB glad_glGetShaderSourceARB | ||||||
|  | #endif | ||||||
|  | #ifndef GL_KHR_debug | ||||||
|  | #define GL_KHR_debug 1 | ||||||
|  | GLAPI int GLAD_GL_KHR_debug; | ||||||
|  | typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); | ||||||
|  | GLAPI PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl; | ||||||
|  | #define glDebugMessageControl glad_glDebugMessageControl | ||||||
|  | typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); | ||||||
|  | GLAPI PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert; | ||||||
|  | #define glDebugMessageInsert glad_glDebugMessageInsert | ||||||
|  | typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void *userParam); | ||||||
|  | GLAPI PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback; | ||||||
|  | #define glDebugMessageCallback glad_glDebugMessageCallback | ||||||
|  | typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); | ||||||
|  | GLAPI PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog; | ||||||
|  | #define glGetDebugMessageLog glad_glGetDebugMessageLog | ||||||
|  | typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, const GLchar *message); | ||||||
|  | GLAPI PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup; | ||||||
|  | #define glPushDebugGroup glad_glPushDebugGroup | ||||||
|  | typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC)(void); | ||||||
|  | GLAPI PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup; | ||||||
|  | #define glPopDebugGroup glad_glPopDebugGroup | ||||||
|  | typedef void (APIENTRYP PFNGLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label); | ||||||
|  | GLAPI PFNGLOBJECTLABELPROC glad_glObjectLabel; | ||||||
|  | #define glObjectLabel glad_glObjectLabel | ||||||
|  | typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); | ||||||
|  | GLAPI PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel; | ||||||
|  | #define glGetObjectLabel glad_glGetObjectLabel | ||||||
|  | typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC)(const void *ptr, GLsizei length, const GLchar *label); | ||||||
|  | GLAPI PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel; | ||||||
|  | #define glObjectPtrLabel glad_glObjectPtrLabel | ||||||
|  | typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); | ||||||
|  | GLAPI PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel; | ||||||
|  | #define glGetObjectPtrLabel glad_glGetObjectPtrLabel | ||||||
|  | typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLKHRPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); | ||||||
|  | GLAPI PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR; | ||||||
|  | #define glDebugMessageControlKHR glad_glDebugMessageControlKHR | ||||||
|  | typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTKHRPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); | ||||||
|  | GLAPI PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR; | ||||||
|  | #define glDebugMessageInsertKHR glad_glDebugMessageInsertKHR | ||||||
|  | typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKKHRPROC)(GLDEBUGPROCKHR callback, const void *userParam); | ||||||
|  | GLAPI PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR; | ||||||
|  | #define glDebugMessageCallbackKHR glad_glDebugMessageCallbackKHR | ||||||
|  | typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGKHRPROC)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); | ||||||
|  | GLAPI PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR; | ||||||
|  | #define glGetDebugMessageLogKHR glad_glGetDebugMessageLogKHR | ||||||
|  | typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPKHRPROC)(GLenum source, GLuint id, GLsizei length, const GLchar *message); | ||||||
|  | GLAPI PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR; | ||||||
|  | #define glPushDebugGroupKHR glad_glPushDebugGroupKHR | ||||||
|  | typedef void (APIENTRYP PFNGLPOPDEBUGGROUPKHRPROC)(void); | ||||||
|  | GLAPI PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR; | ||||||
|  | #define glPopDebugGroupKHR glad_glPopDebugGroupKHR | ||||||
|  | typedef void (APIENTRYP PFNGLOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label); | ||||||
|  | GLAPI PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR; | ||||||
|  | #define glObjectLabelKHR glad_glObjectLabelKHR | ||||||
|  | typedef void (APIENTRYP PFNGLGETOBJECTLABELKHRPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); | ||||||
|  | GLAPI PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR; | ||||||
|  | #define glGetObjectLabelKHR glad_glGetObjectLabelKHR | ||||||
|  | typedef void (APIENTRYP PFNGLOBJECTPTRLABELKHRPROC)(const void *ptr, GLsizei length, const GLchar *label); | ||||||
|  | GLAPI PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR; | ||||||
|  | #define glObjectPtrLabelKHR glad_glObjectPtrLabelKHR | ||||||
|  | typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELKHRPROC)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); | ||||||
|  | GLAPI PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR; | ||||||
|  | #define glGetObjectPtrLabelKHR glad_glGetObjectPtrLabelKHR | ||||||
|  | typedef void (APIENTRYP PFNGLGETPOINTERVKHRPROC)(GLenum pname, void **params); | ||||||
|  | GLAPI PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR; | ||||||
|  | #define glGetPointervKHR glad_glGetPointervKHR | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										143
									
								
								third-party/glad/src/glad.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										143
									
								
								third-party/glad/src/glad.c
									
									
									
									
										vendored
									
									
								
							| @@ -1,22 +1,23 @@ | |||||||
| /* | /* | ||||||
|  |  | ||||||
|     OpenGL loader generated by glad 0.1.36 on Tue Jul  9 02:07:20 2024. |     OpenGL loader generated by glad 0.1.36 on Wed Jul 10 12:56:38 2024. | ||||||
|  |  | ||||||
|     Language/Generator: C/C++ |     Language/Generator: C/C++ | ||||||
|     Specification: gl |     Specification: gl | ||||||
|     APIs: gl=1.5 |     APIs: gl=1.5 | ||||||
|     Profile: compatibility |     Profile: compatibility | ||||||
|     Extensions: |     Extensions: | ||||||
|          |         GL_ARB_shader_objects, | ||||||
|  |         GL_KHR_debug | ||||||
|     Loader: True |     Loader: True | ||||||
|     Local files: False |     Local files: False | ||||||
|     Omit khrplatform: False |     Omit khrplatform: False | ||||||
|     Reproducible: False |     Reproducible: False | ||||||
|  |  | ||||||
|     Commandline: |     Commandline: | ||||||
|         --profile="compatibility" --api="gl=1.5" --generator="c" --spec="gl" --extensions="" |         --profile="compatibility" --api="gl=1.5" --generator="c" --spec="gl" --extensions="GL_ARB_shader_objects,GL_KHR_debug" | ||||||
|     Online: |     Online: | ||||||
|         https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D1.5 |         https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D1.5&extensions=GL_ARB_shader_objects&extensions=GL_KHR_debug | ||||||
| */ | */ | ||||||
|  |  | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| @@ -713,6 +714,68 @@ PFNGLWINDOWPOS3IPROC glad_glWindowPos3i = NULL; | |||||||
| PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv = NULL; | PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv = NULL; | ||||||
| PFNGLWINDOWPOS3SPROC glad_glWindowPos3s = NULL; | PFNGLWINDOWPOS3SPROC glad_glWindowPos3s = NULL; | ||||||
| PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv = NULL; | PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv = NULL; | ||||||
|  | int GLAD_GL_ARB_shader_objects = 0; | ||||||
|  | int GLAD_GL_KHR_debug = 0; | ||||||
|  | PFNGLDELETEOBJECTARBPROC glad_glDeleteObjectARB = NULL; | ||||||
|  | PFNGLGETHANDLEARBPROC glad_glGetHandleARB = NULL; | ||||||
|  | PFNGLDETACHOBJECTARBPROC glad_glDetachObjectARB = NULL; | ||||||
|  | PFNGLCREATESHADEROBJECTARBPROC glad_glCreateShaderObjectARB = NULL; | ||||||
|  | PFNGLSHADERSOURCEARBPROC glad_glShaderSourceARB = NULL; | ||||||
|  | PFNGLCOMPILESHADERARBPROC glad_glCompileShaderARB = NULL; | ||||||
|  | PFNGLCREATEPROGRAMOBJECTARBPROC glad_glCreateProgramObjectARB = NULL; | ||||||
|  | PFNGLATTACHOBJECTARBPROC glad_glAttachObjectARB = NULL; | ||||||
|  | PFNGLLINKPROGRAMARBPROC glad_glLinkProgramARB = NULL; | ||||||
|  | PFNGLUSEPROGRAMOBJECTARBPROC glad_glUseProgramObjectARB = NULL; | ||||||
|  | PFNGLVALIDATEPROGRAMARBPROC glad_glValidateProgramARB = NULL; | ||||||
|  | PFNGLUNIFORM1FARBPROC glad_glUniform1fARB = NULL; | ||||||
|  | PFNGLUNIFORM2FARBPROC glad_glUniform2fARB = NULL; | ||||||
|  | PFNGLUNIFORM3FARBPROC glad_glUniform3fARB = NULL; | ||||||
|  | PFNGLUNIFORM4FARBPROC glad_glUniform4fARB = NULL; | ||||||
|  | PFNGLUNIFORM1IARBPROC glad_glUniform1iARB = NULL; | ||||||
|  | PFNGLUNIFORM2IARBPROC glad_glUniform2iARB = NULL; | ||||||
|  | PFNGLUNIFORM3IARBPROC glad_glUniform3iARB = NULL; | ||||||
|  | PFNGLUNIFORM4IARBPROC glad_glUniform4iARB = NULL; | ||||||
|  | PFNGLUNIFORM1FVARBPROC glad_glUniform1fvARB = NULL; | ||||||
|  | PFNGLUNIFORM2FVARBPROC glad_glUniform2fvARB = NULL; | ||||||
|  | PFNGLUNIFORM3FVARBPROC glad_glUniform3fvARB = NULL; | ||||||
|  | PFNGLUNIFORM4FVARBPROC glad_glUniform4fvARB = NULL; | ||||||
|  | PFNGLUNIFORM1IVARBPROC glad_glUniform1ivARB = NULL; | ||||||
|  | PFNGLUNIFORM2IVARBPROC glad_glUniform2ivARB = NULL; | ||||||
|  | PFNGLUNIFORM3IVARBPROC glad_glUniform3ivARB = NULL; | ||||||
|  | PFNGLUNIFORM4IVARBPROC glad_glUniform4ivARB = NULL; | ||||||
|  | PFNGLUNIFORMMATRIX2FVARBPROC glad_glUniformMatrix2fvARB = NULL; | ||||||
|  | PFNGLUNIFORMMATRIX3FVARBPROC glad_glUniformMatrix3fvARB = NULL; | ||||||
|  | PFNGLUNIFORMMATRIX4FVARBPROC glad_glUniformMatrix4fvARB = NULL; | ||||||
|  | PFNGLGETOBJECTPARAMETERFVARBPROC glad_glGetObjectParameterfvARB = NULL; | ||||||
|  | PFNGLGETOBJECTPARAMETERIVARBPROC glad_glGetObjectParameterivARB = NULL; | ||||||
|  | PFNGLGETINFOLOGARBPROC glad_glGetInfoLogARB = NULL; | ||||||
|  | PFNGLGETATTACHEDOBJECTSARBPROC glad_glGetAttachedObjectsARB = NULL; | ||||||
|  | PFNGLGETUNIFORMLOCATIONARBPROC glad_glGetUniformLocationARB = NULL; | ||||||
|  | PFNGLGETACTIVEUNIFORMARBPROC glad_glGetActiveUniformARB = NULL; | ||||||
|  | PFNGLGETUNIFORMFVARBPROC glad_glGetUniformfvARB = NULL; | ||||||
|  | PFNGLGETUNIFORMIVARBPROC glad_glGetUniformivARB = NULL; | ||||||
|  | PFNGLGETSHADERSOURCEARBPROC glad_glGetShaderSourceARB = NULL; | ||||||
|  | PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl = NULL; | ||||||
|  | PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert = NULL; | ||||||
|  | PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback = NULL; | ||||||
|  | PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog = NULL; | ||||||
|  | PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup = NULL; | ||||||
|  | PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup = NULL; | ||||||
|  | PFNGLOBJECTLABELPROC glad_glObjectLabel = NULL; | ||||||
|  | PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel = NULL; | ||||||
|  | PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel = NULL; | ||||||
|  | PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel = NULL; | ||||||
|  | PFNGLDEBUGMESSAGECONTROLKHRPROC glad_glDebugMessageControlKHR = NULL; | ||||||
|  | PFNGLDEBUGMESSAGEINSERTKHRPROC glad_glDebugMessageInsertKHR = NULL; | ||||||
|  | PFNGLDEBUGMESSAGECALLBACKKHRPROC glad_glDebugMessageCallbackKHR = NULL; | ||||||
|  | PFNGLGETDEBUGMESSAGELOGKHRPROC glad_glGetDebugMessageLogKHR = NULL; | ||||||
|  | PFNGLPUSHDEBUGGROUPKHRPROC glad_glPushDebugGroupKHR = NULL; | ||||||
|  | PFNGLPOPDEBUGGROUPKHRPROC glad_glPopDebugGroupKHR = NULL; | ||||||
|  | PFNGLOBJECTLABELKHRPROC glad_glObjectLabelKHR = NULL; | ||||||
|  | PFNGLGETOBJECTLABELKHRPROC glad_glGetObjectLabelKHR = NULL; | ||||||
|  | PFNGLOBJECTPTRLABELKHRPROC glad_glObjectPtrLabelKHR = NULL; | ||||||
|  | PFNGLGETOBJECTPTRLABELKHRPROC glad_glGetObjectPtrLabelKHR = NULL; | ||||||
|  | PFNGLGETPOINTERVKHRPROC glad_glGetPointervKHR = NULL; | ||||||
| static void load_GL_VERSION_1_0(GLADloadproc load) { | static void load_GL_VERSION_1_0(GLADloadproc load) { | ||||||
| 	if(!GLAD_GL_VERSION_1_0) return; | 	if(!GLAD_GL_VERSION_1_0) return; | ||||||
| 	glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); | 	glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); | ||||||
| @@ -1183,9 +1246,77 @@ static void load_GL_VERSION_1_5(GLADloadproc load) { | |||||||
| 	glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); | 	glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); | ||||||
| 	glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); | 	glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); | ||||||
| } | } | ||||||
|  | static void load_GL_ARB_shader_objects(GLADloadproc load) { | ||||||
|  | 	if(!GLAD_GL_ARB_shader_objects) return; | ||||||
|  | 	glad_glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)load("glDeleteObjectARB"); | ||||||
|  | 	glad_glGetHandleARB = (PFNGLGETHANDLEARBPROC)load("glGetHandleARB"); | ||||||
|  | 	glad_glDetachObjectARB = (PFNGLDETACHOBJECTARBPROC)load("glDetachObjectARB"); | ||||||
|  | 	glad_glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)load("glCreateShaderObjectARB"); | ||||||
|  | 	glad_glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)load("glShaderSourceARB"); | ||||||
|  | 	glad_glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)load("glCompileShaderARB"); | ||||||
|  | 	glad_glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)load("glCreateProgramObjectARB"); | ||||||
|  | 	glad_glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)load("glAttachObjectARB"); | ||||||
|  | 	glad_glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)load("glLinkProgramARB"); | ||||||
|  | 	glad_glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)load("glUseProgramObjectARB"); | ||||||
|  | 	glad_glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC)load("glValidateProgramARB"); | ||||||
|  | 	glad_glUniform1fARB = (PFNGLUNIFORM1FARBPROC)load("glUniform1fARB"); | ||||||
|  | 	glad_glUniform2fARB = (PFNGLUNIFORM2FARBPROC)load("glUniform2fARB"); | ||||||
|  | 	glad_glUniform3fARB = (PFNGLUNIFORM3FARBPROC)load("glUniform3fARB"); | ||||||
|  | 	glad_glUniform4fARB = (PFNGLUNIFORM4FARBPROC)load("glUniform4fARB"); | ||||||
|  | 	glad_glUniform1iARB = (PFNGLUNIFORM1IARBPROC)load("glUniform1iARB"); | ||||||
|  | 	glad_glUniform2iARB = (PFNGLUNIFORM2IARBPROC)load("glUniform2iARB"); | ||||||
|  | 	glad_glUniform3iARB = (PFNGLUNIFORM3IARBPROC)load("glUniform3iARB"); | ||||||
|  | 	glad_glUniform4iARB = (PFNGLUNIFORM4IARBPROC)load("glUniform4iARB"); | ||||||
|  | 	glad_glUniform1fvARB = (PFNGLUNIFORM1FVARBPROC)load("glUniform1fvARB"); | ||||||
|  | 	glad_glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC)load("glUniform2fvARB"); | ||||||
|  | 	glad_glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC)load("glUniform3fvARB"); | ||||||
|  | 	glad_glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC)load("glUniform4fvARB"); | ||||||
|  | 	glad_glUniform1ivARB = (PFNGLUNIFORM1IVARBPROC)load("glUniform1ivARB"); | ||||||
|  | 	glad_glUniform2ivARB = (PFNGLUNIFORM2IVARBPROC)load("glUniform2ivARB"); | ||||||
|  | 	glad_glUniform3ivARB = (PFNGLUNIFORM3IVARBPROC)load("glUniform3ivARB"); | ||||||
|  | 	glad_glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC)load("glUniform4ivARB"); | ||||||
|  | 	glad_glUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC)load("glUniformMatrix2fvARB"); | ||||||
|  | 	glad_glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC)load("glUniformMatrix3fvARB"); | ||||||
|  | 	glad_glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC)load("glUniformMatrix4fvARB"); | ||||||
|  | 	glad_glGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC)load("glGetObjectParameterfvARB"); | ||||||
|  | 	glad_glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)load("glGetObjectParameterivARB"); | ||||||
|  | 	glad_glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)load("glGetInfoLogARB"); | ||||||
|  | 	glad_glGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC)load("glGetAttachedObjectsARB"); | ||||||
|  | 	glad_glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)load("glGetUniformLocationARB"); | ||||||
|  | 	glad_glGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC)load("glGetActiveUniformARB"); | ||||||
|  | 	glad_glGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC)load("glGetUniformfvARB"); | ||||||
|  | 	glad_glGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC)load("glGetUniformivARB"); | ||||||
|  | 	glad_glGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC)load("glGetShaderSourceARB"); | ||||||
|  | } | ||||||
|  | static void load_GL_KHR_debug(GLADloadproc load) { | ||||||
|  | 	if(!GLAD_GL_KHR_debug) return; | ||||||
|  | 	glad_glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)load("glDebugMessageControl"); | ||||||
|  | 	glad_glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC)load("glDebugMessageInsert"); | ||||||
|  | 	glad_glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)load("glDebugMessageCallback"); | ||||||
|  | 	glad_glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC)load("glGetDebugMessageLog"); | ||||||
|  | 	glad_glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC)load("glPushDebugGroup"); | ||||||
|  | 	glad_glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC)load("glPopDebugGroup"); | ||||||
|  | 	glad_glObjectLabel = (PFNGLOBJECTLABELPROC)load("glObjectLabel"); | ||||||
|  | 	glad_glGetObjectLabel = (PFNGLGETOBJECTLABELPROC)load("glGetObjectLabel"); | ||||||
|  | 	glad_glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC)load("glObjectPtrLabel"); | ||||||
|  | 	glad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC)load("glGetObjectPtrLabel"); | ||||||
|  | 	glad_glGetPointerv = (PFNGLGETPOINTERVPROC)load("glGetPointerv"); | ||||||
|  | 	glad_glDebugMessageControlKHR = (PFNGLDEBUGMESSAGECONTROLKHRPROC)load("glDebugMessageControlKHR"); | ||||||
|  | 	glad_glDebugMessageInsertKHR = (PFNGLDEBUGMESSAGEINSERTKHRPROC)load("glDebugMessageInsertKHR"); | ||||||
|  | 	glad_glDebugMessageCallbackKHR = (PFNGLDEBUGMESSAGECALLBACKKHRPROC)load("glDebugMessageCallbackKHR"); | ||||||
|  | 	glad_glGetDebugMessageLogKHR = (PFNGLGETDEBUGMESSAGELOGKHRPROC)load("glGetDebugMessageLogKHR"); | ||||||
|  | 	glad_glPushDebugGroupKHR = (PFNGLPUSHDEBUGGROUPKHRPROC)load("glPushDebugGroupKHR"); | ||||||
|  | 	glad_glPopDebugGroupKHR = (PFNGLPOPDEBUGGROUPKHRPROC)load("glPopDebugGroupKHR"); | ||||||
|  | 	glad_glObjectLabelKHR = (PFNGLOBJECTLABELKHRPROC)load("glObjectLabelKHR"); | ||||||
|  | 	glad_glGetObjectLabelKHR = (PFNGLGETOBJECTLABELKHRPROC)load("glGetObjectLabelKHR"); | ||||||
|  | 	glad_glObjectPtrLabelKHR = (PFNGLOBJECTPTRLABELKHRPROC)load("glObjectPtrLabelKHR"); | ||||||
|  | 	glad_glGetObjectPtrLabelKHR = (PFNGLGETOBJECTPTRLABELKHRPROC)load("glGetObjectPtrLabelKHR"); | ||||||
|  | 	glad_glGetPointervKHR = (PFNGLGETPOINTERVKHRPROC)load("glGetPointervKHR"); | ||||||
|  | } | ||||||
| static int find_extensionsGL(void) { | static int find_extensionsGL(void) { | ||||||
| 	if (!get_exts()) return 0; | 	if (!get_exts()) return 0; | ||||||
| 	(void)&has_ext; | 	GLAD_GL_ARB_shader_objects = has_ext("GL_ARB_shader_objects"); | ||||||
|  | 	GLAD_GL_KHR_debug = has_ext("GL_KHR_debug"); | ||||||
| 	free_exts(); | 	free_exts(); | ||||||
| 	return 1; | 	return 1; | ||||||
| } | } | ||||||
| @@ -1252,6 +1383,8 @@ int gladLoadGLLoader(GLADloadproc load) { | |||||||
| 	load_GL_VERSION_1_5(load); | 	load_GL_VERSION_1_5(load); | ||||||
|  |  | ||||||
| 	if (!find_extensionsGL()) return 0; | 	if (!find_extensionsGL()) return 0; | ||||||
|  | 	load_GL_ARB_shader_objects(load); | ||||||
|  | 	load_GL_KHR_debug(load); | ||||||
| 	return GLVersion.major != 0 || GLVersion.minor != 0; | 	return GLVersion.major != 0 || GLVersion.minor != 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								third-party/stb/stb_ds.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								third-party/stb/stb_ds.h
									
									
									
									
										vendored
									
									
								
							| @@ -1121,7 +1121,7 @@ size_t stbds_hash_bytes(void *p, size_t len, size_t seed) | |||||||
|   unsigned char *d = (unsigned char *) p; |   unsigned char *d = (unsigned char *) p; | ||||||
|  |  | ||||||
|   if (len == 4) { |   if (len == 4) { | ||||||
|     unsigned int hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); |     uint32_t hash = (uint32_t)d[0] | ((uint32_t)d[1] << 8) | ((uint32_t)d[2] << 16) | ((uint32_t)d[3] << 24); | ||||||
|     #if 0 |     #if 0 | ||||||
|     // HASH32-A  Bob Jenkin's hash function w/o large constants |     // HASH32-A  Bob Jenkin's hash function w/o large constants | ||||||
|     hash ^= seed; |     hash ^= seed; | ||||||
| @@ -1177,8 +1177,8 @@ size_t stbds_hash_bytes(void *p, size_t len, size_t seed) | |||||||
|  |  | ||||||
|     return (((size_t) hash << 16 << 16) | hash) ^ seed; |     return (((size_t) hash << 16 << 16) | hash) ^ seed; | ||||||
|   } else if (len == 8 && sizeof(size_t) == 8) { |   } else if (len == 8 && sizeof(size_t) == 8) { | ||||||
|     size_t hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); |     size_t hash = (size_t)d[0] | ((size_t)d[1] << 8) | ((size_t)d[2] << 16) | ((size_t)d[3] << 24); | ||||||
|     hash |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // avoid warning if size_t == 4 |     hash |= ((size_t)d[4] | ((size_t)d[5] << 8) | ((size_t)d[6] << 16) | ((size_t)d[7] << 24)) << 16 << 16; | ||||||
|     hash ^= seed; |     hash ^= seed; | ||||||
|     hash = (~hash) + (hash << 21); |     hash = (~hash) + (hash << 21); | ||||||
|     hash ^= STBDS_ROTATE_RIGHT(hash,24); |     hash ^= STBDS_ROTATE_RIGHT(hash,24); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user