diff --git a/src/k3.c b/src/k3.c index 0094029..3b60e94 100644 --- a/src/k3.c +++ b/src/k3.c @@ -17,6 +17,8 @@ #include"ssort.h" +#include + #define RAST_DIFF 0 #define RAST_NORM 1 #define RAST_DISP 2 @@ -495,6 +497,20 @@ struct k3Tex *k3TexCreate(enum k3TexType type) { return ret; } +int k3TexSetParameter(struct k3Tex *tex, enum k3TexParam param, void *value) { + switch(param) { + case k3_TEX_SET_MIPMAPPING_DISABLED: + tex->mipmapForceDisabled = *(bool*) value; + return 0; + + case k3_TEX_SET_MIPMAP_ALPHA: + tex->mipmapAlphaMode = *(int*) value; + return 0; + } + + return 1; +} + void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t width, uint16_t height, void *data) { GLenum target = tex->cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; @@ -518,22 +534,28 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid GLint internalFmt, externalFmt, intype; int linearFilter, mipmap; int compressed = 0; + int channels; + bool gamma; switch(type) { case k3_RAWCOLOR: internalFmt = GLAD_GL_ARB_texture_float ? GL_RGBA32F_ARB : GL_RGB10_A2; externalFmt = GL_RGBA; + channels = 4; intype = GL_UNSIGNED_BYTE; linearFilter = 1; - mipmap = 1; + mipmap = 0; + gamma = false; break; case k3_NORMAL: compressed = TextureCompressionEnabled; internalFmt = compressed ? TextureCompressionRGBA : GL_RGBA; externalFmt = GL_RGBA; + channels = 4; intype = GL_UNSIGNED_BYTE; linearFilter = 1; mipmap = 1; + gamma = false; break; case k3_DIFFUSE: case k3_EMISSION: @@ -542,39 +564,47 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid ? (GLAD_GL_EXT_texture_sRGB ? TextureCompressionSRGBA : TextureCompressionRGBA) : (GLAD_GL_EXT_texture_sRGB ? GL_SRGB8_ALPHA8_EXT : GL_RGBA8); externalFmt = GL_RGBA; + channels = 4; intype = GL_UNSIGNED_BYTE; linearFilter = 1; mipmap = 1; + gamma = true; break; case k3_DISPLACEMENT: case k3_ROUGHNESS: internalFmt = !k3IsCore ? GL_LUMINANCE8 : GL_RED; externalFmt = GL_RED; + channels = 1; intype = GL_UNSIGNED_BYTE; linearFilter = 1; mipmap = 1; + gamma = false; break; case k3_ALPHA: internalFmt = !k3IsCore ? GL_ALPHA8 : GL_RED; externalFmt = !k3IsCore ? GL_ALPHA : GL_RED; + channels = 1; intype = GL_UNSIGNED_BYTE; linearFilter = 1; mipmap = 1; + gamma = false; break; case k3_DEPTH: - internalFmt = GL_DEPTH_COMPONENT32F; + internalFmt = GL_DEPTH_COMPONENT24; externalFmt = GL_DEPTH_COMPONENT; intype = GL_UNSIGNED_INT; + channels = 4; if(!k3IsCore) glTexParameteri(target, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); linearFilter = 1; mipmap = 0; + gamma = false; break; default: abort(); break; } - if(!MipmappingEnabled) { + if(!MipmappingEnabled || tex->mipmapForceDisabled) { mipmap = 0; } @@ -587,10 +617,6 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } else { - if(!k3IsCore && mipmap) { - glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE); - } } if(type == k3_DEPTH) { @@ -623,23 +649,6 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid k3Log(k3_WARN, "Non-zero index passed for non-cubemap texture"); } - if(compressed && TextureOfflineCompressor) { - k3Log(k3_DEBUG, "Compressing texture..."); - - size_t len; - data = TextureOfflineCompressor(data, width, height, externalFmt, intype, &len); - - glCompressedTexImage2D(target, 0, internalFmt, width, height, 0, len, data); - - free(data); - } else { - glTexImage2D(target, 0, internalFmt, width, height, 0, externalFmt, intype, data); - } - - if(!tex->cubemap && k3IsCore && mipmap) { - glGenerateMipmap(target); - } - tex->szX = width; tex->szY = height; tex->szZ = 0; @@ -647,6 +656,65 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid tex->glInternalFormat = internalFmt; tex->glExternalFormat = externalFmt; tex->glInType = intype; + + if(data) { + char *resized = malloc(width * height * channels); + memcpy(resized, data, width * height * channels); + + size_t level; + for(level = 0;; level++) { + if(compressed && TextureOfflineCompressor) { + k3Log(k3_DEBUG, "Compressing level %i...", level); + + size_t len; + void *compressedData = TextureOfflineCompressor(data, width, height, externalFmt, intype, &len); + + glCompressedTexImage2D(target, level, internalFmt, width, height, 0, len, compressedData); + + free(compressedData); + } else { + glTexImage2D(target, level, internalFmt, width, height, 0, externalFmt, intype, data); + } + + if(!mipmap || tex->cubemap || (width <= 1 && height <= 1)) { + break; + } + + size_t resizedWidth = width >> 1; + if(resizedWidth == 0) { + resizedWidth = 1; + } + + size_t resizedHeight = height >> 1; + if(resizedHeight == 0) { + resizedHeight = 1; + } + + stbir_resize_uint8_generic(data, width, height, 0, resized, resizedWidth, resizedHeight, 0, channels, channels == 4 ? 3 : STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, gamma ? STBIR_COLORSPACE_SRGB : STBIR_COLORSPACE_LINEAR, NULL); + + data = resized; + width = resizedWidth; + height = resizedHeight; + } + + glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, level); + + free(resized); + } else { + glTexImage2D(target, 0, internalFmt, width, height, 0, externalFmt, intype, NULL); + } +} +void k3TexUpdateSub(struct k3Tex *this, int index, uint16_t x, uint16_t y, uint16_t width, uint16_t height, void *data) { + GLenum target = GL_TEXTURE_2D; + if(this->cubemap) { + target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + index; + } else if(index) { + k3Log(k3_WARN, "Non-zero index passed for non-cubemap texture"); + } + + glBindTexture(target, this->tex); + glTexSubImage2D(target, index, x, y, width, height, this->glExternalFormat, this->glInType, data); } uint32_t k3TexSzX(struct k3Tex *this) { return this->szX; diff --git a/src/k3.h b/src/k3.h index 0f425a7..e3e5216 100644 --- a/src/k3.h +++ b/src/k3.h @@ -22,9 +22,18 @@ enum k3TexType { k3_RAWCOLOR, }; +enum k3TexParam { + k3_TEX_SET_MIPMAP_ALPHA, + k3_TEX_SET_MIPMAPPING_DISABLED, +}; +#define k3_PARAM_STANDARD 0 +#define k3_PARAM_MAX_DOWNSAMPLE 1 + struct k3Tex; struct k3Tex *k3TexCreate(enum k3TexType type); +int k3TexSetParameter(struct k3Tex*, enum k3TexParam, void*); void k3TexUpdate(struct k3Tex*, enum k3TexType type, int index, uint16_t width, uint16_t height, void *data); +void k3TexUpdateSub(struct k3Tex*, int index, uint16_t x, uint16_t y, uint16_t width, uint16_t height, void *data); uint32_t k3TexSzX(struct k3Tex*); uint32_t k3TexSzY(struct k3Tex*); uint32_t k3TexSzZ(struct k3Tex*); diff --git a/src/k3_internal.h b/src/k3_internal.h index 3de6961..27d681d 100644 --- a/src/k3_internal.h +++ b/src/k3_internal.h @@ -28,10 +28,8 @@ struct k3Tex { GLuint glInType; bool mipmap; - // Asynchronous decoding - uint8_t deferredRemaining; - uint8_t *deferredData[6]; - struct k3Tex *deferredNext; + bool mipmapForceDisabled; + int mipmapAlphaMode; }; struct k3Storage { diff --git a/src/k3font.c b/src/k3font.c index 42bbb5d..3b44e28 100644 --- a/src/k3font.c +++ b/src/k3font.c @@ -48,6 +48,9 @@ int k3FontLoad(struct k3Font *this, const char *fn) { this->atlasSize = k3TexSzMax() / 4; this->atlas = k3TexCreate(k3_ALPHA); this->atlasCPU = malloc(this->atlasSize * this->atlasSize); + + k3TexSetParameter(this->atlas, k3_TEX_SET_MIPMAPPING_DISABLED, &(bool) {true}); + k3TexUpdate(this->atlas, k3_ALPHA, 0, this->atlasSize, this->atlasSize, NULL); this->fontPixelSize = this->atlasSize / 16;