Make textures immutable and fix font atlas resizing;

This commit is contained in:
bjorn 2017-11-24 14:13:07 -08:00
parent ef0ba9124d
commit eecc675043
6 changed files with 75 additions and 86 deletions

View File

@ -46,12 +46,8 @@ Font* lovrFontCreate(FontData* fontData) {
lovrFontExpandTexture(font);
}
// Texture
TextureData* textureData = lovrTextureDataGetBlank(font->atlas.width, font->atlas.height, 0x0, FORMAT_RGB);
TextureFilter filter = { .mode = FILTER_BILINEAR };
font->texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, false);
lovrTextureSetFilter(font->texture, filter);
lovrTextureSetWrap(font->texture, (TextureWrap) { .s = WRAP_CLAMP, .t = WRAP_CLAMP });
// Create the texture
lovrFontCreateTexture(font);
return font;
}
@ -298,9 +294,8 @@ void lovrFontExpandTexture(Font* font) {
return;
}
// Resize the texture storage
lovrTextureDataResize(font->texture->slices[0], atlas->width, atlas->height, 0x0);
lovrTextureRefresh(font->texture);
// Recreate the texture
lovrFontCreateTexture(font);
// Reset the cursor
atlas->x = atlas->padding;
@ -315,3 +310,15 @@ void lovrFontExpandTexture(Font* font) {
lovrFontAddGlyph(font, glyph);
}
}
void lovrFontCreateTexture(Font* font) {
if (font->texture) {
lovrRelease(&font->texture->ref);
}
TextureData* textureData = lovrTextureDataGetBlank(font->atlas.width, font->atlas.height, 0x0, FORMAT_RGB);
TextureFilter filter = { .mode = FILTER_BILINEAR };
font->texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, false);
lovrTextureSetFilter(font->texture, filter);
lovrTextureSetWrap(font->texture, (TextureWrap) { .s = WRAP_CLAMP, .t = WRAP_CLAMP });
}

View File

@ -56,3 +56,4 @@ void lovrFontSetPixelDensity(Font* font, float pixelDensity);
Glyph* lovrFontGetGlyph(Font* font, uint32_t codepoint);
void lovrFontAddGlyph(Font* font, Glyph* glyph);
void lovrFontExpandTexture(Font* font);
void lovrFontCreateTexture(Font* font);

View File

