diff --git a/src/api/graphics.c b/src/api/graphics.c index b67e8a85..7c717415 100644 --- a/src/api/graphics.c +++ b/src/api/graphics.c @@ -830,6 +830,13 @@ int l_lovrGraphicsNewTexture(lua_State* L) { } } + bool srgb = true; + if (lua_istable(L, count + 1)) { + lua_getfield(L, count + 1, "linear"); + srgb = !lua_toboolean(L, -1); + lua_pop(L, 1); + } + TextureData* slices[6]; for (int i = 0; i < count; i++) { slices[i] = lovrTextureDataFromBlob(blobs[i]); @@ -837,7 +844,7 @@ int l_lovrGraphicsNewTexture(lua_State* L) { } TextureType type = (count == 1) ? TEXTURE_2D : TEXTURE_CUBE; - texture = lovrTextureCreate(type, slices, count); + texture = lovrTextureCreate(type, slices, count, srgb); } luax_pushtype(L, Texture, texture); diff --git a/src/graphics/font.c b/src/graphics/font.c index 88d2d867..4a4a3a5e 100644 --- a/src/graphics/font.c +++ b/src/graphics/font.c @@ -49,7 +49,7 @@ 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(TEXTURE_2D, &textureData, 1); + font->texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, false); lovrTextureSetFilter(font->texture, filter); lovrTextureSetWrap(font->texture, (TextureWrap) { .s = WRAP_CLAMP, .t = WRAP_CLAMP }); diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index 7bc3b6ae..a0e75c36 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -195,12 +195,18 @@ void lovrGraphicsCreateWindow(int w, int h, bool fullscreen, int msaa, const cha glfwSwapInterval(0); glEnable(GL_LINE_SMOOTH); glEnable(GL_PROGRAM_POINT_SIZE); -#endif if (state.gammaCorrect) { glEnable(GL_FRAMEBUFFER_SRGB); } else { glDisable(GL_FRAMEBUFFER_SRGB); } +#else + if (state.gammaCorrect) { + glEnable(GL_FRAMEBUFFER_SRGB_EXT); + } else { + glDisable(GL_FRAMEBUFFER_SRGB_EXT); + } +#endif glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); @@ -1088,7 +1094,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); + state.defaultTexture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, true); } texture = state.defaultTexture; diff --git a/src/graphics/material.c b/src/graphics/material.c index 0aa4d58a..284c6008 100644 --- a/src/graphics/material.c +++ b/src/graphics/material.c @@ -10,7 +10,7 @@ Material* lovrMaterialCreate(MaterialData* materialData, bool isDefault) { for (int i = 0; i < MAX_MATERIAL_TEXTURES; i++) { if (materialData->textures[i]) { - material->textures[i] = lovrTextureCreate(TEXTURE_2D, &materialData->textures[i], 1); + material->textures[i] = lovrTextureCreate(TEXTURE_2D, &materialData->textures[i], 1, true); } else { material->textures[i] = NULL; } diff --git a/src/graphics/texture.c b/src/graphics/texture.c index 6effa086..641159e2 100644 --- a/src/graphics/texture.c +++ b/src/graphics/texture.c @@ -15,7 +15,12 @@ static void lovrTextureCreateStorage(Texture* texture) { int w = textureData->width; int h = textureData->height; int mipmapCount = log2(MAX(w, h)) + 1; - GLenum internalFormat = textureData->format.glInternalFormat; + GLenum internalFormat; + if (lovrGraphicsIsGammaCorrect() && texture->srgb) { + internalFormat = textureData->format.glInternalFormat.srgb; + } else { + internalFormat = textureData->format.glInternalFormat.linear; + } GLenum format = textureData->format.glFormat; #ifndef EMSCRIPTEN if (GLAD_GL_ARB_texture_storage) { @@ -49,7 +54,7 @@ static void validateSlices(TextureType type, TextureData* slices[6], int sliceCo } } -Texture* lovrTextureCreate(TextureType type, TextureData* slices[6], int sliceCount) { +Texture* lovrTextureCreate(TextureType type, TextureData* slices[6], int sliceCount, bool srgb) { Texture* texture = lovrAlloc(sizeof(Texture), lovrTextureDestroy); if (!texture) return NULL; @@ -59,6 +64,7 @@ Texture* lovrTextureCreate(TextureType type, TextureData* slices[6], int sliceCo memcpy(texture->slices, slices, sliceCount * sizeof(TextureData*)); texture->framebuffer = 0; texture->depthBuffer = 0; + texture->srgb = srgb; glGenTextures(1, &texture->id); lovrGraphicsBindTexture(texture, type, 0); lovrTextureCreateStorage(texture); @@ -71,7 +77,7 @@ Texture* lovrTextureCreate(TextureType type, TextureData* slices[6], int sliceCo } Texture* lovrTextureCreateWithFramebuffer(TextureData* textureData, TextureProjection projection, int msaa) { - Texture* texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1); + Texture* texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, true); if (!texture) return NULL; int width = texture->width; @@ -181,7 +187,12 @@ void lovrTextureRefresh(Texture* texture) { for (int i = 0; i < texture->sliceCount; i++) { TextureData* textureData = texture->slices[i]; - GLenum glInternalFormat = textureData->format.glInternalFormat; + GLenum glInternalFormat; + if (lovrGraphicsIsGammaCorrect() && texture->srgb) { + glInternalFormat = textureData->format.glInternalFormat.srgb; + } else { + glInternalFormat = textureData->format.glInternalFormat.linear; + } GLenum glFormat = textureData->format.glFormat; GLenum binding = (texture->type == TEXTURE_CUBE) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + i : GL_TEXTURE_2D; @@ -194,6 +205,7 @@ void lovrTextureRefresh(Texture* texture) { int w = textureData->width; int h = textureData->height; glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, w, h, 0, glFormat, GL_UNSIGNED_BYTE, textureData->data); + printf("%d %d\n", glGetError(), GL_INVALID_OPERATION); if (textureData->mipmaps.generated) { glGenerateMipmap(GL_TEXTURE_2D); // TODO } diff --git a/src/graphics/texture.h b/src/graphics/texture.h index 9818406c..8976c185 100644 --- a/src/graphics/texture.h +++ b/src/graphics/texture.h @@ -54,11 +54,12 @@ typedef struct { TextureFilter filter; TextureWrap wrap; int msaa; + bool srgb; } Texture; GLenum lovrTextureGetGLFormat(TextureFormat format); -Texture* lovrTextureCreate(TextureType type, TextureData* data[6], int count); +Texture* lovrTextureCreate(TextureType type, TextureData* data[6], int count, bool srgb); Texture* lovrTextureCreateWithFramebuffer(TextureData* textureData, TextureProjection projection, int msaa); void lovrTextureDestroy(const Ref* ref); void lovrTextureBindFramebuffer(Texture* texture); diff --git a/src/headset/headset.h b/src/headset/headset.h index 489d3e94..0cad3abf 100644 --- a/src/headset/headset.h +++ b/src/headset/headset.h @@ -97,6 +97,7 @@ typedef struct { // headset implementations extern HeadsetInterface lovrHeadsetOpenVRDriver; +extern HeadsetInterface lovrHeadsetWebVRDriver; extern HeadsetInterface lovrHeadsetFakeDriver; diff --git a/src/loaders/animation.c b/src/loaders/animation.c index 83177e20..033aca56 100644 --- a/src/loaders/animation.c +++ b/src/loaders/animation.c @@ -1,7 +1,7 @@ #include "loaders/animation.h" #include -AnimationData* lovrAnimationDataCreate(const char* name) { +AnimationData* lovrAnimationDataCreate() { AnimationData* animationData = malloc(sizeof(AnimationData)); if (!animationData) return NULL; diff --git a/src/loaders/texture.c b/src/loaders/texture.c index d86b0a2b..4dba1327 100644 --- a/src/loaders/texture.c +++ b/src/loaders/texture.c @@ -7,35 +7,35 @@ #include const TextureFormat FORMAT_RGB = { - .glInternalFormat = GL_RGB, + .glInternalFormat = { GL_RGB, GL_SRGB }, .glFormat = GL_RGB, .compressed = false, .blockBytes = 3 }; const TextureFormat FORMAT_RGBA = { - .glInternalFormat = GL_RGBA, + .glInternalFormat = { GL_RGBA, GL_SRGB_ALPHA }, .glFormat = GL_RGBA, .compressed = false, .blockBytes = 4 }; const TextureFormat FORMAT_DXT1 = { - .glInternalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT, + .glInternalFormat = { GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT }, .glFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT, .compressed = true, .blockBytes = 8 }; const TextureFormat FORMAT_DXT3 = { - .glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, + .glInternalFormat = { GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT }, .glFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, .compressed = true, .blockBytes = 16 }; const TextureFormat FORMAT_DXT5 = { - .glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, + .glInternalFormat = { GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT }, .glFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, .compressed = true, .blockBytes = 16 diff --git a/src/loaders/texture.h b/src/loaders/texture.h index 10f99fa5..e8426ee9 100644 --- a/src/loaders/texture.h +++ b/src/loaders/texture.h @@ -5,8 +5,19 @@ #pragma once +// WEBGL_compressed_texture_s3tc_srgb isn't ratified yet... +#ifdef EMSCRIPTEN +#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F +#endif + typedef struct { - GLenum glInternalFormat; + struct { + GLenum linear; + GLenum srgb; + } glInternalFormat; GLenum glFormat; int blockBytes; bool compressed;