Add support for 2d array textures; Improve mipmaps;

lovr.graphics.newTexture has been changed.
This commit is contained in:
bjorn 2018-02-20 17:15:00 -08:00
parent 5493a980ff
commit f75530b9e1
13 changed files with 145 additions and 128 deletions

View File

@ -86,6 +86,7 @@ extern map_int_t MeshUsages;
extern map_int_t PolygonWindings; extern map_int_t PolygonWindings;
extern map_int_t ShapeTypes; extern map_int_t ShapeTypes;
extern map_int_t TextureFormats; extern map_int_t TextureFormats;
extern map_int_t TextureTypes;
extern map_int_t TimeUnits; extern map_int_t TimeUnits;
extern map_int_t VerticalAligns; extern map_int_t VerticalAligns;
extern map_int_t WrapModes; extern map_int_t WrapModes;

View File

@ -29,6 +29,7 @@ map_int_t MeshDrawModes;
map_int_t MeshUsages; map_int_t MeshUsages;
map_int_t StencilActions; map_int_t StencilActions;
map_int_t TextureFormats; map_int_t TextureFormats;
map_int_t TextureTypes;
map_int_t VerticalAligns; map_int_t VerticalAligns;
map_int_t Windings; map_int_t Windings;
map_int_t WrapModes; map_int_t WrapModes;
@ -204,6 +205,11 @@ int l_lovrGraphicsInit(lua_State* L) {
map_set(&TextureFormats, "dxt3", FORMAT_DXT3); map_set(&TextureFormats, "dxt3", FORMAT_DXT3);
map_set(&TextureFormats, "dxt5", FORMAT_DXT5); map_set(&TextureFormats, "dxt5", FORMAT_DXT5);
map_init(&TextureTypes);
map_set(&TextureTypes, "2d", TEXTURE_2D);
map_set(&TextureTypes, "array", TEXTURE_ARRAY);
map_set(&TextureTypes, "cube", TEXTURE_CUBE);
map_init(&VerticalAligns); map_init(&VerticalAligns);
map_set(&VerticalAligns, "top", ALIGN_TOP); map_set(&VerticalAligns, "top", ALIGN_TOP);
map_set(&VerticalAligns, "bottom", ALIGN_BOTTOM); map_set(&VerticalAligns, "bottom", ALIGN_BOTTOM);
@ -918,7 +924,7 @@ int l_lovrGraphicsNewMaterial(lua_State* L) {
Blob* blob = luax_readblob(L, index++, "Texture"); Blob* blob = luax_readblob(L, index++, "Texture");
TextureData* textureData = lovrTextureDataFromBlob(blob); TextureData* textureData = lovrTextureDataFromBlob(blob);
lovrRelease(&blob->ref); lovrRelease(&blob->ref);
Texture* texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, true); Texture* texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, true, true);
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture); lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture);
lovrRelease(&texture->ref); lovrRelease(&texture->ref);
} else if (lua_isuserdata(L, index)) { } else if (lua_isuserdata(L, index)) {
@ -1020,7 +1026,7 @@ int l_lovrGraphicsNewModel(lua_State* L) {
if (lua_type(L, 2) == LUA_TSTRING) { if (lua_type(L, 2) == LUA_TSTRING) {
Blob* blob = luax_readblob(L, 2, "Texture"); Blob* blob = luax_readblob(L, 2, "Texture");
TextureData* textureData = lovrTextureDataFromBlob(blob); TextureData* textureData = lovrTextureDataFromBlob(blob);
Texture* texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, true); Texture* texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, true, true);
Material* material = lovrMaterialCreate(false); Material* material = lovrMaterialCreate(false);
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture); lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture);
lovrModelSetMaterial(model, material); lovrModelSetMaterial(model, material);
@ -1061,34 +1067,57 @@ int l_lovrGraphicsNewShader(lua_State* L) {
} }
int l_lovrGraphicsNewTexture(lua_State* L) { int l_lovrGraphicsNewTexture(lua_State* L) {
int top = lua_gettop(L);
bool isTable = lua_istable(L, 1); bool isTable = lua_istable(L, 1);
bool hasFlags = isTable ? lua_istable(L, 2) : lua_istable(L, top);
int count = isTable ? lua_objlen(L, 1) : (top - (hasFlags ? 1 : 0));
lovrAssert(count == 1 || count == 6, "Expected 1 image for a 2d texture or 6 images for a cubemap, got %d", count);
TextureData* slices[6]; if (!isTable) {
if (isTable) { lua_newtable(L);
for (int i = 0; i < count; i++) { lua_pushvalue(L, 1);
lua_rawgeti(L, 1, i + 1); lua_rawseti(L, -2, 1);
slices[i] = luax_checktexturedata(L, -1); lua_replace(L, 1);
lua_pop(L, 1);
}
} else {
for (int i = 0; i < count; i++) {
slices[i] = luax_checktexturedata(L, i + 1);
}
} }
int sliceCount = lua_objlen(L, 1);
TextureType type = isTable ? (sliceCount > 0 ? TEXTURE_ARRAY : TEXTURE_CUBE) : TEXTURE_2D;
bool hasFlags = lua_istable(L, 2);
bool srgb = true; bool srgb = true;
bool mipmaps = true;
if (hasFlags) { if (hasFlags) {
lua_getfield(L, top, "linear"); lua_getfield(L, 2, "linear");
srgb = !lua_toboolean(L, -1); srgb = !lua_toboolean(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 2, "mipmaps");
mipmaps = lua_toboolean(L, -1);
lua_pop(L, 1);
lua_getfield(L, 2, "type");
if (!lua_isnil(L, -1)) {
type = *(TextureType*) luax_checkenum(L, -1, &TextureTypes, "texture type");
}
lua_pop(L, 1);
}
if (type == TEXTURE_CUBE && sliceCount == 0) {
sliceCount = 6;
const char* faces[6] = { "left", "right", "top", "bottom", "front", "back" };
for (int i = 0; i < 6; i++) {
lua_pushstring(L, faces[i]);
lua_rawget(L, 1);
lua_rawseti(L, 1, i + 1);
}
}
Texture* texture = lovrTextureCreate(type, NULL, sliceCount, srgb, mipmaps);
for (int i = 0; i < sliceCount; i++) {
lua_rawgeti(L, 1, i + 1);
TextureData* textureData = luax_checktexturedata(L, -1);
lovrTextureReplacePixels(texture, textureData, i);
lua_pop(L, 1);
} }
TextureType type = (count == 1) ? TEXTURE_2D : TEXTURE_CUBE;
Texture* texture = lovrTextureCreate(type, slices, count, srgb);
luax_pushtype(L, Texture, texture); luax_pushtype(L, Texture, texture);
lovrRelease(&texture->ref); lovrRelease(&texture->ref);
return 1; return 1;

View File

@ -136,7 +136,6 @@ TextureData* lovrTextureDataGetBlank(int width, int height, uint8_t value, Textu
textureData->data = memset(malloc(size), value, size); textureData->data = memset(malloc(size), value, size);
textureData->blob = NULL; textureData->blob = NULL;
vec_init(&textureData->mipmaps); vec_init(&textureData->mipmaps);
textureData->generateMipmaps = false;
return textureData; return textureData;
} }
@ -151,7 +150,6 @@ TextureData* lovrTextureDataGetEmpty(int width, int height, TextureFormat format
textureData->data = NULL; textureData->data = NULL;
textureData->blob = NULL; textureData->blob = NULL;
vec_init(&textureData->mipmaps); vec_init(&textureData->mipmaps);
textureData->generateMipmaps = false;
return textureData; return textureData;
} }
@ -171,7 +169,6 @@ TextureData* lovrTextureDataFromBlob(Blob* blob) {
textureData->format = FORMAT_RGBA; textureData->format = FORMAT_RGBA;
textureData->data = stbi_load_from_memory(blob->data, blob->size, &textureData->width, &textureData->height, NULL, 4); textureData->data = stbi_load_from_memory(blob->data, blob->size, &textureData->width, &textureData->height, NULL, 4);
textureData->blob = NULL; textureData->blob = NULL;
textureData->generateMipmaps = true;
if (!textureData->data) { if (!textureData->data) {
lovrThrow("Could not load texture data from '%s'", blob->name); lovrThrow("Could not load texture data from '%s'", blob->name);

View File

@ -40,7 +40,6 @@ typedef struct {
void* data; void* data;
Blob* blob; Blob* blob;
TextureFormat format; TextureFormat format;
bool generateMipmaps;
vec_mipmap_t mipmaps; vec_mipmap_t mipmaps;
} TextureData; } TextureData;

View File

@ -21,7 +21,7 @@ bool lovrCanvasSupportsFormat(TextureFormat format) {
Canvas* lovrCanvasCreate(int width, int height, TextureFormat format, int msaa, bool depth, bool stencil) { Canvas* lovrCanvasCreate(int width, int height, TextureFormat format, int msaa, bool depth, bool stencil) {
TextureData* textureData = lovrTextureDataGetEmpty(width, height, format); TextureData* textureData = lovrTextureDataGetEmpty(width, height, format);
Texture* texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, true); Texture* texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, true, true);
if (!texture) return NULL; if (!texture) return NULL;
Canvas* canvas = lovrAlloc(sizeof(Canvas), lovrCanvasDestroy); Canvas* canvas = lovrAlloc(sizeof(Canvas), lovrCanvasDestroy);

View File

@ -324,7 +324,7 @@ void lovrFontCreateTexture(Font* font) {
TextureData* textureData = lovrTextureDataGetBlank(font->atlas.width, font->atlas.height, 0x0, FORMAT_RGB); TextureData* textureData = lovrTextureDataGetBlank(font->atlas.width, font->atlas.height, 0x0, FORMAT_RGB);
TextureFilter filter = { .mode = FILTER_BILINEAR }; TextureFilter filter = { .mode = FILTER_BILINEAR };
font->texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, false); font->texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, false, false);
lovrTextureSetFilter(font->texture, filter); lovrTextureSetFilter(font->texture, filter);
lovrTextureSetWrap(font->texture, (TextureWrap) { .s = WRAP_CLAMP, .t = WRAP_CLAMP }); lovrTextureSetWrap(font->texture, (TextureWrap) { .s = WRAP_CLAMP, .t = WRAP_CLAMP });
} }

