Use arrays for enums instead of maps;

This commit is contained in:
bjorn 2018-07-04 20:11:52 -07:00
parent 56ea2d43d0
commit f903b6014c
25 changed files with 481 additions and 441 deletions

View File

@ -4,7 +4,6 @@
#include "math/math.h"
#include "math/randomGenerator.h"
#include "physics/physics.h"
#include "lib/map/map.h"
// Module loaders
int l_lovrInit(lua_State* L);
@ -67,34 +66,36 @@ extern const luaL_Reg lovrVertexData[];
extern const luaL_Reg lovrWorld[];
// Enums
extern map_int_t ArcModes;
extern map_int_t AttributeTypes;
extern map_int_t BlendAlphaModes;
extern map_int_t BlendModes;
extern map_int_t CompareModes;
extern map_int_t ControllerAxes;
extern map_int_t ControllerButtons;
extern map_int_t ControllerHands;
extern map_int_t DrawModes;
extern map_int_t EventTypes;
extern map_int_t FilterModes;
extern map_int_t HeadsetEyes;
extern map_int_t HeadsetOrigins;
extern map_int_t HeadsetTypes;
extern map_int_t HorizontalAligns;
extern map_int_t JointTypes;
extern map_int_t MaterialColors;
extern map_int_t MaterialScalars;
extern map_int_t MaterialTextures;
extern map_int_t MeshDrawModes;
extern map_int_t MeshUsages;
extern map_int_t PolygonWindings;
extern map_int_t ShapeTypes;
extern map_int_t TextureFormats;
extern map_int_t TextureTypes;
extern map_int_t TimeUnits;
extern map_int_t VerticalAligns;
extern map_int_t WrapModes;
extern const char* ArcModes[];
extern const char* AttributeTypes[];
extern const char* BlendAlphaModes[];
extern const char* BlendModes[];
extern const char* CompareModes[];
extern const char* ControllerAxes[];
extern const char* ControllerButtons[];
extern const char* ControllerHands[];
extern const char* DrawModes[];
extern const char* EventTypes[];
extern const char* FilterModes[];
extern const char* HeadsetDrivers[];
extern const char* HeadsetEyes[];
extern const char* HeadsetOrigins[];
extern const char* HeadsetTypes[];
extern const char* HorizontalAligns[];
extern const char* JointTypes[];
extern const char* MaterialColors[];
extern const char* MaterialScalars[];
extern const char* MaterialTextures[];
extern const char* MeshDrawModes[];
extern const char* MeshUsages[];
extern const char* ShapeTypes[];
extern const char* StencilActions[];
extern const char* TextureFormats[];
extern const char* TextureTypes[];
extern const char* TimeUnits[];
extern const char* VerticalAligns[];
extern const char* Windings[];
extern const char* WrapModes[];
// Shared helpers
int luax_loadvertices(lua_State* L, int index, VertexFormat* format, VertexPointer vertices);

View File

@ -3,17 +3,17 @@
#include "audio/source.h"
#include "data/audioStream.h"
map_int_t TimeUnits;
const char* TimeUnits[] = {
[UNIT_SECONDS] = "seconds",
[UNIT_SAMPLES] = "samples",
NULL
};
int l_lovrAudioInit(lua_State* L) {
lua_newtable(L);
luaL_register(L, NULL, lovrAudio);
luax_registertype(L, "Source", lovrSource);
map_init(&TimeUnits);
map_set(&TimeUnits, "seconds", UNIT_SECONDS);
map_set(&TimeUnits, "samples", UNIT_SAMPLES);
lovrAudioInit();
return 1;
}

View File

