Consolidate Texture and Skybox;

This commit is contained in:
bjorn 2017-10-15 16:56:00 -07:00
parent e8f2166e00
commit a2860361e9
13 changed files with 173 additions and 259 deletions

View File

@ -229,7 +229,6 @@ set(LOVR_SRC
src/api/types/randomGenerator.c src/api/types/randomGenerator.c
src/api/types/shader.c src/api/types/shader.c
src/api/types/shapes.c src/api/types/shapes.c
src/api/types/skybox.c
src/api/types/source.c src/api/types/source.c
src/api/types/texture.c src/api/types/texture.c
src/api/types/transform.c src/api/types/transform.c
@ -244,7 +243,6 @@ set(LOVR_SRC
src/graphics/mesh.c src/graphics/mesh.c
src/graphics/model.c src/graphics/model.c
src/graphics/shader.c src/graphics/shader.c
src/graphics/skybox.c
src/graphics/texture.c src/graphics/texture.c
src/headset/headset.c src/headset/headset.c
src/lib/glad/glad.c src/lib/glad/glad.c

View File

@ -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 // Base
int l_lovrGraphicsInit(lua_State* L) { int l_lovrGraphicsInit(lua_State* L) {
@ -80,7 +72,6 @@ int l_lovrGraphicsInit(lua_State* L) {
luax_registertype(L, "Mesh", lovrMesh); luax_registertype(L, "Mesh", lovrMesh);
luax_registertype(L, "Model", lovrModel); luax_registertype(L, "Model", lovrModel);
luax_registertype(L, "Shader", lovrShader); luax_registertype(L, "Shader", lovrShader);
luax_registertype(L, "Skybox", lovrSkybox);
luax_registertype(L, "Texture", lovrTexture); luax_registertype(L, "Texture", lovrTexture);
map_init(&BlendAlphaModes); map_init(&BlendAlphaModes);
@ -550,15 +541,21 @@ int l_lovrGraphicsCylinder(lua_State* L) {
} }
int l_lovrGraphicsSphere(lua_State* L) { int l_lovrGraphicsSphere(lua_State* L) {
Texture* texture = NULL;
float transform[16]; float transform[16];
int index = 1; 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); index = luax_readtransform(L, index, transform, 1);
int segments = luaL_optnumber(L, index, 30); 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; return 0;
} }
@ -700,51 +697,6 @@ int l_lovrGraphicsNewShader(lua_State* L) {
return 1; 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) { int l_lovrGraphicsNewTexture(lua_State* L) {
Texture* texture; Texture* texture;
@ -756,7 +708,34 @@ int l_lovrGraphicsNewTexture(lua_State* L) {
TextureData* textureData = lovrTextureDataGetEmpty(width, height, FORMAT_RGBA); TextureData* textureData = lovrTextureDataGetEmpty(width, height, FORMAT_RGBA);
texture = lovrTextureCreateWithFramebuffer(textureData, *projection, msaa); texture = lovrTextureCreateWithFramebuffer(textureData, *projection, msaa);
} else { } 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); luax_pushtype(L, Texture, texture);
@ -812,12 +791,12 @@ const luaL_Reg lovrGraphics[] = {
{ "box", l_lovrGraphicsBox }, { "box", l_lovrGraphicsBox },
{ "cylinder", l_lovrGraphicsCylinder }, { "cylinder", l_lovrGraphicsCylinder },
{ "sphere", l_lovrGraphicsSphere }, { "sphere", l_lovrGraphicsSphere },
{ "skybox", l_lovrGraphicsSkybox },
{ "print", l_lovrGraphicsPrint }, { "print", l_lovrGraphicsPrint },
{ "newFont", l_lovrGraphicsNewFont }, { "newFont", l_lovrGraphicsNewFont },
{ "newMesh", l_lovrGraphicsNewMesh }, { "newMesh", l_lovrGraphicsNewMesh },
{ "newModel", l_lovrGraphicsNewModel }, { "newModel", l_lovrGraphicsNewModel },
{ "newShader", l_lovrGraphicsNewShader }, { "newShader", l_lovrGraphicsNewShader },
{ "newSkybox", l_lovrGraphicsNewSkybox },
{ "newTexture", l_lovrGraphicsNewTexture }, { "newTexture", l_lovrGraphicsNewTexture },
{ NULL, NULL } { NULL, NULL }
}; };

View File

@ -38,7 +38,6 @@ extern const luaL_Reg lovrPhysics[];
extern const luaL_Reg lovrRandomGenerator[]; extern const luaL_Reg lovrRandomGenerator[];
extern const luaL_Reg lovrShader[]; extern const luaL_Reg lovrShader[];
extern const luaL_Reg lovrShape[]; extern const luaL_Reg lovrShape[];
extern const luaL_Reg lovrSkybox[];
extern const luaL_Reg lovrSliderJoint[]; extern const luaL_Reg lovrSliderJoint[];
extern const luaL_Reg lovrSource[]; extern const luaL_Reg lovrSource[];
extern const luaL_Reg lovrSphereShape[]; extern const luaL_Reg lovrSphereShape[];

View File

@ -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 }
};

View File

@ -3,8 +3,8 @@
int l_lovrTextureGetDimensions(lua_State* L) { int l_lovrTextureGetDimensions(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture); Texture* texture = luax_checktype(L, 1, Texture);
lua_pushnumber(L, lovrTextureGetWidth(texture)); lua_pushnumber(L, texture->width);
lua_pushnumber(L, lovrTextureGetHeight(texture)); lua_pushnumber(L, texture->height);
return 2; return 2;
} }
@ -21,22 +21,25 @@ int l_lovrTextureGetFilter(lua_State* L) {
int l_lovrTextureGetHeight(lua_State* L) { int l_lovrTextureGetHeight(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture); Texture* texture = luax_checktype(L, 1, Texture);
lua_pushnumber(L, lovrTextureGetHeight(texture)); lua_pushnumber(L, texture->height);
return 1; return 1;
} }
int l_lovrTextureGetWidth(lua_State* L) { int l_lovrTextureGetWidth(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture); Texture* texture = luax_checktype(L, 1, Texture);
lua_pushnumber(L, lovrTextureGetWidth(texture)); lua_pushnumber(L, texture->width);
return 1; return 1;
} }
int l_lovrTextureGetWrap(lua_State* L) { int l_lovrTextureGetWrap(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture); Texture* texture = luax_checktype(L, 1, Texture);
WrapMode horizontal, vertical; TextureWrap wrap = lovrTextureGetWrap(texture);
lovrTextureGetWrap(texture, &horizontal, &vertical); luax_pushenum(L, &WrapModes, wrap.s);
luax_pushenum(L, &WrapModes, horizontal); luax_pushenum(L, &WrapModes, wrap.t);
luax_pushenum(L, &WrapModes, vertical); if (texture->type == TEXTURE_CUBE) {
luax_pushenum(L, &WrapModes, wrap.r);
return 3;
}
return 2; return 2;
} }
@ -62,9 +65,11 @@ int l_lovrTextureSetFilter(lua_State* L) {
int l_lovrTextureSetWrap(lua_State* L) { int l_lovrTextureSetWrap(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture); Texture* texture = luax_checktype(L, 1, Texture);
WrapMode* horizontal = (WrapMode*) luax_checkenum(L, 2, &WrapModes, "wrap mode"); TextureWrap wrap;
WrapMode* vertical = (WrapMode*) luax_optenum(L, 3, luaL_checkstring(L, 2), &WrapModes, "wrap mode"); wrap.s = *(WrapMode*) luax_checkenum(L, 2, &WrapModes, "wrap mode");
lovrTextureSetWrap(texture, *horizontal, *vertical); 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; return 0;
} }

