Really terrible font rendering;

This commit is contained in:
bjorn 2017-02-03 15:16:30 -08:00
parent 853e9d89d7
commit ab2d0ee79a
12 changed files with 320 additions and 46 deletions

121
src/graphics/font.c Normal file
View File

@ -0,0 +1,121 @@
#include "graphics/font.h"
#include "graphics/graphics.h"
#include "graphics/texture.h"
#include "math/math.h"
#include "loaders/font.h"
#include "loaders/texture.h"
#include "vendor/vec/vec.h"
#include <string.h>
static vec_float_t scratch;
Font* lovrFontCreate(FontData* fontData) {
Font* font = lovrAlloc(sizeof(Font), lovrFontDestroy);
if (!font) return NULL;
font->fontData = fontData;
font->padding = 1;
font->tx = font->padding;
font->ty = font->padding;
font->tw = 256;
font->th = 256;
TextureData* textureData = lovrTextureDataGetBlank(font->tw, font->th, 0x00, FORMAT_RG);
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
font->texture = lovrTextureCreate(textureData);
lovrTextureSetWrap(font->texture, WRAP_CLAMP, WRAP_CLAMP);
int swizzle[] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
map_init(&font->glyphs);
return font;
}
void lovrFontDestroy(const Ref* ref) {
Font* font = containerof(ref, Font);
lovrFontDataDestroy(font->fontData);
free(font);
}
void lovrFontDataDestroy(FontData* fontData) {
// TODO
free(fontData);
}
void lovrFontPrint(Font* font, const char* str) {
vec_reserve(&scratch, strlen(str) * 30);
vec_clear(&scratch);
// Cursor
float x = 0;
float y = 0;
for (unsigned int i = 0; i < strlen(str); i++) {
Glyph* glyph = lovrFontGetGlyph(font, str[i]);
float s = glyph->s;
float t = glyph->t;
float w = glyph->glyphData->w;
float h = glyph->glyphData->h;
float xx = x + glyph->glyphData->x;
float yy = y - glyph->glyphData->y;
float v[30] = {
xx, yy, -5, s, t + h / font->th,
xx, yy + h, -5, s, t,
xx + w, yy, -5, s + w / font->tw, t + h / font->th,
xx + w, yy, -5, s + w / font->tw, t + h / font->th,
xx, yy + h, -5, s, t,
xx + w, yy + h, -5, s + w / font->tw, t
};
x += glyph->glyphData->advance;
vec_pusharr(&scratch, v, 30);
}
lovrGraphicsSetShapeData(scratch.data, scratch.length);
lovrGraphicsDrawPrimitive(GL_TRIANGLES, font->texture, 0, 1, 0);
}
Glyph* lovrFontGetGlyph(Font* font, char character) {
// Return the glyph if it's already loaded
char key[2] = { character, '\0' };
Glyph** g = (Glyph**) map_get(&font->glyphs, key);
if (g) return *g;
// Otherwise, load it (3 mallocs isn't great FIXME)
Glyph* glyph = malloc(sizeof(Glyph));
glyph->glyphData = lovrFontDataCreateGlyph(font->fontData, character);
// Put the glyph somewhere, expanding texture as necessary
while (font->tx + glyph->glyphData->w > font->tw - 2 * font->padding) {
while (font->ty + glyph->glyphData->h > font->th - 2 * font->padding) {
// Expand texture
}
font->tx = font->padding;
font->ty += font->rowHeight;
font->rowHeight = 0;
}
// Calculate texture coordinate
glyph->s = font->tx / (float) font->tw;
glyph->t = font->ty / (float) font->th;
// Upload glyph to texture
lovrGraphicsBindTexture(font->texture);
glTexSubImage2D(
GL_TEXTURE_2D, 0,
font->tx, font->ty, glyph->glyphData->w, glyph->glyphData->h,
GL_RG, GL_UNSIGNED_BYTE, glyph->glyphData->data
);
// Advance the texture cursor
font->tx += glyph->glyphData->w;
font->rowHeight = MAX(font->rowHeight, glyph->glyphData->h);
// Write glyph to cache
map_set(&font->glyphs, key, glyph);
return glyph;
}

View File

