TextureData is now named Image!;

The existing Image construct was renamed StorageImage.
This commit is contained in:
bjorn 2021-02-08 20:17:47 -07:00
parent dca79f83f0
commit 8164e0b6e8
23 changed files with 337 additions and 337 deletions

View File

@ -349,18 +349,18 @@ endif()
if(LOVR_ENABLE_DATA) if(LOVR_ENABLE_DATA)
target_sources(lovr PRIVATE target_sources(lovr PRIVATE
src/modules/data/blob.c src/modules/data/blob.c
src/modules/data/image.c
src/modules/data/modelData.c src/modules/data/modelData.c
src/modules/data/modelData_gltf.c src/modules/data/modelData_gltf.c
src/modules/data/modelData_obj.c src/modules/data/modelData_obj.c
src/modules/data/rasterizer.c src/modules/data/rasterizer.c
src/modules/data/sound.c src/modules/data/sound.c
src/modules/data/textureData.c
src/api/l_data.c src/api/l_data.c
src/api/l_data_blob.c src/api/l_data_blob.c
src/api/l_data_image.c
src/api/l_data_modelData.c src/api/l_data_modelData.c
src/api/l_data_rasterizer.c src/api/l_data_rasterizer.c
src/api/l_data_sound.c src/api/l_data_sound.c
src/api/l_data_textureData.c
src/lib/minimp3/minimp3.c src/lib/minimp3/minimp3.c
src/lib/stb/stb_image.c src/lib/stb/stb_image.c
src/lib/stb/stb_truetype.c src/lib/stb/stb_truetype.c

View File

@ -41,6 +41,7 @@ extern const luaL_Reg lovrCylinderShape[];
extern const luaL_Reg lovrDistanceJoint[]; extern const luaL_Reg lovrDistanceJoint[];
extern const luaL_Reg lovrFont[]; extern const luaL_Reg lovrFont[];
extern const luaL_Reg lovrHingeJoint[]; extern const luaL_Reg lovrHingeJoint[];
extern const luaL_Reg lovrImage[];
extern const luaL_Reg lovrMat4[]; extern const luaL_Reg lovrMat4[];
extern const luaL_Reg lovrMaterial[]; extern const luaL_Reg lovrMaterial[];
extern const luaL_Reg lovrMesh[]; extern const luaL_Reg lovrMesh[];
@ -58,7 +59,6 @@ extern const luaL_Reg lovrSource[];
extern const luaL_Reg lovrSphereShape[]; extern const luaL_Reg lovrSphereShape[];
extern const luaL_Reg lovrMeshShape[]; extern const luaL_Reg lovrMeshShape[];
extern const luaL_Reg lovrTexture[]; extern const luaL_Reg lovrTexture[];
extern const luaL_Reg lovrTextureData[];
extern const luaL_Reg lovrThread[]; extern const luaL_Reg lovrThread[];
extern const luaL_Reg lovrVec2[]; extern const luaL_Reg lovrVec2[];
extern const luaL_Reg lovrVec4[]; extern const luaL_Reg lovrVec4[];

View File

@ -3,7 +3,7 @@
#include "data/modelData.h" #include "data/modelData.h"
#include "data/rasterizer.h" #include "data/rasterizer.h"
#include "data/sound.h" #include "data/sound.h"
#include "data/textureData.h" #include "data/image.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -90,37 +90,37 @@ static int l_lovrDataNewSound(lua_State* L) {
return 1; return 1;
} }
static int l_lovrDataNewTextureData(lua_State* L) { static int l_lovrDataNewImage(lua_State* L) {
TextureData* textureData = NULL; Image* image = NULL;
if (lua_type(L, 1) == LUA_TNUMBER) { if (lua_type(L, 1) == LUA_TNUMBER) {
int width = luaL_checkinteger(L, 1); int width = luaL_checkinteger(L, 1);
int height = luaL_checkinteger(L, 2); int height = luaL_checkinteger(L, 2);
TextureFormat format = luax_checkenum(L, 3, TextureFormat, "rgba"); TextureFormat format = luax_checkenum(L, 3, TextureFormat, "rgba");
Blob* blob = lua_isnoneornil(L, 4) ? NULL : luax_checktype(L, 4, Blob); Blob* blob = lua_isnoneornil(L, 4) ? NULL : luax_checktype(L, 4, Blob);
textureData = lovrTextureDataCreate(width, height, blob, 0x0, format); image = lovrImageCreate(width, height, blob, 0x0, format);
} else { } else {
TextureData* source = luax_totype(L, 1, TextureData); Image* source = luax_totype(L, 1, Image);
if (source) { if (source) {
textureData = lovrTextureDataCreate(source->width, source->height, source->blob, 0x0, source->format); image = lovrImageCreate(source->width, source->height, source->blob, 0x0, source->format);
} else { } else {
Blob* blob = luax_readblob(L, 1, "Texture"); Blob* blob = luax_readblob(L, 1, "Texture");
bool flip = lua_isnoneornil(L, 2) ? true : lua_toboolean(L, 2); bool flip = lua_isnoneornil(L, 2) ? true : lua_toboolean(L, 2);
textureData = lovrTextureDataCreateFromBlob(blob, flip); image = lovrImageCreateFromBlob(blob, flip);
lovrRelease(blob, lovrBlobDestroy); lovrRelease(blob, lovrBlobDestroy);
} }
} }
luax_pushtype(L, TextureData, textureData); luax_pushtype(L, Image, image);
lovrRelease(textureData, lovrTextureDataDestroy); lovrRelease(image, lovrImageDestroy);
return 1; return 1;
} }
static const luaL_Reg lovrData[] = { static const luaL_Reg lovrData[] = {
{ "newBlob", l_lovrDataNewBlob }, { "newBlob", l_lovrDataNewBlob },
{ "newImage", l_lovrDataNewImage },
{ "newModelData", l_lovrDataNewModelData }, { "newModelData", l_lovrDataNewModelData },
{ "newRasterizer", l_lovrDataNewRasterizer }, { "newRasterizer", l_lovrDataNewRasterizer },
{ "newSound", l_lovrDataNewSound }, { "newSound", l_lovrDataNewSound },
{ "newTextureData", l_lovrDataNewTextureData },
{ NULL, NULL } { NULL, NULL }
}; };
@ -128,9 +128,9 @@ int luaopen_lovr_data(lua_State* L) {
lua_newtable(L); lua_newtable(L);
luax_register(L, lovrData); luax_register(L, lovrData);
luax_registertype(L, Blob); luax_registertype(L, Blob);
luax_registertype(L, Image);
luax_registertype(L, ModelData); luax_registertype(L, ModelData);
luax_registertype(L, Rasterizer); luax_registertype(L, Rasterizer);
luax_registertype(L, Sound); luax_registertype(L, Sound);
luax_registertype(L, TextureData);
return 1; return 1;
} }

View File

@ -1,57 +1,57 @@
#include "api.h" #include "api.h"
#include "data/textureData.h" #include "data/image.h"
#include "data/blob.h" #include "data/blob.h"
static int l_lovrTextureDataEncode(lua_State* L) { static int l_lovrImageEncode(lua_State* L) {
TextureData* textureData = luax_checktype(L, 1, TextureData); Image* image = luax_checktype(L, 1, Image);
Blob* blob = lovrTextureDataEncode(textureData); Blob* blob = lovrImageEncode(image);
luax_pushtype(L, Blob, blob); luax_pushtype(L, Blob, blob);
return 1; return 1;
} }
static int l_lovrTextureDataGetWidth(lua_State* L) { static int l_lovrImageGetWidth(lua_State* L) {
TextureData* textureData = luax_checktype(L, 1, TextureData); Image* image = luax_checktype(L, 1, Image);
lua_pushinteger(L, textureData->width); lua_pushinteger(L, image->width);
return 1; return 1;
} }
static int l_lovrTextureDataGetHeight(lua_State* L) { static int l_lovrImageGetHeight(lua_State* L) {
TextureData* textureData = luax_checktype(L, 1, TextureData); Image* image = luax_checktype(L, 1, Image);
lua_pushinteger(L, textureData->height); lua_pushinteger(L, image->height);
return 1; return 1;
} }
static int l_lovrTextureDataGetDimensions(lua_State* L) { static int l_lovrImageGetDimensions(lua_State* L) {
TextureData* textureData = luax_checktype(L, 1, TextureData); Image* image = luax_checktype(L, 1, Image);
lua_pushinteger(L, textureData->width); lua_pushinteger(L, image->width);
lua_pushinteger(L, textureData->height); lua_pushinteger(L, image->height);
return 2; return 2;
} }
static int l_lovrTextureDataGetFormat(lua_State* L) { static int l_lovrImageGetFormat(lua_State* L) {
TextureData* textureData = luax_checktype(L, 1, TextureData); Image* image = luax_checktype(L, 1, Image);
luax_pushenum(L, TextureFormat, textureData->format); luax_pushenum(L, TextureFormat, image->format);
return 1; return 1;
} }
static int l_lovrTextureDataPaste(lua_State* L) { static int l_lovrImagePaste(lua_State* L) {
TextureData* textureData = luax_checktype(L, 1, TextureData); Image* image = luax_checktype(L, 1, Image);
TextureData* source = luax_checktype(L, 2, TextureData); Image* source = luax_checktype(L, 2, Image);
uint32_t dx = luaL_optinteger(L, 3, 0); uint32_t dx = luaL_optinteger(L, 3, 0);
uint32_t dy = luaL_optinteger(L, 4, 0); uint32_t dy = luaL_optinteger(L, 4, 0);
uint32_t sx = luaL_optinteger(L, 5, 0); uint32_t sx = luaL_optinteger(L, 5, 0);
uint32_t sy = luaL_optinteger(L, 6, 0); uint32_t sy = luaL_optinteger(L, 6, 0);
uint32_t w = luaL_optinteger(L, 7, source->width); uint32_t w = luaL_optinteger(L, 7, source->width);
uint32_t h = luaL_optinteger(L, 8, source->height); uint32_t h = luaL_optinteger(L, 8, source->height);
lovrTextureDataPaste(textureData, source, dx, dy, sx, sy, w, h); lovrImagePaste(image, source, dx, dy, sx, sy, w, h);
return 0; return 0;
} }
static int l_lovrTextureDataGetPixel(lua_State* L) { static int l_lovrImageGetPixel(lua_State* L) {
TextureData* textureData = luax_checktype(L, 1, TextureData); Image* image = luax_checktype(L, 1, Image);
int x = luaL_checkinteger(L, 2); int x = luaL_checkinteger(L, 2);
int y = luaL_checkinteger(L, 3); int y = luaL_checkinteger(L, 3);
Color color = lovrTextureDataGetPixel(textureData, x, y); Color color = lovrImageGetPixel(image, x, y);
lua_pushnumber(L, color.r); lua_pushnumber(L, color.r);
lua_pushnumber(L, color.g); lua_pushnumber(L, color.g);
lua_pushnumber(L, color.b); lua_pushnumber(L, color.b);
@ -59,8 +59,8 @@ static int l_lovrTextureDataGetPixel(lua_State* L) {
return 4; return 4;
} }
static int l_lovrTextureDataSetPixel(lua_State* L) { static int l_lovrImageSetPixel(lua_State* L) {
TextureData* textureData = luax_checktype(L, 1, TextureData); Image* image = luax_checktype(L, 1, Image);
int x = luaL_checkinteger(L, 2); int x = luaL_checkinteger(L, 2);
int y = luaL_checkinteger(L, 3); int y = luaL_checkinteger(L, 3);
Color color = { Color color = {
@ -69,26 +69,26 @@ static int l_lovrTextureDataSetPixel(lua_State* L) {
luax_optfloat(L, 6, 1.f), luax_optfloat(L, 6, 1.f),
luax_optfloat(L, 7, 1.f) luax_optfloat(L, 7, 1.f)
}; };
lovrTextureDataSetPixel(textureData, x, y, color); lovrImageSetPixel(image, x, y, color);
return 0; return 0;
} }
static int l_lovrTextureDataGetBlob(lua_State* L) { static int l_lovrImageGetBlob(lua_State* L) {
TextureData* textureData = luax_checktype(L, 1, TextureData); Image* image = luax_checktype(L, 1, Image);
Blob* blob = textureData->blob; Blob* blob = image->blob;
luax_pushtype(L, Blob, blob); luax_pushtype(L, Blob, blob);
return 1; return 1;
} }
const luaL_Reg lovrTextureData[] = { const luaL_Reg lovrImage[] = {
{ "encode", l_lovrTextureDataEncode }, { "encode", l_lovrImageEncode },
{ "getWidth", l_lovrTextureDataGetWidth }, { "getWidth", l_lovrImageGetWidth },
{ "getHeight", l_lovrTextureDataGetHeight }, { "getHeight", l_lovrImageGetHeight },
{ "getDimensions", l_lovrTextureDataGetDimensions }, { "getDimensions", l_lovrImageGetDimensions },
{ "getFormat", l_lovrTextureDataGetFormat }, { "getFormat", l_lovrImageGetFormat },
{ "paste", l_lovrTextureDataPaste }, { "paste", l_lovrImagePaste },
{ "getPixel", l_lovrTextureDataGetPixel }, { "getPixel", l_lovrImageGetPixel },
{ "setPixel", l_lovrTextureDataSetPixel }, { "setPixel", l_lovrImageSetPixel },
{ "getBlob", l_lovrTextureDataGetBlob }, { "getBlob", l_lovrImageGetBlob },
{ NULL, NULL } { NULL, NULL }
}; };

View File

@ -9,7 +9,7 @@
#include "data/blob.h" #include "data/blob.h"
#include "data/modelData.h" #include "data/modelData.h"
#include "data/rasterizer.h" #include "data/rasterizer.h"
#include "data/textureData.h" #include "data/image.h"
#include "core/os.h" #include "core/os.h"
#include "core/util.h" #include "core/util.h"
#include <math.h> #include <math.h>
@ -304,18 +304,18 @@ static void stencilCallback(void* userdata) {
} }
// Must be released when done // Must be released when done
static TextureData* luax_checktexturedata(lua_State* L, int index, bool flip) { static Image* luax_checkimage(lua_State* L, int index, bool flip) {
TextureData* textureData = luax_totype(L, index, TextureData); Image* image = luax_totype(L, index, Image);
if (textureData) { if (image) {
lovrRetain(textureData); lovrRetain(image);
} else { } else {
Blob* blob = luax_readblob(L, index, "Texture"); Blob* blob = luax_readblob(L, index, "Texture");
textureData = lovrTextureDataCreateFromBlob(blob, flip); image = lovrImageCreateFromBlob(blob, flip);
lovrRelease(blob, lovrBlobDestroy); lovrRelease(blob, lovrBlobDestroy);
} }
return textureData; return image;
} }
// Base // Base
@ -360,12 +360,12 @@ static int l_lovrGraphicsCreateWindow(lua_State* L) {
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "icon"); lua_getfield(L, 1, "icon");
TextureData* textureData = NULL; Image* image = NULL;
if (!lua_isnil(L, -1)) { if (!lua_isnil(L, -1)) {
textureData = luax_checktexturedata(L, -1, false); image = luax_checkimage(L, -1, false);
flags.icon.data = textureData->blob->data; flags.icon.data = image->blob->data;
flags.icon.width = textureData->width; flags.icon.width = image->width;
flags.icon.height = textureData->height; flags.icon.height = image->height;
} }
lua_pop(L, 1); lua_pop(L, 1);
@ -375,7 +375,7 @@ static int l_lovrGraphicsCreateWindow(lua_State* L) {
lovrGraphicsCreateWindow(&flags); lovrGraphicsCreateWindow(&flags);
luax_atexit(L, lovrGraphicsDestroy); // The lua_State that creates the window shall be the one to destroy it luax_atexit(L, lovrGraphicsDestroy); // The lua_State that creates the window shall be the one to destroy it
lovrRelease(textureData, lovrTextureDataDestroy); lovrRelease(image, lovrImageDestroy);
return 0; return 0;
} }
@ -1262,11 +1262,11 @@ static int l_lovrGraphicsNewMaterial(lua_State* L) {
if (lua_type(L, index) == LUA_TSTRING) { if (lua_type(L, index) == LUA_TSTRING) {
Blob* blob = luax_readblob(L, index++, "Texture"); Blob* blob = luax_readblob(L, index++, "Texture");
TextureData* textureData = lovrTextureDataCreateFromBlob(blob, true); Image* image = lovrImageCreateFromBlob(blob, true);
Texture* texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, true, true, 0); Texture* texture = lovrTextureCreate(TEXTURE_2D, &image, 1, true, true, 0);
lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture); lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture);
lovrRelease(blob, lovrBlobDestroy); lovrRelease(blob, lovrBlobDestroy);
lovrRelease(textureData, lovrTextureDataDestroy); lovrRelease(image, lovrImageDestroy);
lovrRelease(texture, lovrTextureDestroy); lovrRelease(texture, lovrTextureDestroy);
} else if (lua_isuserdata(L, index)) { } else if (lua_isuserdata(L, index)) {
Texture* texture = luax_checktype(L, index, Texture); Texture* texture = luax_checktype(L, index, Texture);
@ -1710,12 +1710,12 @@ static int l_lovrGraphicsNewTexture(lua_State* L) {
for (int i = 0; i < depth; i++) { for (int i = 0; i < depth; i++) {
lua_rawgeti(L, 1, i + 1); lua_rawgeti(L, 1, i + 1);
TextureData* textureData = luax_checktexturedata(L, -1, type != TEXTURE_CUBE); Image* image = luax_checkimage(L, -1, type != TEXTURE_CUBE);
if (i == 0) { if (i == 0) {
lovrTextureAllocate(texture, textureData->width, textureData->height, depth, textureData->format); lovrTextureAllocate(texture, image->width, image->height, depth, image->format);
} }
lovrTextureReplacePixels(texture, textureData, 0, 0, i, 0); lovrTextureReplacePixels(texture, image, 0, 0, i, 0);
lovrRelease(textureData, lovrTextureDataDestroy); lovrRelease(image, lovrImageDestroy);
lua_pop(L, 1); lua_pop(L, 1);
} }
} }