View File

@ -49,9 +49,9 @@ Font* lovrFontCreate(FontData* fontData) {
// Texture // Texture
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(textureData); font->texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1);
lovrTextureSetFilter(font->texture, filter); lovrTextureSetFilter(font->texture, filter);
lovrTextureSetWrap(font->texture, WRAP_CLAMP, WRAP_CLAMP); lovrTextureSetWrap(font->texture, (TextureWrap) { .s = WRAP_CLAMP, .t = WRAP_CLAMP });
return font; return font;
} }
@ -299,7 +299,7 @@ void lovrFontExpandTexture(Font* font) {
} }
// Resize the texture storage // 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); lovrTextureRefresh(font->texture);
// Reset the cursor // Reset the cursor

View File

@ -734,7 +734,7 @@ void lovrGraphicsCylinder(float x1, float y1, float z1, float x2, float y2, floa
#undef PUSH_CYLINDER_TRIANGLE #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.streamData);
vec_clear(&state.streamIndices); 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, y);
vec_push(&state.streamData, z); vec_push(&state.streamData, z);
if (!skybox) { vec_push(&state.streamData, x);
vec_push(&state.streamData, x); vec_push(&state.streamData, y);
vec_push(&state.streamData, y); vec_push(&state.streamData, z);
vec_push(&state.streamData, z);
}
vec_push(&state.streamData, u); vec_push(&state.streamData, u);
vec_push(&state.streamData, v); vec_push(&state.streamData, v);
@ -777,23 +775,20 @@ void lovrGraphicsSphere(Texture* texture, mat4 transform, int segments, Skybox*
} }
} }
lovrGraphicsSetDefaultShader(SHADER_DEFAULT); if (transform) {
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);
lovrGraphicsPush(); lovrGraphicsPush();
lovrGraphicsMatrixTransform(MATRIX_MODEL, transform); lovrGraphicsMatrixTransform(MATRIX_MODEL, transform);
lovrGraphicsDrawPrimitive(GL_TRIANGLES, 1, 1, 1); }
lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
lovrGraphicsDrawPrimitive(GL_TRIANGLES, 1, 1, 1);
if (transform) {
lovrGraphicsPop(); 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(); lovrGraphicsPush();
lovrGraphicsOrigin(); lovrGraphicsOrigin();
lovrGraphicsRotate(MATRIX_MODEL, angle, ax, ay, az); 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(); int wasCulling = lovrGraphicsIsCullingEnabled();
lovrGraphicsSetCullingEnabled(0); lovrGraphicsSetCullingEnabled(0);
if (skybox->type == SKYBOX_CUBE) { if (texture->type == TEXTURE_CUBE) {
float cube[] = { float cube[] = {
// Front // Front
1.f, -1.f, -1.f, 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 1.f, 1.f, 1.f
}; };
lovrGraphicsSetShapeData(cube, 78);
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_CUBE_MAP, skybox->texture); lovrGraphicsSetShapeData(cube, 78);
lovrGraphicsSetDefaultShader(SHADER_SKYBOX); lovrGraphicsBindTexture(texture);
lovrGraphicsPrepare();
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, 0, 0, 0); lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, 0, 0, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
} else if (skybox->type == SKYBOX_PANORAMA) { } else if (texture->type == TEXTURE_2D) {
lovrGraphicsSphere(NULL, NULL, 30, skybox); lovrGraphicsSphere(NULL, 30);
} }
lovrGraphicsSetCullingEnabled(wasCulling); lovrGraphicsSetCullingEnabled(wasCulling);
@ -925,7 +919,8 @@ Texture* lovrGraphicsGetTexture() {
void lovrGraphicsBindTexture(Texture* texture) { void lovrGraphicsBindTexture(Texture* texture) {
if (!texture) { if (!texture) {
if (!state.defaultTexture) { 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; texture = state.defaultTexture;
@ -933,7 +928,7 @@ void lovrGraphicsBindTexture(Texture* texture) {
if (texture != state.texture) { if (texture != state.texture) {
state.texture = texture; state.texture = texture;
glBindTexture(GL_TEXTURE_2D, texture->id); glBindTexture(texture->type, texture->id);
} }
} }

View File

@ -1,6 +1,5 @@
#include "graphics/font.h" #include "graphics/font.h"
#include "graphics/shader.h" #include "graphics/shader.h"
#include "graphics/skybox.h"
#include "graphics/texture.h" #include "graphics/texture.h"
#include "math/math.h" #include "math/math.h"
#include "lib/glfw.h" #include "lib/glfw.h"
@ -158,8 +157,8 @@ void lovrGraphicsPlane(DrawMode mode, Texture* texture, mat4 transform);
void lovrGraphicsPlaneFullscreen(Texture* texture); void lovrGraphicsPlaneFullscreen(Texture* texture);
void lovrGraphicsBox(DrawMode mode, Texture* texture, mat4 transform); 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 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 lovrGraphicsSphere(mat4 transform, int segments);
void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float az); 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); void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAlign halign, VerticalAlign valign);
// Internal State // Internal State

View File

@ -121,6 +121,7 @@ void lovrMeshDraw(Mesh* mesh, mat4 transform) {
} }
lovrGraphicsSetDefaultShader(SHADER_DEFAULT); lovrGraphicsSetDefaultShader(SHADER_DEFAULT);
lovrGraphicsBindTexture(NULL);
lovrGraphicsPrepare(); lovrGraphicsPrepare();
lovrGraphicsBindVertexArray(mesh->vao); lovrGraphicsBindVertexArray(mesh->vao);
lovrMeshBindAttributes(mesh); lovrMeshBindAttributes(mesh);

View File

@ -1,56 +0,0 @@
#include "graphics/skybox.h"
#include "lib/stb/stb_image.h"
#include <stdlib.h>
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);
}

