Compare commits

...

7 Commits

Author SHA1 Message Date
bjorn af8c061c50 Default buffer can be used for colors; 2022-06-18 23:31:51 -07:00
bjorn a654cec40f lovr.graphics.newFont; 2022-06-18 17:43:12 -07:00
bjorn b89c61a8f4 HorizontalAlign and VerticalAlign enums; 2022-06-18 17:41:10 -07:00
bjorn 3c5288e979 Default fragment shader samples default texture; 2022-06-18 17:40:34 -07:00
bjorn 0d7fed1fa7 Rasterizer:getBoundingBox;
For the global bounding box
2022-06-18 17:40:14 -07:00
bjorn 717f95f6bd Start updating Rasterizer; 2022-06-17 17:43:58 -07:00
bjorn cb121d3d36 Material fixes; Pass cleanup; 2022-06-17 17:43:26 -07:00
10 changed files with 553 additions and 289 deletions

View File

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

View File

@ -5,5 +5,5 @@
#include "lovr.glsl"
void main() {
PixelColors[0] = FragColor;
PixelColors[0] = FragColor * texture(sampler2D(Texture, Sampler), FragUV);
}

View File

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

View File

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

View File

@ -0,0 +1,7 @@
#include "api.h"
#include <lua.h>
#include <lauxlib.h>
const luaL_Reg lovrFont[] = {
{ NULL, NULL }
};

View File

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

View File

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

View File

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

View File

@ -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) {

View File

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