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)
|
||||
target_sources(lovr PRIVATE
|
||||
src/graphics/animator.c
|
||||
src/graphics/buffer.c
|
||||
src/graphics/canvas.c
|
||||
src/graphics/font.c
|
||||
src/graphics/graphics.c
|
||||
|
|
|
@ -46,7 +46,6 @@ const char* BlendModes[] = {
|
|||
[BLEND_LIGHTEN] = "lighten",
|
||||
[BLEND_DARKEN] = "darken",
|
||||
[BLEND_SCREEN] = "screen",
|
||||
[BLEND_REPLACE] = "replace",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -95,8 +94,8 @@ const char* FilterModes[] = {
|
|||
|
||||
const char* HorizontalAligns[] = {
|
||||
[ALIGN_LEFT] = "left",
|
||||
[ALIGN_RIGHT] = "right",
|
||||
[ALIGN_CENTER] = "center",
|
||||
[ALIGN_RIGHT] = "right",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -177,8 +176,8 @@ const char* UniformAccesses[] = {
|
|||
|
||||
const char* VerticalAligns[] = {
|
||||
[ALIGN_TOP] = "top",
|
||||
[ALIGN_BOTTOM] = "bottom",
|
||||
[ALIGN_MIDDLE] = "middle",
|
||||
[ALIGN_BOTTOM] = "bottom",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -195,60 +194,61 @@ const char* WrapModes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static uint32_t luax_readvertices(lua_State* L, int index) {
|
||||
switch (lua_type(L, index)) {
|
||||
case LUA_TTABLE: {
|
||||
size_t count = lua_objlen(L, index);
|
||||
lua_rawgeti(L, index, 1);
|
||||
static uint32_t luax_getvertexcount(lua_State* L, int index) {
|
||||
int type = lua_type(L, index);
|
||||
if (type == LUA_TTABLE) {
|
||||
size_t count = lua_objlen(L, index);
|
||||
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) {
|
||||
lua_pop(L, 1);
|
||||
float* vertices = lovrGraphicsGetVertexPointer(count / 3);
|
||||
for (size_t i = 1; i <= count; i += 3) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
lua_rawgeti(L, index, i + j);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
for (int j = 1; j <= 3; j++) {
|
||||
lua_rawgeti(L, index, 3 * i + j);
|
||||
vertices[j] = lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
vertices += 8;
|
||||
}
|
||||
return count / 3;
|
||||
} else {
|
||||
lua_pop(L, 1);
|
||||
float* vertices = lovrGraphicsGetVertexPointer(count);
|
||||
for (size_t i = 1; i <= count; i++) {
|
||||
lua_rawgeti(L, index, i);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
lua_rawgeti(L, index, i + 1);
|
||||
vec3_init(vertices, luax_checkmathtype(L, -1, MATH_VEC3, NULL));
|
||||
lua_pop(L, 1);
|
||||
vertices += 8;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LUA_TNUMBER: {
|
||||
int top = lua_gettop(L);
|
||||
uint32_t count = (top - index + 1) / 3;
|
||||
float* vertices = lovrGraphicsGetVertexPointer(count);
|
||||
for (int i = index; i <= top; i += 3) {
|
||||
case LUA_TNUMBER:
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
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;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
break;
|
||||
|
||||
default: {
|
||||
int top = lua_gettop(L);
|
||||
uint32_t count = top - index + 1;
|
||||
float* vertices = lovrGraphicsGetVertexPointer(count);
|
||||
for (int i = index; i <= top; i++) {
|
||||
vec3_init(vertices, luax_checkmathtype(L, i, MATH_VEC3, NULL));
|
||||
default:
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
vec3_init(vertices, luax_checkmathtype(L, index + i, MATH_VEC3, NULL));
|
||||
vertices += 8;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -426,7 +426,7 @@ static int l_lovrGraphicsGetBlendMode(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);
|
||||
lovrGraphicsSetBlendMode(mode, alphaMode);
|
||||
return 0;
|
||||
|
@ -711,14 +711,18 @@ static int l_lovrGraphicsFlush(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrGraphicsPoints(lua_State* L) {
|
||||
uint32_t count = luax_readvertices(L, 1);
|
||||
lovrGraphicsPoints(count);
|
||||
float* vertices;
|
||||
uint32_t count = luax_getvertexcount(L, 1);
|
||||
lovrGraphicsPoints(count, &vertices);
|
||||
luax_readvertices(L, 1, vertices, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrGraphicsLine(lua_State* L) {
|
||||
uint32_t count = luax_readvertices(L, 1);
|
||||
lovrGraphicsLine(count);
|
||||
float* vertices;
|
||||
uint32_t count = luax_getvertexcount(L, 1);
|
||||
lovrGraphicsLine(count, &vertices);
|
||||
luax_readvertices(L, 1, vertices, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -731,13 +735,11 @@ static int l_lovrGraphicsTriangle(lua_State* L) {
|
|||
style = luaL_checkoption(L, 1, NULL, DrawStyles);
|
||||
}
|
||||
|
||||
float points[9];
|
||||
int top = lua_gettop(L);
|
||||
lovrAssert(top >= 10, "Expected 3 points to make a triangle, got %d\n", (top - 1) / 3);
|
||||
for (int i = 0; i < 9; i++) {
|
||||
points[i] = luaL_checknumber(L, i + 2);
|
||||
}
|
||||
lovrGraphicsTriangle(style, material, points);
|
||||
float* vertices;
|
||||
uint32_t count = luax_getvertexcount(L, 2);
|
||||
lovrAssert(count % 3 == 0, "Triangle vertex count must be a multiple of 3");
|
||||
lovrGraphicsTriangle(style, material, count, &vertices);
|
||||
luax_readvertices(L, 2, vertices, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -785,17 +787,17 @@ static int l_lovrGraphicsArc(lua_State* L) {
|
|||
} else {
|
||||
style = luaL_checkoption(L, 1, NULL, DrawStyles);
|
||||
}
|
||||
ArcMode arcMode = ARC_MODE_PIE;
|
||||
ArcMode mode = ARC_MODE_PIE;
|
||||
int index = 2;
|
||||
if (lua_type(L, index) == LUA_TSTRING) {
|
||||
arcMode = luaL_checkoption(L, index++, NULL, ArcModes);
|
||||
mode = luaL_checkoption(L, index++, NULL, ArcModes);
|
||||
}
|
||||
float transform[16];
|
||||
index = luax_readmat4(L, index, transform, 1, NULL);
|
||||
float theta1 = luaL_optnumber(L, index++, 0);
|
||||
float theta2 = luaL_optnumber(L, index++, 2 * M_PI);
|
||||
int segments = luaL_optinteger(L, index, 64) * (MIN(fabsf(theta2 - theta1), 2 * M_PI) / (2 * M_PI));
|
||||
lovrGraphicsArc(style, arcMode, material, transform, theta1, theta2, segments);
|
||||
float r1 = luaL_optnumber(L, index++, 0);
|
||||
float r2 = luaL_optnumber(L, index++, 2 * M_PI);
|
||||
int segments = luaL_optinteger(L, index, 64) * (MIN(fabsf(r2 - r1), 2 * M_PI) / (2 * M_PI));
|
||||
lovrGraphicsArc(style, mode, material, transform, r1, r2, segments);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -953,9 +955,14 @@ static int l_lovrGraphicsNewShaderBlock(lua_State* L) {
|
|||
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);
|
||||
vec_deinit(&uniforms);
|
||||
lovrRelease(buffer);
|
||||
lovrRelease(block);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1156,17 +1163,9 @@ static int l_lovrGraphicsNewMesh(lua_State* L) {
|
|||
DrawMode mode = luaL_checkoption(L, drawModeIndex, "fan", DrawModes);
|
||||
BufferUsage usage = luaL_checkoption(L, drawModeIndex + 1, "dynamic", BufferUsages);
|
||||
bool readable = lua_toboolean(L, drawModeIndex + 2);
|
||||
Mesh* mesh = lovrMeshCreate(count, format, mode, usage, readable);
|
||||
|
||||
if (dataIndex) {
|
||||
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);
|
||||
}
|
||||
size_t bufferSize = count * format.stride;
|
||||
Buffer* vertexBuffer = lovrBufferCreate(bufferSize, NULL, BUFFER_VERTEX, usage, readable);
|
||||
Mesh* mesh = lovrMeshCreate(mode, format, vertexBuffer);
|
||||
|
||||
lovrMeshAttachAttribute(mesh, "lovrDrawID", &(MeshAttribute) {
|
||||
.buffer = lovrGraphicsGetIdentityBuffer(),
|
||||
|
@ -1177,6 +1176,17 @@ static int l_lovrGraphicsNewMesh(lua_State* L) {
|
|||
.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);
|
||||
lovrRelease(mesh);
|
||||
return 1;
|
||||
|
|
|
@ -3,9 +3,14 @@
|
|||
|
||||
int l_lovrFontGetWidth(lua_State* L) {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -76,11 +76,22 @@ int l_lovrMeshDraw(lua_State* L) {
|
|||
float transform[16];
|
||||
int index = luax_readmat4(L, 2, transform, 1, NULL);
|
||||
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,
|
||||
.mesh = mesh,
|
||||
.material = lovrMeshGetMaterial(mesh),
|
||||
.instances = instances
|
||||
.material = lovrMeshGetMaterial(mesh)
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
|
@ -113,47 +124,51 @@ int l_lovrMeshGetVertexCount(lua_State* L) {
|
|||
int l_lovrMeshGetVertex(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
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);
|
||||
VertexPointer vertex = { .raw = lovrMeshMapVertices(mesh, index * format->stride) };
|
||||
VertexPointer vertex = { .raw = lovrBufferMap(buffer, index * format->stride) };
|
||||
return luax_pushvertex(L, &vertex, format);
|
||||
}
|
||||
|
||||
int l_lovrMeshSetVertex(lua_State* L) {
|
||||
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);
|
||||
Buffer* buffer = lovrMeshGetVertexBuffer(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);
|
||||
lovrMeshFlushVertices(mesh, index * format->stride, format->stride);
|
||||
lovrMeshMarkVertices(mesh, index * format->stride, (index + 1) * format->stride);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrMeshGetVertexAttribute(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
int vertexIndex = luaL_checkint(L, 2) - 1;
|
||||
int attributeIndex = luaL_checkint(L, 3) - 1;
|
||||
uint32_t vertexIndex = luaL_checkinteger(L, 2) - 1;
|
||||
int attributeIndex = luaL_checkinteger(L, 3) - 1;
|
||||
Buffer* buffer = lovrMeshGetVertexBuffer(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(attributeIndex >= 0 && attributeIndex < format->count, "Invalid mesh attribute: %d", attributeIndex + 1);
|
||||
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);
|
||||
}
|
||||
|
||||
int l_lovrMeshSetVertexAttribute(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
int vertexIndex = luaL_checkint(L, 2) - 1;
|
||||
int attributeIndex = luaL_checkint(L, 3) - 1;
|
||||
uint32_t vertexIndex = luaL_checkinteger(L, 2) - 1;
|
||||
int attributeIndex = luaL_checkinteger(L, 3) - 1;
|
||||
VertexFormat* format = lovrMeshGetVertexFormat(mesh);
|
||||
lovrAssert(vertexIndex >= 0 && vertexIndex < lovrMeshGetVertexCount(mesh), "Invalid mesh vertex: %d", vertexIndex + 1);
|
||||
lovrAssert(attributeIndex >= 0 && attributeIndex < format->count, "Invalid mesh attribute: %d", attributeIndex + 1);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -173,12 +188,13 @@ int l_lovrMeshSetVertices(lua_State* L) {
|
|||
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);
|
||||
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);
|
||||
|
||||
VertexPointer vertices = { .raw = lovrMeshMapVertices(mesh, start * format->stride) };
|
||||
Buffer* buffer = lovrMeshGetVertexBuffer(mesh);
|
||||
VertexPointer vertices = { .raw = lovrBufferMap(buffer, start * format->stride) };
|
||||
|
||||
if (vertexData) {
|
||||
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;
|
||||
}
|
||||
|
||||
int l_lovrMeshGetVertexMap(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
uint32_t count;
|
||||
size_t size;
|
||||
IndexPointer indices = { .raw = lovrMeshReadIndices(mesh, &count, &size) };
|
||||
Buffer* buffer = lovrMeshGetIndexBuffer(mesh);
|
||||
uint32_t count = lovrMeshGetIndexCount(mesh);
|
||||
size_t size = lovrMeshGetIndexSize(mesh);
|
||||
|
||||
if (count == 0 || !indices.raw) {
|
||||
if (!buffer || count == 0 || size == 0) {
|
||||
lua_pushnil(L);
|
||||
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)) {
|
||||
lua_settop(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);
|
||||
|
||||
if (lua_isnoneornil(L, 2)) {
|
||||
lovrMeshMapIndices(mesh, 0, 0, 0);
|
||||
lovrMeshSetIndexBuffer(mesh, NULL, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -241,14 +260,33 @@ int l_lovrMeshSetVertexMap(lua_State* L) {
|
|||
size_t size = luaL_optinteger(L, 3, 4);
|
||||
lovrAssert(size == 2 || size == 4, "Size of Mesh indices should be 2 bytes or 4 bytes");
|
||||
uint32_t count = blob->size / size;
|
||||
void* indices = lovrMeshMapIndices(mesh, count, size, 0);
|
||||
memcpy(indices, blob->data, blob->size);
|
||||
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(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 {
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
uint32_t count = lua_objlen(L, 2);
|
||||
uint32_t vertexCount = lovrMeshGetVertexCount(mesh);
|
||||
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++) {
|
||||
lua_rawgeti(L, 2, i + 1);
|
||||
|
@ -269,9 +307,10 @@ int l_lovrMeshSetVertexMap(lua_State* L) {
|
|||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
lovrMeshFlushIndices(mesh);
|
||||
lovrMeshSetIndexBuffer(mesh, indexBuffer, count, size);
|
||||
lovrBufferFlush(indexBuffer, 0, count * size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
int l_lovrModelDraw(lua_State* L) {
|
||||
Model* model = luax_checktype(L, 1, Model);
|
||||
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);
|
||||
lovrModelDraw(model, transform, instances);
|
||||
return 0;
|
||||
|
|
|
@ -248,7 +248,8 @@ int l_lovrShaderSendBlock(lua_State* L) {
|
|||
const char* name = luaL_checkstring(L, 2);
|
||||
ShaderBlock* block = luax_checktype(L, 3, ShaderBlock);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,10 @@ size_t lovrBufferGetSize(Buffer* buffer) {
|
|||
return buffer->size;
|
||||
}
|
||||
|
||||
bool lovrBufferIsReadable(Buffer* buffer) {
|
||||
return buffer->readable;
|
||||
}
|
||||
|
||||
BufferUsage lovrBufferGetUsage(Buffer* buffer) {
|
||||
return buffer->usage;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,15 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
BUFFER_VERTEX,
|
||||
BUFFER_INDEX,
|
||||
BUFFER_UNIFORM,
|
||||
BUFFER_SHADER_STORAGE,
|
||||
BUFFER_GENERIC,
|
||||
MAX_BUFFER_TYPES
|
||||
} BufferType;
|
||||
|
||||
typedef enum {
|
||||
USAGE_STATIC,
|
||||
USAGE_DYNAMIC,
|
||||
|
@ -15,16 +24,17 @@ typedef struct {
|
|||
Ref ref;
|
||||
void* data;
|
||||
size_t size;
|
||||
bool readable;
|
||||
BufferType type;
|
||||
BufferUsage usage;
|
||||
GPU_BUFFER_FIELDS
|
||||
} 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__)
|
||||
void lovrBufferDestroy(void* ref);
|
||||
size_t lovrBufferGetSize(Buffer* buffer);
|
||||
bool lovrBufferIsReadable(Buffer* buffer);
|
||||
BufferUsage lovrBufferGetUsage(Buffer* buffer);
|
||||
void* lovrBufferMap(Buffer* buffer, size_t offset);
|
||||
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/graphics.h"
|
||||
|
||||
const Attachment* lovrCanvasGetAttachments(Canvas* canvas, int* count) {
|
||||
if (count) *count = canvas->attachmentCount;
|
||||
|
@ -13,6 +14,8 @@ void lovrCanvasSetAttachments(Canvas* canvas, Attachment* attachments, int count
|
|||
return;
|
||||
}
|
||||
|
||||
lovrGraphicsFlushCanvas(canvas);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Texture* texture = attachments[i].texture;
|
||||
int width = lovrTextureGetWidth(texture, attachments[i].level);
|
||||
|
|
|
@ -68,7 +68,7 @@ Rasterizer* lovrFontGetRasterizer(Font* font) {
|
|||
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;
|
||||
|
||||
float cx = 0;
|
||||
|
@ -83,17 +83,16 @@ void lovrFontRender(Font* font, const char* str, size_t length, float wrap, Hori
|
|||
unsigned int codepoint;
|
||||
size_t bytes;
|
||||
|
||||
float* cursor = vertices;
|
||||
float* vertexCursor = vertices;
|
||||
uint16_t* indexCursor = indices;
|
||||
float* lineStart = vertices;
|
||||
int lineCount = 1;
|
||||
*vertexCount = 0;
|
||||
uint16_t I = baseVertex;
|
||||
|
||||
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
||||
|
||||
// Newlines
|
||||
if (codepoint == '\n' || (wrap && cx * scale > wrap && codepoint == ' ')) {
|
||||
lineStart = lovrFontAlignLine(lineStart, cursor, cx, halign);
|
||||
lineCount++;
|
||||
lineStart = lovrFontAlignLine(lineStart, vertexCursor, cx, halign);
|
||||
cx = 0;
|
||||
cy -= font->rasterizer->height * font->lineHeight;
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 t2 = glyph->y / v;
|
||||
|
||||
float quad[48] = {
|
||||
memcpy(vertexCursor, (float[32]) {
|
||||
x1, y1, 0, 0, 0, 0, s1, t1,
|
||||
x1, y2, 0, 0, 0, 0, s1, t2,
|
||||
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
|
||||
};
|
||||
}, 32 * sizeof(float));
|
||||
|
||||
memcpy(cursor, quad, 6 * 8 * sizeof(float));
|
||||
cursor += 48;
|
||||
*vertexCount += 6;
|
||||
memcpy(indexCursor, (uint16_t[6]) { I + 0, I + 1, I + 2, I + 2, I + 1, I + 3 }, 6 * sizeof(uint16_t));
|
||||
|
||||
vertexCursor += 32;
|
||||
indexCursor += 6;
|
||||
I += 4;
|
||||
}
|
||||
|
||||
// Advance cursor
|
||||
|
@ -153,30 +152,24 @@ void lovrFontRender(Font* font, const char* str, size_t length, float wrap, Hori
|
|||
}
|
||||
|
||||
// Align the last line
|
||||
lovrFontAlignLine(lineStart, cursor, 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;
|
||||
}
|
||||
lovrFontAlignLine(lineStart, vertexCursor, cx, halign);
|
||||
}
|
||||
|
||||
float lovrFontGetWidth(Font* font, const char* str, float wrap) {
|
||||
float width = 0;
|
||||
void lovrFontMeasure(Font* font, const char* str, size_t length, float wrap, float* width, uint32_t* lineCount, uint32_t* glyphCount) {
|
||||
float x = 0;
|
||||
const char* end = str + strlen(str);
|
||||
const char* end = str + length;
|
||||
size_t bytes;
|
||||
unsigned int previous = '\0';
|
||||
unsigned int codepoint;
|
||||
float scale = 1 / font->pixelDensity;
|
||||
*width = 0.f;
|
||||
*lineCount = 0;
|
||||
*glyphCount = 0;
|
||||
|
||||
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
||||
if (codepoint == '\n' || (wrap && x * scale > wrap && codepoint == ' ')) {
|
||||
width = MAX(width, x * scale);
|
||||
*width = MAX(*width, x * scale);
|
||||
(*lineCount)++;
|
||||
x = 0;
|
||||
previous = '\0';
|
||||
str += bytes;
|
||||
|
@ -192,12 +185,17 @@ float lovrFontGetWidth(Font* font, const char* str, float wrap) {
|
|||
}
|
||||
|
||||
Glyph* glyph = lovrFontGetGlyph(font, codepoint);
|
||||
|
||||
if (glyph->w > 0 && glyph->h > 0) {
|
||||
(*glyphCount)++;
|
||||
}
|
||||
|
||||
x += glyph->advance + lovrFontGetKerning(font, previous, codepoint);
|
||||
previous = codepoint;
|
||||
str += bytes;
|
||||
}
|
||||
|
||||
return MAX(width, x * scale);
|
||||
*width = MAX(*width, x * scale);
|
||||
}
|
||||
|
||||
float lovrFontGetHeight(Font* font) {
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
|
||||
typedef enum {
|
||||
ALIGN_LEFT,
|
||||
ALIGN_RIGHT,
|
||||
ALIGN_CENTER
|
||||
ALIGN_CENTER,
|
||||
ALIGN_RIGHT
|
||||
} HorizontalAlign;
|
||||
|
||||
typedef enum {
|
||||
ALIGN_TOP,
|
||||
ALIGN_BOTTOM,
|
||||
ALIGN_MIDDLE
|
||||
ALIGN_MIDDLE,
|
||||
ALIGN_BOTTOM
|
||||
} VerticalAlign;
|
||||
|
||||
typedef struct {
|
||||
|
@ -42,8 +42,8 @@ Font* lovrFontInit(Font* font, Rasterizer* rasterizer);
|
|||
#define lovrFontCreate(...) lovrFontInit(lovrAlloc(Font), __VA_ARGS__)
|
||||
void lovrFontDestroy(void* ref);
|
||||
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);
|
||||
float lovrFontGetWidth(Font* font, const char* string, float wrap);
|
||||
void lovrFontRender(Font* font, const char* str, size_t length, float wrap, HorizontalAlign halign, float* vertices, uint16_t* indices, uint16_t baseVertex);
|
||||
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 lovrFontGetAscent(Font* font);
|
||||
float lovrFontGetDescent(Font* font);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -13,9 +13,8 @@
|
|||
#pragma once
|
||||
|
||||
#define MAX_TRANSFORMS 64
|
||||
#define MAX_VERTICES (1 << 16)
|
||||
#define MAX_INDICES (1 << 16)
|
||||
#define MAX_BATCH_SIZE 192 // Enough to fit in any UBO
|
||||
#define MAX_BATCHES 16
|
||||
#define MAX_LOCKS 4
|
||||
|
||||
typedef void (*StencilCallback)(void* userdata);
|
||||
|
||||
|
@ -33,7 +32,7 @@ typedef enum {
|
|||
BLEND_LIGHTEN,
|
||||
BLEND_DARKEN,
|
||||
BLEND_SCREEN,
|
||||
BLEND_REPLACE
|
||||
BLEND_NONE
|
||||
} BlendMode;
|
||||
|
||||
typedef enum {
|
||||
|
@ -70,27 +69,6 @@ typedef enum {
|
|||
WINDING_COUNTERCLOCKWISE
|
||||
} 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 {
|
||||
bool stereo;
|
||||
Canvas* canvas;
|
||||
|
@ -99,34 +77,87 @@ typedef struct {
|
|||
} Camera;
|
||||
|
||||
typedef struct {
|
||||
BlendMode blendMode : 3;
|
||||
BlendAlphaMode blendAlphaMode : 1;
|
||||
CompareMode depthTest : 3;
|
||||
float transform[16];
|
||||
Color color;
|
||||
} 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;
|
||||
uint8_t lineWidth : 8;
|
||||
uint8_t stencilValue: 8;
|
||||
CompareMode stencilMode : 3;
|
||||
bool alphaSampling : 1;
|
||||
bool culling : 1;
|
||||
Winding winding : 1;
|
||||
uint8_t stencilMode : 3; // CompareMode
|
||||
uint8_t winding : 1; // Winding
|
||||
bool wireframe : 1;
|
||||
} 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 {
|
||||
Mesh* mesh;
|
||||
DrawMode mode;
|
||||
struct { uint32_t count; float* data; } vertex;
|
||||
struct { uint32_t count; uint16_t* data; } index;
|
||||
BatchType type;
|
||||
BatchParams params;
|
||||
DefaultShader shader;
|
||||
Pipeline* pipeline;
|
||||
Material* material;
|
||||
Texture* diffuseTexture;
|
||||
Texture* environmentMap;
|
||||
Material* material;
|
||||
Pipeline* pipeline;
|
||||
mat4 transform;
|
||||
float* pose;
|
||||
int instances;
|
||||
bool mono;
|
||||
} DrawRequest;
|
||||
uint32_t vertexCount;
|
||||
uint32_t indexCount;
|
||||
float** vertices;
|
||||
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 {
|
||||
bool initialized;
|
||||
|
@ -137,7 +168,6 @@ typedef struct {
|
|||
Shader* defaultShaders[MAX_DEFAULT_SHADERS];
|
||||
Material* defaultMaterial;
|
||||
Font* defaultFont;
|
||||
Mesh* defaultMesh;
|
||||
TextureFilter defaultFilter;
|
||||
float transforms[MAX_TRANSFORMS][16];
|
||||
int transform;
|
||||
|
@ -148,15 +178,15 @@ typedef struct {
|
|||
Pipeline pipeline;
|
||||
float pointSize;
|
||||
Shader* shader;
|
||||
DrawRequest batch;
|
||||
int batchVertex;
|
||||
int batchIndex;
|
||||
int batchSize;
|
||||
int vertexCursor;
|
||||
int indexCursor;
|
||||
ShaderBlock* block;
|
||||
Buffer* vertexMap;
|
||||
uint32_t maxDraws;
|
||||
Mesh* mesh;
|
||||
Mesh* instancedMesh;
|
||||
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;
|
||||
|
||||
// Base
|
||||
|
@ -167,6 +197,7 @@ void lovrGraphicsSetWindow(WindowFlags* flags);
|
|||
int lovrGraphicsGetWidth();
|
||||
int lovrGraphicsGetHeight();
|
||||
void lovrGraphicsSetCamera(Camera* camera, bool clear);
|
||||
void* lovrGraphicsMapBuffer(BufferRole role, uint32_t count);
|
||||
Buffer* lovrGraphicsGetIdentityBuffer();
|
||||
#define lovrGraphicsGetSupported lovrGpuGetSupported
|
||||
#define lovrGraphicsGetLimits lovrGpuGetLimits
|
||||
|
@ -217,18 +248,20 @@ void lovrGraphicsMatrixTransform(mat4 transform);
|
|||
void lovrGraphicsSetProjection(mat4 projection);
|
||||
|
||||
// Rendering
|
||||
float* lovrGraphicsGetVertexPointer(uint32_t count);
|
||||
uint16_t* lovrGraphicsGetIndexPointer(uint32_t count);
|
||||
void lovrGraphicsClear(Color* color, float* depth, int* stencil);
|
||||
void lovrGraphicsDiscard(bool color, bool depth, bool stencil);
|
||||
void lovrGraphicsBatch(BatchRequest* req);
|
||||
void lovrGraphicsFlush();
|
||||
void lovrGraphicsDraw(DrawRequest* draw);
|
||||
void lovrGraphicsPoints(uint32_t count);
|
||||
void lovrGraphicsLine(uint32_t count);
|
||||
void lovrGraphicsTriangle(DrawStyle style, Material* material, float points[9]);
|
||||
void lovrGraphicsFlushCanvas(Canvas* canvas);
|
||||
void lovrGraphicsFlushShader(Shader* shader);
|
||||
void lovrGraphicsFlushMaterial(Material* material);
|
||||
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 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 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);
|
||||
|
@ -238,14 +271,37 @@ void lovrGraphicsFill(Texture* texture, float u, float v, float w, float h);
|
|||
#define lovrGraphicsStencil lovrGpuStencil
|
||||
#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 {
|
||||
Mesh* mesh;
|
||||
Shader* shader;
|
||||
Canvas* canvas;
|
||||
Shader* shader;
|
||||
Pipeline pipeline;
|
||||
DrawMode drawMode;
|
||||
uint32_t instances;
|
||||
uint32_t rangeStart;
|
||||
uint32_t rangeCount;
|
||||
uint32_t width : 15;
|
||||
uint32_t height : 15;
|
||||
bool stereo : 1;
|
||||
|
@ -256,10 +312,13 @@ void lovrGpuDestroy();
|
|||
void lovrGpuClear(Canvas* canvas, Color* color, float* depth, int* stencil);
|
||||
void lovrGpuCompute(Shader* shader, int x, int y, int z);
|
||||
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 lovrGpuPresent();
|
||||
void lovrGpuDirtyTexture();
|
||||
void* lovrGpuLock();
|
||||
void lovrGpuUnlock(void* lock);
|
||||
void lovrGpuDestroyLock(void* lock);
|
||||
const GpuFeatures* lovrGpuGetSupported();
|
||||
const GpuLimits* lovrGpuGetLimits();
|
||||
const GpuStats* lovrGpuGetStats();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "graphics/material.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "resources/shaders.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -41,12 +42,6 @@ void lovrMaterialBind(Material* material, Shader* shader) {
|
|||
}
|
||||
|
||||
lovrShaderSetMatrices(shader, "lovrMaterialTransform", material->transform, 0, 9);
|
||||
|
||||
material->dirty = false;
|
||||
}
|
||||
|
||||
bool lovrMaterialIsDirty(Material* material) {
|
||||
return material->dirty;
|
||||
}
|
||||
|
||||
float lovrMaterialGetScalar(Material* material, MaterialScalar scalarType) {
|
||||
|
@ -55,8 +50,8 @@ float lovrMaterialGetScalar(Material* material, MaterialScalar scalarType) {
|
|||
|
||||
void lovrMaterialSetScalar(Material* material, MaterialScalar scalarType, float value) {
|
||||
if (material->scalars[scalarType] != value) {
|
||||
lovrGraphicsFlushMaterial(material);
|
||||
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) {
|
||||
if (memcmp(&material->colors[colorType], &color, 4 * sizeof(float))) {
|
||||
lovrGraphicsFlushMaterial(material);
|
||||
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) {
|
||||
if (material->textures[textureType] != texture) {
|
||||
lovrGraphicsFlushMaterial(material);
|
||||
lovrRetain(texture);
|
||||
lovrRelease(material->textures[textureType]);
|
||||
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) {
|
||||
lovrGraphicsFlushMaterial(material);
|
||||
float c = cos(angle);
|
||||
float s = sin(angle);
|
||||
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[7] = oy;
|
||||
material->transform[8] = 1;
|
||||
material->dirty = true;
|
||||
}
|
||||
|
|
|
@ -34,14 +34,12 @@ typedef struct {
|
|||
Color colors[MAX_MATERIAL_COLORS];
|
||||
Texture* textures[MAX_MATERIAL_TEXTURES];
|
||||
float transform[9];
|
||||
bool dirty;
|
||||
} Material;
|
||||
|
||||
Material* lovrMaterialInit(Material* material);
|
||||
#define lovrMaterialCreate() lovrMaterialInit(lovrAlloc(Material))
|
||||
void lovrMaterialDestroy(void* ref);
|
||||
void lovrMaterialBind(Material* material, Shader* shader);
|
||||
bool lovrMaterialIsDirty(Material* material);
|
||||
float lovrMaterialGetScalar(Material* material, MaterialScalar scalarType);
|
||||
void lovrMaterialSetScalar(Material* material, MaterialScalar scalarType, float value);
|
||||
Color lovrMaterialGetColor(Material* material, MaterialColor colorType);
|
||||
|
|
|
@ -1,8 +1,50 @@
|
|||
#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) {
|
||||
lovrAssert(!map_get(&mesh->attributes, name), "Mesh already has an attribute named '%s'", name);
|
||||
lovrAssert(attribute->divisor >= 0, "Divisor can't be negative");
|
||||
lovrGraphicsFlushMesh(mesh);
|
||||
map_set(&mesh->attributes, name, *attribute);
|
||||
lovrRetain(attribute->buffer);
|
||||
}
|
||||
|
@ -10,7 +52,8 @@ void lovrMeshAttachAttribute(Mesh* mesh, const char* name, MeshAttribute* attrib
|
|||
void lovrMeshDetachAttribute(Mesh* mesh, const char* name) {
|
||||
MeshAttribute* attribute = map_get(&mesh->attributes, 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);
|
||||
map_remove(&mesh->attributes, name);
|
||||
}
|
||||
|
@ -19,26 +62,6 @@ MeshAttribute* lovrMeshGetAttribute(Mesh* mesh, const char* 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) {
|
||||
MeshAttribute* attribute = map_get(&mesh->attributes, 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) {
|
||||
MeshAttribute* attribute = map_get(&mesh->attributes, 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) {
|
||||
*start = mesh->rangeStart;
|
||||
*count = mesh->rangeCount;
|
||||
*start = mesh->drawStart;
|
||||
*count = mesh->drawCount;
|
||||
}
|
||||
|
||||
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);
|
||||
mesh->rangeStart = start;
|
||||
mesh->rangeCount = count;
|
||||
mesh->drawStart = start;
|
||||
mesh->drawCount = count;
|
||||
}
|
||||
|
||||
Material* lovrMeshGetMaterial(Mesh* mesh) {
|
||||
|
@ -72,38 +106,3 @@ void lovrMeshSetMaterial(Mesh* mesh, Material* material) {
|
|||
lovrRelease(mesh->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 {
|
||||
Ref ref;
|
||||
uint32_t count;
|
||||
DrawMode mode;
|
||||
VertexFormat format;
|
||||
bool readable;
|
||||
BufferUsage usage;
|
||||
Buffer* vbo;
|
||||
Buffer* ibo;
|
||||
Buffer* vertexBuffer;
|
||||
Buffer* indexBuffer;
|
||||
uint32_t vertexCount;
|
||||
uint32_t indexCount;
|
||||
size_t indexSize;
|
||||
size_t indexCapacity;
|
||||
uint32_t rangeStart;
|
||||
uint32_t rangeCount;
|
||||
size_t flushStart;
|
||||
size_t flushEnd;
|
||||
uint32_t drawStart;
|
||||
uint32_t drawCount;
|
||||
Material* material;
|
||||
map_attribute_t attributes;
|
||||
MeshAttribute layout[MAX_ATTRIBUTES];
|
||||
GPU_MESH_FIELDS
|
||||
} 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__)
|
||||
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 lovrMeshDetachAttribute(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);
|
||||
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 lovrMeshSetDrawRange(Mesh* mesh, uint32_t start, uint32_t count);
|
||||
Material* lovrMeshGetMaterial(Mesh* mesh);
|
||||
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]);
|
||||
}
|
||||
|
||||
lovrMeshSetDrawRange(model->mesh, primitive->drawStart, primitive->drawCount);
|
||||
lovrGraphicsDraw(&(DrawRequest) {
|
||||
lovrGraphicsBatch(&(BatchRequest) {
|
||||
.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],
|
||||
.mesh = model->mesh,
|
||||
.material = lovrMeshGetMaterial(model->mesh),
|
||||
.instances = instances,
|
||||
.pose = (float*) model->pose
|
||||
.material = lovrMeshGetMaterial(model->mesh)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -59,14 +64,26 @@ Model* lovrModelInit(Model* model, ModelData* modelData) {
|
|||
model->modelData = modelData;
|
||||
model->aabbDirty = true;
|
||||
|
||||
model->mesh = lovrMeshCreate(modelData->vertexData->count, modelData->vertexData->format, DRAW_TRIANGLES, USAGE_STATIC, false);
|
||||
void* vertices = lovrMeshMapVertices(model->mesh, 0);
|
||||
memcpy(vertices, modelData->vertexData->blob.data, modelData->vertexData->count * modelData->vertexData->format.stride);
|
||||
lovrMeshFlushVertices(model->mesh, 0, modelData->vertexData->count * modelData->vertexData->format.stride);
|
||||
VertexFormat* format = &modelData->vertexData->format;
|
||||
size_t vboSize = modelData->vertexData->count * format->stride;
|
||||
Buffer* vertexBuffer = lovrBufferCreate(vboSize, modelData->vertexData->blob.data, BUFFER_VERTEX, USAGE_STATIC, false);
|
||||
model->mesh = lovrMeshCreate(DRAW_TRIANGLES, *format, vertexBuffer);
|
||||
lovrRelease(vertexBuffer);
|
||||
|
||||
void* indices = lovrMeshMapIndices(model->mesh, modelData->indexCount, modelData->indexSize, 0);
|
||||
memcpy(indices, modelData->indices.raw, modelData->indexCount * modelData->indexSize);
|
||||
lovrMeshFlushIndices(model->mesh);
|
||||
size_t indexSize = modelData->indexSize;
|
||||
uint32_t indexCount = modelData->indexCount;
|
||||
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) {
|
||||
model->textures = calloc(modelData->textures.length, sizeof(Texture*));
|
||||
|
@ -178,7 +195,6 @@ void lovrModelDraw(Model* model, mat4 transform, int instances) {
|
|||
lovrGraphicsMatrixTransform(transform);
|
||||
renderNode(model, 0, instances);
|
||||
lovrGraphicsPop();
|
||||
lovrGraphicsFlush();
|
||||
}
|
||||
|
||||
Animator* lovrModelGetAnimator(Model* model) {
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#define LOVR_SHADER_TANGENT 4
|
||||
#define LOVR_SHADER_BONES 5
|
||||
#define LOVR_SHADER_BONE_WEIGHTS 6
|
||||
#define LOVR_SHADER_DRAW_ID 7
|
||||
|
||||
typedef enum {
|
||||
BARRIER_BLOCK,
|
||||
|
@ -38,9 +39,16 @@ typedef enum {
|
|||
MAX_BARRIERS
|
||||
} Barrier;
|
||||
|
||||
typedef struct {
|
||||
uint32_t buffer;
|
||||
size_t offset;
|
||||
size_t size;
|
||||
} BlockBuffer;
|
||||
|
||||
static struct {
|
||||
Texture* defaultTexture;
|
||||
bool alphaToCoverage;
|
||||
bool blendEnabled;
|
||||
BlendMode blendMode;
|
||||
BlendAlphaMode blendAlphaMode;
|
||||
bool culling;
|
||||
|
@ -55,15 +63,13 @@ static struct {
|
|||
Winding winding;
|
||||
bool wireframe;
|
||||
uint32_t framebuffer;
|
||||
uint32_t indexBuffer;
|
||||
uint32_t program;
|
||||
uint32_t vertexArray;
|
||||
uint32_t buffers[MAX_BUFFER_TYPES];
|
||||
BlockBuffer blockBuffers[2][MAX_BLOCK_BUFFERS];
|
||||
int activeTexture;
|
||||
Texture* textures[MAX_TEXTURES];
|
||||
Image images[MAX_IMAGES];
|
||||
uint32_t blockBuffers[2][MAX_BLOCK_BUFFERS];
|
||||
uint32_t vertexArray;
|
||||
uint32_t vertexBuffer;
|
||||
uint32_t genericBuffer;
|
||||
float viewports[2][4];
|
||||
vec_void_t incoherents[MAX_BARRIERS];
|
||||
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) {
|
||||
switch (usage) {
|
||||
case USAGE_STATIC: return GL_STATIC_DRAW;
|
||||
|
@ -308,8 +325,8 @@ static void lovrGpuSync(uint8_t flags) {
|
|||
|
||||
if (i == BARRIER_BLOCK) {
|
||||
for (int j = 0; j < state.incoherents[i].length; j++) {
|
||||
ShaderBlock* block = state.incoherents[i].data[j];
|
||||
block->incoherent &= ~(1 << i);
|
||||
Buffer* buffer = state.incoherents[i].data[j];
|
||||
buffer->incoherent &= ~(1 << i);
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
if (state.indexBuffer != indexBuffer) {
|
||||
state.indexBuffer = indexBuffer;
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
|
||||
static void lovrGpuUseProgram(uint32_t program) {
|
||||
if (state.program != program) {
|
||||
state.program = program;
|
||||
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
|
||||
|
||||
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) {
|
||||
const char* key;
|
||||
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));
|
||||
|
||||
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) {
|
||||
|
@ -501,7 +516,7 @@ static void lovrGpuBindMesh(Mesh* mesh, Shader* shader, int divisorMultiplier) {
|
|||
previous.stride != current.stride;
|
||||
|
||||
if (changed) {
|
||||
lovrGpuBindVertexBuffer(current.buffer->id);
|
||||
lovrGpuBindBuffer(BUFFER_VERTEX, current.buffer->id);
|
||||
int count = current.components;
|
||||
int stride = current.stride;
|
||||
GLvoid* offset = (GLvoid*) current.offset;
|
||||
|
@ -604,51 +619,60 @@ static void lovrGpuBindPipeline(Pipeline* pipeline) {
|
|||
state.blendMode = pipeline->blendMode;
|
||||
state.blendAlphaMode = pipeline->blendAlphaMode;
|
||||
|
||||
GLenum srcRGB = state.blendMode == BLEND_MULTIPLY ? GL_DST_COLOR : GL_ONE;
|
||||
if (srcRGB == GL_ONE && state.blendAlphaMode == BLEND_ALPHA_MULTIPLY) {
|
||||
srcRGB = GL_SRC_ALPHA;
|
||||
}
|
||||
if (state.blendMode == BLEND_NONE) {
|
||||
if (state.blendEnabled) {
|
||||
state.blendEnabled = false;
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
} else {
|
||||
if (!state.blendEnabled) {
|
||||
state.blendEnabled = true;
|
||||
glEnable(GL_BLEND);
|
||||
}
|
||||
|
||||
switch (state.blendMode) {
|
||||
case BLEND_ALPHA:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
break;
|
||||
GLenum srcRGB = state.blendMode == BLEND_MULTIPLY ? GL_DST_COLOR : GL_ONE;
|
||||
if (srcRGB == GL_ONE && state.blendAlphaMode == BLEND_ALPHA_MULTIPLY) {
|
||||
srcRGB = GL_SRC_ALPHA;
|
||||
}
|
||||
|
||||
case BLEND_ADD:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE, GL_ZERO, GL_ONE);
|
||||
break;
|
||||
switch (state.blendMode) {
|
||||
case BLEND_ALPHA:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
break;
|
||||
|
||||
case BLEND_SUBTRACT:
|
||||
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE, GL_ZERO, GL_ONE);
|
||||
break;
|
||||
case BLEND_ADD:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE, GL_ZERO, GL_ONE);
|
||||
break;
|
||||
|
||||
case BLEND_MULTIPLY:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_DST_COLOR, GL_ZERO);
|
||||
break;
|
||||
case BLEND_SUBTRACT:
|
||||
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE, GL_ZERO, GL_ONE);
|
||||
break;
|
||||
|
||||
case BLEND_LIGHTEN:
|
||||
glBlendEquation(GL_MAX);
|
||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
||||
break;
|
||||
case BLEND_MULTIPLY:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_DST_COLOR, GL_ZERO);
|
||||
break;
|
||||
|
||||
case BLEND_DARKEN:
|
||||
glBlendEquation(GL_MIN);
|
||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
||||
break;
|
||||
case BLEND_LIGHTEN:
|
||||
glBlendEquation(GL_MAX);
|
||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
||||
break;
|
||||
|
||||
case BLEND_SCREEN:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE_MINUS_SRC_COLOR);
|
||||
break;
|
||||
case BLEND_DARKEN:
|
||||
glBlendEquation(GL_MIN);
|
||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
||||
break;
|
||||
|
||||
case BLEND_REPLACE:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ZERO, GL_ONE, GL_ZERO);
|
||||
break;
|
||||
case BLEND_SCREEN:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(srcRGB, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE_MINUS_SRC_COLOR);
|
||||
break;
|
||||
|
||||
case BLEND_NONE: lovrThrow("Unreachable"); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -678,8 +702,8 @@ static void lovrGpuBindPipeline(Pipeline* pipeline) {
|
|||
}
|
||||
|
||||
// Depth write
|
||||
if (state.depthWrite != pipeline->depthWrite) {
|
||||
state.depthWrite = pipeline->depthWrite;
|
||||
if (state.depthWrite != (pipeline->depthWrite && !state.stencilWriting)) {
|
||||
state.depthWrite = pipeline->depthWrite && !state.stencilWriting;
|
||||
glDepthMask(state.depthWrite);
|
||||
}
|
||||
|
||||
|
@ -848,14 +872,14 @@ static void lovrGpuBindShader(Shader* shader) {
|
|||
for (BlockType type = BLOCK_UNIFORM; type <= BLOCK_STORAGE; type++) {
|
||||
vec_foreach_ptr(&shader->blocks[type], block, i) {
|
||||
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
|
||||
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);
|
||||
lovrGpuBindBlockBuffer(type, block->source->id, block->slot, block->offset, block->size);
|
||||
} 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_SAMPLES, &state.limits.textureMSAA);
|
||||
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);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
state.srgb = srgb;
|
||||
|
||||
state.alphaToCoverage = false;
|
||||
glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
|
||||
|
||||
state.blendEnabled = true;
|
||||
state.blendMode = BLEND_ALPHA;
|
||||
state.blendAlphaMode = BLEND_ALPHA_MULTIPLY;
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
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
|
||||
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");
|
||||
lovrGraphicsFlush();
|
||||
lovrGpuBindShader(shader);
|
||||
glDispatchCompute(x, y, z);
|
||||
#endif
|
||||
|
@ -1021,52 +1048,45 @@ void lovrGpuDiscard(Canvas* canvas, bool color, bool depth, bool stencil) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void lovrGpuDraw(DrawCommand* commands, int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
DrawCommand* draw = &commands[i];
|
||||
void lovrGpuDraw(DrawCommand* draw) {
|
||||
int viewCount = 1 + draw->stereo;
|
||||
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;
|
||||
int drawCount = state.features.singlepass ? 1 : viewCount;
|
||||
int viewsPerDraw = state.features.singlepass ? viewCount : 1;
|
||||
int instances = draw->instances * viewsPerDraw;
|
||||
float w = draw->width / (float) viewCount;
|
||||
float h = draw->height;
|
||||
float viewports[2][4] = { { 0, 0, w, h }, { w, 0, w, h } };
|
||||
lovrShaderSetInts(draw->shader, "lovrViewportCount", &viewCount, 0, 1);
|
||||
|
||||
float w = draw->width / (float) viewCount;
|
||||
float h = draw->height;
|
||||
float viewports[2][4] = { { 0, 0, w, h }, { w, 0, w, h } };
|
||||
lovrShaderSetInts(draw->shader, "lovrViewportCount", &viewCount, 0, 1);
|
||||
lovrGpuBindCanvas(draw->canvas, true);
|
||||
lovrGpuBindPipeline(&draw->pipeline);
|
||||
lovrGpuBindMesh(draw->mesh, draw->shader, viewsPerDraw);
|
||||
|
||||
lovrGpuBindMesh(draw->mesh, draw->shader, viewsPerDraw);
|
||||
lovrGpuBindCanvas(draw->canvas, true);
|
||||
lovrGpuBindPipeline(&draw->pipeline);
|
||||
for (int i = 0; i < drawCount; i++) {
|
||||
lovrGpuSetViewports(&viewports[i][0], viewsPerDraw);
|
||||
lovrShaderSetInts(draw->shader, "lovrViewportIndex", &i, 0, 1);
|
||||
lovrGpuBindShader(draw->shader);
|
||||
|
||||
for (int i = 0; i < drawCount; i++) {
|
||||
lovrGpuSetViewports(&viewports[i][0], viewsPerDraw);
|
||||
lovrShaderSetInts(draw->shader, "lovrViewportIndex", &i, 0, 1);
|
||||
lovrGpuBindShader(draw->shader);
|
||||
|
||||
Mesh* mesh = draw->mesh;
|
||||
GLenum mode = convertDrawMode(mesh->mode);
|
||||
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);
|
||||
}
|
||||
Mesh* mesh = draw->mesh;
|
||||
GLenum mode = convertDrawMode(draw->drawMode);
|
||||
if (mesh->indexCount > 0) {
|
||||
GLenum indexType = mesh->indexSize == sizeof(uint16_t) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
|
||||
GLvoid* offset = (GLvoid*) (draw->rangeStart * mesh->indexSize);
|
||||
if (instances > 1) {
|
||||
glDrawElementsInstanced(mode, draw->rangeCount, indexType, offset, instances);
|
||||
} else {
|
||||
size_t start = mesh->rangeStart;
|
||||
size_t count = mesh->rangeCount ? mesh->rangeCount : mesh->count;
|
||||
if (instances > 1) {
|
||||
glDrawArraysInstanced(mode, start, count, instances);
|
||||
} else {
|
||||
glDrawArrays(mode, start, count);
|
||||
}
|
||||
glDrawElements(mode, draw->rangeCount, indexType, offset);
|
||||
}
|
||||
} else {
|
||||
if (instances > 1) {
|
||||
glDrawArraysInstanced(mode, draw->rangeStart, draw->rangeCount, instances);
|
||||
} 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) {
|
||||
state.depthWrite = false;
|
||||
lovrGraphicsFlush();
|
||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||
|
||||
if (!state.stencilEnabled) {
|
||||
|
@ -1102,6 +1122,7 @@ void lovrGpuStencil(StencilAction action, int replaceValue, StencilCallback call
|
|||
|
||||
state.stencilWriting = true;
|
||||
callback(userdata);
|
||||
lovrGraphicsFlush();
|
||||
state.stencilWriting = false;
|
||||
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
|
@ -1112,6 +1133,24 @@ void lovrGpuDirtyTexture() {
|
|||
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() {
|
||||
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) {
|
||||
lovrGraphicsFlush();
|
||||
lovrAssert(texture->allocated, "Texture is not allocated");
|
||||
|
||||
#ifndef EMSCRIPTEN
|
||||
|
@ -1308,6 +1348,7 @@ void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, int x,
|
|||
}
|
||||
|
||||
void lovrTextureSetFilter(Texture* texture, TextureFilter filter) {
|
||||
lovrGraphicsFlush();
|
||||
float anisotropy = filter.mode == FILTER_ANISOTROPIC ? MAX(filter.anisotropy, 1.) : 1.;
|
||||
lovrGpuBindTexture(texture, 0);
|
||||
texture->filter = filter;
|
||||
|
@ -1344,6 +1385,7 @@ void lovrTextureSetFilter(Texture* texture, TextureFilter filter) {
|
|||
}
|
||||
|
||||
void lovrTextureSetWrap(Texture* texture, TextureWrap wrap) {
|
||||
lovrGraphicsFlush();
|
||||
texture->wrap = wrap;
|
||||
lovrGpuBindTexture(texture, 0);
|
||||
glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, convertWrapMode(wrap.s));
|
||||
|
@ -1416,7 +1458,7 @@ void lovrCanvasResolve(Canvas* canvas) {
|
|||
return;
|
||||
}
|
||||
|
||||
lovrGraphicsFlush();
|
||||
lovrGraphicsFlushCanvas(canvas);
|
||||
|
||||
if (canvas->flags.msaa) {
|
||||
int w = canvas->width;
|
||||
|
@ -1454,6 +1496,7 @@ void lovrCanvasResolve(Canvas* canvas) {
|
|||
}
|
||||
|
||||
TextureData* lovrCanvasNewTextureData(Canvas* canvas, int index) {
|
||||
lovrGraphicsFlushCanvas(canvas);
|
||||
lovrGpuBindCanvas(canvas, false);
|
||||
|
||||
#ifndef EMSCRIPTEN
|
||||
|
@ -1479,21 +1522,24 @@ TextureData* lovrCanvasNewTextureData(Canvas* canvas, int index) {
|
|||
|
||||
// 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->readable = readable;
|
||||
buffer->type = type;
|
||||
buffer->usage = usage;
|
||||
glGenBuffers(1, &buffer->id);
|
||||
lovrGpuBindGenericBuffer(buffer->id);
|
||||
lovrGpuBindBuffer(type, buffer->id);
|
||||
GLenum glType = convertBufferType(type);
|
||||
|
||||
#ifndef EMSCRIPTEN
|
||||
if (GLAD_GL_ARB_buffer_storage) {
|
||||
GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (readable ? GL_MAP_READ_BIT : 0);
|
||||
glBufferStorage(GL_COPY_WRITE_BUFFER, size, data, flags);
|
||||
buffer->data = glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, size, flags | GL_MAP_FLUSH_EXPLICIT_BIT);
|
||||
glBufferStorage(glType, size, data, flags);
|
||||
buffer->data = glMapBufferRange(glType, 0, size, flags | GL_MAP_FLUSH_EXPLICIT_BIT);
|
||||
} else {
|
||||
#endif
|
||||
buffer->data = calloc(1, size);
|
||||
glBufferData(GL_COPY_WRITE_BUFFER, size, data, convertBufferUsage(usage));
|
||||
glBufferData(glType, size, data, convertBufferUsage(usage));
|
||||
|
||||
if (data) {
|
||||
memcpy(buffer->data, data, size);
|
||||
|
@ -1507,6 +1553,7 @@ Buffer* lovrBufferInit(Buffer* buffer, size_t size, void* data, BufferUsage usag
|
|||
|
||||
void lovrBufferDestroy(void* ref) {
|
||||
Buffer* buffer = ref;
|
||||
lovrGpuDestroySyncResource(buffer, buffer->incoherent);
|
||||
glDeleteBuffers(1, &buffer->id);
|
||||
#ifndef EMSCRIPTEN
|
||||
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) {
|
||||
lovrGpuBindGenericBuffer(buffer->id);
|
||||
lovrGpuBindBuffer(buffer->type, buffer->id);
|
||||
#ifndef EMSCRIPTEN
|
||||
if (GLAD_GL_ARB_buffer_storage) {
|
||||
glFlushMappedBufferRange(GL_COPY_WRITE_BUFFER, offset, size);
|
||||
glFlushMappedBufferRange(convertBufferType(buffer->type), offset, size);
|
||||
} else {
|
||||
#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
|
||||
}
|
||||
#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
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Uniforms in the block need to be in order of their offset, so find the right index for it
|
||||
int index = 0;
|
||||
while (index < block->uniforms.length && block->uniforms.data[index].offset < uniform.offset) {
|
||||
index++;
|
||||
}
|
||||
vec_insert(&block->uniforms, index, uniform);
|
||||
vec_push(&block->uniforms, uniform);
|
||||
continue;
|
||||
} else if (uniform.location == -1) {
|
||||
continue;
|
||||
|
@ -1740,7 +1755,7 @@ static void lovrShaderSetupUniforms(Shader* shader) {
|
|||
break;
|
||||
|
||||
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);
|
||||
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" :
|
||||
"#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
|
||||
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]));
|
||||
|
||||
// Fragment
|
||||
|
@ -1823,6 +1842,7 @@ Shader* lovrShaderInitGraphics(Shader* shader, const char* vertexSource, const c
|
|||
glBindAttribLocation(program, LOVR_SHADER_TANGENT, "lovrTangent");
|
||||
glBindAttribLocation(program, LOVR_SHADER_BONES, "lovrBones");
|
||||
glBindAttribLocation(program, LOVR_SHADER_BONE_WEIGHTS, "lovrBoneWeights");
|
||||
glBindAttribLocation(program, LOVR_SHADER_DRAW_ID, "lovrDrawID");
|
||||
linkProgram(program);
|
||||
glDetachShader(program, vertexShader);
|
||||
glDeleteShader(vertexShader);
|
||||
|
@ -1845,7 +1865,9 @@ Shader* lovrShaderInitGraphics(Shader* shader, const char* vertexSource, const c
|
|||
map_init(&shader->attributes);
|
||||
for (int i = 0; i < attributeCount; i++) {
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -1891,71 +1913,20 @@ void lovrShaderDestroy(void* ref) {
|
|||
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* lovrMeshInit(Mesh* mesh, uint32_t count, VertexFormat format, DrawMode mode, BufferUsage usage, bool readable) {
|
||||
mesh->count = count;
|
||||
Mesh* lovrMeshInit(Mesh* mesh, DrawMode mode, VertexFormat format, Buffer* vertexBuffer) {
|
||||
mesh->mode = mode;
|
||||
mesh->format = format;
|
||||
mesh->readable = readable;
|
||||
mesh->usage = usage;
|
||||
mesh->vbo = lovrBufferCreate(count * format.stride, NULL, usage, readable);
|
||||
mesh->vertexBuffer = vertexBuffer;
|
||||
mesh->vertexCount = vertexBuffer ? (lovrBufferGetSize(vertexBuffer) / format.stride) : 0;
|
||||
glGenVertexArrays(1, &mesh->vao);
|
||||
|
||||
map_init(&mesh->attributes);
|
||||
for (int i = 0; i < format.count; i++) {
|
||||
lovrRetain(mesh->vbo);
|
||||
lovrRetain(mesh->vertexBuffer);
|
||||
map_set(&mesh->attributes, format.attributes[i].name, ((MeshAttribute) {
|
||||
.buffer = mesh->vbo,
|
||||
.buffer = mesh->vertexBuffer,
|
||||
.offset = format.attributes[i].offset,
|
||||
.stride = format.stride,
|
||||
.type = format.attributes[i].type,
|
||||
|
@ -1970,7 +1941,6 @@ Mesh* lovrMeshInit(Mesh* mesh, uint32_t count, VertexFormat format, DrawMode mod
|
|||
|
||||
void lovrMeshDestroy(void* ref) {
|
||||
Mesh* mesh = ref;
|
||||
lovrRelease(mesh->material);
|
||||
glDeleteVertexArrays(1, &mesh->vao);
|
||||
const char* key;
|
||||
map_iter_t iter = map_iter(&mesh->attributes);
|
||||
|
@ -1979,6 +1949,7 @@ void lovrMeshDestroy(void* ref) {
|
|||
lovrRelease(attribute->buffer);
|
||||
}
|
||||
map_deinit(&mesh->attributes);
|
||||
lovrRelease(mesh->vbo);
|
||||
lovrRelease(mesh->ibo);
|
||||
lovrRelease(mesh->vertexBuffer);
|
||||
lovrRelease(mesh->indexBuffer);
|
||||
lovrRelease(mesh->material);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
|
||||
#define GPU_BUFFER_FIELDS \
|
||||
GLsync lock; \
|
||||
uint32_t id;
|
||||
uint32_t id; \
|
||||
uint8_t incoherent;
|
||||
|
||||
#define GPU_CANVAS_FIELDS \
|
||||
uint32_t framebuffer; \
|
||||
|
@ -20,15 +21,12 @@
|
|||
bool immortal;
|
||||
|
||||
#define GPU_MESH_FIELDS \
|
||||
uint32_t vao;
|
||||
uint32_t vao; \
|
||||
uint32_t ibo;
|
||||
|
||||
#define GPU_SHADER_FIELDS \
|
||||
uint32_t program;
|
||||
|
||||
#define GPU_SHADER_BLOCK_FIELDS \
|
||||
GLenum target; \
|
||||
uint8_t incoherent;
|
||||
|
||||
#define GPU_TEXTURE_FIELDS \
|
||||
GLuint id; \
|
||||
GLuint msaaId; \
|
||||
|
|
|
@ -96,17 +96,15 @@ static void lovrShaderSetUniform(Shader* shader, const char* name, UniformType t
|
|||
}
|
||||
|
||||
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((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;
|
||||
if (!uniform->dirty && !memcmp(dest, data, count * size)) {
|
||||
return;
|
||||
if (memcmp(dest, data, count * size)) {
|
||||
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) {
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
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);
|
||||
lovrAssert(id, "No shader block named '%s'", name);
|
||||
if (!id) return;
|
||||
|
||||
int type = *id & 1;
|
||||
int index = *id >> 1;
|
||||
UniformBlock* block = &shader->blocks[type].data[index];
|
||||
block->access = access;
|
||||
|
||||
if (source != block->source) {
|
||||
if (source) {
|
||||
lovrAssert(block->uniforms.length == source->uniforms.length, "ShaderBlock must have same number of uniforms as block definition in Shader");
|
||||
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);
|
||||
if (block->source != buffer || block->offset != offset || block->size != size) {
|
||||
lovrGraphicsFlushShader(shader);
|
||||
lovrRetain(buffer);
|
||||
lovrRelease(block->source);
|
||||
block->source = source;
|
||||
block->access = access;
|
||||
block->source = buffer;
|
||||
block->offset = offset;
|
||||
block->size = size;
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return block->type;
|
||||
}
|
||||
|
@ -225,4 +255,3 @@ const Uniform* lovrShaderBlockGetUniform(ShaderBlock* block, const char* name) {
|
|||
Buffer* lovrShaderBlockGetBuffer(ShaderBlock* block) {
|
||||
return block->buffer;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,14 +80,15 @@ typedef struct {
|
|||
vec_uniform_t uniforms;
|
||||
map_int_t uniformMap;
|
||||
Buffer* buffer;
|
||||
GPU_SHADER_BLOCK_FIELDS
|
||||
} ShaderBlock;
|
||||
|
||||
typedef struct {
|
||||
vec_uniform_t uniforms;
|
||||
int slot;
|
||||
ShaderBlock* source;
|
||||
UniformAccess access;
|
||||
Buffer* source;
|
||||
size_t offset;
|
||||
size_t size;
|
||||
int slot;
|
||||
} UniformBlock;
|
||||
|
||||
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 lovrShaderSetImages(Shader* shader, const char* name, Image* data, int start, int count);
|
||||
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* 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__)
|
||||
void lovrShaderBlockDestroy(void* ref);
|
||||
BlockType lovrShaderBlockGetType(ShaderBlock* block);
|
||||
|
|
|
@ -5,7 +5,7 @@ const char* lovrShaderVertexPrefix = ""
|
|||
"#define MAX_BONES 48 \n"
|
||||
"#define lovrView lovrViews[lovrViewportIndex] \n"
|
||||
"#define lovrProjection lovrProjections[lovrViewportIndex] \n"
|
||||
"#define lovrModel lovrModels[lovrDrawID] \n"
|
||||
"#define lovrModel lovrDraws[lovrDrawID].model \n"
|
||||
"#define lovrTransform (lovrView * lovrModel) \n"
|
||||
"#define lovrNormalMatrix mat3(transpose(inverse(lovrTransform))) \n"
|
||||
"#define lovrInstanceID (gl_InstanceID / lovrViewportCount) \n"
|
||||
|
@ -27,8 +27,10 @@ const char* lovrShaderVertexPrefix = ""
|
|||
"out vec4 vertexColor; \n"
|
||||
"out vec4 lovrColor; \n"
|
||||
"uniform lovrDrawData { \n"
|
||||
" mat4 lovrModels[192]; \n"
|
||||
" vec4 lovrColors[192]; \n"
|
||||
" struct { \n"
|
||||
" mat4 model; \n"
|
||||
" vec4 color; \n"
|
||||
" } lovrDraws[MAX_DRAWS]; \n"
|
||||
"}; \n"
|
||||
"uniform mat4 lovrViews[2]; \n"
|
||||
"uniform mat4 lovrProjections[2]; \n"
|
||||
|
@ -47,7 +49,7 @@ const char* lovrShaderVertexSuffix = ""
|
|||
"void main() { \n"
|
||||
" texCoord = (lovrMaterialTransform * vec3(lovrTexCoord, 1.)).xy; \n"
|
||||
" vertexColor = lovrVertexColor; \n"
|
||||
" lovrColor = lovrColors[lovrDrawID]; \n"
|
||||
" lovrColor = lovrDraws[lovrDrawID].color; \n"
|
||||
"#if SINGLEPASS \n"
|
||||
" gl_ViewportIndex = gl_InstanceID % lovrViewportCount; \n"
|
||||
"#endif \n"
|
||||
|
|
Loading…
Reference in New Issue