add texture border to atlas residents, actually make use of mipmapping
This commit is contained in:
parent
a88392b9e9
commit
d66eda1894
@ -340,7 +340,7 @@ void finish_index_builder(IndexBufferBuilder *builder) {
|
|||||||
|
|
||||||
|
|
||||||
static void load_cubemap_side(const char *path, GLenum target) {
|
static void load_cubemap_side(const char *path, GLenum target) {
|
||||||
SDL_Surface *surface = textures_load_surface(path);
|
SDL_Surface *surface = textures_load_surface(path, false);
|
||||||
/* TODO: sanity check whether all of them have same dimensions? */
|
/* TODO: sanity check whether all of them have same dimensions? */
|
||||||
glTexImage2D(target,
|
glTexImage2D(target,
|
||||||
0,
|
0,
|
||||||
@ -350,6 +350,7 @@ static void load_cubemap_side(const char *path, GLenum target) {
|
|||||||
surface->format->BytesPerPixel == 4 ? GL_RGBA : GL_RGB,
|
surface->format->BytesPerPixel == 4 ? GL_RGBA : GL_RGB,
|
||||||
GL_UNSIGNED_BYTE,
|
GL_UNSIGNED_BYTE,
|
||||||
surface->pixels);
|
surface->pixels);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
@ -147,22 +147,27 @@ GPUTexture create_gpu_texture(TextureFilter filter, bool generate_mipmaps, int c
|
|||||||
SDL_assert(width > 0 && height > 0);
|
SDL_assert(width > 0 && height > 0);
|
||||||
SDL_assert(channels > 0 && channels <= 4);
|
SDL_assert(channels > 0 && channels <= 4);
|
||||||
|
|
||||||
|
/* TODO: test whether emscripten emulates this */
|
||||||
#ifndef __EMSCRIPTEN__
|
#ifndef __EMSCRIPTEN__
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLboolean)generate_mipmaps);
|
if (generate_mipmaps) {
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLboolean)generate_mipmaps);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 3);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
(void)generate_mipmaps;
|
(void)generate_mipmaps;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (filter == TEXTURE_FILTER_NEAREAST) {
|
if (filter == TEXTURE_FILTER_NEAREAST) {
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, generate_mipmaps ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
} else if (filter == TEXTURE_FILTER_LINEAR) {
|
} else if (filter == TEXTURE_FILTER_LINEAR) {
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, generate_mipmaps ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
/* it's assumed to be default gl state, so, don't bother */
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||||
|
|
||||||
|
@ -25,4 +25,6 @@
|
|||||||
#include <stb_truetype.h>
|
#include <stb_truetype.h>
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STBI_NO_STDIO
|
||||||
|
#define STBI_NO_HDR
|
||||||
#include <stb_image.h>
|
#include <stb_image.h>
|
||||||
|
@ -95,7 +95,7 @@ static SDL_Surface *gen_missing_texture_surface(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SDL_Surface *textures_load_surface(const char *path) {
|
SDL_Surface *textures_load_surface(const char *path, bool apply_border) {
|
||||||
if (SDL_strncmp(path, "!", 1) == 0)
|
if (SDL_strncmp(path, "!", 1) == 0)
|
||||||
goto GET_MISSING_TEXTURE;
|
goto GET_MISSING_TEXTURE;
|
||||||
|
|
||||||
@ -141,11 +141,59 @@ SDL_Surface *textures_load_surface(const char *path) {
|
|||||||
if (surface == NULL)
|
if (surface == NULL)
|
||||||
goto ERR_CANNOT_CREATE_SURFACE;
|
goto ERR_CANNOT_CREATE_SURFACE;
|
||||||
|
|
||||||
|
/* TODO: investigate possibility of growing 1px border on stbi side, reducing the overhead (right now texture is held 2 times in memory) */
|
||||||
|
/* use in atlases introduces seams on filtering, add 1px padding, growing the resulting */
|
||||||
|
if (apply_border && (width < 2048 && height < 2048)) {
|
||||||
|
SDL_Surface* border = SDL_CreateRGBSurface(0,
|
||||||
|
width + TEXTURE_BORDER_REPEAT_SIZE * 2,
|
||||||
|
height + TEXTURE_BORDER_REPEAT_SIZE * 2,
|
||||||
|
channels * 8,
|
||||||
|
rmask, gmask, bmask, amask);
|
||||||
|
if (surface == NULL)
|
||||||
|
goto ERR_CANNOT_CREATE_BORDER;
|
||||||
|
|
||||||
|
/* main portion */
|
||||||
|
SDL_SoftStretch(surface,
|
||||||
|
&(SDL_Rect){ .x = 0, .y = 0, .w = width, .h = height },
|
||||||
|
border,
|
||||||
|
&(SDL_Rect){ .x = TEXTURE_BORDER_REPEAT_SIZE, .y = TEXTURE_BORDER_REPEAT_SIZE, .w = width, .h = height });
|
||||||
|
|
||||||
|
/* left border */
|
||||||
|
SDL_SoftStretch(surface,
|
||||||
|
&(SDL_Rect){ .w = 1, .h = height },
|
||||||
|
border,
|
||||||
|
&(SDL_Rect){ .y = TEXTURE_BORDER_REPEAT_SIZE, .w = TEXTURE_BORDER_REPEAT_SIZE, .h = height });
|
||||||
|
|
||||||
|
/* right border */
|
||||||
|
SDL_SoftStretch(surface,
|
||||||
|
&(SDL_Rect){ .x = width - 1, .w = 1, .h = height },
|
||||||
|
border,
|
||||||
|
&(SDL_Rect){ .y = TEXTURE_BORDER_REPEAT_SIZE, .x = width + TEXTURE_BORDER_REPEAT_SIZE, .w = TEXTURE_BORDER_REPEAT_SIZE, .h = height });
|
||||||
|
|
||||||
|
/* up border */
|
||||||
|
SDL_SoftStretch(surface,
|
||||||
|
&(SDL_Rect){ .w = width, .h = 1 },
|
||||||
|
border,
|
||||||
|
&(SDL_Rect){ .x = TEXTURE_BORDER_REPEAT_SIZE, .w = width, .h = TEXTURE_BORDER_REPEAT_SIZE });
|
||||||
|
|
||||||
|
/* bottom border */
|
||||||
|
SDL_SoftStretch(surface,
|
||||||
|
&(SDL_Rect){ .y = height - 1, .w = width, .h = 1 },
|
||||||
|
border,
|
||||||
|
&(SDL_Rect){ .x = TEXTURE_BORDER_REPEAT_SIZE, .y = height + TEXTURE_BORDER_REPEAT_SIZE, .w = width, .h = TEXTURE_BORDER_REPEAT_SIZE });
|
||||||
|
|
||||||
|
stbi_image_free(image_mem);
|
||||||
|
SDL_FreeSurface(surface);
|
||||||
|
surface = border;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
|
SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
|
||||||
SDL_SetSurfaceRLE(surface, true);
|
SDL_SetSurfaceRLE(surface, true);
|
||||||
|
|
||||||
return surface;
|
return surface;
|
||||||
|
|
||||||
|
ERR_CANNOT_CREATE_BORDER:
|
||||||
|
SDL_FreeSurface(surface);
|
||||||
ERR_CANNOT_CREATE_SURFACE:
|
ERR_CANNOT_CREATE_SURFACE:
|
||||||
stbi_image_free(image_mem);
|
stbi_image_free(image_mem);
|
||||||
|
|
||||||
@ -361,7 +409,10 @@ void textures_cache_deinit(TextureCache *cache) {
|
|||||||
|
|
||||||
/* free cache hashes */
|
/* free cache hashes */
|
||||||
for (size_t i = 0; i < shlenu(cache->hash); ++i) {
|
for (size_t i = 0; i < shlenu(cache->hash); ++i) {
|
||||||
if (missing_texture_surface == NULL || cache->hash[i].value.data->pixels != missing_texture_surface->pixels)
|
/* TODO: better to have field that stores the source of memory directly, ugh */
|
||||||
|
if (cache->hash[i].value.srcrect.w < 2048 && cache->hash[i].value.srcrect.h < 2048)
|
||||||
|
(void)0; /* do nothing, memory owned by surface */
|
||||||
|
else if (missing_texture_surface == NULL || cache->hash[i].value.data->pixels != missing_texture_surface->pixels)
|
||||||
stbi_image_free(cache->hash[i].value.data->pixels);
|
stbi_image_free(cache->hash[i].value.data->pixels);
|
||||||
else
|
else
|
||||||
SDL_free(cache->hash[i].value.data->pixels);
|
SDL_free(cache->hash[i].value.data->pixels);
|
||||||
@ -427,7 +478,7 @@ bool textures_load_workers_thread(void) {
|
|||||||
|
|
||||||
SDL_assert(texture_id != -1 && queue_index != -1);
|
SDL_assert(texture_id != -1 && queue_index != -1);
|
||||||
|
|
||||||
SDL_Surface *const surface = textures_load_surface(path);
|
SDL_Surface *const surface = textures_load_surface(path, true);
|
||||||
SDL_free(path);
|
SDL_free(path);
|
||||||
|
|
||||||
Texture const response = {
|
Texture const response = {
|
||||||
@ -594,7 +645,15 @@ int32_t textures_get_atlas_id(const TextureCache *cache, TextureKey key) {
|
|||||||
|
|
||||||
Rect textures_get_srcrect(const TextureCache *cache, TextureKey key) {
|
Rect textures_get_srcrect(const TextureCache *cache, TextureKey key) {
|
||||||
if (m_texture_key_is_valid(key)) {
|
if (m_texture_key_is_valid(key)) {
|
||||||
return cache->hash[key.id].value.srcrect;
|
Rect const srcrect = cache->hash[key.id].value.srcrect;
|
||||||
|
if (srcrect.w >= 2048 || srcrect.h >= 2048)
|
||||||
|
return srcrect;
|
||||||
|
else
|
||||||
|
/* offset to not include border*/
|
||||||
|
return (Rect){ .x = srcrect.x + TEXTURE_BORDER_REPEAT_SIZE,
|
||||||
|
.y = srcrect.y + TEXTURE_BORDER_REPEAT_SIZE,
|
||||||
|
.w = srcrect.w - TEXTURE_BORDER_REPEAT_SIZE * 2,
|
||||||
|
.h = srcrect.h - TEXTURE_BORDER_REPEAT_SIZE * 2 };
|
||||||
} else {
|
} 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.");
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#define TEXTURE_ATLAS_SIZE_DEFAULT 2048
|
#define TEXTURE_ATLAS_SIZE_DEFAULT 2048
|
||||||
#define TEXTURE_ATLAS_BIT_DEPTH 32
|
#define TEXTURE_ATLAS_BIT_DEPTH 32
|
||||||
#define TEXTURE_ATLAS_FORMAT SDL_PIXELFORMAT_RGBA32
|
#define TEXTURE_ATLAS_FORMAT SDL_PIXELFORMAT_RGBA32
|
||||||
|
#define TEXTURE_BORDER_REPEAT_SIZE 8
|
||||||
|
|
||||||
/* alpha channel information */
|
/* alpha channel information */
|
||||||
typedef enum TextureMode {
|
typedef enum TextureMode {
|
||||||
@ -98,7 +98,7 @@ void textures_reset_state(void);
|
|||||||
|
|
||||||
/* uncached low-level loading */
|
/* uncached low-level loading */
|
||||||
/* warn: surface->pixels must be freed along side the surface itself */
|
/* warn: surface->pixels must be freed along side the surface itself */
|
||||||
SDL_Surface *textures_load_surface(const char *path);
|
SDL_Surface *textures_load_surface(const char *path, bool apply_border);
|
||||||
|
|
||||||
/* note: will only take an effect after `textures_update_atlas` */
|
/* note: will only take an effect after `textures_update_atlas` */
|
||||||
bool textures_load_workers_thread(void);
|
bool textures_load_workers_thread(void);
|
||||||
|
Loading…
Reference in New Issue
Block a user