From 55d85399e9c38f2761c76d2fa0fa423d3240687f Mon Sep 17 00:00:00 2001 From: veclavtalica Date: Fri, 12 Jul 2024 21:10:25 +0300 Subject: [PATCH] full removal of SDL_Renderer usage, working spatial triangle rendering, temporary(?) regression of HDPI --- src/config.h | 1 + src/context.h | 1 - src/game/scenes/ingame.c | 32 ++--- src/game_api.h | 1 + src/input.c | 22 ++-- src/input.h | 2 +- src/main.c | 19 +-- src/private/rendering.h | 6 +- src/private/textures.h | 41 ++++++ src/rendering.c | 278 ++++++++++++++++++++++++--------------- src/textures.c | 120 +++++++++++++---- src/textures.h | 49 +------ 12 files changed, 348 insertions(+), 224 deletions(-) create mode 100644 src/private/textures.h diff --git a/src/config.h b/src/config.h index 805214f..11d647f 100644 --- a/src/config.h +++ b/src/config.h @@ -17,6 +17,7 @@ #define RENDER_BASE_WIDTH 640 #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_BIT_DEPTH 32 diff --git a/src/context.h b/src/context.h index 54c4f99..bf31e21 100644 --- a/src/context.h +++ b/src/context.h @@ -54,7 +54,6 @@ typedef struct context { unsigned int update_multiplicity; SDL_GLContext *gl_context; - SDL_Renderer *renderer; SDL_Window *window; uint32_t window_id; int window_w; diff --git a/src/game/scenes/ingame.c b/src/game/scenes/ingame.c index 9958539..66e36f9 100644 --- a/src/game/scenes/ingame.c +++ b/src/game/scenes/ingame.c @@ -11,28 +11,20 @@ static void ingame_tick(struct state *state) { world_drawdef(scn->world); player_calc(scn->player); - // unfurl_triangle("/assets/title.png", - // (t_fvec3){ 1250, 700, 0 }, - // (t_fvec3){ 0, 800, 0 }, - // (t_fvec3){ 0, 0, 0 }, - // (t_shvec2){ 0, 360 }, - // (t_shvec2){ 0, 0 }, - // (t_shvec2){ 360, 0 }); - - unfurl_triangle("/assets/red.png", - (t_fvec3){ 0, 0, 0 }, - (t_fvec3){ RENDER_BASE_WIDTH, 0, 0 }, - (t_fvec3){ RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0 }, + unfurl_triangle("/assets/player/baron-walk.png", + (t_fvec3){ -1, -1, 0 }, + (t_fvec3){ 1, -1, 0 }, + (t_fvec3){ 1, 1, 0 }, (t_shvec2){ 0, 0 }, - (t_shvec2){ 80, 0 }, - (t_shvec2){ 80, 80 }); + (t_shvec2){ 48, 0 }, + (t_shvec2){ 48, 48 }); - unfurl_triangle("/assets/red.png", - (t_fvec3){ RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0 }, - (t_fvec3){ 0, RENDER_BASE_HEIGHT, 0 }, - (t_fvec3){ 0, 0, 0 }, - (t_shvec2){ 80, 80 }, - (t_shvec2){ 0, 80 }, + unfurl_triangle("/assets/player/baron-walk.png", + (t_fvec3){ 1, 1, 0 }, + (t_fvec3){ -1, 1, 0 }, + (t_fvec3){ -1, -1, 0 }, + (t_shvec2){ 48, 48 }, + (t_shvec2){ 0, 48 }, (t_shvec2){ 0, 0 }); } diff --git a/src/game_api.h b/src/game_api.h index 79efee9..49760d2 100644 --- a/src/game_api.h +++ b/src/game_api.h @@ -5,6 +5,7 @@ #include "context.h" #include "rendering.h" +#include "audio.h" #include "util.h" #include diff --git a/src/input.c b/src/input.c index 0117801..ad9196e 100644 --- a/src/input.c +++ b/src/input.c @@ -36,18 +36,21 @@ static void update_action_pressed_state(struct input_state *input, struct action else { action->just_changed = !action->is_pressed; 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 * coords into a position inside the logical render * area. this has to be done to get an accurate point * that can actually be used in game logic */ - SDL_RenderWindowToLogical(input->renderer, - input->mouse_window_position.x, - input->mouse_window_position.y, - &action->position.x, - &action->position.y); + // SDL_RenderWindowToLogical(input->renderer, + // input->mouse_window_position.x, + // input->mouse_window_position.y, + // &action->position.x, + // &action->position.y); return; } break; @@ -59,9 +62,9 @@ static void update_action_pressed_state(struct input_state *input, struct action static void input_bind_code_to_action(struct input_state *input, - char *action_name, - enum button_source source, - union button_code code) + char *action_name, + enum button_source source, + union button_code code) { struct action_hash_item *action_item = shgetp_null(input->action_hash, action_name); if (action_item == NULL) { @@ -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); - input->renderer = renderer; } diff --git a/src/input.h b/src/input.h index fab59b3..f514342 100644 --- a/src/input.h +++ b/src/input.h @@ -63,7 +63,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_update(struct input_state *input); diff --git a/src/main.c b/src/main.c index af5bfa2..38db7f4 100644 --- a/src/main.c +++ b/src/main.c @@ -35,6 +35,8 @@ static void poll_events(void) { switch (e.window.event) { case SDL_WINDOWEVENT_RESIZED: + ctx.window_w = e.window.data1; + ctx.window_h = e.window.data2; break; } @@ -175,7 +177,7 @@ static bool initialize(void) { SDL_WINDOWPOS_CENTERED, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, - SDL_WINDOW_ALLOW_HIGHDPI | + // SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL); if (ctx.window == NULL) { @@ -201,14 +203,13 @@ static bool initialize(void) { /* might need this to have multiple windows */ ctx.window_id = SDL_GetWindowID(ctx.window); - - /* now that we have a window, we know a renderer can be created */ - ctx.renderer = SDL_CreateRenderer(ctx.window, -1, SDL_RENDERER_PRESENTVSYNC); - /* SDL_SetHint(SDL_HINT_RENDER_LOGICAL_SIZE_MODE, "overscan"); */ - /* SDL_RenderSetIntegerScale(ctx.renderer, SDL_TRUE); */ - SDL_RenderSetLogicalSize(ctx.renderer, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT); - SDL_GetRendererOutputSize(ctx.renderer, &ctx.window_w, &ctx.window_h); + glViewport(0, 0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT); + + /* TODO: */ + // SDL_GetRendererOutputSize(ctx.renderer, &ctx.window_w, &ctx.window_h); + ctx.window_w = RENDER_BASE_WIDTH; + ctx.window_h = RENDER_BASE_HEIGHT; /* audio initialization */ { @@ -298,7 +299,7 @@ static bool initialize(void) { } /* input */ - input_state_init(&ctx.input, ctx.renderer); + input_state_init(&ctx.input); /* scripting */ /* diff --git a/src/private/rendering.h b/src/private/rendering.h index fcaa614..75b662f 100644 --- a/src/private/rendering.h +++ b/src/private/rendering.h @@ -47,11 +47,11 @@ struct mesh_batch_item { /* is structure that is in opengl vertex array */ struct uncolored_space_triangle { t_fvec3 v0; - t_shvec2 uv0; + t_fvec2 uv0; t_fvec3 v1; - t_shvec2 uv1; + t_fvec2 uv1; t_fvec3 v2; - t_shvec2 uv2; + t_fvec2 uv2; }; #endif diff --git a/src/private/textures.h b/src/private/textures.h new file mode 100644 index 0000000..87b49d4 --- /dev/null +++ b/src/private/textures.h @@ -0,0 +1,41 @@ +#ifndef PRIVATE_TEXTURES_H +#define PRIVATE_TEXTURES_H + +#include +#include +#include + +#include + +struct texture { + SDL_Rect srcrect; /* position in atlas */ + SDL_Surface *data; /* original image data */ + GLuint 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; +}; + + +struct texture_cache { + /* from context */ + SDL_Window *window; + + 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; + GLuint *atlas_textures; + int atlas_index; + + bool is_dirty; /* current atlas needs to be recreated */ +}; + +#endif diff --git a/src/rendering.c b/src/rendering.c index 7108981..508835a 100644 --- a/src/rendering.c +++ b/src/rendering.c @@ -10,6 +10,7 @@ #include #include +/* http://www.swiftless.com/opengltuts.html */ void render_queue_clear(void) { /* since i don't intend to free the queues, */ @@ -108,17 +109,20 @@ void unfurl_triangle(const char *path, t_shvec2 uv2) { /* corrected atlas texture coordinates */ - t_shvec2 uv0c, uv1c, uv2c; + t_fvec2 uv0c, uv1c, uv2c; struct mesh_batch *batch_p; textures_load(&ctx.texture_cache, path); + const SDL_Rect srcrect = textures_get_srcrect(&ctx.texture_cache, path); const int atlas_index = textures_get_atlas_index(&ctx.texture_cache, path); if (atlas_index == -1) { - /* loners span whole texture i assume */ - uv0c = uv0; - uv1c = uv1; - uv2c = uv2; + uv0c.x = (float)uv0.x / (float)srcrect.w; + uv0c.y = (float)uv0.y / (float)srcrect.h; + uv1c.x = (float)uv1.x / (float)srcrect.w; + uv1c.y = (float)uv1.y / (float)srcrect.h; + uv2c.x = (float)uv2.x / (float)srcrect.w; + uv2c.y = (float)uv2.y / (float)srcrect.h; batch_p = &shgetp(ctx.uncolored_mesh_batches_loners, path)->value; @@ -134,20 +138,17 @@ void unfurl_triangle(const char *path, sizeof (struct mesh_batch) * ((atlas_index + 1) - old_len)); } - const SDL_Rect srcrect = ctx.texture_cache.hash[atlas_index].value.srcrect; /* TODO: does it work? */ + const float wr = (float)srcrect.w / TEXTURE_ATLAS_SIZE; + const float hr = (float)srcrect.h / TEXTURE_ATLAS_SIZE; + const float xr = (float)srcrect.x / TEXTURE_ATLAS_SIZE; + const float yr = (float)srcrect.y / TEXTURE_ATLAS_SIZE; - /* fixed point galore */ - const int16_t srcratx = (int16_t)srcrect.x * (INT16_MAX / TEXTURE_ATLAS_SIZE); - const int16_t srcratw = (int16_t)srcrect.w * (INT16_MAX / TEXTURE_ATLAS_SIZE); - const int16_t srcrath = (int16_t)srcrect.h * (INT16_MAX / TEXTURE_ATLAS_SIZE); - const int16_t srcraty = (int16_t)srcrect.y * (INT16_MAX / TEXTURE_ATLAS_SIZE); /* flip? */ - - uv0c.x = (int16_t)(srcratx + ((uint16_t)((uv0.x * (INT16_MAX / srcrect.w)) * srcratw) >> 7)); - uv0c.y = (int16_t)(srcraty + ((uint16_t)((uv0.y * (INT16_MAX / srcrect.h)) * srcrath) >> 7)); - uv1c.x = (int16_t)(srcratx + ((uint16_t)((uv1.x * (INT16_MAX / srcrect.w)) * srcratw) >> 7)); - uv1c.y = (int16_t)(srcraty + ((uint16_t)((uv1.y * (INT16_MAX / srcrect.h)) * srcrath) >> 7)); - uv2c.x = (int16_t)(srcratx + ((uint16_t)((uv2.x * (INT16_MAX / srcrect.w)) * srcratw) >> 7)); - uv2c.y = (int16_t)(srcraty + ((uint16_t)((uv2.y * (INT16_MAX / srcrect.h)) * srcrath) >> 7)); + uv0c.x = xr + ((float)uv0.x / (float)srcrect.w) * wr; + uv0c.y = yr + ((float)uv0.y / (float)srcrect.h) * hr; + uv1c.x = xr + ((float)uv1.x / (float)srcrect.w) * wr; + uv1c.y = yr + ((float)uv1.y / (float)srcrect.h) * hr; + uv2c.x = xr + ((float)uv2.x / (float)srcrect.w) * wr; + uv2c.y = yr + ((float)uv2.y / (float)srcrect.h) * hr; batch_p = &ctx.uncolored_mesh_batches[atlas_index]; } @@ -155,14 +156,11 @@ void unfurl_triangle(const char *path, struct uncolored_space_triangle *data = (struct uncolored_space_triangle *)batch_p->data; struct uncolored_space_triangle pack = { .v0 = v0, - // .uv0 = uv0c, - .uv0 = { 0, 0 }, + .uv0 = uv0c, .v1 = v1, - // .uv1 = uv1c, - .uv1 = { INT16_MAX, 0 }, + .uv1 = uv1c, .v2 = v2, - // .uv2 = uv2c, - .uv2 = { INT16_MAX, INT16_MAX }, + .uv2 = uv2c, }; arrpush(data, pack); @@ -229,6 +227,7 @@ static int cmp_layers(const void *a, const void *b) { } +/* TODO: not that we're SDL free we need to implement batching ourselves */ /* 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); @@ -239,66 +238,86 @@ static void sort_sprites(struct sprite_primitive *sprites) { } +static void upload_quad_vertices(t_frect rect) { + /* client memory needs to be reachable on glDraw*, so */ + static float vertices[6 * 2]; + + vertices[0] = rect.x; vertices[1] = rect.y; + vertices[2] = rect.x; vertices[3] = rect.y + rect.h; + vertices[4] = rect.x + rect.w; vertices[5] = rect.y + rect.h; + vertices[6] = rect.x + rect.w; vertices[7] = rect.y + rect.h; + vertices[8] = rect.x + rect.w; vertices[9] = rect.y; + vertices[10] = rect.x; vertices[11] = rect.y; + + glVertexPointer(2, GL_FLOAT, 0, (void *)&vertices); +} + + +/* TODO: texture flipping */ +/* assumes that orthogonal matrix setup is done already */ static void render_sprite(struct sprite_primitive *sprite) { - SDL_Rect srcrect_value = { 0 }; - SDL_Rect *srcrect = &srcrect_value; - SDL_Texture *texture = NULL; + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0); /* loner */ if (sprite->atlas_index == -1) { - srcrect = NULL; - texture = textures_get_loner(&ctx.texture_cache, sprite->path); + textures_bind_loner(&ctx.texture_cache, sprite->path, GL_TEXTURE_2D); + glTexCoordPointer(2, + GL_SHORT, + 0, + (void *)(int16_t[6 * 2]) { + 0, INT16_MAX, + 0, 0, + INT16_MAX, 0, + INT16_MAX, 0, + INT16_MAX, INT16_MAX, + 0, INT16_MAX }); } else { - *srcrect = textures_get_srcrect(&ctx.texture_cache, sprite->path); - texture = textures_get_atlas(&ctx.texture_cache, sprite->atlas_index); + SDL_Rect srcrect = textures_get_srcrect(&ctx.texture_cache, sprite->path); + textures_bind_atlas(&ctx.texture_cache, sprite->atlas_index, GL_TEXTURE_2D); + glTexCoordPointer(2, + GL_FLOAT, + 0, + /* TODO: try using shorts */ + (void *)(float[6 * 2]) { + (float)srcrect.x / TEXTURE_ATLAS_SIZE, + (float)srcrect.y / TEXTURE_ATLAS_SIZE, + (float)srcrect.x / TEXTURE_ATLAS_SIZE, + (float)(srcrect.y + srcrect.h) / TEXTURE_ATLAS_SIZE, + (float)(srcrect.x + srcrect.w) / TEXTURE_ATLAS_SIZE, + (float)(srcrect.y + srcrect.h) / TEXTURE_ATLAS_SIZE, + (float)(srcrect.x + srcrect.w) / TEXTURE_ATLAS_SIZE, + (float)(srcrect.y + srcrect.h) / TEXTURE_ATLAS_SIZE, + (float)(srcrect.x + srcrect.w) / TEXTURE_ATLAS_SIZE, + (float)srcrect.y / TEXTURE_ATLAS_SIZE, + (float)srcrect.x / TEXTURE_ATLAS_SIZE, + (float)srcrect.y / TEXTURE_ATLAS_SIZE }); } - SDL_RendererFlip flip = SDL_FLIP_NONE; - if (sprite->flip_x) - flip |= SDL_FLIP_HORIZONTAL; - if (sprite->flip_y) - flip |= SDL_FLIP_VERTICAL; + glColor4ub(sprite->color.r, sprite->color.g, sprite->color.b, sprite->color.a); - 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_SetTextureBlendMode(texture, sprite->blend_mode); - SDL_Rect rect = { - (int)sprite->rect.x, - (int)sprite->rect.y, - (int)sprite->rect.w, - (int)sprite->rect.h - }; + glEnableClientState(GL_VERTEX_ARRAY); + upload_quad_vertices(sprite->rect); - SDL_RenderCopyEx(ctx.renderer, - texture, - srcrect, - &rect, - sprite->rotation, - NULL, - flip); + glDrawArrays(GL_TRIANGLES, 0, 6); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glBindTexture(GL_TEXTURE_2D, 0); } static void render_rectangle(struct rect_primitive *rectangle) { - SDL_SetRenderDrawColor(ctx.renderer, - rectangle->color.r, - rectangle->color.g, - rectangle->color.b, - rectangle->color.a); + glColor4ub(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 - }; + glEnableClientState(GL_VERTEX_ARRAY); + upload_quad_vertices(rectangle->rect); - SDL_RenderFillRect(ctx.renderer, &rect); - SDL_SetRenderDrawColor(ctx.renderer, 255, 255, 255, 255); + glDrawArrays(GL_TRIANGLES, 0, 6); + glDisableClientState(GL_VERTEX_ARRAY); } @@ -379,11 +398,25 @@ static void render_circle(struct circle_primitive *circle) { &vertices, &indices); - SDL_RenderGeometry(ctx.renderer, NULL, - vertices, - num_vertices + 1, /* vertices + center vertex */ - indices, - num_vertices * 3); + 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); @@ -439,19 +472,13 @@ static void draw_uncolored_space_traingle_batch(struct mesh_batch *batch) { offsetof(struct uncolored_space_triangle, v1), (void *)offsetof(struct uncolored_space_triangle, v0)); - /* note: propagates further to where texture binding is done */ glEnableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTexture(GL_TEXTURE0); glTexCoordPointer(2, - GL_SHORT, + GL_FLOAT, offsetof(struct uncolored_space_triangle, v1), (void *)offsetof(struct uncolored_space_triangle, uv0)); - // for (size_t i = 0; i < data_len; ++i) { - // struct uncolored_space_triangle t = ((struct uncolored_space_triangle *)batch->data)[i]; - // log_info("{%i, %i, %i, %i, %i, %i}\n", t.uv0.x, t.uv0.y, t.uv1.x, t.uv1.y, t.uv2.x, t.uv2.y); - // } - /* commit for drawing */ glDrawArrays(GL_TRIANGLES, 0, 3 * (int)data_len); @@ -465,12 +492,7 @@ static void draw_uncolored_space_traingle_batch(struct mesh_batch *batch) { static void render_space(void) { - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0, -1, 1); - - glUseProgramObjectARB(0); + glEnable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); /* solid white, no modulation */ @@ -478,24 +500,20 @@ static void render_space(void) { for (size_t i = 0; i < arrlenu(ctx.uncolored_mesh_batches); ++i) { if (arrlenu(&ctx.uncolored_mesh_batches[i].data) > 0) { - SDL_Texture *const atlas = textures_get_atlas(&ctx.texture_cache, (int)i); - SDL_GL_BindTexture(atlas, NULL, NULL); + textures_bind_atlas(&ctx.texture_cache, (int)i, GL_TEXTURE_2D); draw_uncolored_space_traingle_batch(&ctx.uncolored_mesh_batches[i]); - SDL_GL_UnbindTexture(atlas); } } for (size_t i = 0; i < shlenu(ctx.uncolored_mesh_batches_loners); ++i) { if (arrlenu(&ctx.uncolored_mesh_batches_loners[i].value.data) > 0) { - SDL_Texture *const atlas = textures_get_loner(&ctx.texture_cache, - ctx.uncolored_mesh_batches_loners[i].key); - SDL_GL_BindTexture(atlas, NULL, NULL); + textures_bind_loner(&ctx.texture_cache, + ctx.uncolored_mesh_batches_loners[i].key, + GL_TEXTURE_2D); + draw_uncolored_space_traingle_batch(&ctx.uncolored_mesh_batches_loners[i].value); - SDL_GL_UnbindTexture(atlas); } } - - glPopMatrix(); } @@ -503,6 +521,30 @@ void render(void) { if (ctx.texture_cache.is_dirty) textures_update_current_atlas(&ctx.texture_cache); + /* fit rendering context onto the resizable screen */ + 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 + ); + } + + glEnable(GL_DEPTH_TEST); + glEnable(GL_ALPHA_TEST); + glClearColor((1.0f / 255) * 230, (1.0f / 255) * 230, (1.0f / 255) * 230, 1); @@ -511,22 +553,42 @@ void render(void) { GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - // glDisable(GL_CULL_FACE); - // glDisable(GL_DEPTH_TEST); - glEnable(GL_BLEND); + { + glDisable(GL_CULL_FACE); + glDepthFunc(GL_ALWAYS); /* fill depth buffer with ones, 2d view is always in front */ + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0, -1, 1); - /* TODO: write with no depth test, just fill it in */ - render_sprites(); - render_rectangles(); - render_circles(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); - // glEnable(GL_CULL_FACE); - // glEnable(GL_DEPTH_TEST); - glDisable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + + render_sprites(); + render_rectangles(); + render_circles(); + } - /* TODO: use depth test to optimize gui regions away */ - render_space(); + { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glRotatef(60, 1, 0, 0); + + glEnable(GL_CULL_FACE); + glDepthFunc(GL_LESS); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + /* TODO: use depth test to optimize gui regions away */ + render_space(); + } - SDL_RenderFlush(ctx.renderer); SDL_GL_SwapWindow(ctx.window); } diff --git a/src/textures.c b/src/textures.c index c202ff2..37cc773 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1,6 +1,7 @@ -#include "textures.h" +#include "private/textures.h" #include "config.h" #include "util.h" +#include "textures.h" #include #include @@ -35,6 +36,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 */ static void add_new_atlas(struct texture_cache *cache) { SDL_PixelFormat *native_format = @@ -57,12 +76,51 @@ static void add_new_atlas(struct texture_cache *cache) { a_mask); SDL_FreeFormat(native_format); - SDL_SetSurfaceRLE(new_atlas, true); + SDL_SetSurfaceRLE(new_atlas, true); arrput(cache->atlas_surfaces, new_atlas); - - SDL_Texture *new_atlas_texture = - SDL_CreateTextureFromSurface(cache->renderer, new_atlas); - arrput(cache->atlas_textures, new_atlas_texture); + arrput(cache->atlas_textures, new_gl_texture()); +} + + +static void upload_texture_from_surface(GLuint texture, SDL_Surface *surface) { + 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_RGBA, + surface->w, + surface->h, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + intermediate->pixels); + + SDL_UnlockSurface(intermediate); + SDL_FreeSurface(intermediate); + + glBindTexture(GL_TEXTURE_2D, 0); } @@ -85,12 +143,7 @@ static void recreate_current_atlas_texture(struct texture_cache *cache) { } /* texturize it! */ - SDL_LockSurface(atlas_surface); - SDL_UpdateTexture(cache->atlas_textures[cache->atlas_index], - NULL, - atlas_surface->pixels, - atlas_surface->pitch); - SDL_UnlockSurface(atlas_surface); + upload_texture_from_surface(cache->atlas_textures[cache->atlas_index], atlas_surface); } @@ -171,7 +224,6 @@ static void update_texture_rects_in_atlas(struct texture_cache *cache, stbrp_rec void textures_cache_init(struct texture_cache *cache, SDL_Window *window) { cache->window = window; - cache->renderer = SDL_GetRenderer(window); sh_new_arena(cache->hash); sh_new_arena(cache->loner_hash); @@ -185,7 +237,7 @@ void textures_cache_init(struct texture_cache *cache, SDL_Window *window) { void textures_cache_deinit(struct texture_cache *cache) { /* free atlas textures */ for (size_t i = 0; i < arrlenu(cache->atlas_textures); ++i) { - SDL_DestroyTexture(cache->atlas_textures[i]); + glDeleteTextures(1, &cache->atlas_textures[i]); } arrfree(cache->atlas_textures); @@ -247,8 +299,11 @@ void textures_load(struct texture_cache *cache, const char *path) { /* it's a "loner texture," it doesn't fit in an atlas so it's not in one */ if (surface->w > TEXTURE_ATLAS_SIZE || surface->h > TEXTURE_ATLAS_SIZE) { - new_texture.loner_data = SDL_CreateTextureFromSurface(cache->renderer, surface); + new_texture.loner_data = new_gl_texture(); + upload_texture_from_surface(new_texture.loner_data, surface); new_texture.atlas_index = -1; + new_texture.srcrect = (SDL_Rect) { + .w = surface->w, .h = surface->h }; shput(cache->loner_hash, path, new_texture); } else { new_texture.atlas_index = cache->atlas_index; @@ -301,17 +356,23 @@ void textures_update_current_atlas(struct texture_cache *cache) { SDL_Rect textures_get_srcrect(struct texture_cache *cache, const char *path) { - struct texture_cache_item *texture = shgetp_null(cache->hash, path); - if (texture == NULL) { + int index = textures_get_atlas_index(cache, path); + if (index == -1) { + return shget(cache->loner_hash, path).srcrect; + } else if (index == INT_MIN) { CRY("Texture lookup failed.", "Tried to get texture that isn't loaded."); return (SDL_Rect){ 0, 0, 0, 0 }; + } else { + return shget(cache->hash, path).srcrect; } - - return texture->value.srcrect; } +/* TODO: instead of index, return a 'key' with following encoded meaning: */ +/* value of 0 - no atlas (#define NO_ATLAS (0) ?) */ +/* negative value - index in loners (-key - 1) */ +/* positive value - index in atlases (key - 1) */ int textures_get_atlas_index(struct texture_cache *cache, const char *path) { struct texture_cache_item *texture = shgetp_null(cache->hash, path); @@ -331,25 +392,28 @@ int textures_get_atlas_index(struct texture_cache *cache, const char *path) { } -SDL_Texture *textures_get_atlas(struct texture_cache *cache, int index) { +void textures_bind_atlas(struct texture_cache *cache, int index, GLenum target) { /* out of bounds */ - if (arrlen(cache->atlas_textures) < index + 1 || index < 0) - return NULL; + if (arrlen(cache->atlas_textures) < index + 1 || index < 0) { + CRY("Atlas texture binding failed.", + "Tried to bind texture by invalid index"); + return; + } - return cache->atlas_textures[index]; + glBindTexture(target, cache->atlas_textures[index]); } -SDL_Texture *textures_get_loner(struct texture_cache *cache, const char *path) { +void textures_bind_loner(struct texture_cache *cache, const char *path, GLenum target) { 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."); - return NULL; + CRY("Loner texture binding failed.", + "Tried to bind texture that isn't loaded."); + return; } - return texture->value.loner_data; + glBindTexture(target, texture->value.loner_data); } diff --git a/src/textures.h b/src/textures.h index 7d6c7ea..d6a5b58 100644 --- a/src/textures.h +++ b/src/textures.h @@ -1,46 +1,10 @@ #ifndef TEXTURES_H #define TEXTURES_H +#include "private/textures.h" #include -#include - -#include - - -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 */ -}; - +#include void textures_cache_init(struct texture_cache *cache, SDL_Window *window); void textures_cache_deinit(struct texture_cache *cache); @@ -64,15 +28,12 @@ SDL_Rect textures_get_srcrect(struct texture_cache *cache, const char *path); /* if the texture is not found, returns INT_MIN */ int textures_get_atlas_index(struct texture_cache *cache, const char *path); -/* returns a pointer to the atlas at `index` */ -/* if the index is out of bounds, returns NULL. */ -/* you can get the index via texture_get_atlas_index */ -SDL_Texture *textures_get_atlas(struct texture_cache *cache, int index); +/* binds atlas texture in opengl state */ +void textures_bind_atlas(struct texture_cache *cache, int index, GLenum target); -SDL_Texture *textures_get_loner(struct texture_cache *cache, const char *path); +void textures_bind_loner(struct texture_cache *cache, const char *path, GLenum target); /* returns the number of atlases in the cache */ size_t textures_get_num_atlases(struct texture_cache *cache); - #endif