opengl moment #1
@ -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
|
||||||
|
@ -54,7 +54,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;
|
||||||
|
@ -11,28 +11,20 @@ static void ingame_tick(struct state *state) {
|
|||||||
world_drawdef(scn->world);
|
world_drawdef(scn->world);
|
||||||
player_calc(scn->player);
|
player_calc(scn->player);
|
||||||
|
|
||||||
// unfurl_triangle("/assets/title.png",
|
unfurl_triangle("/assets/player/baron-walk.png",
|
||||||
// (t_fvec3){ 1250, 700, 0 },
|
(t_fvec3){ -1, -1, 0 },
|
||||||
// (t_fvec3){ 0, 800, 0 },
|
(t_fvec3){ 1, -1, 0 },
|
||||||
// (t_fvec3){ 0, 0, 0 },
|
(t_fvec3){ 1, 1, 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 },
|
|
||||||
(t_shvec2){ 0, 0 },
|
(t_shvec2){ 0, 0 },
|
||||||
(t_shvec2){ 80, 0 },
|
(t_shvec2){ 48, 0 },
|
||||||
(t_shvec2){ 80, 80 });
|
(t_shvec2){ 48, 48 });
|
||||||
|
|
||||||
unfurl_triangle("/assets/red.png",
|
unfurl_triangle("/assets/player/baron-walk.png",
|
||||||
(t_fvec3){ RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0 },
|
(t_fvec3){ 1, 1, 0 },
|
||||||
(t_fvec3){ 0, RENDER_BASE_HEIGHT, 0 },
|
(t_fvec3){ -1, 1, 0 },
|
||||||
(t_fvec3){ 0, 0, 0 },
|
(t_fvec3){ -1, -1, 0 },
|
||||||
(t_shvec2){ 80, 80 },
|
(t_shvec2){ 48, 48 },
|
||||||
(t_shvec2){ 0, 80 },
|
(t_shvec2){ 0, 48 },
|
||||||
(t_shvec2){ 0, 0 });
|
(t_shvec2){ 0, 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
22
src/input.c
22
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;
|
||||||
@ -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,
|
static void input_bind_code_to_action(struct input_state *input,
|
||||||
char *action_name,
|
char *action_name,
|
||||||
enum button_source source,
|
enum button_source source,
|
||||||
union button_code code)
|
union button_code code)
|
||||||
{
|
{
|
||||||
struct action_hash_item *action_item = shgetp_null(input->action_hash, action_name);
|
struct action_hash_item *action_item = shgetp_null(input->action_hash, action_name);
|
||||||
if (action_item == NULL) {
|
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);
|
sh_new_strdup(input->action_hash);
|
||||||
input->renderer = renderer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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_deinit(struct input_state *input);
|
||||||
void input_state_update(struct input_state *input);
|
void input_state_update(struct input_state *input);
|
||||||
|
|
||||||
|
17
src/main.c
17
src/main.c
@ -35,6 +35,8 @@ static void poll_events(void) {
|
|||||||
|
|
||||||
switch (e.window.event) {
|
switch (e.window.event) {
|
||||||
case SDL_WINDOWEVENT_RESIZED:
|
case SDL_WINDOWEVENT_RESIZED:
|
||||||
|
ctx.window_w = e.window.data1;
|
||||||
|
ctx.window_h = e.window.data2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +177,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) {
|
||||||
@ -202,13 +204,12 @@ static bool initialize(void) {
|
|||||||
/* 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 */
|
||||||
{
|
{
|
||||||
@ -298,7 +299,7 @@ static bool initialize(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* input */
|
/* input */
|
||||||
input_state_init(&ctx.input, ctx.renderer);
|
input_state_init(&ctx.input);
|
||||||
|
|
||||||
/* scripting */
|
/* scripting */
|
||||||
/*
|
/*
|
||||||
|
@ -47,11 +47,11 @@ struct mesh_batch_item {
|
|||||||
/* is structure that is in opengl vertex array */
|
/* is structure that is in opengl vertex array */
|
||||||
struct uncolored_space_triangle {
|
struct uncolored_space_triangle {
|
||||||
t_fvec3 v0;
|
t_fvec3 v0;
|
||||||
t_shvec2 uv0;
|
t_fvec2 uv0;
|
||||||
t_fvec3 v1;
|
t_fvec3 v1;
|
||||||
t_shvec2 uv1;
|
t_fvec2 uv1;
|
||||||
t_fvec3 v2;
|
t_fvec3 v2;
|
||||||
t_shvec2 uv2;
|
t_fvec2 uv2;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
41
src/private/textures.h
Normal file
41
src/private/textures.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#ifndef PRIVATE_TEXTURES_H
|
||||||
|
#define PRIVATE_TEXTURES_H
|
||||||
|
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <stb_rect_pack.h>
|
||||||
|
#include <glad/glad.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
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
|
278
src/rendering.c
278
src/rendering.c
@ -10,6 +10,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <tgmath.h>
|
#include <tgmath.h>
|
||||||
|
|
||||||
|
/* http://www.swiftless.com/opengltuts.html */
|
||||||
|
|
||||||
void render_queue_clear(void) {
|
void render_queue_clear(void) {
|
||||||
/* since i don't intend to free the queues, */
|
/* since i don't intend to free the queues, */
|
||||||
@ -108,17 +109,20 @@ void unfurl_triangle(const char *path,
|
|||||||
t_shvec2 uv2)
|
t_shvec2 uv2)
|
||||||
{
|
{
|
||||||
/* corrected atlas texture coordinates */
|
/* corrected atlas texture coordinates */
|
||||||
t_shvec2 uv0c, uv1c, uv2c;
|
t_fvec2 uv0c, uv1c, uv2c;
|
||||||
struct mesh_batch *batch_p;
|
struct mesh_batch *batch_p;
|
||||||
|
|
||||||
textures_load(&ctx.texture_cache, path);
|
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);
|
const int atlas_index = textures_get_atlas_index(&ctx.texture_cache, path);
|
||||||
if (atlas_index == -1) {
|
if (atlas_index == -1) {
|
||||||
/* loners span whole texture i assume */
|
uv0c.x = (float)uv0.x / (float)srcrect.w;
|
||||||
uv0c = uv0;
|
uv0c.y = (float)uv0.y / (float)srcrect.h;
|
||||||
uv1c = uv1;
|
uv1c.x = (float)uv1.x / (float)srcrect.w;
|
||||||
uv2c = uv2;
|
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;
|
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));
|
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 */
|
uv0c.x = xr + ((float)uv0.x / (float)srcrect.w) * wr;
|
||||||
const int16_t srcratx = (int16_t)srcrect.x * (INT16_MAX / TEXTURE_ATLAS_SIZE);
|
uv0c.y = yr + ((float)uv0.y / (float)srcrect.h) * hr;
|
||||||
const int16_t srcratw = (int16_t)srcrect.w * (INT16_MAX / TEXTURE_ATLAS_SIZE);
|
uv1c.x = xr + ((float)uv1.x / (float)srcrect.w) * wr;
|
||||||
const int16_t srcrath = (int16_t)srcrect.h * (INT16_MAX / TEXTURE_ATLAS_SIZE);
|
uv1c.y = yr + ((float)uv1.y / (float)srcrect.h) * hr;
|
||||||
const int16_t srcraty = (int16_t)srcrect.y * (INT16_MAX / TEXTURE_ATLAS_SIZE); /* flip? */
|
uv2c.x = xr + ((float)uv2.x / (float)srcrect.w) * wr;
|
||||||
|
uv2c.y = yr + ((float)uv2.y / (float)srcrect.h) * hr;
|
||||||
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));
|
|
||||||
|
|
||||||
batch_p = &ctx.uncolored_mesh_batches[atlas_index];
|
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 *data = (struct uncolored_space_triangle *)batch_p->data;
|
||||||
struct uncolored_space_triangle pack = {
|
struct uncolored_space_triangle pack = {
|
||||||
.v0 = v0,
|
.v0 = v0,
|
||||||
// .uv0 = uv0c,
|
.uv0 = uv0c,
|
||||||
.uv0 = { 0, 0 },
|
|
||||||
.v1 = v1,
|
.v1 = v1,
|
||||||
// .uv1 = uv1c,
|
.uv1 = uv1c,
|
||||||
.uv1 = { INT16_MAX, 0 },
|
|
||||||
.v2 = v2,
|
.v2 = v2,
|
||||||
// .uv2 = uv2c,
|
.uv2 = uv2c,
|
||||||
.uv2 = { INT16_MAX, INT16_MAX },
|
|
||||||
};
|
};
|
||||||
arrpush(data, pack);
|
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 */
|
/* necessary to allow the renderer to draw in batches in the best case */
|
||||||
static void sort_sprites(struct sprite_primitive *sprites) {
|
static void sort_sprites(struct sprite_primitive *sprites) {
|
||||||
size_t sprites_len = arrlenu(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) {
|
static void render_sprite(struct sprite_primitive *sprite) {
|
||||||
SDL_Rect srcrect_value = { 0 };
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
SDL_Rect *srcrect = &srcrect_value;
|
glClientActiveTexture(GL_TEXTURE0);
|
||||||
SDL_Texture *texture = NULL;
|
|
||||||
|
|
||||||
/* loner */
|
/* loner */
|
||||||
if (sprite->atlas_index == -1) {
|
if (sprite->atlas_index == -1) {
|
||||||
srcrect = NULL;
|
textures_bind_loner(&ctx.texture_cache, sprite->path, GL_TEXTURE_2D);
|
||||||
texture = textures_get_loner(&ctx.texture_cache, sprite->path);
|
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 {
|
} else {
|
||||||
*srcrect = textures_get_srcrect(&ctx.texture_cache, sprite->path);
|
SDL_Rect srcrect = textures_get_srcrect(&ctx.texture_cache, sprite->path);
|
||||||
texture = textures_get_atlas(&ctx.texture_cache, sprite->atlas_index);
|
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;
|
glColor4ub(sprite->color.r, sprite->color.g, sprite->color.b, sprite->color.a);
|
||||||
if (sprite->flip_x)
|
|
||||||
flip |= SDL_FLIP_HORIZONTAL;
|
|
||||||
if (sprite->flip_y)
|
|
||||||
flip |= SDL_FLIP_VERTICAL;
|
|
||||||
|
|
||||||
SDL_SetTextureColorMod(texture,
|
// SDL_SetTextureBlendMode(texture, sprite->blend_mode);
|
||||||
sprite->color.r,
|
|
||||||
sprite->color.g,
|
|
||||||
sprite->color.b);
|
|
||||||
SDL_SetTextureAlphaMod(texture, sprite->color.a);
|
|
||||||
SDL_SetTextureBlendMode(texture, sprite->blend_mode);
|
|
||||||
|
|
||||||
SDL_Rect rect = {
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
(int)sprite->rect.x,
|
upload_quad_vertices(sprite->rect);
|
||||||
(int)sprite->rect.y,
|
|
||||||
(int)sprite->rect.w,
|
|
||||||
(int)sprite->rect.h
|
|
||||||
};
|
|
||||||
|
|
||||||
SDL_RenderCopyEx(ctx.renderer,
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
texture,
|
|
||||||
srcrect,
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
&rect,
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
sprite->rotation,
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
NULL,
|
|
||||||
flip);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void render_rectangle(struct rect_primitive *rectangle) {
|
static void render_rectangle(struct rect_primitive *rectangle) {
|
||||||
SDL_SetRenderDrawColor(ctx.renderer,
|
glColor4ub(rectangle->color.r, rectangle->color.g,
|
||||||
rectangle->color.r,
|
rectangle->color.b, rectangle->color.a);
|
||||||
rectangle->color.g,
|
|
||||||
rectangle->color.b,
|
|
||||||
rectangle->color.a);
|
|
||||||
|
|
||||||
SDL_Rect rect = {
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
(int)rectangle->rect.x,
|
upload_quad_vertices(rectangle->rect);
|
||||||
(int)rectangle->rect.y,
|
|
||||||
(int)rectangle->rect.w,
|
|
||||||
(int)rectangle->rect.h
|
|
||||||
};
|
|
||||||
|
|
||||||
SDL_RenderFillRect(ctx.renderer, &rect);
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
SDL_SetRenderDrawColor(ctx.renderer, 255, 255, 255, 255);
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -379,11 +398,25 @@ static void render_circle(struct circle_primitive *circle) {
|
|||||||
&vertices,
|
&vertices,
|
||||||
&indices);
|
&indices);
|
||||||
|
|
||||||
SDL_RenderGeometry(ctx.renderer, NULL,
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
vertices,
|
glVertexPointer(2,
|
||||||
num_vertices + 1, /* vertices + center vertex */
|
GL_FLOAT,
|
||||||
indices,
|
sizeof (SDL_Vertex),
|
||||||
num_vertices * 3);
|
&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(vertices);
|
||||||
free(indices);
|
free(indices);
|
||||||
@ -439,19 +472,13 @@ static void draw_uncolored_space_traingle_batch(struct mesh_batch *batch) {
|
|||||||
offsetof(struct uncolored_space_triangle, v1),
|
offsetof(struct uncolored_space_triangle, v1),
|
||||||
(void *)offsetof(struct uncolored_space_triangle, v0));
|
(void *)offsetof(struct uncolored_space_triangle, v0));
|
||||||
|
|
||||||
/* note: propagates further to where texture binding is done */
|
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
glClientActiveTexture(GL_TEXTURE0);
|
glClientActiveTexture(GL_TEXTURE0);
|
||||||
glTexCoordPointer(2,
|
glTexCoordPointer(2,
|
||||||
GL_SHORT,
|
GL_FLOAT,
|
||||||
offsetof(struct uncolored_space_triangle, v1),
|
offsetof(struct uncolored_space_triangle, v1),
|
||||||
(void *)offsetof(struct uncolored_space_triangle, uv0));
|
(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 */
|
/* commit for drawing */
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 3 * (int)data_len);
|
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) {
|
static void render_space(void) {
|
||||||
glMatrixMode(GL_PROJECTION);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glPushMatrix();
|
|
||||||
glLoadIdentity();
|
|
||||||
glOrtho(0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0, -1, 1);
|
|
||||||
|
|
||||||
glUseProgramObjectARB(0);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
/* solid white, no modulation */
|
/* 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) {
|
for (size_t i = 0; i < arrlenu(ctx.uncolored_mesh_batches); ++i) {
|
||||||
if (arrlenu(&ctx.uncolored_mesh_batches[i].data) > 0) {
|
if (arrlenu(&ctx.uncolored_mesh_batches[i].data) > 0) {
|
||||||
SDL_Texture *const atlas = textures_get_atlas(&ctx.texture_cache, (int)i);
|
textures_bind_atlas(&ctx.texture_cache, (int)i, GL_TEXTURE_2D);
|
||||||
SDL_GL_BindTexture(atlas, NULL, NULL);
|
|
||||||
draw_uncolored_space_traingle_batch(&ctx.uncolored_mesh_batches[i]);
|
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) {
|
for (size_t i = 0; i < shlenu(ctx.uncolored_mesh_batches_loners); ++i) {
|
||||||
if (arrlenu(&ctx.uncolored_mesh_batches_loners[i].value.data) > 0) {
|
if (arrlenu(&ctx.uncolored_mesh_batches_loners[i].value.data) > 0) {
|
||||||
SDL_Texture *const atlas = textures_get_loner(&ctx.texture_cache,
|
textures_bind_loner(&ctx.texture_cache,
|
||||||
ctx.uncolored_mesh_batches_loners[i].key);
|
ctx.uncolored_mesh_batches_loners[i].key,
|
||||||
SDL_GL_BindTexture(atlas, NULL, NULL);
|
GL_TEXTURE_2D);
|
||||||
|
|
||||||
draw_uncolored_space_traingle_batch(&ctx.uncolored_mesh_batches_loners[i].value);
|
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)
|
if (ctx.texture_cache.is_dirty)
|
||||||
textures_update_current_atlas(&ctx.texture_cache);
|
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,
|
glClearColor((1.0f / 255) * 230,
|
||||||
(1.0f / 255) * 230,
|
(1.0f / 255) * 230,
|
||||||
(1.0f / 255) * 230, 1);
|
(1.0f / 255) * 230, 1);
|
||||||
@ -511,22 +553,42 @@ void render(void) {
|
|||||||
GL_DEPTH_BUFFER_BIT |
|
GL_DEPTH_BUFFER_BIT |
|
||||||
GL_STENCIL_BUFFER_BIT);
|
GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
// glDisable(GL_CULL_FACE);
|
{
|
||||||
// glDisable(GL_DEPTH_TEST);
|
glDisable(GL_CULL_FACE);
|
||||||
glEnable(GL_BLEND);
|
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);
|
||||||
|
|
||||||
/* TODO: write with no depth test, just fill it in */
|
glMatrixMode(GL_PROJECTION);
|
||||||
render_sprites();
|
glLoadIdentity();
|
||||||
render_rectangles();
|
glOrtho(0, RENDER_BASE_WIDTH, RENDER_BASE_HEIGHT, 0, -1, 1);
|
||||||
render_circles();
|
|
||||||
|
|
||||||
// glEnable(GL_CULL_FACE);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
// glEnable(GL_DEPTH_TEST);
|
glLoadIdentity();
|
||||||
glDisable(GL_BLEND);
|
|
||||||
|
|
||||||
/* TODO: use depth test to optimize gui regions away */
|
glEnable(GL_TEXTURE_2D);
|
||||||
render_space();
|
|
||||||
|
render_sprites();
|
||||||
|
render_rectangles();
|
||||||
|
render_circles();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
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);
|
SDL_GL_SwapWindow(ctx.window);
|
||||||
}
|
}
|
||||||
|
118
src/textures.c
118
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>
|
||||||
@ -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 */
|
/* 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,12 +76,51 @@ static void add_new_atlas(struct texture_cache *cache) {
|
|||||||
a_mask);
|
a_mask);
|
||||||
SDL_FreeFormat(native_format);
|
SDL_FreeFormat(native_format);
|
||||||
|
|
||||||
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_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! */
|
/* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -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) {
|
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);
|
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) {
|
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);
|
||||||
|
|
||||||
@ -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 */
|
/* 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_data = new_gl_texture();
|
||||||
|
upload_texture_from_surface(new_texture.loner_data, surface);
|
||||||
new_texture.atlas_index = -1;
|
new_texture.atlas_index = -1;
|
||||||
|
new_texture.srcrect = (SDL_Rect) {
|
||||||
|
.w = surface->w, .h = surface->h };
|
||||||
shput(cache->loner_hash, path, new_texture);
|
shput(cache->loner_hash, path, new_texture);
|
||||||
} else {
|
} else {
|
||||||
new_texture.atlas_index = cache->atlas_index;
|
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) {
|
SDL_Rect textures_get_srcrect(struct texture_cache *cache, const char *path) {
|
||||||
struct texture_cache_item *texture = shgetp_null(cache->hash, path);
|
int index = textures_get_atlas_index(cache, path);
|
||||||
if (texture == NULL) {
|
if (index == -1) {
|
||||||
|
return shget(cache->loner_hash, path).srcrect;
|
||||||
|
} else if (index == INT_MIN) {
|
||||||
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 (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) {
|
int textures_get_atlas_index(struct texture_cache *cache, const char *path) {
|
||||||
struct texture_cache_item *texture = shgetp_null(cache->hash, 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 */
|
/* out of bounds */
|
||||||
if (arrlen(cache->atlas_textures) < index + 1 || index < 0)
|
if (arrlen(cache->atlas_textures) < index + 1 || index < 0) {
|
||||||
return NULL;
|
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);
|
struct texture_cache_item *texture = shgetp_null(cache->loner_hash, path);
|
||||||
|
|
||||||
if (texture == NULL) {
|
if (texture == NULL) {
|
||||||
CRY("Loner texture lookup failed.",
|
CRY("Loner texture binding failed.",
|
||||||
"Tried to get texture that isn't loaded.");
|
"Tried to bind texture that isn't loaded.");
|
||||||
return NULL;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return texture->value.loner_data;
|
glBindTexture(target, texture->value.loner_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,46 +1,10 @@
|
|||||||
#ifndef TEXTURES_H
|
#ifndef TEXTURES_H
|
||||||
#define TEXTURES_H
|
#define TEXTURES_H
|
||||||
|
|
||||||
|
#include "private/textures.h"
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include <stb_rect_pack.h>
|
#include <glad/glad.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
|
|
||||||
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 */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
@ -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 */
|
/* if the texture is not found, returns INT_MIN */
|
||||||
int textures_get_atlas_index(struct texture_cache *cache, const char *path);
|
int textures_get_atlas_index(struct texture_cache *cache, const char *path);
|
||||||
|
|
||||||
/* returns a pointer to the atlas at `index` */
|
/* binds atlas texture in opengl state */
|
||||||
/* if the index is out of bounds, returns NULL. */
|
void textures_bind_atlas(struct texture_cache *cache, int index, GLenum target);
|
||||||
/* 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, const char *path);
|
void textures_bind_loner(struct texture_cache *cache, const char *path, 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(struct texture_cache *cache);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user