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/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

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

View File

@ -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[];

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) {
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;
}

View File

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

View File

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

View File

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

View File

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

View File

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