Organize graphics state;

This commit is contained in:
bjorn 2017-08-02 00:54:33 -07:00
parent ef06a19fa4
commit 9efa89768c
3 changed files with 228 additions and 224 deletions

View File

@ -15,9 +15,9 @@ 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 Windings;
map_int_t WrapModes;
static void luax_readvertices(lua_State* L, int index, vec_float_t* points) {
@ -123,10 +123,6 @@ int l_lovrGraphicsInit(lua_State* L) {
map_set(&MeshUsages, "dynamic", MESH_DYNAMIC);
map_set(&MeshUsages, "stream", MESH_STREAM);
map_init(&PolygonWindings);
map_set(&PolygonWindings, "clockwise", POLYGON_WINDING_CLOCKWISE);
map_set(&PolygonWindings, "counterclockwise", POLYGON_WINDING_COUNTERCLOCKWISE);
map_init(&TextureProjections);
map_set(&TextureProjections, "2d", PROJECTION_ORTHOGRAPHIC);
map_set(&TextureProjections, "3d", PROJECTION_PERSPECTIVE);
@ -136,6 +132,10 @@ int l_lovrGraphicsInit(lua_State* L) {
map_set(&VerticalAligns, "bottom", ALIGN_BOTTOM);
map_set(&VerticalAligns, "middle", ALIGN_MIDDLE);
map_init(&Windings);
map_set(&Windings, "clockwise", WINDING_CLOCKWISE);
map_set(&Windings, "counterclockwise", WINDING_COUNTERCLOCKWISE);
map_init(&WrapModes);
map_set(&WrapModes, "clamp", WRAP_CLAMP);
map_set(&WrapModes, "repeat", WRAP_REPEAT);
@ -165,7 +165,7 @@ int l_lovrGraphicsPresent(lua_State* L) {
// State
int l_lovrGraphicsGetBackgroundColor(lua_State* L) {
float r, g, b, a;
unsigned char r, g, b, a;
lovrGraphicsGetBackgroundColor(&r, &g, &b, &a);
lua_pushnumber(L, r);
lua_pushnumber(L, g);
@ -175,10 +175,11 @@ int l_lovrGraphicsGetBackgroundColor(lua_State* L) {
}
int l_lovrGraphicsSetBackgroundColor(lua_State* L) {
float r = luaL_checknumber(L, 1);
float g = luaL_checknumber(L, 2);
float b = luaL_checknumber(L, 3);
float a = luaL_optnumber(L, 4, 255.0);
unsigned char r, g, b, a;
r = luaL_checknumber(L, 1);
g = luaL_checknumber(L, 2);
b = luaL_checknumber(L, 3);
a = luaL_optnumber(L, 4, 255.0);
lovrGraphicsSetBackgroundColor(r, g, b, a);
return 0;
}
@ -239,30 +240,63 @@ int l_lovrGraphicsSetColor(lua_State* L) {
return 0;
}
int l_lovrGraphicsGetShader(lua_State* L) {
Shader* shader = lovrGraphicsGetShader();
luax_pushtype(L, Shader, shader);
int l_lovrGraphicsIsCullingEnabled(lua_State* L) {
lua_pushboolean(L, lovrGraphicsIsCullingEnabled());
return 1;
}
int l_lovrGraphicsSetShader(lua_State* L) {
Shader* shader = lua_isnoneornil(L, 1) ? NULL : luax_checktype(L, 1, Shader);
lovrGraphicsSetShader(shader);
int l_lovrGraphicsSetCullingEnabled(lua_State* L) {
lovrGraphicsSetCullingEnabled(lua_toboolean(L, 1));
return 0;
}
int l_lovrGraphicsGetFont(lua_State* L) {
Font* font = lovrGraphicsGetFont();
luax_pushtype(L, Font, font);
int l_lovrGraphicsGetDefaultFilter(lua_State* L) {
TextureFilter filter = lovrGraphicsGetDefaultFilter();
luax_pushenum(L, &FilterModes, filter.mode);
if (filter.mode == FILTER_ANISOTROPIC) {
lua_pushnumber(L, filter.anisotropy);
return 2;
}
return 1;
}
int l_lovrGraphicsSetFont(lua_State* L) {
Font* font = luax_checktype(L, 1, Font);
lovrGraphicsSetFont(font);
int l_lovrGraphicsSetDefaultFilter(lua_State* L) {
FilterMode mode = *(FilterMode*) luax_checkenum(L, 1, &FilterModes, "filter mode");
float anisotropy = luaL_optnumber(L, 2, 1.);
TextureFilter filter = { .mode = mode, .anisotropy = anisotropy };
lovrGraphicsSetDefaultFilter(filter);
return 0;
}
int l_lovrGraphicsGetDepthTest(lua_State* L) {
luax_pushenum(L, &CompareModes, lovrGraphicsGetDepthTest());
return 1;
}
int l_lovrGraphicsSetDepthTest(lua_State* L) {
if (lua_isnoneornil(L, 1)) {
lovrGraphicsSetDepthTest(COMPARE_NONE);
} else {
CompareMode* depthTest = (CompareMode*) luax_checkenum(L, 1, &CompareModes, "compare mode");
lovrGraphicsSetDepthTest(*depthTest);
}
return 0;
}
int l_lovrGraphicsGetSystemLimits(lua_State* L) {
GraphicsLimits limits = lovrGraphicsGetLimits();
lua_newtable(L);
lua_pushnumber(L, limits.pointSizes[1]);
lua_setfield(L, -2, "pointsize");
lua_pushinteger(L, limits.textureSize);
lua_setfield(L, -2, "texturesize");
lua_pushinteger(L, limits.textureMSAA);
lua_setfield(L, -2, "texturemsaa");
lua_pushinteger(L, limits.textureAnisotropy);
lua_setfield(L, -2, "anisotropy");
return 1;
}
int l_lovrGraphicsGetLineWidth(lua_State* L) {
lua_pushnumber(L, lovrGraphicsGetLineWidth());
return 1;
@ -285,39 +319,14 @@ int l_lovrGraphicsSetPointSize(lua_State* L) {
return 0;
}
int l_lovrGraphicsIsCullingEnabled(lua_State* L) {
lua_pushboolean(L, lovrGraphicsIsCullingEnabled());
int l_lovrGraphicsGetWinding(lua_State* L) {
luax_pushenum(L, &Windings, lovrGraphicsGetWinding());
return 1;
}
int l_lovrGraphicsSetCullingEnabled(lua_State* L) {
lovrGraphicsSetCullingEnabled(lua_toboolean(L, 1));
return 0;
}
int l_lovrGraphicsGetPolygonWinding(lua_State* L) {
luax_pushenum(L, &PolygonWindings, lovrGraphicsGetPolygonWinding());
return 1;
}
int l_lovrGraphicsSetPolygonWinding(lua_State* L) {
PolygonWinding* winding = (PolygonWinding*) luax_checkenum(L, 1, &PolygonWindings, "winding direction");
lovrGraphicsSetPolygonWinding(*winding);
return 0;
}
int l_lovrGraphicsGetDepthTest(lua_State* L) {
luax_pushenum(L, &CompareModes, lovrGraphicsGetDepthTest());
return 1;
}
int l_lovrGraphicsSetDepthTest(lua_State* L) {
if (lua_isnoneornil(L, 1)) {
lovrGraphicsSetDepthTest(COMPARE_NONE);
} else {
CompareMode* depthTest = (CompareMode*) luax_checkenum(L, 1, &CompareModes, "compare mode");
lovrGraphicsSetDepthTest(*depthTest);
}
int l_lovrGraphicsSetWinding(lua_State* L) {
Winding* winding = (Winding*) luax_checkenum(L, 1, &Windings, "winding");
lovrGraphicsSetWinding(*winding);
return 0;
}
@ -331,21 +340,27 @@ int l_lovrGraphicsSetWireframe(lua_State* L) {
return 0;
}
int l_lovrGraphicsGetDefaultFilter(lua_State* L) {
TextureFilter filter = lovrGraphicsGetDefaultFilter();
luax_pushenum(L, &FilterModes, filter.mode);
if (filter.mode == FILTER_ANISOTROPIC) {
lua_pushnumber(L, filter.anisotropy);
return 2;
}
int l_lovrGraphicsGetShader(lua_State* L) {
Shader* shader = lovrGraphicsGetShader();
luax_pushtype(L, Shader, shader);
return 1;
}
int l_lovrGraphicsSetDefaultFilter(lua_State* L) {
FilterMode mode = *(FilterMode*) luax_checkenum(L, 1, &FilterModes, "filter mode");
float anisotropy = luaL_optnumber(L, 2, 1.);
TextureFilter filter = { .mode = mode, .anisotropy = anisotropy };
lovrGraphicsSetDefaultFilter(filter);
int l_lovrGraphicsSetShader(lua_State* L) {
Shader* shader = lua_isnoneornil(L, 1) ? NULL : luax_checktype(L, 1, Shader);
lovrGraphicsSetShader(shader);
return 0;
}
int l_lovrGraphicsGetFont(lua_State* L) {
Font* font = lovrGraphicsGetFont();
luax_pushtype(L, Font, font);
return 1;
}
int l_lovrGraphicsSetFont(lua_State* L) {
Font* font = luax_checktype(L, 1, Font);
lovrGraphicsSetFont(font);
return 0;
}
@ -365,20 +380,6 @@ int l_lovrGraphicsGetDimensions(lua_State* L) {
return 2;
}
int l_lovrGraphicsGetSystemLimits(lua_State* L) {
GraphicsLimits limits = lovrGraphicsGetLimits();
lua_newtable(L);
lua_pushnumber(L, limits.pointSizes[1]);
lua_setfield(L, -2, "pointsize");
lua_pushinteger(L, limits.textureSize);
lua_setfield(L, -2, "texturesize");
lua_pushinteger(L, limits.textureMSAA);
lua_setfield(L, -2, "texturemsaa");
lua_pushinteger(L, limits.textureAnisotropy);
lua_setfield(L, -2, "anisotropy");
return 1;
}
// Transforms
int l_lovrGraphicsPush(lua_State* L) {
@ -759,24 +760,28 @@ const luaL_Reg lovrGraphics[] = {
{ "setBlendMode", l_lovrGraphicsSetBlendMode },
{ "getColor", l_lovrGraphicsGetColor },
{ "setColor", l_lovrGraphicsSetColor },
{ "getShader", l_lovrGraphicsGetShader },
{ "setShader", l_lovrGraphicsSetShader },
{ "getFont", l_lovrGraphicsGetFont },
{ "setFont", l_lovrGraphicsSetFont },
{ "isCullingEnabled", l_lovrGraphicsIsCullingEnabled },
{ "setCullingEnabled", l_lovrGraphicsSetCullingEnabled },
{ "getDepthTest", l_lovrGraphicsGetDepthTest },
{ "setDepthTest", l_lovrGraphicsSetDepthTest },
{ "getDefaultFilter", l_lovrGraphicsGetDefaultFilter },
{ "setDefaultFilter", l_lovrGraphicsSetDefaultFilter },
{ "getSystemLimits", l_lovrGraphicsGetSystemLimits },
{ "getLineWidth", l_lovrGraphicsGetLineWidth },
{ "setLineWidth", l_lovrGraphicsSetLineWidth },
{ "getPointSize", l_lovrGraphicsGetPointSize },
{ "setPointSize", l_lovrGraphicsSetPointSize },
{ "isCullingEnabled", l_lovrGraphicsIsCullingEnabled },
{ "setCullingEnabled", l_lovrGraphicsSetCullingEnabled },
{ "getPolygonWinding", l_lovrGraphicsGetPolygonWinding },
{ "setPolygonWinding", l_lovrGraphicsSetPolygonWinding },
{ "getDepthTest", l_lovrGraphicsGetDepthTest },
{ "setDepthTest", l_lovrGraphicsSetDepthTest },
{ "getWinding", l_lovrGraphicsGetWinding },
{ "setWinding", l_lovrGraphicsSetWinding },
{ "isWireframe", l_lovrGraphicsIsWireframe },
{ "setWireframe", l_lovrGraphicsSetWireframe },
{ "getDefaultFilter", l_lovrGraphicsGetDefaultFilter },
{ "setDefaultFilter", l_lovrGraphicsSetDefaultFilter },
{ "getShader", l_lovrGraphicsGetShader },
{ "setShader", l_lovrGraphicsSetShader },
{ "getFont", l_lovrGraphicsGetFont },
{ "setFont", l_lovrGraphicsSetFont },
{ "getWidth", l_lovrGraphicsGetWidth },
{ "getHeight", l_lovrGraphicsGetHeight },
{ "getDimensions", l_lovrGraphicsGetDimensions },
{ "push", l_lovrGraphicsPush },
{ "pop", l_lovrGraphicsPop },
{ "origin", l_lovrGraphicsOrigin },
@ -793,10 +798,6 @@ const luaL_Reg lovrGraphics[] = {
{ "cylinder", l_lovrGraphicsCylinder },
{ "sphere", l_lovrGraphicsSphere },
{ "print", l_lovrGraphicsPrint },
{ "getWidth", l_lovrGraphicsGetWidth },
{ "getHeight", l_lovrGraphicsGetHeight },
{ "getDimensions", l_lovrGraphicsGetDimensions },
{ "getSystemLimits", l_lovrGraphicsGetSystemLimits },
{ "newFont", l_lovrGraphicsNewFont },
{ "newMesh", l_lovrGraphicsNewMesh },
{ "newModel", l_lovrGraphicsNewModel },

View File

@ -129,7 +129,7 @@ void lovrGraphicsReset() {
lovrGraphicsSetLineWidth(1);
lovrGraphicsSetPointSize(1);
lovrGraphicsSetCullingEnabled(0);
lovrGraphicsSetPolygonWinding(POLYGON_WINDING_COUNTERCLOCKWISE);
lovrGraphicsSetWinding(WINDING_COUNTERCLOCKWISE);
lovrGraphicsSetDepthTest(COMPARE_LEQUAL);
lovrGraphicsSetWireframe(0);
lovrGraphicsOrigin();
@ -153,17 +153,16 @@ void lovrGraphicsPrepare() {
// State
void lovrGraphicsGetBackgroundColor(float* r, float* g, float* b, float* a) {
GLfloat clearColor[4];
glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor);
*r = clearColor[0];
*g = clearColor[1];
*b = clearColor[2];
*a = clearColor[3];
void lovrGraphicsGetBackgroundColor(unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a) {
*r = LOVR_COLOR_R(state.backgroundColor);
*g = LOVR_COLOR_G(state.backgroundColor);
*b = LOVR_COLOR_B(state.backgroundColor);
*a = LOVR_COLOR_A(state.backgroundColor);
}
void lovrGraphicsSetBackgroundColor(float r, float g, float b, float a) {
glClearColor(r / 255, g / 255, b / 255, a / 255);
void lovrGraphicsSetBackgroundColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
state.backgroundColor = LOVR_COLOR(r, g, b, a);
glClearColor(r / 255., g / 255., b / 255., a / 255.);
}
void lovrGraphicsGetBlendMode(BlendMode* mode, BlendAlphaMode* alphaMode) {
@ -232,6 +231,99 @@ void lovrGraphicsSetColor(unsigned char r, unsigned char g, unsigned char b, uns
state.color = LOVR_COLOR(r, g, b, a);
}
int lovrGraphicsIsCullingEnabled() {
return state.culling;
}
void lovrGraphicsSetCullingEnabled(int culling) {
if (culling != state.culling) {
state.culling = culling;
if (culling) {
glEnable(GL_CULL_FACE);
} else {
glDisable(GL_CULL_FACE);
}
}
}
TextureFilter lovrGraphicsGetDefaultFilter() {
return state.defaultFilter;
}
void lovrGraphicsSetDefaultFilter(TextureFilter filter) {
state.defaultFilter = filter;
}
CompareMode lovrGraphicsGetDepthTest() {
return state.depthTest;
}
void lovrGraphicsSetDepthTest(CompareMode depthTest) {
if (state.depthTest != depthTest) {
state.depthTest = depthTest;
glDepthFunc(depthTest);
if (depthTest) {
glEnable(GL_DEPTH_TEST);
} else {
glDisable(GL_DEPTH_TEST);
}
}
}
GraphicsLimits lovrGraphicsGetLimits() {
if (!state.limits.initialized) {
glGetFloatv(GL_POINT_SIZE_RANGE, state.limits.pointSizes);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &state.limits.textureSize);
glGetIntegerv(GL_MAX_SAMPLES, &state.limits.textureMSAA);
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &state.limits.textureAnisotropy);
state.limits.initialized = 1;
}
return state.limits;
}
float lovrGraphicsGetLineWidth() {
return state.lineWidth;
}
void lovrGraphicsSetLineWidth(float width) {
state.lineWidth = width;
glLineWidth(width);
}
float lovrGraphicsGetPointSize() {
return state.pointSize;
}
void lovrGraphicsSetPointSize(float size) {
#ifndef EMSCRIPTEN
state.pointSize = size;
glPointSize(size);
#endif
}
Winding lovrGraphicsGetWinding() {
return state.winding;
}
void lovrGraphicsSetWinding(Winding winding) {
state.winding = winding;
glFrontFace(winding);
}
int lovrGraphicsIsWireframe() {
return state.wireframe;
}
void lovrGraphicsSetWireframe(int wireframe) {
#ifndef EMSCRIPTEN
if (state.wireframe != wireframe) {
state.wireframe = wireframe;
glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL);
}
#endif
}
Shader* lovrGraphicsGetShader() {
return state.activeShader;
}
@ -291,85 +383,6 @@ void lovrGraphicsSetProjection(mat4 projection) {
memcpy(state.canvases[state.canvas].projection, projection, 16 * sizeof(float));
}
float lovrGraphicsGetLineWidth() {
return state.lineWidth;
}
void lovrGraphicsSetLineWidth(float width) {
state.lineWidth = width;
glLineWidth(width);
}
float lovrGraphicsGetPointSize() {
return state.pointSize;
}
void lovrGraphicsSetPointSize(float size) {
#ifndef EMSCRIPTEN
state.pointSize = size;
glPointSize(size);
#endif
}
int lovrGraphicsIsCullingEnabled() {
return state.isCullingEnabled;
}
void lovrGraphicsSetCullingEnabled(int isEnabled) {
state.isCullingEnabled = isEnabled;
if (isEnabled) {
glEnable(GL_CULL_FACE);
} else {
glDisable(GL_CULL_FACE);
}
}
PolygonWinding lovrGraphicsGetPolygonWinding() {
return state.polygonWinding;
}
void lovrGraphicsSetPolygonWinding(PolygonWinding winding) {
state.polygonWinding = winding;
glFrontFace(winding);
}
CompareMode lovrGraphicsGetDepthTest() {
return state.depthTest;
}
void lovrGraphicsSetDepthTest(CompareMode depthTest) {
if (state.depthTest != depthTest) {
state.depthTest = depthTest;
glDepthFunc(depthTest);
if (depthTest) {
glEnable(GL_DEPTH_TEST);
} else {
glDisable(GL_DEPTH_TEST);
}
}
}
int lovrGraphicsIsWireframe() {
return state.isWireframe;
}
void lovrGraphicsSetWireframe(int wireframe) {
#ifndef EMSCRIPTEN
if (state.isWireframe != wireframe) {
state.isWireframe = wireframe;
glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL);
}
#endif
}
TextureFilter lovrGraphicsGetDefaultFilter() {
return state.defaultFilter;
}
void lovrGraphicsSetDefaultFilter(TextureFilter filter) {
state.defaultFilter = filter;
}
int lovrGraphicsGetWidth() {
int width, height;
glfwGetFramebufferSize(state.window, &width, &height);
@ -382,18 +395,6 @@ int lovrGraphicsGetHeight() {
return height;
}
GraphicsLimits lovrGraphicsGetLimits() {
if (!state.limits.initialized) {
glGetFloatv(GL_POINT_SIZE_RANGE, state.limits.pointSizes);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &state.limits.textureSize);
glGetIntegerv(GL_MAX_SAMPLES, &state.limits.textureMSAA);
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &state.limits.textureAnisotropy);
state.limits.initialized = 1;
}
return state.limits;
}
void lovrGraphicsPushCanvas() {
if (++state.canvas >= MAX_CANVASES) {
error("Canvas overflow");

View File

@ -35,9 +35,9 @@ typedef enum {
} DrawMode;
typedef enum {
POLYGON_WINDING_CLOCKWISE = GL_CW,
POLYGON_WINDING_COUNTERCLOCKWISE = GL_CCW
} PolygonWinding;
WINDING_CLOCKWISE = GL_CW,
WINDING_COUNTERCLOCKWISE = GL_CCW
} Winding;
typedef enum {
COMPARE_NONE = 0,
@ -78,22 +78,24 @@ typedef struct {
CanvasState canvases[MAX_CANVASES];
int transform;
int canvas;
unsigned int color;
BlendMode blendMode;
BlendAlphaMode blendAlphaMode;
GLuint shapeArray;
GLuint shapeBuffer;
GLuint shapeIndexBuffer;
vec_float_t shapeData;
vec_uint_t shapeIndices;
unsigned int backgroundColor;
BlendMode blendMode;
BlendAlphaMode blendAlphaMode;
unsigned int color;
int culling;
TextureFilter defaultFilter;
CompareMode depthTest;
GraphicsLimits limits;
float lineWidth;
float pointSize;
int isCullingEnabled;
PolygonWinding polygonWinding;
CompareMode depthTest;
int isWireframe;
TextureFilter defaultFilter;
GraphicsLimits limits;
Winding winding;
int wireframe;
} GraphicsState;
// Base
@ -105,12 +107,27 @@ void lovrGraphicsPresent();
void lovrGraphicsPrepare();
// State
void lovrGraphicsGetBackgroundColor(float* r, float* g, float* b, float* a);
void lovrGraphicsSetBackgroundColor(float r, float g, float b, float a);
void lovrGraphicsGetBackgroundColor(unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a);
void lovrGraphicsSetBackgroundColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
void lovrGraphicsGetBlendMode(BlendMode* mode, BlendAlphaMode* alphaMode);
void lovrGraphicsSetBlendMode(BlendMode mode, BlendAlphaMode alphaMode);
void lovrGraphicsGetColor(unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a);
void lovrGraphicsSetColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
int lovrGraphicsIsCullingEnabled();
void lovrGraphicsSetCullingEnabled(int culling);
TextureFilter lovrGraphicsGetDefaultFilter();
void lovrGraphicsSetDefaultFilter(TextureFilter filter);
CompareMode lovrGraphicsGetDepthTest();
void lovrGraphicsSetDepthTest(CompareMode depthTest);
GraphicsLimits lovrGraphicsGetLimits();
float lovrGraphicsGetLineWidth();
void lovrGraphicsSetLineWidth(float width);
float lovrGraphicsGetPointSize();
void lovrGraphicsSetPointSize(float size);
Winding lovrGraphicsGetWinding();
void lovrGraphicsSetWinding(Winding winding);
int lovrGraphicsIsWireframe();
void lovrGraphicsSetWireframe(int wireframe);
Shader* lovrGraphicsGetShader();
void lovrGraphicsSetShader(Shader* shader);
Font* lovrGraphicsGetFont();
@ -119,23 +136,8 @@ Texture* lovrGraphicsGetTexture();
void lovrGraphicsBindTexture(Texture* texture);
mat4 lovrGraphicsGetProjection();
void lovrGraphicsSetProjection(mat4 projection);
float lovrGraphicsGetLineWidth();
void lovrGraphicsSetLineWidth(float width);
float lovrGraphicsGetPointSize();
void lovrGraphicsSetPointSize(float size);
int lovrGraphicsIsCullingEnabled();
void lovrGraphicsSetCullingEnabled(int isEnabled);
PolygonWinding lovrGraphicsGetPolygonWinding();
void lovrGraphicsSetPolygonWinding(PolygonWinding winding);
CompareMode lovrGraphicsGetDepthTest();
void lovrGraphicsSetDepthTest(CompareMode depthTest);
int lovrGraphicsIsWireframe();
void lovrGraphicsSetWireframe(int wireframe);
TextureFilter lovrGraphicsGetDefaultFilter();
void lovrGraphicsSetDefaultFilter(TextureFilter filter);
int lovrGraphicsGetWidth();
int lovrGraphicsGetHeight();
GraphicsLimits lovrGraphicsGetLimits();
void lovrGraphicsPushCanvas();
void lovrGraphicsPopCanvas();
void lovrGraphicsSetViewport(int x, int y, int w, int h);