@ -1,14 +1,45 @@
#include "util.h"
#include "graphics/texture.h"
#include "vendor/map/map.h"
#include <stdint.h>
#pragma once
typedef struct {
int width;
int height;
int x;
int y;
int w;
int h;
int advance;
uint8_t* data;
} GlyphData;
typedef struct {
void* rasterizer;
} FontData;
// GlyphData along with the glyph's position in the texture atlas
typedef struct {
GlyphData* glyphData;
float s;
float t;
} Glyph;
typedef struct {
void* face;
} FontData;
typedef struct {
FontData fontData;
Ref ref;
FontData* fontData;
Texture* texture;
int tx;
int ty;
int tw;
int th;
int rowHeight;
int padding;
map_void_t glyphs;
} Font;
Font* lovrFontCreate(FontData* fontData);
void lovrFontDestroy(const Ref* ref);
void lovrFontDataDestroy(FontData* fontData);
void lovrFontPrint(Font* font, const char* str);
Glyph* lovrFontGetGlyph(Font* font, char character);

View File

@ -21,7 +21,7 @@ void lovrGraphicsInit() {
state.fullscreenShader = lovrShaderCreate(lovrNoopVertexShader, lovrDefaultFragmentShader);
int uniformId = lovrShaderGetUniformId(state.skyboxShader, "cube");
lovrShaderSendInt(state.skyboxShader, uniformId, 1);
state.defaultTexture = lovrTextureCreate(lovrTextureDataGetBlank(1, 1, 0xff));
state.defaultTexture = lovrTextureCreate(lovrTextureDataGetBlank(1, 1, 0xff, FORMAT_RGBA));
glGenBuffers(1, &state.shapeBuffer);
glGenBuffers(1, &state.shapeIndexBuffer);
glGenVertexArrays(1, &state.shapeArray);
@ -182,6 +182,14 @@ void lovrGraphicsSetShader(Shader* shader) {
}
}
Font* lovrGraphicsGetFont() {
return state.activeFont;
}
void lovrGraphicsSetFont(Font* font) {
state.activeFont = font;
}
void lovrGraphicsBindTexture(Texture* texture) {
if (!texture) {
texture = state.defaultTexture;
@ -348,6 +356,16 @@ void lovrGraphicsMatrixTransform(mat4 transform) {
// Primitives
void lovrGraphicsSetShapeData(float* data, int length) {
vec_clear(&state.shapeData);
vec_pusharr(&state.shapeData, data, length);
}
void lovrGraphicsSetIndexData(unsigned int* data, int length) {
vec_clear(&state.shapeIndices);
vec_pusharr(&state.shapeIndices, data, length);
}
void lovrGraphicsDrawPrimitive(GLenum mode, Texture* texture, int hasNormals, int hasTexCoords, int useIndices) {
int stride = 3 + (hasNormals ? 3 : 0) + (hasTexCoords ? 2 : 0);
int strideBytes = stride * sizeof(float);
@ -387,21 +405,18 @@ void lovrGraphicsDrawPrimitive(GLenum mode, Texture* texture, int hasNormals, in
}
void lovrGraphicsPoints(float* points, int count) {
vec_clear(&state.shapeData);
vec_pusharr(&state.shapeData, points, count);
lovrGraphicsSetShapeData(points, count);
lovrGraphicsDrawPrimitive(GL_POINTS, NULL, 0, 0, 0);
}
void lovrGraphicsLine(float* points, int count) {
vec_clear(&state.shapeData);
vec_pusharr(&state.shapeData, points, count);
lovrGraphicsSetShapeData(points, count);
lovrGraphicsDrawPrimitive(GL_LINE_STRIP, NULL, 0, 0, 0);
}
void lovrGraphicsTriangle(DrawMode mode, float* points) {
if (mode == DRAW_MODE_LINE) {
vec_clear(&state.shapeData);
vec_pusharr(&state.shapeData, points, 9);
lovrGraphicsSetShapeData(points, 9);
lovrGraphicsDrawPrimitive(GL_LINE_LOOP, NULL, 0, 0, 0);
} else {
float normal[3];
@ -413,8 +428,7 @@ void lovrGraphicsTriangle(DrawMode mode, float* points) {
points[6], points[7], points[8], normal[0], normal[1], normal[2]
};
vec_clear(&state.shapeData);
vec_pusharr(&state.shapeData, data, 18);
lovrGraphicsSetShapeData(data, 18);
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, NULL, 1, 0, 0);
}
}
@ -452,8 +466,7 @@ void lovrGraphicsPlane(DrawMode mode, Texture* texture, float x, float y, float
-.5, -.5, 0
};
vec_clear(&state.shapeData);
vec_pusharr(&state.shapeData, points, 12);
lovrGraphicsSetShapeData(points, 12);
lovrGraphicsDrawPrimitive(GL_LINE_LOOP, NULL, 0, 0, 0);
} else if (mode == DRAW_MODE_FILL) {
float data[] = {
@ -463,8 +476,7 @@ void lovrGraphicsPlane(DrawMode mode, Texture* texture, float x, float y, float
.5, -.5, 0, 0, 0, -1, 1, 1
};
vec_clear(&state.shapeData);
vec_pusharr(&state.shapeData, data, 32);
lovrGraphicsSetShapeData(data, 32);
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, texture, 1, 1, 0);
}
@ -483,8 +495,7 @@ void lovrGraphicsPlaneFullscreen(Texture* texture) {
lovrRetain(&lastShader->ref);
lovrGraphicsSetShader(state.fullscreenShader);
vec_clear(&state.shapeData);
vec_pusharr(&state.shapeData, data, 20);
lovrGraphicsSetShapeData(data, 20);
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, texture, 0, 1, 0);
lovrGraphicsSetShader(lastShader);
@ -516,10 +527,8 @@ void lovrGraphicsCube(DrawMode mode, Texture* texture, mat4 transform) {
0, 4, 1, 5, 2, 6, 3, 7 // Connections
};
vec_clear(&state.shapeData);
vec_pusharr(&state.shapeData, points, 24);
vec_clear(&state.shapeIndices);
vec_pusharr(&state.shapeIndices, indices, 24);
lovrGraphicsSetShapeData(points, 24);
lovrGraphicsSetIndexData(indices, 24);
lovrGraphicsDrawPrimitive(GL_LINES, NULL, 0, 0, 1);
} else {
float data[] = {
@ -564,8 +573,7 @@ void lovrGraphicsCube(DrawMode mode, Texture* texture, mat4 transform) {
.5, .5, .5, 0, 1, 0, 1, 0
};
vec_clear(&state.shapeData);
vec_pusharr(&state.shapeData, data, 208);
lovrGraphicsSetShapeData(data, 208);
lovrGraphicsDrawPrimitive(GL_TRIANGLE_STRIP, texture, 1, 1, 0);
}
@ -624,8 +632,7 @@ void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float a
1.f, 1.f, 1.f
};
vec_clear(&state.shapeData);
vec_pusharr(&state.shapeData, cube, 156);
lovrGraphicsSetShapeData(cube, 156);
glDepthMask(GL_FALSE);
glActiveTexture(GL_TEXTURE1);
@ -644,3 +651,7 @@ void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float a
lovrRelease(&lastShader->ref);
lovrGraphicsPop();
}
void lovrGraphicsPrint(const char* str) {
lovrFontPrint(state.activeFont, str);
}