View File

@ -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);

View File

@ -6,9 +6,9 @@
#include <stdio.h> #include <stdio.h>
static void lovrTextureCreateStorage(Texture* texture) { 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; return;
} }
@ -32,30 +32,50 @@ static void lovrTextureCreateStorage(Texture* texture) {
#endif #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); Texture* texture = lovrAlloc(sizeof(Texture), lovrTextureDestroy);
if (!texture) return NULL; 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->framebuffer = 0;
texture->depthBuffer = 0; texture->depthBuffer = 0;
texture->textureData = textureData;
glGenTextures(1, &texture->id); glGenTextures(1, &texture->id);
lovrGraphicsBindTexture(texture); lovrGraphicsBindTexture(texture);
lovrTextureCreateStorage(texture); lovrTextureCreateStorage(texture);
lovrTextureRefresh(texture); lovrTextureRefresh(texture);
lovrTextureSetFilter(texture, lovrGraphicsGetDefaultFilter()); lovrTextureSetFilter(texture, lovrGraphicsGetDefaultFilter());
WrapMode wrapMode = (type == TEXTURE_CUBE) ? WRAP_CLAMP : WRAP_REPEAT;
lovrTextureSetWrap(texture, WRAP_REPEAT, WRAP_REPEAT); lovrTextureSetWrap(texture, (TextureWrap) { .s = wrapMode, .t = wrapMode, .r = wrapMode });
return texture; return texture;
} }
Texture* lovrTextureCreateWithFramebuffer(TextureData* textureData, TextureProjection projection, int msaa) { Texture* lovrTextureCreateWithFramebuffer(TextureData* textureData, TextureProjection projection, int msaa) {
Texture* texture = lovrTextureCreate(textureData); Texture* texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1);
if (!texture) return NULL; if (!texture) return NULL;
int width = texture->textureData->width; int width = texture->width;
int height = texture->textureData->height; int height = texture->height;
texture->projection = projection; texture->projection = projection;
texture->msaa = msaa; texture->msaa = msaa;
@ -102,7 +122,9 @@ Texture* lovrTextureCreateWithFramebuffer(TextureData* textureData, TextureProje
void lovrTextureDestroy(const Ref* ref) { void lovrTextureDestroy(const Ref* ref) {
Texture* texture = containerof(ref, Texture); Texture* texture = containerof(ref, Texture);
lovrTextureDataDestroy(texture->textureData); for (int i = 0; i < texture->sliceCount; i++) {
lovrTextureDataDestroy(texture->slices[i]);
}
if (texture->framebuffer) { if (texture->framebuffer) {
glDeleteFramebuffers(1, &texture->framebuffer); glDeleteFramebuffers(1, &texture->framebuffer);
} }
@ -112,23 +134,19 @@ void lovrTextureDestroy(const Ref* ref) {
void lovrTextureBindFramebuffer(Texture* texture) { void lovrTextureBindFramebuffer(Texture* texture) {
lovrAssert(texture->framebuffer, "Texture cannot be used as a canvas"); lovrAssert(texture->framebuffer, "Texture cannot be used as a canvas");
int w = texture->textureData->width;
int h = texture->textureData->height;
lovrGraphicsBindFramebuffer(texture->framebuffer); lovrGraphicsBindFramebuffer(texture->framebuffer);
lovrGraphicsSetViewport(0, 0, w, h); lovrGraphicsSetViewport(0, 0, texture->width, texture->height);
if (texture->projection == PROJECTION_ORTHOGRAPHIC) { if (texture->projection == PROJECTION_ORTHOGRAPHIC) {
float projection[16]; 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); lovrGraphicsSetProjection(projection);
} else if (texture->projection == PROJECTION_PERSPECTIVE) { } else if (texture->projection == PROJECTION_PERSPECTIVE) {
mat4 projection = lovrGraphicsGetProjection(); mat4 projection = lovrGraphicsGetProjection();
float b = projection[5]; float b = projection[5];
float c = projection[10]; float c = projection[10];
float d = projection[14]; 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 k = (c - 1.f) / (c + 1.f);
float near = (d * (1.f - k)) / (2.f * k); float near = (d * (1.f - k)) / (2.f * k);
float far = k * near; float far = k * near;
@ -145,51 +163,50 @@ void lovrTextureResolveMSAA(Texture* texture) {
return; return;
} }
int w = texture->textureData->width; int width = texture->width;
int h = texture->textureData->height; int height = texture->height;
glBindFramebuffer(GL_READ_FRAMEBUFFER, texture->framebuffer); glBindFramebuffer(GL_READ_FRAMEBUFFER, texture->framebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, texture->resolveFramebuffer); 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_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
} }
void lovrTextureRefresh(Texture* texture) { void lovrTextureRefresh(Texture* texture) {
TextureData* textureData = texture->textureData;
GLenum glInternalFormat = textureData->format.glInternalFormat;
GLenum glFormat = textureData->format.glFormat;
lovrGraphicsBindTexture(texture); lovrGraphicsBindTexture(texture);
if (textureData->format.compressed) { validateSlices(texture->type, texture->slices, texture->sliceCount);
Mipmap m; int i; texture->width = texture->slices[0]->width;
vec_foreach(&textureData->mipmaps.list, m, i) { texture->height = texture->slices[0]->height;
glCompressedTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, m.width, m.height, 0, m.size, m.data);
} for (int i = 0; i < texture->sliceCount; i++) {
} else { TextureData* textureData = texture->slices[i];
int w = textureData->width; GLenum glInternalFormat = textureData->format.glInternalFormat;
int h = textureData->height; GLenum glFormat = textureData->format.glFormat;
glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, w, h, 0, glFormat, GL_UNSIGNED_BYTE, textureData->data); GLenum binding = (texture->type == TEXTURE_CUBE) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + i : GL_TEXTURE_2D;
if (textureData->mipmaps.generated) {
glGenerateMipmap(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) { TextureFilter lovrTextureGetFilter(Texture* texture) {
return texture->filter; return texture->filter;
} }
void lovrTextureSetFilter(Texture* texture, TextureFilter 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.; float anisotropy = filter.mode == FILTER_ANISOTROPIC ? MAX(filter.anisotropy, 1.) : 1.;
lovrGraphicsBindTexture(texture); lovrGraphicsBindTexture(texture);
texture->filter = filter; texture->filter = filter;
@ -225,15 +242,16 @@ void lovrTextureSetFilter(Texture* texture, TextureFilter filter) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
} }
void lovrTextureGetWrap(Texture* texture, WrapMode* horizontal, WrapMode* vertical) { TextureWrap lovrTextureGetWrap(Texture* texture) {
*horizontal = texture->wrapHorizontal; return texture->wrap;
*vertical = texture->wrapVertical;
} }
void lovrTextureSetWrap(Texture* texture, WrapMode horizontal, WrapMode vertical) { void lovrTextureSetWrap(Texture* texture, TextureWrap wrap) {
texture->wrapHorizontal = horizontal; texture->wrap = wrap;
texture->wrapVertical = vertical;
lovrGraphicsBindTexture(texture); lovrGraphicsBindTexture(texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, horizontal); glTexParameteri(texture->type, GL_TEXTURE_WRAP_S, wrap.s);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vertical); glTexParameteri(texture->type, GL_TEXTURE_WRAP_T, wrap.t);
if (texture->type == TEXTURE_CUBE) {
glTexParameteri(texture->type, GL_TEXTURE_WRAP_R, wrap.r);
}
} }

View File

@ -4,6 +4,11 @@
#pragma once #pragma once
typedef enum {
TEXTURE_2D = GL_TEXTURE_2D,
TEXTURE_CUBE = GL_TEXTURE_CUBE_MAP
} TextureType;
typedef enum { typedef enum {
FILTER_NEAREST, FILTER_NEAREST,
FILTER_BILINEAR, FILTER_BILINEAR,
@ -22,6 +27,12 @@ typedef enum {
WRAP_MIRRORED_REPEAT = GL_MIRRORED_REPEAT WRAP_MIRRORED_REPEAT = GL_MIRRORED_REPEAT
} WrapMode; } WrapMode;
typedef struct {
WrapMode s;
WrapMode t;
WrapMode r;
} TextureWrap;
typedef enum { typedef enum {
PROJECTION_ORTHOGRAPHIC, PROJECTION_ORTHOGRAPHIC,
PROJECTION_PERSPECTIVE PROJECTION_PERSPECTIVE
@ -29,7 +40,11 @@ typedef enum {
typedef struct { typedef struct {
Ref ref; Ref ref;
TextureData* textureData; TextureType type;
TextureData* slices[6];
int sliceCount;
int width;
int height;
GLuint id; GLuint id;
GLuint msaaId; GLuint msaaId;
GLuint framebuffer; GLuint framebuffer;
@ -37,22 +52,19 @@ typedef struct {
GLuint depthBuffer; GLuint depthBuffer;
TextureProjection projection; TextureProjection projection;
TextureFilter filter; TextureFilter filter;
WrapMode wrapHorizontal; TextureWrap wrap;
WrapMode wrapVertical;
int msaa; int msaa;
} Texture; } Texture;
GLenum lovrTextureGetGLFormat(TextureFormat format); 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); Texture* lovrTextureCreateWithFramebuffer(TextureData* textureData, TextureProjection projection, int msaa);
void lovrTextureDestroy(const Ref* ref); void lovrTextureDestroy(const Ref* ref);
void lovrTextureBindFramebuffer(Texture* texture); void lovrTextureBindFramebuffer(Texture* texture);
void lovrTextureResolveMSAA(Texture* texture); void lovrTextureResolveMSAA(Texture* texture);
void lovrTextureRefresh(Texture* texture); void lovrTextureRefresh(Texture* texture);
int lovrTextureGetHeight(Texture* texture);
int lovrTextureGetWidth(Texture* texture);
TextureFilter lovrTextureGetFilter(Texture* texture); TextureFilter lovrTextureGetFilter(Texture* texture);
void lovrTextureSetFilter(Texture* texture, TextureFilter filter); void lovrTextureSetFilter(Texture* texture, TextureFilter filter);
void lovrTextureGetWrap(Texture* texture, WrapMode* horizontal, WrapMode* vertical); TextureWrap lovrTextureGetWrap(Texture* texture);
void lovrTextureSetWrap(Texture* texture, WrapMode horizontal, WrapMode vertical); void lovrTextureSetWrap(Texture* texture, TextureWrap wrap);