View File

@ -1136,6 +1136,8 @@ void lovrGraphicsSkybox(Texture* texture, float angle, float ax, float ay, float
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture); lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture);
lovrGraphicsSphere(material, NULL, 30); lovrGraphicsSphere(material, NULL, 30);
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, NULL); lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, NULL);
} else {
lovrThrow("lovr.graphics.skybox only accepts 2d and cube Textures");
} }
lovrGraphicsSetDepthTest(mode, write); lovrGraphicsSetDepthTest(mode, write);
@ -1234,7 +1236,7 @@ void lovrGraphicsBindTexture(Texture* texture, TextureType type, int slot) {
if (!texture) { if (!texture) {
if (!state.defaultTexture) { if (!state.defaultTexture) {
TextureData* textureData = lovrTextureDataGetBlank(1, 1, 0xff, FORMAT_RGBA); TextureData* textureData = lovrTextureDataGetBlank(1, 1, 0xff, FORMAT_RGBA);
state.defaultTexture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, true); state.defaultTexture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, true, false);
} }
texture = state.defaultTexture; texture = state.defaultTexture;

View File

@ -70,7 +70,7 @@ Model* lovrModelCreate(ModelData* modelData) {
model->textures = malloc(modelData->textures.length * sizeof(Texture*)); model->textures = malloc(modelData->textures.length * sizeof(Texture*));
for (int i = 0; i < modelData->textures.length; i++) { for (int i = 0; i < modelData->textures.length; i++) {
if (modelData->textures.data[i]) { if (modelData->textures.data[i]) {
model->textures[i] = lovrTextureCreate(TEXTURE_2D, (TextureData**) &modelData->textures.data[i], 1, true); model->textures[i] = lovrTextureCreate(TEXTURE_2D, (TextureData**) &modelData->textures.data[i], 1, true, true);
} else { } else {
model->textures[i] = NULL; model->textures[i] = NULL;
} }

View File

@ -26,6 +26,7 @@ static UniformType getUniformType(GLenum type, const char* debug) {
case GL_SAMPLER_2D: case GL_SAMPLER_2D:
case GL_SAMPLER_CUBE: case GL_SAMPLER_CUBE:
case GL_SAMPLER_2D_ARRAY:
return UNIFORM_SAMPLER; return UNIFORM_SAMPLER;
default: default:
@ -40,6 +41,7 @@ static int getUniformComponents(GLenum type) {
case GL_INT: case GL_INT:
case GL_SAMPLER_2D: case GL_SAMPLER_2D:
case GL_SAMPLER_CUBE: case GL_SAMPLER_CUBE:
case GL_SAMPLER_2D_ARRAY:
return 1; return 1;
case GL_FLOAT_VEC2: case GL_FLOAT_VEC2:
@ -303,7 +305,12 @@ void lovrShaderBind(Shader* shader) {
case UNIFORM_SAMPLER: case UNIFORM_SAMPLER:
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
TextureType type = uniform->glType == GL_SAMPLER_2D ? TEXTURE_2D : TEXTURE_CUBE; TextureType type;
switch (uniform->glType) {
case GL_SAMPLER_2D: type = TEXTURE_2D; break;
case GL_SAMPLER_CUBE: type = TEXTURE_CUBE; break;
case GL_SAMPLER_2D_ARRAY: type = TEXTURE_ARRAY; break;
}
lovrGraphicsBindTexture(uniform->value.textures[i], type, uniform->baseTextureSlot + i); lovrGraphicsBindTexture(uniform->value.textures[i], type, uniform->baseTextureSlot + i);
} }
break; break;

View File

@ -31,113 +31,66 @@ GLenum lovrTextureFormatGetGLInternalFormat(TextureFormat format, bool srgb) {
} }
bool lovrTextureFormatIsCompressed(TextureFormat format) { bool lovrTextureFormatIsCompressed(TextureFormat format) {
switch (format) { return format == FORMAT_DXT1 || format == FORMAT_DXT3 || format == FORMAT_DXT5;
case FORMAT_DXT1:
case FORMAT_DXT3:
case FORMAT_DXT5:
return true;
default:
return false;
}
} }
static void lovrTextureUpload(Texture* texture) { static void lovrTextureAllocate(Texture* texture, TextureData* textureData) {
TextureData* textureData = texture->slices[0]; texture->allocated = true;
texture->width = textureData->width; texture->width = textureData->width;
texture->height = textureData->height; texture->height = textureData->height;
if (lovrTextureFormatIsCompressed(textureData->format)) {
return;
}
int w = textureData->width;
int h = textureData->height;
int mipmapCount = log2(MAX(w, h)) + 1;
bool srgb = lovrGraphicsIsGammaCorrect() && texture->srgb; bool srgb = lovrGraphicsIsGammaCorrect() && texture->srgb;
GLenum glFormat = lovrTextureFormatGetGLFormat(textureData->format);
// Allocate storage GLenum internalFormat = lovrTextureFormatGetGLInternalFormat(textureData->format, srgb);
if (!lovrTextureFormatIsCompressed(textureData->format) && texture->type != TEXTURE_CUBE) {
int w = textureData->width;
int h = textureData->height;
int mipmapCount = log2(MAX(w, h)) + 1;
GLenum glFormat = lovrTextureFormatGetGLFormat(textureData->format);
GLenum internalFormat = lovrTextureFormatGetGLInternalFormat(textureData->format, srgb);
#ifndef EMSCRIPTEN #ifndef EMSCRIPTEN
if (GLAD_GL_ARB_texture_storage) { if (GLAD_GL_ARB_texture_storage) {
#endif #endif
glTexStorage2D(GL_TEXTURE_2D, mipmapCount, internalFormat, w, h); glTexStorage2D(texture->type, mipmapCount, internalFormat, w, h);
#ifndef EMSCRIPTEN #ifndef EMSCRIPTEN
} else {
for (int i = 0; i < mipmapCount; i++) {
glTexImage2D(GL_TEXTURE_2D, i, internalFormat, w, h, 0, glFormat, 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 glFormat = lovrTextureFormatGetGLFormat(textureData->format);
GLenum glInternalFormat = lovrTextureFormatGetGLInternalFormat(textureData->format, srgb);
GLenum binding = (texture->type == TEXTURE_CUBE) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + i : GL_TEXTURE_2D;
if (lovrTextureFormatIsCompressed(textureData->format)) {
Mipmap m; int i;
vec_foreach(&textureData->mipmaps, 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->generateMipmaps) {
glGenerateMipmap(texture->type);
}
}
}
}
static void validateSlices(TextureType type, TextureData* slices[6], int sliceCount) {
lovrAssert(sliceCount > 0, "At least one layer must be provided to create a texture");
int maxSize = lovrGraphicsGetLimits().textureSize;
int width = slices[0]->width;
int height = slices[0]->height;
bool oversized = width > maxSize || height > maxSize;
lovrAssert(!oversized, "Texture is too big, max size is %d x %d", maxSize, maxSize);
if (type == TEXTURE_CUBE) {
lovrAssert(sliceCount == 6, "Cube textures must have 6 images");
lovrAssert(width == height, "Cube textures must be square");
for (int i = 1; i < sliceCount; i++) {
int hasSameDimensions = slices[i]->width == width && slices[i]->height == height;
lovrAssert(hasSameDimensions, "All textures in a cube texture must have the same dimensions");
}
} else if (type == TEXTURE_2D) {
lovrAssert(sliceCount == 1, "2D textures can only contain a single image");
} else { } else {
lovrThrow("Unknown texture type"); for (int i = 0; i < mipmapCount; i++) {
if (texture->type == TEXTURE_CUBE) {
for (int face = 0; face < 6; face++) {
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, i, internalFormat, w, h, 0, glFormat, GL_UNSIGNED_BYTE, NULL);
}
} else {
glTexImage2D(texture->type, i, internalFormat, w, h, 0, glFormat, GL_UNSIGNED_BYTE, NULL);
}
w = MAX(w >> 1, 1);
h = MAX(h >> 1, 1);
}
} }
#endif
} }
Texture* lovrTextureCreate(TextureType type, TextureData* slices[6], int sliceCount, bool srgb) { Texture* lovrTextureCreate(TextureType type, TextureData** slices, int sliceCount, bool srgb, bool mipmaps) {
Texture* texture = lovrAlloc(sizeof(Texture), lovrTextureDestroy); Texture* texture = lovrAlloc(sizeof(Texture), lovrTextureDestroy);
if (!texture) return NULL; if (!texture) return NULL;
texture->type = type; texture->type = type;
validateSlices(type, slices, sliceCount); texture->slices = calloc(sliceCount, sizeof(TextureData**));
texture->sliceCount = sliceCount; texture->sliceCount = sliceCount;
memcpy(texture->slices, slices, sliceCount * sizeof(TextureData*));
texture->srgb = srgb; texture->srgb = srgb;
glGenTextures(1, &texture->id); texture->mipmaps = mipmaps;
lovrGraphicsBindTexture(texture, type, 0); texture->allocated = false;
lovrTextureUpload(texture);
lovrTextureSetFilter(texture, lovrGraphicsGetDefaultFilter());
WrapMode wrapMode = (type == TEXTURE_CUBE) ? WRAP_CLAMP : WRAP_REPEAT;
lovrTextureSetWrap(texture, (TextureWrap) { .s = wrapMode, .t = wrapMode, .r = wrapMode });
for (int i = 0; i < sliceCount; i++) { WrapMode wrap = type == TEXTURE_CUBE ? WRAP_CLAMP : WRAP_REPEAT;
lovrRetain(&slices[i]->ref); glGenTextures(1, &texture->id);
lovrGraphicsBindTexture(texture, texture->type, 0);
lovrTextureSetFilter(texture, lovrGraphicsGetDefaultFilter());
lovrTextureSetWrap(texture, (TextureWrap) { .s = wrap, .t = wrap, .r = wrap });
if (slices) {
for (int i = 0; i < sliceCount; i++) {
lovrTextureReplacePixels(texture, slices[i], i);
}
} }
return texture; return texture;
@ -146,17 +99,44 @@ Texture* lovrTextureCreate(TextureType type, TextureData* slices[6], int sliceCo
void lovrTextureDestroy(const Ref* ref) { void lovrTextureDestroy(const Ref* ref) {
Texture* texture = containerof(ref, Texture); Texture* texture = containerof(ref, Texture);
for (int i = 0; i < texture->sliceCount; i++) { for (int i = 0; i < texture->sliceCount; i++) {
lovrRelease(&texture->slices[i]->ref); if (&texture->slices[i]) {
lovrRelease(&texture->slices[i]->ref);
}
} }
glDeleteTextures(1, &texture->id); glDeleteTextures(1, &texture->id);
free(texture->slices);
free(texture); free(texture);
} }
void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, int slice) { void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, int slice) {
lovrAssert(slice >= 0 && slice < texture->sliceCount, "Invalid texture slice to replace: %d", slice); lovrRetain(&textureData->ref);
lovrAssert(textureData->width == texture->width && textureData->height == texture->height, "Texture dimensions must match"); if (texture->slices[slice]) {
lovrAssert(textureData->format == texture->slices[0]->format, "Texture formats must match"); lovrRelease(&texture->slices[slice]->ref);
lovrTextureUpload(texture); }
texture->slices[slice] = textureData;
if (!texture->allocated) {
lovrTextureAllocate(texture, textureData);
} else {
// validation
}
GLenum glFormat = lovrTextureFormatGetGLFormat(textureData->format);
GLenum glInternalFormat = lovrTextureFormatGetGLInternalFormat(textureData->format, texture->srgb);
GLenum binding = (texture->type == TEXTURE_CUBE) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice : texture->type;
if (lovrTextureFormatIsCompressed(textureData->format)) {
Mipmap m; int i;
vec_foreach(&textureData->mipmaps, m, i) {
glCompressedTexImage2D(binding, i, glInternalFormat, m.width, m.height, 0, m.size, m.data);
}
} else {
glTexSubImage2D(binding, 0, 0, 0, textureData->width, textureData->height, glFormat, GL_UNSIGNED_BYTE, textureData->data);
if (texture->mipmaps) {
glGenerateMipmap(texture->type);
}
}
} }
TextureFilter lovrTextureGetFilter(Texture* texture) { TextureFilter lovrTextureGetFilter(Texture* texture) {
@ -164,7 +144,6 @@ TextureFilter lovrTextureGetFilter(Texture* texture) {
} }
void lovrTextureSetFilter(Texture* texture, TextureFilter filter) { void lovrTextureSetFilter(Texture* texture, TextureFilter filter) {
bool hasMipmaps = lovrTextureFormatIsCompressed(texture->slices[0]->format) || texture->slices[0]->generateMipmaps;
float anisotropy = filter.mode == FILTER_ANISOTROPIC ? MAX(filter.anisotropy, 1.) : 1.; float anisotropy = filter.mode == FILTER_ANISOTROPIC ? MAX(filter.anisotropy, 1.) : 1.;
lovrGraphicsBindTexture(texture, texture->type, 0); lovrGraphicsBindTexture(texture, texture->type, 0);
texture->filter = filter; texture->filter = filter;
@ -176,7 +155,7 @@ void lovrTextureSetFilter(Texture* texture, TextureFilter filter) {
break; break;
case FILTER_BILINEAR: case FILTER_BILINEAR:
if (hasMipmaps) { if (texture->mipmaps) {
glTexParameteri(texture->type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(texture->type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(texture->type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(texture->type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else { } else {
@ -187,7 +166,7 @@ void lovrTextureSetFilter(Texture* texture, TextureFilter filter) {
case FILTER_TRILINEAR: case FILTER_TRILINEAR:
case FILTER_ANISOTROPIC: case FILTER_ANISOTROPIC:
if (hasMipmaps) { if (texture->mipmaps) {
glTexParameteri(texture->type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(texture->type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(texture->type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(texture->type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else { } else {

View File

@ -6,6 +6,7 @@
typedef enum { typedef enum {
TEXTURE_2D = GL_TEXTURE_2D, TEXTURE_2D = GL_TEXTURE_2D,
TEXTURE_ARRAY = GL_TEXTURE_2D_ARRAY,
TEXTURE_CUBE = GL_TEXTURE_CUBE_MAP TEXTURE_CUBE = GL_TEXTURE_CUBE_MAP
} TextureType; } TextureType;
@ -36,7 +37,7 @@ typedef struct {
typedef struct { typedef struct {
Ref ref; Ref ref;
TextureType type; TextureType type;
TextureData* slices[6]; TextureData** slices;
int sliceCount; int sliceCount;
int width; int width;
int height; int height;
@ -44,13 +45,15 @@ typedef struct {
TextureFilter filter; TextureFilter filter;
TextureWrap wrap; TextureWrap wrap;
bool srgb; bool srgb;
bool mipmaps;
bool allocated;
} Texture; } Texture;
GLenum lovrTextureFormatGetGLFormat(TextureFormat format); GLenum lovrTextureFormatGetGLFormat(TextureFormat format);
GLenum lovrTextureFormatGetGLInternalFormat(TextureFormat format, bool srgb); GLenum lovrTextureFormatGetGLInternalFormat(TextureFormat format, bool srgb);
bool lovrTextureFormatIsCompressed(TextureFormat format); bool lovrTextureFormatIsCompressed(TextureFormat format);
Texture* lovrTextureCreate(TextureType type, TextureData* data[6], int count, bool srgb); Texture* lovrTextureCreate(TextureType type, TextureData** slices, int count, bool srgb, bool mipmaps);
void lovrTextureDestroy(const Ref* ref); void lovrTextureDestroy(const Ref* ref);
void lovrTextureReplacePixels(Texture* texture, TextureData* data, int slice); void lovrTextureReplacePixels(Texture* texture, TextureData* data, int slice);
TextureFilter lovrTextureGetFilter(Texture* texture); TextureFilter lovrTextureGetFilter(Texture* texture);

View File

@ -713,7 +713,6 @@ static ModelData* openvrControllerNewModelData(Controller* controller) {
textureData->format = FORMAT_RGBA; textureData->format = FORMAT_RGBA;
textureData->data = memcpy(malloc(size), vrTexture->rubTextureMapData, size); textureData->data = memcpy(malloc(size), vrTexture->rubTextureMapData, size);
textureData->blob = NULL; textureData->blob = NULL;
textureData->generateMipmaps = true;
vec_init(&textureData->mipmaps); vec_init(&textureData->mipmaps);
modelData->materials[0].diffuseColor = (Color) { 1, 1, 1, 1 }; modelData->materials[0].diffuseColor = (Color) { 1, 1, 1, 1 };

View File

@ -106,6 +106,7 @@ const char* lovrSkyboxVertexShader = ""
"out vec3 texturePosition; \n" "out vec3 texturePosition; \n"
"vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n" "vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n"
" texturePosition = vertex.xyz; \n" " texturePosition = vertex.xyz; \n"
" texturePosition.y *= -1; \n"
" return projection * transform * vertex; \n" " return projection * transform * vertex; \n"
"}"; "}";