View File

@ -1,4 +1,5 @@
#include "graphics/buffer.h"
#include "graphics/font.h"
#include "graphics/model.h"
#include "graphics/shader.h"
#include "graphics/skybox.h"
@ -48,6 +49,7 @@ typedef struct {
Shader* defaultShader;
Shader* skyboxShader;
Shader* fullscreenShader;
Font* activeFont;
Texture* defaultTexture;
float transforms[MAX_TRANSFORMS][16];
CanvasState* canvases[MAX_CANVASES];
@ -91,6 +93,8 @@ void lovrGraphicsGetScissor(int* x, int* y, int* width, int* height);
void lovrGraphicsSetScissor(int x, int y, int width, int height);
Shader* lovrGraphicsGetShader();
void lovrGraphicsSetShader(Shader* shader);
Font* lovrGraphicsGetFont();
void lovrGraphicsSetFont(Font* font);
void lovrGraphicsBindTexture(Texture* texture);
mat4 lovrGraphicsGetProjection();
void lovrGraphicsSetProjection(float near, float far, float fov);
@ -124,6 +128,8 @@ void lovrGraphicsScale(float x, float y, float z);
void lovrGraphicsMatrixTransform(mat4 transform);
// Primitives
void lovrGraphicsSetShapeData(float* data, int length);
void lovrGraphicsSetIndexData(unsigned int* data, int length);
void lovrGraphicsDrawPrimitive(GLenum mode, Texture* texture, int hasNormals, int hasTexCoords, int useIndices);
void lovrGraphicsPoints(float* points, int count);
void lovrGraphicsLine(float* points, int count);
@ -132,3 +138,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);