View File

@ -50,15 +50,15 @@ void luax_readattachments(lua_State* L, int index, Attachment* attachments, int*
} }
} }
static int l_lovrCanvasNewTextureData(lua_State* L) { static int l_lovrCanvasNewImage(lua_State* L) {
Canvas* canvas = luax_checktype(L, 1, Canvas); Canvas* canvas = luax_checktype(L, 1, Canvas);
uint32_t index = luaL_optinteger(L, 2, 1) - 1; uint32_t index = luaL_optinteger(L, 2, 1) - 1;
uint32_t count; uint32_t count;
lovrCanvasGetAttachments(canvas, &count); lovrCanvasGetAttachments(canvas, &count);
lovrAssert(index < count, "Can not create a TextureData from Texture #%d of Canvas (it only has %d textures)", index, count); lovrAssert(index < count, "Can not create an Image from Texture #%d of Canvas (it only has %d textures)", index, count);
TextureData* textureData = lovrCanvasNewTextureData(canvas, index); Image* image = lovrCanvasNewImage(canvas, index);
luax_pushtype(L, TextureData, textureData); luax_pushtype(L, Image, image);
lovrRelease(textureData, lovrTextureDataDestroy); lovrRelease(image, lovrImageDestroy);
return 1; return 1;
} }
@ -133,7 +133,7 @@ static int l_lovrCanvasIsStereo(lua_State* L) {
} }
const luaL_Reg lovrCanvas[] = { const luaL_Reg lovrCanvas[] = {
{ "newTextureData", l_lovrCanvasNewTextureData }, { "newImage", l_lovrCanvasNewImage },
{ "renderTo", l_lovrCanvasRenderTo }, { "renderTo", l_lovrCanvasRenderTo },
{ "getTexture", l_lovrCanvasGetTexture }, { "getTexture", l_lovrCanvasGetTexture },
{ "setTexture", l_lovrCanvasSetTexture }, { "setTexture", l_lovrCanvasSetTexture },

View File

@ -71,13 +71,13 @@ int luax_checkuniform(lua_State* L, int index, const Uniform* uniform, void* des
} }
case UNIFORM_IMAGE: { case UNIFORM_IMAGE: {
Image* image = (Image*) dest + i; StorageImage* image = (StorageImage*) dest + i;
image->texture = luax_checktype(L, j, Texture); image->texture = luax_checktype(L, j, Texture);
image->slice = -1; image->slice = -1;
image->mipmap = 0; image->mipmap = 0;
image->access = ACCESS_READ_WRITE; image->access = ACCESS_READ_WRITE;
TextureType type = lovrTextureGetType(image->texture); TextureType type = lovrTextureGetType(image->texture);
lovrAssert(type == uniform->textureType, "Attempt to send %s texture to %s image uniform", lovrTextureType[type], lovrTextureType[uniform->textureType]); lovrAssert(type == uniform->textureType, "Attempt to send %s texture to %s storage image uniform", lovrTextureType[type], lovrTextureType[uniform->textureType]);
break; break;
} }
@ -256,7 +256,7 @@ static int l_lovrShaderSendImage(lua_State* L) {
int slice = luaL_optinteger(L, index++, 0) - 1; // Default is -1 int slice = luaL_optinteger(L, index++, 0) - 1; // Default is -1
int mipmap = luax_optmipmap(L, index++, texture); int mipmap = luax_optmipmap(L, index++, texture);
UniformAccess access = luax_checkenum(L, index++, UniformAccess, "readwrite"); UniformAccess access = luax_checkenum(L, index++, UniformAccess, "readwrite");
Image image = { .texture = texture, .slice = slice, .mipmap = mipmap, .access = access }; StorageImage image = { .texture = texture, .slice = slice, .mipmap = mipmap, .access = access };
lovrShaderSetImages(shader, name, &image, start, 1); lovrShaderSetImages(shader, name, &image, start, 1);
return 0; return 0;
} }

View File

