|
|
|
@ -242,7 +242,7 @@ typedef struct {
|
|
|
|
|
} Camera;
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
float color[4];
|
|
|
|
|
Font* font;
|
|
|
|
|
Shader* shader;
|
|
|
|
|
Sampler* sampler;
|
|
|
|
|
Material* material;
|
|
|
|
@ -251,6 +251,7 @@ typedef struct {
|
|
|
|
|
float viewport[4];
|
|
|
|
|
float depthRange[2];
|
|
|
|
|
uint32_t scissor[4];
|
|
|
|
|
float color[4];
|
|
|
|
|
MeshMode mode;
|
|
|
|
|
bool dirty;
|
|
|
|
|
} Pipeline;
|
|
|
|
@ -261,6 +262,7 @@ enum {
|
|
|
|
|
SHAPE_CIRCLE,
|
|
|
|
|
SHAPE_SPHERE,
|
|
|
|
|
SHAPE_CYLINDER,
|
|
|
|
|
SHAPE_CONE,
|
|
|
|
|
SHAPE_CAPSULE,
|
|
|
|
|
SHAPE_TORUS,
|
|
|
|
|
SHAPE_MONKEY
|
|
|
|
@ -1348,7 +1350,7 @@ ShaderSource lovrGraphicsCompileShader(ShaderStage stage, ShaderSource* source)
|
|
|
|
|
[STAGE_VERTEX] = ""
|
|
|
|
|
"void main() {"
|
|
|
|
|
"Color = PassColor * VertexColor;"
|
|
|
|
|
"Normal = normalize(NormalMatrix * VertexNormal);"
|
|
|
|
|
"Normal = NormalMatrix * VertexNormal;"
|
|
|
|
|
"UV = VertexUV;"
|
|
|
|
|
"Position = lovrmain();"
|
|
|
|
|
"}",
|
|
|
|
@ -2278,6 +2280,124 @@ void lovrFontGetLines(Font* font, ColoredString* strings, uint32_t count, float
|
|
|
|
|
tempPop(stack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void aline(GlyphVertex* vertices, uint32_t head, uint32_t tail, float width, HorizontalAlign align) {
|
|
|
|
|
if (align == ALIGN_LEFT) return;
|
|
|
|
|
float shift = align / 2.f * width;
|
|
|
|
|
for (uint32_t i = head; i < tail; i++) {
|
|
|
|
|
vertices[i].position.x -= shift;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void lovrFontGetVertices(Font* font, ColoredString* strings, uint32_t count, float wrap, HorizontalAlign halign, VerticalAlign valign, GlyphVertex* vertices, uint32_t* glyphCount, uint32_t* lineCount, Material** material, bool flip) {
|
|
|
|
|
uint32_t vertexCount = 0;
|
|
|
|
|
uint32_t lineStart = 0;
|
|
|
|
|
uint32_t wordStart = 0;
|
|
|
|
|
*glyphCount = 0;
|
|
|
|
|
*lineCount = 1;
|
|
|
|
|
|
|
|
|
|
float x = 0.f;
|
|
|
|
|
float y = 0.f;
|
|
|
|
|
float wordStartX = 0.f;
|
|
|
|
|
float prevWordEndX = 0.f;
|
|
|
|
|
float leading = lovrRasterizerGetLeading(font->info.rasterizer) * font->lineSpacing;
|
|
|
|
|
float space = lovrFontGetGlyph(font, ' ', NULL)->advance;
|
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
|
|
|
size_t bytes;
|
|
|
|
|
uint32_t codepoint;
|
|
|
|
|
uint32_t previous = '\0';
|
|
|
|
|
const char* str = strings[i].string;
|
|
|
|
|
const char* end = strings[i].string + strings[i].length;
|
|
|
|
|
uint8_t r = (uint8_t) (CLAMP(strings[i].color[0], 0.f, 1.f) * 255.f);
|
|
|
|
|
uint8_t g = (uint8_t) (CLAMP(strings[i].color[1], 0.f, 1.f) * 255.f);
|
|
|
|
|
uint8_t b = (uint8_t) (CLAMP(strings[i].color[2], 0.f, 1.f) * 255.f);
|
|
|
|
|
uint8_t a = (uint8_t) (CLAMP(strings[i].color[3], 0.f, 1.f) * 255.f);
|
|
|
|
|
|
|
|
|
|
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
|
|
|
|
if (codepoint == ' ' || codepoint == '\t') {
|
|
|
|
|
if (previous) prevWordEndX = x;
|
|
|
|
|
wordStart = vertexCount;
|
|
|
|
|
x += codepoint == '\t' ? space * 4.f : space;
|
|
|
|
|
wordStartX = x;
|
|
|
|
|
previous = '\0';
|
|
|
|
|
str += bytes;
|
|
|
|
|
continue;
|
|
|
|
|
} else if (codepoint == '\n') {
|
|
|
|
|
aline(vertices, lineStart, vertexCount, x, halign);
|
|
|
|
|
lineStart = vertexCount;
|
|
|
|
|
wordStart = vertexCount;
|
|
|
|
|
x = 0.f;
|
|
|
|
|
y -= leading;
|
|
|
|
|
wordStartX = 0.f;
|
|
|
|
|
prevWordEndX = 0.f;
|
|
|
|
|
(*lineCount)++;
|
|
|
|
|
previous = '\0';
|
|
|
|
|
str += bytes;
|
|
|
|
|
continue;
|
|
|
|
|
} else if (codepoint == '\r') {
|
|
|
|
|
str += bytes;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool resized;
|
|
|
|
|
Glyph* glyph = lovrFontGetGlyph(font, codepoint, &resized);
|
|
|
|
|
|
|
|
|
|
if (resized) {
|
|
|
|
|
lovrFontGetVertices(font, strings, count, wrap, halign, valign, vertices, glyphCount, lineCount, material, flip);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Keming
|
|
|
|
|
if (previous) x += lovrFontGetKerning(font, previous, codepoint);
|
|
|
|
|
previous = codepoint;
|
|
|
|
|
|
|
|
|
|
// Wrap
|
|
|
|
|
if (wrap > 0.f && x + glyph->advance > wrap && wordStart != lineStart) {
|
|
|
|
|
float dx = wordStartX;
|
|
|
|
|
float dy = leading;
|
|
|
|
|
|
|
|
|
|
// Shift the vertices of the overflowing word down a line and back to the beginning
|
|
|
|
|
for (uint32_t v = wordStart; v < vertexCount; v++) {
|
|
|
|
|
vertices[v].position.x -= dx;
|
|
|
|
|
vertices[v].position.y -= dy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
aline(vertices, lineStart, wordStart, prevWordEndX, halign);
|
|
|
|
|
lineStart = wordStart;
|
|
|
|
|
wordStartX = 0.f;
|
|
|
|
|
(*lineCount)++;
|
|
|
|
|
x -= dx;
|
|
|
|
|
y -= dy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Vertices
|
|
|
|
|
float* bb = glyph->box;
|
|
|
|
|
uint16_t* uv = glyph->uv;
|
|
|
|
|
if (flip) {
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[0], -(y + bb[1]) }, { uv[0], uv[3] }, { r, g, b, a } };
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[2], -(y + bb[1]) }, { uv[2], uv[3] }, { r, g, b, a } };
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[0], -(y + bb[3]) }, { uv[0], uv[1] }, { r, g, b, a } };
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[2], -(y + bb[3]) }, { uv[2], uv[1] }, { r, g, b, a } };
|
|
|
|
|
} else {
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[0], y + bb[3] }, { uv[0], uv[1] }, { r, g, b, a } };
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[2], y + bb[3] }, { uv[2], uv[1] }, { r, g, b, a } };
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[0], y + bb[1] }, { uv[0], uv[3] }, { r, g, b, a } };
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[2], y + bb[1] }, { uv[2], uv[3] }, { r, g, b, a } };
|
|
|
|
|
}
|
|
|
|
|
(*glyphCount)++;
|
|
|
|
|
|
|
|
|
|
// Advance
|
|
|
|
|
x += glyph->advance;
|
|
|
|
|
str += bytes;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Align last line
|
|
|
|
|
aline(vertices, lineStart, vertexCount, x, halign);
|
|
|
|
|
|
|
|
|
|
*material = font->material;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Model
|
|
|
|
|
|
|
|
|
|
Model* lovrModelCreate(const ModelInfo* info) {
|
|
|
|
@ -3171,6 +3291,7 @@ void lovrPassPush(Pass* pass, StackType stack) {
|
|
|
|
|
pass->pipeline = &pass->pipelines[++pass->pipelineIndex];
|
|
|
|
|
lovrCheck(pass->pipelineIndex < COUNTOF(pass->pipelines), "%s stack overflow (more pushes than pops?)", "Pipeline");
|
|
|
|
|
memcpy(pass->pipeline, &pass->pipelines[pass->pipelineIndex - 1], sizeof(Pipeline));
|
|
|
|
|
lovrRetain(pass->pipeline->font);
|
|
|
|
|
lovrRetain(pass->pipeline->sampler);
|
|
|
|
|
lovrRetain(pass->pipeline->shader);
|
|
|
|
|
lovrRetain(pass->pipeline->material);
|
|
|
|
@ -3186,6 +3307,7 @@ void lovrPassPop(Pass* pass, StackType stack) {
|
|
|
|
|
lovrCheck(pass->transformIndex < COUNTOF(pass->transforms), "%s stack underflow (more pops than pushes?)", "Transform");
|
|
|
|
|
break;
|
|
|
|
|
case STACK_PIPELINE:
|
|
|
|
|
lovrRelease(pass->pipeline->font, lovrFontDestroy);
|
|
|
|
|
lovrRelease(pass->pipeline->sampler, lovrSamplerDestroy);
|
|
|
|
|
lovrRelease(pass->pipeline->shader, lovrShaderDestroy);
|
|
|
|
|
lovrRelease(pass->pipeline->material, lovrMaterialDestroy);
|
|
|
|
@ -3344,6 +3466,14 @@ void lovrPassSetDepthClamp(Pass* pass, bool clamp) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void lovrPassSetFont(Pass* pass, Font* font) {
|
|
|
|
|
if (pass->pipeline->font != font) {
|
|
|
|
|
lovrRetain(font);
|
|
|
|
|
lovrRelease(pass->pipeline->font, lovrFontDestroy);
|
|
|
|
|
pass->pipeline->font = font;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void lovrPassSetMaterial(Pass* pass, Material* material, Texture* texture) {
|
|
|
|
|
if (texture) {
|
|
|
|
|
material = lovrTextureGetMaterial(texture);
|
|
|
|
@ -4324,6 +4454,59 @@ void lovrPassCylinder(Pass* pass, float* transform, bool capped, float angle1, f
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void lovrPassCone(Pass* pass, float* transform, uint32_t segments) {
|
|
|
|
|
uint32_t key[] = { SHAPE_CONE, segments };
|
|
|
|
|
uint32_t vertexCount = 2 * segments + 1;
|
|
|
|
|
uint32_t indexCount = 3 * (segments - 2) + 3 * segments;
|
|
|
|
|
ShapeVertex* vertices;
|
|
|
|
|
uint16_t* indices;
|
|
|
|
|
|
|
|
|
|
lovrPassDraw(pass, &(Draw) {
|
|
|
|
|
.hash = hash64(key, sizeof(key)),
|
|
|
|
|
.mode = MESH_TRIANGLES,
|
|
|
|
|
.transform = transform,
|
|
|
|
|
.vertex.pointer = (void**) &vertices,
|
|
|
|
|
.vertex.count = vertexCount,
|
|
|
|
|
.index.pointer = (void**) &indices,
|
|
|
|
|
.index.count = indexCount
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!vertices) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < segments; i++) {
|
|
|
|
|
float theta = i * 2.f * (float) M_PI / segments;
|
|
|
|
|
float x = cosf(theta);
|
|
|
|
|
float y = sinf(theta);
|
|
|
|
|
float rsqrt3 = .57735f;
|
|
|
|
|
float nx = cosf(theta) * rsqrt3;
|
|
|
|
|
float ny = sinf(theta) * rsqrt3;
|
|
|
|
|
float nz = -rsqrt3;
|
|
|
|
|
float u = x + .5f;
|
|
|
|
|
float v = .5f - y;
|
|
|
|
|
vertices[segments * 0] = (ShapeVertex) { { x, y, 0.f }, { 0.f, 0.f, 1.f }, { u, v } };
|
|
|
|
|
vertices[segments * 1] = (ShapeVertex) { { x, y, 0.f }, { nx, ny, nz }, { u, v } };
|
|
|
|
|
vertices++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vertices[segments] = (ShapeVertex) { { 0.f, 0.f, -1.f }, { 0.f, 0.f, 0.f }, { .5f, .5f } };
|
|
|
|
|
|
|
|
|
|
// Base
|
|
|
|
|
for (uint32_t i = 0; i < segments - 2; i++) {
|
|
|
|
|
uint16_t tri[] = { 0, i + 1, i + 2 };
|
|
|
|
|
memcpy(indices, tri, sizeof(tri));
|
|
|
|
|
indices += COUNTOF(tri);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sides
|
|
|
|
|
for (uint32_t i = 0; i < segments; i++) {
|
|
|
|
|
uint16_t tri[] = { segments + i, segments + (i + 1) % segments, vertexCount - 1 };
|
|
|
|
|
memcpy(indices, tri, sizeof(tri));
|
|
|
|
|
indices += COUNTOF(tri);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void lovrPassCapsule(Pass* pass, float* transform, uint32_t segments) {
|
|
|
|
|
float sx = vec3_length(transform + 0);
|
|
|
|
|
float sy = vec3_length(transform + 4);
|
|
|
|
@ -4349,7 +4532,7 @@ void lovrPassCapsule(Pass* pass, float* transform, uint32_t segments) {
|
|
|
|
|
.vertex.pointer = (void**) &vertices,
|
|
|
|
|
.vertex.count = vertexCount,
|
|
|
|
|
.index.pointer = (void**) &indices,
|
|
|
|
|
.index.count = indexCount,
|
|
|
|
|
.index.count = indexCount
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!vertices) {
|
|
|
|
@ -4473,126 +4656,8 @@ void lovrPassTorus(Pass* pass, float* transform, uint32_t segmentsT, uint32_t se
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void aline(GlyphVertex* vertices, uint32_t head, uint32_t tail, float width, HorizontalAlign align) {
|
|
|
|
|
if (align == ALIGN_LEFT) return;
|
|
|
|
|
float shift = align / 2.f * width;
|
|
|
|
|
for (uint32_t i = head; i < tail; i++) {
|
|
|
|
|
vertices[i].position.x -= shift;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void lovrFontGetVertices(Font* font, ColoredString* strings, uint32_t count, float wrap, HorizontalAlign halign, VerticalAlign valign, GlyphVertex* vertices, uint32_t* glyphCount, uint32_t* lineCount, Material** material, bool flip) {
|
|
|
|
|
uint32_t vertexCount = 0;
|
|
|
|
|
uint32_t lineStart = 0;
|
|
|
|
|
uint32_t wordStart = 0;
|
|
|
|
|
*glyphCount = 0;
|
|
|
|
|
*lineCount = 1;
|
|
|
|
|
|
|
|
|
|
float x = 0.f;
|
|
|
|
|
float y = 0.f;
|
|
|
|
|
float wordStartX = 0.f;
|
|
|
|
|
float prevWordEndX = 0.f;
|
|
|
|
|
float leading = lovrRasterizerGetLeading(font->info.rasterizer) * font->lineSpacing;
|
|
|
|
|
float space = lovrFontGetGlyph(font, ' ', NULL)->advance;
|
|
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
|
|
|
size_t bytes;
|
|
|
|
|
uint32_t codepoint;
|
|
|
|
|
uint32_t previous = '\0';
|
|
|
|
|
const char* str = strings[i].string;
|
|
|
|
|
const char* end = strings[i].string + strings[i].length;
|
|
|
|
|
uint8_t r = (uint8_t) (CLAMP(strings[i].color[0], 0.f, 1.f) * 255.f);
|
|
|
|
|
uint8_t g = (uint8_t) (CLAMP(strings[i].color[1], 0.f, 1.f) * 255.f);
|
|
|
|
|
uint8_t b = (uint8_t) (CLAMP(strings[i].color[2], 0.f, 1.f) * 255.f);
|
|
|
|
|
uint8_t a = (uint8_t) (CLAMP(strings[i].color[3], 0.f, 1.f) * 255.f);
|
|
|
|
|
|
|
|
|
|
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
|
|
|
|
if (codepoint == ' ' || codepoint == '\t') {
|
|
|
|
|
if (previous) prevWordEndX = x;
|
|
|
|
|
wordStart = vertexCount;
|
|
|
|
|
x += codepoint == '\t' ? space * 4.f : space;
|
|
|
|
|
wordStartX = x;
|
|
|
|
|
previous = '\0';
|
|
|
|
|
str += bytes;
|
|
|
|
|
continue;
|
|
|
|
|
} else if (codepoint == '\n') {
|
|
|
|
|
aline(vertices, lineStart, vertexCount, x, halign);
|
|
|
|
|
lineStart = vertexCount;
|
|
|
|
|
wordStart = vertexCount;
|
|
|
|
|
x = 0.f;
|
|
|
|
|
y -= leading;
|
|
|
|
|
wordStartX = 0.f;
|
|
|
|
|
prevWordEndX = 0.f;
|
|
|
|
|
(*lineCount)++;
|
|
|
|
|
previous = '\0';
|
|
|
|
|
str += bytes;
|
|
|
|
|
continue;
|
|
|
|
|
} else if (codepoint == '\r') {
|
|
|
|
|
str += bytes;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool resized;
|
|
|
|
|
Glyph* glyph = lovrFontGetGlyph(font, codepoint, &resized);
|
|
|
|
|
|
|
|
|
|
if (resized) {
|
|
|
|
|
lovrFontGetVertices(font, strings, count, wrap, halign, valign, vertices, glyphCount, lineCount, material, flip);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Keming
|
|
|
|
|
if (previous) x += lovrFontGetKerning(font, previous, codepoint);
|
|
|
|
|
previous = codepoint;
|
|
|
|
|
|
|
|
|
|
// Wrap
|
|
|
|
|
if (wrap > 0.f && x + glyph->advance > wrap && wordStart != lineStart) {
|
|
|
|
|
float dx = wordStartX;
|
|
|
|
|
float dy = leading;
|
|
|
|
|
|
|
|
|
|
// Shift the vertices of the overflowing word down a line and back to the beginning
|
|
|
|
|
for (uint32_t v = wordStart; v < vertexCount; v++) {
|
|
|
|
|
vertices[v].position.x -= dx;
|
|
|
|
|
vertices[v].position.y -= dy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
aline(vertices, lineStart, wordStart, prevWordEndX, halign);
|
|
|
|
|
lineStart = wordStart;
|
|
|
|
|
wordStartX = 0.f;
|
|
|
|
|
(*lineCount)++;
|
|
|
|
|
x -= dx;
|
|
|
|
|
y -= dy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Vertices
|
|
|
|
|
float* bb = glyph->box;
|
|
|
|
|
uint16_t* uv = glyph->uv;
|
|
|
|
|
if (flip) {
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[0], -(y + bb[1]) }, { uv[0], uv[3] }, { r, g, b, a } };
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[2], -(y + bb[1]) }, { uv[2], uv[3] }, { r, g, b, a } };
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[0], -(y + bb[3]) }, { uv[0], uv[1] }, { r, g, b, a } };
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[2], -(y + bb[3]) }, { uv[2], uv[1] }, { r, g, b, a } };
|
|
|
|
|
} else {
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[0], y + bb[3] }, { uv[0], uv[1] }, { r, g, b, a } };
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[2], y + bb[3] }, { uv[2], uv[1] }, { r, g, b, a } };
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[0], y + bb[1] }, { uv[0], uv[3] }, { r, g, b, a } };
|
|
|
|
|
vertices[vertexCount++] = (GlyphVertex) { { x + bb[2], y + bb[1] }, { uv[2], uv[3] }, { r, g, b, a } };
|
|
|
|
|
}
|
|
|
|
|
(*glyphCount)++;
|
|
|
|
|
|
|
|
|
|
// Advance
|
|
|
|
|
x += glyph->advance;
|
|
|
|
|
str += bytes;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Align last line
|
|
|
|
|
aline(vertices, lineStart, vertexCount, x, halign);
|
|
|
|
|
|
|
|
|
|
*material = font->material;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void lovrPassText(Pass* pass, Font* font, ColoredString* strings, uint32_t count, float* transform, float wrap, HorizontalAlign halign, VerticalAlign valign) {
|
|
|
|
|
font = font ? font : lovrGraphicsGetDefaultFont();
|
|
|
|
|
void lovrPassText(Pass* pass, ColoredString* strings, uint32_t count, float* transform, float wrap, HorizontalAlign halign, VerticalAlign valign) {
|
|
|
|
|
Font* font = pass->pipeline->font ? pass->pipeline->font : lovrGraphicsGetDefaultFont();
|
|
|
|
|
|
|
|
|
|
size_t totalLength = 0;
|
|
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
|
|
@ -5120,9 +5185,11 @@ static void cleanupPasses(void) {
|
|
|
|
|
|
|
|
|
|
if (pass->info.type == PASS_RENDER) {
|
|
|
|
|
for (size_t j = 0; j <= pass->pipelineIndex; j++) {
|
|
|
|
|
lovrRelease(pass->pipelines[j].font, lovrFontDestroy);
|
|
|
|
|
lovrRelease(pass->pipelines[j].sampler, lovrSamplerDestroy);
|
|
|
|
|
lovrRelease(pass->pipelines[j].shader, lovrShaderDestroy);
|
|
|
|
|
lovrRelease(pass->pipelines[j].material, lovrMaterialDestroy);
|
|
|
|
|
pass->pipelines[j].font = NULL;
|
|
|
|
|
pass->pipelines[j].sampler = NULL;
|
|
|
|
|
pass->pipelines[j].shader = NULL;
|
|
|
|
|
pass->pipelines[j].material = NULL;
|
|
|
|
|