rework of textures, finalization of basic opengl rendering
This commit is contained in:
136
src/textures.c
136
src/textures.c
@@ -10,7 +10,6 @@
|
||||
#include <stb_ds.h>
|
||||
#include <stb_rect_pack.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -139,7 +138,12 @@ static void recreate_current_atlas_texture(struct texture_cache *cache) {
|
||||
SDL_BlitSurface(cache->hash[i].value.data,
|
||||
NULL,
|
||||
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! */
|
||||
@@ -212,7 +216,7 @@ static bool update_rects(struct texture_cache *cache, stbrp_rect *rects, stbrp_r
|
||||
/* updates the atlas location of every rect in the cache */
|
||||
static void update_texture_rects_in_atlas(struct texture_cache *cache, stbrp_rect *rects) {
|
||||
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,
|
||||
.y = rects[i].y,
|
||||
.w = rects[i].w,
|
||||
@@ -225,7 +229,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;
|
||||
sh_new_arena(cache->hash);
|
||||
sh_new_arena(cache->loner_hash);
|
||||
|
||||
cache->node_buffer = cmalloc(sizeof *cache->node_buffer * TEXTURE_ATLAS_SIZE);
|
||||
|
||||
@@ -253,11 +256,6 @@ void textures_cache_deinit(struct texture_cache *cache) {
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -282,38 +280,38 @@ void textures_dump_atlases(struct texture_cache *cache) {
|
||||
IMG_SavePNG_RW(cache->atlas_surfaces[i], handle, true);
|
||||
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, const 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 */
|
||||
if (shgeti(cache->hash, path) >= 0 || shgeti(cache->loner_hash, path) >= 0)
|
||||
return;
|
||||
if (shgeti(cache->hash, path) >= 0)
|
||||
return (t_texture_key){0};
|
||||
|
||||
SDL_Surface *surface = image_to_surface(path);
|
||||
struct texture new_texture;
|
||||
struct texture new_texture = {0};
|
||||
new_texture.data = surface;
|
||||
|
||||
/* 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 = 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);
|
||||
new_texture.loner_texture = new_gl_texture();
|
||||
upload_texture_from_surface(new_texture.loner_texture, surface);
|
||||
new_texture.srcrect = (t_rect) { .w = surface->w, .h = surface->h };
|
||||
shput(cache->hash, path, new_texture);
|
||||
return (t_texture_key){ (int)shgeti(cache->hash, path) + 1 };
|
||||
} else {
|
||||
new_texture.atlas_index = cache->atlas_index;
|
||||
shput(cache->hash, path, new_texture);
|
||||
cache->is_dirty = true;
|
||||
return (t_texture_key){ (int)shgeti(cache->hash, path) + 1 };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 */
|
||||
stbrp_context pack_ctx; /* target info */
|
||||
stbrp_init_target(&pack_ctx,
|
||||
@@ -355,68 +353,56 @@ void textures_update_current_atlas(struct texture_cache *cache) {
|
||||
}
|
||||
|
||||
|
||||
SDL_Rect textures_get_srcrect(struct texture_cache *cache, const char *path) {
|
||||
int index = textures_get_atlas_index(cache, path);
|
||||
if (index == -1) {
|
||||
return shget(cache->loner_hash, path).srcrect;
|
||||
} else if (index == INT_MIN) {
|
||||
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 */
|
||||
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){ (int)texture + 1 };
|
||||
}
|
||||
|
||||
|
||||
t_rect textures_get_srcrect(const struct texture_cache *cache, t_texture_key key) {
|
||||
if (key.id != 0) {
|
||||
return cache->hash[key.id - 1].value.srcrect;
|
||||
} else {
|
||||
CRY("Texture lookup failed.",
|
||||
"Tried to get texture that isn't loaded.");
|
||||
return (SDL_Rect){ 0, 0, 0, 0 };
|
||||
return (t_rect){ 0, 0, 0, 0 };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
t_rect textures_get_dims(const struct texture_cache *cache, t_texture_key key) {
|
||||
if (key.id != 0) {
|
||||
if (cache->hash[key.id - 1].value.loner_texture != 0)
|
||||
return cache->hash[key.id - 1].value.srcrect;
|
||||
else
|
||||
return (t_rect){ .w = TEXTURE_ATLAS_SIZE, .h = TEXTURE_ATLAS_SIZE };
|
||||
} else {
|
||||
return shget(cache->hash, path).srcrect;
|
||||
CRY("Texture lookup failed.",
|
||||
"Tried to get texture that isn't loaded.");
|
||||
return (t_rect){ 0, 0, 0, 0 };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
void textures_bind(const struct texture_cache *cache, t_texture_key key, GLenum target) {
|
||||
if (key.id != 0) {
|
||||
if (cache->hash[key.id - 1].value.loner_texture == 0)
|
||||
glBindTexture(target, cache->atlas_textures[cache->hash[key.id - 1].value.atlas_index]);
|
||||
else
|
||||
glBindTexture(target, cache->hash[key.id - 1].value.loner_texture);
|
||||
} else if (key.id == 0) {
|
||||
CRY("Texture binding failed.",
|
||||
"Tried to get texture that isn't loaded.");
|
||||
}
|
||||
|
||||
return texture->value.atlas_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) {
|
||||
CRY("Atlas texture binding failed.",
|
||||
"Tried to bind texture by invalid index");
|
||||
return;
|
||||
}
|
||||
|
||||
glBindTexture(target, cache->atlas_textures[index]);
|
||||
}
|
||||
|
||||
|
||||
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 binding failed.",
|
||||
"Tried to bind texture that isn't loaded.");
|
||||
return;
|
||||
}
|
||||
|
||||
glBindTexture(target, texture->value.loner_data);
|
||||
}
|
||||
|
||||
|
||||
size_t textures_get_num_atlases(struct texture_cache *cache) {
|
||||
size_t textures_get_num_atlases(const struct texture_cache *cache) {
|
||||
return cache->atlas_index + 1;
|
||||
}
|
||||
|
Reference in New Issue
Block a user