mirror of https://github.com/bjornbytes/lovr.git
Compare commits
7 Commits
c1bb47d737
...
af8c061c50
Author | SHA1 | Date |
---|---|---|
bjorn | af8c061c50 | |
bjorn | a654cec40f | |
bjorn | b89c61a8f4 | |
bjorn | 3c5288e979 | |
bjorn | 0d7fed1fa7 | |
bjorn | 717f95f6bd | |
bjorn | cb121d3d36 |
|
@ -2,3 +2,9 @@
|
|||
#include "shaders/unlit.frag.h"
|
||||
|
||||
#include "shaders/lovr.glsl.h"
|
||||
|
||||
#define LOCATION_POSITION 10
|
||||
#define LOCATION_NORMAL 11
|
||||
#define LOCATION_UV 12
|
||||
#define LOCATION_COLOR 13
|
||||
#define LOCATION_TANGENT 14
|
||||
|
|
|
@ -5,5 +5,5 @@
|
|||
#include "lovr.glsl"
|
||||
|
||||
void main() {
|
||||
PixelColors[0] = FragColor;
|
||||
PixelColors[0] = FragColor * texture(sampler2D(Texture, Sampler), FragUV);
|
||||
}
|
||||
|
|
|
@ -4,78 +4,214 @@
|
|||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
static int l_lovrRasterizerGetHeight(lua_State* L) {
|
||||
static int l_lovrRasterizerGetFontSize(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
lua_pushinteger(L, lovrRasterizerGetHeight(rasterizer));
|
||||
float size = lovrRasterizerGetFontSize(rasterizer);
|
||||
lua_pushnumber(L, size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetAdvance(lua_State* L) {
|
||||
static int l_lovrRasterizerGetBoundingBox(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
lua_pushinteger(L, lovrRasterizerGetAdvance(rasterizer));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetAscent(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
lua_pushinteger(L, lovrRasterizerGetAscent(rasterizer));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetDescent(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
lua_pushinteger(L, lovrRasterizerGetDescent(rasterizer));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetLineHeight(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
lua_pushinteger(L, lovrRasterizerGetHeight(rasterizer) * 1.25f);
|
||||
return 1;
|
||||
float box[4];
|
||||
lovrRasterizerGetBoundingBox(rasterizer, box);
|
||||
lua_pushnumber(L, box[0]);
|
||||
lua_pushnumber(L, box[1]);
|
||||
lua_pushnumber(L, box[2]);
|
||||
lua_pushnumber(L, box[3]);
|
||||
return 4;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetGlyphCount(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
lua_pushinteger(L, lovrRasterizerGetGlyphCount(rasterizer));
|
||||
uint32_t count = lovrRasterizerGetGlyphCount(rasterizer);
|
||||
lua_pushinteger(L, count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerHasGlyphs(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
bool hasGlyphs = true;
|
||||
for (int i = 2; i <= lua_gettop(L); i++) {
|
||||
if (lua_type(L, i) == LUA_TSTRING) {
|
||||
hasGlyphs &= lovrRasterizerHasGlyphs(rasterizer, lua_tostring(L, i));
|
||||
} else {
|
||||
hasGlyphs &= lovrRasterizerHasGlyph(rasterizer, luax_checku32(L, i));
|
||||
size_t length;
|
||||
const char* str;
|
||||
switch (lua_type(L, i)) {
|
||||
case LUA_TSTRING:
|
||||
str = lua_tolstring(L, i, &length);
|
||||
if (!lovrRasterizerHasGlyphs(rasterizer, str, length)) {
|
||||
lua_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case LUA_TNUMBER:
|
||||
if (!lovrRasterizerHasGlyph(rasterizer, luax_checku32(L, i))) {
|
||||
lua_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default: return luax_typeerror(L, i, "string or number");
|
||||
}
|
||||
}
|
||||
lua_pushboolean(L, hasGlyphs);
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetWidth(lua_State* L) {
|
||||
static int l_lovrRasterizerGetAscent(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
float ascent = lovrRasterizerGetAscent(rasterizer);
|
||||
lua_pushnumber(L, ascent);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetDescent(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
float descent = lovrRasterizerGetDescent(rasterizer);
|
||||
lua_pushnumber(L, descent);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetLineGap(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
float lineGap = lovrRasterizerGetLineGap(rasterizer);
|
||||
lua_pushnumber(L, lineGap);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetLeading(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
float leading = lovrRasterizerGetLeading(rasterizer);
|
||||
lua_pushnumber(L, leading);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t luax_checkcodepoint(lua_State* L, int index) {
|
||||
size_t length;
|
||||
const char* string = luaL_checklstring(L, 2, &length);
|
||||
float wrap = luax_optfloat(L, 4, 0.f);
|
||||
float width, lastLineWidth, height;
|
||||
uint32_t lineCount, glyphCount;
|
||||
lovrRasterizerMeasure(rasterizer, string, length, wrap, &width, &lastLineWidth, &height, &lineCount, &glyphCount);
|
||||
lua_pushnumber(L, width);
|
||||
lua_pushnumber(L, lineCount + 1);
|
||||
lua_pushnumber(L, lastLineWidth);
|
||||
const char* str;
|
||||
uint32_t codepoint;
|
||||
switch (lua_type(L, index)) {
|
||||
case LUA_TSTRING:
|
||||
str = lua_tolstring(L, index, &length);
|
||||
return utf8_decode(str, str + length, &codepoint) ? codepoint : 0;
|
||||
case LUA_TNUMBER:
|
||||
return luax_checku32(L, index);
|
||||
default: return luax_typeerror(L, index, "string or number"), 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetKerning(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
uint32_t prev = luax_checkcodepoint(L, 2);
|
||||
uint32_t next = luax_checkcodepoint(L, 3);
|
||||
float kerning = lovrRasterizerGetKerning(rasterizer, prev, next);
|
||||
lua_pushnumber(L, kerning);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetGlyphAdvance(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
uint32_t codepoint = luax_checkcodepoint(L, 2);
|
||||
float advance = lovrRasterizerGetGlyphAdvance(rasterizer, codepoint);
|
||||
lua_pushnumber(L, advance);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetGlyphBearing(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
uint32_t codepoint = luax_checkcodepoint(L, 2);
|
||||
float bearing = lovrRasterizerGetGlyphBearing(rasterizer, codepoint);
|
||||
lua_pushnumber(L, bearing);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetGlyphWidth(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
uint32_t codepoint = luax_checkcodepoint(L, 2);
|
||||
float box[4];
|
||||
lovrRasterizerGetGlyphBoundingBox(rasterizer, codepoint, box);
|
||||
lua_pushnumber(L, box[2] - box[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetGlyphHeight(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
uint32_t codepoint = luax_checkcodepoint(L, 2);
|
||||
float box[4];
|
||||
lovrRasterizerGetGlyphBoundingBox(rasterizer, codepoint, box);
|
||||
lua_pushnumber(L, box[3] - box[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetGlyphDimensions(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
uint32_t codepoint = luax_checkcodepoint(L, 2);
|
||||
float box[4];
|
||||
lovrRasterizerGetGlyphBoundingBox(rasterizer, codepoint, box);
|
||||
lua_pushnumber(L, box[2] - box[0]);
|
||||
lua_pushnumber(L, box[3] - box[1]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetGlyphBoundingBox(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
uint32_t codepoint = luax_checkcodepoint(L, 2);
|
||||
float box[4];
|
||||
lovrRasterizerGetGlyphBoundingBox(rasterizer, codepoint, box);
|
||||
lua_pushnumber(L, box[0]);
|
||||
lua_pushnumber(L, box[1]);
|
||||
lua_pushnumber(L, box[2]);
|
||||
lua_pushnumber(L, box[3]);
|
||||
return 4;
|
||||
}
|
||||
|
||||
static void onCurve2D(void* context, uint32_t degree, float* points) {
|
||||
lua_State* L = context;
|
||||
uint32_t count = (degree + 1) * 2;
|
||||
lua_createtable(L, count, 0);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
lua_pushnumber(L, points[i]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
lua_rawseti(L, -2, luax_len(L, -2) + 1);
|
||||
}
|
||||
|
||||
static void onCurve3D(void* context, uint32_t degree, float* points) {
|
||||
lua_State* L = context;
|
||||
lua_createtable(L, (degree + 1) * 3, 0);
|
||||
for (uint32_t i = 0; i < degree + 1; i++) {
|
||||
lua_pushnumber(L, points[2 * i + 0]);
|
||||
lua_rawseti(L, -2, 3 * i + 1);
|
||||
lua_pushnumber(L, points[2 * i + 1]);
|
||||
lua_rawseti(L, -2, 3 * i + 2);
|
||||
lua_pushnumber(L, 0.);
|
||||
lua_rawseti(L, -2, 3 * i + 3);
|
||||
}
|
||||
lua_rawseti(L, -2, luax_len(L, -2) + 1);
|
||||
}
|
||||
|
||||
static int l_lovrRasterizerGetGlyphCurves(lua_State* L) {
|
||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||
uint32_t codepoint = luax_checkcodepoint(L, 2);
|
||||
bool three = lua_toboolean(L, 3);
|
||||
lua_newtable(L);
|
||||
lovrRasterizerGetGlyphCurves(rasterizer, codepoint, three ? onCurve3D : onCurve2D, L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrRasterizer[] = {
|
||||
{ "getHeight", l_lovrRasterizerGetHeight },
|
||||
{ "getAdvance", l_lovrRasterizerGetAdvance },
|
||||
{ "getAscent", l_lovrRasterizerGetAscent },
|
||||
{ "getDescent", l_lovrRasterizerGetDescent },
|
||||
{ "getLineHeight", l_lovrRasterizerGetLineHeight },
|
||||
{ "getFontSize", l_lovrRasterizerGetFontSize },
|
||||
{ "getBoundingBox", l_lovrRasterizerGetBoundingBox },
|
||||
{ "getGlyphCount", l_lovrRasterizerGetGlyphCount },
|
||||
{ "hasGlyphs", l_lovrRasterizerHasGlyphs },
|
||||
{ "getWidth", l_lovrRasterizerGetWidth },
|
||||
{ "getAscent", l_lovrRasterizerGetAscent },
|
||||
{ "getDescent", l_lovrRasterizerGetDescent },
|
||||
{ "getLineGap", l_lovrRasterizerGetLineGap },
|
||||
{ "getLeading", l_lovrRasterizerGetLeading },
|
||||
{ "getKerning", l_lovrRasterizerGetKerning },
|
||||
{ "getGlyphAdvance", l_lovrRasterizerGetGlyphAdvance },
|
||||
{ "getGlyphBearing", l_lovrRasterizerGetGlyphBearing },
|
||||
{ "getGlyphWidth", l_lovrRasterizerGetGlyphWidth },
|
||||
{ "getGlyphHeight", l_lovrRasterizerGetGlyphHeight },
|
||||
{ "getGlyphDimensions", l_lovrRasterizerGetGlyphDimensions },
|
||||
{ "getGlyphBoundingBox", l_lovrRasterizerGetGlyphBoundingBox },
|
||||
{ "getGlyphCurves", l_lovrRasterizerGetGlyphCurves },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "graphics/graphics.h"
|
||||
#include "data/blob.h"
|
||||
#include "data/image.h"
|
||||
#include "data/rasterizer.h"
|
||||
#include "util.h"
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
@ -97,10 +98,10 @@ StringEntry lovrFilterMode[] = {
|
|||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrVertexMode[] = {
|
||||
[VERTEX_POINTS] = ENTRY("points"),
|
||||
[VERTEX_LINES] = ENTRY("lines"),
|
||||
[VERTEX_TRIANGLES] = ENTRY("triangles"),
|
||||
StringEntry lovrHorizontalAlign[] = {
|
||||
[ALIGN_LEFT] = ENTRY("left"),
|
||||
[ALIGN_CENTER] = ENTRY("center"),
|
||||
[ALIGN_RIGHT] = ENTRY("right"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
@ -169,6 +170,20 @@ StringEntry lovrTextureUsage[] = {
|
|||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrVertexMode[] = {
|
||||
[VERTEX_POINTS] = ENTRY("points"),
|
||||
[VERTEX_LINES] = ENTRY("lines"),
|
||||
[VERTEX_TRIANGLES] = ENTRY("triangles"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrVerticalAlign[] = {
|
||||
[ALIGN_TOP] = ENTRY("top"),
|
||||
[ALIGN_MIDDLE] = ENTRY("middle"),
|
||||
[ALIGN_BOTTOM] = ENTRY("bottom"),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
StringEntry lovrWinding[] = {
|
||||
[WINDING_COUNTERCLOCKWISE] = ENTRY("counterclockwise"),
|
||||
[WINDING_CLOCKWISE] = ENTRY("clockwise"),
|
||||
|
@ -1192,6 +1207,42 @@ static int l_lovrGraphicsNewMaterial(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrGraphicsNewFont(lua_State* L) {
|
||||
FontInfo info = { 0 };
|
||||
|
||||
info.rasterizer = luax_totype(L, 1, Rasterizer);
|
||||
info.padding = 1;
|
||||
info.spread = 4.;
|
||||
|
||||
if (!info.rasterizer) {
|
||||
Blob* blob = NULL;
|
||||
float size;
|
||||
|
||||
if (lua_type(L, 1) == LUA_TNUMBER || lua_isnoneornil(L, 1)) {
|
||||
size = luax_optfloat(L, 1, 32.f);
|
||||
info.padding = luaL_optinteger(L, 2, info.padding);
|
||||
info.spread = luaL_optnumber(L, 3, info.spread);
|
||||
} else {
|
||||
blob = luax_readblob(L, 1, "Font");
|
||||
size = luax_optfloat(L, 2, 32.f);
|
||||
info.padding = luaL_optinteger(L, 3, info.padding);
|
||||
info.spread = luaL_optnumber(L, 4, info.spread);
|
||||
}
|
||||
|
||||
info.rasterizer = lovrRasterizerCreate(blob, size);
|
||||
lovrRelease(blob, lovrBlobDestroy);
|
||||
} else {
|
||||
info.padding = luaL_optinteger(L, 2, info.padding);
|
||||
info.spread = luaL_optnumber(L, 3, info.spread);
|
||||
}
|
||||
|
||||
Font* font = lovrFontCreate(&info);
|
||||
luax_pushtype(L, Font, font);
|
||||
lovrRelease(info.rasterizer, lovrRasterizerDestroy);
|
||||
lovrRelease(font, lovrFontDestroy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrGraphicsGetPass(lua_State* L) {
|
||||
PassInfo info;
|
||||
info.type = luax_checkenum(L, 1, PassType, NULL);
|
||||
|
@ -1221,6 +1272,7 @@ static const luaL_Reg lovrGraphics[] = {
|
|||
{ "compileShader", l_lovrGraphicsCompileShader },
|
||||
{ "newShader", l_lovrGraphicsNewShader },
|
||||
{ "newMaterial", l_lovrGraphicsNewMaterial },
|
||||
{ "newFont", l_lovrGraphicsNewFont },
|
||||
{ "getPass", l_lovrGraphicsGetPass },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
@ -1230,6 +1282,7 @@ extern const luaL_Reg lovrTexture[];
|
|||
extern const luaL_Reg lovrSampler[];
|
||||
extern const luaL_Reg lovrShader[];
|
||||
extern const luaL_Reg lovrMaterial[];
|
||||
extern const luaL_Reg lovrFont[];
|
||||
extern const luaL_Reg lovrPass[];
|
||||
|
||||
int luaopen_lovr_graphics(lua_State* L) {
|
||||
|
@ -1240,6 +1293,7 @@ int luaopen_lovr_graphics(lua_State* L) {
|
|||
luax_registertype(L, Sampler);
|
||||
luax_registertype(L, Shader);
|
||||
luax_registertype(L, Material);
|
||||
luax_registertype(L, Font);
|
||||
luax_registertype(L, Pass);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#include "api.h"
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
const luaL_Reg lovrFont[] = {
|
||||
{ NULL, NULL }
|
||||
};
|
|
@ -1467,7 +1467,7 @@ void gpu_bind_vertex_buffers(gpu_stream* stream, gpu_buffer** buffers, uint32_t*
|
|||
uint64_t offsets64[COUNTOF(handles)];
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
handles[i] = buffers[i]->handle;
|
||||
offsets64[i] = buffers[i]->offset + offsets[i];
|
||||
offsets64[i] = buffers[i]->offset + (offsets ? offsets[i] : 0);
|
||||
}
|
||||
vkCmdBindVertexBuffers(stream->commands, first, count, handles, offsets64);
|
||||
}
|
||||
|
|
|
@ -1,25 +1,21 @@
|
|||
#include "data/rasterizer.h"
|
||||
#include "data/blob.h"
|
||||
#include "data/image.h"
|
||||
#include "util.h"
|
||||
#include "VarelaRound.ttf.h"
|
||||
#include "lib/stb/stb_truetype.h"
|
||||
#include <msdfgen-c.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
struct Rasterizer {
|
||||
uint32_t ref;
|
||||
stbtt_fontinfo font;
|
||||
struct Blob* blob;
|
||||
float size;
|
||||
float scale;
|
||||
int glyphCount;
|
||||
int height;
|
||||
int advance;
|
||||
int ascent;
|
||||
int descent;
|
||||
float ascent;
|
||||
float descent;
|
||||
float lineGap;
|
||||
float leading;
|
||||
stbtt_fontinfo font;
|
||||
};
|
||||
|
||||
Rasterizer* lovrRasterizerCreate(Blob* blob, float size) {
|
||||
|
@ -37,17 +33,13 @@ Rasterizer* lovrRasterizerCreate(Blob* blob, float size) {
|
|||
rasterizer->blob = blob;
|
||||
rasterizer->size = size;
|
||||
rasterizer->scale = stbtt_ScaleForMappingEmToPixels(font, size);
|
||||
rasterizer->glyphCount = font->numGlyphs;
|
||||
|
||||
int ascent, descent, linegap;
|
||||
stbtt_GetFontVMetrics(font, &ascent, &descent, &linegap);
|
||||
rasterizer->ascent = roundf(ascent * rasterizer->scale);
|
||||
rasterizer->descent = roundf(descent * rasterizer->scale);
|
||||
rasterizer->height = roundf((ascent - descent + linegap) * rasterizer->scale);
|
||||
|
||||
int x0, y0, x1, y1;
|
||||
stbtt_GetFontBoundingBox(font, &x0, &y0, &x1, &y1);
|
||||
rasterizer->advance = roundf(x1 * rasterizer->scale);
|
||||
int ascent, descent, lineGap;
|
||||
stbtt_GetFontVMetrics(font, &ascent, &descent, &lineGap);
|
||||
rasterizer->ascent = ascent * rasterizer->scale;
|
||||
rasterizer->descent = descent * rasterizer->scale;
|
||||
rasterizer->lineGap = lineGap * rasterizer->scale;
|
||||
rasterizer->leading = (ascent - descent + lineGap) * rasterizer->scale;
|
||||
|
||||
return rasterizer;
|
||||
}
|
||||
|
@ -58,96 +50,117 @@ void lovrRasterizerDestroy(void* ref) {
|
|||
free(rasterizer);
|
||||
}
|
||||
|
||||
float lovrRasterizerGetSize(Rasterizer* rasterizer) {
|
||||
float lovrRasterizerGetFontSize(Rasterizer* rasterizer) {
|
||||
return rasterizer->size;
|
||||
}
|
||||
|
||||
int lovrRasterizerGetGlyphCount(Rasterizer* rasterizer) {
|
||||
return rasterizer->glyphCount;
|
||||
void lovrRasterizerGetBoundingBox(Rasterizer* rasterizer, float box[4]) {
|
||||
int x0, y0, x1, y1;
|
||||
stbtt_GetFontBoundingBox(&rasterizer->font, &x0, &y0, &x1, &y1);
|
||||
box[0] = x0 * rasterizer->scale;
|
||||
box[1] = y0 * rasterizer->scale;
|
||||
box[2] = x1 * rasterizer->scale;
|
||||
box[3] = y1 * rasterizer->scale;
|
||||
}
|
||||
|
||||
int lovrRasterizerGetHeight(Rasterizer* rasterizer) {
|
||||
return rasterizer->height;
|
||||
uint32_t lovrRasterizerGetGlyphCount(Rasterizer* rasterizer) {
|
||||
return rasterizer->font.numGlyphs;
|
||||
}
|
||||
|
||||
int lovrRasterizerGetAdvance(Rasterizer* rasterizer) {
|
||||
return rasterizer->advance;
|
||||
bool lovrRasterizerHasGlyph(Rasterizer* rasterizer, uint32_t codepoint) {
|
||||
return stbtt_FindGlyphIndex(&rasterizer->font, codepoint) != 0;
|
||||
}
|
||||
|
||||
int lovrRasterizerGetAscent(Rasterizer* rasterizer) {
|
||||
bool lovrRasterizerHasGlyphs(Rasterizer* rasterizer, const char* str, size_t length) {
|
||||
size_t bytes;
|
||||
uint32_t codepoint;
|
||||
const char* end = str + length;
|
||||
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
||||
if (!lovrRasterizerHasGlyph(rasterizer, codepoint)) {
|
||||
return false;
|
||||
}
|
||||
str += bytes;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
float lovrRasterizerGetAscent(Rasterizer* rasterizer) {
|
||||
return rasterizer->ascent;
|
||||
}
|
||||
|
||||
int lovrRasterizerGetDescent(Rasterizer* rasterizer) {
|
||||
float lovrRasterizerGetDescent(Rasterizer* rasterizer) {
|
||||
return rasterizer->descent;
|
||||
}
|
||||
|
||||
bool lovrRasterizerHasGlyph(Rasterizer* rasterizer, uint32_t character) {
|
||||
return stbtt_FindGlyphIndex(&rasterizer->font, character) != 0;
|
||||
float lovrRasterizerGetLineGap(Rasterizer* rasterizer) {
|
||||
return rasterizer->lineGap;
|
||||
}
|
||||
|
||||
bool lovrRasterizerHasGlyphs(Rasterizer* rasterizer, const char* str) {
|
||||
const char* end = str + strlen(str);
|
||||
unsigned int codepoint;
|
||||
size_t bytes;
|
||||
|
||||
bool hasGlyphs = true;
|
||||
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
||||
hasGlyphs &= lovrRasterizerHasGlyph(rasterizer, codepoint);
|
||||
str += bytes;
|
||||
}
|
||||
return hasGlyphs;
|
||||
float lovrRasterizerGetLeading(Rasterizer* rasterizer) {
|
||||
return rasterizer->leading;
|
||||
}
|
||||
|
||||
void lovrRasterizerLoadGlyph(Rasterizer* rasterizer, uint32_t character, uint32_t padding, double spread, Glyph* glyph) {
|
||||
int glyphIndex = stbtt_FindGlyphIndex(&rasterizer->font, character);
|
||||
float lovrRasterizerGetKerning(Rasterizer* rasterizer, uint32_t prev, uint32_t next) {
|
||||
return stbtt_GetCodepointKernAdvance(&rasterizer->font, prev, next) * rasterizer->scale;
|
||||
}
|
||||
|
||||
float lovrRasterizerGetGlyphAdvance(Rasterizer* rasterizer, uint32_t codepoint) {
|
||||
int advance, bearing;
|
||||
stbtt_GetGlyphHMetrics(&rasterizer->font, glyphIndex, &advance, &bearing);
|
||||
stbtt_GetCodepointHMetrics(&rasterizer->font, codepoint, &advance, &bearing);
|
||||
return advance * rasterizer->scale;
|
||||
}
|
||||
|
||||
if (stbtt_IsGlyphEmpty(&rasterizer->font, glyphIndex)) {
|
||||
memset(glyph, 0, sizeof(Glyph));
|
||||
glyph->advance = roundf(advance * rasterizer->scale);
|
||||
float lovrRasterizerGetGlyphBearing(Rasterizer* rasterizer, uint32_t codepoint) {
|
||||
int advance, bearing;
|
||||
stbtt_GetCodepointHMetrics(&rasterizer->font, codepoint, &advance, &bearing);
|
||||
return bearing * rasterizer->scale;
|
||||
}
|
||||
|
||||
void lovrRasterizerGetGlyphBoundingBox(Rasterizer* rasterizer, uint32_t codepoint, float box[4]) {
|
||||
int x0, y0, x1, y1;
|
||||
stbtt_GetCodepointBox(&rasterizer->font, codepoint, &x0, &y0, &x1, &y1);
|
||||
box[0] = x0 * rasterizer->scale;
|
||||
box[1] = y0 * rasterizer->scale;
|
||||
box[2] = x1 * rasterizer->scale;
|
||||
box[3] = y1 * rasterizer->scale;
|
||||
}
|
||||
|
||||
bool lovrRasterizerIsGlyphEmpty(Rasterizer* rasterizer, uint32_t codepoint) {
|
||||
return stbtt_IsGlyphEmpty(&rasterizer->font, stbtt_FindGlyphIndex(&rasterizer->font, codepoint));
|
||||
}
|
||||
|
||||
void lovrRasterizerGetGlyphCurves(Rasterizer* rasterizer, uint32_t codepoint, void (*fn)(void* context, uint32_t degree, float* points), void* context) {
|
||||
uint32_t id = stbtt_FindGlyphIndex(&rasterizer->font, codepoint);
|
||||
|
||||
if (stbtt_IsGlyphEmpty(&rasterizer->font, id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Trace glyph outline
|
||||
stbtt_vertex* vertices;
|
||||
int vertexCount = stbtt_GetGlyphShape(&rasterizer->font, glyphIndex, &vertices);
|
||||
msShape* shape = msShapeCreate();
|
||||
msContour* contour = NULL;
|
||||
uint32_t count = stbtt_GetGlyphShape(&rasterizer->font, id, &vertices);
|
||||
|
||||
float x = 0.f;
|
||||
float y = 0.f;
|
||||
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
stbtt_vertex vertex = vertices[i];
|
||||
float x2 = vertex.x * rasterizer->scale;
|
||||
float y2 = vertex.y * rasterizer->scale;
|
||||
|
||||
switch (vertex.type) {
|
||||
case STBTT_vmove:
|
||||
contour = msShapeAddContour(shape);
|
||||
break;
|
||||
|
||||
case STBTT_vline:
|
||||
msContourAddLinearEdge(contour, x, y, x2, y2);
|
||||
break;
|
||||
|
||||
case STBTT_vcurve: {
|
||||
float cx = vertex.cx * rasterizer->scale;
|
||||
float cy = vertex.cy * rasterizer->scale;
|
||||
msContourAddQuadraticEdge(contour, x, y, cx, cy, x2, y2);
|
||||
break;
|
||||
}
|
||||
|
||||
case STBTT_vcubic: {
|
||||
float cx1 = vertex.cx * rasterizer->scale;
|
||||
float cy1 = vertex.cy * rasterizer->scale;
|
||||
float cx2 = vertex.cx1 * rasterizer->scale;
|
||||
float cy2 = vertex.cy1 * rasterizer->scale;
|
||||
msContourAddCubicEdge(contour, x, y, cx1, cy1, cx2, cy2, x2, y2);
|
||||
break;
|
||||
}
|
||||
if (vertex.type == STBTT_vline) {
|
||||
float points[4] = { x, y, x2, y2 };
|
||||
fn(context, 1, points);
|
||||
} else if (vertex.type == STBTT_vcurve) {
|
||||
float cx = vertex.cx * rasterizer->scale;
|
||||
float cy = vertex.cy * rasterizer->scale;
|
||||
float points[6] = { x, y, cx, cy, x2, y2 };
|
||||
fn(context, 2, points);
|
||||
} else if (vertex.type == STBTT_vcubic) {
|
||||
float cx1 = vertex.cx * rasterizer->scale;
|
||||
float cy1 = vertex.cy * rasterizer->scale;
|
||||
float cx2 = vertex.cx1 * rasterizer->scale;
|
||||
float cy2 = vertex.cy1 * rasterizer->scale;
|
||||
float points[8] = { x, y, cx1, cy1, cx2, cy2, x2, y2 };
|
||||
fn(context, 3, points);
|
||||
}
|
||||
|
||||
x = x2;
|
||||
|
@ -155,86 +168,4 @@ void lovrRasterizerLoadGlyph(Rasterizer* rasterizer, uint32_t character, uint32_
|
|||
}
|
||||
|
||||
stbtt_FreeShape(&rasterizer->font, vertices);
|
||||
|
||||
int x0, y0, x1, y1;
|
||||
stbtt_GetGlyphBox(&rasterizer->font, glyphIndex, &x0, &y0, &x1, &y1);
|
||||
|
||||
// Initialize glyph data
|
||||
glyph->x = 0;
|
||||
glyph->y = 0;
|
||||
glyph->w = ceilf((x1 - x0) * rasterizer->scale);
|
||||
glyph->h = ceilf((y1 - y0) * rasterizer->scale);
|
||||
glyph->tw = glyph->w + 2 * padding;
|
||||
glyph->th = glyph->h + 2 * padding;
|
||||
glyph->dx = roundf(bearing * rasterizer->scale);
|
||||
glyph->dy = roundf(y1 * rasterizer->scale);
|
||||
glyph->advance = roundf(advance * rasterizer->scale);
|
||||
glyph->data = lovrImageCreateRaw(glyph->tw, glyph->th, FORMAT_RGBA32F);
|
||||
|
||||
// Render SDF
|
||||
float tx = (float) padding + -glyph->dx;
|
||||
float ty = (float) padding + (float) glyph->h - glyph->dy;
|
||||
msShapeNormalize(shape);
|
||||
msEdgeColoringSimple(shape, 3., 0);
|
||||
msGenerateMTSDF(lovrImageGetBlob(glyph->data)->data, glyph->tw, glyph->th, shape, spread, 1.f, 1.f, tx, ty);
|
||||
msShapeDestroy(shape);
|
||||
}
|
||||
|
||||
int32_t lovrRasterizerGetKerning(Rasterizer* rasterizer, uint32_t left, uint32_t right) {
|
||||
return stbtt_GetCodepointKernAdvance(&rasterizer->font, left, right) * rasterizer->scale;
|
||||
}
|
||||
|
||||
void lovrRasterizerMeasure(Rasterizer* rasterizer, const char* str, size_t length, float wrap, float* width, float* lastLineWidth, float* height, uint32_t* lineCount, uint32_t* glyphCount) {
|
||||
float x = 0.f;
|
||||
const char* end = str + length;
|
||||
size_t bytes;
|
||||
unsigned int previous = '\0';
|
||||
unsigned int codepoint;
|
||||
*width = 0.f;
|
||||
*lastLineWidth = 0.f;
|
||||
*lineCount = 0;
|
||||
*glyphCount = 0;
|
||||
|
||||
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
||||
if (codepoint == '\n' || (wrap && x > wrap && (codepoint == ' ' || previous == ' '))) {
|
||||
*width = MAX(*width, x);
|
||||
(*lineCount)++;
|
||||
x = 0.f;
|
||||
previous = '\0';
|
||||
if (codepoint == ' ' || codepoint == '\n') {
|
||||
str += bytes;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Tabs
|
||||
if (codepoint == '\t') {
|
||||
int glyphIndex = stbtt_FindGlyphIndex(&rasterizer->font, ' ');
|
||||
int advance, bearing;
|
||||
stbtt_GetGlyphHMetrics(&rasterizer->font, glyphIndex, &advance, &bearing);
|
||||
x += advance * 4.f;
|
||||
str += bytes;
|
||||
continue;
|
||||
}
|
||||
|
||||
int glyphIndex = stbtt_FindGlyphIndex(&rasterizer->font, codepoint);
|
||||
int advance, bearing;
|
||||
stbtt_GetGlyphHMetrics(&rasterizer->font, glyphIndex, &advance, &bearing);
|
||||
int x0, y0, x1, y1;
|
||||
if (stbtt_GetGlyphBox(&rasterizer->font, glyphIndex, &x0, &y0, &x1, &y1)) {
|
||||
float w = ceilf((x1 - x0) * rasterizer->scale);
|
||||
float h = ceilf((y1 - y0) * rasterizer->scale);
|
||||
if (w > 0 && h > 0) {
|
||||
(*glyphCount)++;
|
||||
}
|
||||
}
|
||||
|
||||
x += roundf(advance * rasterizer->scale) + lovrRasterizerGetKerning(rasterizer, previous, codepoint);
|
||||
previous = codepoint;
|
||||
str += bytes;
|
||||
}
|
||||
|
||||
*width = MAX(*width, x);
|
||||
*lastLineWidth = x;
|
||||
*height = ((*lineCount + 1) * lovrRasterizerGetHeight(rasterizer));
|
||||
}
|
||||
|
|
|
@ -7,30 +7,21 @@
|
|||
struct Blob;
|
||||
struct Image;
|
||||
|
||||
typedef struct {
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
uint32_t w;
|
||||
uint32_t h;
|
||||
uint32_t tw;
|
||||
uint32_t th;
|
||||
int32_t dx;
|
||||
int32_t dy;
|
||||
int32_t advance;
|
||||
struct Image* data;
|
||||
} Glyph;
|
||||
|
||||
typedef struct Rasterizer Rasterizer;
|
||||
Rasterizer* lovrRasterizerCreate(struct Blob* blob, float size);
|
||||
void lovrRasterizerDestroy(void* ref);
|
||||
float lovrRasterizerGetSize(Rasterizer* rasterizer);
|
||||
int lovrRasterizerGetGlyphCount(Rasterizer* rasterizer);
|
||||
int lovrRasterizerGetHeight(Rasterizer* rasterizer);
|
||||
int lovrRasterizerGetAdvance(Rasterizer* rasterizer);
|
||||
int lovrRasterizerGetAscent(Rasterizer* rasterizer);
|
||||
int lovrRasterizerGetDescent(Rasterizer* rasterizer);
|
||||
bool lovrRasterizerHasGlyph(Rasterizer* fontData, uint32_t character);
|
||||
bool lovrRasterizerHasGlyphs(Rasterizer* fontData, const char* str);
|
||||
void lovrRasterizerLoadGlyph(Rasterizer* fontData, uint32_t character, uint32_t padding, double spread, Glyph* glyph);
|
||||
int32_t lovrRasterizerGetKerning(Rasterizer* fontData, uint32_t left, uint32_t right);
|
||||
void lovrRasterizerMeasure(Rasterizer* rasterizer, const char* str, size_t length, float wrap, float* width, float* lastLineWidth, float* height, uint32_t* lineCount, uint32_t* glyphCount);
|
||||
float lovrRasterizerGetFontSize(Rasterizer* rasterizer);
|
||||
void lovrRasterizerGetBoundingBox(Rasterizer* rasterizer, float box[4]);
|
||||
uint32_t lovrRasterizerGetGlyphCount(Rasterizer* rasterizer);
|
||||
bool lovrRasterizerHasGlyph(Rasterizer* rasterizer, uint32_t codepoint);
|
||||
bool lovrRasterizerHasGlyphs(Rasterizer* rasterizer, const char* str, size_t length);
|
||||
float lovrRasterizerGetAscent(Rasterizer* rasterizer);
|
||||
float lovrRasterizerGetDescent(Rasterizer* rasterizer);
|
||||
float lovrRasterizerGetLineGap(Rasterizer* rasterizer);
|
||||
float lovrRasterizerGetLeading(Rasterizer* rasterizer);
|
||||
float lovrRasterizerGetKerning(Rasterizer* rasterizer, uint32_t prev, uint32_t next);
|
||||
float lovrRasterizerGetGlyphAdvance(Rasterizer* rasterizer, uint32_t codepoint);
|
||||
float lovrRasterizerGetGlyphBearing(Rasterizer* rasterizer, uint32_t codepoint);
|
||||
void lovrRasterizerGetGlyphBoundingBox(Rasterizer* rasterizer, uint32_t codepoint, float box[4]);
|
||||
bool lovrRasterizerIsGlyphEmpty(Rasterizer* rasterizer, uint32_t codepoint);
|
||||
void lovrRasterizerGetGlyphCurves(Rasterizer* rasterizer, uint32_t codepoint, void (*fn)(void* context, uint32_t degree, float* points), void* context);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "graphics/graphics.h"
|
||||
#include "data/blob.h"
|
||||
#include "data/image.h"
|
||||
#include "data/rasterizer.h"
|
||||
#include "headset/headset.h"
|
||||
#include "math/math.h"
|
||||
#include "core/gpu.h"
|
||||
|
@ -24,6 +25,18 @@ const char** os_vk_get_instance_extensions(uint32_t* count);
|
|||
#define MAX_SHADER_RESOURCES 32
|
||||
#define MATERIALS_PER_BLOCK 1024
|
||||
|
||||
typedef struct {
|
||||
struct { float x, y, z; } position;
|
||||
struct { float x, y, z; } normal;
|
||||
struct { float u, v; } uv;
|
||||
} ShapeVertex;
|
||||
|
||||
typedef struct {
|
||||
struct { float x, y; } position;
|
||||
struct { uint8_t r, g, b, a; } color;
|
||||
struct { uint16_t u, v; } uv;
|
||||
} GlyphVertex;
|
||||
|
||||
typedef struct {
|
||||
gpu_phase readPhase;
|
||||
gpu_phase writePhase;
|
||||
|
@ -109,6 +122,31 @@ struct Material {
|
|||
MaterialInfo info;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t codepoint;
|
||||
uint16_t atlas[4];
|
||||
float width;
|
||||
float height;
|
||||
float advance;
|
||||
float offsetX;
|
||||
float offsetY;
|
||||
} Glyph;
|
||||
|
||||
struct Font {
|
||||
uint32_t ref;
|
||||
FontInfo info;
|
||||
Material* material;
|
||||
arr_t(Glyph) glyphs;
|
||||
map_t glyphLookup;
|
||||
float pixelDensity;
|
||||
Texture* atlas;
|
||||
uint32_t atlasWidth;
|
||||
uint32_t atlasHeight;
|
||||
uint32_t rowHeight;
|
||||
uint32_t atlasX;
|
||||
uint32_t atlasY;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
float view[16];
|
||||
float projection[16];
|
||||
|
@ -139,9 +177,7 @@ typedef struct {
|
|||
typedef enum {
|
||||
VERTEX_SHAPE,
|
||||
VERTEX_POINT,
|
||||
VERTEX_MODEL,
|
||||
VERTEX_GLYPH,
|
||||
VERTEX_EMPTY,
|
||||
VERTEX_FORMAT_COUNT
|
||||
} VertexFormat;
|
||||
|
||||
|
@ -206,12 +242,6 @@ struct Pass {
|
|||
arr_t(Access) access;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct { float x, y, z; } position;
|
||||
struct { float x, y, z; } normal;
|
||||
struct { float u, v; } uv;
|
||||
} ShapeVertex;
|
||||
|
||||
typedef struct {
|
||||
Material* list;
|
||||
gpu_buffer* buffer;
|
||||
|
@ -267,9 +297,10 @@ static struct {
|
|||
Shader* defaultShaders[DEFAULT_SHADER_COUNT];
|
||||
gpu_vertex_format vertexFormats[VERTEX_FORMAT_COUNT];
|
||||
Material* defaultMaterial;
|
||||
MaterialBlock* materials;
|
||||
uint32_t materialBlock;
|
||||
arr_t(MaterialBlock) materialBlocks;
|
||||
arr_t(TempAttachment) attachments;
|
||||
arr_t(Pass*) passes;
|
||||
map_t pipelineLookup;
|
||||
arr_t(gpu_pipeline*) pipelines;
|
||||
arr_t(Layout) layouts;
|
||||
|
@ -340,6 +371,7 @@ bool lovrGraphicsInit(bool debug, bool vsync) {
|
|||
arr_init(&state.layouts, realloc);
|
||||
arr_init(&state.materialBlocks, realloc);
|
||||
arr_init(&state.attachments, realloc);
|
||||
arr_init(&state.passes, realloc);
|
||||
|
||||
gpu_slot builtinSlots[] = {
|
||||
{ 0, GPU_SLOT_UNIFORM_BUFFER, GPU_STAGE_ALL }, // Cameras
|
||||
|
@ -362,12 +394,20 @@ bool lovrGraphicsInit(bool debug, bool vsync) {
|
|||
|
||||
state.materialLayout = getLayout(materialSlots, COUNTOF(materialSlots));
|
||||
|
||||
float data[] = { 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f };
|
||||
|
||||
state.defaultBuffer = lovrBufferCreate(&(BufferInfo) {
|
||||
.length = 4096,
|
||||
.length = sizeof(data),
|
||||
.stride = 1,
|
||||
.label = "Default Buffer"
|
||||
}, NULL);
|
||||
|
||||
beginFrame();
|
||||
gpu_buffer* scratchpad = tempAlloc(gpu_sizeof_buffer());
|
||||
float* pointer = gpu_map(scratchpad, sizeof(data), 4, GPU_MAP_WRITE);
|
||||
memcpy(pointer, data, sizeof(data));
|
||||
gpu_copy_buffers(state.stream, scratchpad, state.defaultBuffer->gpu, 0, 0, sizeof(data));
|
||||
|
||||
Image* image = lovrImageCreateRaw(4, 4, FORMAT_RGBA8);
|
||||
|
||||
float white[4] = { 1.f, 1.f, 1.f, 1.f };
|
||||
|
@ -403,33 +443,42 @@ bool lovrGraphicsInit(bool debug, bool vsync) {
|
|||
});
|
||||
}
|
||||
|
||||
beginFrame();
|
||||
gpu_clear_buffer(state.stream, state.defaultBuffer->gpu, 0, 4096);
|
||||
|
||||
state.vertexFormats[VERTEX_SHAPE] = (gpu_vertex_format) {
|
||||
.bufferCount = 2,
|
||||
.attributeCount = 5,
|
||||
.bufferStrides[1] = sizeof(ShapeVertex),
|
||||
.attributes[0] = { 1, 10, offsetof(ShapeVertex, position), GPU_TYPE_F32x3 },
|
||||
.attributes[1] = { 1, 11, offsetof(ShapeVertex, normal), GPU_TYPE_F32x3 },
|
||||
.attributes[2] = { 1, 12, offsetof(ShapeVertex, uv), GPU_TYPE_F32x2 },
|
||||
.attributes[3] = { 0, 13, 0, GPU_TYPE_F32x4 },
|
||||
.attributes[4] = { 0, 14, 0, GPU_TYPE_F32x4 }
|
||||
.bufferStrides[0] = sizeof(ShapeVertex),
|
||||
.attributes[0] = { 0, 10, offsetof(ShapeVertex, position), GPU_TYPE_F32x3 },
|
||||
.attributes[1] = { 0, 11, offsetof(ShapeVertex, normal), GPU_TYPE_F32x3 },
|
||||
.attributes[2] = { 0, 12, offsetof(ShapeVertex, uv), GPU_TYPE_F32x2 },
|
||||
.attributes[3] = { 1, 13, 16, GPU_TYPE_F32x4 },
|
||||
.attributes[4] = { 1, 14, 0, GPU_TYPE_F32x4 }
|
||||
};
|
||||
|
||||
state.vertexFormats[VERTEX_POINT] = (gpu_vertex_format) {
|
||||
.bufferCount = 2,
|
||||
.attributeCount = 1,
|
||||
.bufferStrides[1] = 12,
|
||||
.attributes[0] = { 1, 10, 0, GPU_TYPE_F32x3 },
|
||||
.attributes[1] = { 0, 11, 0, GPU_TYPE_F32x4 },
|
||||
.attributes[2] = { 0, 12, 0, GPU_TYPE_F32x4 },
|
||||
.attributes[3] = { 0, 13, 0, GPU_TYPE_F32x4 },
|
||||
.attributes[4] = { 0, 14, 0, GPU_TYPE_F32x4 }
|
||||
.attributeCount = 5,
|
||||
.bufferStrides[2] = 12,
|
||||
.attributes[0] = { 0, 10, 0, GPU_TYPE_F32x3 },
|
||||
.attributes[1] = { 1, 11, 0, GPU_TYPE_F32x4 },
|
||||
.attributes[2] = { 1, 12, 0, GPU_TYPE_F32x4 },
|
||||
.attributes[3] = { 1, 13, 16, GPU_TYPE_F32x4 },
|
||||
.attributes[4] = { 1, 14, 0, GPU_TYPE_F32x4 }
|
||||
};
|
||||
|
||||
state.vertexFormats[VERTEX_GLYPH] = (gpu_vertex_format) {
|
||||
.bufferCount = 2,
|
||||
.attributeCount = 5,
|
||||
.bufferStrides[2] = 16,
|
||||
.attributes[0] = { 0, 10, offsetof(GlyphVertex, position), GPU_TYPE_F32x2 },
|
||||
.attributes[1] = { 1, 11, 0, GPU_TYPE_F32x4 },
|
||||
.attributes[2] = { 0, 12, offsetof(GlyphVertex, uv), GPU_TYPE_UN16x2 },
|
||||
.attributes[3] = { 0, 13, offsetof(GlyphVertex, color), GPU_TYPE_UN8x4 },
|
||||
.attributes[4] = { 1, 14, 0, GPU_TYPE_F32x4 }
|
||||
};
|
||||
|
||||
state.defaultMaterial = lovrMaterialCreate(&(MaterialInfo) {
|
||||
.data.color = { 1.f, 1.f, 1.f, 1.f }
|
||||
.data.color = { 1.f, 1.f, 1.f, 1.f },
|
||||
.texture = state.defaultTexture
|
||||
});
|
||||
|
||||
float16Init();
|
||||
|
@ -619,7 +668,7 @@ void lovrGraphicsSubmit(Pass** passes, uint32_t count) {
|
|||
for (uint32_t i = 0; i < count; i++) {
|
||||
Pass* pass = passes[i];
|
||||
|
||||
for (uint32_t j = 0; j < pass->access.length; j++) {
|
||||
for (size_t j = 0; j < pass->access.length; j++) {
|
||||
// access is the incoming resource access performed by the pass
|
||||
Access* access = &pass->access.data[j];
|
||||
|
||||
|
@ -693,9 +742,6 @@ void lovrGraphicsSubmit(Pass** passes, uint32_t count) {
|
|||
sync->pendingWrite = write;
|
||||
sync->lastWriteIndex = i + 1;
|
||||
}
|
||||
|
||||
lovrRelease(access->buffer, lovrBufferDestroy);
|
||||
lovrRelease(access->texture, lovrTextureDestroy);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -715,6 +761,26 @@ void lovrGraphicsSubmit(Pass** passes, uint32_t count) {
|
|||
|
||||
gpu_submit(streams, total);
|
||||
|
||||
// Clean up ALL passes created during the frame
|
||||
for (size_t i = 0; i < state.passes.length; i++) {
|
||||
Pass* pass = state.passes.data[i];
|
||||
|
||||
for (size_t j = 0; j < pass->access.length; j++) {
|
||||
Access* access = &pass->access.data[j];
|
||||
lovrRelease(access->buffer, lovrBufferDestroy);
|
||||
lovrRelease(access->texture, lovrTextureDestroy);
|
||||
}
|
||||
|
||||
for (size_t j = 0; j <= pass->pipelineIndex; j++) {
|
||||
lovrRelease(pass->pipelines[j].sampler, lovrSamplerDestroy);
|
||||
lovrRelease(pass->pipelines[j].shader, lovrShaderDestroy);
|
||||
lovrRelease(pass->pipelines[j].material, lovrMaterialDestroy);
|
||||
pass->pipelines[j].sampler = NULL;
|
||||
pass->pipelines[j].shader = NULL;
|
||||
pass->pipelines[j].material = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (state.window) {
|
||||
state.window->gpu = NULL;
|
||||
state.window->renderView = NULL;
|
||||
|
@ -1494,7 +1560,7 @@ const ShaderInfo* lovrShaderGetInfo(Shader* shader) {
|
|||
// Material
|
||||
|
||||
Material* lovrMaterialCreate(MaterialInfo* info) {
|
||||
MaterialBlock* block = state.materials;
|
||||
MaterialBlock* block = &state.materialBlocks.data[state.materialBlock];
|
||||
|
||||
if (!block || block->head == ~0u || !gpu_finished(block->list[block->head].tick)) {
|
||||
bool found = false;
|
||||
|
@ -1502,7 +1568,7 @@ Material* lovrMaterialCreate(MaterialInfo* info) {
|
|||
for (size_t i = 0; i < state.materialBlocks.length; i++) {
|
||||
block = &state.materialBlocks.data[i];
|
||||
if (block->head != ~0u && gpu_finished(block->list[block->head].tick)) {
|
||||
state.materials = block;
|
||||
state.materialBlock = i;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
@ -1510,8 +1576,8 @@ Material* lovrMaterialCreate(MaterialInfo* info) {
|
|||
|
||||
if (!found) {
|
||||
arr_expand(&state.materialBlocks, 1);
|
||||
uint32_t blockIndex = state.materialBlocks.length++;
|
||||
block = state.materials = &state.materialBlocks.data[blockIndex];
|
||||
state.materialBlock = state.materialBlocks.length++;
|
||||
block = &state.materialBlocks.data[state.materialBlock];
|
||||
block->list = malloc(MATERIALS_PER_BLOCK * sizeof(Material));
|
||||
block->buffer = malloc(gpu_sizeof_buffer());
|
||||
block->bundlePool = malloc(gpu_sizeof_bundle_pool());
|
||||
|
@ -1521,7 +1587,7 @@ Material* lovrMaterialCreate(MaterialInfo* info) {
|
|||
for (uint32_t i = 0; i < MATERIALS_PER_BLOCK; i++) {
|
||||
block->list[i].next = i + 1;
|
||||
block->list[i].tick = state.tick - 4;
|
||||
block->list[i].block = blockIndex;
|
||||
block->list[i].block = state.materialBlock;
|
||||
block->list[i].index = i;
|
||||
block->list[i].bundle = (gpu_bundle*) ((char*) block->bundles + i * gpu_sizeof_bundle());
|
||||
}
|
||||
|
@ -1549,6 +1615,7 @@ Material* lovrMaterialCreate(MaterialInfo* info) {
|
|||
block->head = material->next;
|
||||
material->next = ~0u;
|
||||
material->ref = 1;
|
||||
material->info = *info;
|
||||
|
||||
MaterialData* data;
|
||||
uint32_t stride = ALIGN(sizeof(MaterialData), state.limits.uniformBufferAlign);
|
||||
|
@ -1587,10 +1654,10 @@ Material* lovrMaterialCreate(MaterialInfo* info) {
|
|||
};
|
||||
|
||||
for (uint32_t i = 0; i < COUNTOF(textures); i++) {
|
||||
lovrRetain(textures[i]);
|
||||
Texture* texture = textures[i] ? textures[i] : state.defaultTexture;
|
||||
lovrCheck(texture->info.type == TEXTURE_2D, "Material textures must be 2D");
|
||||
bindings[i + 1] = (gpu_binding) { i + 1, GPU_SLOT_SAMPLED_TEXTURE, .texture = texture->gpu };
|
||||
lovrRetain(texture);
|
||||
}
|
||||
|
||||
gpu_bundle_info bundleInfo = {
|
||||
|
@ -1612,12 +1679,48 @@ void lovrMaterialDestroy(void* ref) {
|
|||
if (block->head == ~0u) block->head = block->tail;
|
||||
lovrRelease(material->info.texture, lovrTextureDestroy);
|
||||
lovrRelease(material->info.glowTexture, lovrTextureDestroy);
|
||||
lovrRelease(material->info.occlusionTexture, lovrTextureDestroy);
|
||||
lovrRelease(material->info.metalnessTexture, lovrTextureDestroy);
|
||||
lovrRelease(material->info.roughnessTexture, lovrTextureDestroy);
|
||||
lovrRelease(material->info.clearcoatTexture, lovrTextureDestroy);
|
||||
lovrRelease(material->info.normalTexture, lovrTextureDestroy);
|
||||
}
|
||||
|
||||
const MaterialInfo* lovrMaterialGetInfo(Material* material) {
|
||||
return &material->info;
|
||||
}
|
||||
|
||||
// Font
|
||||
|
||||
Font* lovrFontCreate(FontInfo* info) {
|
||||
Font* font = calloc(1, sizeof(Font));
|
||||
lovrAssert(font, "Out of memory");
|
||||
font->ref = 1;
|
||||
font->info = *info;
|
||||
lovrRetain(info->rasterizer);
|
||||
map_init(&font->glyphLookup, 36);
|
||||
arr_init(&font->glyphs, realloc);
|
||||
return font;
|
||||
}
|
||||
|
||||
void lovrFontDestroy(void* ref) {
|
||||
Font* font = ref;
|
||||
lovrRelease(font->info.rasterizer, lovrRasterizerDestroy);
|
||||
lovrRelease(font->material, lovrMaterialDestroy);
|
||||
lovrRelease(font->atlas, lovrTextureDestroy);
|
||||
map_free(&font->glyphLookup);
|
||||
arr_free(&font->glyphs);
|
||||
free(font);
|
||||
}
|
||||
|
||||
float lovrFontGetPixelDensity(Font* font) {
|
||||
return font->pixelDensity;
|
||||
}
|
||||
|
||||
void lovrFontSetPixelDensity(Font* font, float pixelDensity) {
|
||||
font->pixelDensity = pixelDensity;
|
||||
}
|
||||
|
||||
// Pass
|
||||
|
||||
Pass* lovrGraphicsGetPass(PassInfo* info) {
|
||||
|
@ -1627,6 +1730,8 @@ Pass* lovrGraphicsGetPass(PassInfo* info) {
|
|||
pass->info = *info;
|
||||
pass->stream = gpu_stream_begin(info->label);
|
||||
arr_init(&pass->access, tempGrow);
|
||||
arr_push(&state.passes, pass);
|
||||
lovrRetain(pass);
|
||||
|
||||
if (info->type == PASS_TRANSFER) {
|
||||
return pass;
|
||||
|
@ -1732,9 +1837,8 @@ Pass* lovrGraphicsGetPass(PassInfo* info) {
|
|||
|
||||
gpu_render_begin(pass->stream, &target);
|
||||
|
||||
// The default Buffer (filled with zero) is always at slot #0, used for missing vertex attributes
|
||||
uint32_t offset = 0;
|
||||
gpu_bind_vertex_buffers(pass->stream, &state.defaultBuffer->gpu, &offset, 0, 1);
|
||||
// The default Buffer (filled with zeros/ones) is always at slot #1, used for default vertex data
|
||||
gpu_bind_vertex_buffers(pass->stream, &state.defaultBuffer->gpu, NULL, 1, 1);
|
||||
|
||||
// Reset state
|
||||
|
||||
|
@ -1761,9 +1865,10 @@ Pass* lovrGraphicsGetPass(PassInfo* info) {
|
|||
memcpy(pass->pipeline->color, defaultColor, sizeof(defaultColor));
|
||||
pass->pipeline->formatHash = 0;
|
||||
pass->pipeline->shader = NULL;
|
||||
pass->pipeline->material = state.defaultMaterial;
|
||||
pass->pipeline->drawMode = VERTEX_TRIANGLES;
|
||||
pass->pipeline->dirty = true;
|
||||
pass->pipeline->material = state.defaultMaterial;
|
||||
lovrRetain(pass->pipeline->material);
|
||||
pass->materialDirty = true;
|
||||
|
||||
memset(pass->constants, 0, sizeof(pass->constants));
|
||||
|
@ -1790,6 +1895,7 @@ Pass* lovrGraphicsGetPass(PassInfo* info) {
|
|||
pass->builtins[2] = (gpu_binding) { 2, GPU_SLOT_SAMPLER, .sampler = NULL };
|
||||
pass->pipeline->sampler = state.defaultSamplers[FILTER_LINEAR];
|
||||
pass->samplerDirty = true;
|
||||
lovrRetain(pass->pipeline->sampler);
|
||||
|
||||
pass->vertexBuffer = NULL;
|
||||
pass->indexBuffer = NULL;
|
||||
|
@ -1844,8 +1950,9 @@ 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->shader);
|
||||
lovrRetain(pass->pipeline->sampler);
|
||||
lovrRetain(pass->pipeline->shader);
|
||||
lovrRetain(pass->pipeline->material);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
@ -1858,7 +1965,9 @@ 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->sampler, lovrSamplerDestroy);
|
||||
lovrRelease(pass->pipeline->shader, lovrShaderDestroy);
|
||||
lovrRelease(pass->pipeline->material, lovrMaterialDestroy);
|
||||
pass->pipeline = &pass->pipelines[--pass->pipelineIndex];
|
||||
lovrCheck(pass->pipelineIndex < COUNTOF(pass->pipelines), "%s stack underflow (more pops than pushes?)", "Pipeline");
|
||||
gpu_set_viewport(pass->stream, pass->pipeline->viewport, pass->pipeline->depthRange);
|
||||
|
@ -2076,7 +2185,9 @@ void lovrPassSetShader(Pass* pass, Shader* shader) {
|
|||
pass->bindings[i].type = shader->resources[i].type;
|
||||
|
||||
if (shader->bufferMask & bit) {
|
||||
pass->bindings[i].buffer = (gpu_buffer_binding) { state.defaultBuffer->gpu, 0, 4096 };
|
||||
pass->bindings[i].buffer.object = state.defaultBuffer->gpu;
|
||||
pass->bindings[i].buffer.offset = 0;
|
||||
pass->bindings[i].buffer.extent = state.defaultBuffer->size;
|
||||
} else if (shader->textureMask & bit) {
|
||||
pass->bindings[i].texture = state.defaultTexture->gpu;
|
||||
} else if (shader->samplerMask & bit) {
|
||||
|
@ -2291,10 +2402,10 @@ static void flushPipeline(Pass* pass, Draw* draw, Shader* shader) {
|
|||
for (uint32_t i = 0; i < shader->attributeCount; i++) {
|
||||
if (shader->attributes[i].location < 10) {
|
||||
pipeline->info.vertex.attributes[pipeline->info.vertex.attributeCount++] = (gpu_attribute) {
|
||||
.buffer = 0,
|
||||
.buffer = 1,
|
||||
.location = shader->attributes[i].location,
|
||||
.type = GPU_TYPE_F32x4,
|
||||
.offset = 0
|
||||
.offset = shader->attributes[i].location == LOCATION_COLOR ? 16 : 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -2306,8 +2417,8 @@ static void flushPipeline(Pass* pass, Draw* draw, Shader* shader) {
|
|||
pipeline->formatHash = draw->vertex.buffer->hash;
|
||||
pipeline->info.vertex.bufferCount = 2;
|
||||
pipeline->info.vertex.attributeCount = shader->attributeCount;
|
||||
pipeline->info.vertex.bufferStrides[0] = 0;
|
||||
pipeline->info.vertex.bufferStrides[1] = draw->vertex.buffer->info.stride;
|
||||
pipeline->info.vertex.bufferStrides[0] = draw->vertex.buffer->info.stride;
|
||||
pipeline->info.vertex.bufferStrides[1] = 0;
|
||||
pipeline->dirty = true;
|
||||
|
||||
for (uint32_t i = 0; i < shader->attributeCount; i++) {
|
||||
|
@ -2318,7 +2429,7 @@ static void flushPipeline(Pass* pass, Draw* draw, Shader* shader) {
|
|||
BufferField field = draw->vertex.buffer->info.fields[j];
|
||||
if (field.hash ? (field.hash == attribute->hash) : (field.location == attribute->location)) {
|
||||
pipeline->info.vertex.attributes[i] = (gpu_attribute) {
|
||||
.buffer = 1,
|
||||
.buffer = 0,
|
||||
.location = attribute->location,
|
||||
.offset = field.offset,
|
||||
.type = field.type
|
||||
|
@ -2330,9 +2441,9 @@ static void flushPipeline(Pass* pass, Draw* draw, Shader* shader) {
|
|||
|
||||
if (!found) {
|
||||
pipeline->info.vertex.attributes[i] = (gpu_attribute) {
|
||||
.buffer = 0,
|
||||
.buffer = 1,
|
||||
.location = attribute->location,
|
||||
.offset = 0,
|
||||
.offset = attribute->location == LOCATION_COLOR ? 16 : 0,
|
||||
.type = GPU_TYPE_F32x4
|
||||
};
|
||||
}
|
||||
|
@ -2460,11 +2571,9 @@ static void flushMaterial(Pass* pass, Draw* draw, Shader* shader) {
|
|||
}
|
||||
|
||||
static void flushBuffers(Pass* pass, Draw* draw) {
|
||||
uint32_t vertexOffset = 0;
|
||||
|
||||
if (!draw->vertex.buffer && draw->vertex.count > 0) {
|
||||
lovrCheck(draw->vertex.count < UINT16_MAX, "This draw has too many vertices (max is 65534), try splitting it up into multiple draws or using a Buffer");
|
||||
uint32_t stride = state.vertexFormats[draw->vertex.format].bufferStrides[1];
|
||||
uint32_t stride = state.vertexFormats[draw->vertex.format].bufferStrides[0];
|
||||
uint32_t size = draw->vertex.count * stride;
|
||||
|
||||
gpu_buffer* scratchpad = tempAlloc(gpu_sizeof_buffer());
|
||||
|
@ -2476,11 +2585,11 @@ static void flushBuffers(Pass* pass, Draw* draw) {
|
|||
memcpy(pointer, draw->vertex.data, size);
|
||||
}
|
||||
|
||||
gpu_bind_vertex_buffers(pass->stream, &scratchpad, &vertexOffset, 1, 1);
|
||||
gpu_bind_vertex_buffers(pass->stream, &scratchpad, NULL, 0, 1);
|
||||
pass->vertexBuffer = NULL;
|
||||
} else if (draw->vertex.buffer && draw->vertex.buffer->gpu != pass->vertexBuffer) {
|
||||
lovrCheck(draw->vertex.buffer->info.stride <= state.limits.vertexBufferStride, "Vertex buffer stride exceeds vertexBufferStride limit");
|
||||
gpu_bind_vertex_buffers(pass->stream, &draw->vertex.buffer->gpu, &vertexOffset, 1, 1);
|
||||
gpu_bind_vertex_buffers(pass->stream, &draw->vertex.buffer->gpu, NULL, 0, 1);
|
||||
pass->vertexBuffer = draw->vertex.buffer->gpu;
|
||||
trackBuffer(pass, draw->vertex.buffer, GPU_PHASE_INPUT_VERTEX, GPU_CACHE_VERTEX);
|
||||
}
|
||||
|
@ -2957,6 +3066,8 @@ static void beginFrame(void) {
|
|||
state.active = true;
|
||||
state.tick = gpu_begin();
|
||||
state.stream = gpu_stream_begin("Internal uploads");
|
||||
state.allocator.cursor = 0;
|
||||
arr_clear(&state.passes);
|
||||
}
|
||||
|
||||
static uint32_t getLayout(gpu_slot* slots, uint32_t count) {
|
||||
|
|
|
@ -6,12 +6,14 @@
|
|||
|
||||
struct Blob;
|
||||
struct Image;
|
||||
struct Rasterizer;
|
||||
|
||||
typedef struct Buffer Buffer;
|
||||
typedef struct Texture Texture;
|
||||
typedef struct Sampler Sampler;
|
||||
typedef struct Shader Shader;
|
||||
typedef struct Material Material;
|
||||
typedef struct Font Font;
|
||||
typedef struct Pass Pass;
|
||||
|
||||
typedef struct {
|
||||
|
@ -316,6 +318,20 @@ Material* lovrMaterialCreate(MaterialInfo* info);
|
|||
void lovrMaterialDestroy(void* ref);
|
||||
const MaterialInfo* lovrMaterialGetInfo(Material* material);
|
||||
|
||||
// Font
|
||||
|
||||
typedef struct {
|
||||
struct Rasterizer* rasterizer;
|
||||
uint32_t padding;
|
||||
double spread;
|
||||
} FontInfo;
|
||||
|
||||
Font* lovrFontCreate(FontInfo* info);
|
||||
void lovrFontDestroy(void* ref);
|
||||
const FontInfo* lovrFontGetInfo(Font* font);
|
||||
float lovrFontGetPixelDensity(Font* font);
|
||||
void lovrFontSetPixelDensity(Font* font, float pixelDensity);
|
||||
|
||||
// Pass
|
||||
|
||||
typedef enum {
|
||||
|
@ -351,6 +367,12 @@ typedef enum {
|
|||
CULL_BACK
|
||||
} CullMode;
|
||||
|
||||
typedef enum {
|
||||
ALIGN_LEFT,
|
||||
ALIGN_CENTER,
|
||||
ALIGN_RIGHT
|
||||
} HorizontalAlign;
|
||||
|
||||
typedef enum {
|
||||
STENCIL_KEEP,
|
||||
STENCIL_ZERO,
|
||||
|
@ -368,6 +390,12 @@ typedef enum {
|
|||
VERTEX_TRIANGLES
|
||||
} VertexMode;
|
||||
|
||||
typedef enum {
|
||||
ALIGN_TOP,
|
||||
ALIGN_MIDDLE,
|
||||
ALIGN_BOTTOM
|
||||
} VerticalAlign;
|
||||
|
||||
typedef enum {
|
||||
WINDING_COUNTERCLOCKWISE,
|
||||
WINDING_CLOCKWISE
|
||||
|
|
Loading…
Reference in New Issue