mirror of https://github.com/bjornbytes/lovr.git
Add support for 2d array textures; Improve mipmaps;
lovr.graphics.newTexture has been changed.
This commit is contained in:
parent
5493a980ff
commit
f75530b9e1
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -40,7 +40,6 @@ typedef struct {
|
|||
void* data;
|
||||
Blob* blob;
|
||||
TextureFormat format;
|
||||
bool generateMipmaps;
|
||||
vec_mipmap_t mipmaps;
|
||||
} TextureData;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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"
|
||||
"}";
|
||||
|
||||
|
|
Loading…
Reference in New Issue