@ -5,36 +5,70 @@
#include <stdlib.h>
#include <stdio.h>
static void lovrTextureCreateStorage(Texture* texture) {
static void lovrTextureUpload(Texture* texture) {
TextureData* textureData = texture->slices[0];
texture->width = textureData->width;
texture->height = textureData->height;
if (textureData->format.compressed || texture->type == TEXTURE_CUBE) {
return;
}
int w = textureData->width;
int h = textureData->height;
int mipmapCount = log2(MAX(w, h)) + 1;
GLenum internalFormat;
if (lovrGraphicsIsGammaCorrect() && texture->srgb) {
internalFormat = textureData->format.glInternalFormat.srgb;
} else {
internalFormat = textureData->format.glInternalFormat.linear;
}
GLenum format = textureData->format.glFormat;
// Allocate storage
if (!textureData->format.compressed && texture->type != TEXTURE_CUBE) {
int w = textureData->width;
int h = textureData->height;
int mipmapCount = log2(MAX(w, h)) + 1;
GLenum internalFormat;
if (lovrGraphicsIsGammaCorrect() && texture->srgb) {
internalFormat = textureData->format.glInternalFormat.srgb;
} else {
internalFormat = textureData->format.glInternalFormat.linear;
}
GLenum format = textureData->format.glFormat;
#ifndef EMSCRIPTEN
if (GLAD_GL_ARB_texture_storage) {
if (GLAD_GL_ARB_texture_storage) {
#endif
glTexStorage2D(GL_TEXTURE_2D, mipmapCount, internalFormat, w, h);
glTexStorage2D(GL_TEXTURE_2D, mipmapCount, internalFormat, w, h);
#ifndef EMSCRIPTEN
} else {
for (int i = 0; i < mipmapCount; i++) {
glTexImage2D(GL_TEXTURE_2D, i, internalFormat, w, h, 0, format, GL_UNSIGNED_BYTE, NULL);
w = MAX(w >> 1, 1);
h = MAX(h >> 1, 1);
} else {
for (int i = 0; i < mipmapCount; i++) {
glTexImage2D(GL_TEXTURE_2D, i, internalFormat, w, h, 0, format, GL_UNSIGNED_BYTE, NULL);
w = MAX(w >> 1, 1);
h = MAX(h >> 1, 1);
}
}
#endif
}
// Upload data
for (int i = 0; i < texture->sliceCount; i++) {
TextureData* textureData = texture->slices[i];
GLenum glInternalFormat;
if (lovrGraphicsIsGammaCorrect() && texture->srgb) {
glInternalFormat = textureData->format.glInternalFormat.srgb;
} else {
glInternalFormat = textureData->format.glInternalFormat.linear;
}
GLenum glFormat = textureData->format.glFormat;
GLenum binding = (texture->type == TEXTURE_CUBE) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + i : GL_TEXTURE_2D;
if (textureData->format.compressed) {
Mipmap m; int i;
vec_foreach(&textureData->mipmaps.list, m, i) {
glCompressedTexImage2D(binding, i, glInternalFormat, m.width, m.height, 0, m.size, m.data);
}
} else {
int w = textureData->width;
int h = textureData->height;
if (texture->type == TEXTURE_CUBE) {
glTexImage2D(binding, 0, glInternalFormat, w, h, 0, glFormat, GL_UNSIGNED_BYTE, textureData->data);
} else if (textureData->data) {
glTexSubImage2D(binding, 0, 0, 0, w, h, glFormat, GL_UNSIGNED_BYTE, textureData->data);
}
if (textureData->mipmaps.generated) {
glGenerateMipmap(texture->type);
}
}
}
#endif
}
static void validateSlices(TextureType type, TextureData* slices[6], int sliceCount) {
@ -67,8 +101,7 @@ Texture* lovrTextureCreate(TextureType type, TextureData* slices[6], int sliceCo
texture->srgb = srgb;
glGenTextures(1, &texture->id);
lovrGraphicsBindTexture(texture, type, 0);
lovrTextureCreateStorage(texture);
lovrTextureRefresh(texture);
lovrTextureUpload(texture);
lovrTextureSetFilter(texture, lovrGraphicsGetDefaultFilter());
WrapMode wrapMode = (type == TEXTURE_CUBE) ? WRAP_CLAMP : WRAP_REPEAT;
lovrTextureSetWrap(texture, (TextureWrap) { .s = wrapMode, .t = wrapMode, .r = wrapMode });
@ -179,44 +212,6 @@ void lovrTextureResolveMSAA(Texture* texture) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
void lovrTextureRefresh(Texture* texture) {
lovrGraphicsBindTexture(texture, texture->type, 0);
validateSlices(texture->type, texture->slices, texture->sliceCount);
texture->width = texture->slices[0]->width;
texture->height = texture->slices[0]->height;
for (int i = 0; i < texture->sliceCount; i++) {
TextureData* textureData = texture->slices[i];
GLenum glInternalFormat;
if (lovrGraphicsIsGammaCorrect() && texture->srgb) {
glInternalFormat = textureData->format.glInternalFormat.srgb;
} else {
glInternalFormat = textureData->format.glInternalFormat.linear;
}
GLenum glFormat = textureData->format.glFormat;
GLenum binding = (texture->type == TEXTURE_CUBE) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + i : GL_TEXTURE_2D;
if (textureData->format.compressed) {
Mipmap m; int i;
vec_foreach(&textureData->mipmaps.list, m, i) {
glCompressedTexImage2D(binding, i, glInternalFormat, m.width, m.height, 0, m.size, m.data);
}
} else {
int w = textureData->width;
int h = textureData->height;
if (textureData->data) {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, glFormat, GL_UNSIGNED_BYTE, textureData->data);
}
if (textureData->mipmaps.generated) {
glGenerateMipmap(GL_TEXTURE_2D); // TODO
}
}
}
}
TextureFilter lovrTextureGetFilter(Texture* texture) {
return texture->filter;
}

View File

@ -64,7 +64,6 @@ Texture* lovrTextureCreateWithFramebuffer(TextureData* textureData, TextureProje
void lovrTextureDestroy(const Ref* ref);
void lovrTextureBindFramebuffer(Texture* texture);
void lovrTextureResolveMSAA(Texture* texture);
void lovrTextureRefresh(Texture* texture);
TextureFilter lovrTextureGetFilter(Texture* texture);
void lovrTextureSetFilter(Texture* texture, TextureFilter filter);
TextureWrap lovrTextureGetWrap(Texture* texture);

View File

@ -192,18 +192,6 @@ TextureData* lovrTextureDataFromBlob(Blob* blob) {
return textureData;
}
void lovrTextureDataResize(TextureData* textureData, int width, int height, uint8_t value) {
if (textureData->format.compressed || textureData->mipmaps.generated) {
lovrThrow("Can't resize a compressed texture or a texture with generated mipmaps.");
}
int size = width * height * textureData->format.blockBytes;
textureData->width = width;
textureData->height = height;
textureData->data = realloc(textureData->data, size);
memset(textureData->data, value, size);
}
void lovrTextureDataDestroy(TextureData* textureData) {
if (textureData->blob) {
lovrRelease(&textureData->blob->ref);

View File

@ -49,5 +49,4 @@ typedef struct {
TextureData* lovrTextureDataGetBlank(int width, int height, uint8_t value, TextureFormat format);
TextureData* lovrTextureDataGetEmpty(int width, int height, TextureFormat format);
TextureData* lovrTextureDataFromBlob(Blob* blob);
void lovrTextureDataResize(TextureData* textureData, int width, int height, uint8_t value);
void lovrTextureDataDestroy(TextureData* textureData);