From f75530b9e1c14f5ae32cec5ff1ff5ebbfffc0381 Mon Sep 17 00:00:00 2001 From: bjorn Date: Tue, 20 Feb 2018 17:15:00 -0800 Subject: [PATCH] Add support for 2d array textures; Improve mipmaps; lovr.graphics.newTexture has been changed. --- src/api.h | 1 + src/api/graphics.c | 69 +++++++++++----- src/data/textureData.c | 3 - src/data/textureData.h | 1 - src/graphics/canvas.c | 2 +- src/graphics/font.c | 2 +- src/graphics/graphics.c | 4 +- src/graphics/model.c | 2 +- src/graphics/shader.c | 9 ++- src/graphics/texture.c | 171 ++++++++++++++++++---------------------- src/graphics/texture.h | 7 +- src/headset/openvr.c | 1 - src/resources/shaders.c | 1 + 13 files changed, 145 insertions(+), 128 deletions(-) diff --git a/src/api.h b/src/api.h index 20d76058..81d55729 100644 --- a/src/api.h +++ b/src/api.h @@ -86,6 +86,7 @@ extern map_int_t MeshUsages; extern map_int_t PolygonWindings; extern map_int_t ShapeTypes; extern map_int_t TextureFormats; +extern map_int_t TextureTypes; extern map_int_t TimeUnits; extern map_int_t VerticalAligns; extern map_int_t WrapModes; diff --git a/src/api/graphics.c b/src/api/graphics.c index d43d4354..1671ba33 100644 --- a/src/api/graphics.c +++ b/src/api/graphics.c @@ -29,6 +29,7 @@ map_int_t MeshDrawModes; map_int_t MeshUsages; map_int_t StencilActions; map_int_t TextureFormats; +map_int_t TextureTypes; map_int_t VerticalAligns; map_int_t Windings; map_int_t WrapModes; @@ -204,6 +205,11 @@ int l_lovrGraphicsInit(lua_State* L) { map_set(&TextureFormats, "dxt3", FORMAT_DXT3); 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_set(&VerticalAligns, "top", ALIGN_TOP); map_set(&VerticalAligns, "bottom", ALIGN_BOTTOM); @@ -918,7 +924,7 @@ int l_lovrGraphicsNewMaterial(lua_State* L) { Blob* blob = luax_readblob(L, index++, "Texture"); TextureData* textureData = lovrTextureDataFromBlob(blob); 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); lovrRelease(&texture->ref); } else if (lua_isuserdata(L, index)) { @@ -1020,7 +1026,7 @@ int l_lovrGraphicsNewModel(lua_State* L) { if (lua_type(L, 2) == LUA_TSTRING) { Blob* blob = luax_readblob(L, 2, "Texture"); 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); lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture); lovrModelSetMaterial(model, material); @@ -1061,34 +1067,57 @@ int l_lovrGraphicsNewShader(lua_State* L) { } int l_lovrGraphicsNewTexture(lua_State* L) { - int top = lua_gettop(L); 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) { - for (int i = 0; i < count; i++) { - lua_rawgeti(L, 1, i + 1); - slices[i] = luax_checktexturedata(L, -1); - lua_pop(L, 1); - } - } else { - for (int i = 0; i < count; i++) { - slices[i] = luax_checktexturedata(L, i + 1); - } + if (!isTable) { + lua_newtable(L); + lua_pushvalue(L, 1); + lua_rawseti(L, -2, 1); + lua_replace(L, 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 mipmaps = true; + if (hasFlags) { - lua_getfield(L, top, "linear"); + lua_getfield(L, 2, "linear"); srgb = !lua_toboolean(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); lovrRelease(&texture->ref); return 1; diff --git a/src/data/textureData.c b/src/data/textureData.c index 75abf7bc..fe0101af 100644 --- a/src/data/textureData.c +++ b/src/data/textureData.c @@ -136,7 +136,6 @@ TextureData* lovrTextureDataGetBlank(int width, int height, uint8_t value, Textu textureData->data = memset(malloc(size), value, size); textureData->blob = NULL; vec_init(&textureData->mipmaps); - textureData->generateMipmaps = false; return textureData; } @@ -151,7 +150,6 @@ TextureData* lovrTextureDataGetEmpty(int width, int height, TextureFormat format textureData->data = NULL; textureData->blob = NULL; vec_init(&textureData->mipmaps); - textureData->generateMipmaps = false; return textureData; } @@ -171,7 +169,6 @@ TextureData* lovrTextureDataFromBlob(Blob* blob) { textureData->format = FORMAT_RGBA; textureData->data = stbi_load_from_memory(blob->data, blob->size, &textureData->width, &textureData->height, NULL, 4); textureData->blob = NULL; - textureData->generateMipmaps = true; if (!textureData->data) { lovrThrow("Could not load texture data from '%s'", blob->name); diff --git a/src/data/textureData.h b/src/data/textureData.h index 2da776bb..1eb779a5 100644 --- a/src/data/textureData.h +++ b/src/data/textureData.h @@ -40,7 +40,6 @@ typedef struct { void* data; Blob* blob; TextureFormat format; - bool generateMipmaps; vec_mipmap_t mipmaps; } TextureData; diff --git a/src/graphics/canvas.c b/src/graphics/canvas.c index a35b331c..f12a7628 100644 --- a/src/graphics/canvas.c +++ b/src/graphics/canvas.c @@ -21,7 +21,7 @@ bool lovrCanvasSupportsFormat(TextureFormat format) { Canvas* lovrCanvasCreate(int width, int height, TextureFormat format, int msaa, bool depth, bool stencil) { 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; Canvas* canvas = lovrAlloc(sizeof(Canvas), lovrCanvasDestroy); diff --git a/src/graphics/font.c b/src/graphics/font.c index 4ebba33d..209f20d8 100644 --- a/src/graphics/font.c +++ b/src/graphics/font.c @@ -324,7 +324,7 @@ void lovrFontCreateTexture(Font* font) { 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); + font->texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, false, false); lovrTextureSetFilter(font->texture, filter); lovrTextureSetWrap(font->texture, (TextureWrap) { .s = WRAP_CLAMP, .t = WRAP_CLAMP }); } diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index 4171402c..add48aec 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -1136,6 +1136,8 @@ void lovrGraphicsSkybox(Texture* texture, float angle, float ax, float ay, float lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture); lovrGraphicsSphere(material, NULL, 30); lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, NULL); + } else { + lovrThrow("lovr.graphics.skybox only accepts 2d and cube Textures"); } lovrGraphicsSetDepthTest(mode, write); @@ -1234,7 +1236,7 @@ void lovrGraphicsBindTexture(Texture* texture, TextureType type, int slot) { if (!texture) { if (!state.defaultTexture) { 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; diff --git a/src/graphics/model.c b/src/graphics/model.c index 012a990d..0c6e3a80 100644 --- a/src/graphics/model.c +++ b/src/graphics/model.c @@ -70,7 +70,7 @@ Model* lovrModelCreate(ModelData* modelData) { model->textures = malloc(modelData->textures.length * sizeof(Texture*)); for (int i = 0; i < modelData->textures.length; 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 { model->textures[i] = NULL; } diff --git a/src/graphics/shader.c b/src/graphics/shader.c index 390ae87c..9d7a4a11 100644 --- a/src/graphics/shader.c +++ b/src/graphics/shader.c @@ -26,6 +26,7 @@ static UniformType getUniformType(GLenum type, const char* debug) { case GL_SAMPLER_2D: case GL_SAMPLER_CUBE: + case GL_SAMPLER_2D_ARRAY: return UNIFORM_SAMPLER; default: @@ -40,6 +41,7 @@ static int getUniformComponents(GLenum type) { case GL_INT: case GL_SAMPLER_2D: case GL_SAMPLER_CUBE: + case GL_SAMPLER_2D_ARRAY: return 1; case GL_FLOAT_VEC2: @@ -303,7 +305,12 @@ void lovrShaderBind(Shader* shader) { case UNIFORM_SAMPLER: 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); } break; diff --git a/src/graphics/texture.c b/src/graphics/texture.c index 5b8aa074..62ec482f 100644 --- a/src/graphics/texture.c +++ b/src/graphics/texture.c @@ -31,113 +31,66 @@ GLenum lovrTextureFormatGetGLInternalFormat(TextureFormat format, bool srgb) { } bool lovrTextureFormatIsCompressed(TextureFormat format) { - switch (format) { - case FORMAT_DXT1: - case FORMAT_DXT3: - case FORMAT_DXT5: - return true; - default: - return false; - } + return format == FORMAT_DXT1 || format == FORMAT_DXT3 || format == FORMAT_DXT5; } -static void lovrTextureUpload(Texture* texture) { - TextureData* textureData = texture->slices[0]; +static void lovrTextureAllocate(Texture* texture, TextureData* textureData) { + texture->allocated = true; texture->width = textureData->width; 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; - - // Allocate storage - 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); + GLenum glFormat = lovrTextureFormatGetGLFormat(textureData->format); + GLenum internalFormat = lovrTextureFormatGetGLInternalFormat(textureData->format, srgb); #ifndef EMSCRIPTEN - if (GLAD_GL_ARB_texture_storage) { + if (GLAD_GL_ARB_texture_storage) { #endif - glTexStorage2D(GL_TEXTURE_2D, mipmapCount, internalFormat, w, h); + glTexStorage2D(texture->type, mipmapCount, internalFormat, w, h); #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 { - 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); if (!texture) return NULL; texture->type = type; - validateSlices(type, slices, sliceCount); + texture->slices = calloc(sliceCount, sizeof(TextureData**)); texture->sliceCount = sliceCount; - memcpy(texture->slices, slices, sliceCount * sizeof(TextureData*)); texture->srgb = srgb; - glGenTextures(1, &texture->id); - lovrGraphicsBindTexture(texture, type, 0); - lovrTextureUpload(texture); - lovrTextureSetFilter(texture, lovrGraphicsGetDefaultFilter()); - WrapMode wrapMode = (type == TEXTURE_CUBE) ? WRAP_CLAMP : WRAP_REPEAT; - lovrTextureSetWrap(texture, (TextureWrap) { .s = wrapMode, .t = wrapMode, .r = wrapMode }); + texture->mipmaps = mipmaps; + texture->allocated = false; - for (int i = 0; i < sliceCount; i++) { - lovrRetain(&slices[i]->ref); + WrapMode wrap = type == TEXTURE_CUBE ? WRAP_CLAMP : WRAP_REPEAT; + 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; @@ -146,17 +99,44 @@ Texture* lovrTextureCreate(TextureType type, TextureData* slices[6], int sliceCo void lovrTextureDestroy(const Ref* ref) { Texture* texture = containerof(ref, Texture); 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); + free(texture->slices); free(texture); } void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, int slice) { - lovrAssert(slice >= 0 && slice < texture->sliceCount, "Invalid texture slice to replace: %d", slice); - lovrAssert(textureData->width == texture->width && textureData->height == texture->height, "Texture dimensions must match"); - lovrAssert(textureData->format == texture->slices[0]->format, "Texture formats must match"); - lovrTextureUpload(texture); + lovrRetain(&textureData->ref); + if (texture->slices[slice]) { + lovrRelease(&texture->slices[slice]->ref); + } + + 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) { @@ -164,7 +144,6 @@ TextureFilter lovrTextureGetFilter(Texture* texture) { } 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.; lovrGraphicsBindTexture(texture, texture->type, 0); texture->filter = filter; @@ -176,7 +155,7 @@ void lovrTextureSetFilter(Texture* texture, TextureFilter filter) { break; case FILTER_BILINEAR: - if (hasMipmaps) { + if (texture->mipmaps) { glTexParameteri(texture->type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(texture->type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { @@ -187,7 +166,7 @@ void lovrTextureSetFilter(Texture* texture, TextureFilter filter) { case FILTER_TRILINEAR: case FILTER_ANISOTROPIC: - if (hasMipmaps) { + if (texture->mipmaps) { glTexParameteri(texture->type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(texture->type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { diff --git a/src/graphics/texture.h b/src/graphics/texture.h index e7d1d32a..6637174f 100644 --- a/src/graphics/texture.h +++ b/src/graphics/texture.h @@ -6,6 +6,7 @@ typedef enum { TEXTURE_2D = GL_TEXTURE_2D, + TEXTURE_ARRAY = GL_TEXTURE_2D_ARRAY, TEXTURE_CUBE = GL_TEXTURE_CUBE_MAP } TextureType; @@ -36,7 +37,7 @@ typedef struct { typedef struct { Ref ref; TextureType type; - TextureData* slices[6]; + TextureData** slices; int sliceCount; int width; int height; @@ -44,13 +45,15 @@ typedef struct { TextureFilter filter; TextureWrap wrap; bool srgb; + bool mipmaps; + bool allocated; } Texture; GLenum lovrTextureFormatGetGLFormat(TextureFormat format); GLenum lovrTextureFormatGetGLInternalFormat(TextureFormat format, bool srgb); 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 lovrTextureReplacePixels(Texture* texture, TextureData* data, int slice); TextureFilter lovrTextureGetFilter(Texture* texture); diff --git a/src/headset/openvr.c b/src/headset/openvr.c index df992882..666c7920 100644 --- a/src/headset/openvr.c +++ b/src/headset/openvr.c @@ -713,7 +713,6 @@ static ModelData* openvrControllerNewModelData(Controller* controller) { textureData->format = FORMAT_RGBA; textureData->data = memcpy(malloc(size), vrTexture->rubTextureMapData, size); textureData->blob = NULL; - textureData->generateMipmaps = true; vec_init(&textureData->mipmaps); modelData->materials[0].diffuseColor = (Color) { 1, 1, 1, 1 }; diff --git a/src/resources/shaders.c b/src/resources/shaders.c index e00f8556..450785c6 100644 --- a/src/resources/shaders.c +++ b/src/resources/shaders.c @@ -106,6 +106,7 @@ const char* lovrSkyboxVertexShader = "" "out vec3 texturePosition; \n" "vec4 position(mat4 projection, mat4 transform, vec4 vertex) { \n" " texturePosition = vertex.xyz; \n" +" texturePosition.y *= -1; \n" " return projection * transform * vertex; \n" "}";