Font alignment;

This commit is contained in:
bjorn 2017-03-15 20:12:56 -07:00
parent a6cb4ee53f
commit 390220f945
7 changed files with 78 additions and 37 deletions

View File

@ -11,11 +11,13 @@ map_int_t BlendModes;
map_int_t CompareModes;
map_int_t DrawModes;
map_int_t FilterModes;
map_int_t HorizontalAligns;
map_int_t MeshAttributeTypes;
map_int_t MeshDrawModes;
map_int_t MeshUsages;
map_int_t PolygonWindings;
map_int_t TextureProjections;
map_int_t VerticalAligns;
map_int_t WrapModes;
static void luax_readvertices(lua_State* L, int index, vec_float_t* points) {
@ -103,6 +105,11 @@ int l_lovrGraphicsInit(lua_State* L) {
map_set(&FilterModes, "nearest", FILTER_NEAREST);
map_set(&FilterModes, "linear", FILTER_LINEAR);
map_init(&HorizontalAligns);
map_set(&HorizontalAligns, "left", ALIGN_LEFT);
map_set(&HorizontalAligns, "right", ALIGN_RIGHT);
map_set(&HorizontalAligns, "center", ALIGN_CENTER);
map_init(&MeshAttributeTypes);
map_set(&MeshAttributeTypes, "float", MESH_FLOAT);
map_set(&MeshAttributeTypes, "byte", MESH_BYTE);
@ -127,6 +134,11 @@ int l_lovrGraphicsInit(lua_State* L) {
map_set(&TextureProjections, "2d", PROJECTION_ORTHOGRAPHIC);
map_set(&TextureProjections, "3d", PROJECTION_PERSPECTIVE);
map_init(&VerticalAligns);
map_set(&VerticalAligns, "top", ALIGN_TOP);
map_set(&VerticalAligns, "bottom", ALIGN_BOTTOM);
map_set(&VerticalAligns, "middle", ALIGN_MIDDLE);
map_init(&WrapModes);
map_set(&WrapModes, "clamp", WRAP_CLAMP);
map_set(&WrapModes, "repeat", WRAP_REPEAT);
@ -524,16 +536,12 @@ int l_lovrGraphicsCube(lua_State* L) {
int l_lovrGraphicsPrint(lua_State* L) {
const char* str = luaL_checkstring(L, 1);
float x = luaL_optnumber(L, 2, 0);
float y = luaL_optnumber(L, 3, 0);
float z = luaL_optnumber(L, 4, 0);
float w = luaL_optnumber(L, 5, 0);
float h = luaL_optnumber(L, 6, .1);
float angle = luaL_optnumber(L, 7, 0);
float ax = luaL_optnumber(L, 8, 0);
float ay = luaL_optnumber(L, 9, 1);
float az = luaL_optnumber(L, 10, 0);
lovrGraphicsPrint(str, x, y, z, w, h, angle, ax, ay, az);
float transform[16];
int index = luax_readtransform(L, 2, transform);
float wrap = luaL_optnumber(L, index++, 0);
HorizontalAlign halign = *(HorizontalAlign*) luax_optenum(L, index++, "center", &HorizontalAligns, "alignment");
VerticalAlign valign = *(VerticalAlign*) luax_optenum(L, index++, "middle", &VerticalAligns, "alignment");
lovrGraphicsPrint(str, transform, wrap, halign, valign);
return 0;
}

View File

@ -37,13 +37,15 @@ extern map_int_t DrawModes;
extern map_int_t EventTypes;
extern map_int_t FilterModes;
extern map_int_t HeadsetEyes;
extern map_int_t HorizontalAligns;
extern map_int_t MeshAttributeTypes;
extern map_int_t MeshDrawModes;
extern map_int_t MeshUsages;
extern map_int_t PolygonWindings;
extern map_int_t TextureProjections;
extern map_int_t TimeUnits;
extern map_int_t VerticalAligns;
extern map_int_t WrapModes;
void luax_checkmeshformat(lua_State* L, int index, MeshFormat* format);
void luax_readtransform(lua_State* L, int i, mat4 transform);
int luax_readtransform(lua_State* L, int i, mat4 transform);

View File

@ -2,7 +2,7 @@
#include "math/mat4.h"
#include "math/transform.h"
void luax_readtransform(lua_State* L, int i, mat4 m) {
int luax_readtransform(lua_State* L, int i, mat4 m) {
if (lua_isnumber(L, i)) {
float x = luaL_optnumber(L, i++, 0);
float y = luaL_optnumber(L, i++, 0);
@ -13,11 +13,14 @@ void luax_readtransform(lua_State* L, int i, mat4 m) {
float ay = luaL_optnumber(L, i++, 1);
float az = luaL_optnumber(L, i++, 0);
mat4_setTransform(m, x, y, z, s, angle, ax, ay, az);
return i;
} else if (lua_isnoneornil(L, i)) {
mat4_identity(m);
return i;
} else {
Transform* transform = luax_checktype(L, i, Transform);
mat4_init(m, transform->matrix);
return ++i;
}
}

View File

@ -8,6 +8,20 @@
#include <stdlib.h>
#include <stdio.h>
static int lovrFontAlignLine(vec_float_t* vertices, int index, float width, HorizontalAlign halign) {
while (index < vertices->length) {
if (halign == ALIGN_CENTER) {
vertices->data[index] -= width / 2;
} else if (halign == ALIGN_RIGHT) {
vertices->data[index] -= width;
}
index += 5;
}
return index;
}
Font* lovrFontCreate(FontData* fontData) {
Font* font = lovrAlloc(sizeof(Font), lovrFontDestroy);
if (!font) return NULL;
@ -52,14 +66,14 @@ void lovrFontDestroy(const Ref* ref) {
free(font);
}
void lovrFontPrint(Font* font, const char* str, float x, float y, float z, float w, float h, float angle, float ax, float ay, float az) {
void lovrFontPrint(Font* font, const char* str, mat4 transform, float wrap, HorizontalAlign halign, VerticalAlign valign) {
FontAtlas* atlas = &font->atlas;
float cx = 0;
float cy = -font->fontData->height * font->lineHeight / 2;
float cy = -font->fontData->height * .8;
float u = atlas->width;
float v = atlas->height;
float scale = h / font->fontData->height;
float scale = 1 / (float) font->fontData->height;
int len = strlen(str);
const char* start = str;
@ -69,6 +83,7 @@ void lovrFontPrint(Font* font, const char* str, float x, float y, float z, float
size_t bytes;
int linePtr = 0;
int lineCount = 1;
vec_reserve(&font->vertices, len * 30);
vec_clear(&font->vertices);
@ -76,16 +91,11 @@ void lovrFontPrint(Font* font, const char* str, float x, float y, float z, float
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
// Newlines
if (codepoint == '\n' || (w && cx > w / scale && codepoint == ' ')) {
// Center the line
while (linePtr < font->vertices.length) {
font->vertices.data[linePtr] -= cx / 2;
linePtr += 5;
}
if (codepoint == '\n' || (wrap && cx * scale > wrap && codepoint == ' ')) {
linePtr = lovrFontAlignLine(&font->vertices, linePtr, cx, halign);
lineCount++;
cx = 0;
cy -= font->fontData->size * font->lineHeight;
cy -= font->fontData->height * font->lineHeight;
previous = '\0';
str += bytes;
continue;
@ -100,7 +110,7 @@ void lovrFontPrint(Font* font, const char* str, float x, float y, float z, float
// Start over if texture was repacked
if (u != atlas->width || v != atlas->height) {
lovrFontPrint(font, start, x, y, z, w, h, angle, ax, ay, az);
lovrFontPrint(font, start, transform, wrap, halign, valign);
return;
}
@ -132,20 +142,25 @@ void lovrFontPrint(Font* font, const char* str, float x, float y, float z, float
str += bytes;
}
// Center the last line
while (linePtr < font->vertices.length) {
font->vertices.data[linePtr] -= cx / 2;
linePtr += 5;
// Align the last line
lovrFontAlignLine(&font->vertices, linePtr, cx, halign);
// Calculate vertical offset
float offsety = 0;
if (valign == ALIGN_MIDDLE) {
offsety = lineCount * font->fontData->height * font->lineHeight * .5f;
} else if (valign == ALIGN_BOTTOM) {
offsety = lineCount * font->fontData->height * font->lineHeight;
}
// We override the depth test to LEQUAL to prevent blending issues with glyphs, not great
CompareMode oldCompareMode = lovrGraphicsGetDepthTest();
// Render!
lovrGraphicsPush();
lovrGraphicsTranslate(x, y, z);
lovrGraphicsMatrixTransform(transform);
lovrGraphicsScale(scale, scale, scale);
lovrGraphicsRotate(angle, ax, ay, az);
lovrGraphicsTranslate(0, -cy / 2, 0);
lovrGraphicsTranslate(0, offsety, 0);
lovrGraphicsSetDepthTest(COMPARE_LEQUAL);
lovrGraphicsBindTexture(font->texture);
lovrGraphicsSetShapeData(font->vertices.data, font->vertices.length);

View File

@ -1,12 +1,25 @@
#include "loaders/font.h"
#include "util.h"
#include "graphics/texture.h"
#include "math/math.h"
#include "lib/map/map.h"
#include "lib/vec/vec.h"
#include <stdint.h>
#pragma once
typedef enum {
ALIGN_LEFT,
ALIGN_RIGHT,
ALIGN_CENTER
} HorizontalAlign;
typedef enum {
ALIGN_TOP,
ALIGN_BOTTOM,
ALIGN_MIDDLE
} VerticalAlign;
typedef struct {
int x;
int y;
@ -24,12 +37,12 @@ typedef struct {
FontAtlas atlas;
map_int_t kerning;
vec_float_t vertices;
int lineHeight;
float lineHeight;
} Font;
Font* lovrFontCreate(FontData* fontData);
void lovrFontDestroy(const Ref* ref);
void lovrFontPrint(Font* font, const char* str, float x, float y, float z, float w, float h, float angle, float ax, float ay, float az);
void lovrFontPrint(Font* font, const char* str, mat4 transform, float wrap, HorizontalAlign halign, VerticalAlign valign);
float lovrFontGetLineHeight(Font* font);
void lovrFontSetLineHeight(Font* font, float lineHeight);
int lovrFontGetKerning(Font* font, unsigned int a, unsigned int b);

View File

@ -806,7 +806,7 @@ void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float a
lovrGraphicsPop();
}
void lovrGraphicsPrint(const char* str, float x, float y, float z, float w, float h, float angle, float ax, float ay, float az) {
void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAlign halign, VerticalAlign valign) {
lovrGraphicsEnsureFont();
lovrFontPrint(state.activeFont, str, x, y, z, w, h, angle, ax, ay, az);
lovrFontPrint(state.activeFont, str, transform, wrap, halign, valign);
}

View File

@ -162,4 +162,4 @@ void lovrGraphicsPlane(DrawMode mode, Texture* texture, float x, float y, float
void lovrGraphicsPlaneFullscreen(Texture* texture);
void lovrGraphicsCube(DrawMode mode, Texture* texture, mat4 transform);
void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float az);
void lovrGraphicsPrint(const char* str, float x, float y, float z, float w, float h, float angle, float ax, float ay, float az);
void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAlign halign, VerticalAlign valign);