mirror of https://github.com/bjornbytes/lovr.git
Compare commits
11 Commits
72dd7ee0f2
...
a0cd36a77b
Author | SHA1 | Date |
---|---|---|
bjorn | a0cd36a77b | |
bjorn | 0a251495bc | |
bjorn | 698977c5be | |
bjorn | e8ebb17796 | |
bjorn | cfa5613db4 | |
bjorn | f23ae4009f | |
bjorn | dacd17066d | |
bjorn | 4e8fe82f94 | |
bjorn | 889b1d8271 | |
bjorn | f89b1811aa | |
bjorn | f7d7281e70 |
|
@ -106,6 +106,8 @@ StringEntry lovrFieldType[] = {
|
|||
[FIELD_MAT2] = ENTRY("mat2"),
|
||||
[FIELD_MAT3] = ENTRY("mat3"),
|
||||
[FIELD_MAT4] = ENTRY("mat4"),
|
||||
[FIELD_INDEX16] = ENTRY("index16"),
|
||||
[FIELD_INDEX32] = ENTRY("index32"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
@ -245,7 +247,9 @@ static struct { uint32_t size, scalarAlign, baseAlign, components; } fieldInfo[]
|
|||
[FIELD_F32x4] = { 16, 4, 16, 4 },
|
||||
[FIELD_MAT2] = { 16, 4, 8, 4 },
|
||||
[FIELD_MAT3] = { 64, 4, 16, 9 },
|
||||
[FIELD_MAT4] = { 64, 4, 16, 16 }
|
||||
[FIELD_MAT4] = { 64, 4, 16, 16 },
|
||||
[FIELD_INDEX16] = { 2, 2, 2, 1 },
|
||||
[FIELD_INDEX32] = { 4, 4, 4, 1 }
|
||||
};
|
||||
|
||||
static uint32_t luax_checkfieldtype(lua_State* L, int index, uint32_t* nameHash) {
|
||||
|
@ -296,6 +300,10 @@ static uint32_t luax_checkfieldtype(lua_State* L, int index, uint32_t* nameHash)
|
|||
return FIELD_UN8x4;
|
||||
}
|
||||
|
||||
if (length == 6 && !memcmp(string, "index", length)) {
|
||||
return FIELD_INDEX32;
|
||||
}
|
||||
|
||||
for (int i = 0; lovrFieldType[i].length; i++) {
|
||||
if (length == lovrFieldType[i].length && !memcmp(string, lovrFieldType[i].string, length)) {
|
||||
return i;
|
||||
|
@ -314,6 +322,7 @@ static void luax_checkbufferformat(lua_State* L, int index, BufferInfo* info) {
|
|||
case LUA_TSTRING:
|
||||
info->fieldCount = 1;
|
||||
info->fields[0].type = luax_checkfieldtype(L, index, &info->fields[0].hash);
|
||||
info->fields[0].location = 10;
|
||||
info->stride = fieldInfo[info->fields[0].type].size;
|
||||
break;
|
||||
case LUA_TTABLE:
|
||||
|
@ -326,7 +335,7 @@ static void luax_checkbufferformat(lua_State* L, int index, BufferInfo* info) {
|
|||
|
||||
uint32_t offset = 0;
|
||||
uint32_t extent = 0;
|
||||
uint32_t location = 0;
|
||||
uint32_t location = 10;
|
||||
uint32_t maxAlign = 1;
|
||||
for (int i = 0; i < length; i++) {
|
||||
BufferField* field = &info->fields[i];
|
||||
|
@ -394,6 +403,50 @@ static void luax_checkbufferformat(lua_State* L, int index, BufferInfo* info) {
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t luax_getbufferlength(lua_State* L, int index, BufferInfo* info) {
|
||||
switch (lua_type(L, 1)) {
|
||||
case LUA_TNUMBER: return lua_tointeger(L, 1); break;
|
||||
case LUA_TTABLE: {
|
||||
uint32_t length = luax_len(L, 1);
|
||||
|
||||
if (length < info->fieldCount) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_rawgeti(L, 1, 1);
|
||||
if (lua_istable(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
return length;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
uint32_t tableStride = 0;
|
||||
for (uint32_t i = 0, j = 1; i < info->fieldCount; i++) {
|
||||
lua_rawgeti(L, 1, (int) j);
|
||||
if (lua_isuserdata(L, -1)) {
|
||||
tableStride++;
|
||||
j++;
|
||||
} else {
|
||||
uint32_t components = fieldInfo[info->fields[i].type].components;
|
||||
tableStride += components;
|
||||
j += components;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return length / tableStride;
|
||||
}
|
||||
default: {
|
||||
Blob* blob = luax_totype(L, 1, Blob);
|
||||
if (blob) {
|
||||
return (uint32_t) blob->size / info->stride;
|
||||
} else {
|
||||
return luax_typeerror(L, 1, "number, table, or Blob");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Canvas luax_checkcanvas(lua_State* L, int index) {
|
||||
Canvas canvas = {
|
||||
.loads = { LOAD_CLEAR, LOAD_CLEAR, LOAD_CLEAR, LOAD_CLEAR },
|
||||
|
@ -487,7 +540,7 @@ static Canvas luax_checkcanvas(lua_State* L, int index) {
|
|||
}
|
||||
}
|
||||
} else if (lua_isnumber(L, -1) || lua_isuserdata(L, -1)) {
|
||||
luax_optcolor(L, -1, canvas.clears[1]);
|
||||
luax_optcolor(L, -1, canvas.clears[0]);
|
||||
} else if (!lua_isnil(L, -1)) {
|
||||
LoadAction load = lua_toboolean(L, -1) ? LOAD_DISCARD : LOAD_KEEP;
|
||||
canvas.loads[0] = canvas.loads[1] = canvas.loads[2] = canvas.loads[3] = load;
|
||||
|
@ -735,20 +788,7 @@ static int l_lovrGraphicsGetBuffer(lua_State* L) {
|
|||
BufferInfo info = { 0 };
|
||||
|
||||
luax_checkbufferformat(L, 2, &info);
|
||||
|
||||
switch (lua_type(L, 1)) {
|
||||
case LUA_TNUMBER: info.length = lua_tointeger(L, 1); break;
|
||||
case LUA_TTABLE: info.length = luax_len(L, 1); break;
|
||||
default: {
|
||||
Blob* blob = luax_totype(L, 1, Blob);
|
||||
if (blob) {
|
||||
info.length = blob->size / info.stride;
|
||||
break;
|
||||
} else {
|
||||
return luax_typeerror(L, 1, "number, table, or Blob");
|
||||
}
|
||||
}
|
||||
}
|
||||
info.length = luax_getbufferlength(L, 1, &info);
|
||||
|
||||
void* pointer;
|
||||
bool hasData = !lua_isnumber(L, 1);
|
||||
|
@ -768,20 +808,7 @@ static int l_lovrGraphicsNewBuffer(lua_State* L) {
|
|||
BufferInfo info = { 0 };
|
||||
|
||||
luax_checkbufferformat(L, 2, &info);
|
||||
|
||||
switch (lua_type(L, 1)) {
|
||||
case LUA_TNUMBER: info.length = lua_tointeger(L, 1); break;
|
||||
case LUA_TTABLE: info.length = luax_len(L, 1); break;
|
||||
default: {
|
||||
Blob* blob = luax_totype(L, 1, Blob);
|
||||
if (blob) {
|
||||
info.length = blob->size / info.stride;
|
||||
break;
|
||||
} else {
|
||||
return luax_typeerror(L, 1, "number, table, or Blob");
|
||||
}
|
||||
}
|
||||
}
|
||||
info.length = luax_getbufferlength(L, 1, &info);
|
||||
|
||||
void* pointer;
|
||||
bool hasData = !lua_isnumber(L, 1);
|
||||
|
|
|
@ -47,7 +47,9 @@ static const uint32_t fieldComponents[] = {
|
|||
[FIELD_F32x4] = 4,
|
||||
[FIELD_MAT2] = 4,
|
||||
[FIELD_MAT3] = 9,
|
||||
[FIELD_MAT4] = 16
|
||||
[FIELD_MAT4] = 16,
|
||||
[FIELD_INDEX16] = 1,
|
||||
[FIELD_INDEX32] = 1
|
||||
};
|
||||
|
||||
typedef union {
|
||||
|
@ -131,6 +133,8 @@ void luax_readbufferfield(lua_State* L, int index, int type, void* data) {
|
|||
case FIELD_MAT2: p.f32[i] = (float) x; break;
|
||||
case FIELD_MAT3: p.f32[i] = (float) x; break;
|
||||
case FIELD_MAT4: p.f32[i] = (float) x; break;
|
||||
case FIELD_INDEX16: p.u16[i] = (uint16_t) x - 1; break;
|
||||
case FIELD_INDEX32: p.u32[i] = (uint32_t) x - 1; break;
|
||||
default: lovrUnreachable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,6 +106,16 @@ static void online(void* context, const char* string, size_t length) {
|
|||
lua_rawseti(L, -2, index);
|
||||
}
|
||||
|
||||
static int l_lovrFontGetWidth(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
uint32_t count;
|
||||
ColoredString stack;
|
||||
ColoredString* strings = luax_checkcoloredstrings(L, 2, &count, &stack);
|
||||
float width = lovrFontGetWidth(font, strings, count);
|
||||
lua_pushnumber(L, width);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFontGetLines(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
uint32_t count;
|
||||
|
@ -118,14 +128,41 @@ static int l_lovrFontGetLines(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFontGetWidth(lua_State* L) {
|
||||
static int l_lovrFontGetVertices(lua_State* L) {
|
||||
Font* font = luax_checktype(L, 1, Font);
|
||||
uint32_t count;
|
||||
ColoredString stack;
|
||||
ColoredString* strings = luax_checkcoloredstrings(L, 2, &count, &stack);
|
||||
float width = lovrFontGetWidth(font, strings, count);
|
||||
lua_pushnumber(L, width);
|
||||
return 1;
|
||||
float wrap = luax_checkfloat(L, 3);
|
||||
HorizontalAlign halign = luax_checkenum(L, 4, HorizontalAlign, "center");
|
||||
VerticalAlign valign = luax_checkenum(L, 5, VerticalAlign, "middle");
|
||||
size_t totalLength = 0;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
totalLength += strings[i].length;
|
||||
}
|
||||
GlyphVertex* vertices = malloc(totalLength * 4 * sizeof(GlyphVertex));
|
||||
lovrAssert(vertices, "Out of memory");
|
||||
uint32_t glyphCount, lineCount;
|
||||
Material* material;
|
||||
lovrFontGetVertices(font, strings, count, wrap, halign, valign, vertices, &glyphCount, &lineCount, &material);
|
||||
int vertexCount = glyphCount * 4;
|
||||
lua_createtable(L, vertexCount, 0);
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
lua_createtable(L, 4, 0);
|
||||
lua_pushnumber(L, vertices[i].position.x);
|
||||
lua_rawseti(L, -2, 1);
|
||||
lua_pushnumber(L, vertices[i].position.y);
|
||||
lua_rawseti(L, -2, 2);
|
||||
lua_pushnumber(L, vertices[i].uv.u / 65535.f);
|
||||
lua_rawseti(L, -2, 3);
|
||||
lua_pushnumber(L, vertices[i].uv.v / 65535.f);
|
||||
lua_rawseti(L, -2, 4);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
luax_pushtype(L, Material, material);
|
||||
if (strings != &stack) free(strings);
|
||||
free(vertices);
|
||||
return 2;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrFont[] = {
|
||||
|
@ -140,5 +177,6 @@ const luaL_Reg lovrFont[] = {
|
|||
{ "getKerning", l_lovrFontGetKerning },
|
||||
{ "getWidth", l_lovrFontGetWidth },
|
||||
{ "getLines", l_lovrFontGetLines },
|
||||
{ "getVertices", l_lovrFontGetVertices },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -529,11 +529,28 @@ static int l_lovrPassSphere(lua_State* L) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool luax_checkendpoints(lua_State* L, int index, float transform[16]) {
|
||||
float *v, *u;
|
||||
VectorType t1, t2;
|
||||
if ((v = luax_tovector(L, index + 0, &t1)) == NULL || t1 != V_VEC3) return false;
|
||||
if ((u = luax_tovector(L, index + 1, &t2)) == NULL || t2 != V_VEC3) return false;
|
||||
float radius = luax_optfloat(L, index + 2, 1.);
|
||||
float orientation[4];
|
||||
float forward[4] = { 0.f, 0.f, -1.f, 0.f };
|
||||
float direction[4];
|
||||
vec3_sub(vec3_init(direction, u), v);
|
||||
quat_between(orientation, forward, direction);
|
||||
mat4_identity(transform);
|
||||
mat4_translate(transform, (v[0] + u[0]) / 2.f, (v[1] + u[1]) / 2.f, (v[2] + u[2]) / 2.f);
|
||||
mat4_rotateQuat(transform, orientation);
|
||||
mat4_scale(transform, radius, radius, vec3_length(direction));
|
||||
return true;
|
||||
}
|
||||
|
||||
static int l_lovrPassCylinder(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
float transform[16];
|
||||
// TODO vec3+vec3
|
||||
int index = luax_readmat4(L, 2, transform, -2);
|
||||
int index = luax_checkendpoints(L, 2, transform) ? 5 : luax_readmat4(L, 2, transform, -2);
|
||||
bool capped = lua_isnoneornil(L, index) ? true : lua_toboolean(L, index++);
|
||||
float angle1 = luax_optfloat(L, index++, 0.f);
|
||||
float angle2 = luax_optfloat(L, index++, 2.f * (float) M_PI);
|
||||
|
@ -545,7 +562,7 @@ static int l_lovrPassCylinder(lua_State* L) {
|
|||
static int l_lovrPassCapsule(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
float transform[16];
|
||||
int index = luax_readmat4(L, 2, transform, -2);
|
||||
int index = luax_checkendpoints(L, 2, transform) ? 5 : luax_readmat4(L, 2, transform, -2);
|
||||
uint32_t segments = luax_optu32(L, index, 32);
|
||||
lovrPassCapsule(pass, transform, segments);
|
||||
return 0;
|
||||
|
@ -556,7 +573,7 @@ static int l_lovrPassTorus(lua_State* L) {
|
|||
float transform[16];
|
||||
int index = luax_readmat4(L, 2, transform, -2);
|
||||
uint32_t segmentsT = luax_optu32(L, index++, 64);
|
||||
uint32_t segmentsP = luax_optu32(L, index++, 32);
|
||||
uint32_t segmentsP = luax_optu32(L, index++, segmentsT / 2);
|
||||
lovrPassTorus(pass, transform, segmentsT, segmentsP);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ typedef struct {
|
|||
struct {
|
||||
VkFormat format;
|
||||
VkImageLayout layout;
|
||||
VkImageLayout resolveLayout;
|
||||
gpu_load_op load;
|
||||
gpu_save_op save;
|
||||
} color[4];
|
||||
|
@ -1276,6 +1277,7 @@ bool gpu_pipeline_init_graphics(gpu_pipeline* pipeline, gpu_pipeline_info* info)
|
|||
for (uint32_t i = 0; i < info->colorCount; i++) {
|
||||
pass.color[i].format = convertFormat(info->color[i].format, info->color[i].srgb);
|
||||
pass.color[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
pass.color[i].resolveLayout = resolve ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
pass.color[i].load = GPU_LOAD_OP_CLEAR;
|
||||
pass.color[i].save = GPU_SAVE_OP_SAVE;
|
||||
}
|
||||
|
@ -1440,6 +1442,7 @@ void gpu_render_begin(gpu_stream* stream, gpu_canvas* canvas) {
|
|||
if (pass.resolve) {
|
||||
for (uint32_t i = 0; i < pass.count; i++) {
|
||||
images[pass.count + i] = canvas->color[i].resolve->view;
|
||||
pass.color[i].resolveLayout = canvas->color[i].resolve->layout;
|
||||
}
|
||||
pass.count <<= 1;
|
||||
}
|
||||
|
@ -2456,6 +2459,10 @@ static VkRenderPass getCachedRenderPass(gpu_pass_info* pass, bool compatible) {
|
|||
count > 1 ? pass->color[1].layout : 0x00,
|
||||
count > 2 ? pass->color[2].layout : 0x00,
|
||||
count > 3 ? pass->color[3].layout : 0x00,
|
||||
pass->resolve && count > 0 ? pass->color[0].resolveLayout : 0x00,
|
||||
pass->resolve && count > 1 ? pass->color[1].resolveLayout : 0x00,
|
||||
pass->resolve && count > 2 ? pass->color[2].resolveLayout : 0x00,
|
||||
pass->resolve && count > 3 ? pass->color[3].resolveLayout : 0x00,
|
||||
depth ? pass->depth.layout : 0x00,
|
||||
0
|
||||
};
|
||||
|
@ -2476,8 +2483,8 @@ static VkRenderPass getCachedRenderPass(gpu_pass_info* pass, bool compatible) {
|
|||
if ((row[i].hash & mask) == hash) {
|
||||
gpu_cache_entry entry = row[i];
|
||||
if (i > 0) {
|
||||
for (uint32_t j = 0; j < i; j++) {
|
||||
row[j + 1] = row[j];
|
||||
for (uint32_t j = i; j >= 1; j--) {
|
||||
row[j] = row[j - 1];
|
||||
}
|
||||
row[0] = entry;
|
||||
}
|
||||
|
@ -2505,7 +2512,7 @@ static VkRenderPass getCachedRenderPass(gpu_pass_info* pass, bool compatible) {
|
|||
references[i].attachment = i;
|
||||
references[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
bool surface = pass->color[i].format == state.surfaceFormat;
|
||||
bool discard = surface || pass->resolve || pass->color[i].load != GPU_LOAD_OP_LOAD;
|
||||
bool discard = surface || pass->color[i].load != GPU_LOAD_OP_LOAD;
|
||||
attachments[i] = (VkAttachmentDescription) {
|
||||
.format = pass->color[i].format,
|
||||
.samples = pass->samples,
|
||||
|
@ -2528,7 +2535,7 @@ static VkRenderPass getCachedRenderPass(gpu_pass_info* pass, bool compatible) {
|
|||
.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
.storeOp = storeOps[pass->color[i].save],
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.finalLayout = surface ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : pass->color[i].layout
|
||||
.finalLayout = surface ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : pass->color[i].resolveLayout
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -469,7 +469,7 @@ MAF mat4 mat4_cofactor(mat4 m) {
|
|||
m[6] = -(m00 * (m09 * m15 - m11 * m13) - m08 * (m01 * m15 - m03 * m13) + m12 * (m01 * m11 - m03 * m09));
|
||||
m[7] = (m00 * (m09 * m14 - m10 * m13) - m08 * (m01 * m14 - m02 * m13) + m12 * (m01 * m10 - m02 * m09));
|
||||
m[8] = (m01 * (m06 * m15 - m07 * m14) - m05 * (m02 * m15 - m03 * m14) + m13 * (m02 * m07 - m03 * m06));
|
||||
m[9] = -(m00 * (m10 * m15 - m07 * m14) - m04 * (m02 * m15 - m03 * m14) + m12 * (m02 * m07 - m03 * m10));
|
||||
m[9] = -(m00 * (m06 * m15 - m07 * m14) - m04 * (m02 * m15 - m03 * m14) + m12 * (m02 * m07 - m03 * m06));
|
||||
m[10] = (m00 * (m05 * m15 - m07 * m13) - m04 * (m01 * m15 - m03 * m13) + m12 * (m01 * m07 - m03 * m05));
|
||||
m[11] = -(m00 * (m05 * m14 - m06 * m13) - m04 * (m01 * m14 - m02 * m13) + m12 * (m01 * m06 - m02 * m05));
|
||||
m[12] = -(m01 * (m06 * m11 - m07 * m10) - m05 * (m02 * m11 - m03 * m10) + m09 * (m02 * m07 - m03 * m06));
|
||||
|
|
|
@ -33,12 +33,6 @@ typedef struct {
|
|||
struct { float u, v; } uv;
|
||||
} ShapeVertex;
|
||||
|
||||
typedef struct {
|
||||
struct { float x, y; } position;
|
||||
struct { uint16_t u, v; } uv;
|
||||
struct { uint8_t r, g, b, a; } color;
|
||||
} GlyphVertex;
|
||||
|
||||
typedef struct {
|
||||
struct { float x, y, z; } position;
|
||||
struct { float x, y, z; } normal;
|
||||
|
@ -2342,7 +2336,7 @@ Model* lovrModelCreate(ModelInfo* info) {
|
|||
.length = data->indexCount,
|
||||
.stride = indexSize,
|
||||
.fieldCount = 1,
|
||||
.fields[0] = { 0, 0, data->indexType == U32 ? FIELD_U32 : FIELD_I32, 0 }
|
||||
.fields[0] = { 0, 0, data->indexType == U32 ? FIELD_INDEX32 : FIELD_INDEX16, 0 }
|
||||
}, (void**) &indices);
|
||||
}
|
||||
|
||||
|
@ -3435,6 +3429,7 @@ static void flushPipeline(Pass* pass, Draw* draw, Shader* shader) {
|
|||
bool found = false;
|
||||
for (uint32_t j = 0; j < draw->vertex.buffer->info.fieldCount; j++) {
|
||||
BufferField field = draw->vertex.buffer->info.fields[j];
|
||||
lovrCheck(field.type < FIELD_MAT2, "Currently, matrix and index types can not be used in vertex buffers");
|
||||
if (field.hash ? (field.hash == attribute->hash) : (field.location == attribute->location)) {
|
||||
pipeline->info.vertex.attributes[i] = (gpu_attribute) {
|
||||
.buffer = 0,
|
||||
|
@ -3563,6 +3558,10 @@ static void flushBuiltins(Pass* pass, Draw* draw, Shader* shader) {
|
|||
|
||||
float cofactor[16];
|
||||
mat4_init(cofactor, transform);
|
||||
cofactor[12] = 0.f;
|
||||
cofactor[13] = 0.f;
|
||||
cofactor[14] = 0.f;
|
||||
cofactor[15] = 1.f;
|
||||
mat4_cofactor(cofactor);
|
||||
|
||||
memcpy(pass->drawData->transform, transform, 64);
|
||||
|
@ -4170,7 +4169,7 @@ void lovrPassTorus(Pass* pass, float* transform, uint32_t segmentsT, uint32_t se
|
|||
uint16_t b = (t + 1) % segmentsT * segmentsP + p;
|
||||
uint16_t c = (t + 0) * segmentsP + (p + 1) % segmentsP;
|
||||
uint16_t d = (t + 1) % segmentsT * segmentsP + (p + 1) % segmentsP;
|
||||
uint16_t quad[] = { a, b, c, b, c, d };
|
||||
uint16_t quad[] = { a, b, c, c, b, d };
|
||||
memcpy(indices, quad, sizeof(quad));
|
||||
indices += COUNTOF(quad);
|
||||
}
|
||||
|
@ -4185,31 +4184,19 @@ static void aline(GlyphVertex* vertices, uint32_t head, uint32_t tail, float wid
|
|||
}
|
||||
}
|
||||
|
||||
void lovrPassText(Pass* pass, Font* font, ColoredString* strings, uint32_t count, float* transform, float wrap, HorizontalAlign halign, VerticalAlign valign) {
|
||||
font = font ? font : lovrGraphicsGetDefaultFont();
|
||||
float space = lovrFontGetGlyph(font, ' ', NULL)->advance;
|
||||
|
||||
size_t totalLength = 0;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
totalLength += strings[i].length;
|
||||
}
|
||||
|
||||
uint32_t stack = tempPush();
|
||||
GlyphVertex* vertices = tempAlloc(totalLength * 4 * sizeof(GlyphVertex));
|
||||
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) {
|
||||
uint32_t vertexCount = 0;
|
||||
uint32_t glyphCount = 0;
|
||||
uint32_t lineCount = 1;
|
||||
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 ascent = lovrRasterizerGetAscent(font->info.rasterizer);
|
||||
float scale = 1.f / font->pixelDensity;
|
||||
wrap /= scale;
|
||||
float space = lovrFontGetGlyph(font, ' ', NULL)->advance;
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
size_t bytes;
|
||||
|
@ -4239,7 +4226,7 @@ void lovrPassText(Pass* pass, Font* font, ColoredString* strings, uint32_t count
|
|||
y -= leading;
|
||||
wordStartX = 0.f;
|
||||
prevWordEndX = 0.f;
|
||||
lineCount++;
|
||||
(*lineCount)++;
|
||||
previous = '\0';
|
||||
str += bytes;
|
||||
continue;
|
||||
|
@ -4252,8 +4239,7 @@ void lovrPassText(Pass* pass, Font* font, ColoredString* strings, uint32_t count
|
|||
Glyph* glyph = lovrFontGetGlyph(font, codepoint, &resized);
|
||||
|
||||
if (resized) {
|
||||
tempPop(stack);
|
||||
lovrPassText(pass, font, strings, count, transform, wrap, halign, valign);
|
||||
lovrFontGetVertices(font, strings, count, wrap, halign, valign, vertices, glyphCount, lineCount, material);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4275,7 +4261,7 @@ void lovrPassText(Pass* pass, Font* font, ColoredString* strings, uint32_t count
|
|||
aline(vertices, lineStart, wordStart, prevWordEndX, halign);
|
||||
lineStart = wordStart;
|
||||
wordStartX = 0.f;
|
||||
lineCount++;
|
||||
(*lineCount)++;
|
||||
x -= dx;
|
||||
y -= dy;
|
||||
}
|
||||
|
@ -4287,7 +4273,7 @@ void lovrPassText(Pass* pass, Font* font, ColoredString* strings, uint32_t count
|
|||
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++;
|
||||
(*glyphCount)++;
|
||||
|
||||
// Advance
|
||||
x += glyph->advance;
|
||||
|
@ -4298,6 +4284,30 @@ void lovrPassText(Pass* pass, Font* font, ColoredString* strings, uint32_t count
|
|||
// 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();
|
||||
|
||||
size_t totalLength = 0;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
totalLength += strings[i].length;
|
||||
}
|
||||
|
||||
uint32_t stack = tempPush();
|
||||
GlyphVertex* vertices = tempAlloc(totalLength * 4 * sizeof(GlyphVertex));
|
||||
uint32_t glyphCount;
|
||||
uint32_t lineCount;
|
||||
|
||||
float leading = lovrRasterizerGetLeading(font->info.rasterizer) * font->lineSpacing;
|
||||
float ascent = lovrRasterizerGetAscent(font->info.rasterizer);
|
||||
float scale = 1.f / font->pixelDensity;
|
||||
wrap /= scale;
|
||||
|
||||
Material* material;
|
||||
lovrFontGetVertices(font, strings, count, wrap, halign, valign, vertices, &glyphCount, &lineCount, &material);
|
||||
|
||||
mat4_scale(transform, scale, scale, scale);
|
||||
mat4_translate(transform, 0.f, -ascent + valign / 2.f * (leading * lineCount), 0.f);
|
||||
|
||||
|
@ -4308,13 +4318,13 @@ void lovrPassText(Pass* pass, Font* font, ColoredString* strings, uint32_t count
|
|||
.material = font->material,
|
||||
.transform = transform,
|
||||
.vertex.format = VERTEX_GLYPH,
|
||||
.vertex.count = vertexCount,
|
||||
.vertex.count = glyphCount * 4,
|
||||
.vertex.data = vertices,
|
||||
.index.count = glyphCount * 6,
|
||||
.index.pointer = (void**) &indices
|
||||
});
|
||||
|
||||
for (uint32_t i = 0; i < vertexCount; i += 4) {
|
||||
for (uint32_t i = 0; i < glyphCount * 4; i += 4) {
|
||||
uint16_t quad[] = { i + 0, i + 2, i + 1, i + 1, i + 2, i + 3 };
|
||||
memcpy(indices, quad, sizeof(quad));
|
||||
indices += COUNTOF(quad);
|
||||
|
|
|
@ -138,7 +138,9 @@ typedef enum {
|
|||
FIELD_F32x4,
|
||||
FIELD_MAT2,
|
||||
FIELD_MAT3,
|
||||
FIELD_MAT4
|
||||
FIELD_MAT4,
|
||||
FIELD_INDEX16,
|
||||
FIELD_INDEX32
|
||||
} FieldType;
|
||||
|
||||
typedef struct {
|
||||
|
@ -365,6 +367,12 @@ typedef enum {
|
|||
ALIGN_BOTTOM
|
||||
} VerticalAlign;
|
||||
|
||||
typedef struct {
|
||||
struct { float x, y; } position;
|
||||
struct { uint16_t u, v; } uv;
|
||||
struct { uint8_t r, g, b, a; } color;
|
||||
} GlyphVertex;
|
||||
|
||||
Font* lovrFontCreate(FontInfo* info);
|
||||
void lovrFontDestroy(void* ref);
|
||||
const FontInfo* lovrFontGetInfo(Font* font);
|
||||
|
@ -375,6 +383,7 @@ void lovrFontSetLineSpacing(Font* font, float spacing);
|
|||
float lovrFontGetKerning(Font* font, uint32_t first, uint32_t second);
|
||||
float lovrFontGetWidth(Font* font, ColoredString* strings, uint32_t count);
|
||||
void lovrFontGetLines(Font* font, ColoredString* strings, uint32_t count, float wrap, void (*callback)(void* context, const char* string, size_t length), void* context);
|
||||
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);
|
||||
|
||||
// Model
|
||||
|
||||
|
|
Loading…
Reference in New Issue