Compare commits

...

3 Commits

Author SHA1 Message Date
bjorn d9623a51a9 Pass:setFont; 2022-07-17 19:53:31 -07:00
bjorn 24504d1719 Adjust; 2022-07-17 16:38:29 -07:00
bjorn d17131c421 Pass:cone; 2022-07-17 16:38:00 -07:00
3 changed files with 214 additions and 129 deletions

View File

@ -239,6 +239,13 @@ static int l_lovrPassSetDepthClamp(lua_State* L) {
return 0;
}
static int l_lovrPassSetFont(lua_State* L) {
Pass* pass = luax_checktype(L, 1, Pass);
Font* font = luax_totype(L, 2, Font);
lovrPassSetFont(pass, font);
return 0;
}
static int l_lovrPassSetMaterial(lua_State* L) {
Pass* pass = luax_checktype(L, 1, Pass);
Material* material = luax_totype(L, 2, Material);
@ -559,6 +566,15 @@ static int l_lovrPassCylinder(lua_State* L) {
return 0;
}
static int l_lovrPassCone(lua_State* L) {
Pass* pass = luax_checktype(L, 1, Pass);
float transform[16];
int index = luax_readmat4(L, 2, transform, -2);
uint32_t segments = luax_optu32(L, index, 64);
lovrPassCone(pass, transform, segments);
return 0;
}
static int l_lovrPassCapsule(lua_State* L) {
Pass* pass = luax_checktype(L, 1, Pass);
float transform[16];
@ -580,17 +596,15 @@ static int l_lovrPassTorus(lua_State* L) {
static int l_lovrPassText(lua_State* L) {
Pass* pass = luax_checktype(L, 1, Pass);
Font* font = luax_totype(L, 2, Font);
int index = font ? 3 : 2;
uint32_t count;
ColoredString stack;
ColoredString* strings = luax_checkcoloredstrings(L, index++, &count, &stack);
ColoredString* strings = luax_checkcoloredstrings(L, 2, &count, &stack);
float transform[16];
index = luax_readmat4(L, index++, transform, 1);
int index = luax_readmat4(L, 3, transform, 1);
float wrap = luax_optfloat(L, index++, 0.);
HorizontalAlign halign = luax_checkenum(L, index++, HorizontalAlign, "center");
VerticalAlign valign = luax_checkenum(L, index++, VerticalAlign, "middle");
lovrPassText(pass, font, strings, count, transform, wrap, halign, valign);
lovrPassText(pass, strings, count, transform, wrap, halign, valign);
if (strings != &stack) free(strings);
return 0;
}
@ -937,6 +951,7 @@ const luaL_Reg lovrPass[] = {
{ "setDepthWrite", l_lovrPassSetDepthWrite },
{ "setDepthOffset", l_lovrPassSetDepthOffset },
{ "setDepthClamp", l_lovrPassSetDepthClamp },
{ "setFont", l_lovrPassSetFont },
{ "setMaterial", l_lovrPassSetMaterial },
{ "setMeshMode", l_lovrPassSetMeshMode },
{ "setSampler", l_lovrPassSetSampler },
@ -958,6 +973,7 @@ const luaL_Reg lovrPass[] = {
{ "circle", l_lovrPassCircle },
{ "sphere", l_lovrPassSphere },
{ "cylinder", l_lovrPassCylinder },
{ "cone", l_lovrPassCone },
{ "capsule", l_lovrPassCapsule },
{ "torus", l_lovrPassTorus },
{ "text", l_lovrPassText },

View File

@ -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;

View File

@ -591,6 +591,7 @@ void lovrPassSetDepthTest(Pass* pass, CompareMode test);
void lovrPassSetDepthWrite(Pass* pass, bool write);
void lovrPassSetDepthOffset(Pass* pass, float offset, float sloped);
void lovrPassSetDepthClamp(Pass* pass, bool clamp);
void lovrPassSetFont(Pass* pass, Font* font);
void lovrPassSetMaterial(Pass* pass, Material* material, Texture* texture);
void lovrPassSetMeshMode(Pass* pass, MeshMode mode);
void lovrPassSetSampler(Pass* pass, Sampler* sampler);
@ -612,9 +613,10 @@ void lovrPassBox(Pass* pass, float* transform, DrawStyle style);
void lovrPassCircle(Pass* pass, float* transform, DrawStyle style, float angle1, float angle2, uint32_t segments);
void lovrPassSphere(Pass* pass, float* transform, uint32_t segmentsH, uint32_t segmentsV);
void lovrPassCylinder(Pass* pass, float* transform, bool capped, float angle1, float angle2, uint32_t segments);
void lovrPassCone(Pass* pass, float* transform, uint32_t segments);
void lovrPassCapsule(Pass* pass, float* transform, uint32_t segments);
void lovrPassTorus(Pass* pass, float* transform, uint32_t segmentsT, uint32_t segmentsP);
void lovrPassText(Pass* pass, Font* font, ColoredString* strings, uint32_t count, float* transform, float wrap, HorizontalAlign halign, VerticalAlign valign);
void lovrPassText(Pass* pass, ColoredString* strings, uint32_t count, float* transform, float wrap, HorizontalAlign halign, VerticalAlign valign);
void lovrPassSkybox(Pass* pass, Texture* texture);
void lovrPassFill(Pass* pass, Texture* texture);
void lovrPassMonkey(Pass* pass, float* transform);