mirror of https://github.com/bjornbytes/lovr.git
Many batching improvements; Refactoring;
This commit is contained in:
parent
d66057ee70
commit
ea3a77a73a
|
@ -423,6 +423,7 @@ if(LOVR_ENABLE_GRAPHICS)
|
||||||
add_definitions(-DLOVR_ENABLE_GRAPHICS)
|
add_definitions(-DLOVR_ENABLE_GRAPHICS)
|
||||||
target_sources(lovr PRIVATE
|
target_sources(lovr PRIVATE
|
||||||
src/graphics/animator.c
|
src/graphics/animator.c
|
||||||
|
src/graphics/buffer.c
|
||||||
src/graphics/canvas.c
|
src/graphics/canvas.c
|
||||||
src/graphics/font.c
|
src/graphics/font.c
|
||||||
src/graphics/graphics.c
|
src/graphics/graphics.c
|
||||||
|
|
|
@ -46,7 +46,6 @@ const char* BlendModes[] = {
|
||||||
[BLEND_LIGHTEN] = "lighten",
|
[BLEND_LIGHTEN] = "lighten",
|
||||||
[BLEND_DARKEN] = "darken",
|
[BLEND_DARKEN] = "darken",
|
||||||
[BLEND_SCREEN] = "screen",
|
[BLEND_SCREEN] = "screen",
|
||||||
[BLEND_REPLACE] = "replace",
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -95,8 +94,8 @@ const char* FilterModes[] = {
|
||||||
|
|
||||||
const char* HorizontalAligns[] = {
|
const char* HorizontalAligns[] = {
|
||||||
[ALIGN_LEFT] = "left",
|
[ALIGN_LEFT] = "left",
|
||||||
[ALIGN_RIGHT] = "right",
|
|
||||||
[ALIGN_CENTER] = "center",
|
[ALIGN_CENTER] = "center",
|
||||||
|
[ALIGN_RIGHT] = "right",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -177,8 +176,8 @@ const char* UniformAccesses[] = {
|
||||||
|
|
||||||
const char* VerticalAligns[] = {
|
const char* VerticalAligns[] = {
|
||||||
[ALIGN_TOP] = "top",
|
[ALIGN_TOP] = "top",
|
||||||
[ALIGN_BOTTOM] = "bottom",
|
|
||||||
[ALIGN_MIDDLE] = "middle",
|
[ALIGN_MIDDLE] = "middle",
|
||||||
|
[ALIGN_BOTTOM] = "bottom",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -195,60 +194,61 @@ const char* WrapModes[] = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint32_t luax_readvertices(lua_State* L, int index) {
|
static uint32_t luax_getvertexcount(lua_State* L, int index) {
|
||||||
switch (lua_type(L, index)) {
|
int type = lua_type(L, index);
|
||||||
case LUA_TTABLE: {
|
if (type == LUA_TTABLE) {
|
||||||
size_t count = lua_objlen(L, index);
|
size_t count = lua_objlen(L, index);
|
||||||
lua_rawgeti(L, index, 1);
|
lua_rawgeti(L, index, 1);
|
||||||
|
int tableType = lua_type(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return tableType == LUA_TNUMBER ? count / 3 : count;
|
||||||
|
} else if (type == LUA_TNUMBER) {
|
||||||
|
return (lua_gettop(L) - index + 1) / 3;
|
||||||
|
} else {
|
||||||
|
return lua_gettop(L) - index + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void luax_readvertices(lua_State* L, int index, float* vertices, uint32_t count) {
|
||||||
|
switch (lua_type(L, index)) {
|
||||||
|
case LUA_TTABLE:
|
||||||
|
lua_rawgeti(L, index, 1);
|
||||||
if (lua_type(L, -1) == LUA_TNUMBER) {
|
if (lua_type(L, -1) == LUA_TNUMBER) {
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
float* vertices = lovrGraphicsGetVertexPointer(count / 3);
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
for (size_t i = 1; i <= count; i += 3) {
|
for (int j = 1; j <= 3; j++) {
|
||||||
for (int j = 0; j < 3; j++) {
|
lua_rawgeti(L, index, 3 * i + j);
|
||||||
lua_rawgeti(L, index, i + j);
|
|
||||||
vertices[j] = lua_tonumber(L, -1);
|
vertices[j] = lua_tonumber(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
vertices += 8;
|
vertices += 8;
|
||||||
}
|
}
|
||||||
return count / 3;
|
|
||||||
} else {
|
} else {
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
float* vertices = lovrGraphicsGetVertexPointer(count);
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
for (size_t i = 1; i <= count; i++) {
|
lua_rawgeti(L, index, i + 1);
|
||||||
lua_rawgeti(L, index, i);
|
|
||||||
vec3_init(vertices, luax_checkmathtype(L, -1, MATH_VEC3, NULL));
|
vec3_init(vertices, luax_checkmathtype(L, -1, MATH_VEC3, NULL));
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
vertices += 8;
|
vertices += 8;
|
||||||
}
|
}
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
|
|
||||||
case LUA_TNUMBER: {
|
case LUA_TNUMBER:
|
||||||
int top = lua_gettop(L);
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
uint32_t count = (top - index + 1) / 3;
|
|
||||||
float* vertices = lovrGraphicsGetVertexPointer(count);
|
|
||||||
for (int i = index; i <= top; i += 3) {
|
|
||||||
for (int j = 0; j < 3; j++) {
|
for (int j = 0; j < 3; j++) {
|
||||||
vertices[j] = lua_tonumber(L, i + j);
|
vertices[j] = lua_tonumber(L, index + 3 * i + j);
|
||||||
}
|
}
|
||||||
vertices += 8;
|
vertices += 8;
|
||||||
}
|
}
|
||||||
return count;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
default:
|
||||||
int top = lua_gettop(L);
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
uint32_t count = top - index + 1;
|
vec3_init(vertices, luax_checkmathtype(L, index + i, MATH_VEC3, NULL));
|
||||||
float* vertices = lovrGraphicsGetVertexPointer(count);
|
|
||||||
for (int i = index; i <= top; i++) {
|
|
||||||
vec3_init(vertices, luax_checkmathtype(L, i, MATH_VEC3, NULL));
|
|
||||||
vertices += 8;
|
vertices += 8;
|
||||||
}
|
}
|
||||||
return count;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,7 +426,7 @@ static int l_lovrGraphicsGetBlendMode(lua_State* L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_lovrGraphicsSetBlendMode(lua_State* L) {
|
static int l_lovrGraphicsSetBlendMode(lua_State* L) {
|
||||||
BlendMode mode = luaL_checkoption(L, 1, NULL, BlendModes);
|
BlendMode mode = lua_isnoneornil(L, 1) ? BLEND_NONE : luaL_checkoption(L, 1, NULL, BlendModes);
|
||||||
BlendAlphaMode alphaMode = luaL_checkoption(L, 2, "alphamultiply", BlendAlphaModes);
|
BlendAlphaMode alphaMode = luaL_checkoption(L, 2, "alphamultiply", BlendAlphaModes);
|
||||||
lovrGraphicsSetBlendMode(mode, alphaMode);
|
lovrGraphicsSetBlendMode(mode, alphaMode);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -711,14 +711,18 @@ static int l_lovrGraphicsFlush(lua_State* L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_lovrGraphicsPoints(lua_State* L) {
|
static int l_lovrGraphicsPoints(lua_State* L) {
|
||||||
uint32_t count = luax_readvertices(L, 1);
|
float* vertices;
|
||||||
lovrGraphicsPoints(count);
|
uint32_t count = luax_getvertexcount(L, 1);
|
||||||
|
lovrGraphicsPoints(count, &vertices);
|
||||||
|
luax_readvertices(L, 1, vertices, count);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_lovrGraphicsLine(lua_State* L) {
|
static int l_lovrGraphicsLine(lua_State* L) {
|
||||||
uint32_t count = luax_readvertices(L, 1);
|
float* vertices;
|
||||||
lovrGraphicsLine(count);
|
uint32_t count = luax_getvertexcount(L, 1);
|
||||||
|
lovrGraphicsLine(count, &vertices);
|
||||||
|
luax_readvertices(L, 1, vertices, count);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -731,13 +735,11 @@ static int l_lovrGraphicsTriangle(lua_State* L) {
|
||||||
style = luaL_checkoption(L, 1, NULL, DrawStyles);
|
style = luaL_checkoption(L, 1, NULL, DrawStyles);
|
||||||
}
|
}
|
||||||
|
|
||||||
float points[9];
|
float* vertices;
|
||||||
int top = lua_gettop(L);
|
uint32_t count = luax_getvertexcount(L, 2);
|
||||||
lovrAssert(top >= 10, "Expected 3 points to make a triangle, got %d\n", (top - 1) / 3);
|
lovrAssert(count % 3 == 0, "Triangle vertex count must be a multiple of 3");
|
||||||
for (int i = 0; i < 9; i++) {
|
lovrGraphicsTriangle(style, material, count, &vertices);
|
||||||
points[i] = luaL_checknumber(L, i + 2);
|
luax_readvertices(L, 2, vertices, count);
|
||||||
}
|
|
||||||
lovrGraphicsTriangle(style, material, points);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -785,17 +787,17 @@ static int l_lovrGraphicsArc(lua_State* L) {
|
||||||
} else {
|
} else {
|
||||||
style = luaL_checkoption(L, 1, NULL, DrawStyles);
|
style = luaL_checkoption(L, 1, NULL, DrawStyles);
|
||||||
}
|
}
|
||||||
ArcMode arcMode = ARC_MODE_PIE;
|
ArcMode mode = ARC_MODE_PIE;
|
||||||
int index = 2;
|
int index = 2;
|
||||||
if (lua_type(L, index) == LUA_TSTRING) {
|
if (lua_type(L, index) == LUA_TSTRING) {
|
||||||
arcMode = luaL_checkoption(L, index++, NULL, ArcModes);
|
mode = luaL_checkoption(L, index++, NULL, ArcModes);
|
||||||
}
|
}
|
||||||
float transform[16];
|
float transform[16];
|
||||||
index = luax_readmat4(L, index, transform, 1, NULL);
|
index = luax_readmat4(L, index, transform, 1, NULL);
|
||||||
float theta1 = luaL_optnumber(L, index++, 0);
|
float r1 = luaL_optnumber(L, index++, 0);
|
||||||
float theta2 = luaL_optnumber(L, index++, 2 * M_PI);
|
float r2 = luaL_optnumber(L, index++, 2 * M_PI);
|
||||||
int segments = luaL_optinteger(L, index, 64) * (MIN(fabsf(theta2 - theta1), 2 * M_PI) / (2 * M_PI));
|
int segments = luaL_optinteger(L, index, 64) * (MIN(fabsf(r2 - r1), 2 * M_PI) / (2 * M_PI));
|
||||||
lovrGraphicsArc(style, arcMode, material, transform, theta1, theta2, segments);
|
lovrGraphicsArc(style, mode, material, transform, r1, r2, segments);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -953,9 +955,14 @@ static int l_lovrGraphicsNewShaderBlock(lua_State* L) {
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderBlock* block = lovrShaderBlockCreate(&uniforms, type, usage);
|
lovrAssert(type != BLOCK_STORAGE || lovrGraphicsGetSupported()->computeShaders, "Writable ShaderBlocks are not supported on this system");
|
||||||
|
size_t size = lovrShaderComputeUniformLayout(&uniforms);
|
||||||
|
Buffer* buffer = lovrBufferCreate(size, NULL, type == BLOCK_STORAGE ? BUFFER_SHADER_STORAGE : BUFFER_UNIFORM, usage, false);
|
||||||
|
ShaderBlock* block = lovrShaderBlockCreate(type, buffer, &uniforms);
|
||||||
luax_pushobject(L, block);
|
luax_pushobject(L, block);
|
||||||
vec_deinit(&uniforms);
|
vec_deinit(&uniforms);
|
||||||
|
lovrRelease(buffer);
|
||||||
|
lovrRelease(block);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1156,17 +1163,9 @@ static int l_lovrGraphicsNewMesh(lua_State* L) {
|
||||||
DrawMode mode = luaL_checkoption(L, drawModeIndex, "fan", DrawModes);
|
DrawMode mode = luaL_checkoption(L, drawModeIndex, "fan", DrawModes);
|
||||||
BufferUsage usage = luaL_checkoption(L, drawModeIndex + 1, "dynamic", BufferUsages);
|
BufferUsage usage = luaL_checkoption(L, drawModeIndex + 1, "dynamic", BufferUsages);
|
||||||
bool readable = lua_toboolean(L, drawModeIndex + 2);
|
bool readable = lua_toboolean(L, drawModeIndex + 2);
|
||||||
Mesh* mesh = lovrMeshCreate(count, format, mode, usage, readable);
|
size_t bufferSize = count * format.stride;
|
||||||
|
Buffer* vertexBuffer = lovrBufferCreate(bufferSize, NULL, BUFFER_VERTEX, usage, readable);
|
||||||
if (dataIndex) {
|
Mesh* mesh = lovrMeshCreate(mode, format, vertexBuffer);
|
||||||
VertexPointer vertices = { .raw = lovrMeshMapVertices(mesh, 0) };
|
|
||||||
luax_loadvertices(L, dataIndex, lovrMeshGetVertexFormat(mesh), vertices);
|
|
||||||
lovrMeshFlushVertices(mesh, 0, count * format.stride);
|
|
||||||
} else if (vertexData) {
|
|
||||||
void* vertices = lovrMeshMapVertices(mesh, 0);
|
|
||||||
memcpy(vertices, vertexData->blob.data, vertexData->count * vertexData->format.stride);
|
|
||||||
lovrMeshFlushVertices(mesh, 0, count * format.stride);
|
|
||||||
}
|
|
||||||
|
|
||||||
lovrMeshAttachAttribute(mesh, "lovrDrawID", &(MeshAttribute) {
|
lovrMeshAttachAttribute(mesh, "lovrDrawID", &(MeshAttribute) {
|
||||||
.buffer = lovrGraphicsGetIdentityBuffer(),
|
.buffer = lovrGraphicsGetIdentityBuffer(),
|
||||||
|
@ -1177,6 +1176,17 @@ static int l_lovrGraphicsNewMesh(lua_State* L) {
|
||||||
.enabled = true
|
.enabled = true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (dataIndex) {
|
||||||
|
VertexPointer vertices = { .raw = lovrBufferMap(vertexBuffer, 0) };
|
||||||
|
luax_loadvertices(L, dataIndex, &format, vertices);
|
||||||
|
} else if (vertexData) {
|
||||||
|
void* vertices = lovrBufferMap(vertexBuffer, 0);
|
||||||
|
memcpy(vertices, vertexData->blob.data, vertexData->count * vertexData->format.stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
lovrBufferFlush(vertexBuffer, 0, count * format.stride);
|
||||||
|
lovrRelease(vertexBuffer);
|
||||||
|
|
||||||
luax_pushobject(L, mesh);
|
luax_pushobject(L, mesh);
|
||||||
lovrRelease(mesh);
|
lovrRelease(mesh);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -3,9 +3,14 @@
|
||||||
|
|
||||||
int l_lovrFontGetWidth(lua_State* L) {
|
int l_lovrFontGetWidth(lua_State* L) {
|
||||||
Font* font = luax_checktype(L, 1, Font);
|
Font* font = luax_checktype(L, 1, Font);
|
||||||
const char* string = luaL_checkstring(L, 2);
|
size_t length;
|
||||||
|
const char* string = luaL_checklstring(L, 2, &length);
|
||||||
float wrap = luaL_optnumber(L, 3, 0);
|
float wrap = luaL_optnumber(L, 3, 0);
|
||||||
lua_pushnumber(L, lovrFontGetWidth(font, string, wrap));
|
float width;
|
||||||
|
uint32_t lineCount;
|
||||||
|
uint32_t glyphCount;
|
||||||
|
lovrFontMeasure(font, string, length, wrap, &width, &lineCount, &glyphCount);
|
||||||
|
lua_pushnumber(L, width);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,11 +76,22 @@ int l_lovrMeshDraw(lua_State* L) {
|
||||||
float transform[16];
|
float transform[16];
|
||||||
int index = luax_readmat4(L, 2, transform, 1, NULL);
|
int index = luax_readmat4(L, 2, transform, 1, NULL);
|
||||||
int instances = luaL_optinteger(L, index, 1);
|
int instances = luaL_optinteger(L, index, 1);
|
||||||
lovrGraphicsDraw(&(DrawRequest) {
|
uint32_t vertexCount = lovrMeshGetVertexCount(mesh);
|
||||||
|
uint32_t indexCount = lovrMeshGetIndexCount(mesh);
|
||||||
|
uint32_t defaultCount = indexCount > 0 ? indexCount : vertexCount;
|
||||||
|
uint32_t rangeStart, rangeCount;
|
||||||
|
lovrMeshGetDrawRange(mesh, &rangeStart, &rangeCount);
|
||||||
|
lovrGraphicsBatch(&(BatchRequest) {
|
||||||
|
.type = BATCH_MESH,
|
||||||
|
.params.mesh = {
|
||||||
|
.object = mesh,
|
||||||
|
.mode = lovrMeshGetDrawMode(mesh),
|
||||||
|
.rangeStart = rangeStart,
|
||||||
|
.rangeCount = rangeCount ? rangeCount : defaultCount,
|
||||||
|
.instances = instances
|
||||||
|
},
|
||||||
.transform = transform,
|
.transform = transform,
|
||||||
.mesh = mesh,
|
.material = lovrMeshGetMaterial(mesh)
|
||||||
.material = lovrMeshGetMaterial(mesh),
|
|
||||||
.instances = instances
|
|
||||||
});
|
});
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -113,47 +124,51 @@ int l_lovrMeshGetVertexCount(lua_State* L) {
|
||||||
int l_lovrMeshGetVertex(lua_State* L) {
|
int l_lovrMeshGetVertex(lua_State* L) {
|
||||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||||
int index = luaL_checkint(L, 2) - 1;
|
int index = luaL_checkint(L, 2) - 1;
|
||||||
lovrAssert(lovrMeshIsReadable(mesh), "Mesh:getVertex can only be used if the Mesh was created with the readable flag");
|
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||||
|
lovrAssert(lovrBufferIsReadable(buffer), "Mesh:getVertex can only be used if the Mesh was created with the readable flag");
|
||||||
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
|
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
|
||||||
VertexPointer vertex = { .raw = lovrMeshMapVertices(mesh, index * format->stride) };
|
VertexPointer vertex = { .raw = lovrBufferMap(buffer, index * format->stride) };
|
||||||
return luax_pushvertex(L, &vertex, format);
|
return luax_pushvertex(L, &vertex, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
int l_lovrMeshSetVertex(lua_State* L) {
|
int l_lovrMeshSetVertex(lua_State* L) {
|
||||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||||
int index = luaL_checkint(L, 2) - 1;
|
uint32_t index = luaL_checkinteger(L, 2) - 1;
|
||||||
lovrAssert(index >= 0 && index < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex index: %d", index + 1);
|
lovrAssert(index >= 0 && index < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex index: %d", index + 1);
|
||||||
|
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||||
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
|
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
|
||||||
VertexPointer vertex = { .raw = lovrMeshMapVertices(mesh, index * format->stride) };
|
VertexPointer vertex = { .raw = lovrBufferMap(buffer, index * format->stride) };
|
||||||
luax_setvertex(L, 3, &vertex, format);
|
luax_setvertex(L, 3, &vertex, format);
|
||||||
lovrMeshFlushVertices(mesh, index * format->stride, format->stride);
|
lovrMeshMarkVertices(mesh, index * format->stride, (index + 1) * format->stride);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int l_lovrMeshGetVertexAttribute(lua_State* L) {
|
int l_lovrMeshGetVertexAttribute(lua_State* L) {
|
||||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||||
int vertexIndex = luaL_checkint(L, 2) - 1;
|
uint32_t vertexIndex = luaL_checkinteger(L, 2) - 1;
|
||||||
int attributeIndex = luaL_checkint(L, 3) - 1;
|
int attributeIndex = luaL_checkinteger(L, 3) - 1;
|
||||||
|
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||||
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
|
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
|
||||||
lovrAssert(lovrMeshIsReadable(mesh), "Mesh:getVertex can only be used if the Mesh was created with the readable flag");
|
lovrAssert(lovrBufferIsReadable(buffer), "Mesh:getVertex can only be used if the Mesh was created with the readable flag");
|
||||||
lovrAssert(vertexIndex >= 0 && vertexIndex < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex: %d", vertexIndex + 1);
|
lovrAssert(vertexIndex >= 0 && vertexIndex < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex: %d", vertexIndex + 1);
|
||||||
lovrAssert(attributeIndex >= 0 && attributeIndex < format->count, "Invalid mesh attribute: %d", attributeIndex + 1);
|
lovrAssert(attributeIndex >= 0 && attributeIndex < format->count, "Invalid mesh attribute: %d", attributeIndex + 1);
|
||||||
Attribute attribute = format->attributes[attributeIndex];
|
Attribute attribute = format->attributes[attributeIndex];
|
||||||
VertexPointer vertex = { .raw = lovrMeshMapVertices(mesh, vertexIndex * format->stride + attribute.offset) };
|
VertexPointer vertex = { .raw = lovrBufferMap(buffer, vertexIndex * format->stride + attribute.offset) };
|
||||||
return luax_pushvertexattribute(L, &vertex, attribute);
|
return luax_pushvertexattribute(L, &vertex, attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
int l_lovrMeshSetVertexAttribute(lua_State* L) {
|
int l_lovrMeshSetVertexAttribute(lua_State* L) {
|
||||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||||
int vertexIndex = luaL_checkint(L, 2) - 1;
|
uint32_t vertexIndex = luaL_checkinteger(L, 2) - 1;
|
||||||
int attributeIndex = luaL_checkint(L, 3) - 1;
|
int attributeIndex = luaL_checkinteger(L, 3) - 1;
|
||||||
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
|
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
|
||||||
lovrAssert(vertexIndex >= 0 && vertexIndex < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex: %d", vertexIndex + 1);
|
lovrAssert(vertexIndex >= 0 && vertexIndex < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex: %d", vertexIndex + 1);
|
||||||
lovrAssert(attributeIndex >= 0 && attributeIndex < format->count, "Invalid mesh attribute: %d", attributeIndex + 1);
|
lovrAssert(attributeIndex >= 0 && attributeIndex < format->count, "Invalid mesh attribute: %d", attributeIndex + 1);
|
||||||
Attribute attribute = format->attributes[attributeIndex];
|
Attribute attribute = format->attributes[attributeIndex];
|
||||||
VertexPointer vertex = { .raw = lovrMeshMapVertices(mesh, vertexIndex * format->stride + attribute.offset) };
|
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||||
|
VertexPointer vertex = { .raw = lovrBufferMap(buffer, vertexIndex * format->stride + attribute.offset) };
|
||||||
luax_setvertexattribute(L, 4, &vertex, attribute);
|
luax_setvertexattribute(L, 4, &vertex, attribute);
|
||||||
lovrMeshFlushVertices(mesh, vertexIndex * format->stride + attribute.offset, attribute.size);
|
lovrMeshMarkVertices(mesh, vertexIndex * format->stride + attribute.offset, vertexIndex * format->stride + attribute.offset + attribute.size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,12 +188,13 @@ int l_lovrMeshSetVertices(lua_State* L) {
|
||||||
lovrAssert(sameFormat, "Mesh and VertexData must have the same format to copy vertices");
|
lovrAssert(sameFormat, "Mesh and VertexData must have the same format to copy vertices");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t start = luaL_optnumber(L, 3, 1) - 1;
|
uint32_t start = luaL_optinteger(L, 3, 1) - 1;
|
||||||
uint32_t count = luaL_optinteger(L, 4, sourceSize);
|
uint32_t count = luaL_optinteger(L, 4, sourceSize);
|
||||||
lovrAssert(start + count <= capacity, "Overflow in Mesh:setVertices: Mesh can only hold %d vertices", capacity);
|
lovrAssert(start + count <= capacity, "Overflow in Mesh:setVertices: Mesh can only hold %d vertices", capacity);
|
||||||
lovrAssert(count <= sourceSize, "Cannot set %d vertices on Mesh: source only has %d vertices", count, sourceSize);
|
lovrAssert(count <= sourceSize, "Cannot set %d vertices on Mesh: source only has %d vertices", count, sourceSize);
|
||||||
|
|
||||||
VertexPointer vertices = { .raw = lovrMeshMapVertices(mesh, start * format->stride) };
|
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||||
|
VertexPointer vertices = { .raw = lovrBufferMap(buffer, start * format->stride) };
|
||||||
|
|
||||||
if (vertexData) {
|
if (vertexData) {
|
||||||
memcpy(vertices.raw, vertexData->blob.data, count * format->stride);
|
memcpy(vertices.raw, vertexData->blob.data, count * format->stride);
|
||||||
|
@ -191,22 +207,25 @@ int l_lovrMeshSetVertices(lua_State* L) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lovrMeshFlushVertices(mesh, start * format->stride, count * format->stride);
|
lovrMeshMarkVertices(mesh, start * format->stride, (start + count) * format->stride);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int l_lovrMeshGetVertexMap(lua_State* L) {
|
int l_lovrMeshGetVertexMap(lua_State* L) {
|
||||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||||
uint32_t count;
|
Buffer* buffer = lovrMeshGetIndexBuffer(mesh);
|
||||||
size_t size;
|
uint32_t count = lovrMeshGetIndexCount(mesh);
|
||||||
IndexPointer indices = { .raw = lovrMeshReadIndices(mesh, &count, &size) };
|
size_t size = lovrMeshGetIndexSize(mesh);
|
||||||
|
|
||||||
if (count == 0 || !indices.raw) {
|
if (!buffer || count == 0 || size == 0) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lovrAssert(lovrBufferIsReadable(buffer), "Mesh:getVertexMap can only be used if the Mesh was created with the readable flag");
|
||||||
|
IndexPointer indices = { .raw = lovrBufferMap(buffer, 0) };
|
||||||
|
|
||||||
if (lua_istable(L, 2)) {
|
if (lua_istable(L, 2)) {
|
||||||
lua_settop(L, 2);
|
lua_settop(L, 2);
|
||||||
} else if (lua_isuserdata(L, 2)) {
|
} else if (lua_isuserdata(L, 2)) {
|
||||||
|
@ -232,7 +251,7 @@ int l_lovrMeshSetVertexMap(lua_State* L) {
|
||||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||||
|
|
||||||
if (lua_isnoneornil(L, 2)) {
|
if (lua_isnoneornil(L, 2)) {
|
||||||
lovrMeshMapIndices(mesh, 0, 0, 0);
|
lovrMeshSetIndexBuffer(mesh, NULL, 0, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,14 +260,33 @@ int l_lovrMeshSetVertexMap(lua_State* L) {
|
||||||
size_t size = luaL_optinteger(L, 3, 4);
|
size_t size = luaL_optinteger(L, 3, 4);
|
||||||
lovrAssert(size == 2 || size == 4, "Size of Mesh indices should be 2 bytes or 4 bytes");
|
lovrAssert(size == 2 || size == 4, "Size of Mesh indices should be 2 bytes or 4 bytes");
|
||||||
uint32_t count = blob->size / size;
|
uint32_t count = blob->size / size;
|
||||||
void* indices = lovrMeshMapIndices(mesh, count, size, 0);
|
Buffer* indexBuffer = lovrMeshGetIndexBuffer(mesh);
|
||||||
memcpy(indices, blob->data, blob->size);
|
if (!indexBuffer || count * size > lovrBufferGetSize(indexBuffer)) {
|
||||||
|
Buffer* vertexBuffer = lovrMeshGetVertexBuffer(mesh);
|
||||||
|
BufferUsage usage = vertexBuffer ? lovrBufferGetUsage(vertexBuffer) : USAGE_DYNAMIC;
|
||||||
|
bool readable = vertexBuffer ? lovrBufferIsReadable(vertexBuffer) : false;
|
||||||
|
indexBuffer = lovrBufferCreate(blob->size, blob->data, BUFFER_INDEX, usage, readable);
|
||||||
|
lovrMeshSetIndexBuffer(mesh, indexBuffer, count, size);
|
||||||
|
} else {
|
||||||
|
void* indices = lovrBufferMap(indexBuffer, 0);
|
||||||
|
memcpy(indices, blob->data, blob->size);
|
||||||
|
lovrBufferFlush(indexBuffer, 0, blob->size);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
luaL_checktype(L, 2, LUA_TTABLE);
|
luaL_checktype(L, 2, LUA_TTABLE);
|
||||||
uint32_t count = lua_objlen(L, 2);
|
uint32_t count = lua_objlen(L, 2);
|
||||||
uint32_t vertexCount = lovrMeshGetVertexCount(mesh);
|
uint32_t vertexCount = lovrMeshGetVertexCount(mesh);
|
||||||
size_t size = vertexCount > USHRT_MAX ? sizeof(uint32_t) : sizeof(uint16_t);
|
size_t size = vertexCount > USHRT_MAX ? sizeof(uint32_t) : sizeof(uint16_t);
|
||||||
IndexPointer indices = { .raw = lovrMeshMapIndices(mesh, count, size, 0) };
|
|
||||||
|
Buffer* indexBuffer = lovrMeshGetIndexBuffer(mesh);
|
||||||
|
if (!indexBuffer || count * size > lovrBufferGetSize(indexBuffer)) {
|
||||||
|
Buffer* vertexBuffer = lovrMeshGetVertexBuffer(mesh);
|
||||||
|
BufferUsage usage = vertexBuffer ? lovrBufferGetUsage(vertexBuffer) : USAGE_DYNAMIC;
|
||||||
|
bool readable = vertexBuffer ? lovrBufferIsReadable(vertexBuffer) : false;
|
||||||
|
indexBuffer = lovrBufferCreate(count * size, NULL, BUFFER_INDEX, usage, readable);
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexPointer indices = { .raw = lovrBufferMap(indexBuffer, 0) };
|
||||||
|
|
||||||
for (uint32_t i = 0; i < count; i++) {
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
lua_rawgeti(L, 2, i + 1);
|
lua_rawgeti(L, 2, i + 1);
|
||||||
|
@ -269,9 +307,10 @@ int l_lovrMeshSetVertexMap(lua_State* L) {
|
||||||
|
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
lovrMeshFlushIndices(mesh);
|
lovrMeshSetIndexBuffer(mesh, indexBuffer, count, size);
|
||||||
|
lovrBufferFlush(indexBuffer, 0, count * size);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
int l_lovrModelDraw(lua_State* L) {
|
int l_lovrModelDraw(lua_State* L) {
|
||||||
Model* model = luax_checktype(L, 1, Model);
|
Model* model = luax_checktype(L, 1, Model);
|
||||||
float transform[16];
|
float transform[16];
|
||||||
int index = luax_readmat4(L, 3, transform, 1, NULL);
|
int index = luax_readmat4(L, 2, transform, 1, NULL);
|
||||||
int instances = luaL_optinteger(L, index, 1);
|
int instances = luaL_optinteger(L, index, 1);
|
||||||
lovrModelDraw(model, transform, instances);
|
lovrModelDraw(model, transform, instances);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -248,7 +248,8 @@ int l_lovrShaderSendBlock(lua_State* L) {
|
||||||
const char* name = luaL_checkstring(L, 2);
|
const char* name = luaL_checkstring(L, 2);
|
||||||
ShaderBlock* block = luax_checktype(L, 3, ShaderBlock);
|
ShaderBlock* block = luax_checktype(L, 3, ShaderBlock);
|
||||||
UniformAccess access = luaL_checkoption(L, 4, "readwrite", UniformAccesses);
|
UniformAccess access = luaL_checkoption(L, 4, "readwrite", UniformAccesses);
|
||||||
lovrShaderSetBlock(shader, name, block, access);
|
Buffer* buffer = lovrShaderBlockGetBuffer(block);
|
||||||
|
lovrShaderSetBlock(shader, name, buffer, 0, lovrBufferGetSize(buffer), access);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,10 @@ size_t lovrBufferGetSize(Buffer* buffer) {
|
||||||
return buffer->size;
|
return buffer->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool lovrBufferIsReadable(Buffer* buffer) {
|
||||||
|
return buffer->readable;
|
||||||
|
}
|
||||||
|
|
||||||
BufferUsage lovrBufferGetUsage(Buffer* buffer) {
|
BufferUsage lovrBufferGetUsage(Buffer* buffer) {
|
||||||
return buffer->usage;
|
return buffer->usage;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,15 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BUFFER_VERTEX,
|
||||||
|
BUFFER_INDEX,
|
||||||
|
BUFFER_UNIFORM,
|
||||||
|
BUFFER_SHADER_STORAGE,
|
||||||
|
BUFFER_GENERIC,
|
||||||
|
MAX_BUFFER_TYPES
|
||||||
|
} BufferType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
USAGE_STATIC,
|
USAGE_STATIC,
|
||||||
USAGE_DYNAMIC,
|
USAGE_DYNAMIC,
|
||||||
|
@ -15,16 +24,17 @@ typedef struct {
|
||||||
Ref ref;
|
Ref ref;
|
||||||
void* data;
|
void* data;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
bool readable;
|
||||||
|
BufferType type;
|
||||||
BufferUsage usage;
|
BufferUsage usage;
|
||||||
GPU_BUFFER_FIELDS
|
GPU_BUFFER_FIELDS
|
||||||
} Buffer;
|
} Buffer;
|
||||||
|
|
||||||
Buffer* lovrBufferInit(Buffer* buffer, size_t size, void* data, BufferUsage usage, bool readable);
|
Buffer* lovrBufferInit(Buffer* buffer, size_t size, void* data, BufferType type, BufferUsage usage, bool readable);
|
||||||
#define lovrBufferCreate(...) lovrBufferInit(lovrAlloc(Buffer), __VA_ARGS__)
|
#define lovrBufferCreate(...) lovrBufferInit(lovrAlloc(Buffer), __VA_ARGS__)
|
||||||
void lovrBufferDestroy(void* ref);
|
void lovrBufferDestroy(void* ref);
|
||||||
size_t lovrBufferGetSize(Buffer* buffer);
|
size_t lovrBufferGetSize(Buffer* buffer);
|
||||||
|
bool lovrBufferIsReadable(Buffer* buffer);
|
||||||
BufferUsage lovrBufferGetUsage(Buffer* buffer);
|
BufferUsage lovrBufferGetUsage(Buffer* buffer);
|
||||||
void* lovrBufferMap(Buffer* buffer, size_t offset);
|
void* lovrBufferMap(Buffer* buffer, size_t offset);
|
||||||
void lovrBufferFlush(Buffer* buffer, size_t offset, size_t size);
|
void lovrBufferFlush(Buffer* buffer, size_t offset, size_t size);
|
||||||
void lovrBufferLock(Buffer* buffer);
|
|
||||||
void lovrBufferUnlock(Buffer* buffer);
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "graphics/canvas.h"
|
#include "graphics/canvas.h"
|
||||||
|
#include "graphics/graphics.h"
|
||||||
|
|
||||||
const Attachment* lovrCanvasGetAttachments(Canvas* canvas, int* count) {
|
const Attachment* lovrCanvasGetAttachments(Canvas* canvas, int* count) {
|
||||||
if (count) *count = canvas->attachmentCount;
|
if (count) *count = canvas->attachmentCount;
|
||||||
|
@ -13,6 +14,8 @@ void lovrCanvasSetAttachments(Canvas* canvas, Attachment* attachments, int count
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lovrGraphicsFlushCanvas(canvas);
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
Texture* texture = attachments[i].texture;
|
Texture* texture = attachments[i].texture;
|
||||||
int width = lovrTextureGetWidth(texture, attachments[i].level);
|
int width = lovrTextureGetWidth(texture, attachments[i].level);
|
||||||
|
|
|
@ -68,7 +68,7 @@ Rasterizer* lovrFontGetRasterizer(Font* font) {
|
||||||
return font->rasterizer;
|
return font->rasterizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrFontRender(Font* font, const char* str, size_t length, float wrap, HorizontalAlign halign, VerticalAlign valign, float* vertices, float* offsety, uint32_t* vertexCount) {
|
void lovrFontRender(Font* font, const char* str, size_t length, float wrap, HorizontalAlign halign, float* vertices, uint16_t* indices, uint16_t baseVertex) {
|
||||||
FontAtlas* atlas = &font->atlas;
|
FontAtlas* atlas = &font->atlas;
|
||||||
|
|
||||||
float cx = 0;
|
float cx = 0;
|
||||||
|
@ -83,17 +83,16 @@ void lovrFontRender(Font* font, const char* str, size_t length, float wrap, Hori
|
||||||
unsigned int codepoint;
|
unsigned int codepoint;
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
|
|
||||||
float* cursor = vertices;
|
float* vertexCursor = vertices;
|
||||||
|
uint16_t* indexCursor = indices;
|
||||||
float* lineStart = vertices;
|
float* lineStart = vertices;
|
||||||
int lineCount = 1;
|
uint16_t I = baseVertex;
|
||||||
*vertexCount = 0;
|
|
||||||
|
|
||||||
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
||||||
|
|
||||||
// Newlines
|
// Newlines
|
||||||
if (codepoint == '\n' || (wrap && cx * scale > wrap && codepoint == ' ')) {
|
if (codepoint == '\n' || (wrap && cx * scale > wrap && codepoint == ' ')) {
|
||||||
lineStart = lovrFontAlignLine(lineStart, cursor, cx, halign);
|
lineStart = lovrFontAlignLine(lineStart, vertexCursor, cx, halign);
|
||||||
lineCount++;
|
|
||||||
cx = 0;
|
cx = 0;
|
||||||
cy -= font->rasterizer->height * font->lineHeight;
|
cy -= font->rasterizer->height * font->lineHeight;
|
||||||
previous = '\0';
|
previous = '\0';
|
||||||
|
@ -118,7 +117,7 @@ void lovrFontRender(Font* font, const char* str, size_t length, float wrap, Hori
|
||||||
|
|
||||||
// Start over if texture was repacked
|
// Start over if texture was repacked
|
||||||
if (u != atlas->width || v != atlas->height) {
|
if (u != atlas->width || v != atlas->height) {
|
||||||
lovrFontRender(font, start, length, wrap, halign, valign, vertices, offsety, vertexCount);
|
lovrFontRender(font, start, length, wrap, halign, vertices, indices, baseVertex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,18 +132,18 @@ void lovrFontRender(Font* font, const char* str, size_t length, float wrap, Hori
|
||||||
float s2 = (glyph->x + glyph->tw) / u;
|
float s2 = (glyph->x + glyph->tw) / u;
|
||||||
float t2 = glyph->y / v;
|
float t2 = glyph->y / v;
|
||||||
|
|
||||||
float quad[48] = {
|
memcpy(vertexCursor, (float[32]) {
|
||||||
x1, y1, 0, 0, 0, 0, s1, t1,
|
x1, y1, 0, 0, 0, 0, s1, t1,
|
||||||
x1, y2, 0, 0, 0, 0, s1, t2,
|
x1, y2, 0, 0, 0, 0, s1, t2,
|
||||||
x2, y1, 0, 0, 0, 0, s2, t1,
|
x2, y1, 0, 0, 0, 0, s2, t1,
|
||||||
x2, y1, 0, 0, 0, 0, s2, t1,
|
|
||||||
x1, y2, 0, 0, 0, 0, s1, t2,
|
|
||||||
x2, y2, 0, 0, 0, 0, s2, t2
|
x2, y2, 0, 0, 0, 0, s2, t2
|
||||||
};
|
}, 32 * sizeof(float));
|
||||||
|
|
||||||
memcpy(cursor, quad, 6 * 8 * sizeof(float));
|
memcpy(indexCursor, (uint16_t[6]) { I + 0, I + 1, I + 2, I + 2, I + 1, I + 3 }, 6 * sizeof(uint16_t));
|
||||||
cursor += 48;
|
|
||||||
*vertexCount += 6;
|
vertexCursor += 32;
|
||||||
|
indexCursor += 6;
|
||||||
|
I += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advance cursor
|
// Advance cursor
|
||||||
|
@ -153,30 +152,24 @@ void lovrFontRender(Font* font, const char* str, size_t length, float wrap, Hori
|
||||||
}
|
}
|
||||||
|
|
||||||
// Align the last line
|
// Align the last line
|
||||||
lovrFontAlignLine(lineStart, cursor, cx, halign);
|
lovrFontAlignLine(lineStart, vertexCursor, cx, halign);
|
||||||
|
|
||||||
// Calculate vertical offset
|
|
||||||
if (valign == ALIGN_MIDDLE) {
|
|
||||||
*offsety = lineCount * font->rasterizer->height * font->lineHeight * .5f;
|
|
||||||
} else if (valign == ALIGN_BOTTOM) {
|
|
||||||
*offsety = lineCount * font->rasterizer->height * font->lineHeight;
|
|
||||||
} else {
|
|
||||||
*offsety = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float lovrFontGetWidth(Font* font, const char* str, float wrap) {
|
void lovrFontMeasure(Font* font, const char* str, size_t length, float wrap, float* width, uint32_t* lineCount, uint32_t* glyphCount) {
|
||||||
float width = 0;
|
|
||||||
float x = 0;
|
float x = 0;
|
||||||
const char* end = str + strlen(str);
|
const char* end = str + length;
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
unsigned int previous = '\0';
|
unsigned int previous = '\0';
|
||||||
unsigned int codepoint;
|
unsigned int codepoint;
|
||||||
float scale = 1 / font->pixelDensity;
|
float scale = 1 / font->pixelDensity;
|
||||||
|
*width = 0.f;
|
||||||
|
*lineCount = 0;
|
||||||
|
*glyphCount = 0;
|
||||||
|
|
||||||
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
||||||
if (codepoint == '\n' || (wrap && x * scale > wrap && codepoint == ' ')) {
|
if (codepoint == '\n' || (wrap && x * scale > wrap && codepoint == ' ')) {
|
||||||
width = MAX(width, x * scale);
|
*width = MAX(*width, x * scale);
|
||||||
|
(*lineCount)++;
|
||||||
x = 0;
|
x = 0;
|
||||||
previous = '\0';
|
previous = '\0';
|
||||||
str += bytes;
|
str += bytes;
|
||||||
|
@ -192,12 +185,17 @@ float lovrFontGetWidth(Font* font, const char* str, float wrap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Glyph* glyph = lovrFontGetGlyph(font, codepoint);
|
Glyph* glyph = lovrFontGetGlyph(font, codepoint);
|
||||||
|
|
||||||
|
if (glyph->w > 0 && glyph->h > 0) {
|
||||||
|
(*glyphCount)++;
|
||||||
|
}
|
||||||
|
|
||||||
x += glyph->advance + lovrFontGetKerning(font, previous, codepoint);
|
x += glyph->advance + lovrFontGetKerning(font, previous, codepoint);
|
||||||
previous = codepoint;
|
previous = codepoint;
|
||||||
str += bytes;
|
str += bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MAX(width, x * scale);
|
*width = MAX(*width, x * scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
float lovrFontGetHeight(Font* font) {
|
float lovrFontGetHeight(Font* font) {
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ALIGN_LEFT,
|
ALIGN_LEFT,
|
||||||
ALIGN_RIGHT,
|
ALIGN_CENTER,
|
||||||
ALIGN_CENTER
|
ALIGN_RIGHT
|
||||||
} HorizontalAlign;
|
} HorizontalAlign;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ALIGN_TOP,
|
ALIGN_TOP,
|
||||||
ALIGN_BOTTOM,
|
ALIGN_MIDDLE,
|
||||||
ALIGN_MIDDLE
|
ALIGN_BOTTOM
|
||||||
} VerticalAlign;
|
} VerticalAlign;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -42,8 +42,8 @@ Font* lovrFontInit(Font* font, Rasterizer* rasterizer);
|
||||||
#define lovrFontCreate(...) lovrFontInit(lovrAlloc(Font), __VA_ARGS__)
|
#define lovrFontCreate(...) lovrFontInit(lovrAlloc(Font), __VA_ARGS__)
|
||||||
void lovrFontDestroy(void* ref);
|
void lovrFontDestroy(void* ref);
|
||||||
Rasterizer* lovrFontGetRasterizer(Font* font);
|
Rasterizer* lovrFontGetRasterizer(Font* font);
|
||||||
void lovrFontRender(Font* font, const char* str, size_t length, float wrap, HorizontalAlign halign, VerticalAlign valign, float* vertices, float* offsety, uint32_t* vertexCount);
|
void lovrFontRender(Font* font, const char* str, size_t length, float wrap, HorizontalAlign halign, float* vertices, uint16_t* indices, uint16_t baseVertex);
|
||||||
float lovrFontGetWidth(Font* font, const char* string, float wrap);
|
void lovrFontMeasure(Font* font, const char* string, size_t length, float wrap, float* width, uint32_t* lineCount, uint32_t* glyphCount);
|
||||||
float lovrFontGetHeight(Font* font);
|
float lovrFontGetHeight(Font* font);
|
||||||
float lovrFontGetAscent(Font* font);
|
float lovrFontGetAscent(Font* font);
|
||||||
float lovrFontGetDescent(Font* font);
|
float lovrFontGetDescent(Font* font);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -13,9 +13,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define MAX_TRANSFORMS 64
|
#define MAX_TRANSFORMS 64
|
||||||
#define MAX_VERTICES (1 << 16)
|
#define MAX_BATCHES 16
|
||||||
#define MAX_INDICES (1 << 16)
|
#define MAX_LOCKS 4
|
||||||
#define MAX_BATCH_SIZE 192 // Enough to fit in any UBO
|
|
||||||
|
|
||||||
typedef void (*StencilCallback)(void* userdata);
|
typedef void (*StencilCallback)(void* userdata);
|
||||||
|
|
||||||
|
@ -33,7 +32,7 @@ typedef enum {
|
||||||
BLEND_LIGHTEN,
|
BLEND_LIGHTEN,
|
||||||
BLEND_DARKEN,
|
BLEND_DARKEN,
|
||||||
BLEND_SCREEN,
|
BLEND_SCREEN,
|
||||||
BLEND_REPLACE
|
BLEND_NONE
|
||||||
} BlendMode;
|
} BlendMode;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -70,27 +69,6 @@ typedef enum {
|
||||||
WINDING_COUNTERCLOCKWISE
|
WINDING_COUNTERCLOCKWISE
|
||||||
} Winding;
|
} Winding;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
bool computeShaders;
|
|
||||||
bool singlepass;
|
|
||||||
} GpuFeatures;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
bool initialized;
|
|
||||||
float pointSizes[2];
|
|
||||||
int textureSize;
|
|
||||||
int textureMSAA;
|
|
||||||
float textureAnisotropy;
|
|
||||||
int blockSize;
|
|
||||||
} GpuLimits;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int shaderSwitches;
|
|
||||||
int drawCalls;
|
|
||||||
} GpuStats;
|
|
||||||
|
|
||||||
// Internal
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool stereo;
|
bool stereo;
|
||||||
Canvas* canvas;
|
Canvas* canvas;
|
||||||
|
@ -99,34 +77,87 @@ typedef struct {
|
||||||
} Camera;
|
} Camera;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
BlendMode blendMode : 3;
|
float transform[16];
|
||||||
BlendAlphaMode blendAlphaMode : 1;
|
Color color;
|
||||||
CompareMode depthTest : 3;
|
} DrawData;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool alphaSampling : 1;
|
||||||
|
uint8_t blendMode : 3; // BlendMode
|
||||||
|
uint8_t blendAlphaMode : 1; // BlendAlphaMode
|
||||||
|
bool culling : 1;
|
||||||
|
uint8_t depthTest : 3; // CompareMode
|
||||||
bool depthWrite : 1;
|
bool depthWrite : 1;
|
||||||
uint8_t lineWidth : 8;
|
uint8_t lineWidth : 8;
|
||||||
uint8_t stencilValue: 8;
|
uint8_t stencilValue: 8;
|
||||||
CompareMode stencilMode : 3;
|
uint8_t stencilMode : 3; // CompareMode
|
||||||
bool alphaSampling : 1;
|
uint8_t winding : 1; // Winding
|
||||||
bool culling : 1;
|
|
||||||
Winding winding : 1;
|
|
||||||
bool wireframe : 1;
|
bool wireframe : 1;
|
||||||
} Pipeline;
|
} Pipeline;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
STREAM_VERTEX,
|
||||||
|
STREAM_INDEX,
|
||||||
|
STREAM_DRAW_ID,
|
||||||
|
STREAM_DRAW_DATA,
|
||||||
|
MAX_BUFFER_ROLES
|
||||||
|
} BufferRole;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BATCH_POINTS,
|
||||||
|
BATCH_LINES,
|
||||||
|
BATCH_TRIANGLES,
|
||||||
|
BATCH_PLANE,
|
||||||
|
BATCH_BOX,
|
||||||
|
BATCH_ARC,
|
||||||
|
BATCH_SPHERE,
|
||||||
|
BATCH_SKYBOX,
|
||||||
|
BATCH_TEXT,
|
||||||
|
BATCH_FILL,
|
||||||
|
BATCH_MESH
|
||||||
|
} BatchType;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
struct { DrawStyle style; } triangles;
|
||||||
|
struct { DrawStyle style; } plane;
|
||||||
|
struct { DrawStyle style; } box;
|
||||||
|
struct { DrawStyle style; ArcMode mode; float r1; float r2; int segments; } arc;
|
||||||
|
struct { int segments; } sphere;
|
||||||
|
struct { float u; float v; float w; float h; } fill;
|
||||||
|
struct { Mesh* object; DrawMode mode; uint32_t rangeStart; uint32_t rangeCount; uint32_t instances; float* pose; } mesh;
|
||||||
|
} BatchParams;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Mesh* mesh;
|
BatchType type;
|
||||||
DrawMode mode;
|
BatchParams params;
|
||||||
struct { uint32_t count; float* data; } vertex;
|
|
||||||
struct { uint32_t count; uint16_t* data; } index;
|
|
||||||
DefaultShader shader;
|
DefaultShader shader;
|
||||||
|
Pipeline* pipeline;
|
||||||
|
Material* material;
|
||||||
Texture* diffuseTexture;
|
Texture* diffuseTexture;
|
||||||
Texture* environmentMap;
|
Texture* environmentMap;
|
||||||
Material* material;
|
|
||||||
Pipeline* pipeline;
|
|
||||||
mat4 transform;
|
mat4 transform;
|
||||||
float* pose;
|
uint32_t vertexCount;
|
||||||
int instances;
|
uint32_t indexCount;
|
||||||
bool mono;
|
float** vertices;
|
||||||
} DrawRequest;
|
uint16_t** indices;
|
||||||
|
uint16_t* baseVertex;
|
||||||
|
} BatchRequest;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
BatchType type;
|
||||||
|
BatchParams params;
|
||||||
|
Canvas* canvas;
|
||||||
|
Shader* shader;
|
||||||
|
Pipeline pipeline;
|
||||||
|
Material* material;
|
||||||
|
uint32_t vertexStart;
|
||||||
|
uint32_t vertexCount;
|
||||||
|
uint32_t indexStart;
|
||||||
|
uint32_t indexCount;
|
||||||
|
uint32_t drawStart;
|
||||||
|
uint32_t drawCount;
|
||||||
|
DrawData* drawData;
|
||||||
|
} Batch;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool initialized;
|
bool initialized;
|
||||||
|
@ -137,7 +168,6 @@ typedef struct {
|
||||||
Shader* defaultShaders[MAX_DEFAULT_SHADERS];
|
Shader* defaultShaders[MAX_DEFAULT_SHADERS];
|
||||||
Material* defaultMaterial;
|
Material* defaultMaterial;
|
||||||
Font* defaultFont;
|
Font* defaultFont;
|
||||||
Mesh* defaultMesh;
|
|
||||||
TextureFilter defaultFilter;
|
TextureFilter defaultFilter;
|
||||||
float transforms[MAX_TRANSFORMS][16];
|
float transforms[MAX_TRANSFORMS][16];
|
||||||
int transform;
|
int transform;
|
||||||
|
@ -148,15 +178,15 @@ typedef struct {
|
||||||
Pipeline pipeline;
|
Pipeline pipeline;
|
||||||
float pointSize;
|
float pointSize;
|
||||||
Shader* shader;
|
Shader* shader;
|
||||||
DrawRequest batch;
|
uint32_t maxDraws;
|
||||||
int batchVertex;
|
Mesh* mesh;
|
||||||
int batchIndex;
|
Mesh* instancedMesh;
|
||||||
int batchSize;
|
|
||||||
int vertexCursor;
|
|
||||||
int indexCursor;
|
|
||||||
ShaderBlock* block;
|
|
||||||
Buffer* vertexMap;
|
|
||||||
Buffer* identityBuffer;
|
Buffer* identityBuffer;
|
||||||
|
Buffer* buffers[MAX_BUFFER_ROLES];
|
||||||
|
size_t cursors[MAX_BUFFER_ROLES];
|
||||||
|
void* locks[MAX_BUFFER_ROLES][MAX_LOCKS];
|
||||||
|
Batch batches[MAX_BATCHES];
|
||||||
|
uint8_t batchCount;
|
||||||
} GraphicsState;
|
} GraphicsState;
|
||||||
|
|
||||||
// Base
|
// Base
|
||||||
|
@ -167,6 +197,7 @@ void lovrGraphicsSetWindow(WindowFlags* flags);
|
||||||
int lovrGraphicsGetWidth();
|
int lovrGraphicsGetWidth();
|
||||||
int lovrGraphicsGetHeight();
|
int lovrGraphicsGetHeight();
|
||||||
void lovrGraphicsSetCamera(Camera* camera, bool clear);
|
void lovrGraphicsSetCamera(Camera* camera, bool clear);
|
||||||
|
void* lovrGraphicsMapBuffer(BufferRole role, uint32_t count);
|
||||||
Buffer* lovrGraphicsGetIdentityBuffer();
|
Buffer* lovrGraphicsGetIdentityBuffer();
|
||||||
#define lovrGraphicsGetSupported lovrGpuGetSupported
|
#define lovrGraphicsGetSupported lovrGpuGetSupported
|
||||||
#define lovrGraphicsGetLimits lovrGpuGetLimits
|
#define lovrGraphicsGetLimits lovrGpuGetLimits
|
||||||
|
@ -217,18 +248,20 @@ void lovrGraphicsMatrixTransform(mat4 transform);
|
||||||
void lovrGraphicsSetProjection(mat4 projection);
|
void lovrGraphicsSetProjection(mat4 projection);
|
||||||
|
|
||||||
// Rendering
|
// Rendering
|
||||||
float* lovrGraphicsGetVertexPointer(uint32_t count);
|
|
||||||
uint16_t* lovrGraphicsGetIndexPointer(uint32_t count);
|
|
||||||
void lovrGraphicsClear(Color* color, float* depth, int* stencil);
|
void lovrGraphicsClear(Color* color, float* depth, int* stencil);
|
||||||
void lovrGraphicsDiscard(bool color, bool depth, bool stencil);
|
void lovrGraphicsDiscard(bool color, bool depth, bool stencil);
|
||||||
|
void lovrGraphicsBatch(BatchRequest* req);
|
||||||
void lovrGraphicsFlush();
|
void lovrGraphicsFlush();
|
||||||
void lovrGraphicsDraw(DrawRequest* draw);
|
void lovrGraphicsFlushCanvas(Canvas* canvas);
|
||||||
void lovrGraphicsPoints(uint32_t count);
|
void lovrGraphicsFlushShader(Shader* shader);
|
||||||
void lovrGraphicsLine(uint32_t count);
|
void lovrGraphicsFlushMaterial(Material* material);
|
||||||
void lovrGraphicsTriangle(DrawStyle style, Material* material, float points[9]);
|
void lovrGraphicsFlushMesh(Mesh* mesh);
|
||||||
|
void lovrGraphicsPoints(uint32_t count, float** vertices);
|
||||||
|
void lovrGraphicsLine(uint32_t count, float** vertices);
|
||||||
|
void lovrGraphicsTriangle(DrawStyle style, Material* material, uint32_t count, float** vertices);
|
||||||
void lovrGraphicsPlane(DrawStyle style, Material* material, mat4 transform);
|
void lovrGraphicsPlane(DrawStyle style, Material* material, mat4 transform);
|
||||||
void lovrGraphicsBox(DrawStyle style, Material* material, mat4 transform);
|
void lovrGraphicsBox(DrawStyle style, Material* material, mat4 transform);
|
||||||
void lovrGraphicsArc(DrawStyle style, ArcMode, Material* material, mat4 transform, float theta1, float theta2, int segments);
|
void lovrGraphicsArc(DrawStyle style, ArcMode mode, Material* material, mat4 transform, float r1, float r2, int segments);
|
||||||
void lovrGraphicsCircle(DrawStyle style, Material* material, mat4 transform, int segments);
|
void lovrGraphicsCircle(DrawStyle style, Material* material, mat4 transform, int segments);
|
||||||
void lovrGraphicsCylinder(Material* material, float x1, float y1, float z1, float x2, float y2, float z2, float r1, float r2, bool capped, int segments);
|
void lovrGraphicsCylinder(Material* material, float x1, float y1, float z1, float x2, float y2, float z2, float r1, float r2, bool capped, int segments);
|
||||||
void lovrGraphicsSphere(Material* material, mat4 transform, int segments);
|
void lovrGraphicsSphere(Material* material, mat4 transform, int segments);
|
||||||
|
@ -238,14 +271,37 @@ void lovrGraphicsFill(Texture* texture, float u, float v, float w, float h);
|
||||||
#define lovrGraphicsStencil lovrGpuStencil
|
#define lovrGraphicsStencil lovrGpuStencil
|
||||||
#define lovrGraphicsCompute lovrGpuCompute
|
#define lovrGraphicsCompute lovrGpuCompute
|
||||||
|
|
||||||
// GPU API
|
// GPU
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool computeShaders;
|
||||||
|
bool singlepass;
|
||||||
|
} GpuFeatures;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool initialized;
|
||||||
|
float pointSizes[2];
|
||||||
|
int textureSize;
|
||||||
|
int textureMSAA;
|
||||||
|
float textureAnisotropy;
|
||||||
|
int blockSize;
|
||||||
|
int blockAlign;
|
||||||
|
} GpuLimits;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int shaderSwitches;
|
||||||
|
int drawCalls;
|
||||||
|
} GpuStats;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Mesh* mesh;
|
Mesh* mesh;
|
||||||
Shader* shader;
|
|
||||||
Canvas* canvas;
|
Canvas* canvas;
|
||||||
|
Shader* shader;
|
||||||
Pipeline pipeline;
|
Pipeline pipeline;
|
||||||
|
DrawMode drawMode;
|
||||||
uint32_t instances;
|
uint32_t instances;
|
||||||
|
uint32_t rangeStart;
|
||||||
|
uint32_t rangeCount;
|
||||||
uint32_t width : 15;
|
uint32_t width : 15;
|
||||||
uint32_t height : 15;
|
uint32_t height : 15;
|
||||||
bool stereo : 1;
|
bool stereo : 1;
|
||||||
|
@ -256,10 +312,13 @@ void lovrGpuDestroy();
|
||||||
void lovrGpuClear(Canvas* canvas, Color* color, float* depth, int* stencil);
|
void lovrGpuClear(Canvas* canvas, Color* color, float* depth, int* stencil);
|
||||||
void lovrGpuCompute(Shader* shader, int x, int y, int z);
|
void lovrGpuCompute(Shader* shader, int x, int y, int z);
|
||||||
void lovrGpuDiscard(Canvas* canvas, bool color, bool depth, bool stencil);
|
void lovrGpuDiscard(Canvas* canvas, bool color, bool depth, bool stencil);
|
||||||
void lovrGpuDraw(DrawCommand* commands, int count);
|
void lovrGpuDraw(DrawCommand* draw);
|
||||||
void lovrGpuStencil(StencilAction action, int replaceValue, StencilCallback callback, void* userdata);
|
void lovrGpuStencil(StencilAction action, int replaceValue, StencilCallback callback, void* userdata);
|
||||||
void lovrGpuPresent();
|
void lovrGpuPresent();
|
||||||
void lovrGpuDirtyTexture();
|
void lovrGpuDirtyTexture();
|
||||||
|
void* lovrGpuLock();
|
||||||
|
void lovrGpuUnlock(void* lock);
|
||||||
|
void lovrGpuDestroyLock(void* lock);
|
||||||
const GpuFeatures* lovrGpuGetSupported();
|
const GpuFeatures* lovrGpuGetSupported();
|
||||||
const GpuLimits* lovrGpuGetLimits();
|
const GpuLimits* lovrGpuGetLimits();
|
||||||
const GpuStats* lovrGpuGetStats();
|
const GpuStats* lovrGpuGetStats();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "graphics/material.h"
|
#include "graphics/material.h"
|
||||||
|
#include "graphics/graphics.h"
|
||||||
#include "resources/shaders.h"
|
#include "resources/shaders.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -41,12 +42,6 @@ void lovrMaterialBind(Material* material, Shader* shader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
lovrShaderSetMatrices(shader, "lovrMaterialTransform", material->transform, 0, 9);
|
lovrShaderSetMatrices(shader, "lovrMaterialTransform", material->transform, 0, 9);
|
||||||
|
|
||||||
material->dirty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lovrMaterialIsDirty(Material* material) {
|
|
||||||
return material->dirty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float lovrMaterialGetScalar(Material* material, MaterialScalar scalarType) {
|
float lovrMaterialGetScalar(Material* material, MaterialScalar scalarType) {
|
||||||
|
@ -55,8 +50,8 @@ float lovrMaterialGetScalar(Material* material, MaterialScalar scalarType) {
|
||||||
|
|
||||||
void lovrMaterialSetScalar(Material* material, MaterialScalar scalarType, float value) {
|
void lovrMaterialSetScalar(Material* material, MaterialScalar scalarType, float value) {
|
||||||
if (material->scalars[scalarType] != value) {
|
if (material->scalars[scalarType] != value) {
|
||||||
|
lovrGraphicsFlushMaterial(material);
|
||||||
material->scalars[scalarType] = value;
|
material->scalars[scalarType] = value;
|
||||||
material->dirty = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,8 +61,8 @@ Color lovrMaterialGetColor(Material* material, MaterialColor colorType) {
|
||||||
|
|
||||||
void lovrMaterialSetColor(Material* material, MaterialColor colorType, Color color) {
|
void lovrMaterialSetColor(Material* material, MaterialColor colorType, Color color) {
|
||||||
if (memcmp(&material->colors[colorType], &color, 4 * sizeof(float))) {
|
if (memcmp(&material->colors[colorType], &color, 4 * sizeof(float))) {
|
||||||
|
lovrGraphicsFlushMaterial(material);
|
||||||
material->colors[colorType] = color;
|
material->colors[colorType] = color;
|
||||||
material->dirty = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,10 +72,10 @@ Texture* lovrMaterialGetTexture(Material* material, MaterialTexture textureType)
|
||||||
|
|
||||||
void lovrMaterialSetTexture(Material* material, MaterialTexture textureType, Texture* texture) {
|
void lovrMaterialSetTexture(Material* material, MaterialTexture textureType, Texture* texture) {
|
||||||
if (material->textures[textureType] != texture) {
|
if (material->textures[textureType] != texture) {
|
||||||
|
lovrGraphicsFlushMaterial(material);
|
||||||
lovrRetain(texture);
|
lovrRetain(texture);
|
||||||
lovrRelease(material->textures[textureType]);
|
lovrRelease(material->textures[textureType]);
|
||||||
material->textures[textureType] = texture;
|
material->textures[textureType] = texture;
|
||||||
material->dirty = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +88,7 @@ void lovrMaterialGetTransform(Material* material, float* ox, float* oy, float* s
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrMaterialSetTransform(Material* material, float ox, float oy, float sx, float sy, float angle) {
|
void lovrMaterialSetTransform(Material* material, float ox, float oy, float sx, float sy, float angle) {
|
||||||
|
lovrGraphicsFlushMaterial(material);
|
||||||
float c = cos(angle);
|
float c = cos(angle);
|
||||||
float s = sin(angle);
|
float s = sin(angle);
|
||||||
material->transform[0] = c * sx;
|
material->transform[0] = c * sx;
|
||||||
|
@ -104,5 +100,4 @@ void lovrMaterialSetTransform(Material* material, float ox, float oy, float sx,
|
||||||
material->transform[6] = ox;
|
material->transform[6] = ox;
|
||||||
material->transform[7] = oy;
|
material->transform[7] = oy;
|
||||||
material->transform[8] = 1;
|
material->transform[8] = 1;
|
||||||
material->dirty = true;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,14 +34,12 @@ typedef struct {
|
||||||
Color colors[MAX_MATERIAL_COLORS];
|
Color colors[MAX_MATERIAL_COLORS];
|
||||||
Texture* textures[MAX_MATERIAL_TEXTURES];
|
Texture* textures[MAX_MATERIAL_TEXTURES];
|
||||||
float transform[9];
|
float transform[9];
|
||||||
bool dirty;
|
|
||||||
} Material;
|
} Material;
|
||||||
|
|
||||||
Material* lovrMaterialInit(Material* material);
|
Material* lovrMaterialInit(Material* material);
|
||||||
#define lovrMaterialCreate() lovrMaterialInit(lovrAlloc(Material))
|
#define lovrMaterialCreate() lovrMaterialInit(lovrAlloc(Material))
|
||||||
void lovrMaterialDestroy(void* ref);
|
void lovrMaterialDestroy(void* ref);
|
||||||
void lovrMaterialBind(Material* material, Shader* shader);
|
void lovrMaterialBind(Material* material, Shader* shader);
|
||||||
bool lovrMaterialIsDirty(Material* material);
|
|
||||||
float lovrMaterialGetScalar(Material* material, MaterialScalar scalarType);
|
float lovrMaterialGetScalar(Material* material, MaterialScalar scalarType);
|
||||||
void lovrMaterialSetScalar(Material* material, MaterialScalar scalarType, float value);
|
void lovrMaterialSetScalar(Material* material, MaterialScalar scalarType, float value);
|
||||||
Color lovrMaterialGetColor(Material* material, MaterialColor colorType);
|
Color lovrMaterialGetColor(Material* material, MaterialColor colorType);
|
||||||
|
|
|
@ -1,8 +1,50 @@
|
||||||
#include "graphics/mesh.h"
|
#include "graphics/mesh.h"
|
||||||
|
#include "graphics/graphics.h"
|
||||||
|
|
||||||
|
VertexFormat* lovrMeshGetVertexFormat(Mesh* mesh) {
|
||||||
|
return &mesh->format;
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer* lovrMeshGetVertexBuffer(Mesh* mesh) {
|
||||||
|
return mesh->vertexBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer* lovrMeshGetIndexBuffer(Mesh* mesh) {
|
||||||
|
return mesh->indexBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lovrMeshSetIndexBuffer(Mesh* mesh, Buffer* buffer, uint32_t indexCount, size_t indexSize) {
|
||||||
|
if (mesh->indexBuffer != buffer || mesh->indexCount != indexCount || mesh->indexSize != indexSize) {
|
||||||
|
lovrGraphicsFlushMesh(mesh);
|
||||||
|
lovrRetain(buffer);
|
||||||
|
lovrRelease(mesh->indexBuffer);
|
||||||
|
mesh->indexBuffer = buffer;
|
||||||
|
mesh->indexCount = indexCount;
|
||||||
|
mesh->indexSize = indexSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t lovrMeshGetVertexCount(Mesh* mesh) {
|
||||||
|
return mesh->vertexCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t lovrMeshGetIndexCount(Mesh* mesh) {
|
||||||
|
return mesh->indexCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t lovrMeshGetIndexSize(Mesh* mesh) {
|
||||||
|
return mesh->indexSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lovrMeshMarkVertices(Mesh* mesh, size_t start, size_t end) {
|
||||||
|
mesh->flushStart = MIN(mesh->flushStart, start);
|
||||||
|
mesh->flushEnd = MAX(mesh->flushEnd, end);
|
||||||
|
}
|
||||||
|
|
||||||
void lovrMeshAttachAttribute(Mesh* mesh, const char* name, MeshAttribute* attribute) {
|
void lovrMeshAttachAttribute(Mesh* mesh, const char* name, MeshAttribute* attribute) {
|
||||||
lovrAssert(!map_get(&mesh->attributes, name), "Mesh already has an attribute named '%s'", name);
|
lovrAssert(!map_get(&mesh->attributes, name), "Mesh already has an attribute named '%s'", name);
|
||||||
lovrAssert(attribute->divisor >= 0, "Divisor can't be negative");
|
lovrAssert(attribute->divisor >= 0, "Divisor can't be negative");
|
||||||
|
lovrGraphicsFlushMesh(mesh);
|
||||||
map_set(&mesh->attributes, name, *attribute);
|
map_set(&mesh->attributes, name, *attribute);
|
||||||
lovrRetain(attribute->buffer);
|
lovrRetain(attribute->buffer);
|
||||||
}
|
}
|
||||||
|
@ -10,7 +52,8 @@ void lovrMeshAttachAttribute(Mesh* mesh, const char* name, MeshAttribute* attrib
|
||||||
void lovrMeshDetachAttribute(Mesh* mesh, const char* name) {
|
void lovrMeshDetachAttribute(Mesh* mesh, const char* name) {
|
||||||
MeshAttribute* attribute = map_get(&mesh->attributes, name);
|
MeshAttribute* attribute = map_get(&mesh->attributes, name);
|
||||||
lovrAssert(attribute, "No attached attribute '%s' was found", name);
|
lovrAssert(attribute, "No attached attribute '%s' was found", name);
|
||||||
lovrAssert(attribute->buffer != mesh->vbo, "Attribute '%s' was not attached from another Mesh", name);
|
lovrAssert(attribute->buffer != mesh->vertexBuffer, "Attribute '%s' was not attached from another Mesh", name);
|
||||||
|
lovrGraphicsFlushMesh(mesh);
|
||||||
lovrRelease(attribute->buffer);
|
lovrRelease(attribute->buffer);
|
||||||
map_remove(&mesh->attributes, name);
|
map_remove(&mesh->attributes, name);
|
||||||
}
|
}
|
||||||
|
@ -19,26 +62,6 @@ MeshAttribute* lovrMeshGetAttribute(Mesh* mesh, const char* name) {
|
||||||
return map_get(&mesh->attributes, name);
|
return map_get(&mesh->attributes, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexFormat* lovrMeshGetVertexFormat(Mesh* mesh) {
|
|
||||||
return &mesh->format;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lovrMeshIsReadable(Mesh* mesh) {
|
|
||||||
return mesh->readable;
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawMode lovrMeshGetDrawMode(Mesh* mesh) {
|
|
||||||
return mesh->mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void lovrMeshSetDrawMode(Mesh* mesh, DrawMode mode) {
|
|
||||||
mesh->mode = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lovrMeshGetVertexCount(Mesh* mesh) {
|
|
||||||
return mesh->count;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lovrMeshIsAttributeEnabled(Mesh* mesh, const char* name) {
|
bool lovrMeshIsAttributeEnabled(Mesh* mesh, const char* name) {
|
||||||
MeshAttribute* attribute = map_get(&mesh->attributes, name);
|
MeshAttribute* attribute = map_get(&mesh->attributes, name);
|
||||||
lovrAssert(attribute, "Mesh does not have an attribute named '%s'", name);
|
lovrAssert(attribute, "Mesh does not have an attribute named '%s'", name);
|
||||||
|
@ -48,19 +71,30 @@ bool lovrMeshIsAttributeEnabled(Mesh* mesh, const char* name) {
|
||||||
void lovrMeshSetAttributeEnabled(Mesh* mesh, const char* name, bool enable) {
|
void lovrMeshSetAttributeEnabled(Mesh* mesh, const char* name, bool enable) {
|
||||||
MeshAttribute* attribute = map_get(&mesh->attributes, name);
|
MeshAttribute* attribute = map_get(&mesh->attributes, name);
|
||||||
lovrAssert(attribute, "Mesh does not have an attribute named '%s'", name);
|
lovrAssert(attribute, "Mesh does not have an attribute named '%s'", name);
|
||||||
attribute->enabled = enable;
|
if (attribute->enabled != enable) {
|
||||||
|
lovrGraphicsFlushMesh(mesh);
|
||||||
|
attribute->enabled = enable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawMode lovrMeshGetDrawMode(Mesh* mesh) {
|
||||||
|
return mesh->mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lovrMeshSetDrawMode(Mesh* mesh, DrawMode mode) {
|
||||||
|
mesh->mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrMeshGetDrawRange(Mesh* mesh, uint32_t* start, uint32_t* count) {
|
void lovrMeshGetDrawRange(Mesh* mesh, uint32_t* start, uint32_t* count) {
|
||||||
*start = mesh->rangeStart;
|
*start = mesh->drawStart;
|
||||||
*count = mesh->rangeCount;
|
*count = mesh->drawCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrMeshSetDrawRange(Mesh* mesh, uint32_t start, uint32_t count) {
|
void lovrMeshSetDrawRange(Mesh* mesh, uint32_t start, uint32_t count) {
|
||||||
uint32_t limit = mesh->indexCount > 0 ? mesh->indexCount : mesh->count;
|
uint32_t limit = mesh->indexSize > 0 ? mesh->indexCount : mesh->vertexCount;
|
||||||
lovrAssert(start + count <= limit, "Invalid mesh draw range [%d, %d]", start + 1, start + count + 1);
|
lovrAssert(start + count <= limit, "Invalid mesh draw range [%d, %d]", start + 1, start + count + 1);
|
||||||
mesh->rangeStart = start;
|
mesh->drawStart = start;
|
||||||
mesh->rangeCount = count;
|
mesh->drawCount = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
Material* lovrMeshGetMaterial(Mesh* mesh) {
|
Material* lovrMeshGetMaterial(Mesh* mesh) {
|
||||||
|
@ -72,38 +106,3 @@ void lovrMeshSetMaterial(Mesh* mesh, Material* material) {
|
||||||
lovrRelease(mesh->material);
|
lovrRelease(mesh->material);
|
||||||
mesh->material = material;
|
mesh->material = material;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* lovrMeshMapVertices(Mesh* mesh, size_t offset) {
|
|
||||||
return lovrBufferMap(mesh->vbo, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lovrMeshFlushVertices(Mesh* mesh, size_t offset, size_t size) {
|
|
||||||
lovrBufferFlush(mesh->vbo, offset, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* lovrMeshMapIndices(Mesh* mesh, uint32_t count, size_t indexSize, size_t offset) {
|
|
||||||
mesh->indexSize = indexSize;
|
|
||||||
mesh->indexCount = count;
|
|
||||||
|
|
||||||
if (count == 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mesh->indexCapacity < indexSize * count) {
|
|
||||||
mesh->indexCapacity = nextPo2(indexSize * count);
|
|
||||||
lovrRelease(mesh->ibo);
|
|
||||||
mesh->ibo = lovrBufferCreate(mesh->indexCapacity, NULL, mesh->usage, mesh->readable);
|
|
||||||
}
|
|
||||||
|
|
||||||
return lovrBufferMap(mesh->ibo, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lovrMeshFlushIndices(Mesh* mesh) {
|
|
||||||
if (mesh->indexCount > 0) {
|
|
||||||
lovrBufferFlush(mesh->ibo, 0, mesh->indexCount * mesh->indexSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void* lovrMeshReadIndices(Mesh* mesh, uint32_t* count, size_t* indexSize) {
|
|
||||||
return *count = mesh->indexCount, *indexSize = mesh->indexSize, lovrBufferMap(mesh->ibo, 0);
|
|
||||||
}
|
|
||||||
|
|
|
@ -34,43 +34,42 @@ typedef enum {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Ref ref;
|
Ref ref;
|
||||||
uint32_t count;
|
|
||||||
DrawMode mode;
|
DrawMode mode;
|
||||||
VertexFormat format;
|
VertexFormat format;
|
||||||
bool readable;
|
Buffer* vertexBuffer;
|
||||||
BufferUsage usage;
|
Buffer* indexBuffer;
|
||||||
Buffer* vbo;
|
uint32_t vertexCount;
|
||||||
Buffer* ibo;
|
|
||||||
uint32_t indexCount;
|
uint32_t indexCount;
|
||||||
size_t indexSize;
|
size_t indexSize;
|
||||||
size_t indexCapacity;
|
size_t flushStart;
|
||||||
uint32_t rangeStart;
|
size_t flushEnd;
|
||||||
uint32_t rangeCount;
|
uint32_t drawStart;
|
||||||
|
uint32_t drawCount;
|
||||||
Material* material;
|
Material* material;
|
||||||
map_attribute_t attributes;
|
map_attribute_t attributes;
|
||||||
MeshAttribute layout[MAX_ATTRIBUTES];
|
MeshAttribute layout[MAX_ATTRIBUTES];
|
||||||
GPU_MESH_FIELDS
|
GPU_MESH_FIELDS
|
||||||
} Mesh;
|
} Mesh;
|
||||||
|
|
||||||
Mesh* lovrMeshInit(Mesh* mesh, uint32_t count, VertexFormat format, DrawMode drawMode, BufferUsage usage, bool readable);
|
Mesh* lovrMeshInit(Mesh* mesh, DrawMode mode, VertexFormat format, Buffer* vertexBuffer);
|
||||||
#define lovrMeshCreate(...) lovrMeshInit(lovrAlloc(Mesh), __VA_ARGS__)
|
#define lovrMeshCreate(...) lovrMeshInit(lovrAlloc(Mesh), __VA_ARGS__)
|
||||||
void lovrMeshDestroy(void* ref);
|
void lovrMeshDestroy(void* ref);
|
||||||
|
VertexFormat* lovrMeshGetVertexFormat(Mesh* mesh);
|
||||||
|
Buffer* lovrMeshGetVertexBuffer(Mesh* mesh);
|
||||||
|
Buffer* lovrMeshGetIndexBuffer(Mesh* mesh);
|
||||||
|
void lovrMeshSetIndexBuffer(Mesh* mesh, Buffer* buffer, uint32_t indexCount, size_t indexSize);
|
||||||
|
uint32_t lovrMeshGetVertexCount(Mesh* mesh);
|
||||||
|
uint32_t lovrMeshGetIndexCount(Mesh* mesh);
|
||||||
|
size_t lovrMeshGetIndexSize(Mesh* mesh);
|
||||||
|
void lovrMeshMarkVertices(Mesh* mesh, size_t start, size_t end);
|
||||||
void lovrMeshAttachAttribute(Mesh* mesh, const char* name, MeshAttribute* attribute);
|
void lovrMeshAttachAttribute(Mesh* mesh, const char* name, MeshAttribute* attribute);
|
||||||
void lovrMeshDetachAttribute(Mesh* mesh, const char* name);
|
void lovrMeshDetachAttribute(Mesh* mesh, const char* name);
|
||||||
MeshAttribute* lovrMeshGetAttribute(Mesh* mesh, const char* name);
|
MeshAttribute* lovrMeshGetAttribute(Mesh* mesh, const char* name);
|
||||||
VertexFormat* lovrMeshGetVertexFormat(Mesh* mesh);
|
|
||||||
bool lovrMeshIsReadable(Mesh* mesh);
|
|
||||||
DrawMode lovrMeshGetDrawMode(Mesh* mesh);
|
|
||||||
void lovrMeshSetDrawMode(Mesh* mesh, DrawMode mode);
|
|
||||||
int lovrMeshGetVertexCount(Mesh* mesh);
|
|
||||||
bool lovrMeshIsAttributeEnabled(Mesh* mesh, const char* name);
|
bool lovrMeshIsAttributeEnabled(Mesh* mesh, const char* name);
|
||||||
void lovrMeshSetAttributeEnabled(Mesh* mesh, const char* name, bool enabled);
|
void lovrMeshSetAttributeEnabled(Mesh* mesh, const char* name, bool enabled);
|
||||||
|
DrawMode lovrMeshGetDrawMode(Mesh* mesh);
|
||||||
|
void lovrMeshSetDrawMode(Mesh* mesh, DrawMode mode);
|
||||||
void lovrMeshGetDrawRange(Mesh* mesh, uint32_t* start, uint32_t* count);
|
void lovrMeshGetDrawRange(Mesh* mesh, uint32_t* start, uint32_t* count);
|
||||||
void lovrMeshSetDrawRange(Mesh* mesh, uint32_t start, uint32_t count);
|
void lovrMeshSetDrawRange(Mesh* mesh, uint32_t start, uint32_t count);
|
||||||
Material* lovrMeshGetMaterial(Mesh* mesh);
|
Material* lovrMeshGetMaterial(Mesh* mesh);
|
||||||
void lovrMeshSetMaterial(Mesh* mesh, Material* material);
|
void lovrMeshSetMaterial(Mesh* mesh, Material* material);
|
||||||
void* lovrMeshMapVertices(Mesh* mesh, size_t offset);
|
|
||||||
void lovrMeshFlushVertices(Mesh* mesh, size_t offset, size_t size);
|
|
||||||
void* lovrMeshMapIndices(Mesh* mesh, uint32_t count, size_t indexSize, size_t offset);
|
|
||||||
void lovrMeshFlushIndices(Mesh* mesh);
|
|
||||||
void* lovrMeshReadIndices(Mesh* mesh, uint32_t* count, size_t* indexSize);
|
|
||||||
|
|
|
@ -38,13 +38,18 @@ static void renderNode(Model* model, int nodeIndex, int instances) {
|
||||||
lovrMeshSetMaterial(model->mesh, model->materials[primitive->material]);
|
lovrMeshSetMaterial(model->mesh, model->materials[primitive->material]);
|
||||||
}
|
}
|
||||||
|
|
||||||
lovrMeshSetDrawRange(model->mesh, primitive->drawStart, primitive->drawCount);
|
lovrGraphicsBatch(&(BatchRequest) {
|
||||||
lovrGraphicsDraw(&(DrawRequest) {
|
.type = BATCH_MESH,
|
||||||
|
.params.mesh = {
|
||||||
|
.object = model->mesh,
|
||||||
|
.mode = DRAW_TRIANGLES,
|
||||||
|
.rangeStart = primitive->drawStart,
|
||||||
|
.rangeCount = primitive->drawCount,
|
||||||
|
.pose = (float*) model->pose,
|
||||||
|
.instances = instances
|
||||||
|
},
|
||||||
.transform = model->nodeTransforms[nodeIndex],
|
.transform = model->nodeTransforms[nodeIndex],
|
||||||
.mesh = model->mesh,
|
.material = lovrMeshGetMaterial(model->mesh)
|
||||||
.material = lovrMeshGetMaterial(model->mesh),
|
|
||||||
.instances = instances,
|
|
||||||
.pose = (float*) model->pose
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,14 +64,26 @@ Model* lovrModelInit(Model* model, ModelData* modelData) {
|
||||||
model->modelData = modelData;
|
model->modelData = modelData;
|
||||||
model->aabbDirty = true;
|
model->aabbDirty = true;
|
||||||
|
|
||||||
model->mesh = lovrMeshCreate(modelData->vertexData->count, modelData->vertexData->format, DRAW_TRIANGLES, USAGE_STATIC, false);
|
VertexFormat* format = &modelData->vertexData->format;
|
||||||
void* vertices = lovrMeshMapVertices(model->mesh, 0);
|
size_t vboSize = modelData->vertexData->count * format->stride;
|
||||||
memcpy(vertices, modelData->vertexData->blob.data, modelData->vertexData->count * modelData->vertexData->format.stride);
|
Buffer* vertexBuffer = lovrBufferCreate(vboSize, modelData->vertexData->blob.data, BUFFER_VERTEX, USAGE_STATIC, false);
|
||||||
lovrMeshFlushVertices(model->mesh, 0, modelData->vertexData->count * modelData->vertexData->format.stride);
|
model->mesh = lovrMeshCreate(DRAW_TRIANGLES, *format, vertexBuffer);
|
||||||
|
lovrRelease(vertexBuffer);
|
||||||
|
|
||||||
void* indices = lovrMeshMapIndices(model->mesh, modelData->indexCount, modelData->indexSize, 0);
|
size_t indexSize = modelData->indexSize;
|
||||||
memcpy(indices, modelData->indices.raw, modelData->indexCount * modelData->indexSize);
|
uint32_t indexCount = modelData->indexCount;
|
||||||
lovrMeshFlushIndices(model->mesh);
|
Buffer* indexBuffer = lovrBufferCreate(indexCount * indexSize, modelData->indices.raw, BUFFER_INDEX, USAGE_STATIC, false);
|
||||||
|
lovrMeshSetIndexBuffer(model->mesh, indexBuffer, indexCount, indexSize);
|
||||||
|
lovrRelease(indexBuffer);
|
||||||
|
|
||||||
|
lovrMeshAttachAttribute(model->mesh, "lovrDrawID", &(MeshAttribute) {
|
||||||
|
.buffer = lovrGraphicsGetIdentityBuffer(),
|
||||||
|
.type = ATTR_BYTE,
|
||||||
|
.components = 1,
|
||||||
|
.divisor = 1,
|
||||||
|
.integer = true,
|
||||||
|
.enabled = true
|
||||||
|
});
|
||||||
|
|
||||||
if (modelData->textures.length > 0) {
|
if (modelData->textures.length > 0) {
|
||||||
model->textures = calloc(modelData->textures.length, sizeof(Texture*));
|
model->textures = calloc(modelData->textures.length, sizeof(Texture*));
|
||||||
|
@ -178,7 +195,6 @@ void lovrModelDraw(Model* model, mat4 transform, int instances) {
|
||||||
lovrGraphicsMatrixTransform(transform);
|
lovrGraphicsMatrixTransform(transform);
|
||||||
renderNode(model, 0, instances);
|
renderNode(model, 0, instances);
|
||||||
lovrGraphicsPop();
|
lovrGraphicsPop();
|
||||||
lovrGraphicsFlush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Animator* lovrModelGetAnimator(Model* model) {
|
Animator* lovrModelGetAnimator(Model* model) {
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#define LOVR_SHADER_TANGENT 4
|
#define LOVR_SHADER_TANGENT 4
|
||||||
#define LOVR_SHADER_BONES 5
|
#define LOVR_SHADER_BONES 5
|
||||||
#define LOVR_SHADER_BONE_WEIGHTS 6
|
#define LOVR_SHADER_BONE_WEIGHTS 6
|
||||||
|
#define LOVR_SHADER_DRAW_ID 7
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BARRIER_BLOCK,
|
BARRIER_BLOCK,
|
||||||
|
@ -38,9 +39,16 @@ typedef enum {
|
||||||
MAX_BARRIERS
|
MAX_BARRIERS
|
||||||
} Barrier;
|
} Barrier;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t buffer;
|
||||||
|
size_t offset;
|
||||||
|
size_t size;
|
||||||
|
} BlockBuffer;
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
Texture* defaultTexture;
|
Texture* defaultTexture;
|
||||||
bool alphaToCoverage;
|
bool alphaToCoverage;
|
||||||
|
bool blendEnabled;
|
||||||
BlendMode blendMode;
|
BlendMode blendMode;
|
||||||
BlendAlphaMode blendAlphaMode;
|
BlendAlphaMode blendAlphaMode;
|
||||||
bool culling;
|
bool culling;
|
||||||
|
@ -55,15 +63,13 @@ static struct {
|
||||||
Winding winding;
|
Winding winding;
|
||||||
bool wireframe;
|
bool wireframe;
|
||||||
uint32_t framebuffer;
|
uint32_t framebuffer;
|
||||||
uint32_t indexBuffer;
|
|
||||||
uint32_t program;
|
uint32_t program;
|
||||||
|
uint32_t vertexArray;
|
||||||
|
uint32_t buffers[MAX_BUFFER_TYPES];
|
||||||
|
BlockBuffer blockBuffers[2][MAX_BLOCK_BUFFERS];
|
||||||
int activeTexture;
|
int activeTexture;
|
||||||
Texture* textures[MAX_TEXTURES];
|
Texture* textures[MAX_TEXTURES];
|
||||||
Image images[MAX_IMAGES];
|
Image images[MAX_IMAGES];
|
||||||
uint32_t blockBuffers[2][MAX_BLOCK_BUFFERS];
|
|
||||||
uint32_t vertexArray;
|
|
||||||
uint32_t vertexBuffer;
|
|
||||||
uint32_t genericBuffer;
|
|
||||||
float viewports[2][4];
|
float viewports[2][4];
|
||||||
vec_void_t incoherents[MAX_BARRIERS];
|
vec_void_t incoherents[MAX_BARRIERS];
|
||||||
bool srgb;
|
bool srgb;
|
||||||
|
@ -188,6 +194,17 @@ static bool isTextureFormatDepth(TextureFormat format) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GLenum convertBufferType(BufferType type) {
|
||||||
|
switch (type) {
|
||||||
|
case BUFFER_VERTEX: return GL_ARRAY_BUFFER;
|
||||||
|
case BUFFER_INDEX: return GL_ELEMENT_ARRAY_BUFFER;
|
||||||
|
case BUFFER_UNIFORM: return GL_UNIFORM_BUFFER;
|
||||||
|
case BUFFER_SHADER_STORAGE: return GL_SHADER_STORAGE_BUFFER;
|
||||||
|
case BUFFER_GENERIC: return GL_COPY_WRITE_BUFFER;
|
||||||
|
default: lovrThrow("Unreachable"); return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static GLenum convertBufferUsage(BufferUsage usage) {
|
static GLenum convertBufferUsage(BufferUsage usage) {
|
||||||
switch (usage) {
|
switch (usage) {
|
||||||
case USAGE_STATIC: return GL_STATIC_DRAW;
|
case USAGE_STATIC: return GL_STATIC_DRAW;
|
||||||
|
@ -308,8 +325,8 @@ static void lovrGpuSync(uint8_t flags) {
|
||||||
|
|
||||||
if (i == BARRIER_BLOCK) {
|
if (i == BARRIER_BLOCK) {
|
||||||
for (int j = 0; j < state.incoherents[i].length; j++) {
|
for (int j = 0; j < state.incoherents[i].length; j++) {
|
||||||
ShaderBlock* block = state.incoherents[i].data[j];
|
Buffer* buffer = state.incoherents[i].data[j];
|
||||||
block->incoherent &= ~(1 << i);
|
buffer->incoherent &= ~(1 << i);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int j = 0; j < state.incoherents[i].length; j++) {
|
for (int j = 0; j < state.incoherents[i].length; j++) {
|
||||||
|
@ -359,10 +376,43 @@ static void lovrGpuBindFramebuffer(uint32_t framebuffer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lovrGpuBindIndexBuffer(uint32_t indexBuffer) {
|
static void lovrGpuUseProgram(uint32_t program) {
|
||||||
if (state.indexBuffer != indexBuffer) {
|
if (state.program != program) {
|
||||||
state.indexBuffer = indexBuffer;
|
state.program = program;
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
|
glUseProgram(program);
|
||||||
|
state.stats.shaderSwitches++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lovrGpuBindVertexArray(uint32_t vertexArray) {
|
||||||
|
if (state.vertexArray != vertexArray) {
|
||||||
|
state.vertexArray = vertexArray;
|
||||||
|
glBindVertexArray(vertexArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lovrGpuBindBuffer(BufferType type, uint32_t buffer) {
|
||||||
|
if (state.buffers[type] != buffer) {
|
||||||
|
state.buffers[type] = buffer;
|
||||||
|
glBindBuffer(convertBufferType(type), buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lovrGpuBindBlockBuffer(BlockType type, uint32_t buffer, int slot, size_t offset, size_t size) {
|
||||||
|
lovrAssert(offset % state.limits.blockAlign == 0, "Block buffer offset must be aligned to %d", state.limits.blockAlign);
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
lovrAssert(type == BLOCK_UNIFORM, "Writable blocks are not supported on this system");
|
||||||
|
GLenum target = GL_UNIFORM_BUFFER;
|
||||||
|
#else
|
||||||
|
GLenum target = type == BLOCK_UNIFORM ? GL_UNIFORM_BUFFER : GL_SHADER_STORAGE_BUFFER;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BlockBuffer* block = &state.blockBuffers[type][slot];
|
||||||
|
if (block->buffer != buffer || block->offset != offset || block->size != size) {
|
||||||
|
block->buffer = buffer;
|
||||||
|
block->offset = offset;
|
||||||
|
block->size = size;
|
||||||
|
glBindBufferRange(target, slot, buffer, offset, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,49 +457,6 @@ static void lovrGpuBindImage(Image* image, int slot) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void lovrGpuBindBlockBuffer(BlockType type, uint32_t buffer, int slot) {
|
|
||||||
#ifdef EMSCRIPTEN
|
|
||||||
lovrAssert(type == BLOCK_UNIFORM, "Writable ShaderBlocks are not supported on this system");
|
|
||||||
GLenum target = GL_UNIFORM_BUFFER;
|
|
||||||
#else
|
|
||||||
GLenum target = type == BLOCK_UNIFORM ? GL_UNIFORM_BUFFER : GL_SHADER_STORAGE_BUFFER;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (state.blockBuffers[type][slot] != buffer) {
|
|
||||||
state.blockBuffers[type][slot] = buffer;
|
|
||||||
glBindBufferBase(target, slot, buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lovrGpuBindVertexArray(uint32_t vertexArray) {
|
|
||||||
if (state.vertexArray != vertexArray) {
|
|
||||||
state.vertexArray = vertexArray;
|
|
||||||
glBindVertexArray(vertexArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lovrGpuBindVertexBuffer(uint32_t vertexBuffer) {
|
|
||||||
if (state.vertexBuffer != vertexBuffer) {
|
|
||||||
state.vertexBuffer = vertexBuffer;
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lovrGpuBindGenericBuffer(uint32_t buffer) {
|
|
||||||
if (state.genericBuffer != buffer) {
|
|
||||||
state.genericBuffer = buffer;
|
|
||||||
glBindBuffer(GL_COPY_WRITE_BUFFER, buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lovrGpuUseProgram(uint32_t program) {
|
|
||||||
if (state.program != program) {
|
|
||||||
state.program = program;
|
|
||||||
glUseProgram(program);
|
|
||||||
state.stats.shaderSwitches++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lovrGpuBindMesh(Mesh* mesh, Shader* shader, int divisorMultiplier) {
|
static void lovrGpuBindMesh(Mesh* mesh, Shader* shader, int divisorMultiplier) {
|
||||||
const char* key;
|
const char* key;
|
||||||
map_iter_t iter = map_iter(&mesh->attachments);
|
map_iter_t iter = map_iter(&mesh->attachments);
|
||||||
|
@ -458,8 +465,16 @@ static void lovrGpuBindMesh(Mesh* mesh, Shader* shader, int divisorMultiplier) {
|
||||||
memset(layout, 0, MAX_ATTRIBUTES * sizeof(MeshAttribute));
|
memset(layout, 0, MAX_ATTRIBUTES * sizeof(MeshAttribute));
|
||||||
|
|
||||||
lovrGpuBindVertexArray(mesh->vao);
|
lovrGpuBindVertexArray(mesh->vao);
|
||||||
if (mesh->indexCount > 0) {
|
|
||||||
lovrGpuBindIndexBuffer(mesh->ibo->id);
|
if (mesh->indexBuffer && mesh->indexCount > 0 && mesh->ibo != mesh->indexBuffer->id) {
|
||||||
|
mesh->ibo = mesh->indexBuffer->id;
|
||||||
|
state.buffers[BUFFER_INDEX] = mesh->ibo;
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ibo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mesh->flushEnd > 0) {
|
||||||
|
lovrBufferFlush(mesh->vertexBuffer, mesh->flushStart, mesh->flushEnd - mesh->flushStart);
|
||||||
|
mesh->flushStart = mesh->flushEnd = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((key = map_next(&mesh->attributes, &iter)) != NULL) {
|
while ((key = map_next(&mesh->attributes, &iter)) != NULL) {
|
||||||
|
@ -501,7 +516,7 @@ static void lovrGpuBindMesh(Mesh* mesh, Shader* shader, int divisorMultiplier) {
|
||||||
previous.stride != current.stride;
|
previous.stride != current.stride;
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
lovrGpuBindVertexBuffer(current.buffer->id);
|
lovrGpuBindBuffer(BUFFER_VERTEX, current.buffer->id);
|
||||||
int count = current.components;
|
int count = current.components;
|
||||||
int stride = current.stride;
|
int stride = current.stride;
|
||||||
GLvoid* offset = (GLvoid*) current.offset;
|
GLvoid* offset = (GLvoid*) current.offset;
|
||||||
|
@ -604,51 +619,60 @@ static void lovrGpuBindPipeline(Pipeline* pipeline) {
|
||||||
state.blendMode = pipeline->blendMode;
|
state.blendMode = pipeline->blendMode;
|
||||||
state.blendAlphaMode = pipeline->blendAlphaMode;
|
state.blendAlphaMode = pipeline->blendAlphaMode;
|
||||||
|
|
||||||
GLenum srcRGB = state.blendMode == BLEND_MULTIPLY ? GL_DST_COLOR : GL_ONE;
|
if (state.blendMode == BLEND_NONE) {
|
||||||
if (srcRGB == GL_ONE && state.blendAlphaMode == BLEND_ALPHA_MULTIPLY) {
|
if (state.blendEnabled) {
|
||||||
srcRGB = GL_SRC_ALPHA;
|
state.blendEnabled = false;
|
||||||
}
|
glDisable(GL_BLEND);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!state.blendEnabled) {
|
||||||
|
state.blendEnabled = true;
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
switch (state.blendMode) {
|
GLenum srcRGB = state.blendMode == BLEND_MULTIPLY ? GL_DST_COLOR : GL_ONE;
|
||||||
case BLEND_ALPHA:
|
if (srcRGB == GL_ONE && state.blendAlphaMode == BLEND_ALPHA_MULTIPLY) {
|
||||||
glBlendEquation(GL_FUNC_ADD);
|
srcRGB = GL_SRC_ALPHA;
|
||||||
glBlendFuncSeparate(srcRGB, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case BLEND_ADD:
|
switch (state.blendMode) {
|
||||||
glBlendEquation(GL_FUNC_ADD);
|
case BLEND_ALPHA:
|
||||||
glBlendFuncSeparate(srcRGB, GL_ONE, GL_ZERO, GL_ONE);
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
break;
|
glBlendFuncSeparate(srcRGB, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
break;
|
||||||
|
|
||||||
case BLEND_SUBTRACT:
|
case BLEND_ADD:
|
||||||
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
glBlendFuncSeparate(srcRGB, GL_ONE, GL_ZERO, GL_ONE);
|
glBlendFuncSeparate(srcRGB, GL_ONE, GL_ZERO, GL_ONE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BLEND_MULTIPLY:
|
case BLEND_SUBTRACT:
|
||||||
glBlendEquation(GL_FUNC_ADD);
|
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
||||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_DST_COLOR, GL_ZERO);
|
glBlendFuncSeparate(srcRGB, GL_ONE, GL_ZERO, GL_ONE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BLEND_LIGHTEN:
|
case BLEND_MULTIPLY:
|
||||||
glBlendEquation(GL_MAX);
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_DST_COLOR, GL_ZERO);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BLEND_DARKEN:
|
case BLEND_LIGHTEN:
|
||||||
glBlendEquation(GL_MIN);
|
glBlendEquation(GL_MAX);
|
||||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BLEND_SCREEN:
|
case BLEND_DARKEN:
|
||||||
glBlendEquation(GL_FUNC_ADD);
|
glBlendEquation(GL_MIN);
|
||||||
glBlendFuncSeparate(srcRGB, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE_MINUS_SRC_COLOR);
|
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BLEND_REPLACE:
|
case BLEND_SCREEN:
|
||||||
glBlendEquation(GL_FUNC_ADD);
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
glBlendFuncSeparate(srcRGB, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE_MINUS_SRC_COLOR);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BLEND_NONE: lovrThrow("Unreachable"); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -678,8 +702,8 @@ static void lovrGpuBindPipeline(Pipeline* pipeline) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depth write
|
// Depth write
|
||||||
if (state.depthWrite != pipeline->depthWrite) {
|
if (state.depthWrite != (pipeline->depthWrite && !state.stencilWriting)) {
|
||||||
state.depthWrite = pipeline->depthWrite;
|
state.depthWrite = pipeline->depthWrite && !state.stencilWriting;
|
||||||
glDepthMask(state.depthWrite);
|
glDepthMask(state.depthWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -848,14 +872,14 @@ static void lovrGpuBindShader(Shader* shader) {
|
||||||
for (BlockType type = BLOCK_UNIFORM; type <= BLOCK_STORAGE; type++) {
|
for (BlockType type = BLOCK_UNIFORM; type <= BLOCK_STORAGE; type++) {
|
||||||
vec_foreach_ptr(&shader->blocks[type], block, i) {
|
vec_foreach_ptr(&shader->blocks[type], block, i) {
|
||||||
if (block->source) {
|
if (block->source) {
|
||||||
|
if (type == BLOCK_STORAGE && block->access != ACCESS_READ) {
|
||||||
|
block->source->incoherent |= (1 << BARRIER_BLOCK);
|
||||||
|
vec_push(&state.incoherents[BARRIER_BLOCK], block->source);
|
||||||
|
}
|
||||||
|
|
||||||
// If the Shader can write to the block, mark it as incoherent
|
lovrGpuBindBlockBuffer(type, block->source->id, block->slot, block->offset, block->size);
|
||||||
bool writable = type == BLOCK_STORAGE && block->access != ACCESS_READ;
|
|
||||||
block->source->incoherent |= writable ? (1 << BARRIER_BLOCK) : 0;
|
|
||||||
vec_push(&state.incoherents[BARRIER_BLOCK], block->source);
|
|
||||||
lovrGpuBindBlockBuffer(type, block->source->buffer->id, block->slot);
|
|
||||||
} else {
|
} else {
|
||||||
lovrGpuBindBlockBuffer(type, 0, block->slot);
|
lovrGpuBindBlockBuffer(type, 0, block->slot, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -900,17 +924,19 @@ void lovrGpuInit(bool srgb, getProcAddressProc getProcAddress) {
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &state.limits.textureSize);
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &state.limits.textureSize);
|
||||||
glGetIntegerv(GL_MAX_SAMPLES, &state.limits.textureMSAA);
|
glGetIntegerv(GL_MAX_SAMPLES, &state.limits.textureMSAA);
|
||||||
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &state.limits.blockSize);
|
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &state.limits.blockSize);
|
||||||
|
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &state.limits.blockAlign);
|
||||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &state.limits.textureAnisotropy);
|
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &state.limits.textureAnisotropy);
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
state.srgb = srgb;
|
state.srgb = srgb;
|
||||||
|
|
||||||
state.alphaToCoverage = false;
|
state.alphaToCoverage = false;
|
||||||
glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
|
glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
|
||||||
|
|
||||||
|
state.blendEnabled = true;
|
||||||
state.blendMode = BLEND_ALPHA;
|
state.blendMode = BLEND_ALPHA;
|
||||||
state.blendAlphaMode = BLEND_ALPHA_MULTIPLY;
|
state.blendAlphaMode = BLEND_ALPHA_MULTIPLY;
|
||||||
|
glEnable(GL_BLEND);
|
||||||
glBlendEquation(GL_FUNC_ADD);
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
@ -990,6 +1016,7 @@ void lovrGpuCompute(Shader* shader, int x, int y, int z) {
|
||||||
#else
|
#else
|
||||||
lovrAssert(GLAD_GL_ARB_compute_shader, "Compute shaders are not supported on this system");
|
lovrAssert(GLAD_GL_ARB_compute_shader, "Compute shaders are not supported on this system");
|
||||||
lovrAssert(shader->type == SHADER_COMPUTE, "Attempt to use a non-compute shader for a compute operation");
|
lovrAssert(shader->type == SHADER_COMPUTE, "Attempt to use a non-compute shader for a compute operation");
|
||||||
|
lovrGraphicsFlush();
|
||||||
lovrGpuBindShader(shader);
|
lovrGpuBindShader(shader);
|
||||||
glDispatchCompute(x, y, z);
|
glDispatchCompute(x, y, z);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1021,52 +1048,45 @@ void lovrGpuDiscard(Canvas* canvas, bool color, bool depth, bool stencil) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrGpuDraw(DrawCommand* commands, int count) {
|
void lovrGpuDraw(DrawCommand* draw) {
|
||||||
for (int i = 0; i < count; i++) {
|
int viewCount = 1 + draw->stereo;
|
||||||
DrawCommand* draw = &commands[i];
|
int drawCount = state.features.singlepass ? 1 : viewCount;
|
||||||
|
int viewsPerDraw = state.features.singlepass ? viewCount : 1;
|
||||||
|
int instances = MAX(draw->instances, 1) * viewsPerDraw;
|
||||||
|
|
||||||
int viewCount = 1 + draw->stereo;
|
float w = draw->width / (float) viewCount;
|
||||||
int drawCount = state.features.singlepass ? 1 : viewCount;
|
float h = draw->height;
|
||||||
int viewsPerDraw = state.features.singlepass ? viewCount : 1;
|
float viewports[2][4] = { { 0, 0, w, h }, { w, 0, w, h } };
|
||||||
int instances = draw->instances * viewsPerDraw;
|
lovrShaderSetInts(draw->shader, "lovrViewportCount", &viewCount, 0, 1);
|
||||||
|
|
||||||
float w = draw->width / (float) viewCount;
|
lovrGpuBindCanvas(draw->canvas, true);
|
||||||
float h = draw->height;
|
lovrGpuBindPipeline(&draw->pipeline);
|
||||||
float viewports[2][4] = { { 0, 0, w, h }, { w, 0, w, h } };
|
lovrGpuBindMesh(draw->mesh, draw->shader, viewsPerDraw);
|
||||||
lovrShaderSetInts(draw->shader, "lovrViewportCount", &viewCount, 0, 1);
|
|
||||||
|
|
||||||
lovrGpuBindMesh(draw->mesh, draw->shader, viewsPerDraw);
|
for (int i = 0; i < drawCount; i++) {
|
||||||
lovrGpuBindCanvas(draw->canvas, true);
|
lovrGpuSetViewports(&viewports[i][0], viewsPerDraw);
|
||||||
lovrGpuBindPipeline(&draw->pipeline);
|
lovrShaderSetInts(draw->shader, "lovrViewportIndex", &i, 0, 1);
|
||||||
|
lovrGpuBindShader(draw->shader);
|
||||||
|
|
||||||
for (int i = 0; i < drawCount; i++) {
|
Mesh* mesh = draw->mesh;
|
||||||
lovrGpuSetViewports(&viewports[i][0], viewsPerDraw);
|
GLenum mode = convertDrawMode(draw->drawMode);
|
||||||
lovrShaderSetInts(draw->shader, "lovrViewportIndex", &i, 0, 1);
|
if (mesh->indexCount > 0) {
|
||||||
lovrGpuBindShader(draw->shader);
|
GLenum indexType = mesh->indexSize == sizeof(uint16_t) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
|
||||||
|
GLvoid* offset = (GLvoid*) (draw->rangeStart * mesh->indexSize);
|
||||||
Mesh* mesh = draw->mesh;
|
if (instances > 1) {
|
||||||
GLenum mode = convertDrawMode(mesh->mode);
|
glDrawElementsInstanced(mode, draw->rangeCount, indexType, offset, instances);
|
||||||
if (mesh->indexCount > 0) {
|
|
||||||
size_t count = mesh->rangeCount ? mesh->rangeCount : mesh->indexCount;
|
|
||||||
GLenum indexType = mesh->indexSize == sizeof(uint16_t) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
|
|
||||||
GLvoid* offset = (GLvoid*) (mesh->rangeStart * mesh->indexSize);
|
|
||||||
if (instances > 1) {
|
|
||||||
glDrawElementsInstanced(mode, count, indexType, offset, instances);
|
|
||||||
} else {
|
|
||||||
glDrawElements(mode, count, indexType, offset);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
size_t start = mesh->rangeStart;
|
glDrawElements(mode, draw->rangeCount, indexType, offset);
|
||||||
size_t count = mesh->rangeCount ? mesh->rangeCount : mesh->count;
|
}
|
||||||
if (instances > 1) {
|
} else {
|
||||||
glDrawArraysInstanced(mode, start, count, instances);
|
if (instances > 1) {
|
||||||
} else {
|
glDrawArraysInstanced(mode, draw->rangeStart, draw->rangeCount, instances);
|
||||||
glDrawArrays(mode, start, count);
|
} else {
|
||||||
}
|
glDrawArrays(mode, draw->rangeStart, draw->rangeCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.stats.drawCalls++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.stats.drawCalls++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1079,7 +1099,7 @@ void lovrGpuPresent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrGpuStencil(StencilAction action, int replaceValue, StencilCallback callback, void* userdata) {
|
void lovrGpuStencil(StencilAction action, int replaceValue, StencilCallback callback, void* userdata) {
|
||||||
state.depthWrite = false;
|
lovrGraphicsFlush();
|
||||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||||
|
|
||||||
if (!state.stencilEnabled) {
|
if (!state.stencilEnabled) {
|
||||||
|
@ -1102,6 +1122,7 @@ void lovrGpuStencil(StencilAction action, int replaceValue, StencilCallback call
|
||||||
|
|
||||||
state.stencilWriting = true;
|
state.stencilWriting = true;
|
||||||
callback(userdata);
|
callback(userdata);
|
||||||
|
lovrGraphicsFlush();
|
||||||
state.stencilWriting = false;
|
state.stencilWriting = false;
|
||||||
|
|
||||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||||
|
@ -1112,6 +1133,24 @@ void lovrGpuDirtyTexture() {
|
||||||
state.textures[state.activeTexture] = NULL;
|
state.textures[state.activeTexture] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* lovrGpuLock() {
|
||||||
|
return (void*) glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lovrGpuUnlock(void* lock) {
|
||||||
|
if (!lock) return;
|
||||||
|
GLsync sync = (GLsync) lock;
|
||||||
|
if (glClientWaitSync(sync, 0, 0) == GL_TIMEOUT_EXPIRED) {
|
||||||
|
while (glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1E9) == GL_TIMEOUT_EXPIRED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lovrGpuDestroyLock(void* lock) {
|
||||||
|
if (lock) glDeleteSync((GLsync) lock);
|
||||||
|
}
|
||||||
|
|
||||||
const GpuFeatures* lovrGpuGetSupported() {
|
const GpuFeatures* lovrGpuGetSupported() {
|
||||||
return &state.features;
|
return &state.features;
|
||||||
}
|
}
|
||||||
|
@ -1242,6 +1281,7 @@ void lovrTextureAllocate(Texture* texture, int width, int height, int depth, Tex
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, int x, int y, int slice, int mipmap) {
|
void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, int x, int y, int slice, int mipmap) {
|
||||||
|
lovrGraphicsFlush();
|
||||||
lovrAssert(texture->allocated, "Texture is not allocated");
|
lovrAssert(texture->allocated, "Texture is not allocated");
|
||||||
|
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef EMSCRIPTEN
|
||||||
|
@ -1308,6 +1348,7 @@ void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, int x,
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrTextureSetFilter(Texture* texture, TextureFilter filter) {
|
void lovrTextureSetFilter(Texture* texture, TextureFilter filter) {
|
||||||
|
lovrGraphicsFlush();
|
||||||
float anisotropy = filter.mode == FILTER_ANISOTROPIC ? MAX(filter.anisotropy, 1.) : 1.;
|
float anisotropy = filter.mode == FILTER_ANISOTROPIC ? MAX(filter.anisotropy, 1.) : 1.;
|
||||||
lovrGpuBindTexture(texture, 0);
|
lovrGpuBindTexture(texture, 0);
|
||||||
texture->filter = filter;
|
texture->filter = filter;
|
||||||
|
@ -1344,6 +1385,7 @@ void lovrTextureSetFilter(Texture* texture, TextureFilter filter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrTextureSetWrap(Texture* texture, TextureWrap wrap) {
|
void lovrTextureSetWrap(Texture* texture, TextureWrap wrap) {
|
||||||
|
lovrGraphicsFlush();
|
||||||
texture->wrap = wrap;
|
texture->wrap = wrap;
|
||||||
lovrGpuBindTexture(texture, 0);
|
lovrGpuBindTexture(texture, 0);
|
||||||
glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, convertWrapMode(wrap.s));
|
glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, convertWrapMode(wrap.s));
|
||||||
|
@ -1416,7 +1458,7 @@ void lovrCanvasResolve(Canvas* canvas) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lovrGraphicsFlush();
|
lovrGraphicsFlushCanvas(canvas);
|
||||||
|
|
||||||
if (canvas->flags.msaa) {
|
if (canvas->flags.msaa) {
|
||||||
int w = canvas->width;
|
int w = canvas->width;
|
||||||
|
@ -1454,6 +1496,7 @@ void lovrCanvasResolve(Canvas* canvas) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureData* lovrCanvasNewTextureData(Canvas* canvas, int index) {
|
TextureData* lovrCanvasNewTextureData(Canvas* canvas, int index) {
|
||||||
|
lovrGraphicsFlushCanvas(canvas);
|
||||||
lovrGpuBindCanvas(canvas, false);
|
lovrGpuBindCanvas(canvas, false);
|
||||||
|
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef EMSCRIPTEN
|
||||||
|
@ -1479,21 +1522,24 @@ TextureData* lovrCanvasNewTextureData(Canvas* canvas, int index) {
|
||||||
|
|
||||||
// Buffer
|
// Buffer
|
||||||
|
|
||||||
Buffer* lovrBufferInit(Buffer* buffer, size_t size, void* data, BufferUsage usage, bool readable) {
|
Buffer* lovrBufferInit(Buffer* buffer, size_t size, void* data, BufferType type, BufferUsage usage, bool readable) {
|
||||||
buffer->size = size;
|
buffer->size = size;
|
||||||
|
buffer->readable = readable;
|
||||||
|
buffer->type = type;
|
||||||
buffer->usage = usage;
|
buffer->usage = usage;
|
||||||
glGenBuffers(1, &buffer->id);
|
glGenBuffers(1, &buffer->id);
|
||||||
lovrGpuBindGenericBuffer(buffer->id);
|
lovrGpuBindBuffer(type, buffer->id);
|
||||||
|
GLenum glType = convertBufferType(type);
|
||||||
|
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef EMSCRIPTEN
|
||||||
if (GLAD_GL_ARB_buffer_storage) {
|
if (GLAD_GL_ARB_buffer_storage) {
|
||||||
GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (readable ? GL_MAP_READ_BIT : 0);
|
GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (readable ? GL_MAP_READ_BIT : 0);
|
||||||
glBufferStorage(GL_COPY_WRITE_BUFFER, size, data, flags);
|
glBufferStorage(glType, size, data, flags);
|
||||||
buffer->data = glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, size, flags | GL_MAP_FLUSH_EXPLICIT_BIT);
|
buffer->data = glMapBufferRange(glType, 0, size, flags | GL_MAP_FLUSH_EXPLICIT_BIT);
|
||||||
} else {
|
} else {
|
||||||
#endif
|
#endif
|
||||||
buffer->data = calloc(1, size);
|
buffer->data = calloc(1, size);
|
||||||
glBufferData(GL_COPY_WRITE_BUFFER, size, data, convertBufferUsage(usage));
|
glBufferData(glType, size, data, convertBufferUsage(usage));
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
memcpy(buffer->data, data, size);
|
memcpy(buffer->data, data, size);
|
||||||
|
@ -1507,6 +1553,7 @@ Buffer* lovrBufferInit(Buffer* buffer, size_t size, void* data, BufferUsage usag
|
||||||
|
|
||||||
void lovrBufferDestroy(void* ref) {
|
void lovrBufferDestroy(void* ref) {
|
||||||
Buffer* buffer = ref;
|
Buffer* buffer = ref;
|
||||||
|
lovrGpuDestroySyncResource(buffer, buffer->incoherent);
|
||||||
glDeleteBuffers(1, &buffer->id);
|
glDeleteBuffers(1, &buffer->id);
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef EMSCRIPTEN
|
||||||
if (!GLAD_GL_ARB_buffer_storage) {
|
if (!GLAD_GL_ARB_buffer_storage) {
|
||||||
|
@ -1522,45 +1569,18 @@ void* lovrBufferMap(Buffer* buffer, size_t offset) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrBufferFlush(Buffer* buffer, size_t offset, size_t size) {
|
void lovrBufferFlush(Buffer* buffer, size_t offset, size_t size) {
|
||||||
lovrGpuBindGenericBuffer(buffer->id);
|
lovrGpuBindBuffer(buffer->type, buffer->id);
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef EMSCRIPTEN
|
||||||
if (GLAD_GL_ARB_buffer_storage) {
|
if (GLAD_GL_ARB_buffer_storage) {
|
||||||
glFlushMappedBufferRange(GL_COPY_WRITE_BUFFER, offset, size);
|
glFlushMappedBufferRange(convertBufferType(buffer->type), offset, size);
|
||||||
} else {
|
} else {
|
||||||
#endif
|
#endif
|
||||||
glBufferSubData(GL_COPY_WRITE_BUFFER, offset, size, (GLvoid*) ((uint8_t*) buffer->data + offset));
|
glBufferSubData(convertBufferType(buffer->type), offset, size, (GLvoid*) ((uint8_t*) buffer->data + offset));
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef EMSCRIPTEN
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrBufferLock(Buffer* buffer) {
|
|
||||||
#ifndef EMSCRIPTEN
|
|
||||||
if (!GLAD_GL_ARB_buffer_storage) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lovrBufferUnlock(buffer);
|
|
||||||
buffer->lock = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void lovrBufferUnlock(Buffer* buffer) {
|
|
||||||
#ifndef EMSCRIPTEN
|
|
||||||
if (!GLAD_GL_ARB_buffer_storage || !buffer->lock) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (glClientWaitSync(buffer->lock, 0, 0) == GL_TIMEOUT_EXPIRED) {
|
|
||||||
while (glClientWaitSync(buffer->lock, GL_SYNC_FLUSH_COMMANDS_BIT, 1E9) == GL_TIMEOUT_EXPIRED) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
glDeleteSync(buffer->lock);
|
|
||||||
buffer->lock = NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shader
|
// Shader
|
||||||
|
|
||||||
static GLuint compileShader(GLenum type, const char** sources, int count) {
|
static GLuint compileShader(GLenum type, const char** sources, int count) {
|
||||||
|
@ -1717,12 +1737,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
|
||||||
uniform.size = 4 * (uniform.components == 3 ? 4 : uniform.components);
|
uniform.size = 4 * (uniform.components == 3 ? 4 : uniform.components);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uniforms in the block need to be in order of their offset, so find the right index for it
|
vec_push(&block->uniforms, uniform);
|
||||||
int index = 0;
|
|
||||||
while (index < block->uniforms.length && block->uniforms.data[index].offset < uniform.offset) {
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
vec_insert(&block->uniforms, index, uniform);
|
|
||||||
continue;
|
continue;
|
||||||
} else if (uniform.location == -1) {
|
} else if (uniform.location == -1) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1740,7 +1755,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UNIFORM_MATRIX:
|
case UNIFORM_MATRIX:
|
||||||
uniform.size = uniform.components * uniform.components * uniform.count * sizeof(int);
|
uniform.size = uniform.components * uniform.components * uniform.count * sizeof(float);
|
||||||
uniform.value.data = calloc(1, uniform.size);
|
uniform.value.data = calloc(1, uniform.size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1802,9 +1817,13 @@ Shader* lovrShaderInitGraphics(Shader* shader, const char* vertexSource, const c
|
||||||
"#extension GL_ARB_fragment_layer_viewport : require\n" "#define SINGLEPASS 1\n" :
|
"#extension GL_ARB_fragment_layer_viewport : require\n" "#define SINGLEPASS 1\n" :
|
||||||
"#define SINGLEPASS 0\n";
|
"#define SINGLEPASS 0\n";
|
||||||
|
|
||||||
|
size_t maxDraws = MIN(state.limits.blockSize / (20 * sizeof(float)) / 64 * 64, 256);
|
||||||
|
char maxDrawSource[32];
|
||||||
|
snprintf(maxDrawSource, 31, "#define MAX_DRAWS %zu\n", maxDraws);
|
||||||
|
|
||||||
// Vertex
|
// Vertex
|
||||||
vertexSource = vertexSource == NULL ? lovrDefaultVertexShader : vertexSource;
|
vertexSource = vertexSource == NULL ? lovrDefaultVertexShader : vertexSource;
|
||||||
const char* vertexSources[] = { vertexHeader, vertexSinglepass, lovrShaderVertexPrefix, vertexSource, lovrShaderVertexSuffix };
|
const char* vertexSources[] = { vertexHeader, vertexSinglepass, maxDrawSource, lovrShaderVertexPrefix, vertexSource, lovrShaderVertexSuffix };
|
||||||
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSources, sizeof(vertexSources) / sizeof(vertexSources[0]));
|
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSources, sizeof(vertexSources) / sizeof(vertexSources[0]));
|
||||||
|
|
||||||
// Fragment
|
// Fragment
|
||||||
|
@ -1823,6 +1842,7 @@ Shader* lovrShaderInitGraphics(Shader* shader, const char* vertexSource, const c
|
||||||
glBindAttribLocation(program, LOVR_SHADER_TANGENT, "lovrTangent");
|
glBindAttribLocation(program, LOVR_SHADER_TANGENT, "lovrTangent");
|
||||||
glBindAttribLocation(program, LOVR_SHADER_BONES, "lovrBones");
|
glBindAttribLocation(program, LOVR_SHADER_BONES, "lovrBones");
|
||||||
glBindAttribLocation(program, LOVR_SHADER_BONE_WEIGHTS, "lovrBoneWeights");
|
glBindAttribLocation(program, LOVR_SHADER_BONE_WEIGHTS, "lovrBoneWeights");
|
||||||
|
glBindAttribLocation(program, LOVR_SHADER_DRAW_ID, "lovrDrawID");
|
||||||
linkProgram(program);
|
linkProgram(program);
|
||||||
glDetachShader(program, vertexShader);
|
glDetachShader(program, vertexShader);
|
||||||
glDeleteShader(vertexShader);
|
glDeleteShader(vertexShader);
|
||||||
|
@ -1845,7 +1865,9 @@ Shader* lovrShaderInitGraphics(Shader* shader, const char* vertexSource, const c
|
||||||
map_init(&shader->attributes);
|
map_init(&shader->attributes);
|
||||||
for (int i = 0; i < attributeCount; i++) {
|
for (int i = 0; i < attributeCount; i++) {
|
||||||
char name[LOVR_MAX_ATTRIBUTE_LENGTH];
|
char name[LOVR_MAX_ATTRIBUTE_LENGTH];
|
||||||
glGetActiveAttrib(program, i, LOVR_MAX_ATTRIBUTE_LENGTH, NULL, NULL, NULL, name);
|
GLint size;
|
||||||
|
GLenum type;
|
||||||
|
glGetActiveAttrib(program, i, LOVR_MAX_ATTRIBUTE_LENGTH, NULL, &size, &type, name);
|
||||||
map_set(&shader->attributes, name, glGetAttribLocation(program, name));
|
map_set(&shader->attributes, name, glGetAttribLocation(program, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1891,71 +1913,20 @@ void lovrShaderDestroy(void* ref) {
|
||||||
map_deinit(&shader->blockMap);
|
map_deinit(&shader->blockMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShaderBlock
|
|
||||||
|
|
||||||
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, vec_uniform_t* uniforms, BlockType type, BufferUsage usage) {
|
|
||||||
lovrAssert(type != BLOCK_STORAGE || state.features.computeShaders, "Writable ShaderBlocks are not supported on this system");
|
|
||||||
|
|
||||||
vec_init(&block->uniforms);
|
|
||||||
vec_extend(&block->uniforms, uniforms);
|
|
||||||
map_init(&block->uniformMap);
|
|
||||||
|
|
||||||
int i;
|
|
||||||
Uniform* uniform;
|
|
||||||
size_t size = 0;
|
|
||||||
vec_foreach_ptr(&block->uniforms, uniform, i) {
|
|
||||||
|
|
||||||
// Calculate size and offset based on the cryptic std140 rules
|
|
||||||
size_t align;
|
|
||||||
if (uniform->count > 1 || uniform->type == UNIFORM_MATRIX) {
|
|
||||||
align = 16 * (uniform->type == UNIFORM_MATRIX ? uniform->components : 1);
|
|
||||||
uniform->size = align * uniform->count;
|
|
||||||
} else {
|
|
||||||
align = (uniform->components + (uniform->components == 3)) * 4;
|
|
||||||
uniform->size = uniform->components * 4;
|
|
||||||
}
|
|
||||||
uniform->offset = (size + (align - 1)) & -align;
|
|
||||||
size = uniform->offset + uniform->size;
|
|
||||||
|
|
||||||
// Write index to uniform lookup
|
|
||||||
map_set(&block->uniformMap, uniform->name, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
|
||||||
block->target = GL_UNIFORM_BUFFER;
|
|
||||||
#else
|
|
||||||
block->target = block->type == BLOCK_UNIFORM ? GL_UNIFORM_BUFFER : GL_SHADER_STORAGE_BUFFER;
|
|
||||||
#endif
|
|
||||||
block->type = type;
|
|
||||||
block->buffer = lovrBufferCreate(size, NULL, usage, false);
|
|
||||||
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
void lovrShaderBlockDestroy(void* ref) {
|
|
||||||
ShaderBlock* block = ref;
|
|
||||||
lovrGpuDestroySyncResource(block, block->incoherent);
|
|
||||||
lovrRelease(block->buffer);
|
|
||||||
vec_deinit(&block->uniforms);
|
|
||||||
map_deinit(&block->uniformMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mesh
|
// Mesh
|
||||||
|
|
||||||
Mesh* lovrMeshInit(Mesh* mesh, uint32_t count, VertexFormat format, DrawMode mode, BufferUsage usage, bool readable) {
|
Mesh* lovrMeshInit(Mesh* mesh, DrawMode mode, VertexFormat format, Buffer* vertexBuffer) {
|
||||||
mesh->count = count;
|
|
||||||
mesh->mode = mode;
|
mesh->mode = mode;
|
||||||
mesh->format = format;
|
mesh->format = format;
|
||||||
mesh->readable = readable;
|
mesh->vertexBuffer = vertexBuffer;
|
||||||
mesh->usage = usage;
|
mesh->vertexCount = vertexBuffer ? (lovrBufferGetSize(vertexBuffer) / format.stride) : 0;
|
||||||
mesh->vbo = lovrBufferCreate(count * format.stride, NULL, usage, readable);
|
|
||||||
glGenVertexArrays(1, &mesh->vao);
|
glGenVertexArrays(1, &mesh->vao);
|
||||||
|
|
||||||
map_init(&mesh->attributes);
|
map_init(&mesh->attributes);
|
||||||
for (int i = 0; i < format.count; i++) {
|
for (int i = 0; i < format.count; i++) {
|
||||||
lovrRetain(mesh->vbo);
|
lovrRetain(mesh->vertexBuffer);
|
||||||
map_set(&mesh->attributes, format.attributes[i].name, ((MeshAttribute) {
|
map_set(&mesh->attributes, format.attributes[i].name, ((MeshAttribute) {
|
||||||
.buffer = mesh->vbo,
|
.buffer = mesh->vertexBuffer,
|
||||||
.offset = format.attributes[i].offset,
|
.offset = format.attributes[i].offset,
|
||||||
.stride = format.stride,
|
.stride = format.stride,
|
||||||
.type = format.attributes[i].type,
|
.type = format.attributes[i].type,
|
||||||
|
@ -1970,7 +1941,6 @@ Mesh* lovrMeshInit(Mesh* mesh, uint32_t count, VertexFormat format, DrawMode mod
|
||||||
|
|
||||||
void lovrMeshDestroy(void* ref) {
|
void lovrMeshDestroy(void* ref) {
|
||||||
Mesh* mesh = ref;
|
Mesh* mesh = ref;
|
||||||
lovrRelease(mesh->material);
|
|
||||||
glDeleteVertexArrays(1, &mesh->vao);
|
glDeleteVertexArrays(1, &mesh->vao);
|
||||||
const char* key;
|
const char* key;
|
||||||
map_iter_t iter = map_iter(&mesh->attributes);
|
map_iter_t iter = map_iter(&mesh->attributes);
|
||||||
|
@ -1979,6 +1949,7 @@ void lovrMeshDestroy(void* ref) {
|
||||||
lovrRelease(attribute->buffer);
|
lovrRelease(attribute->buffer);
|
||||||
}
|
}
|
||||||
map_deinit(&mesh->attributes);
|
map_deinit(&mesh->attributes);
|
||||||
lovrRelease(mesh->vbo);
|
lovrRelease(mesh->vertexBuffer);
|
||||||
lovrRelease(mesh->ibo);
|
lovrRelease(mesh->indexBuffer);
|
||||||
|
lovrRelease(mesh->material);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
|
|
||||||
#define GPU_BUFFER_FIELDS \
|
#define GPU_BUFFER_FIELDS \
|
||||||
GLsync lock; \
|
GLsync lock; \
|
||||||
uint32_t id;
|
uint32_t id; \
|
||||||
|
uint8_t incoherent;
|
||||||
|
|
||||||
#define GPU_CANVAS_FIELDS \
|
#define GPU_CANVAS_FIELDS \
|
||||||
uint32_t framebuffer; \
|
uint32_t framebuffer; \
|
||||||
|
@ -20,15 +21,12 @@
|
||||||
bool immortal;
|
bool immortal;
|
||||||
|
|
||||||
#define GPU_MESH_FIELDS \
|
#define GPU_MESH_FIELDS \
|
||||||
uint32_t vao;
|
uint32_t vao; \
|
||||||
|
uint32_t ibo;
|
||||||
|
|
||||||
#define GPU_SHADER_FIELDS \
|
#define GPU_SHADER_FIELDS \
|
||||||
uint32_t program;
|
uint32_t program;
|
||||||
|
|
||||||
#define GPU_SHADER_BLOCK_FIELDS \
|
|
||||||
GLenum target; \
|
|
||||||
uint8_t incoherent;
|
|
||||||
|
|
||||||
#define GPU_TEXTURE_FIELDS \
|
#define GPU_TEXTURE_FIELDS \
|
||||||
GLuint id; \
|
GLuint id; \
|
||||||
GLuint msaaId; \
|
GLuint msaaId; \
|
||||||
|
|
|
@ -96,17 +96,15 @@ static void lovrShaderSetUniform(Shader* shader, const char* name, UniformType t
|
||||||
}
|
}
|
||||||
|
|
||||||
Uniform* uniform = &shader->uniforms.data[*index];
|
Uniform* uniform = &shader->uniforms.data[*index];
|
||||||
const char* plural = (uniform->size / size) > 1 ? "s" : "";
|
|
||||||
lovrAssert(uniform->type == type, "Unable to send %ss to uniform %s", debug, name);
|
lovrAssert(uniform->type == type, "Unable to send %ss to uniform %s", debug, name);
|
||||||
lovrAssert((start + count) * size <= uniform->size, "Too many %s%s for uniform %s, maximum is %d", debug, plural, name, uniform->size / size);
|
lovrAssert((start + count) * size <= uniform->size, "Too many %ss for uniform %s, maximum is %d", debug, name, uniform->size / size);
|
||||||
|
|
||||||
void* dest = uniform->value.bytes + start * size;
|
void* dest = uniform->value.bytes + start * size;
|
||||||
if (!uniform->dirty && !memcmp(dest, data, count * size)) {
|
if (memcmp(dest, data, count * size)) {
|
||||||
return;
|
lovrGraphicsFlushShader(shader);
|
||||||
|
memcpy(dest, data, count * size);
|
||||||
|
uniform->dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(dest, data, count * size);
|
|
||||||
uniform->dirty = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrShaderSetFloats(Shader* shader, const char* name, float* data, int start, int count) {
|
void lovrShaderSetFloats(Shader* shader, const char* name, float* data, int start, int count) {
|
||||||
|
@ -139,37 +137,69 @@ void lovrShaderSetColor(Shader* shader, const char* name, Color color) {
|
||||||
lovrShaderSetUniform(shader, name, UNIFORM_FLOAT, (float*) &color, 0, 4, sizeof(float), "float");
|
lovrShaderSetUniform(shader, name, UNIFORM_FLOAT, (float*) &color, 0, 4, sizeof(float), "float");
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrShaderSetBlock(Shader* shader, const char* name, ShaderBlock* source, UniformAccess access) {
|
void lovrShaderSetBlock(Shader* shader, const char* name, Buffer* buffer, size_t offset, size_t size, UniformAccess access) {
|
||||||
int* id = map_get(&shader->blockMap, name);
|
int* id = map_get(&shader->blockMap, name);
|
||||||
lovrAssert(id, "No shader block named '%s'", name);
|
if (!id) return;
|
||||||
|
|
||||||
int type = *id & 1;
|
int type = *id & 1;
|
||||||
int index = *id >> 1;
|
int index = *id >> 1;
|
||||||
UniformBlock* block = &shader->blocks[type].data[index];
|
UniformBlock* block = &shader->blocks[type].data[index];
|
||||||
block->access = access;
|
|
||||||
|
|
||||||
if (source != block->source) {
|
if (block->source != buffer || block->offset != offset || block->size != size) {
|
||||||
if (source) {
|
lovrGraphicsFlushShader(shader);
|
||||||
lovrAssert(block->uniforms.length == source->uniforms.length, "ShaderBlock must have same number of uniforms as block definition in Shader");
|
lovrRetain(buffer);
|
||||||
for (int i = 0; i < block->uniforms.length; i++) {
|
|
||||||
const Uniform* u = &block->uniforms.data[i];
|
|
||||||
const Uniform* v = &source->uniforms.data[i];
|
|
||||||
lovrAssert(u->type == v->type, "Shader is not compatible with ShaderBlock, check type of variable '%s'", v->name);
|
|
||||||
lovrAssert(u->offset == v->offset, "Shader is not compatible with ShaderBlock, check order of variable '%s'", v->name);
|
|
||||||
|
|
||||||
// This check is disabled due to observed driver bugs with std140 layouts
|
|
||||||
// lovrAssert(u->size == v->size, "Shader is not compatible with ShaderBlock, check count of variable '%s'", v->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lovrRetain(source);
|
|
||||||
lovrRelease(block->source);
|
lovrRelease(block->source);
|
||||||
block->source = source;
|
block->access = access;
|
||||||
|
block->source = buffer;
|
||||||
|
block->offset = offset;
|
||||||
|
block->size = size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShaderBlock
|
// ShaderBlock
|
||||||
|
|
||||||
|
// Calculates uniform size and byte offsets using std140 rules, returning the total buffer size
|
||||||
|
size_t lovrShaderComputeUniformLayout(vec_uniform_t* uniforms) {
|
||||||
|
size_t size = 0;
|
||||||
|
Uniform* uniform; int i;
|
||||||
|
vec_foreach_ptr(uniforms, uniform, i) {
|
||||||
|
size_t align;
|
||||||
|
if (uniform->count > 1 || uniform->type == UNIFORM_MATRIX) {
|
||||||
|
align = 16 * (uniform->type == UNIFORM_MATRIX ? uniform->components : 1);
|
||||||
|
uniform->size = align * uniform->count;
|
||||||
|
} else {
|
||||||
|
align = (uniform->components + (uniform->components == 3)) * 4;
|
||||||
|
uniform->size = uniform->components * 4;
|
||||||
|
}
|
||||||
|
uniform->offset = (size + (align - 1)) & -align;
|
||||||
|
size = uniform->offset + uniform->size;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, BlockType type, Buffer* buffer, vec_uniform_t* uniforms) {
|
||||||
|
vec_init(&block->uniforms);
|
||||||
|
map_init(&block->uniformMap);
|
||||||
|
|
||||||
|
Uniform* uniform; int i;
|
||||||
|
vec_extend(&block->uniforms, uniforms);
|
||||||
|
vec_foreach_ptr(&block->uniforms, uniform, i) {
|
||||||
|
map_set(&block->uniformMap, uniform->name, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
block->type = type;
|
||||||
|
block->buffer = buffer;
|
||||||
|
lovrRetain(buffer);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lovrShaderBlockDestroy(void* ref) {
|
||||||
|
ShaderBlock* block = ref;
|
||||||
|
lovrRelease(block->buffer);
|
||||||
|
vec_deinit(&block->uniforms);
|
||||||
|
map_deinit(&block->uniformMap);
|
||||||
|
}
|
||||||
|
|
||||||
BlockType lovrShaderBlockGetType(ShaderBlock* block) {
|
BlockType lovrShaderBlockGetType(ShaderBlock* block) {
|
||||||
return block->type;
|
return block->type;
|
||||||
}
|
}
|
||||||
|
@ -225,4 +255,3 @@ const Uniform* lovrShaderBlockGetUniform(ShaderBlock* block, const char* name) {
|
||||||
Buffer* lovrShaderBlockGetBuffer(ShaderBlock* block) {
|
Buffer* lovrShaderBlockGetBuffer(ShaderBlock* block) {
|
||||||
return block->buffer;
|
return block->buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,14 +80,15 @@ typedef struct {
|
||||||
vec_uniform_t uniforms;
|
vec_uniform_t uniforms;
|
||||||
map_int_t uniformMap;
|
map_int_t uniformMap;
|
||||||
Buffer* buffer;
|
Buffer* buffer;
|
||||||
GPU_SHADER_BLOCK_FIELDS
|
|
||||||
} ShaderBlock;
|
} ShaderBlock;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
vec_uniform_t uniforms;
|
vec_uniform_t uniforms;
|
||||||
int slot;
|
|
||||||
ShaderBlock* source;
|
|
||||||
UniformAccess access;
|
UniformAccess access;
|
||||||
|
Buffer* source;
|
||||||
|
size_t offset;
|
||||||
|
size_t size;
|
||||||
|
int slot;
|
||||||
} UniformBlock;
|
} UniformBlock;
|
||||||
|
|
||||||
typedef vec_t(UniformBlock) vec_block_t;
|
typedef vec_t(UniformBlock) vec_block_t;
|
||||||
|
@ -122,11 +123,13 @@ void lovrShaderSetMatrices(Shader* shader, const char* name, float* data, int st
|
||||||
void lovrShaderSetTextures(Shader* shader, const char* name, Texture** data, int start, int count);
|
void lovrShaderSetTextures(Shader* shader, const char* name, 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, Image* 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, ShaderBlock* block, UniformAccess access);
|
void lovrShaderSetBlock(Shader* shader, const char* name, Buffer* buffer, size_t offset, size_t size, UniformAccess access);
|
||||||
|
|
||||||
// ShaderBlock
|
// ShaderBlock
|
||||||
|
|
||||||
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, vec_uniform_t* uniforms, BlockType type, BufferUsage usage);
|
size_t lovrShaderComputeUniformLayout(vec_uniform_t* uniforms);
|
||||||
|
|
||||||
|
ShaderBlock* lovrShaderBlockInit(ShaderBlock* block, BlockType type, Buffer* buffer, vec_uniform_t* uniforms);
|
||||||
#define lovrShaderBlockCreate(...) lovrShaderBlockInit(lovrAlloc(ShaderBlock), __VA_ARGS__)
|
#define lovrShaderBlockCreate(...) lovrShaderBlockInit(lovrAlloc(ShaderBlock), __VA_ARGS__)
|
||||||
void lovrShaderBlockDestroy(void* ref);
|
void lovrShaderBlockDestroy(void* ref);
|
||||||
BlockType lovrShaderBlockGetType(ShaderBlock* block);
|
BlockType lovrShaderBlockGetType(ShaderBlock* block);
|
||||||
|
|
|
@ -5,7 +5,7 @@ const char* lovrShaderVertexPrefix = ""
|
||||||
"#define MAX_BONES 48 \n"
|
"#define MAX_BONES 48 \n"
|
||||||
"#define lovrView lovrViews[lovrViewportIndex] \n"
|
"#define lovrView lovrViews[lovrViewportIndex] \n"
|
||||||
"#define lovrProjection lovrProjections[lovrViewportIndex] \n"
|
"#define lovrProjection lovrProjections[lovrViewportIndex] \n"
|
||||||
"#define lovrModel lovrModels[lovrDrawID] \n"
|
"#define lovrModel lovrDraws[lovrDrawID].model \n"
|
||||||
"#define lovrTransform (lovrView * lovrModel) \n"
|
"#define lovrTransform (lovrView * lovrModel) \n"
|
||||||
"#define lovrNormalMatrix mat3(transpose(inverse(lovrTransform))) \n"
|
"#define lovrNormalMatrix mat3(transpose(inverse(lovrTransform))) \n"
|
||||||
"#define lovrInstanceID (gl_InstanceID / lovrViewportCount) \n"
|
"#define lovrInstanceID (gl_InstanceID / lovrViewportCount) \n"
|
||||||
|
@ -27,8 +27,10 @@ const char* lovrShaderVertexPrefix = ""
|
||||||
"out vec4 vertexColor; \n"
|
"out vec4 vertexColor; \n"
|
||||||
"out vec4 lovrColor; \n"
|
"out vec4 lovrColor; \n"
|
||||||
"uniform lovrDrawData { \n"
|
"uniform lovrDrawData { \n"
|
||||||
" mat4 lovrModels[192]; \n"
|
" struct { \n"
|
||||||
" vec4 lovrColors[192]; \n"
|
" mat4 model; \n"
|
||||||
|
" vec4 color; \n"
|
||||||
|
" } lovrDraws[MAX_DRAWS]; \n"
|
||||||
"}; \n"
|
"}; \n"
|
||||||
"uniform mat4 lovrViews[2]; \n"
|
"uniform mat4 lovrViews[2]; \n"
|
||||||
"uniform mat4 lovrProjections[2]; \n"
|
"uniform mat4 lovrProjections[2]; \n"
|
||||||
|
@ -47,7 +49,7 @@ const char* lovrShaderVertexSuffix = ""
|
||||||
"void main() { \n"
|
"void main() { \n"
|
||||||
" texCoord = (lovrMaterialTransform * vec3(lovrTexCoord, 1.)).xy; \n"
|
" texCoord = (lovrMaterialTransform * vec3(lovrTexCoord, 1.)).xy; \n"
|
||||||
" vertexColor = lovrVertexColor; \n"
|
" vertexColor = lovrVertexColor; \n"
|
||||||
" lovrColor = lovrColors[lovrDrawID]; \n"
|
" lovrColor = lovrDraws[lovrDrawID].color; \n"
|
||||||
"#if SINGLEPASS \n"
|
"#if SINGLEPASS \n"
|
||||||
" gl_ViewportIndex = gl_InstanceID % lovrViewportCount; \n"
|
" gl_ViewportIndex = gl_InstanceID % lovrViewportCount; \n"
|
||||||
"#endif \n"
|
"#endif \n"
|
||||||
|
|
Loading…
Reference in New Issue