From a2860361e9d13e6863b2192d16de62f721a777a5 Mon Sep 17 00:00:00 2001 From: bjorn Date: Sun, 15 Oct 2017 16:56:00 -0700 Subject: [PATCH] Consolidate Texture and Skybox; --- CMakeLists.txt | 2 - src/api/graphics.c | 101 +++++++++++++-------------------- src/api/lovr.h | 1 - src/api/types/skybox.c | 17 ------ src/api/types/texture.c | 27 +++++---- src/graphics/font.c | 6 +- src/graphics/graphics.c | 47 +++++++--------- src/graphics/graphics.h | 5 +- src/graphics/mesh.c | 1 + src/graphics/skybox.c | 56 ------------------ src/graphics/skybox.h | 19 ------- src/graphics/texture.c | 122 +++++++++++++++++++++++----------------- src/graphics/texture.h | 28 ++++++--- 13 files changed, 173 insertions(+), 259 deletions(-) delete mode 100644 src/api/types/skybox.c delete mode 100644 src/graphics/skybox.c delete mode 100644 src/graphics/skybox.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f2faba66..599b818e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -229,7 +229,6 @@ set(LOVR_SRC src/api/types/randomGenerator.c src/api/types/shader.c src/api/types/shapes.c - src/api/types/skybox.c src/api/types/source.c src/api/types/texture.c src/api/types/transform.c @@ -244,7 +243,6 @@ set(LOVR_SRC src/graphics/mesh.c src/graphics/model.c src/graphics/shader.c - src/graphics/skybox.c src/graphics/texture.c src/headset/headset.c src/lib/glad/glad.c diff --git a/src/api/graphics.c b/src/api/graphics.c index 5621943d..cb3b581e 100644 --- a/src/api/graphics.c +++ b/src/api/graphics.c @@ -63,14 +63,6 @@ static void luax_readvertices(lua_State* L, int index, vec_float_t* points) { } } -static Texture* luax_readtexture(lua_State* L, int index) { - Blob* blob = luax_readblob(L, index, "Texture"); - TextureData* textureData = lovrTextureDataFromBlob(blob); - Texture* texture = lovrTextureCreate(textureData); - lovrRelease(&blob->ref); - return texture; -} - // Base int l_lovrGraphicsInit(lua_State* L) { @@ -80,7 +72,6 @@ int l_lovrGraphicsInit(lua_State* L) { luax_registertype(L, "Mesh", lovrMesh); luax_registertype(L, "Model", lovrModel); luax_registertype(L, "Shader", lovrShader); - luax_registertype(L, "Skybox", lovrSkybox); luax_registertype(L, "Texture", lovrTexture); map_init(&BlendAlphaModes); @@ -550,15 +541,21 @@ int l_lovrGraphicsCylinder(lua_State* L) { } int l_lovrGraphicsSphere(lua_State* L) { - Texture* texture = NULL; float transform[16]; int index = 1; - if (lua_isuserdata(L, 1) && (lua_isuserdata(L, 2) || lua_isnumber(L, 2))) { - texture = luax_checktype(L, index++, Texture); - } index = luax_readtransform(L, index, transform, 1); int segments = luaL_optnumber(L, index, 30); - lovrGraphicsSphere(texture, transform, segments, NULL); + lovrGraphicsSphere(transform, segments); + return 0; +} + +int l_lovrGraphicsSkybox(lua_State* L) { + Texture* texture = luax_checktype(L, 1, Texture); + float angle = luaL_optnumber(L, 2, 0); + float ax = luaL_optnumber(L, 3, 0); + float ay = luaL_optnumber(L, 4, 1); + float az = luaL_optnumber(L, 5, 0); + lovrGraphicsSkybox(texture, angle, ax, ay, az); return 0; } @@ -700,51 +697,6 @@ int l_lovrGraphicsNewShader(lua_State* L) { return 1; } -int l_lovrGraphicsNewSkybox(lua_State* L) { - Blob* blobs[6] = { NULL }; - SkyboxType type; - - if (lua_gettop(L) == 1 && lua_type(L, 1) == LUA_TSTRING) { - type = SKYBOX_PANORAMA; - blobs[0] = luax_readblob(L, 1, "Skybox"); - } else if (lua_istable(L, 1)) { - if (lua_objlen(L, 1) != 6) { - return luaL_argerror(L, 1, "Expected 6 strings or a table containing 6 strings"); - } - - for (int i = 0; i < 6; i++) { - lua_rawgeti(L, 1, i + 1); - - if (!lua_isstring(L, -1)) { - return luaL_argerror(L, 1, "Expected 6 strings or a table containing 6 strings"); - } - - blobs[i] = luax_readblob(L, -1, "Skybox"); - lua_pop(L, 1); - } - - type = SKYBOX_CUBE; - } else { - for (int i = 0; i < 6; i++) { - blobs[i] = luax_readblob(L, i + 1, "Skybox"); - } - - type = SKYBOX_CUBE; - } - - Skybox* skybox = lovrSkyboxCreate(blobs, type); - luax_pushtype(L, Skybox, skybox); - lovrRelease(&skybox->ref); - - for (int i = 0; i < 6; i++) { - if (blobs[i]) { - lovrRelease(&blobs[i]->ref); - } - } - - return 1; -} - int l_lovrGraphicsNewTexture(lua_State* L) { Texture* texture; @@ -756,7 +708,34 @@ int l_lovrGraphicsNewTexture(lua_State* L) { TextureData* textureData = lovrTextureDataGetEmpty(width, height, FORMAT_RGBA); texture = lovrTextureCreateWithFramebuffer(textureData, *projection, msaa); } else { - texture = luax_readtexture(L, 1); + Blob* blobs[6]; + int isTable = lua_istable(L, 1); + int count = isTable ? lua_objlen(L, 1) : lua_gettop(L); + + if (count != 1 && count != 6) { + return luaL_error(L, "Expected 1 image for a 2D texture or 6 images for a cube texture, got %d", count); + } + + if (isTable) { + for (int i = 0; i < count; i++) { + lua_rawgeti(L, -1, i + 1); + blobs[i] = luax_readblob(L, -1, "Texture"); + lua_pop(L, 1); + } + } else { + for (int i = 0; i < count; i++) { + blobs[i] = luax_readblob(L, i + 1, "Texture"); + } + } + + TextureData* slices[6]; + for (int i = 0; i < count; i++) { + slices[i] = lovrTextureDataFromBlob(blobs[i]); + lovrRelease(&blobs[i]->ref); + } + + TextureType type = (count == 1) ? TEXTURE_2D : TEXTURE_CUBE; + texture = lovrTextureCreate(type, slices, count); } luax_pushtype(L, Texture, texture); @@ -812,12 +791,12 @@ const luaL_Reg lovrGraphics[] = { { "box", l_lovrGraphicsBox }, { "cylinder", l_lovrGraphicsCylinder }, { "sphere", l_lovrGraphicsSphere }, + { "skybox", l_lovrGraphicsSkybox }, { "print", l_lovrGraphicsPrint }, { "newFont", l_lovrGraphicsNewFont }, { "newMesh", l_lovrGraphicsNewMesh }, { "newModel", l_lovrGraphicsNewModel }, { "newShader", l_lovrGraphicsNewShader }, - { "newSkybox", l_lovrGraphicsNewSkybox }, { "newTexture", l_lovrGraphicsNewTexture }, { NULL, NULL } }; diff --git a/src/api/lovr.h b/src/api/lovr.h index 23683c0a..ef72bbf6 100644 --- a/src/api/lovr.h +++ b/src/api/lovr.h @@ -38,7 +38,6 @@ extern const luaL_Reg lovrPhysics[]; extern const luaL_Reg lovrRandomGenerator[]; extern const luaL_Reg lovrShader[]; extern const luaL_Reg lovrShape[]; -extern const luaL_Reg lovrSkybox[]; extern const luaL_Reg lovrSliderJoint[]; extern const luaL_Reg lovrSource[]; extern const luaL_Reg lovrSphereShape[]; diff --git a/src/api/types/skybox.c b/src/api/types/skybox.c deleted file mode 100644 index f31edce7..00000000 --- a/src/api/types/skybox.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "api/lovr.h" -#include "graphics/graphics.h" - -int l_lovrSkyboxDraw(lua_State* L) { - Skybox* skybox = luax_checktype(L, 1, Skybox); - float angle = luaL_optnumber(L, 2, 0.f); - float ax = luaL_optnumber(L, 3, 0.f); - float ay = luaL_optnumber(L, 4, 0.f); - float az = luaL_optnumber(L, 5, 0.f); - lovrGraphicsSkybox(skybox, angle, ax, ay, az); - return 0; -} - -const luaL_Reg lovrSkybox[] = { - { "draw", l_lovrSkyboxDraw }, - { NULL, NULL } -}; diff --git a/src/api/types/texture.c b/src/api/types/texture.c index 109b45c2..1aa550d1 100644 --- a/src/api/types/texture.c +++ b/src/api/types/texture.c @@ -3,8 +3,8 @@ int l_lovrTextureGetDimensions(lua_State* L) { Texture* texture = luax_checktype(L, 1, Texture); - lua_pushnumber(L, lovrTextureGetWidth(texture)); - lua_pushnumber(L, lovrTextureGetHeight(texture)); + lua_pushnumber(L, texture->width); + lua_pushnumber(L, texture->height); return 2; } @@ -21,22 +21,25 @@ int l_lovrTextureGetFilter(lua_State* L) { int l_lovrTextureGetHeight(lua_State* L) { Texture* texture = luax_checktype(L, 1, Texture); - lua_pushnumber(L, lovrTextureGetHeight(texture)); + lua_pushnumber(L, texture->height); return 1; } int l_lovrTextureGetWidth(lua_State* L) { Texture* texture = luax_checktype(L, 1, Texture); - lua_pushnumber(L, lovrTextureGetWidth(texture)); + lua_pushnumber(L, texture->width); return 1; } int l_lovrTextureGetWrap(lua_State* L) { Texture* texture = luax_checktype(L, 1, Texture); - WrapMode horizontal, vertical; - lovrTextureGetWrap(texture, &horizontal, &vertical); - luax_pushenum(L, &WrapModes, horizontal); - luax_pushenum(L, &WrapModes, vertical); + TextureWrap wrap = lovrTextureGetWrap(texture); + luax_pushenum(L, &WrapModes, wrap.s); + luax_pushenum(L, &WrapModes, wrap.t); + if (texture->type == TEXTURE_CUBE) { + luax_pushenum(L, &WrapModes, wrap.r); + return 3; + } return 2; } @@ -62,9 +65,11 @@ int l_lovrTextureSetFilter(lua_State* L) { int l_lovrTextureSetWrap(lua_State* L) { Texture* texture = luax_checktype(L, 1, Texture); - WrapMode* horizontal = (WrapMode*) luax_checkenum(L, 2, &WrapModes, "wrap mode"); - WrapMode* vertical = (WrapMode*) luax_optenum(L, 3, luaL_checkstring(L, 2), &WrapModes, "wrap mode"); - lovrTextureSetWrap(texture, *horizontal, *vertical); + TextureWrap wrap; + wrap.s = *(WrapMode*) luax_checkenum(L, 2, &WrapModes, "wrap mode"); + wrap.t = *(WrapMode*) luax_optenum(L, 3, luaL_checkstring(L, 2), &WrapModes, "wrap mode"); + wrap.r = *(WrapMode*) luax_optenum(L, 4, luaL_checkstring(L, 2), &WrapModes, "wrap mode"); + lovrTextureSetWrap(texture, wrap); return 0; } diff --git a/src/graphics/font.c b/src/graphics/font.c index c406b643..3c12e1c2 100644 --- a/src/graphics/font.c +++ b/src/graphics/font.c @@ -49,9 +49,9 @@ Font* lovrFontCreate(FontData* fontData) { // Texture TextureData* textureData = lovrTextureDataGetBlank(font->atlas.width, font->atlas.height, 0x0, FORMAT_RGB); TextureFilter filter = { .mode = FILTER_BILINEAR }; - font->texture = lovrTextureCreate(textureData); + font->texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1); lovrTextureSetFilter(font->texture, filter); - lovrTextureSetWrap(font->texture, WRAP_CLAMP, WRAP_CLAMP); + lovrTextureSetWrap(font->texture, (TextureWrap) { .s = WRAP_CLAMP, .t = WRAP_CLAMP }); return font; } @@ -299,7 +299,7 @@ void lovrFontExpandTexture(Font* font) { } // Resize the texture storage - lovrTextureDataResize(font->texture->textureData, atlas->width, atlas->height, 0x0); + lovrTextureDataResize(font->texture->slices[0], atlas->width, atlas->height, 0x0); lovrTextureRefresh(font->texture); // Reset the cursor diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index 2c5913af..245308da 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -734,7 +734,7 @@ void lovrGraphicsCylinder(float x1, float y1, float z1, float x2, float y2, floa #undef PUSH_CYLINDER_TRIANGLE } -void lovrGraphicsSphere(Texture* texture, mat4 transform, int segments, Skybox* skybox) { +void lovrGraphicsSphere(mat4 transform, int segments) { vec_clear(&state.streamData); vec_clear(&state.streamIndices); @@ -751,11 +751,9 @@ void lovrGraphicsSphere(Texture* texture, mat4 transform, int segments, Skybox* vec_push(&state.streamData, y); vec_push(&state.streamData, z); - if (!skybox) { - vec_push(&state.streamData, x); - vec_push(&state.streamData, y); - vec_push(&state.streamData, z); - } + vec_push(&state.streamData, x); + vec_push(&state.streamData, y); + vec_push(&state.streamData, z); vec_push(&state.streamData, u); vec_push(&state.streamData, v); @@ -777,23 +775,20 @@ void lovrGraphicsSphere(Texture* texture, mat4 transform, int segments, Skybox* } } - lovrGraphicsSetDefaultShader(SHADER_DEFAULT); - - if (skybox) { - Texture* oldTexture = lovrGraphicsGetTexture(); - glBindTexture(GL_TEXTURE_2D, skybox->texture); - lovrGraphicsDrawPrimitive(GL_TRIANGLES, 0, 1, 1); - glBindTexture(GL_TEXTURE_2D, oldTexture->id); - } else { - lovrGraphicsBindTexture(texture); + if (transform) { lovrGraphicsPush(); lovrGraphicsMatrixTransform(MATRIX_MODEL, transform); - lovrGraphicsDrawPrimitive(GL_TRIANGLES, 1, 1, 1); + } + + lovrGraphicsSetDefaultShader(SHADER_DEFAULT); + lovrGraphicsDrawPrimitive(GL_TRIANGLES, 1, 1, 1); + + if (transform) { lovrGraphicsPop(); } } -void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float az) { +void lovrGraphicsSkybox(Texture* texture, float angle, float ax, float ay, float az) { lovrGraphicsPush(); lovrGraphicsOrigin(); lovrGraphicsRotate(MATRIX_MODEL, angle, ax, ay, az); @@ -801,7 +796,7 @@ void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float a int wasCulling = lovrGraphicsIsCullingEnabled(); lovrGraphicsSetCullingEnabled(0); - if (skybox->type == SKYBOX_CUBE) { + if (texture->type == TEXTURE_CUBE) { float cube[] = { // Front 1.f, -1.f, -1.f, @@ -844,15 +839,14 @@ void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float a 1.f, 1.f, 1.f }; - lovrGraphicsSetShapeData(cube, 78); glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_CUBE_MAP, skybox->texture); - lovrGraphicsSetDefaultShader(SHADER_SKYBOX); + lovrGraphicsSetShapeData(cube, 78); + lovrGraphicsBindTexture(texture); + lovrGraphicsPrepare(); lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, 0, 0, 0); - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); glActiveTexture(GL_TEXTURE0); - } else if (skybox->type == SKYBOX_PANORAMA) { - lovrGraphicsSphere(NULL, NULL, 30, skybox); + } else if (texture->type == TEXTURE_2D) { + lovrGraphicsSphere(NULL, 30); } lovrGraphicsSetCullingEnabled(wasCulling); @@ -925,7 +919,8 @@ Texture* lovrGraphicsGetTexture() { void lovrGraphicsBindTexture(Texture* texture) { if (!texture) { if (!state.defaultTexture) { - state.defaultTexture = lovrTextureCreate(lovrTextureDataGetBlank(1, 1, 0xff, FORMAT_RGBA)); + TextureData* textureData = lovrTextureDataGetBlank(1, 1, 0xff, FORMAT_RGBA); + state.defaultTexture = lovrTextureCreate(TEXTURE_2D, &textureData, 1); } texture = state.defaultTexture; @@ -933,7 +928,7 @@ void lovrGraphicsBindTexture(Texture* texture) { if (texture != state.texture) { state.texture = texture; - glBindTexture(GL_TEXTURE_2D, texture->id); + glBindTexture(texture->type, texture->id); } } diff --git a/src/graphics/graphics.h b/src/graphics/graphics.h index a8b6f276..262814a3 100644 --- a/src/graphics/graphics.h +++ b/src/graphics/graphics.h @@ -1,6 +1,5 @@ #include "graphics/font.h" #include "graphics/shader.h" -#include "graphics/skybox.h" #include "graphics/texture.h" #include "math/math.h" #include "lib/glfw.h" @@ -158,8 +157,8 @@ void lovrGraphicsPlane(DrawMode mode, Texture* texture, mat4 transform); void lovrGraphicsPlaneFullscreen(Texture* texture); void lovrGraphicsBox(DrawMode mode, Texture* texture, mat4 transform); void lovrGraphicsCylinder(float x1, float y1, float z1, float x2, float y2, float z2, float r1, float r2, int capped, int segments); -void lovrGraphicsSphere(Texture* texture, mat4 transform, int segments, Skybox* skybox); -void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float az); +void lovrGraphicsSphere(mat4 transform, int segments); +void lovrGraphicsSkybox(Texture* texture, float angle, float ax, float ay, float az); void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAlign halign, VerticalAlign valign); // Internal State diff --git a/src/graphics/mesh.c b/src/graphics/mesh.c index fa38710f..b39abcd9 100644 --- a/src/graphics/mesh.c +++ b/src/graphics/mesh.c @@ -121,6 +121,7 @@ void lovrMeshDraw(Mesh* mesh, mat4 transform) { } lovrGraphicsSetDefaultShader(SHADER_DEFAULT); + lovrGraphicsBindTexture(NULL); lovrGraphicsPrepare(); lovrGraphicsBindVertexArray(mesh->vao); lovrMeshBindAttributes(mesh); diff --git a/src/graphics/skybox.c b/src/graphics/skybox.c deleted file mode 100644 index 13d9f768..00000000 --- a/src/graphics/skybox.c +++ /dev/null @@ -1,56 +0,0 @@ -#include "graphics/skybox.h" -#include "lib/stb/stb_image.h" -#include - -Skybox* lovrSkyboxCreate(Blob** blobs, SkyboxType type) { - Skybox* skybox = lovrAlloc(sizeof(Skybox), lovrSkyboxDestroy); - if (!skybox) return NULL; - - skybox->type = type; - - GLenum binding; - int count; - - if (type == SKYBOX_CUBE) { - binding = GL_TEXTURE_CUBE_MAP; - count = 6; - } else { - binding = GL_TEXTURE_2D; - count = 1; - } - - glGenTextures(1, &skybox->texture); - glBindTexture(binding, skybox->texture); - - for (int i = 0; i < count; i++) { - int width, height, channels; - stbi_set_flip_vertically_on_load(0); - unsigned char* image = stbi_load_from_memory(blobs[i]->data, blobs[i]->size, &width, &height, &channels, 3); - lovrAssert(image, "Could not load skybox image %d", i); - - if (type == SKYBOX_CUBE) { - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); - } else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); - } - - free(image); - } - - glTexParameteri(binding, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(binding, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(binding, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(binding, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - if (type == SKYBOX_CUBE) { - glTexParameteri(binding, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - } - - return skybox; -} - -void lovrSkyboxDestroy(const Ref* ref) { - Skybox* skybox = containerof(ref, Skybox); - glDeleteTextures(1, &skybox->texture); - free(skybox); -} diff --git a/src/graphics/skybox.h b/src/graphics/skybox.h deleted file mode 100644 index a0649847..00000000 --- a/src/graphics/skybox.h +++ /dev/null @@ -1,19 +0,0 @@ -#include "filesystem/blob.h" -#include "lib/glad/glad.h" -#include "util.h" - -#pragma once - -typedef enum { - SKYBOX_CUBE, - SKYBOX_PANORAMA -} SkyboxType; - -typedef struct { - Ref ref; - SkyboxType type; - GLuint texture; -} Skybox; - -Skybox* lovrSkyboxCreate(Blob** blobs, SkyboxType type); -void lovrSkyboxDestroy(const Ref* ref); diff --git a/src/graphics/texture.c b/src/graphics/texture.c index e96a8dc1..c5b5dcbd 100644 --- a/src/graphics/texture.c +++ b/src/graphics/texture.c @@ -6,9 +6,9 @@ #include static void lovrTextureCreateStorage(Texture* texture) { - TextureData* textureData = texture->textureData; + TextureData* textureData = texture->slices[0]; - if (textureData->format.compressed || !textureData->mipmaps.generated) { + if (textureData->format.compressed || !textureData->mipmaps.generated || texture->type == TEXTURE_CUBE) { return; } @@ -32,30 +32,50 @@ static void lovrTextureCreateStorage(Texture* texture) { #endif } -Texture* lovrTextureCreate(TextureData* textureData) { +static void validateSlices(TextureType type, TextureData* slices[6], int sliceCount) { + if (type == TEXTURE_CUBE) { + lovrAssert(sliceCount == 6, "Cube textures must have 6 images"); + int width = slices[0]->width; + int height = slices[0]->height; + 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"); + } +} + +Texture* lovrTextureCreate(TextureType type, TextureData* slices[6], int sliceCount) { Texture* texture = lovrAlloc(sizeof(Texture), lovrTextureDestroy); if (!texture) return NULL; + texture->type = type; + validateSlices(type, slices, sliceCount); + texture->sliceCount = sliceCount; + memcpy(texture->slices, slices, sliceCount * sizeof(TextureData*)); texture->framebuffer = 0; texture->depthBuffer = 0; - texture->textureData = textureData; glGenTextures(1, &texture->id); lovrGraphicsBindTexture(texture); lovrTextureCreateStorage(texture); lovrTextureRefresh(texture); lovrTextureSetFilter(texture, lovrGraphicsGetDefaultFilter()); - - lovrTextureSetWrap(texture, WRAP_REPEAT, WRAP_REPEAT); + WrapMode wrapMode = (type == TEXTURE_CUBE) ? WRAP_CLAMP : WRAP_REPEAT; + lovrTextureSetWrap(texture, (TextureWrap) { .s = wrapMode, .t = wrapMode, .r = wrapMode }); return texture; } Texture* lovrTextureCreateWithFramebuffer(TextureData* textureData, TextureProjection projection, int msaa) { - Texture* texture = lovrTextureCreate(textureData); + Texture* texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1); if (!texture) return NULL; - int width = texture->textureData->width; - int height = texture->textureData->height; + int width = texture->width; + int height = texture->height; texture->projection = projection; texture->msaa = msaa; @@ -102,7 +122,9 @@ Texture* lovrTextureCreateWithFramebuffer(TextureData* textureData, TextureProje void lovrTextureDestroy(const Ref* ref) { Texture* texture = containerof(ref, Texture); - lovrTextureDataDestroy(texture->textureData); + for (int i = 0; i < texture->sliceCount; i++) { + lovrTextureDataDestroy(texture->slices[i]); + } if (texture->framebuffer) { glDeleteFramebuffers(1, &texture->framebuffer); } @@ -112,23 +134,19 @@ void lovrTextureDestroy(const Ref* ref) { void lovrTextureBindFramebuffer(Texture* texture) { lovrAssert(texture->framebuffer, "Texture cannot be used as a canvas"); - - int w = texture->textureData->width; - int h = texture->textureData->height; - lovrGraphicsBindFramebuffer(texture->framebuffer); - lovrGraphicsSetViewport(0, 0, w, h); + lovrGraphicsSetViewport(0, 0, texture->width, texture->height); if (texture->projection == PROJECTION_ORTHOGRAPHIC) { float projection[16]; - mat4_orthographic(projection, 0, w, 0, h, -1, 1); + mat4_orthographic(projection, 0, texture->width, 0, texture->height, -1, 1); lovrGraphicsSetProjection(projection); } else if (texture->projection == PROJECTION_PERSPECTIVE) { mat4 projection = lovrGraphicsGetProjection(); float b = projection[5]; float c = projection[10]; float d = projection[14]; - float aspect = (float) w / h; + float aspect = (float) texture->width / texture->height; float k = (c - 1.f) / (c + 1.f); float near = (d * (1.f - k)) / (2.f * k); float far = k * near; @@ -145,51 +163,50 @@ void lovrTextureResolveMSAA(Texture* texture) { return; } - int w = texture->textureData->width; - int h = texture->textureData->height; - + int width = texture->width; + int height = texture->height; glBindFramebuffer(GL_READ_FRAMEBUFFER, texture->framebuffer); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, texture->resolveFramebuffer); - glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR); + glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } void lovrTextureRefresh(Texture* texture) { - TextureData* textureData = texture->textureData; - GLenum glInternalFormat = textureData->format.glInternalFormat; - GLenum glFormat = textureData->format.glFormat; lovrGraphicsBindTexture(texture); - if (textureData->format.compressed) { - Mipmap m; int i; - vec_foreach(&textureData->mipmaps.list, m, i) { - glCompressedTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, m.width, m.height, 0, m.size, m.data); - } - } else { - int w = textureData->width; - int h = textureData->height; - glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, w, h, 0, glFormat, GL_UNSIGNED_BYTE, textureData->data); - if (textureData->mipmaps.generated) { - glGenerateMipmap(GL_TEXTURE_2D); + 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 = textureData->format.glInternalFormat; + 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; + glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, w, h, 0, glFormat, GL_UNSIGNED_BYTE, textureData->data); + if (textureData->mipmaps.generated) { + glGenerateMipmap(GL_TEXTURE_2D); // TODO + } } } } -int lovrTextureGetHeight(Texture* texture) { - return texture->textureData->height; -} - -int lovrTextureGetWidth(Texture* texture) { - return texture->textureData->width; -} - TextureFilter lovrTextureGetFilter(Texture* texture) { return texture->filter; } void lovrTextureSetFilter(Texture* texture, TextureFilter filter) { - int hasMipmaps = texture->textureData->format.compressed || texture->textureData->mipmaps.generated; + int hasMipmaps = texture->slices[0]->format.compressed || texture->slices[0]->mipmaps.generated; float anisotropy = filter.mode == FILTER_ANISOTROPIC ? MAX(filter.anisotropy, 1.) : 1.; lovrGraphicsBindTexture(texture); texture->filter = filter; @@ -225,15 +242,16 @@ void lovrTextureSetFilter(Texture* texture, TextureFilter filter) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); } -void lovrTextureGetWrap(Texture* texture, WrapMode* horizontal, WrapMode* vertical) { - *horizontal = texture->wrapHorizontal; - *vertical = texture->wrapVertical; +TextureWrap lovrTextureGetWrap(Texture* texture) { + return texture->wrap; } -void lovrTextureSetWrap(Texture* texture, WrapMode horizontal, WrapMode vertical) { - texture->wrapHorizontal = horizontal; - texture->wrapVertical = vertical; +void lovrTextureSetWrap(Texture* texture, TextureWrap wrap) { + texture->wrap = wrap; lovrGraphicsBindTexture(texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, horizontal); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vertical); + glTexParameteri(texture->type, GL_TEXTURE_WRAP_S, wrap.s); + glTexParameteri(texture->type, GL_TEXTURE_WRAP_T, wrap.t); + if (texture->type == TEXTURE_CUBE) { + glTexParameteri(texture->type, GL_TEXTURE_WRAP_R, wrap.r); + } } diff --git a/src/graphics/texture.h b/src/graphics/texture.h index 20512d7a..9818406c 100644 --- a/src/graphics/texture.h +++ b/src/graphics/texture.h @@ -4,6 +4,11 @@ #pragma once +typedef enum { + TEXTURE_2D = GL_TEXTURE_2D, + TEXTURE_CUBE = GL_TEXTURE_CUBE_MAP +} TextureType; + typedef enum { FILTER_NEAREST, FILTER_BILINEAR, @@ -22,6 +27,12 @@ typedef enum { WRAP_MIRRORED_REPEAT = GL_MIRRORED_REPEAT } WrapMode; +typedef struct { + WrapMode s; + WrapMode t; + WrapMode r; +} TextureWrap; + typedef enum { PROJECTION_ORTHOGRAPHIC, PROJECTION_PERSPECTIVE @@ -29,7 +40,11 @@ typedef enum { typedef struct { Ref ref; - TextureData* textureData; + TextureType type; + TextureData* slices[6]; + int sliceCount; + int width; + int height; GLuint id; GLuint msaaId; GLuint framebuffer; @@ -37,22 +52,19 @@ typedef struct { GLuint depthBuffer; TextureProjection projection; TextureFilter filter; - WrapMode wrapHorizontal; - WrapMode wrapVertical; + TextureWrap wrap; int msaa; } Texture; GLenum lovrTextureGetGLFormat(TextureFormat format); -Texture* lovrTextureCreate(TextureData* textureData); +Texture* lovrTextureCreate(TextureType type, TextureData* data[6], int count); Texture* lovrTextureCreateWithFramebuffer(TextureData* textureData, TextureProjection projection, int msaa); void lovrTextureDestroy(const Ref* ref); void lovrTextureBindFramebuffer(Texture* texture); void lovrTextureResolveMSAA(Texture* texture); void lovrTextureRefresh(Texture* texture); -int lovrTextureGetHeight(Texture* texture); -int lovrTextureGetWidth(Texture* texture); TextureFilter lovrTextureGetFilter(Texture* texture); void lovrTextureSetFilter(Texture* texture, TextureFilter filter); -void lovrTextureGetWrap(Texture* texture, WrapMode* horizontal, WrapMode* vertical); -void lovrTextureSetWrap(Texture* texture, WrapMode horizontal, WrapMode vertical); +TextureWrap lovrTextureGetWrap(Texture* texture); +void lovrTextureSetWrap(Texture* texture, TextureWrap wrap);