@ -83,12 +83,12 @@ static int l_lovrTextureGetWrap(lua_State* L) {
static int l_lovrTextureReplacePixels(lua_State* L) { static int l_lovrTextureReplacePixels(lua_State* L) {
Texture* texture = luax_checktype(L, 1, Texture); Texture* texture = luax_checktype(L, 1, Texture);
TextureData* textureData = luax_checktype(L, 2, TextureData); Image* image = luax_checktype(L, 2, Image);
int x = luaL_optinteger(L, 3, 0); int x = luaL_optinteger(L, 3, 0);
int y = luaL_optinteger(L, 4, 0); int y = luaL_optinteger(L, 4, 0);
int slice = luaL_optinteger(L, 5, 1) - 1; int slice = luaL_optinteger(L, 5, 1) - 1;
int mipmap = luaL_optinteger(L, 6, 1) - 1; int mipmap = luaL_optinteger(L, 6, 1) - 1;
lovrTextureReplacePixels(texture, textureData, x, y, slice, mipmap); lovrTextureReplacePixels(texture, image, x, y, slice, mipmap);
return 0; return 0;
} }

View File

@ -1,4 +1,4 @@
#include "data/textureData.h" #include "data/image.h"
#include "data/blob.h" #include "data/blob.h"
#include "lib/stb/stb_image.h" #include "lib/stb/stb_image.h"
#include <stdlib.h> #include <stdlib.h>
@ -32,7 +32,7 @@ static size_t getPixelSize(TextureFormat format) {
} }
// Modified from ddsparse (https://bitbucket.org/slime73/ddsparse) // Modified from ddsparse (https://bitbucket.org/slime73/ddsparse)
static bool parseDDS(uint8_t* data, size_t size, TextureData* textureData) { static bool parseDDS(uint8_t* data, size_t size, Image* image) {
enum { enum {
DDPF_ALPHAPIXELS = 0x000001, DDPF_ALPHAPIXELS = 0x000001,
DDPF_ALPHA = 0x000002, DDPF_ALPHA = 0x000002,
@ -255,17 +255,17 @@ static bool parseDDS(uint8_t* data, size_t size, TextureData* textureData) {
case DXGI_FORMAT_BC1_TYPELESS: case DXGI_FORMAT_BC1_TYPELESS:
case DXGI_FORMAT_BC1_UNORM: case DXGI_FORMAT_BC1_UNORM:
case DXGI_FORMAT_BC1_UNORM_SRGB: case DXGI_FORMAT_BC1_UNORM_SRGB:
textureData->format = FORMAT_DXT1; image->format = FORMAT_DXT1;
break; break;
case DXGI_FORMAT_BC2_TYPELESS: case DXGI_FORMAT_BC2_TYPELESS:
case DXGI_FORMAT_BC2_UNORM: case DXGI_FORMAT_BC2_UNORM:
case DXGI_FORMAT_BC2_UNORM_SRGB: case DXGI_FORMAT_BC2_UNORM_SRGB:
textureData->format = FORMAT_DXT3; image->format = FORMAT_DXT3;
break; break;
case DXGI_FORMAT_BC3_TYPELESS: case DXGI_FORMAT_BC3_TYPELESS:
case DXGI_FORMAT_BC3_UNORM: case DXGI_FORMAT_BC3_UNORM:
case DXGI_FORMAT_BC3_UNORM_SRGB: case DXGI_FORMAT_BC3_UNORM_SRGB:
textureData->format = FORMAT_DXT5; image->format = FORMAT_DXT5;
break; break;
default: default:
return 1; return 1;
@ -277,20 +277,20 @@ static bool parseDDS(uint8_t* data, size_t size, TextureData* textureData) {
// Ensure DXT 1/3/5 // Ensure DXT 1/3/5
switch (header->format.fourCC) { switch (header->format.fourCC) {
case FOUR_CC('D', 'X', 'T', '1'): textureData->format = FORMAT_DXT1; break; case FOUR_CC('D', 'X', 'T', '1'): image->format = FORMAT_DXT1; break;
case FOUR_CC('D', 'X', 'T', '3'): textureData->format = FORMAT_DXT3; break; case FOUR_CC('D', 'X', 'T', '3'): image->format = FORMAT_DXT3; break;
case FOUR_CC('D', 'X', 'T', '5'): textureData->format = FORMAT_DXT5; break; case FOUR_CC('D', 'X', 'T', '5'): image->format = FORMAT_DXT5; break;
default: return false; default: return false;
} }
} }
uint32_t width = textureData->width = header->width; uint32_t width = image->width = header->width;
uint32_t height = textureData->height = header->height; uint32_t height = image->height = header->height;
uint32_t mipmapCount = textureData->mipmapCount = MAX(header->mipMapCount, 1); uint32_t mipmapCount = image->mipmapCount = MAX(header->mipMapCount, 1);
textureData->mipmaps = malloc(mipmapCount * sizeof(Mipmap)); image->mipmaps = malloc(mipmapCount * sizeof(Mipmap));
size_t blockBytes = 0; size_t blockBytes = 0;
switch (textureData->format) { switch (image->format) {
case FORMAT_DXT1: blockBytes = 8; break; case FORMAT_DXT1: blockBytes = 8; break;
case FORMAT_DXT3: blockBytes = 16; break; case FORMAT_DXT3: blockBytes = 16; break;
case FORMAT_DXT5: blockBytes = 16; break; case FORMAT_DXT5: blockBytes = 16; break;
@ -305,22 +305,22 @@ static bool parseDDS(uint8_t* data, size_t size, TextureData* textureData) {
// Overflow check // Overflow check
if (mipmapSize == 0 || (offset + mipmapSize) > size) { if (mipmapSize == 0 || (offset + mipmapSize) > size) {
free(textureData->mipmaps); free(image->mipmaps);
return false; return false;
} }
textureData->mipmaps[i] = (Mipmap) { .width = width, .height = height, .data = &data[offset], .size = mipmapSize }; image->mipmaps[i] = (Mipmap) { .width = width, .height = height, .data = &data[offset], .size = mipmapSize };
offset += mipmapSize; offset += mipmapSize;
width = MAX(width >> 1, 1); width = MAX(width >> 1, 1);
height = MAX(height >> 1, 1); height = MAX(height >> 1, 1);
} }
textureData->blob->data = NULL; image->blob->data = NULL;
return true; return true;
} }
static bool parseKTX(uint8_t* bytes, size_t size, TextureData* textureData) { static bool parseKTX(uint8_t* bytes, size_t size, Image* image) {
typedef struct { typedef struct {
uint8_t magic[12]; uint8_t magic[12];
uint32_t endianness; uint32_t endianness;
@ -356,34 +356,34 @@ static bool parseKTX(uint8_t* bytes, size_t size, TextureData* textureData) {
// TODO MOAR FORMATS, GIMME COOOBMAPS // TODO MOAR FORMATS, GIMME COOOBMAPS
switch (data.ktx->glInternalFormat) { switch (data.ktx->glInternalFormat) {
case 0x83F0: textureData->format = FORMAT_DXT1; break; case 0x83F0: image->format = FORMAT_DXT1; break;
case 0x83F2: textureData->format = FORMAT_DXT3; break; case 0x83F2: image->format = FORMAT_DXT3; break;
case 0x83F3: textureData->format = FORMAT_DXT5; break; case 0x83F3: image->format = FORMAT_DXT5; break;
case 0x93B0: case 0x93D0: textureData->format = FORMAT_ASTC_4x4; break; case 0x93B0: case 0x93D0: image->format = FORMAT_ASTC_4x4; break;
case 0x93B1: case 0x93D1: textureData->format = FORMAT_ASTC_5x4; break; case 0x93B1: case 0x93D1: image->format = FORMAT_ASTC_5x4; break;
case 0x93B2: case 0x93D2: textureData->format = FORMAT_ASTC_5x5; break; case 0x93B2: case 0x93D2: image->format = FORMAT_ASTC_5x5; break;
case 0x93B3: case 0x93D3: textureData->format = FORMAT_ASTC_6x5; break; case 0x93B3: case 0x93D3: image->format = FORMAT_ASTC_6x5; break;
case 0x93B4: case 0x93D4: textureData->format = FORMAT_ASTC_6x6; break; case 0x93B4: case 0x93D4: image->format = FORMAT_ASTC_6x6; break;
case 0x93B5: case 0x93D5: textureData->format = FORMAT_ASTC_8x5; break; case 0x93B5: case 0x93D5: image->format = FORMAT_ASTC_8x5; break;
case 0x93B6: case 0x93D6: textureData->format = FORMAT_ASTC_8x6; break; case 0x93B6: case 0x93D6: image->format = FORMAT_ASTC_8x6; break;
case 0x93B7: case 0x93D7: textureData->format = FORMAT_ASTC_8x8; break; case 0x93B7: case 0x93D7: image->format = FORMAT_ASTC_8x8; break;
case 0x93B8: case 0x93D8: textureData->format = FORMAT_ASTC_10x5; break; case 0x93B8: case 0x93D8: image->format = FORMAT_ASTC_10x5; break;
case 0x93B9: case 0x93D9: textureData->format = FORMAT_ASTC_10x6; break; case 0x93B9: case 0x93D9: image->format = FORMAT_ASTC_10x6; break;
case 0x93BA: case 0x93DA: textureData->format = FORMAT_ASTC_10x8; break; case 0x93BA: case 0x93DA: image->format = FORMAT_ASTC_10x8; break;
case 0x93BB: case 0x93DB: textureData->format = FORMAT_ASTC_10x10; break; case 0x93BB: case 0x93DB: image->format = FORMAT_ASTC_10x10; break;
case 0x93BC: case 0x93DC: textureData->format = FORMAT_ASTC_12x10; break; case 0x93BC: case 0x93DC: image->format = FORMAT_ASTC_12x10; break;
case 0x93BD: case 0x93DD: textureData->format = FORMAT_ASTC_12x12; break; case 0x93BD: case 0x93DD: image->format = FORMAT_ASTC_12x12; break;
default: lovrThrow("Unsupported KTX format '%d' (please open an issue)", data.ktx->glInternalFormat); default: lovrThrow("Unsupported KTX format '%d' (please open an issue)", data.ktx->glInternalFormat);
} }
uint32_t width = textureData->width = data.ktx->pixelWidth; uint32_t width = image->width = data.ktx->pixelWidth;
uint32_t height = textureData->height = data.ktx->pixelHeight; uint32_t height = image->height = data.ktx->pixelHeight;
uint32_t mipmapCount = textureData->mipmapCount = data.ktx->numberOfMipmapLevels; uint32_t mipmapCount = image->mipmapCount = data.ktx->numberOfMipmapLevels;
textureData->mipmaps = malloc(mipmapCount * sizeof(Mipmap)); image->mipmaps = malloc(mipmapCount * sizeof(Mipmap));
data.u8 += sizeof(KTXHeader) + data.ktx->bytesOfKeyValueData; data.u8 += sizeof(KTXHeader) + data.ktx->bytesOfKeyValueData;
for (uint32_t i = 0; i < mipmapCount; i++) { for (uint32_t i = 0; i < mipmapCount; i++) {
textureData->mipmaps[i] = (Mipmap) { .width = width, .height = height, .data = data.u8 + sizeof(uint32_t), .size = *data.u32 }; image->mipmaps[i] = (Mipmap) { .width = width, .height = height, .data = data.u8 + sizeof(uint32_t), .size = *data.u32 };
width = MAX(width >> 1, 1u); width = MAX(width >> 1, 1u);
height = MAX(height >> 1, 1u); height = MAX(height >> 1, 1u);
data.u8 = (uint8_t*) ALIGN(data.u8 + sizeof(uint32_t) + *data.u32, 4); data.u8 = (uint8_t*) ALIGN(data.u8 + sizeof(uint32_t) + *data.u32, 4);
@ -392,7 +392,7 @@ static bool parseKTX(uint8_t* bytes, size_t size, TextureData* textureData) {
return true; return true;
} }
static bool parseASTC(uint8_t* bytes, size_t size, TextureData* textureData) { static bool parseASTC(uint8_t* bytes, size_t size, Image* image) {
typedef struct { typedef struct {
uint32_t magic; uint32_t magic;
uint8_t blockX; uint8_t blockX;
@ -416,36 +416,36 @@ static bool parseASTC(uint8_t* bytes, size_t size, TextureData* textureData) {
} }
uint32_t bx = data.astc->blockX, by = data.astc->blockY, bz = data.astc->blockZ; uint32_t bx = data.astc->blockX, by = data.astc->blockY, bz = data.astc->blockZ;
if (bx == 4 && by == 4 && bz == 1) { textureData->format = FORMAT_ASTC_4x4; } if (bx == 4 && by == 4 && bz == 1) { image->format = FORMAT_ASTC_4x4; }
else if (bx == 5 && by == 4 && bz == 1) { textureData->format = FORMAT_ASTC_5x4; } else if (bx == 5 && by == 4 && bz == 1) { image->format = FORMAT_ASTC_5x4; }
else if (bx == 5 && by == 5 && bz == 1) { textureData->format = FORMAT_ASTC_5x5; } else if (bx == 5 && by == 5 && bz == 1) { image->format = FORMAT_ASTC_5x5; }
else if (bx == 6 && by == 5 && bz == 1) { textureData->format = FORMAT_ASTC_6x5; } else if (bx == 6 && by == 5 && bz == 1) { image->format = FORMAT_ASTC_6x5; }
else if (bx == 6 && by == 6 && bz == 1) { textureData->format = FORMAT_ASTC_6x6; } else if (bx == 6 && by == 6 && bz == 1) { image->format = FORMAT_ASTC_6x6; }
else if (bx == 8 && by == 5 && bz == 1) { textureData->format = FORMAT_ASTC_8x5; } else if (bx == 8 && by == 5 && bz == 1) { image->format = FORMAT_ASTC_8x5; }
else if (bx == 8 && by == 6 && bz == 1) { textureData->format = FORMAT_ASTC_8x6; } else if (bx == 8 && by == 6 && bz == 1) { image->format = FORMAT_ASTC_8x6; }
else if (bx == 8 && by == 8 && bz == 1) { textureData->format = FORMAT_ASTC_8x8; } else if (bx == 8 && by == 8 && bz == 1) { image->format = FORMAT_ASTC_8x8; }
else if (bx == 10 && by == 5 && bz == 1) { textureData->format = FORMAT_ASTC_10x5; } else if (bx == 10 && by == 5 && bz == 1) { image->format = FORMAT_ASTC_10x5; }
else if (bx == 10 && by == 6 && bz == 1) { textureData->format = FORMAT_ASTC_10x6; } else if (bx == 10 && by == 6 && bz == 1) { image->format = FORMAT_ASTC_10x6; }
else if (bx == 10 && by == 8 && bz == 1) { textureData->format = FORMAT_ASTC_10x8; } else if (bx == 10 && by == 8 && bz == 1) { image->format = FORMAT_ASTC_10x8; }
else if (bx == 10 && by == 10 && bz == 1) { textureData->format = FORMAT_ASTC_10x10; } else if (bx == 10 && by == 10 && bz == 1) { image->format = FORMAT_ASTC_10x10; }
else if (bx == 12 && by == 10 && bz == 1) { textureData->format = FORMAT_ASTC_12x10; } else if (bx == 12 && by == 10 && bz == 1) { image->format = FORMAT_ASTC_12x10; }
else if (bx == 12 && by == 12 && bz == 1) { textureData->format = FORMAT_ASTC_12x12; } else if (bx == 12 && by == 12 && bz == 1) { image->format = FORMAT_ASTC_12x12; }
else { lovrThrow("Unsupported ASTC format %dx%dx%d", bx, by, bz); } else { lovrThrow("Unsupported ASTC format %dx%dx%d", bx, by, bz); }
textureData->width = data.astc->width[0] + (data.astc->width[1] << 8) + (data.astc->width[2] << 16); image->width = data.astc->width[0] + (data.astc->width[1] << 8) + (data.astc->width[2] << 16);
textureData->height = data.astc->height[0] + (data.astc->height[1] << 8) + (data.astc->height[2] << 16); image->height = data.astc->height[0] + (data.astc->height[1] << 8) + (data.astc->height[2] << 16);
size_t imageSize = ((textureData->width + bx - 1) / bx) * ((textureData->height + by - 1) / by) * (128 / 8); size_t imageSize = ((image->width + bx - 1) / bx) * ((image->height + by - 1) / by) * (128 / 8);
if (imageSize > size - sizeof(ASTCHeader)) { if (imageSize > size - sizeof(ASTCHeader)) {
return false; return false;
} }
textureData->mipmapCount = 1; image->mipmapCount = 1;
textureData->mipmaps = malloc(sizeof(Mipmap)); image->mipmaps = malloc(sizeof(Mipmap));
textureData->mipmaps[0] = (Mipmap) { image->mipmaps[0] = (Mipmap) {
.width = textureData->width, .width = image->width,
.height = textureData->height, .height = image->height,
.data = data.u8 + sizeof(ASTCHeader), .data = data.u8 + sizeof(ASTCHeader),
.size = imageSize .size = imageSize
}; };
@ -453,18 +453,18 @@ static bool parseASTC(uint8_t* bytes, size_t size, TextureData* textureData) {
return true; return true;
} }
TextureData* lovrTextureDataCreate(uint32_t width, uint32_t height, Blob* contents, uint8_t value, TextureFormat format) { Image* lovrImageCreate(uint32_t width, uint32_t height, Blob* contents, uint8_t value, TextureFormat format) {
TextureData* textureData = calloc(1, sizeof(TextureData)); Image* image = calloc(1, sizeof(Image));
lovrAssert(textureData, "Out of memory"); lovrAssert(image, "Out of memory");
textureData->ref = 1; image->ref = 1;
size_t pixelSize = getPixelSize(format); size_t pixelSize = getPixelSize(format);
size_t size = width * height * pixelSize; size_t size = width * height * pixelSize;
lovrAssert(width > 0 && height > 0, "TextureData dimensions must be positive"); lovrAssert(width > 0 && height > 0, "Image dimensions must be positive");
lovrAssert(format < FORMAT_DXT1, "Blank TextureData cannot be compressed"); lovrAssert(format < FORMAT_DXT1, "Blank images cannot be compressed");
lovrAssert(!contents || contents->size >= size, "TextureData Blob is too small (%d bytes needed, got %d)", size, contents->size); lovrAssert(!contents || contents->size >= size, "Image Blob is too small (%d bytes needed, got %d)", size, contents->size);
textureData->width = width; image->width = width;
textureData->height = height; image->height = height;
textureData->format = format; image->format = format;
void* data = malloc(size); void* data = malloc(size);
lovrAssert(data, "Out of memory"); lovrAssert(data, "Out of memory");
if (contents) { if (contents) {
@ -472,27 +472,27 @@ TextureData* lovrTextureDataCreate(uint32_t width, uint32_t height, Blob* conten
} else { } else {
memset(data, value, size); memset(data, value, size);
} }
textureData->blob = lovrBlobCreate(data, size, "TextureData plain"); image->blob = lovrBlobCreate(data, size, "Image");
return textureData; return image;
} }
TextureData* lovrTextureDataCreateFromBlob(Blob* blob, bool flip) { Image* lovrImageCreateFromBlob(Blob* blob, bool flip) {
TextureData* textureData = calloc(1, sizeof(TextureData)); Image* image = calloc(1, sizeof(Image));
lovrAssert(textureData, "Out of memory"); lovrAssert(image, "Out of memory");
textureData->ref = 1; image->ref = 1;
textureData->blob = lovrBlobCreate(NULL, 0, NULL); image->blob = lovrBlobCreate(NULL, 0, NULL);
if (parseDDS(blob->data, blob->size, textureData)) { if (parseDDS(blob->data, blob->size, image)) {
textureData->source = blob; image->source = blob;
lovrRetain(blob); lovrRetain(blob);
return textureData; return image;
} else if (parseKTX(blob->data, blob->size, textureData)) { } else if (parseKTX(blob->data, blob->size, image)) {
textureData->source = blob; image->source = blob;
lovrRetain(blob); lovrRetain(blob);
return textureData; return image;
} else if (parseASTC(blob->data, blob->size, textureData)) { } else if (parseASTC(blob->data, blob->size, image)) {
textureData->source = blob; image->source = blob;
lovrRetain(blob); lovrRetain(blob);
return textureData; return image;
} }
int width, height; int width, height;
@ -500,71 +500,79 @@ TextureData* lovrTextureDataCreateFromBlob(Blob* blob, bool flip) {
stbi_set_flip_vertically_on_load_thread(flip); stbi_set_flip_vertically_on_load_thread(flip);
if (stbi_is_16_bit_from_memory(blob->data, length)) { if (stbi_is_16_bit_from_memory(blob->data, length)) {
int channels; int channels;
textureData->blob->data = stbi_load_16_from_memory(blob->data, length, &width, &height, &channels, 0); image->blob->data = stbi_load_16_from_memory(blob->data, length, &width, &height, &channels, 0);
switch (channels) { switch (channels) {
case 1: case 1:
textureData->format = FORMAT_R16; image->format = FORMAT_R16;
textureData->blob->size = 2 * width * height; image->blob->size = 2 * width * height;
break; break;
case 2: case 2:
textureData->format = FORMAT_RG16; image->format = FORMAT_RG16;
textureData->blob->size = 4 * width * height; image->blob->size = 4 * width * height;
break; break;
case 4: case 4:
textureData->format = FORMAT_RGBA16; image->format = FORMAT_RGBA16;
textureData->blob->size = 8 * width * height; image->blob->size = 8 * width * height;
break; break;
default: default:
lovrThrow("Unsupported channel count for 16 bit image: %d", channels); lovrThrow("Unsupported channel count for 16 bit image: %d", channels);
} }
} else if (stbi_is_hdr_from_memory(blob->data, length)) { } else if (stbi_is_hdr_from_memory(blob->data, length)) {
textureData->format = FORMAT_RGBA32F; image->format = FORMAT_RGBA32F;
textureData->blob->data = stbi_loadf_from_memory(blob->data, length, &width, &height, NULL, 4); image->blob->data = stbi_loadf_from_memory(blob->data, length, &width, &height, NULL, 4);
textureData->blob->size = 16 * width * height; image->blob->size = 16 * width * height;
} else { } else {
textureData->format = FORMAT_RGBA; image->format = FORMAT_RGBA;
textureData->blob->data = stbi_load_from_memory(blob->data, length, &width, &height, NULL, 4); image->blob->data = stbi_load_from_memory(blob->data, length, &width, &height, NULL, 4);
textureData->blob->size = 4 * width * height; image->blob->size = 4 * width * height;
} }
if (!textureData->blob->data) { if (!image->blob->data) {
lovrThrow("Could not load texture data from '%s'", blob->name); lovrThrow("Could not load image from '%s'", blob->name);
lovrRelease(textureData->blob, lovrBlobDestroy); lovrRelease(image->blob, lovrBlobDestroy);
free(textureData); free(image);
return NULL; return NULL;
} }
textureData->width = width; image->width = width;
textureData->height = height; image->height = height;
textureData->mipmapCount = 0; image->mipmapCount = 0;
return textureData; return image;
} }
Color lovrTextureDataGetPixel(TextureData* textureData, uint32_t x, uint32_t y) { void lovrImageDestroy(void* ref) {
lovrAssert(textureData->blob->data, "TextureData does not have any pixel data"); Image* image = ref;
lovrAssert(x < textureData->width && y < textureData->height, "getPixel coordinates must be within TextureData bounds"); lovrRelease(image->source, lovrBlobDestroy);
size_t index = (textureData->height - (y + 1)) * textureData->width + x; free(image->mipmaps);
size_t pixelSize = getPixelSize(textureData->format); lovrRelease(image->blob, lovrBlobDestroy);
uint8_t* u8 = (uint8_t*) textureData->blob->data + pixelSize * index; free(image);
}
Color lovrImageGetPixel(Image* image, uint32_t x, uint32_t y) {
lovrAssert(image->blob->data, "Image does not have any pixel data");
lovrAssert(x < image->width && y < image->height, "getPixel coordinates must be within Image bounds");
size_t index = (image->height - (y + 1)) * image->width + x;
size_t pixelSize = getPixelSize(image->format);
uint8_t* u8 = (uint8_t*) image->blob->data + pixelSize * index;
float* f32 = (float*) u8; float* f32 = (float*) u8;
switch (textureData->format) { switch (image->format) {
case FORMAT_RGB: return (Color) { u8[0] / 255.f, u8[1] / 255.f, u8[2] / 255.f, 1.f }; case FORMAT_RGB: return (Color) { u8[0] / 255.f, u8[1] / 255.f, u8[2] / 255.f, 1.f };
case FORMAT_RGBA: return (Color) { u8[0] / 255.f, u8[1] / 255.f, u8[2] / 255.f, u8[3] / 255.f }; case FORMAT_RGBA: return (Color) { u8[0] / 255.f, u8[1] / 255.f, u8[2] / 255.f, u8[3] / 255.f };
case FORMAT_RGBA32F: return (Color) { f32[0], f32[1], f32[2], f32[3] }; case FORMAT_RGBA32F: return (Color) { f32[0], f32[1], f32[2], f32[3] };
case FORMAT_R32F: return (Color) { f32[0], 1.f, 1.f, 1.f }; case FORMAT_R32F: return (Color) { f32[0], 1.f, 1.f, 1.f };
case FORMAT_RG32F: return (Color) { f32[0], f32[1], 1.f, 1.f }; case FORMAT_RG32F: return (Color) { f32[0], f32[1], 1.f, 1.f };
default: lovrThrow("Unsupported format for TextureData:getPixel"); default: lovrThrow("Unsupported format for Image:getPixel");
} }
} }
void lovrTextureDataSetPixel(TextureData* textureData, uint32_t x, uint32_t y, Color color) { void lovrImageSetPixel(Image* image, uint32_t x, uint32_t y, Color color) {
lovrAssert(textureData->blob->data, "TextureData does not have any pixel data"); lovrAssert(image->blob->data, "Image does not have any pixel data");
lovrAssert(x < textureData->width && y < textureData->height, "setPixel coordinates must be within TextureData bounds"); lovrAssert(x < image->width && y < image->height, "setPixel coordinates must be within Image bounds");
size_t index = (textureData->height - (y + 1)) * textureData->width + x; size_t index = (image->height - (y + 1)) * image->width + x;
size_t pixelSize = getPixelSize(textureData->format); size_t pixelSize = getPixelSize(image->format);
uint8_t* u8 = (uint8_t*) textureData->blob->data + pixelSize * index; uint8_t* u8 = (uint8_t*) image->blob->data + pixelSize * index;
float* f32 = (float*) u8; float* f32 = (float*) u8;
switch (textureData->format) { switch (image->format) {
case FORMAT_RGB: case FORMAT_RGB:
u8[0] = (uint8_t) (color.r * 255.f + .5f); u8[0] = (uint8_t) (color.r * 255.f + .5f);
u8[1] = (uint8_t) (color.g * 255.f + .5f); u8[1] = (uint8_t) (color.g * 255.f + .5f);
@ -594,7 +602,7 @@ void lovrTextureDataSetPixel(TextureData* textureData, uint32_t x, uint32_t y, C
f32[1] = color.g; f32[1] = color.g;
break; break;
default: lovrThrow("Unsupported format for TextureData:setPixel"); default: lovrThrow("Unsupported format for Image:setPixel");
} }
} }
@ -623,11 +631,11 @@ static uint32_t crc32(uint8_t* data, size_t length) {
return c ^ 0xffffffff; return c ^ 0xffffffff;
} }
Blob* lovrTextureDataEncode(TextureData* textureData) { Blob* lovrImageEncode(Image* image) {
lovrAssert(textureData->format == FORMAT_RGBA, "Only RGBA TextureData can be encoded"); lovrAssert(image->format == FORMAT_RGBA, "Only RGBA Image can be encoded");
uint32_t w = textureData->width; uint32_t w = image->width;
uint32_t h = textureData->height; uint32_t h = image->height;
uint8_t* pixels = (uint8_t*) textureData->blob->data + (h - 1) * w * 4; uint8_t* pixels = (uint8_t*) image->blob->data + (h - 1) * w * 4;
int32_t stride = -1 * (int) (w * 4); int32_t stride = -1 * (int) (w * 4);
// The world's worst png encoder // The world's worst png encoder
@ -732,28 +740,20 @@ Blob* lovrTextureDataEncode(TextureData* textureData) {
memcpy(data + 8, (uint8_t[4]) { crc >> 24, crc >> 16, crc >> 8, crc >> 0 }, 4); memcpy(data + 8, (uint8_t[4]) { crc >> 24, crc >> 16, crc >> 8, crc >> 0 }, 4);
data += 8 + 4; data += 8 + 4;
return lovrBlobCreate(data - size, size, "Encoded TextureData"); return lovrBlobCreate(data - size, size, "Encoded Image");
} }
void lovrTextureDataPaste(TextureData* textureData, TextureData* source, uint32_t dx, uint32_t dy, uint32_t sx, uint32_t sy, uint32_t w, uint32_t h) { void lovrImagePaste(Image* image, Image* source, uint32_t dx, uint32_t dy, uint32_t sx, uint32_t sy, uint32_t w, uint32_t h) {
lovrAssert(textureData->format == source->format, "Currently TextureData must have the same format to paste"); lovrAssert(image->format == source->format, "Currently Image must have the same format to paste");
lovrAssert(textureData->format < FORMAT_DXT1, "Compressed TextureData cannot be pasted"); lovrAssert(image->format < FORMAT_DXT1, "Compressed Image cannot be pasted");
size_t pixelSize = getPixelSize(textureData->format); size_t pixelSize = getPixelSize(image->format);
lovrAssert(dx + w <= textureData->width && dy + h <= textureData->height, "Attempt to paste outside of destination TextureData bounds"); lovrAssert(dx + w <= image->width && dy + h <= image->height, "Attempt to paste outside of destination Image bounds");
lovrAssert(sx + w <= source->width && sy + h <= source->height, "Attempt to paste from outside of source TextureData bounds"); lovrAssert(sx + w <= source->width && sy + h <= source->height, "Attempt to paste from outside of source Image bounds");
uint8_t* src = (uint8_t*) source->blob->data + ((source->height - 1 - sy) * source->width + sx) * pixelSize; uint8_t* src = (uint8_t*) source->blob->data + ((source->height - 1 - sy) * source->width + sx) * pixelSize;
uint8_t* dst = (uint8_t*) textureData->blob->data + ((textureData->height - 1 - dy) * textureData->width + sx) * pixelSize; uint8_t* dst = (uint8_t*) image->blob->data + ((image->height - 1 - dy) * image->width + sx) * pixelSize;
for (uint32_t y = 0; y < h; y++) { for (uint32_t y = 0; y < h; y++) {
memcpy(dst, src, w * pixelSize); memcpy(dst, src, w * pixelSize);
src -= source->width * pixelSize; src -= source->width * pixelSize;
dst -= textureData->width * pixelSize; dst -= image->width * pixelSize;
} }
} }
void lovrTextureDataDestroy(void* ref) {
TextureData* textureData = ref;
lovrRelease(textureData->source, lovrBlobDestroy);
free(textureData->mipmaps);
lovrRelease(textureData->blob, lovrBlobDestroy);
free(textureData);
}

View File

@ -51,7 +51,7 @@ typedef struct {
void* data; void* data;
} Mipmap; } Mipmap;
typedef struct TextureData { typedef struct Image {
ref_t ref; ref_t ref;
struct Blob* blob; struct Blob* blob;
uint32_t width; uint32_t width;
@ -60,12 +60,12 @@ typedef struct TextureData {
TextureFormat format; TextureFormat format;
Mipmap* mipmaps; Mipmap* mipmaps;
uint32_t mipmapCount; uint32_t mipmapCount;
} TextureData; } Image;
TextureData* lovrTextureDataCreate(uint32_t width, uint32_t height, struct Blob* contents, uint8_t value, TextureFormat format); Image* lovrImageCreate(uint32_t width, uint32_t height, struct Blob* contents, uint8_t value, TextureFormat format);
TextureData* lovrTextureDataCreateFromBlob(struct Blob* blob, bool flip); Image* lovrImageCreateFromBlob(struct Blob* blob, bool flip);
Color lovrTextureDataGetPixel(TextureData* textureData, uint32_t x, uint32_t y); void lovrImageDestroy(void* ref);
void lovrTextureDataSetPixel(TextureData* textureData, uint32_t x, uint32_t y, Color color); Color lovrImageGetPixel(Image* image, uint32_t x, uint32_t y);
struct Blob* lovrTextureDataEncode(TextureData* textureData); void lovrImageSetPixel(Image* image, uint32_t x, uint32_t y, Color color);
void lovrTextureDataPaste(TextureData* textureData, TextureData* source, uint32_t dx, uint32_t dy, uint32_t sx, uint32_t sy, uint32_t w, uint32_t h); struct Blob* lovrImageEncode(Image* image);
void lovrTextureDataDestroy(void* ref); void lovrImagePaste(Image* image, Image* source, uint32_t dx, uint32_t dy, uint32_t sx, uint32_t sy, uint32_t w, uint32_t h);

View File

@ -1,6 +1,6 @@
#include "data/modelData.h" #include "data/modelData.h"
#include "data/blob.h" #include "data/blob.h"
#include "data/textureData.h" #include "data/image.h"
#include <stdlib.h> #include <stdlib.h>
ModelData* lovrModelDataCreate(Blob* source, ModelDataIO* io) { ModelData* lovrModelDataCreate(Blob* source, ModelDataIO* io) {
@ -23,8 +23,8 @@ void lovrModelDataDestroy(void* ref) {
for (uint32_t i = 0; i < model->blobCount; i++) { for (uint32_t i = 0; i < model->blobCount; i++) {
lovrRelease(model->blobs[i], lovrBlobDestroy); lovrRelease(model->blobs[i], lovrBlobDestroy);
} }
for (uint32_t i = 0; i < model->textureCount; i++) { for (uint32_t i = 0; i < model->imageCount; i++) {
lovrRelease(model->textures[i], lovrTextureDataDestroy); lovrRelease(model->images[i], lovrImageDestroy);
} }
map_free(&model->animationMap); map_free(&model->animationMap);
map_free(&model->materialMap); map_free(&model->materialMap);
@ -40,7 +40,7 @@ void lovrModelDataAllocate(ModelData* model) {
size_t alignment = 8; size_t alignment = 8;
totalSize += sizes[0] = ALIGN(model->blobCount * sizeof(Blob*), alignment); totalSize += sizes[0] = ALIGN(model->blobCount * sizeof(Blob*), alignment);
totalSize += sizes[1] = ALIGN(model->bufferCount * sizeof(ModelBuffer), alignment); totalSize += sizes[1] = ALIGN(model->bufferCount * sizeof(ModelBuffer), alignment);
totalSize += sizes[2] = ALIGN(model->textureCount * sizeof(TextureData*), alignment); totalSize += sizes[2] = ALIGN(model->imageCount * sizeof(Image*), alignment);
totalSize += sizes[3] = ALIGN(model->materialCount * sizeof(ModelMaterial), alignment); totalSize += sizes[3] = ALIGN(model->materialCount * sizeof(ModelMaterial), alignment);
totalSize += sizes[4] = ALIGN(model->attributeCount * sizeof(ModelAttribute), alignment); totalSize += sizes[4] = ALIGN(model->attributeCount * sizeof(ModelAttribute), alignment);
totalSize += sizes[5] = ALIGN(model->primitiveCount * sizeof(ModelPrimitive), alignment); totalSize += sizes[5] = ALIGN(model->primitiveCount * sizeof(ModelPrimitive), alignment);
@ -57,7 +57,7 @@ void lovrModelDataAllocate(ModelData* model) {
lovrAssert(model->data, "Out of memory"); lovrAssert(model->data, "Out of memory");
model->blobs = (Blob**) (p + offset), offset += sizes[0]; model->blobs = (Blob**) (p + offset), offset += sizes[0];
model->buffers = (ModelBuffer*) (p + offset), offset += sizes[1]; model->buffers = (ModelBuffer*) (p + offset), offset += sizes[1];
model->textures = (TextureData**) (p + offset), offset += sizes[2]; model->images = (Image**) (p + offset), offset += sizes[2];
model->materials = (ModelMaterial*) (p + offset), offset += sizes[3]; model->materials = (ModelMaterial*) (p + offset), offset += sizes[3];
model->attributes = (ModelAttribute*) (p + offset), offset += sizes[4]; model->attributes = (ModelAttribute*) (p + offset), offset += sizes[4];
model->primitives = (ModelPrimitive*) (p + offset), offset += sizes[5]; model->primitives = (ModelPrimitive*) (p + offset), offset += sizes[5];

View File

@ -8,8 +8,8 @@
#define MAX_BONES 48 #define MAX_BONES 48
struct TextureData;
struct Blob; struct Blob;
struct Image;
typedef enum { typedef enum {
ATTR_POSITION, ATTR_POSITION,
@ -142,7 +142,7 @@ typedef struct {
const char* name; const char* name;
float scalars[MAX_MATERIAL_SCALARS]; float scalars[MAX_MATERIAL_SCALARS];
Color colors[MAX_MATERIAL_COLORS]; Color colors[MAX_MATERIAL_COLORS];
uint32_t textures[MAX_MATERIAL_TEXTURES]; uint32_t images[MAX_MATERIAL_TEXTURES];
TextureFilter filters[MAX_MATERIAL_TEXTURES]; TextureFilter filters[MAX_MATERIAL_TEXTURES];
TextureWrap wraps[MAX_MATERIAL_TEXTURES]; TextureWrap wraps[MAX_MATERIAL_TEXTURES];
} ModelMaterial; } ModelMaterial;
@ -183,7 +183,7 @@ typedef struct ModelData {
void* data; void* data;
struct Blob** blobs; struct Blob** blobs;
ModelBuffer* buffers; ModelBuffer* buffers;
struct TextureData** textures; struct Image** images;
ModelMaterial* materials; ModelMaterial* materials;
ModelAttribute* attributes; ModelAttribute* attributes;
ModelPrimitive* primitives; ModelPrimitive* primitives;
@ -194,7 +194,7 @@ typedef struct ModelData {
uint32_t blobCount; uint32_t blobCount;
uint32_t bufferCount; uint32_t bufferCount;
uint32_t textureCount; uint32_t imageCount;
uint32_t materialCount; uint32_t materialCount;
uint32_t attributeCount; uint32_t attributeCount;
uint32_t primitiveCount; uint32_t primitiveCount;

View File

@ -1,6 +1,6 @@
#include "data/modelData.h" #include "data/modelData.h"
#include "data/blob.h" #include "data/blob.h"
#include "data/textureData.h" #include "data/image.h"
#include "core/maf.h" #include "core/maf.h"
#include "lib/jsmn/jsmn.h" #include "lib/jsmn/jsmn.h"
#include <stdbool.h> #include <stdbool.h>
@ -133,7 +133,7 @@ static jsmntok_t* resolveTexture(const char* json, jsmntok_t* token, ModelMateri
uint32_t index = NOM_INT(json, token); uint32_t index = NOM_INT(json, token);
gltfTexture* texture = &textures[index]; gltfTexture* texture = &textures[index];
gltfSampler* sampler = texture->sampler == ~0u ? NULL : &samplers[texture->sampler]; gltfSampler* sampler = texture->sampler == ~0u ? NULL : &samplers[texture->sampler];
material->textures[textureType] = texture->image; material->images[textureType] = texture->image;
material->filters[textureType] = sampler ? sampler->filter : (TextureFilter) { .mode = FILTER_BILINEAR }; material->filters[textureType] = sampler ? sampler->filter : (TextureFilter) { .mode = FILTER_BILINEAR };
material->wraps[textureType] = sampler ? sampler->wrap : (TextureWrap) { .s = WRAP_REPEAT, .t = WRAP_REPEAT, .r = WRAP_REPEAT }; material->wraps[textureType] = sampler ? sampler->wrap : (TextureWrap) { .s = WRAP_REPEAT, .t = WRAP_REPEAT, .r = WRAP_REPEAT };
} else if (STR_EQ(key, "texCoord")) { } else if (STR_EQ(key, "texCoord")) {
@ -303,7 +303,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
} else if (STR_EQ(key, "images")) { } else if (STR_EQ(key, "images")) {
info.images = token; info.images = token;
model->textureCount = token->size; model->imageCount = token->size;
token += NOM_VALUE(json, token); token += NOM_VALUE(json, token);
} else if (STR_EQ(key, "samplers")) { } else if (STR_EQ(key, "samplers")) {
@ -649,17 +649,17 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
} }
} }
// Textures (glTF images) // Images
if (model->textureCount > 0) { if (model->imageCount > 0) {
jsmntok_t* token = info.images; jsmntok_t* token = info.images;
TextureData** texture = model->textures; Image** image = model->images;
for (int i = (token++)->size; i > 0; i--, texture++) { for (int i = (token++)->size; i > 0; i--, image++) {
for (int k = (token++)->size; k > 0; k--) { for (int k = (token++)->size; k > 0; k--) {
gltfString key = NOM_STR(json, token); gltfString key = NOM_STR(json, token);
if (STR_EQ(key, "bufferView")) { if (STR_EQ(key, "bufferView")) {
ModelBuffer* buffer = &model->buffers[NOM_INT(json, token)]; ModelBuffer* buffer = &model->buffers[NOM_INT(json, token)];
Blob* blob = lovrBlobCreate(buffer->data, buffer->size, NULL); Blob* blob = lovrBlobCreate(buffer->data, buffer->size, NULL);
*texture = lovrTextureDataCreateFromBlob(blob, false); *image = lovrImageCreateFromBlob(blob, false);
blob->data = NULL; // XXX Blob data ownership blob->data = NULL; // XXX Blob data ownership
lovrRelease(blob, lovrBlobDestroy); lovrRelease(blob, lovrBlobDestroy);
} else if (STR_EQ(key, "uri")) { } else if (STR_EQ(key, "uri")) {
@ -669,9 +669,9 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
lovrAssert(uri.length < maxPathLength, "Image filename is too long"); lovrAssert(uri.length < maxPathLength, "Image filename is too long");
strncat(filename, uri.data, uri.length); strncat(filename, uri.data, uri.length);
void* data = io(filename, &size); void* data = io(filename, &size);
lovrAssert(data && size > 0, "Unable to read texture from '%s'", filename); lovrAssert(data && size > 0, "Unable to read image from '%s'", filename);
Blob* blob = lovrBlobCreate(data, size, NULL); Blob* blob = lovrBlobCreate(data, size, NULL);
*texture = lovrTextureDataCreateFromBlob(blob, false); *image = lovrImageCreateFromBlob(blob, false);
lovrRelease(blob, lovrBlobDestroy); lovrRelease(blob, lovrBlobDestroy);
*root = '\0'; *root = '\0';
} else { } else {
@ -690,7 +690,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
material->scalars[SCALAR_ROUGHNESS] = 1.f; material->scalars[SCALAR_ROUGHNESS] = 1.f;
material->colors[COLOR_DIFFUSE] = (Color) { 1.f, 1.f, 1.f, 1.f }; material->colors[COLOR_DIFFUSE] = (Color) { 1.f, 1.f, 1.f, 1.f };
material->colors[COLOR_EMISSIVE] = (Color) { 0.f, 0.f, 0.f, 0.f }; material->colors[COLOR_EMISSIVE] = (Color) { 0.f, 0.f, 0.f, 0.f };
memset(material->textures, 0xff, MAX_MATERIAL_TEXTURES * sizeof(uint32_t)); memset(material->images, 0xff, MAX_MATERIAL_TEXTURES * sizeof(uint32_t));
for (int k = (token++)->size; k > 0; k--) { for (int k = (token++)->size; k > 0; k--) {
gltfString key = NOM_STR(json, token); gltfString key = NOM_STR(json, token);
@ -711,7 +711,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io
material->scalars[SCALAR_ROUGHNESS] = NOM_FLOAT(json, token); material->scalars[SCALAR_ROUGHNESS] = NOM_FLOAT(json, token);
} else if (STR_EQ(key, "metallicRoughnessTexture")) { } else if (STR_EQ(key, "metallicRoughnessTexture")) {
token = resolveTexture(json, token, material, TEXTURE_METALNESS, textures, samplers); token = resolveTexture(json, token, material, TEXTURE_METALNESS, textures, samplers);
material->textures[TEXTURE_ROUGHNESS] = material->textures[TEXTURE_METALNESS]; material->images[TEXTURE_ROUGHNESS] = material->images[TEXTURE_METALNESS];
material->filters[TEXTURE_ROUGHNESS] = material->filters[TEXTURE_METALNESS]; material->filters[TEXTURE_ROUGHNESS] = material->filters[TEXTURE_METALNESS];
material->wraps[TEXTURE_ROUGHNESS] = material->wraps[TEXTURE_METALNESS]; material->wraps[TEXTURE_ROUGHNESS] = material->wraps[TEXTURE_METALNESS];
} else { } else {

View File

@ -1,6 +1,6 @@
#include "data/modelData.h" #include "data/modelData.h"
#include "data/blob.h" #include "data/blob.h"
#include "data/textureData.h" #include "data/image.h"
#include "core/maf.h" #include "core/maf.h"
#include "core/map.h" #include "core/map.h"
#include "core/util.h" #include "core/util.h"
@ -15,7 +15,7 @@ typedef struct {
} objGroup; } objGroup;
typedef arr_t(ModelMaterial) arr_material_t; typedef arr_t(ModelMaterial) arr_material_t;
typedef arr_t(TextureData*) arr_texturedata_t; typedef arr_t(Image*) arr_image_t;
typedef arr_t(objGroup) arr_group_t; typedef arr_t(objGroup) arr_group_t;
#define STARTS_WITH(a, b) !strncmp(a, b, strlen(b)) #define STARTS_WITH(a, b) !strncmp(a, b, strlen(b))
@ -27,7 +27,7 @@ static uint32_t nomu32(char* s, char** end) {
return n; return n;
} }
static void parseMtl(char* path, char* base, ModelDataIO* io, arr_texturedata_t* textures, arr_material_t* materials, map_t* names) { static void parseMtl(char* path, char* base, ModelDataIO* io, arr_image_t* images, arr_material_t* materials, map_t* names) {
size_t size = 0; size_t size = 0;
char* p = io(path, &size); char* p = io(path, &size);
lovrAssert(p && size > 0, "Unable to read mtl from '%s'", path); lovrAssert(p && size > 0, "Unable to read mtl from '%s'", path);
@ -53,7 +53,7 @@ static void parseMtl(char* path, char* base, ModelDataIO* io, arr_texturedata_t*
.colors[COLOR_DIFFUSE] = { 1.f, 1.f, 1.f, 1.f }, .colors[COLOR_DIFFUSE] = { 1.f, 1.f, 1.f, 1.f },
.colors[COLOR_EMISSIVE] = { 0.f, 0.f, 0.f, 0.f } .colors[COLOR_EMISSIVE] = { 0.f, 0.f, 0.f, 0.f }
})); }));
memset(&materials->data[materials->length - 1].textures, 0xff, MAX_MATERIAL_TEXTURES * sizeof(int)); memset(&materials->data[materials->length - 1].images, 0xff, MAX_MATERIAL_TEXTURES * sizeof(int));
} else if (line[0] == 'K' && line[1] == 'd' && line[2] == ' ') { } else if (line[0] == 'K' && line[1] == 'd' && line[2] == ' ') {
float r, g, b; float r, g, b;
char* s = line + 3; char* s = line + 3;
@ -63,22 +63,22 @@ static void parseMtl(char* path, char* base, ModelDataIO* io, arr_texturedata_t*
ModelMaterial* material = &materials->data[materials->length - 1]; ModelMaterial* material = &materials->data[materials->length - 1];
material->colors[COLOR_DIFFUSE] = (Color) { r, g, b, 1.f }; material->colors[COLOR_DIFFUSE] = (Color) { r, g, b, 1.f };
} else if (STARTS_WITH(line, "map_Kd ")) { } else if (STARTS_WITH(line, "map_Kd ")) {
lovrAssert(base - path + (length - 7) < 1024, "Bad OBJ: Material texture filename is too long"); lovrAssert(base - path + (length - 7) < 1024, "Bad OBJ: Material image filename is too long");
memcpy(base, line + 7, length - 7); memcpy(base, line + 7, length - 7);
base[length - 7] = '\0'; base[length - 7] = '\0';
size_t imageSize = 0; size_t imageSize = 0;
void* image = io(path, &imageSize); void* pixels = io(path, &imageSize);
lovrAssert(image && imageSize > 0, "Unable to read texture from %s", path); lovrAssert(pixels && imageSize > 0, "Unable to read image from %s", path);
Blob* blob = lovrBlobCreate(image, imageSize, NULL); Blob* blob = lovrBlobCreate(pixels, imageSize, NULL);
TextureData* texture = lovrTextureDataCreateFromBlob(blob, true); Image* image = lovrImageCreateFromBlob(blob, true);
lovrAssert(materials->length > 0, "Tried to set a material property without declaring a material first"); lovrAssert(materials->length > 0, "Tried to set a material property without declaring a material first");
ModelMaterial* material = &materials->data[materials->length - 1]; ModelMaterial* material = &materials->data[materials->length - 1];
material->textures[TEXTURE_DIFFUSE] = (uint32_t) textures->length; material->images[TEXTURE_DIFFUSE] = (uint32_t) images->length;
material->filters[TEXTURE_DIFFUSE].mode = FILTER_TRILINEAR; material->filters[TEXTURE_DIFFUSE].mode = FILTER_TRILINEAR;
material->wraps[TEXTURE_DIFFUSE] = (TextureWrap) { .s = WRAP_REPEAT, .t = WRAP_REPEAT }; material->wraps[TEXTURE_DIFFUSE] = (TextureWrap) { .s = WRAP_REPEAT, .t = WRAP_REPEAT };
arr_push(textures, texture); arr_push(images, image);
lovrRelease(blob, lovrBlobDestroy); lovrRelease(blob, lovrBlobDestroy);
} }
@ -96,7 +96,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO* io)
size_t size = source->size; size_t size = source->size;
arr_group_t groups; arr_group_t groups;
arr_texturedata_t textures; arr_image_t images;
arr_material_t materials; arr_material_t materials;
arr_t(float) vertexBlob; arr_t(float) vertexBlob;
arr_t(int) indexBlob; arr_t(int) indexBlob;
@ -107,7 +107,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO* io)
arr_t(float) uvs; arr_t(float) uvs;
arr_init(&groups, realloc); arr_init(&groups, realloc);
arr_init(&textures, realloc); arr_init(&images, realloc);
arr_init(&materials, realloc); arr_init(&materials, realloc);
map_init(&materialMap, 0); map_init(&materialMap, 0);
arr_init(&vertexBlob, realloc); arr_init(&vertexBlob, realloc);
@ -215,7 +215,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO* io)
lovrAssert(baseLength + filenameLength < sizeof(path), "Bad OBJ: Material filename is too long"); lovrAssert(baseLength + filenameLength < sizeof(path), "Bad OBJ: Material filename is too long");
memcpy(path + baseLength, filename, filenameLength); memcpy(path + baseLength, filename, filenameLength);
path[baseLength + filenameLength] = '\0'; path[baseLength + filenameLength] = '\0';
parseMtl(path, base, io, &textures, &materials, &materialMap); parseMtl(path, base, io, &images, &materials, &materialMap);
} else if (STARTS_WITH(line, "usemtl ")) { } else if (STARTS_WITH(line, "usemtl ")) {
uint64_t index = map_get(&materialMap, hash64(line + 7, length - 7)); uint64_t index = map_get(&materialMap, hash64(line + 7, length - 7));
int material = index == MAP_NIL ? -1 : index; int material = index == MAP_NIL ? -1 : index;
@ -244,7 +244,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO* io)
model->attributeCount = 3 + (uint32_t) groups.length; model->attributeCount = 3 + (uint32_t) groups.length;
model->primitiveCount = (uint32_t) groups.length; model->primitiveCount = (uint32_t) groups.length;
model->nodeCount = 1; model->nodeCount = 1;
model->textureCount = (uint32_t) textures.length; model->imageCount = (uint32_t) images.length;
model->materialCount = (uint32_t) materials.length; model->materialCount = (uint32_t) materials.length;
lovrModelDataAllocate(model); lovrModelDataAllocate(model);
@ -263,7 +263,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO* io)
.stride = sizeof(int) .stride = sizeof(int)
}; };
memcpy(model->textures, textures.data, model->textureCount * sizeof(TextureData*)); memcpy(model->images, images.data, model->imageCount * sizeof(Image*));
memcpy(model->materials, materials.data, model->materialCount * sizeof(ModelMaterial)); memcpy(model->materials, materials.data, model->materialCount * sizeof(ModelMaterial));
memcpy(model->materialMap.hashes, materialMap.hashes, materialMap.size * sizeof(uint64_t)); memcpy(model->materialMap.hashes, materialMap.hashes, materialMap.size * sizeof(uint64_t));
memcpy(model->materialMap.values, materialMap.values, materialMap.size * sizeof(uint64_t)); memcpy(model->materialMap.values, materialMap.values, materialMap.size * sizeof(uint64_t));
@ -348,7 +348,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO* io)
finish: finish:
arr_free(&groups); arr_free(&groups);
arr_free(&textures); arr_free(&images);
arr_free(&materials); arr_free(&materials);
map_free(&materialMap); map_free(&materialMap);
map_free(&vertexMap); map_free(&vertexMap);

View File

@ -1,6 +1,6 @@
#include "data/rasterizer.h" #include "data/rasterizer.h"
#include "data/blob.h" #include "data/blob.h"
#include "data/textureData.h" #include "data/image.h"
#include "resources/VarelaRound.ttf.h" #include "resources/VarelaRound.ttf.h"
#include "core/utf.h" #include "core/utf.h"
#include "core/util.h" #include "core/util.h"
@ -167,7 +167,7 @@ void lovrRasterizerLoadGlyph(Rasterizer* rasterizer, uint32_t character, Glyph*
glyph->dx = empty ? 0 : roundf(bearing * rasterizer->scale); glyph->dx = empty ? 0 : roundf(bearing * rasterizer->scale);
glyph->dy = empty ? 0 : roundf(y1 * rasterizer->scale); glyph->dy = empty ? 0 : roundf(y1 * rasterizer->scale);
glyph->advance = roundf(advance * rasterizer->scale); glyph->advance = roundf(advance * rasterizer->scale);
glyph->data = lovrTextureDataCreate(glyph->tw, glyph->th, NULL, 0, FORMAT_RGB); glyph->data = lovrImageCreate(glyph->tw, glyph->th, NULL, 0, FORMAT_RGB);
// Render SDF // Render SDF
float tx = GLYPH_PADDING + -glyph->dx; float tx = GLYPH_PADDING + -glyph->dx;

View File

@ -6,7 +6,7 @@
#define GLYPH_PADDING 1 #define GLYPH_PADDING 1
struct Blob; struct Blob;
struct TextureData; struct Image;
typedef struct { typedef struct {
uint32_t x; uint32_t x;
@ -18,7 +18,7 @@ typedef struct {
int32_t dx; int32_t dx;
int32_t dy; int32_t dy;
int32_t advance; int32_t advance;
struct TextureData* data; struct Image* data;
} Glyph; } Glyph;
typedef struct Rasterizer Rasterizer; typedef struct Rasterizer Rasterizer;

View File

@ -1,11 +1,11 @@
#include "data/textureData.h" #include "data/image.h"
#pragma once #pragma once
#define MAX_CANVAS_ATTACHMENTS 4 #define MAX_CANVAS_ATTACHMENTS 4
struct Image;
struct Texture; struct Texture;
struct TextureData;
typedef struct Attachment { typedef struct Attachment {
struct Texture* texture; struct Texture* texture;
@ -39,4 +39,4 @@ void lovrCanvasSetWidth(Canvas* canvas, uint32_t width);
void lovrCanvasSetHeight(Canvas* canvas, uint32_t height); void lovrCanvasSetHeight(Canvas* canvas, uint32_t height);
uint32_t lovrCanvasGetMSAA(Canvas* canvas); uint32_t lovrCanvasGetMSAA(Canvas* canvas);
struct Texture* lovrCanvasGetDepthTexture(Canvas* canvas); struct Texture* lovrCanvasGetDepthTexture(Canvas* canvas);
struct TextureData* lovrCanvasNewTextureData(Canvas* canvas, uint32_t index); struct Image* lovrCanvasNewImage(Canvas* canvas, uint32_t index);

View File

@ -1,7 +1,7 @@
#include "graphics/font.h" #include "graphics/font.h"
#include "graphics/texture.h" #include "graphics/texture.h"
#include "data/rasterizer.h" #include "data/rasterizer.h"
#include "data/textureData.h" #include "data/image.h"
#include "core/map.h" #include "core/map.h"
#include "core/utf.h" #include "core/utf.h"
#include <string.h> #include <string.h>
@ -85,7 +85,7 @@ void lovrFontDestroy(void* ref) {
lovrRelease(font->rasterizer, lovrRasterizerDestroy); lovrRelease(font->rasterizer, lovrRasterizerDestroy);
lovrRelease(font->texture, lovrTextureDestroy); lovrRelease(font->texture, lovrTextureDestroy);
for (size_t i = 0; i < font->atlas.glyphs.length; i++) { for (size_t i = 0; i < font->atlas.glyphs.length; i++) {
lovrRelease(font->atlas.glyphs.data[i].data, lovrTextureDataDestroy); lovrRelease(font->atlas.glyphs.data[i].data, lovrImageDestroy);
} }
arr_free(&font->atlas.glyphs); arr_free(&font->atlas.glyphs);
map_free(&font->atlas.glyphMap); map_free(&font->atlas.glyphMap);
@ -369,13 +369,13 @@ static void lovrFontExpandTexture(Font* font) {
} }
} }
// TODO we only need the TextureData here to clear the texture, but it's a big waste of memory. // TODO we only need the Image here to clear the texture, but it's a big waste of memory.
// Could look into using glClearTexImage when supported to make this more efficient. // Could look into using glClearTexImage when supported to make this more efficient.
static void lovrFontCreateTexture(Font* font) { static void lovrFontCreateTexture(Font* font) {
lovrRelease(font->texture, lovrTextureDestroy); lovrRelease(font->texture, lovrTextureDestroy);
TextureData* textureData = lovrTextureDataCreate(font->atlas.width, font->atlas.height, NULL, 0x0, FORMAT_RGB); Image* image = lovrImageCreate(font->atlas.width, font->atlas.height, NULL, 0x0, FORMAT_RGB);
font->texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, false, false, 0); font->texture = lovrTextureCreate(TEXTURE_2D, &image, 1, false, false, 0);
lovrTextureSetFilter(font->texture, (TextureFilter) { .mode = FILTER_BILINEAR }); lovrTextureSetFilter(font->texture, (TextureFilter) { .mode = FILTER_BILINEAR });
lovrTextureSetWrap(font->texture, (TextureWrap) { .s = WRAP_CLAMP, .t = WRAP_CLAMP }); lovrTextureSetWrap(font->texture, (TextureWrap) { .s = WRAP_CLAMP, .t = WRAP_CLAMP });
lovrRelease(textureData, lovrTextureDataDestroy); lovrRelease(image, lovrImageDestroy);
} }

View File

@ -86,8 +86,8 @@ Model* lovrModelCreate(ModelData* data) {
if (data->materialCount > 0) { if (data->materialCount > 0) {
model->materials = malloc(data->materialCount * sizeof(Material*)); model->materials = malloc(data->materialCount * sizeof(Material*));
if (data->textureCount > 0) { if (data->imageCount > 0) {
model->textures = calloc(data->textureCount, sizeof(Texture*)); model->textures = calloc(data->imageCount, sizeof(Texture*));
} }
for (uint32_t i = 0; i < data->materialCount; i++) { for (uint32_t i = 0; i < data->materialCount; i++) {
@ -102,13 +102,13 @@ Model* lovrModelCreate(ModelData* data) {
} }
for (uint32_t j = 0; j < MAX_MATERIAL_TEXTURES; j++) { for (uint32_t j = 0; j < MAX_MATERIAL_TEXTURES; j++) {
uint32_t index = data->materials[i].textures[j]; uint32_t index = data->materials[i].images[j];
if (index != ~0u) { if (index != ~0u) {
if (!model->textures[index]) { if (!model->textures[index]) {
TextureData* textureData = data->textures[index]; Image* image = data->images[index];
bool srgb = j == TEXTURE_DIFFUSE || j == TEXTURE_EMISSIVE; bool srgb = j == TEXTURE_DIFFUSE || j == TEXTURE_EMISSIVE;
model->textures[index] = lovrTextureCreate(TEXTURE_2D, &textureData, 1, srgb, true, 0); model->textures[index] = lovrTextureCreate(TEXTURE_2D, &image, 1, srgb, true, 0);
lovrTextureSetFilter(model->textures[index], data->materials[i].filters[j]); lovrTextureSetFilter(model->textures[index], data->materials[i].filters[j]);
lovrTextureSetWrap(model->textures[index], data->materials[i].wraps[j]); lovrTextureSetWrap(model->textures[index], data->materials[i].wraps[j]);
} }
@ -214,7 +214,7 @@ void lovrModelDestroy(void* ref) {
} }
if (model->textures) { if (model->textures) {
for (uint32_t i = 0; i < model->data->textureCount; i++) { for (uint32_t i = 0; i < model->data->imageCount; i++) {
lovrRelease(model->textures[i], lovrTextureDestroy); lovrRelease(model->textures[i], lovrTextureDestroy);
} }
free(model->textures); free(model->textures);

View File

@ -189,7 +189,7 @@ static struct {
BlockBuffer blockBuffers[2][MAX_BLOCK_BUFFERS]; BlockBuffer blockBuffers[2][MAX_BLOCK_BUFFERS];
int activeTexture; int activeTexture;
Texture* textures[MAX_TEXTURES]; Texture* textures[MAX_TEXTURES];
Image images[MAX_IMAGES]; StorageImage images[MAX_IMAGES];
float viewports[2][4]; float viewports[2][4];
uint32_t viewportCount; uint32_t viewportCount;
arr_t(void*) incoherents[MAX_BARRIERS]; arr_t(void*) incoherents[MAX_BARRIERS];
@ -766,11 +766,11 @@ static void lovrGpuBindTexture(Texture* texture, int slot) {
} }
#ifndef LOVR_WEBGL #ifndef LOVR_WEBGL
static void lovrGpuBindImage(Image* image, int slot, const char* name) { static void lovrGpuBindImage(StorageImage* image, int slot, const char* name) {
lovrAssert(slot >= 0 && slot < MAX_IMAGES, "Invalid image slot %d", slot); lovrAssert(slot >= 0 && slot < MAX_IMAGES, "Invalid image slot %d", slot);
// This is a risky way to compare the two structs // This is a risky way to compare the two structs
if (memcmp(state.images + slot, image, sizeof(Image))) { if (memcmp(state.images + slot, image, sizeof(StorageImage))) {
Texture* texture = image->texture; Texture* texture = image->texture;
lovrAssert(texture, "No Texture bound to image uniform '%s'", name); lovrAssert(texture, "No Texture bound to image uniform '%s'", name);
lovrAssert(texture->format != FORMAT_RGBA || !texture->srgb, "Attempt to bind sRGB texture to image uniform '%s'", name); lovrAssert(texture->format != FORMAT_RGBA || !texture->srgb, "Attempt to bind sRGB texture to image uniform '%s'", name);
@ -786,7 +786,7 @@ static void lovrGpuBindImage(Image* image, int slot, const char* name) {
lovrRetain(texture); lovrRetain(texture);
lovrRelease(state.images[slot].texture, lovrTextureDestroy); lovrRelease(state.images[slot].texture, lovrTextureDestroy);
glBindImageTexture(slot, texture->id, image->mipmap, layered, slice, glAccess, glFormat); glBindImageTexture(slot, texture->id, image->mipmap, layered, slice, glAccess, glFormat);
memcpy(state.images + slot, image, sizeof(Image)); memcpy(state.images + slot, image, sizeof(StorageImage));
} }
} }
#endif #endif
@ -1167,7 +1167,7 @@ static void lovrGpuBindShader(Shader* shader) {
case UNIFORM_IMAGE: case UNIFORM_IMAGE:
#ifndef LOVR_WEBGL #ifndef LOVR_WEBGL
for (int j = 0; j < count; j++) { for (int j = 0; j < count; j++) {
Image* image = &uniform->value.images[j]; StorageImage* image = &uniform->value.images[j];
Texture* texture = image->texture; Texture* texture = image->texture;
lovrAssert(!texture || texture->type == uniform->textureType, "Uniform texture type mismatch for uniform '%s'", uniform->name); lovrAssert(!texture || texture->type == uniform->textureType, "Uniform texture type mismatch for uniform '%s'", uniform->name);
@ -1348,11 +1348,11 @@ void lovrGpuInit(void* (*getProcAddress)(const char*), bool debug) {
arr_init(&state.incoherents[i], realloc); arr_init(&state.incoherents[i], realloc);
} }
TextureData* textureData = lovrTextureDataCreate(1, 1, NULL, 0xff, FORMAT_RGBA); Image* image = lovrImageCreate(1, 1, NULL, 0xff, FORMAT_RGBA);
state.defaultTexture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, true, false, 0); state.defaultTexture = lovrTextureCreate(TEXTURE_2D, &image, 1, true, false, 0);
lovrTextureSetFilter(state.defaultTexture, (TextureFilter) { .mode = FILTER_NEAREST }); lovrTextureSetFilter(state.defaultTexture, (TextureFilter) { .mode = FILTER_NEAREST });
lovrTextureSetWrap(state.defaultTexture, (TextureWrap) { WRAP_CLAMP, WRAP_CLAMP, WRAP_CLAMP }); lovrTextureSetWrap(state.defaultTexture, (TextureWrap) { WRAP_CLAMP, WRAP_CLAMP, WRAP_CLAMP });
lovrRelease(textureData, lovrTextureDataDestroy); lovrRelease(image, lovrImageDestroy);
map_init(&state.timerMap, 4); map_init(&state.timerMap, 4);
state.queryPool.next = ~0u; state.queryPool.next = ~0u;
@ -1670,7 +1670,7 @@ const GpuStats* lovrGpuGetStats() {
// Texture // Texture
Texture* lovrTextureCreate(TextureType type, TextureData** slices, uint32_t sliceCount, bool srgb, bool mipmaps, uint32_t msaa) { Texture* lovrTextureCreate(TextureType type, Image** slices, uint32_t sliceCount, bool srgb, bool mipmaps, uint32_t msaa) {
Texture* texture = calloc(1, sizeof(Texture)); Texture* texture = calloc(1, sizeof(Texture));
lovrAssert(texture, "Out of memory"); lovrAssert(texture, "Out of memory");
texture->ref = 1; texture->ref = 1;
@ -1814,7 +1814,7 @@ void lovrTextureAllocate(Texture* texture, uint32_t width, uint32_t height, uint
state.stats.textureMemory += getTextureMemorySize(texture); state.stats.textureMemory += getTextureMemorySize(texture);
} }
void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, uint32_t x, uint32_t y, uint32_t slice, uint32_t mipmap) { void lovrTextureReplacePixels(Texture* texture, Image* image, uint32_t x, uint32_t y, uint32_t slice, uint32_t mipmap) {
lovrGraphicsFlush(); lovrGraphicsFlush();
lovrAssert(texture->allocated, "Texture is not allocated"); lovrAssert(texture->allocated, "Texture is not allocated");
@ -1826,21 +1826,21 @@ void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, uint32
uint32_t maxWidth = lovrTextureGetWidth(texture, mipmap); uint32_t maxWidth = lovrTextureGetWidth(texture, mipmap);
uint32_t maxHeight = lovrTextureGetHeight(texture, mipmap); uint32_t maxHeight = lovrTextureGetHeight(texture, mipmap);
uint32_t width = textureData->width; uint32_t width = image->width;
uint32_t height = textureData->height; uint32_t height = image->height;
bool overflow = (x + width > maxWidth) || (y + height > maxHeight); bool overflow = (x + width > maxWidth) || (y + height > maxHeight);
lovrAssert(!overflow, "Trying to replace pixels outside the texture's bounds"); lovrAssert(!overflow, "Trying to replace pixels outside the texture's bounds");
lovrAssert(mipmap < texture->mipmapCount, "Invalid mipmap level %d", mipmap); lovrAssert(mipmap < texture->mipmapCount, "Invalid mipmap level %d", mipmap);
GLenum glFormat = convertTextureFormat(textureData->format); GLenum glFormat = convertTextureFormat(image->format);
GLenum glInternalFormat = convertTextureFormatInternal(textureData->format, texture->srgb); GLenum glInternalFormat = convertTextureFormatInternal(image->format, texture->srgb);
GLenum binding = (texture->type == TEXTURE_CUBE) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice : texture->target; GLenum binding = (texture->type == TEXTURE_CUBE) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice : texture->target;
lovrGpuBindTexture(texture, 0); lovrGpuBindTexture(texture, 0);
if (isTextureFormatCompressed(textureData->format)) { if (isTextureFormatCompressed(image->format)) {
lovrAssert(width == maxWidth && height == maxHeight, "Compressed texture pixels must be fully replaced"); lovrAssert(width == maxWidth && height == maxHeight, "Compressed texture pixels must be fully replaced");
lovrAssert(mipmap == 0, "Unable to replace a specific mipmap of a compressed texture"); lovrAssert(mipmap == 0, "Unable to replace a specific mipmap of a compressed texture");
for (uint32_t i = 0; i < textureData->mipmapCount; i++) { for (uint32_t i = 0; i < image->mipmapCount; i++) {
Mipmap* m = textureData->mipmaps + i; Mipmap* m = image->mipmaps + i;
switch (texture->type) { switch (texture->type) {
case TEXTURE_2D: case TEXTURE_2D:
case TEXTURE_CUBE: case TEXTURE_CUBE:
@ -1853,17 +1853,17 @@ void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, uint32
} }
} }
} else { } else {
lovrAssert(textureData->blob->data, "Trying to replace Texture pixels with empty pixel data"); lovrAssert(image->blob->data, "Trying to replace Texture pixels with empty pixel data");
GLenum glType = convertTextureFormatType(textureData->format); GLenum glType = convertTextureFormatType(image->format);
switch (texture->type) { switch (texture->type) {
case TEXTURE_2D: case TEXTURE_2D:
case TEXTURE_CUBE: case TEXTURE_CUBE:
glTexSubImage2D(binding, mipmap, x, y, width, height, glFormat, glType, textureData->blob->data); glTexSubImage2D(binding, mipmap, x, y, width, height, glFormat, glType, image->blob->data);
break; break;
case TEXTURE_ARRAY: case TEXTURE_ARRAY:
case TEXTURE_VOLUME: case TEXTURE_VOLUME:
glTexSubImage3D(binding, mipmap, x, y, slice, width, height, 1, glFormat, glType, textureData->blob->data); glTexSubImage3D(binding, mipmap, x, y, slice, width, height, 1, glFormat, glType, image->blob->data);
break; break;
} }
@ -2110,7 +2110,7 @@ void lovrCanvasResolve(Canvas* canvas) {
canvas->needsResolve = false; canvas->needsResolve = false;
} }
TextureData* lovrCanvasNewTextureData(Canvas* canvas, uint32_t index) { Image* lovrCanvasNewImage(Canvas* canvas, uint32_t index) {
lovrGraphicsFlushCanvas(canvas); lovrGraphicsFlushCanvas(canvas);
lovrGpuBindCanvas(canvas, false); lovrGpuBindCanvas(canvas, false);
@ -2129,14 +2129,14 @@ TextureData* lovrCanvasNewTextureData(Canvas* canvas, uint32_t index) {
glReadBuffer(index); glReadBuffer(index);
} }
TextureData* textureData = lovrTextureDataCreate(canvas->width, canvas->height, NULL, 0x0, FORMAT_RGBA); Image* image = lovrImageCreate(canvas->width, canvas->height, NULL, 0x0, FORMAT_RGBA);
glReadPixels(0, 0, canvas->width, canvas->height, GL_RGBA, GL_UNSIGNED_BYTE, textureData->blob->data); glReadPixels(0, 0, canvas->width, canvas->height, GL_RGBA, GL_UNSIGNED_BYTE, image->blob->data);
if (index != 0) { if (index != 0) {
glReadBuffer(0); glReadBuffer(0);
} }
return textureData; return image;
} }
const Attachment* lovrCanvasGetAttachments(Canvas* canvas, uint32_t* count) { const Attachment* lovrCanvasGetAttachments(Canvas* canvas, uint32_t* count) {
@ -2536,7 +2536,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
case UNIFORM_SAMPLER: case UNIFORM_SAMPLER:
case UNIFORM_IMAGE: case UNIFORM_IMAGE:
uniform.size = uniform.count * (uniform.type == UNIFORM_SAMPLER ? sizeof(Texture*) : sizeof(Image)); uniform.size = uniform.count * (uniform.type == UNIFORM_SAMPLER ? sizeof(Texture*) : sizeof(StorageImage));
uniform.value.data = calloc(1, uniform.size); uniform.value.data = calloc(1, uniform.size);
lovrAssert(uniform.value.data, "Out of memory"); lovrAssert(uniform.value.data, "Out of memory");
@ -2815,8 +2815,8 @@ void lovrShaderSetTextures(Shader* shader, const char* name, Texture** data, int
lovrShaderSetUniform(shader, name, UNIFORM_SAMPLER, data, start, count, sizeof(Texture*), "texture"); lovrShaderSetUniform(shader, name, UNIFORM_SAMPLER, data, start, count, sizeof(Texture*), "texture");
} }
void lovrShaderSetImages(Shader* shader, const char* name, Image* data, int start, int count) { void lovrShaderSetImages(Shader* shader, const char* name, StorageImage* data, int start, int count) {
lovrShaderSetUniform(shader, name, UNIFORM_IMAGE, data, start, count, sizeof(Image), "image"); lovrShaderSetUniform(shader, name, UNIFORM_IMAGE, data, start, count, sizeof(StorageImage), "image");
} }
void lovrShaderSetColor(Shader* shader, const char* name, Color color) { void lovrShaderSetColor(Shader* shader, const char* name, Color color) {

View File

@ -64,7 +64,7 @@ typedef struct {
int slice; int slice;
int mipmap; int mipmap;
UniformAccess access; UniformAccess access;
} Image; } StorageImage;
typedef struct Uniform { typedef struct Uniform {
char name[LOVR_MAX_UNIFORM_LENGTH]; char name[LOVR_MAX_UNIFORM_LENGTH];
@ -80,7 +80,7 @@ typedef struct Uniform {
int* ints; int* ints;
float* floats; float* floats;
struct Texture** textures; struct Texture** textures;
Image* images; StorageImage* images;
} value; } value;
TextureType textureType; TextureType textureType;
int baseSlot; int baseSlot;
@ -118,7 +118,7 @@ void lovrShaderSetFloats(Shader* shader, const char* name, float* data, int star
void lovrShaderSetInts(Shader* shader, const char* name, int* data, int start, int count); void lovrShaderSetInts(Shader* shader, const char* name, int* data, int start, int count);
void lovrShaderSetMatrices(Shader* shader, const char* name, float* data, int start, int count); void lovrShaderSetMatrices(Shader* shader, const char* name, float* data, int start, int count);
void lovrShaderSetTextures(Shader* shader, const char* name, struct Texture** data, int start, int count); void lovrShaderSetTextures(Shader* shader, const char* name, struct Texture** data, int start, int count);
void lovrShaderSetImages(Shader* shader, const char* name, Image* data, int start, int count); void lovrShaderSetImages(Shader* shader, const char* name, StorageImage* data, int start, int count);
void lovrShaderSetColor(Shader* shader, const char* name, Color color); void lovrShaderSetColor(Shader* shader, const char* name, Color color);
void lovrShaderSetBlock(Shader* shader, const char* name, struct Buffer* buffer, size_t offset, size_t size, UniformAccess access); void lovrShaderSetBlock(Shader* shader, const char* name, struct Buffer* buffer, size_t offset, size_t size, UniformAccess access);

View File

@ -1,11 +1,11 @@
#include "data/textureData.h" #include "data/image.h"
#include "graphics/graphics.h" #include "graphics/graphics.h"
#include "data/modelData.h" #include "data/modelData.h"
#include <stdbool.h> #include <stdbool.h>
#pragma once #pragma once
struct TextureData; struct Image;
typedef enum { typedef enum {
TEXTURE_2D, TEXTURE_2D,
@ -15,11 +15,11 @@ typedef enum {
} TextureType; } TextureType;
typedef struct Texture Texture; typedef struct Texture Texture;
Texture* lovrTextureCreate(TextureType type, struct TextureData** slices, uint32_t sliceCount, bool srgb, bool mipmaps, uint32_t msaa); Texture* lovrTextureCreate(TextureType type, struct Image** slices, uint32_t sliceCount, bool srgb, bool mipmaps, uint32_t msaa);
Texture* lovrTextureCreateFromHandle(uint32_t handle, TextureType type, uint32_t depth, uint32_t msaa); Texture* lovrTextureCreateFromHandle(uint32_t handle, TextureType type, uint32_t depth, uint32_t msaa);
void lovrTextureDestroy(void* ref); void lovrTextureDestroy(void* ref);
void lovrTextureAllocate(Texture* texture, uint32_t width, uint32_t height, uint32_t depth, TextureFormat format); void lovrTextureAllocate(Texture* texture, uint32_t width, uint32_t height, uint32_t depth, TextureFormat format);
void lovrTextureReplacePixels(Texture* texture, struct TextureData* data, uint32_t x, uint32_t y, uint32_t slice, uint32_t mipmap); void lovrTextureReplacePixels(Texture* texture, struct Image* data, uint32_t x, uint32_t y, uint32_t slice, uint32_t mipmap);
uint64_t lovrTextureGetId(Texture* texture); uint64_t lovrTextureGetId(Texture* texture);
uint32_t lovrTextureGetWidth(Texture* texture, uint32_t mipmap); uint32_t lovrTextureGetWidth(Texture* texture, uint32_t mipmap);
uint32_t lovrTextureGetHeight(Texture* texture, uint32_t mipmap); uint32_t lovrTextureGetHeight(Texture* texture, uint32_t mipmap);

View File

@ -626,7 +626,7 @@ static ModelData* openvr_newModelData(Device device, bool animated) {
model->nodeCount = animated ? (1 + modelCount) : 1; model->nodeCount = animated ? (1 + modelCount) : 1;
model->bufferCount = 2 * modelCount; model->bufferCount = 2 * modelCount;
model->attributeCount = 4 * modelCount; model->attributeCount = 4 * modelCount;
model->textureCount = modelCount; model->imageCount = modelCount;
model->materialCount = modelCount; model->materialCount = modelCount;
model->primitiveCount = modelCount; model->primitiveCount = modelCount;
model->childCount = animated ? modelCount : 0; model->childCount = animated ? modelCount : 0;
@ -702,12 +702,12 @@ static ModelData* openvr_newModelData(Device device, bool animated) {
}; };
RenderModel_TextureMap_t* texture = renderModelTextures[i]; RenderModel_TextureMap_t* texture = renderModelTextures[i];
model->textures[i] = lovrTextureDataCreate(texture->unWidth, texture->unHeight, NULL, 0, FORMAT_RGBA); model->images[i] = lovrImageCreate(texture->unWidth, texture->unHeight, NULL, 0, FORMAT_RGBA);
memcpy(model->textures[i]->blob->data, texture->rubTextureMapData, texture->unWidth * texture->unHeight * 4); memcpy(model->images[i]->blob->data, texture->rubTextureMapData, texture->unWidth * texture->unHeight * 4);
model->materials[i] = (ModelMaterial) { model->materials[i] = (ModelMaterial) {
.colors[COLOR_DIFFUSE] = { 1.f, 1.f, 1.f, 1.f }, .colors[COLOR_DIFFUSE] = { 1.f, 1.f, 1.f, 1.f },
.textures[TEXTURE_DIFFUSE] = i, .images[TEXTURE_DIFFUSE] = i,
.filters[TEXTURE_DIFFUSE] = lovrGraphicsGetDefaultFilter() .filters[TEXTURE_DIFFUSE] = lovrGraphicsGetDefaultFilter()
}; };