View File

@ -4,17 +4,29 @@
#include <math.h>
#include <stdlib.h>
static GLenum getGLFormat(TextureFormat format) {
switch (format) {
case FORMAT_RED: return GL_RED;
case FORMAT_RG: return GL_RG;
case FORMAT_RGB: return GL_RGB;
case FORMAT_RGBA: return GL_RGBA;
}
return 0;
}
Texture* lovrTextureCreate(TextureData* textureData) {
Texture* texture = lovrAlloc(sizeof(Texture), lovrTextureDestroy);
if (!texture) return NULL;
int w = textureData->width;
int h = textureData->height;
GLenum format = getGLFormat(textureData->format);
texture->textureData = textureData;
glGenTextures(1, &texture->id);
lovrTextureBind(texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData->data);
glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, format, GL_UNSIGNED_BYTE, textureData->data);
lovrTextureSetFilter(texture, FILTER_LINEAR, FILTER_LINEAR);
lovrTextureSetWrap(texture, WRAP_REPEAT, WRAP_REPEAT);

View File

@ -5,11 +5,19 @@ struct CanvasState;
#pragma once
typedef enum {
FORMAT_RED,
FORMAT_RG,
FORMAT_RGB,
FORMAT_RGBA
} TextureFormat;
typedef struct {
void* data;
int width;
int height;
int channels;
TextureFormat format;
} TextureData;
typedef enum {

View File

@ -12,23 +12,55 @@ FontData* lovrFontDataCreate(void* data, int size) {
}
FontData* fontData = malloc(sizeof(FontData));
FT_Face face = fontData->face;
if (FT_New_Memory_Face(ft, data, size, 0, &face)) {
if (FT_New_Memory_Face(ft, data, size, 0, (FT_Face*)&fontData->rasterizer)) {
error("Error loading font");
}
if (FT_Set_Pixel_Sizes(face, 16, 16)) {
if (FT_Set_Pixel_Sizes(fontData->rasterizer, 0, 64)) {
error("Problem setting font size");
}
return fontData;
}
void lovrFontDataGetGlyph(FontData* fontData, char c, Glyph* glyph) {
FT_Glyph ftglyph;
FT_Face face = fontData->face;
FT_Load_Glyph(face, c, FT_LOAD_DEFAULT);
FT_Get_Glyph(face->glyph, &ftglyph);
GlyphData* lovrFontDataCreateGlyph(FontData* fontData, uint32_t character) {
FT_Face face = fontData->rasterizer;
FT_Error err = FT_Err_Ok;
FT_Glyph ftGlyph;
FT_Bitmap ftBitmap;
FT_BitmapGlyph ftBitmapGlyph;
//
err |= FT_Load_Glyph(face, FT_Get_Char_Index(face, character), FT_LOAD_DEFAULT);
err |= FT_Get_Glyph(face->glyph, &ftGlyph);
err |= FT_Glyph_To_Bitmap(&ftGlyph, FT_RENDER_MODE_NORMAL, 0, 1);
if (err) {
error("Error loading glyph\n");
}
ftBitmapGlyph = (FT_BitmapGlyph) ftGlyph;
ftBitmap = ftBitmapGlyph->bitmap;
GlyphData* glyphData = malloc(sizeof(GlyphData));
FT_Glyph_Metrics* metrics = &face->glyph->metrics;
glyphData->x = metrics->horiBearingX >> 6;
glyphData->y = metrics->horiBearingY >> 6;
glyphData->w = metrics->width >> 6;
glyphData->h = metrics->height >> 6;
glyphData->advance = metrics->horiAdvance >> 6;
glyphData->data = malloc(2 * glyphData->w * glyphData->h);
int i = 0;
uint8_t* row = ftBitmap.buffer;
for (int y = 0; y < glyphData->h; y++) {
for (int x = 0; x < glyphData->w; x++) {
glyphData->data[i++] = 0xff;
glyphData->data[i++] = row[x];
}
row += ftBitmap.pitch;
}
FT_Done_Glyph(ftGlyph);
return glyphData;
}

View File

@ -1,4 +1,5 @@
#include "graphics/font.h"
#include <stdint.h>
FontData* lovrFontDataCreate(void* data, int size);
void lovrFontDataGetGlyph(FontData* fontData, char c, Glyph* glyph);
GlyphData* lovrFontDataCreateGlyph(FontData* fontData, uint32_t characer);

View File

@ -3,11 +3,18 @@
#include <stdlib.h>
#include <string.h>
TextureData* lovrTextureDataGetBlank(int width, int height, uint8_t value) {
TextureData* lovrTextureDataGetBlank(int width, int height, uint8_t value, TextureFormat format) {
TextureData* textureData = malloc(sizeof(TextureData));
if (!textureData) return NULL;
int channels = 4;
int channels = 0;
switch (format) {
case FORMAT_RED: channels = 1; break;
case FORMAT_RG: channels = 2; break;
case FORMAT_RGB: channels = 3; break;
case FORMAT_RGBA: channels = 4; break;
}
int size = sizeof(uint8_t) * width * height * channels;
uint8_t* data = malloc(size);
memset(data, value, size);
@ -16,6 +23,7 @@ TextureData* lovrTextureDataGetBlank(int width, int height, uint8_t value) {
textureData->width = width;
textureData->height = height;
textureData->channels = channels;
textureData->format = format;
return textureData;
}
@ -28,6 +36,7 @@ TextureData* lovrTextureDataGetEmpty(int width, int height) {
textureData->width = width;
textureData->height = height;
textureData->channels = 4;
textureData->format = FORMAT_RGBA;
return textureData;
}
@ -44,6 +53,7 @@ TextureData* lovrTextureDataFromFile(void* data, int size) {
if (image) {
textureData->data = image;
textureData->format = FORMAT_RGBA;
return textureData;
}
@ -59,5 +69,6 @@ TextureData* lovrTextureDataFromOpenVRModel(OpenVRModel* vrModel) {
textureData->width = texture->unWidth;
textureData->height = texture->unHeight;
textureData->data = texture->rubTextureMapData;
textureData->format = FORMAT_RGBA;
return textureData;
}

View File

@ -2,7 +2,7 @@
#include "openvr.h"
#include <stdint.h>
TextureData* lovrTextureDataGetBlank(int width, int height, uint8_t value);
TextureData* lovrTextureDataGetBlank(int width, int height, uint8_t value, TextureFormat format);
TextureData* lovrTextureDataGetEmpty(int width, int height);
TextureData* lovrTextureDataFromFile(void* data, int size);
TextureData* lovrTextureDataFromOpenVRModel(OpenVRModel* vrModel);

View File

@ -6,6 +6,7 @@
#include "lovr/types/texture.h"
#include "lovr/types/transform.h"
#include "graphics/graphics.h"
#include "loaders/font.h"
#include "loaders/model.h"
#include "loaders/texture.h"
#include "filesystem/filesystem.h"
@ -68,6 +69,8 @@ const luaL_Reg lovrGraphics[] = {
{ "setScissor", l_lovrGraphicsSetScissor },
{ "getShader", l_lovrGraphicsGetShader },
{ "setShader", l_lovrGraphicsSetShader },
{ "getFont", l_lovrGraphicsGetFont },
{ "setFont", l_lovrGraphicsSetFont },
{ "setProjection", l_lovrGraphicsSetProjection },
{ "getLineWidth", l_lovrGraphicsGetLineWidth },
{ "setLineWidth", l_lovrGraphicsSetLineWidth },
@ -93,11 +96,13 @@ const luaL_Reg lovrGraphics[] = {
{ "triangle", l_lovrGraphicsTriangle },
{ "plane", l_lovrGraphicsPlane },
{ "cube", l_lovrGraphicsCube },
{ "print", l_lovrGraphicsPrint },
{ "getWidth", l_lovrGraphicsGetWidth },
{ "getHeight", l_lovrGraphicsGetHeight },
{ "getDimensions", l_lovrGraphicsGetDimensions },
{ "newModel", l_lovrGraphicsNewModel },
{ "newBuffer", l_lovrGraphicsNewBuffer },
{ "newFont", l_lovrGraphicsNewFont },
{ "newModel", l_lovrGraphicsNewModel },
{ "newShader", l_lovrGraphicsNewShader },
{ "newSkybox", l_lovrGraphicsNewSkybox },
{ "newTexture", l_lovrGraphicsNewTexture },
@ -110,6 +115,7 @@ int l_lovrGraphicsInit(lua_State* L) {
lua_newtable(L);
luaL_register(L, NULL, lovrGraphics);
luax_registertype(L, "Buffer", lovrBuffer);
luax_registertype(L, "Font", NULL);
luax_registertype(L, "Model", lovrModel);
luax_registertype(L, "Shader", lovrShader);
luax_registertype(L, "Skybox", lovrSkybox);
@ -311,6 +317,17 @@ int l_lovrGraphicsSetShader(lua_State* L) {
return 0;
}
int l_lovrGraphicsGetFont(lua_State* L) {
luax_pushtype(L, Font, lovrGraphicsGetFont());
return 1;
}
int l_lovrGraphicsSetFont(lua_State* L) {
Font* font = luax_checktype(L, 1, Font);
lovrGraphicsSetFont(font);
return 0;
}
int l_lovrGraphicsSetProjection(lua_State* L) {
float near = luaL_checknumber(L, 1);
float far = luaL_checknumber(L, 2);
@ -531,6 +548,12 @@ int l_lovrGraphicsCube(lua_State* L) {
return 0;
}
int l_lovrGraphicsPrint(lua_State* L) {
const char* str = luaL_checkstring(L, 1);
lovrGraphicsPrint(str);
return 0;
}
// Types
int l_lovrGraphicsNewBuffer(lua_State* L) {
@ -600,6 +623,20 @@ int l_lovrGraphicsNewBuffer(lua_State* L) {
return 1;
}
int l_lovrGraphicsNewFont(lua_State* L) {
const char* path = luaL_checkstring(L, 1);
//float size = luaL_optnumber(L, 2, 16);
int fileSize;
void* data = lovrFilesystemRead(path, &fileSize);
if (!data) {
luaL_error(L, "Could not load font '%s'", path);
}
FontData* fontData = lovrFontDataCreate(data, fileSize);
Font* font = lovrFontCreate(fontData);
luax_pushtype(L, Font, font);
return 1;
}
int l_lovrGraphicsNewModel(lua_State* L) {
const char* path = lua_tostring(L, 1);
int size;
@ -695,4 +732,3 @@ int l_lovrGraphicsNewTexture(lua_State* L) {
luax_pushtype(L, Texture, texture);
return 1;
}

View File

@ -30,6 +30,8 @@ int l_lovrGraphicsGetScissor(lua_State* L);
int l_lovrGraphicsSetScissor(lua_State* L);
int l_lovrGraphicsGetShader(lua_State* L);
int l_lovrGraphicsSetShader(lua_State* L);
int l_lovrGraphicsGetFont(lua_State* L);
int l_lovrGraphicsSetFont(lua_State* L);
int l_lovrGraphicsSetProjection(lua_State* L);
int l_lovrGraphicsGetLineWidth(lua_State* L);
int l_lovrGraphicsSetLineWidth(lua_State* L);
@ -62,9 +64,11 @@ int l_lovrGraphicsLine(lua_State* L);
int l_lovrGraphicsTriangle(lua_State* L);
int l_lovrGraphicsPlane(lua_State* L);
int l_lovrGraphicsCube(lua_State* L);
int l_lovrGraphicsPrint(lua_State* L);
// Types
int l_lovrGraphicsNewBuffer(lua_State* L);
int l_lovrGraphicsNewFont(lua_State* L);
int l_lovrGraphicsNewModel(lua_State* L);
int l_lovrGraphicsNewShader(lua_State* L);
int l_lovrGraphicsNewSkybox(lua_State* L);