@ -1,7 +1,16 @@
#include "api.h"
#include "event/event.h"
map_int_t EventTypes;
const char* EventTypes[] = {
[EVENT_QUIT] = "quit",
[EVENT_FOCUS] = "focus",
[EVENT_MOUNT] = "mount",
[EVENT_THREAD_ERROR] = "threaderror",
[EVENT_CONTROLLER_ADDED] = "controlleradded",
[EVENT_CONTROLLER_REMOVED] = "controllerremoved",
[EVENT_CONTROLLER_PRESSED] = "controllerpressed",
[EVENT_CONTROLLER_RELEASED] = "controllerreleased",
};
static _Thread_local int pollRef;
@ -12,7 +21,7 @@ static int nextEvent(lua_State* L) {
return 0;
}
luax_pushenum(L, &EventTypes, event.type);
lua_pushstring(L, EventTypes[event.type]);
switch (event.type) {
case EVENT_QUIT:
@ -51,12 +60,12 @@ static int nextEvent(lua_State* L) {
case EVENT_CONTROLLER_PRESSED:
luax_pushtype(L, Controller, event.data.controllerpressed.controller);
luax_pushenum(L, &ControllerButtons, event.data.controllerpressed.button);
lua_pushstring(L, ControllerButtons[event.data.controllerpressed.button]);
return 3;
case EVENT_CONTROLLER_RELEASED:
luax_pushtype(L, Controller, event.data.controllerreleased.controller);
luax_pushenum(L, &ControllerButtons, event.data.controllerreleased.button);
lua_pushstring(L, ControllerButtons[event.data.controllerpressed.button]);
return 3;
default:
@ -72,16 +81,6 @@ int l_lovrEventInit(lua_State* L) {
lua_pushcfunction(L, nextEvent);
pollRef = luaL_ref(L, LUA_REGISTRYINDEX);
map_init(&EventTypes);
map_set(&EventTypes, "quit", EVENT_QUIT);
map_set(&EventTypes, "focus", EVENT_FOCUS);
map_set(&EventTypes, "mount", EVENT_MOUNT);
map_set(&EventTypes, "threaderror", EVENT_THREAD_ERROR);
map_set(&EventTypes, "controlleradded", EVENT_CONTROLLER_ADDED);
map_set(&EventTypes, "controllerremoved", EVENT_CONTROLLER_REMOVED);
map_set(&EventTypes, "controllerpressed", EVENT_CONTROLLER_PRESSED);
map_set(&EventTypes, "controllerreleased", EVENT_CONTROLLER_RELEASED);
lovrEventInit();
return 1;
}
@ -102,7 +101,7 @@ int l_lovrEventPump(lua_State* L) {
}
int l_lovrEventPush(lua_State* L) {
EventType type = *(EventType*) luax_checkenum(L, 1, &EventTypes, "event type");
EventType type = luaL_checkoption(L, 1, NULL, EventTypes);
EventData data;
switch (type) {
@ -142,12 +141,12 @@ int l_lovrEventPush(lua_State* L) {
case EVENT_CONTROLLER_PRESSED:
data.controllerpressed.controller = luax_checktype(L, 2, Controller);
data.controllerpressed.button = *(ControllerButton*) luax_checkenum(L, 3, &ControllerButtons, "button");
data.controllerpressed.button = luaL_checkoption(L, 3, NULL, ControllerButtons);
break;
case EVENT_CONTROLLER_RELEASED:
data.controllerreleased.controller = luax_checktype(L, 2, Controller);
data.controllerreleased.button = *(ControllerButton*) luax_checkenum(L, 3, &ControllerButtons, "button");
data.controllerreleased.button = luaL_checkoption(L, 3, NULL, ControllerButtons);
break;
}

View File

@ -13,25 +13,158 @@
#include <math.h>
#include <stdbool.h>
map_int_t ArcModes;
map_int_t AttributeTypes;
map_int_t BlendAlphaModes;
map_int_t BlendModes;
map_int_t CompareModes;
map_int_t DrawModes;
map_int_t FilterModes;
map_int_t HorizontalAligns;
map_int_t MaterialColors;
map_int_t MaterialScalars;
map_int_t MaterialTextures;
map_int_t MeshDrawModes;
map_int_t MeshUsages;
map_int_t StencilActions;
map_int_t TextureFormats;
map_int_t TextureTypes;
map_int_t VerticalAligns;
map_int_t Windings;
map_int_t WrapModes;
const char* ArcModes[] = {
[ARC_MODE_PIE] = "pie",
[ARC_MODE_OPEN] = "open",
[ARC_MODE_CLOSED] = "closed",
NULL
};
const char* AttributeTypes[] = {
[ATTR_FLOAT] = "float",
[ATTR_BYTE] = "byte",
[ATTR_INT] = "int",
NULL
};
const char* BlendAlphaModes[] = {
[BLEND_ALPHA_MULTIPLY] = "alphamultiply",
[BLEND_PREMULTIPLIED] = "premultiplied",
NULL
};
const char* BlendModes[] = {
[BLEND_ALPHA] = "alpha",
[BLEND_ADD] = "add",
[BLEND_SUBTRACT] = "subtract",
[BLEND_MULTIPLY] = "multiply",
[BLEND_LIGHTEN] = "lighten",
[BLEND_DARKEN] = "darken",
[BLEND_SCREEN] = "screen",
[BLEND_REPLACE] = "replace",
NULL
};
const char* CompareModes[] = {
[COMPARE_EQUAL] = "equal",
[COMPARE_NEQUAL] = "notequal",
[COMPARE_LESS] = "less",
[COMPARE_LEQUAL] = "lequal",
[COMPARE_GREATER] = "greater",
[COMPARE_GEQUAL] = "gequal",
NULL
};
const char* DrawModes[] = {
[DRAW_MODE_FILL] = "fill",
[DRAW_MODE_LINE] = "line",
NULL
};
const char* FilterModes[] = {
[FILTER_NEAREST] = "nearest",
[FILTER_BILINEAR] = "bilinear",
[FILTER_TRILINEAR] = "trilinear",
[FILTER_ANISOTROPIC] = "anisotropic",
NULL
};
const char* HorizontalAligns[] = {
[ALIGN_LEFT] = "left",
[ALIGN_RIGHT] = "right",
[ALIGN_CENTER] = "center",
NULL
};
const char* MaterialColors[] = {
[COLOR_DIFFUSE] = "diffuse",
[COLOR_EMISSIVE] = "emissive",
NULL
};
const char* MaterialScalars[] = {
[SCALAR_METALNESS] = "metalness",
[SCALAR_ROUGHNESS] = "roughness",
NULL
};
const char* MaterialTextures[] = {
[TEXTURE_DIFFUSE] = "diffuse",
[TEXTURE_EMISSIVE] = "emissive",
[TEXTURE_METALNESS] = "metalness",
[TEXTURE_ROUGHNESS] = "roughness",
[TEXTURE_OCCLUSION] = "occlusion",
[TEXTURE_NORMAL] = "normal",
[TEXTURE_ENVIRONMENT_MAP] = "environment",
NULL
};
const char* MeshDrawModes[] = {
[MESH_POINTS] = "points",
[MESH_LINES] = "lines",
[MESH_LINE_STRIP] = "linestrip",
[MESH_TRIANGLE_STRIP] = "strip",
[MESH_TRIANGLES] = "triangles",
[MESH_TRIANGLE_FAN] = "fan",
NULL
};
const char* MeshUsages[] = {
[MESH_STATIC] = "static",
[MESH_DYNAMIC] = "dynamic",
[MESH_STREAM] = "stream",
NULL
};
const char* StencilActions[] = {
[STENCIL_REPLACE] = "replace",
[STENCIL_INCREMENT] = "increment",
[STENCIL_DECREMENT] = "decrement",
[STENCIL_INCREMENT_WRAP] = "incrementwrap",
[STENCIL_DECREMENT_WRAP] = "decrementwrap",
[STENCIL_INVERT] = "invert",
NULL
};
const char* TextureFormats[] = {
[FORMAT_RGB] = "rgb",
[FORMAT_RGBA] = "rgba",
[FORMAT_RGBA16F] = "rgba16f",
[FORMAT_RGBA32F] = "rgba32f",
[FORMAT_RG11B10F] = "rg11b10f",
[FORMAT_DXT1] = "dxt1",
[FORMAT_DXT3] = "dxt3",
[FORMAT_DXT5] = "dxt5",
NULL
};
const char* TextureTypes[] = {
[TEXTURE_2D] = "2d",
[TEXTURE_ARRAY] = "array",
[TEXTURE_CUBE] = "cube",
[TEXTURE_VOLUME] = "volume",
NULL
};
const char* VerticalAligns[] = {
[ALIGN_TOP] = "top",
[ALIGN_BOTTOM] = "bottom",
[ALIGN_MIDDLE] = "middle",
NULL
};
const char* Windings[] = {
[WINDING_CLOCKWISE] = "clockwise",
[WINDING_COUNTERCLOCKWISE] = "counterclockwise",
NULL
};
const char* WrapModes[] = {
[WRAP_CLAMP] = "clamp",
[WRAP_REPEAT] = "repeat",
[WRAP_MIRRORED_REPEAT] = "mirroredrepeat",
NULL
};
static uint32_t luax_readvertices(lua_State* L, int index) {
bool isTable = lua_istable(L, index);
@ -102,122 +235,6 @@ int l_lovrGraphicsInit(lua_State* L) {
luax_registertype(L, "Shader", lovrShader);
luax_registertype(L, "Texture", lovrTexture);
luax_extendtype(L, "Texture", "Canvas", lovrTexture, lovrCanvas);
map_init(&ArcModes);
map_set(&ArcModes, "pie", ARC_MODE_PIE);
map_set(&ArcModes, "open", ARC_MODE_OPEN);
map_set(&ArcModes, "closed", ARC_MODE_CLOSED);
map_init(&AttributeTypes);
map_set(&AttributeTypes, "float", ATTR_FLOAT);
map_set(&AttributeTypes, "byte", ATTR_BYTE);
map_set(&AttributeTypes, "int", ATTR_INT);
map_init(&BlendAlphaModes);
map_set(&BlendAlphaModes, "alphamultiply", BLEND_ALPHA_MULTIPLY);
map_set(&BlendAlphaModes, "premultiplied", BLEND_PREMULTIPLIED);
map_init(&BlendModes);
map_set(&BlendModes, "alpha", BLEND_ALPHA);
map_set(&BlendModes, "add", BLEND_ADD);
map_set(&BlendModes, "subtract", BLEND_SUBTRACT);
map_set(&BlendModes, "multiply", BLEND_MULTIPLY);
map_set(&BlendModes, "lighten", BLEND_LIGHTEN);
map_set(&BlendModes, "darken", BLEND_DARKEN);
map_set(&BlendModes, "screen", BLEND_SCREEN);
map_set(&BlendModes, "replace", BLEND_REPLACE);
map_init(&CompareModes);
map_set(&CompareModes, "equal", COMPARE_EQUAL);
map_set(&CompareModes, "notequal", COMPARE_NOT_EQUAL);
map_set(&CompareModes, "less", COMPARE_LESS);
map_set(&CompareModes, "lequal", COMPARE_LEQUAL);
map_set(&CompareModes, "gequal", COMPARE_GEQUAL);
map_set(&CompareModes, "greater", COMPARE_GREATER);
map_init(&DrawModes);
map_set(&DrawModes, "fill", DRAW_MODE_FILL);
map_set(&DrawModes, "line", DRAW_MODE_LINE);
map_init(&FilterModes);
map_set(&FilterModes, "nearest", FILTER_NEAREST);
map_set(&FilterModes, "bilinear", FILTER_BILINEAR);
map_set(&FilterModes, "trilinear", FILTER_TRILINEAR);
map_set(&FilterModes, "anisotropic", FILTER_ANISOTROPIC);
map_init(&HorizontalAligns);
map_set(&HorizontalAligns, "left", ALIGN_LEFT);
map_set(&HorizontalAligns, "right", ALIGN_RIGHT);
map_set(&HorizontalAligns, "center", ALIGN_CENTER);
map_init(&MaterialColors);
map_set(&MaterialColors, "diffuse", COLOR_DIFFUSE);
map_set(&MaterialColors, "emissive", COLOR_EMISSIVE);
map_init(&MaterialScalars);
map_set(&MaterialScalars, "metalness", SCALAR_METALNESS);
map_set(&MaterialScalars, "roughness", SCALAR_ROUGHNESS);
map_init(&MaterialTextures);
map_set(&MaterialTextures, "diffuse", TEXTURE_DIFFUSE);
map_set(&MaterialTextures, "emissive", TEXTURE_EMISSIVE);
map_set(&MaterialTextures, "metalness", TEXTURE_METALNESS);
map_set(&MaterialTextures, "roughness", TEXTURE_ROUGHNESS);
map_set(&MaterialTextures, "occlusion", TEXTURE_OCCLUSION);
map_set(&MaterialTextures, "normal", TEXTURE_NORMAL);
map_set(&MaterialTextures, "environment", TEXTURE_ENVIRONMENT_MAP);
map_init(&MeshDrawModes);
map_set(&MeshDrawModes, "points", MESH_POINTS);
map_set(&MeshDrawModes, "lines", MESH_LINES);
map_set(&MeshDrawModes, "linestrip", MESH_LINE_STRIP);
map_set(&MeshDrawModes, "strip", MESH_TRIANGLE_STRIP);
map_set(&MeshDrawModes, "triangles", MESH_TRIANGLES);
map_set(&MeshDrawModes, "fan", MESH_TRIANGLE_FAN);
map_init(&MeshUsages);
map_set(&MeshUsages, "static", MESH_STATIC);
map_set(&MeshUsages, "dynamic", MESH_DYNAMIC);
map_set(&MeshUsages, "stream", MESH_STREAM);
map_init(&StencilActions);
map_set(&StencilActions, "replace", STENCIL_REPLACE);
map_set(&StencilActions, "increment", STENCIL_INCREMENT);
map_set(&StencilActions, "decrement", STENCIL_DECREMENT);
map_set(&StencilActions, "incrementwrap", STENCIL_INCREMENT_WRAP);
map_set(&StencilActions, "decrementwrap", STENCIL_DECREMENT_WRAP);
map_set(&StencilActions, "invert", STENCIL_INVERT);
map_init(&TextureFormats);
map_set(&TextureFormats, "rgb", FORMAT_RGB);
map_set(&TextureFormats, "rgba", FORMAT_RGBA);
map_set(&TextureFormats, "rgba16f", FORMAT_RGBA16F);
map_set(&TextureFormats, "rgba32f", FORMAT_RGBA32F);
map_set(&TextureFormats, "rg11b10f", FORMAT_RG11B10F);
map_set(&TextureFormats, "dxt1", FORMAT_DXT1);
map_set(&TextureFormats, "dxt3", FORMAT_DXT3);
map_set(&TextureFormats, "dxt5", FORMAT_DXT5);
map_init(&TextureTypes);
map_set(&TextureTypes, "2d", TEXTURE_2D);
map_set(&TextureTypes, "array", TEXTURE_ARRAY);
map_set(&TextureTypes, "cube", TEXTURE_CUBE);
map_set(&TextureTypes, "volume", TEXTURE_VOLUME);
map_init(&VerticalAligns);
map_set(&VerticalAligns, "top", ALIGN_TOP);
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);
map_set(&WrapModes, "mirroredrepeat", WRAP_MIRRORED_REPEAT);
lovrGraphicsInit();
luax_pushconf(L);
@ -386,14 +403,14 @@ int l_lovrGraphicsGetBlendMode(lua_State* L) {
BlendMode mode;
BlendAlphaMode alphaMode;
lovrGraphicsGetBlendMode(&mode, &alphaMode);
luax_pushenum(L, &BlendModes, mode);
luax_pushenum(L, &BlendAlphaModes, alphaMode);
lua_pushstring(L, BlendModes[mode]);
lua_pushstring(L, BlendAlphaModes[alphaMode]);
return 2;
}
int l_lovrGraphicsSetBlendMode(lua_State* L) {
BlendMode mode = *(BlendMode*) luax_checkenum(L, 1, &BlendModes, "blend mode");
BlendAlphaMode alphaMode = *(BlendAlphaMode*) luax_optenum(L, 2, "alphamultiply", &BlendAlphaModes, "alpha blend mode");
BlendMode mode = luaL_checkoption(L, 1, NULL, BlendModes);
BlendAlphaMode alphaMode = luaL_checkoption(L, 2, "alphamultiply", BlendAlphaModes);
lovrGraphicsSetBlendMode(mode, alphaMode);
return 0;
}
@ -445,7 +462,7 @@ int l_lovrGraphicsSetCullingEnabled(lua_State* L) {
int l_lovrGraphicsGetDefaultFilter(lua_State* L) {
TextureFilter filter = lovrGraphicsGetDefaultFilter();
luax_pushenum(L, &FilterModes, filter.mode);
lua_pushstring(L, FilterModes[filter.mode]);
if (filter.mode == FILTER_ANISOTROPIC) {
lua_pushnumber(L, filter.anisotropy);
return 2;
@ -454,10 +471,9 @@ int l_lovrGraphicsGetDefaultFilter(lua_State* L) {
}
int l_lovrGraphicsSetDefaultFilter(lua_State* L) {
FilterMode mode = *(FilterMode*) luax_checkenum(L, 1, &FilterModes, "filter mode");
FilterMode mode = luaL_checkoption(L, 1, NULL, FilterModes);
float anisotropy = luaL_optnumber(L, 2, 1.);
TextureFilter filter = { .mode = mode, .anisotropy = anisotropy };
lovrGraphicsSetDefaultFilter(filter);
lovrGraphicsSetDefaultFilter((TextureFilter) { .mode = mode, .anisotropy = anisotropy });
return 0;
}
@ -465,18 +481,13 @@ int l_lovrGraphicsGetDepthTest(lua_State* L) {
CompareMode mode;
bool write;
lovrGraphicsGetDepthTest(&mode, &write);
luax_pushenum(L, &CompareModes, mode);
lua_pushstring(L, CompareModes[mode]);
lua_pushboolean(L, write);
return 2;
}
int l_lovrGraphicsSetDepthTest(lua_State* L) {
CompareMode mode = COMPARE_NONE;
if (lua_type(L, 1) == LUA_TSTRING) {
mode = *(CompareMode*) luax_checkenum(L, 1, &CompareModes, "compare mode");
}
CompareMode mode = lua_isnoneornil(L, 1) ? COMPARE_NONE : luaL_checkoption(L, 1, NULL, CompareModes);
bool write = lua_isnoneornil(L, 2) ? true : lua_toboolean(L, 2);
lovrGraphicsSetDepthTest(mode, write);
return 0;
@ -558,7 +569,7 @@ int l_lovrGraphicsGetStencilTest(lua_State* L) {
return 1;
}
luax_pushenum(L, &CompareModes, mode);
lua_pushstring(L, CompareModes[mode]);
lua_pushinteger(L, value);
return 2;
}
@ -567,7 +578,7 @@ int l_lovrGraphicsSetStencilTest(lua_State* L) {
if (lua_isnoneornil(L, 1)) {
lovrGraphicsSetStencilTest(COMPARE_NONE, 0);
} else {
CompareMode mode = *(CompareMode*) luax_checkenum(L, 1, &CompareModes, "compare mode");
CompareMode mode = luaL_checkoption(L, 1, NULL, CompareModes);
int value = luaL_checkinteger(L, 2);
lovrGraphicsSetStencilTest(mode, value);
}
@ -575,13 +586,12 @@ int l_lovrGraphicsSetStencilTest(lua_State* L) {
}
int l_lovrGraphicsGetWinding(lua_State* L) {
luax_pushenum(L, &Windings, lovrGraphicsGetWinding());
lua_pushstring(L, Windings[lovrGraphicsGetWinding()]);
return 1;
}
int l_lovrGraphicsSetWinding(lua_State* L) {
Winding* winding = (Winding*) luax_checkenum(L, 1, &Windings, "winding");
lovrGraphicsSetWinding(*winding);
lovrGraphicsSetWinding(luaL_checkoption(L, 1, NULL, Windings));
return 0;
}
@ -664,7 +674,7 @@ int l_lovrGraphicsTriangle(lua_State* L) {
if (lua_isuserdata(L, 1)) {
material = luax_checktype(L, 1, Material);
} else {
drawMode = *(DrawMode*) luax_checkenum(L, 1, &DrawModes, "draw mode");
drawMode = luaL_checkoption(L, 1, NULL, DrawModes);
}
float points[9];
@ -683,7 +693,7 @@ int l_lovrGraphicsPlane(lua_State* L) {
if (lua_isuserdata(L, 1)) {
material = luax_checktype(L, 1, Material);
} else {
drawMode = *(DrawMode*) luax_checkenum(L, 1, &DrawModes, "draw mode");
drawMode = luaL_checkoption(L, 1, NULL, DrawModes);
}
float transform[16];
luax_readtransform(L, 2, transform, 2);
@ -697,7 +707,7 @@ static int luax_rectangularprism(lua_State* L, int scaleComponents) {
if (lua_isuserdata(L, 1)) {
material = luax_checktype(L, 1, Material);
} else {
drawMode = *(DrawMode*) luax_checkenum(L, 1, &DrawModes, "draw mode");
drawMode = luaL_checkoption(L, 1, NULL, DrawModes);
}
float transform[16];
luax_readtransform(L, 2, transform, scaleComponents);
@ -719,12 +729,12 @@ int l_lovrGraphicsArc(lua_State* L) {
if (lua_isuserdata(L, 1)) {
material = luax_checktype(L, 1, Material);
} else {
drawMode = *(DrawMode*) luax_checkenum(L, 1, &DrawModes, "draw mode");
drawMode = luaL_checkoption(L, 1, NULL, DrawModes);
}
ArcMode arcMode = ARC_MODE_PIE;
int index = 2;
if (lua_type(L, index) == LUA_TSTRING) {
arcMode = *(ArcMode*) luax_checkenum(L, index++, &ArcModes, "arc mode");
arcMode = luaL_checkoption(L, index++, NULL, ArcModes);
}
float transform[16];
index = luax_readtransform(L, index, transform, 1);
@ -741,7 +751,7 @@ int l_lovrGraphicsCircle(lua_State* L) {
if (lua_isuserdata(L, 1)) {
material = luax_checktype(L, 1, Material);
} else {
drawMode = *(DrawMode*) luax_checkenum(L, 1, &DrawModes, "draw mode");
drawMode = luaL_checkoption(L, 1, NULL, DrawModes);
}
float transform[16];
int index = luax_readtransform(L, 2, transform, 1);
@ -792,15 +802,15 @@ int l_lovrGraphicsPrint(lua_State* L) {
float transform[16];
int index = luax_readtransform(L, 2, transform, 1);
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");
HorizontalAlign halign = luaL_checkoption(L, index++, "center", HorizontalAligns);
VerticalAlign valign = luaL_checkoption(L, index++, "middle", VerticalAligns);
lovrGraphicsPrint(str, transform, wrap, halign, valign);
return 0;
}
int l_lovrGraphicsStencil(lua_State* L) {
luaL_checktype(L, 1, LUA_TFUNCTION);
StencilAction action = *(StencilAction*) luax_optenum(L, 2, "replace", &StencilActions, "stencil action");
StencilAction action = luaL_checkoption(L, 2, "replace", StencilActions);
int replaceValue = luaL_optinteger(L, 3, 1);
bool keepValues = lua_toboolean(L, 4);
if (!keepValues) {
@ -839,7 +849,7 @@ int l_lovrGraphicsNewCanvas(lua_State* L) {
if (lua_istable(L, 3)) {
lua_getfield(L, 3, "format");
format = *(TextureFormat*) luax_optenum(L, -1, "rgba", &TextureFormats, "canvas format");
format = luaL_checkoption(L, -1, "rgba", TextureFormats);
lua_pop(L, 1);
lua_getfield(L, 3, "msaa");
@ -967,9 +977,9 @@ int l_lovrGraphicsNewMesh(lua_State* L) {
vertexFormatAppend(&format, "lovrTexCoord", ATTR_FLOAT, 2);
}
MeshDrawMode* drawMode = (MeshDrawMode*) luax_optenum(L, drawModeIndex, "fan", &MeshDrawModes, "mesh draw mode");
MeshUsage* usage = (MeshUsage*) luax_optenum(L, drawModeIndex + 1, "dynamic", &MeshUsages, "mesh usage");
Mesh* mesh = lovrMeshCreate(count, format, *drawMode, *usage);
MeshDrawMode drawMode = luaL_checkoption(L, drawModeIndex, "fan", MeshDrawModes);
MeshUsage usage = luaL_checkoption(L, drawModeIndex + 1, "dynamic", MeshUsages);
Mesh* mesh = lovrMeshCreate(count, format, drawMode, usage);
if (dataIndex) {
VertexPointer vertices = lovrMeshMapVertices(mesh, 0, lua_objlen(L, dataIndex), false, true);
@ -1070,7 +1080,7 @@ int l_lovrGraphicsNewTexture(lua_State* L) {
lua_getfield(L, 2, "type");
if (!lua_isnil(L, -1)) {
type = *(TextureType*) luax_checkenum(L, -1, &TextureTypes, "texture type");
type = luaL_checkoption(L, -1, NULL, TextureTypes);
}
lua_pop(L, 1);
}

View File

@ -1,13 +1,60 @@
#include "api.h"
#include "headset/headset.h"
map_int_t ControllerAxes;
map_int_t ControllerButtons;
map_int_t ControllerHands;
map_int_t HeadsetDrivers;
map_int_t HeadsetEyes;
map_int_t HeadsetOrigins;
map_int_t HeadsetTypes;
const char* ControllerAxes[] = {
[CONTROLLER_AXIS_TRIGGER] = "trigger",
[CONTROLLER_AXIS_GRIP] = "grip",
[CONTROLLER_AXIS_TOUCHPAD_X] = "touchx",
[CONTROLLER_AXIS_TOUCHPAD_Y] = "touchy",
NULL
};
const char* ControllerButtons[] = {
[CONTROLLER_BUTTON_SYSTEM] = "system",
[CONTROLLER_BUTTON_MENU] = "menu",
[CONTROLLER_BUTTON_TRIGGER] = "trigger",
[CONTROLLER_BUTTON_GRIP] = "grip",
[CONTROLLER_BUTTON_TOUCHPAD] = "touchpad",
[CONTROLLER_BUTTON_A] = "a",
[CONTROLLER_BUTTON_B] = "b",
[CONTROLLER_BUTTON_X] = "x",
[CONTROLLER_BUTTON_Y] = "y",
NULL
};
const char* ControllerHands[] = {
[HAND_UNKNOWN] = "unknown",
[HAND_LEFT] = "left",
[HAND_RIGHT] = "right",
NULL
};
const char* HeadsetDrivers[] = {
[DRIVER_FAKE] = "fake",
[DRIVER_OPENVR] = "openvr",
[DRIVER_WEBVR] = "webvr",
NULL
};
const char* HeadsetEyes[] = {
[EYE_LEFT] = "left",
[EYE_RIGHT] = "right",
NULL
};
const char* HeadsetOrigins[] = {
[ORIGIN_HEAD] = "head",
[ORIGIN_FLOOR] = "floor",
NULL
};
const char* HeadsetTypes[] = {
[HEADSET_UNKNOWN] = "unknown",
[HEADSET_VIVE] = "vive",
[HEADSET_RIFT] = "rift",
[HEADSET_WINDOWS_MR] = "windowsmr",
NULL
};
typedef struct {
lua_State* L;
@ -32,47 +79,6 @@ int l_lovrHeadsetInit(lua_State* L) {
luaL_register(L, NULL, lovrHeadset);
luax_registertype(L, "Controller", lovrController);
map_init(&ControllerAxes);
map_set(&ControllerAxes, "trigger", CONTROLLER_AXIS_TRIGGER);
map_set(&ControllerAxes, "grip", CONTROLLER_AXIS_GRIP);
map_set(&ControllerAxes, "touchx", CONTROLLER_AXIS_TOUCHPAD_X);
map_set(&ControllerAxes, "touchy", CONTROLLER_AXIS_TOUCHPAD_Y);
map_init(&ControllerButtons);
map_set(&ControllerButtons, "system", CONTROLLER_BUTTON_SYSTEM);
map_set(&ControllerButtons, "menu", CONTROLLER_BUTTON_MENU);
map_set(&ControllerButtons, "trigger", CONTROLLER_BUTTON_TRIGGER);
map_set(&ControllerButtons, "grip", CONTROLLER_BUTTON_GRIP);
map_set(&ControllerButtons, "touchpad", CONTROLLER_BUTTON_TOUCHPAD);
map_set(&ControllerButtons, "a", CONTROLLER_BUTTON_A);
map_set(&ControllerButtons, "b", CONTROLLER_BUTTON_B);
map_set(&ControllerButtons, "x", CONTROLLER_BUTTON_X);
map_set(&ControllerButtons, "y", CONTROLLER_BUTTON_Y);
map_init(&ControllerHands);
map_set(&ControllerHands, "unknown", HAND_UNKNOWN);
map_set(&ControllerHands, "left", HAND_LEFT);
map_set(&ControllerHands, "right", HAND_RIGHT);
map_init(&HeadsetEyes);
map_set(&HeadsetEyes, "left", EYE_LEFT);
map_set(&HeadsetEyes, "right", EYE_RIGHT);
map_init(&HeadsetOrigins);
map_set(&HeadsetOrigins, "head", ORIGIN_HEAD);
map_set(&HeadsetOrigins, "floor", ORIGIN_FLOOR);
map_init(&HeadsetTypes);
map_set(&HeadsetTypes, "unknown", HEADSET_UNKNOWN);
map_set(&HeadsetTypes, "vive", HEADSET_VIVE);
map_set(&HeadsetTypes, "rift", HEADSET_RIFT);
map_set(&HeadsetTypes, "windowsmr", HEADSET_WINDOWS_MR);
map_init(&HeadsetDrivers);
map_set(&HeadsetDrivers, "fake", DRIVER_FAKE);
map_set(&HeadsetDrivers, "openvr", DRIVER_OPENVR);
map_set(&HeadsetDrivers, "webvr", DRIVER_WEBVR);
luax_pushconf(L);
lua_getfield(L, -1, "headset");
@ -88,7 +94,7 @@ int l_lovrHeadsetInit(lua_State* L) {
int n = lua_objlen(L, -1);
for (int i = 0; i < n; i++) {
lua_rawgeti(L, -1, i + 1);
vec_push(&drivers, *(HeadsetDriver*) luax_checkenum(L, -1, &HeadsetDrivers, "headset driver"));
vec_push(&drivers, luaL_checkoption(L, -1, NULL, HeadsetDrivers));
lua_pop(L, 1);
}
lua_pop(L, 1);
@ -116,17 +122,17 @@ int l_lovrHeadsetInit(lua_State* L) {
}
int l_lovrHeadsetGetDriver(lua_State* L) {
luax_pushenum(L, &HeadsetDrivers, lovrHeadsetDriver->driverType);
lua_pushstring(L, HeadsetDrivers[lovrHeadsetDriver->driverType]);
return 1;
}
int l_lovrHeadsetGetType(lua_State* L) {
luax_pushenum(L, &HeadsetTypes, lovrHeadsetDriver->getType());
lua_pushstring(L, HeadsetTypes[lovrHeadsetDriver->getType()]);
return 1;
}
int l_lovrHeadsetGetOriginType(lua_State* L) {
luax_pushenum(L, &HeadsetOrigins, lovrHeadsetDriver->getOriginType());
lua_pushstring(L, HeadsetOrigins[lovrHeadsetDriver->getOriginType()]);
return 1;
}
@ -207,7 +213,7 @@ int l_lovrHeadsetGetBoundsDimensions(lua_State* L) {
static void luax_getPose(lua_State* L, float* x, float* y, float* z, float* angle, float* ax, float* ay, float* az) {
if (lua_type(L, 1) == LUA_TSTRING) {
HeadsetEye eye = *(HeadsetEye*) luax_checkenum(L, 1, &HeadsetEyes, "eye");
HeadsetEye eye = luaL_checkoption(L, 1, NULL, HeadsetEyes);
lovrHeadsetDriver->getEyePose(eye, x, y, z, angle, ax, ay, az);
} else {
lovrHeadsetDriver->getPose(x, y, z, angle, ax, ay, az);

View File

@ -1,8 +1,21 @@
#include "api.h"
#include "physics/physics.h"
map_int_t ShapeTypes;
map_int_t JointTypes;
const char* ShapeTypes[] = {
[SHAPE_SPHERE] = "sphere",
[SHAPE_BOX] = "box",
[SHAPE_CAPSULE] = "capsule",
[SHAPE_CYLINDER] = "cylinder",
NULL
};
const char* JointTypes[] = {
[JOINT_BALL] = "ball",
[JOINT_DISTANCE] = "distance",
[JOINT_HINGE] = "hinge",
[JOINT_SLIDER] = "slider",
NULL
};
int l_lovrPhysicsInit(lua_State* L) {
lua_newtable(L);
@ -17,19 +30,6 @@ int l_lovrPhysicsInit(lua_State* L) {
luax_extendtype(L, "Shape", "BoxShape", lovrShape, lovrBoxShape);
luax_extendtype(L, "Shape", "CapsuleShape", lovrShape, lovrCapsuleShape);
luax_extendtype(L, "Shape", "CylinderShape", lovrShape, lovrCylinderShape);
map_init(&JointTypes);
map_set(&JointTypes, "ball", JOINT_BALL);
map_set(&JointTypes, "distance", JOINT_DISTANCE);
map_set(&JointTypes, "hinge", JOINT_HINGE);
map_set(&JointTypes, "slider", JOINT_SLIDER);
map_init(&ShapeTypes);
map_set(&ShapeTypes, "sphere", SHAPE_SPHERE);
map_set(&ShapeTypes, "box", SHAPE_BOX);
map_set(&ShapeTypes, "capsule", SHAPE_CAPSULE);
map_set(&ShapeTypes, "cylinder", SHAPE_CYLINDER);
lovrPhysicsInit();
return 1;
}

View File

@ -19,7 +19,7 @@ int l_lovrCanvasRenderTo(lua_State* L) {
int l_lovrCanvasGetFormat(lua_State* L) {
Canvas* canvas = luax_checktype(L, 1, Canvas);
TextureFormat format = lovrCanvasGetFormat(canvas);
luax_pushenum(L, &TextureFormats, format);
lua_pushstring(L, TextureFormats[format]);
return 1;
}

View File

@ -12,7 +12,7 @@ int l_lovrControllerIsConnected(lua_State* L) {
int l_lovrControllerGetHand(lua_State* L) {
Controller* controller = luax_checktype(L, 1, Controller);
ControllerHand hand = lovrHeadsetDriver->controllerGetHand(controller);
luax_pushenum(L, &ControllerHands, hand);
lua_pushstring(L, ControllerHands[hand]);
return 1;
}
@ -53,22 +53,22 @@ int l_lovrControllerGetOrientation(lua_State* L) {
int l_lovrControllerGetAxis(lua_State* L) {
Controller* controller = luax_checktype(L, 1, Controller);
ControllerAxis* axis = (ControllerAxis*) luax_checkenum(L, 2, &ControllerAxes, "controller axis");
lua_pushnumber(L, lovrHeadsetDriver->controllerGetAxis(controller, *axis));
ControllerAxis axis = luaL_checkoption(L, 2, NULL, ControllerAxes);
lua_pushnumber(L, lovrHeadsetDriver->controllerGetAxis(controller, axis));
return 1;
}
int l_lovrControllerIsDown(lua_State* L) {
Controller* controller = luax_checktype(L, 1, Controller);
ControllerButton* button = (ControllerButton*) luax_checkenum(L, 2, &ControllerButtons, "controller button");
lua_pushboolean(L, lovrHeadsetDriver->controllerIsDown(controller, *button));
ControllerButton button = luaL_checkoption(L, 2, NULL, ControllerButtons);
lua_pushboolean(L, lovrHeadsetDriver->controllerIsDown(controller, button));
return 1;
}
int l_lovrControllerIsTouched(lua_State* L) {
Controller* controller = luax_checktype(L, 1, Controller);
ControllerButton* button = (ControllerButton*) luax_checkenum(L, 2, &ControllerButtons, "controller button");
lua_pushboolean(L, lovrHeadsetDriver->controllerIsTouched(controller, *button));
ControllerButton button = luaL_checkoption(L, 2, NULL, ControllerButtons);
lua_pushboolean(L, lovrHeadsetDriver->controllerIsTouched(controller, button));
return 1;
}

View File

@ -19,7 +19,7 @@ int l_lovrJointDestroy(lua_State* L) {
int l_lovrJointGetType(lua_State* L) {
Joint* joint = luax_checktypeof(L, 1, Joint);
luax_pushenum(L, &JointTypes, lovrJointGetType(joint));
lua_pushstring(L, JointTypes[lovrJointGetType(joint)]);
return 1;
}

View File

@ -3,7 +3,7 @@
int l_lovrMaterialGetColor(lua_State* L) {
Material* material = luax_checktype(L, 1, Material);
MaterialColor colorType = *(MaterialColor*) luax_optenum(L, 2, "diffuse", &MaterialColors, "color");
MaterialColor colorType = luaL_checkoption(L, 2, "diffuse", MaterialColors);
Color color = lovrMaterialGetColor(material, colorType);
lua_pushnumber(L, color.r);
lua_pushnumber(L, color.g);
@ -17,7 +17,7 @@ int l_lovrMaterialSetColor(lua_State* L) {
MaterialColor colorType = COLOR_DIFFUSE;
int index = 2;
if (lua_type(L, index) == LUA_TSTRING) {
colorType = *(MaterialColor*) luax_checkenum(L, index, &MaterialColors, "color");
colorType = luaL_checkoption(L, index, NULL, MaterialColors);
index++;
}
Color color = luax_checkcolor(L, index);
@ -27,7 +27,7 @@ int l_lovrMaterialSetColor(lua_State* L) {
int l_lovrMaterialGetScalar(lua_State* L) {
Material* material = luax_checktype(L, 1, Material);
MaterialScalar scalarType = *(MaterialScalar*) luax_checkenum(L, 2, &MaterialScalars, "scalar");
MaterialScalar scalarType = luaL_checkoption(L, 2, NULL, MaterialScalars);
float value = lovrMaterialGetScalar(material, scalarType);
lua_pushnumber(L, value);
return 1;
@ -35,7 +35,7 @@ int l_lovrMaterialGetScalar(lua_State* L) {
int l_lovrMaterialSetScalar(lua_State* L) {
Material* material = luax_checktype(L, 1, Material);
MaterialScalar scalarType = *(MaterialScalar*) luax_checkenum(L, 2, &MaterialScalars, "scalar");
MaterialScalar scalarType = luaL_checkoption(L, 2, NULL, MaterialScalars);
float value = luaL_checknumber(L, 3);
lovrMaterialSetScalar(material, scalarType, value);
return 0;
@ -43,7 +43,7 @@ int l_lovrMaterialSetScalar(lua_State* L) {
int l_lovrMaterialGetTexture(lua_State* L) {
Material* material = luax_checktype(L, 1, Material);
MaterialTexture textureType = *(MaterialTexture*) luax_optenum(L, 2, "diffuse", &MaterialTextures, "texture");
MaterialTexture textureType = luaL_checkoption(L, 2, "diffuse", MaterialTextures);
Texture* texture = lovrMaterialGetTexture(material, textureType);
luax_pushtype(L, Texture, texture);
return 1;
@ -54,7 +54,7 @@ int l_lovrMaterialSetTexture(lua_State* L) {
MaterialTexture textureType = TEXTURE_DIFFUSE;
int index = 2;
if (lua_type(L, index) == LUA_TSTRING) {
textureType = *(MaterialTexture*) luax_checkenum(L, index, &MaterialTextures, "texture");
textureType = luaL_checkoption(L, index, NULL, MaterialTextures);
index++;
}
Texture* texture = lua_isnoneornil(L, index) ? NULL : luax_checktypeof(L, index, Texture);

View File

@ -69,14 +69,14 @@ int l_lovrMeshDraw(lua_State* L) {
int l_lovrMeshGetDrawMode(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
luax_pushenum(L, &MeshDrawModes, lovrMeshGetDrawMode(mesh));
lua_pushstring(L, MeshDrawModes[lovrMeshGetDrawMode(mesh)]);
return 1;
}
int l_lovrMeshSetDrawMode(lua_State* L) {
Mesh* mesh = luax_checktype(L, 1, Mesh);
MeshDrawMode* drawMode = (MeshDrawMode*) luax_checkenum(L, 2, &MeshDrawModes, "mesh draw mode");
lovrMeshSetDrawMode(mesh, *drawMode);
MeshDrawMode drawMode = luaL_checkoption(L, 2, NULL, MeshDrawModes);
lovrMeshSetDrawMode(mesh, drawMode);
return 0;
}

View File

@ -19,7 +19,7 @@ int l_lovrShapeDestroy(lua_State* L) {
int l_lovrShapeGetType(lua_State* L) {
Shape* shape = luax_checktypeof(L, 1, Shape);
luax_pushenum(L, &ShapeTypes, lovrShapeGetType(shape));
lua_pushstring(L, ShapeTypes[lovrShapeGetType(shape)]);
return 1;
}

View File

@ -35,10 +35,10 @@ int l_lovrSourceGetDirection(lua_State* L) {
int l_lovrSourceGetDuration(lua_State* L) {
Source* source = luax_checktype(L, 1, Source);
TimeUnit* unit = luax_optenum(L, 2, "seconds", &TimeUnits, "unit");
TimeUnit unit = luaL_checkoption(L, 2, "seconds", TimeUnits);
int duration = lovrSourceGetDuration(source);
if (*unit == UNIT_SECONDS) {
if (unit == UNIT_SECONDS) {
lua_pushnumber(L, (float) duration / lovrSourceGetSampleRate(source));
} else {
lua_pushinteger(L, duration);
@ -151,9 +151,9 @@ int l_lovrSourceRewind(lua_State* L) {
int l_lovrSourceSeek(lua_State* L) {
Source* source = luax_checktype(L, 1, Source);
TimeUnit* unit = luax_optenum(L, 3, "seconds", &TimeUnits, "unit");
TimeUnit unit = luaL_checkoption(L, 3, "seconds", TimeUnits);
if (*unit == UNIT_SECONDS) {
if (unit == UNIT_SECONDS) {
float seconds = luaL_checknumber(L, 2);
int sampleRate = lovrSourceGetSampleRate(source);
lovrSourceSeek(source, (int) (seconds * sampleRate + .5f));
@ -243,10 +243,10 @@ int l_lovrSourceStop(lua_State* L) {
int l_lovrSourceTell(lua_State* L) {
Source* source = luax_checktype(L, 1, Source);
TimeUnit* unit = luax_optenum(L, 2, "seconds", &TimeUnits, "unit");
TimeUnit unit = luaL_checkoption(L, 2, "seconds", TimeUnits);
int offset = lovrSourceTell(source);
if (*unit == UNIT_SECONDS) {
if (unit == UNIT_SECONDS) {
lua_pushnumber(L, (float) offset / lovrSourceGetSampleRate(source));
} else {
lua_pushinteger(L, offset);

View File

@ -20,7 +20,7 @@ int l_lovrTextureGetDimensions(lua_State* L) {
int l_lovrTextureGetFilter(lua_State* L) {
Texture* texture = luax_checktypeof(L, 1, Texture);
TextureFilter filter = lovrTextureGetFilter(texture);
luax_pushenum(L, &FilterModes, filter.mode);
lua_pushstring(L, FilterModes[filter.mode]);
if (filter.mode == FILTER_ANISOTROPIC) {
lua_pushnumber(L, filter.anisotropy);
return 2;
@ -36,7 +36,7 @@ int l_lovrTextureGetHeight(lua_State* L) {
int l_lovrTextureGetType(lua_State* L) {
Texture* texture = luax_checktypeof(L, 1, Texture);
luax_pushenum(L, &TextureTypes, lovrTextureGetType(texture));
lua_pushstring(L, TextureTypes[lovrTextureGetType(texture)]);
return 1;
}
@ -49,10 +49,10 @@ int l_lovrTextureGetWidth(lua_State* L) {
int l_lovrTextureGetWrap(lua_State* L) {
Texture* texture = luax_checktypeof(L, 1, Texture);
TextureWrap wrap = lovrTextureGetWrap(texture);
luax_pushenum(L, &WrapModes, wrap.s);
luax_pushenum(L, &WrapModes, wrap.t);
lua_pushstring(L, WrapModes[wrap.s]);
lua_pushstring(L, WrapModes[wrap.t]);
if (texture->type == TEXTURE_CUBE) {
luax_pushenum(L, &WrapModes, wrap.r);
lua_pushstring(L, WrapModes[wrap.r]);
return 3;
}
return 2;
@ -68,19 +68,18 @@ int l_lovrTextureReplacePixels(lua_State* L) {
int l_lovrTextureSetFilter(lua_State* L) {
Texture* texture = luax_checktypeof(L, 1, Texture);
FilterMode mode = *(FilterMode*) luax_checkenum(L, 2, &FilterModes, "filter mode");
FilterMode mode = luaL_checkoption(L, 2, NULL, FilterModes);
float anisotropy = luaL_optnumber(L, 3, 1.);
TextureFilter filter = { .mode = mode, .anisotropy = anisotropy };
lovrTextureSetFilter(texture, filter);
lovrTextureSetFilter(texture, (TextureFilter) { .mode = mode, .anisotropy = anisotropy });
return 0;
}
int l_lovrTextureSetWrap(lua_State* L) {
Texture* texture = luax_checktypeof(L, 1, Texture);
TextureWrap wrap;
wrap.s = *(WrapMode*) luax_checkenum(L, 2, &WrapModes, "wrap mode");
wrap.t = *(WrapMode*) luax_optenum(L, 3, luaL_checkstring(L, 2), &WrapModes, "wrap mode");
wrap.r = *(WrapMode*) luax_optenum(L, 4, luaL_checkstring(L, 2), &WrapModes, "wrap mode");
wrap.s = luaL_checkoption(L, 2, NULL, WrapModes);
wrap.t = luaL_checkoption(L, 3, luaL_checkstring(L, 2), WrapModes);
wrap.r = luaL_checkoption(L, 4, luaL_checkstring(L, 2), WrapModes);
lovrTextureSetWrap(texture, wrap);
return 0;
}

View File

@ -49,9 +49,9 @@ bool luax_checkvertexformat(lua_State* L, int index, VertexFormat* format) {
lua_rawgeti(L, -3, 3);
const char* name = lua_tostring(L, -3);
AttributeType* type = (AttributeType*) luax_checkenum(L, -2, &AttributeTypes, "mesh attribute type");
AttributeType type = luaL_checkoption(L, -2, NULL, AttributeTypes);
int count = lua_tointeger(L, -1);
vertexFormatAppend(format, name, *type, count);
vertexFormatAppend(format, name, type, count);
lua_pop(L, 4);
}
@ -69,7 +69,7 @@ int luax_pushvertexformat(lua_State* L, VertexFormat* format) {
lua_rawseti(L, -2, 1);
// Type
luax_pushenum(L, &AttributeTypes, attribute.type);
lua_pushstring(L, AttributeTypes[attribute.type]);
lua_rawseti(L, -2, 2);
// Count

View File

@ -275,7 +275,7 @@ void lovrFontAddGlyph(Font* font, Glyph* glyph) {
glyph->y = atlas->y;
// Paste glyph into texture
lovrGraphicsBindTexture(font->texture, TEXTURE_2D, 0);
lovrGraphicsBindTexture(font->texture, GL_TEXTURE_2D, 0);
glTexSubImage2D(GL_TEXTURE_2D, 0, atlas->x, atlas->y, glyph->tw, glyph->th, GL_RGB, GL_UNSIGNED_BYTE, glyph->data);
// Advance atlas cursor

View File

@ -34,6 +34,30 @@ static void gammaCorrectColor(Color* color) {
}
}
static GLenum convertCompareMode(CompareMode mode) {
switch (mode) {
case COMPARE_NONE: return GL_ALWAYS;
case COMPARE_EQUAL: return GL_EQUAL;
case COMPARE_NEQUAL: return GL_NOTEQUAL;
case COMPARE_LESS: return GL_LESS;
case COMPARE_LEQUAL: return GL_LEQUAL;
case COMPARE_GREATER: return GL_GREATER;
case COMPARE_GEQUAL: return GL_GEQUAL;
}
}
static GLenum convertMeshDrawMode(MeshDrawMode drawMode) {
switch (drawMode) {
case MESH_POINTS: return GL_POINTS;
case MESH_LINES: return GL_LINES;
case MESH_LINE_STRIP: return GL_LINE_STRIP;
case MESH_LINE_LOOP: return GL_LINE_LOOP;
case MESH_TRIANGLE_STRIP: return GL_TRIANGLE_STRIP;
case MESH_TRIANGLES: return GL_TRIANGLES;
case MESH_TRIANGLE_FAN: return GL_TRIANGLE_FAN;
}
}
// Base
void lovrGraphicsInit() {
@ -345,11 +369,11 @@ void lovrGraphicsGetDepthTest(CompareMode* mode, bool* write) {
*write = state.depthWrite;
}
void lovrGraphicsSetDepthTest(CompareMode depthTest, bool write) {
if (state.depthTest != depthTest) {
state.depthTest = depthTest;
if (depthTest != COMPARE_NONE) {
glDepthFunc(depthTest);
void lovrGraphicsSetDepthTest(CompareMode mode, bool write) {
if (state.depthTest != mode) {
state.depthTest = mode;
if (mode != COMPARE_NONE) {
glDepthFunc(convertCompareMode(mode));
glEnable(GL_DEPTH_TEST);
} else {
glDisable(GL_DEPTH_TEST);
@ -454,12 +478,14 @@ void lovrGraphicsSetStencilTest(CompareMode mode, int value) {
state.stencilEnabled = true;
}
GLenum glMode = mode;
GLenum glMode = GL_ALWAYS;
switch (mode) {
case COMPARE_EQUAL: glMode = GL_EQUAL; break;
case COMPARE_NEQUAL: glMode = GL_NOTEQUAL; break;
case COMPARE_LESS: glMode = GL_GREATER; break;
case COMPARE_LEQUAL: glMode = GL_GEQUAL; break;
case COMPARE_GEQUAL: glMode = GL_LEQUAL; break;
case COMPARE_GREATER: glMode = GL_LESS; break;
case COMPARE_GEQUAL: glMode = GL_LEQUAL; break;
default: break;
}
@ -478,7 +504,8 @@ Winding lovrGraphicsGetWinding() {
void lovrGraphicsSetWinding(Winding winding) {
if (winding != state.winding) {
state.winding = winding;
glFrontFace(winding);
GLenum glWinding = winding == WINDING_CLOCKWISE ? GL_CW : GL_CCW;
glFrontFace(glWinding);
}
}
@ -959,8 +986,18 @@ void lovrGraphicsStencil(StencilAction action, int replaceValue, StencilCallback
state.stencilEnabled = true;
}
GLenum glAction;
switch (action) {
case STENCIL_REPLACE: glAction = GL_REPLACE; break;
case STENCIL_INCREMENT: glAction = GL_INCR; break;
case STENCIL_DECREMENT: glAction = GL_DECR; break;
case STENCIL_INCREMENT_WRAP: glAction = GL_INCR_WRAP; break;
case STENCIL_DECREMENT_WRAP: glAction = GL_DECR_WRAP; break;
case STENCIL_INVERT: glAction = GL_INVERT; break;
}
glStencilFunc(GL_ALWAYS, replaceValue, 0xff);
glStencilOp(GL_KEEP, GL_KEEP, action);
glStencilOp(GL_KEEP, GL_KEEP, glAction);
state.stencilWriting = true;
callback(userdata);
@ -1108,21 +1145,22 @@ void lovrGraphicsDraw(Mesh* mesh, mat4 transform, DefaultShader defaultShader, i
lovrMeshBind(mesh, shader);
size_t start = mesh->rangeStart;
GLenum glDrawMode = convertMeshDrawMode(mesh->drawMode);
if (mesh->indexCount > 0) {
size_t count = mesh->rangeCount ? mesh->rangeCount : mesh->indexCount;
GLenum indexType = mesh->indexSize == sizeof(uint16_t) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
size_t offset = start * mesh->indexSize;
if (instances > 1) {
glDrawElementsInstanced(mesh->drawMode, count, indexType, (GLvoid*) offset, instances);
glDrawElementsInstanced(glDrawMode, count, indexType, (GLvoid*) offset, instances);
} else {
glDrawElements(mesh->drawMode, count, indexType, (GLvoid*) offset);
glDrawElements(glDrawMode, count, indexType, (GLvoid*) offset);
}
} else {
size_t count = mesh->rangeCount ? mesh->rangeCount : mesh->count;
if (instances > 1) {
glDrawArraysInstanced(mesh->drawMode, start, count, instances);
glDrawArraysInstanced(glDrawMode, start, count, instances);
} else {
glDrawArrays(mesh->drawMode, start, count);
glDrawArrays(glDrawMode, start, count);
}
}
@ -1166,7 +1204,7 @@ Texture* lovrGraphicsGetTexture(int slot) {
return state.textures[slot];
}
void lovrGraphicsBindTexture(Texture* texture, TextureType type, int slot) {
void lovrGraphicsBindTexture(Texture* texture, GLenum type, int slot) {
if (!texture) {
if (!state.defaultTexture) {
TextureData* textureData = lovrTextureDataGetBlank(1, 1, 0xff, FORMAT_RGBA);

View File

@ -48,27 +48,27 @@ typedef enum {
} ArcMode;
typedef enum {
WINDING_CLOCKWISE = GL_CW,
WINDING_COUNTERCLOCKWISE = GL_CCW
WINDING_CLOCKWISE,
WINDING_COUNTERCLOCKWISE
} Winding;
typedef enum {
COMPARE_NONE = 0,
COMPARE_EQUAL = GL_EQUAL,
COMPARE_NOT_EQUAL = GL_NOTEQUAL,
COMPARE_LESS = GL_LESS,
COMPARE_LEQUAL = GL_LEQUAL,
COMPARE_GEQUAL = GL_GEQUAL,
COMPARE_GREATER = GL_GREATER
COMPARE_NONE,
COMPARE_EQUAL,
COMPARE_NEQUAL,
COMPARE_LESS,
COMPARE_LEQUAL,
COMPARE_GREATER,
COMPARE_GEQUAL
} CompareMode;
typedef enum {
STENCIL_REPLACE = GL_REPLACE,
STENCIL_INCREMENT = GL_INCR,
STENCIL_DECREMENT = GL_DECR,
STENCIL_INCREMENT_WRAP = GL_INCR_WRAP,
STENCIL_DECREMENT_WRAP = GL_DECR_WRAP,
STENCIL_INVERT = GL_INVERT
STENCIL_REPLACE,
STENCIL_INCREMENT,
STENCIL_DECREMENT,
STENCIL_INCREMENT_WRAP,
STENCIL_DECREMENT_WRAP,
STENCIL_INVERT
} StencilAction;
typedef struct {
@ -211,7 +211,7 @@ void lovrGraphicsPopLayer();
void lovrGraphicsSetCamera(mat4 projection, mat4 view);
void lovrGraphicsSetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height);
Texture* lovrGraphicsGetTexture(int slot);
void lovrGraphicsBindTexture(Texture* texture, TextureType type, int slot);
void lovrGraphicsBindTexture(Texture* texture, GLenum type, int slot);
Material* lovrGraphicsGetDefaultMaterial();
void lovrGraphicsUseProgram(uint32_t program);
void lovrGraphicsBindFramebuffer(uint32_t framebuffer);

View File

@ -6,6 +6,14 @@
#include <string.h>
#include <stdio.h>
static GLenum convertMeshUsage(MeshUsage usage) {
switch (usage) {
case MESH_STATIC: return GL_STATIC_DRAW;
case MESH_DYNAMIC: return GL_DYNAMIC_DRAW;
case MESH_STREAM: return GL_STREAM_DRAW;
}
}
Mesh* lovrMeshCreate(uint32_t count, VertexFormat format, MeshDrawMode drawMode, MeshUsage usage) {
Mesh* mesh = lovrAlloc(sizeof(Mesh), lovrMeshDestroy);
if (!mesh) return NULL;
@ -13,7 +21,7 @@ Mesh* lovrMeshCreate(uint32_t count, VertexFormat format, MeshDrawMode drawMode,
mesh->count = count;
mesh->format = format;
mesh->drawMode = drawMode;
mesh->usage = usage;
mesh->usage = convertMeshUsage(usage);
glGenBuffers(1, &mesh->vbo);
glGenBuffers(1, &mesh->ibo);

View File

@ -11,19 +11,19 @@
#define MAX_ATTACHMENTS 16
typedef enum {
MESH_POINTS = GL_POINTS,
MESH_LINES = GL_LINES,
MESH_LINE_STRIP = GL_LINE_STRIP,
MESH_LINE_LOOP = GL_LINE_LOOP,
MESH_TRIANGLE_STRIP = GL_TRIANGLE_STRIP,
MESH_TRIANGLES = GL_TRIANGLES,
MESH_TRIANGLE_FAN = GL_TRIANGLE_FAN
MESH_POINTS,
MESH_LINES,
MESH_LINE_STRIP,
MESH_LINE_LOOP,
MESH_TRIANGLE_STRIP,
MESH_TRIANGLES,
MESH_TRIANGLE_FAN
} MeshDrawMode;
typedef enum {
MESH_STATIC = GL_STATIC_DRAW,
MESH_DYNAMIC = GL_DYNAMIC_DRAW,
MESH_STREAM = GL_STREAM_DRAW
MESH_STATIC,
MESH_DYNAMIC,
MESH_STREAM
} MeshUsage;
typedef struct Mesh Mesh;
@ -42,7 +42,7 @@ struct Mesh {
uint32_t count;
VertexFormat format;
MeshDrawMode drawMode;
MeshUsage usage;
GLenum usage;
VertexPointer data;
IndexPointer indices;
uint32_t indexCount;

View File

@ -319,10 +319,10 @@ void lovrShaderBind(Shader* shader) {
for (int i = 0; i < count; i++) {
TextureType type;
switch (uniform->glType) {
case GL_SAMPLER_2D: type = TEXTURE_2D; break;
case GL_SAMPLER_3D: type = TEXTURE_VOLUME; break;
case GL_SAMPLER_CUBE: type = TEXTURE_CUBE; break;
case GL_SAMPLER_2D_ARRAY: type = TEXTURE_ARRAY; break;
case GL_SAMPLER_2D: type = GL_TEXTURE_2D; break;
case GL_SAMPLER_3D: type = GL_TEXTURE_3D; break;
case GL_SAMPLER_CUBE: type = GL_TEXTURE_CUBE_MAP; break;
case GL_SAMPLER_2D_ARRAY: type = GL_TEXTURE_2D_ARRAY; break;
}
lovrGraphicsBindTexture(uniform->value.textures[i], type, uniform->baseTextureSlot + i);
}

View File

@ -7,6 +7,14 @@
#include <stdlib.h>
#include <stdio.h>
GLenum convertWrap(WrapMode mode) {
switch (mode) {
case WRAP_CLAMP: return GL_CLAMP_TO_EDGE;
case WRAP_REPEAT: return GL_REPEAT;
case WRAP_MIRRORED_REPEAT: return GL_MIRRORED_REPEAT;
}
}
GLenum lovrTextureFormatGetGLFormat(TextureFormat format) {
switch (format) {
case FORMAT_RGB: return GL_RGB;
@ -56,16 +64,16 @@ static void lovrTextureAllocate(Texture* texture, TextureData* textureData) {
if (GLAD_GL_ARB_texture_storage) {
#endif
if (texture->type == TEXTURE_ARRAY) {
glTexStorage3D(texture->type, mipmapCount, internalFormat, w, h, texture->depth);
glTexStorage3D(texture->glType, mipmapCount, internalFormat, w, h, texture->depth);
} else {
glTexStorage2D(texture->type, mipmapCount, internalFormat, w, h);
glTexStorage2D(texture->glType, mipmapCount, internalFormat, w, h);
}
#ifndef EMSCRIPTEN
} else {
for (int i = 0; i < mipmapCount; i++) {
switch (texture->type) {
case TEXTURE_2D:
glTexImage2D(texture->type, i, internalFormat, w, h, 0, glFormat, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(texture->glType, i, internalFormat, w, h, 0, glFormat, GL_UNSIGNED_BYTE, NULL);
break;
case TEXTURE_CUBE:
@ -76,7 +84,7 @@ static void lovrTextureAllocate(Texture* texture, TextureData* textureData) {
case TEXTURE_ARRAY:
case TEXTURE_VOLUME:
glTexImage3D(texture->type, i, internalFormat, w, h, texture->depth, 0, glFormat, GL_UNSIGNED_BYTE, NULL);
glTexImage3D(texture->glType, i, internalFormat, w, h, texture->depth, 0, glFormat, GL_UNSIGNED_BYTE, NULL);
break;
}
w = MAX(w >> 1, 1);
@ -91,6 +99,13 @@ Texture* lovrTextureCreate(TextureType type, TextureData** slices, int depth, bo
if (!texture) return NULL;
texture->type = type;
switch (type) {
case TEXTURE_2D: texture->glType = GL_TEXTURE_2D; break;
case TEXTURE_ARRAY: texture->glType = GL_TEXTURE_2D_ARRAY; break;
case TEXTURE_CUBE: texture->glType = GL_TEXTURE_CUBE_MAP; break;
case TEXTURE_VOLUME: texture->glType = GL_TEXTURE_3D; break;
}
texture->slices = calloc(depth, sizeof(TextureData**));
texture->depth = depth;
texture->srgb = srgb;
@ -98,7 +113,7 @@ Texture* lovrTextureCreate(TextureType type, TextureData** slices, int depth, bo
WrapMode wrap = type == TEXTURE_CUBE ? WRAP_CLAMP : WRAP_REPEAT;
glGenTextures(1, &texture->id);
lovrGraphicsBindTexture(texture, texture->type, 0);
lovrGraphicsBindTexture(texture, texture->glType, 0);
lovrTextureSetFilter(texture, lovrGraphicsGetDefaultFilter());
lovrTextureSetWrap(texture, (TextureWrap) { .s = wrap, .t = wrap, .r = wrap });
@ -146,7 +161,7 @@ void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, int sl
GLenum glFormat = lovrTextureFormatGetGLFormat(textureData->format);
GLenum glInternalFormat = lovrTextureFormatGetGLInternalFormat(textureData->format, texture->srgb);
GLenum binding = (texture->type == TEXTURE_CUBE) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice : texture->type;
GLenum binding = (texture->type == TEXTURE_CUBE) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice : texture->glType;
if (lovrTextureFormatIsCompressed(textureData->format)) {
Mipmap m; int i;
@ -175,7 +190,7 @@ void lovrTextureReplacePixels(Texture* texture, TextureData* textureData, int sl
}
if (texture->mipmaps) {
glGenerateMipmap(texture->type);
glGenerateMipmap(texture->glType);
}
}
}
@ -186,38 +201,38 @@ TextureFilter lovrTextureGetFilter(Texture* texture) {
void lovrTextureSetFilter(Texture* texture, TextureFilter filter) {
float anisotropy = filter.mode == FILTER_ANISOTROPIC ? MAX(filter.anisotropy, 1.) : 1.;
lovrGraphicsBindTexture(texture, texture->type, 0);
lovrGraphicsBindTexture(texture, texture->glType, 0);
texture->filter = filter;
switch (filter.mode) {
case FILTER_NEAREST:
glTexParameteri(texture->type, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(texture->type, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(texture->glType, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(texture->glType, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
break;
case FILTER_BILINEAR:
if (texture->mipmaps) {
glTexParameteri(texture->type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(texture->type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(texture->glType, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(texture->glType, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else {
glTexParameteri(texture->type, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(texture->type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(texture->glType, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(texture->glType, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
break;
case FILTER_TRILINEAR:
case FILTER_ANISOTROPIC:
if (texture->mipmaps) {
glTexParameteri(texture->type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(texture->type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(texture->glType, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(texture->glType, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else {
glTexParameteri(texture->type, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(texture->type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(texture->glType, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(texture->glType, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
break;
}
glTexParameteri(texture->type, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
glTexParameteri(texture->glType, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
}
TextureWrap lovrTextureGetWrap(Texture* texture) {
@ -226,10 +241,10 @@ TextureWrap lovrTextureGetWrap(Texture* texture) {
void lovrTextureSetWrap(Texture* texture, TextureWrap wrap) {
texture->wrap = wrap;
lovrGraphicsBindTexture(texture, texture->type, 0);
glTexParameteri(texture->type, GL_TEXTURE_WRAP_S, wrap.s);
glTexParameteri(texture->type, GL_TEXTURE_WRAP_T, wrap.t);
lovrGraphicsBindTexture(texture, texture->glType, 0);
glTexParameteri(texture->glType, GL_TEXTURE_WRAP_S, wrap.s);
glTexParameteri(texture->glType, GL_TEXTURE_WRAP_T, wrap.t);
if (texture->type == TEXTURE_CUBE || texture->type == TEXTURE_VOLUME) {
glTexParameteri(texture->type, GL_TEXTURE_WRAP_R, wrap.r);
glTexParameteri(texture->glType, GL_TEXTURE_WRAP_R, wrap.r);
}
}

View File

@ -6,10 +6,10 @@
#pragma once
typedef enum {
TEXTURE_2D = GL_TEXTURE_2D,
TEXTURE_CUBE = GL_TEXTURE_CUBE_MAP,
TEXTURE_ARRAY = GL_TEXTURE_2D_ARRAY,
TEXTURE_VOLUME = GL_TEXTURE_3D
TEXTURE_2D,
TEXTURE_CUBE,
TEXTURE_ARRAY,
TEXTURE_VOLUME
} TextureType;
typedef enum {
@ -25,9 +25,9 @@ typedef struct {
} TextureFilter;
typedef enum {
WRAP_CLAMP = GL_CLAMP_TO_EDGE,
WRAP_REPEAT = GL_REPEAT,
WRAP_MIRRORED_REPEAT = GL_MIRRORED_REPEAT
WRAP_CLAMP,
WRAP_REPEAT,
WRAP_MIRRORED_REPEAT
} WrapMode;
typedef struct {
@ -39,6 +39,7 @@ typedef struct {
typedef struct {
Ref ref;
TextureType type;
GLenum glType;
TextureData** slices;
int width;
int height;

View File

@ -155,40 +155,6 @@ int luax_setconf(lua_State* L) {
return 0;
}
void luax_pushenum(lua_State* L, map_int_t* map, int value) {
const char* key;
map_iter_t iter = map_iter(map);
while ((key = map_next(map, &iter))) {
if (*map_get(map, key) == value) {
lua_pushstring(L, key);
return;
}
}
lua_pushnil(L);
}
void* luax_checkenum(lua_State* L, int index, map_int_t* map, const char* typeName) {
const char* key = luaL_checkstring(L, index);
void* value = map_get(map, key);
if (!value) {
luaL_error(L, "Invalid %s '%s'", typeName, key);
return NULL;
}
return value;
}
void* luax_optenum(lua_State* L, int index, const char* fallback, map_int_t* map, const char* typeName) {
const char* key = luaL_optstring(L, index, fallback);
void* value = map_get(map, key);
if (!value) {
luaL_error(L, "Invalid %s '%s'", typeName, key);
return NULL;
}
return value;
}
Color luax_checkcolor(lua_State* L, int index) {
Color color = { 1., 1., 1., 1. };

View File

@ -40,7 +40,4 @@ void luax_registerobject(lua_State* L, void* object);
int luax_getstack(lua_State* L);
void luax_pushconf(lua_State* L);
int luax_setconf(lua_State* L);
void luax_pushenum(lua_State* L, map_int_t* map, int value);
void* luax_checkenum(lua_State* L, int index, map_int_t* map, const char* typeName);
void* luax_optenum(lua_State* L, int index, const char* fallback, map_int_t* map, const char* typeName);
Color luax_checkcolor(lua_State* L, int index);