Texture API improvements
1. Selective mipmapping 2. Manual mipmap generation (actually produced better results at least for alpha-tested foliage)
This commit is contained in:
parent
a571d2d999
commit
63d641cc82
116
src/k3.c
116
src/k3.c
@ -17,6 +17,8 @@
|
||||
|
||||
#include"ssort.h"
|
||||
|
||||
#include<stb_image_resize.h>
|
||||
|
||||
#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;
|
||||
|
||||
9
src/k3.h
9
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*);
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user