2017-12-10 20:40:37 +00:00
|
|
|
#include "api.h"
|
2016-11-19 09:28:01 +00:00
|
|
|
#include "graphics/graphics.h"
|
2022-04-27 07:28:39 +00:00
|
|
|
#include "data/blob.h"
|
2022-04-30 00:12:10 +00:00
|
|
|
#include "data/image.h"
|
2022-07-04 00:26:31 +00:00
|
|
|
#include "data/modelData.h"
|
2022-06-19 00:43:12 +00:00
|
|
|
#include "data/rasterizer.h"
|
2022-04-26 22:32:54 +00:00
|
|
|
#include "util.h"
|
2021-03-16 00:54:27 +00:00
|
|
|
#include <lua.h>
|
|
|
|
#include <lauxlib.h>
|
2022-05-01 01:49:46 +00:00
|
|
|
#include <stdlib.h>
|
2022-04-26 22:32:54 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
2022-05-11 19:50:26 +00:00
|
|
|
StringEntry lovrBlendAlphaMode[] = {
|
|
|
|
[BLEND_ALPHA_MULTIPLY] = ENTRY("alphamultiply"),
|
|
|
|
[BLEND_PREMULTIPLIED] = ENTRY("premultiplied"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
StringEntry lovrBlendMode[] = {
|
|
|
|
[BLEND_ALPHA] = ENTRY("alpha"),
|
|
|
|
[BLEND_ADD] = ENTRY("add"),
|
|
|
|
[BLEND_SUBTRACT] = ENTRY("subtract"),
|
|
|
|
[BLEND_MULTIPLY] = ENTRY("multiply"),
|
|
|
|
[BLEND_LIGHTEN] = ENTRY("lighten"),
|
|
|
|
[BLEND_DARKEN] = ENTRY("darken"),
|
|
|
|
[BLEND_SCREEN] = ENTRY("screen"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-04-26 22:32:54 +00:00
|
|
|
StringEntry lovrBufferLayout[] = {
|
|
|
|
[LAYOUT_PACKED] = ENTRY("packed"),
|
|
|
|
[LAYOUT_STD140] = ENTRY("std140"),
|
|
|
|
[LAYOUT_STD430] = ENTRY("std430"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-05-01 22:47:17 +00:00
|
|
|
StringEntry lovrCompareMode[] = {
|
|
|
|
[COMPARE_NONE] = ENTRY("none"),
|
|
|
|
[COMPARE_EQUAL] = ENTRY("equal"),
|
|
|
|
[COMPARE_NEQUAL] = ENTRY("notequal"),
|
|
|
|
[COMPARE_LESS] = ENTRY("less"),
|
|
|
|
[COMPARE_LEQUAL] = ENTRY("lequal"),
|
|
|
|
[COMPARE_GREATER] = ENTRY("greater"),
|
|
|
|
[COMPARE_GEQUAL] = ENTRY("gequal"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-05-11 19:50:26 +00:00
|
|
|
StringEntry lovrCullMode[] = {
|
|
|
|
[CULL_NONE] = ENTRY("none"),
|
|
|
|
[CULL_FRONT] = ENTRY("front"),
|
|
|
|
[CULL_BACK] = ENTRY("back"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-05-28 03:47:07 +00:00
|
|
|
StringEntry lovrDefaultShader[] = {
|
|
|
|
[SHADER_UNLIT] = ENTRY("unlit"),
|
2022-09-10 18:07:40 +00:00
|
|
|
[SHADER_NORMAL] = ENTRY("normal"),
|
2022-06-22 07:05:26 +00:00
|
|
|
[SHADER_FONT] = ENTRY("font"),
|
2022-08-02 05:10:06 +00:00
|
|
|
[SHADER_CUBEMAP] = ENTRY("cubemap"),
|
|
|
|
[SHADER_EQUIRECT] = ENTRY("equirect"),
|
|
|
|
[SHADER_FILL] = ENTRY("fill"),
|
2022-09-14 00:36:10 +00:00
|
|
|
[SHADER_FILL_ARRAY] = ENTRY("fillarray"),
|
|
|
|
[SHADER_FILL_STEREO] = ENTRY("fillstereo"),
|
|
|
|
[SHADER_LOGO] = ENTRY("logo"),
|
2022-06-22 07:05:26 +00:00
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
StringEntry lovrDrawStyle[] = {
|
|
|
|
[STYLE_FILL] = ENTRY("fill"),
|
|
|
|
[STYLE_LINE] = ENTRY("line"),
|
2022-05-28 03:47:07 +00:00
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-04-26 22:32:54 +00:00
|
|
|
StringEntry lovrFieldType[] = {
|
|
|
|
[FIELD_I8x4] = ENTRY("i8x4"),
|
|
|
|
[FIELD_U8x4] = ENTRY("u8x4"),
|
|
|
|
[FIELD_SN8x4] = ENTRY("sn8x4"),
|
|
|
|
[FIELD_UN8x4] = ENTRY("un8x4"),
|
|
|
|
[FIELD_UN10x3] = ENTRY("un10x3"),
|
|
|
|
[FIELD_I16] = ENTRY("i16"),
|
|
|
|
[FIELD_I16x2] = ENTRY("i16x2"),
|
|
|
|
[FIELD_I16x4] = ENTRY("i16x4"),
|
|
|
|
[FIELD_U16] = ENTRY("u16"),
|
|
|
|
[FIELD_U16x2] = ENTRY("u16x2"),
|
|
|
|
[FIELD_U16x4] = ENTRY("u16x4"),
|
|
|
|
[FIELD_SN16x2] = ENTRY("sn16x2"),
|
|
|
|
[FIELD_SN16x4] = ENTRY("sn16x4"),
|
|
|
|
[FIELD_UN16x2] = ENTRY("un16x2"),
|
|
|
|
[FIELD_UN16x4] = ENTRY("un16x4"),
|
|
|
|
[FIELD_I32] = ENTRY("i32"),
|
|
|
|
[FIELD_I32x2] = ENTRY("i32x2"),
|
|
|
|
[FIELD_I32x3] = ENTRY("i32x3"),
|
|
|
|
[FIELD_I32x4] = ENTRY("i32x4"),
|
|
|
|
[FIELD_U32] = ENTRY("u32"),
|
|
|
|
[FIELD_U32x2] = ENTRY("u32x2"),
|
|
|
|
[FIELD_U32x3] = ENTRY("u32x3"),
|
|
|
|
[FIELD_U32x4] = ENTRY("u32x4"),
|
|
|
|
[FIELD_F16x2] = ENTRY("f16x2"),
|
|
|
|
[FIELD_F16x4] = ENTRY("f16x4"),
|
|
|
|
[FIELD_F32] = ENTRY("f32"),
|
|
|
|
[FIELD_F32x2] = ENTRY("f32x2"),
|
|
|
|
[FIELD_F32x3] = ENTRY("f32x3"),
|
|
|
|
[FIELD_F32x4] = ENTRY("f32x4"),
|
|
|
|
[FIELD_MAT2] = ENTRY("mat2"),
|
|
|
|
[FIELD_MAT3] = ENTRY("mat3"),
|
|
|
|
[FIELD_MAT4] = ENTRY("mat4"),
|
2022-07-10 19:18:31 +00:00
|
|
|
[FIELD_INDEX16] = ENTRY("index16"),
|
|
|
|
[FIELD_INDEX32] = ENTRY("index32"),
|
2022-04-26 22:32:54 +00:00
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-05-01 22:47:17 +00:00
|
|
|
StringEntry lovrFilterMode[] = {
|
|
|
|
[FILTER_NEAREST] = ENTRY("nearest"),
|
|
|
|
[FILTER_LINEAR] = ENTRY("linear"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-06-19 00:41:10 +00:00
|
|
|
StringEntry lovrHorizontalAlign[] = {
|
|
|
|
[ALIGN_LEFT] = ENTRY("left"),
|
|
|
|
[ALIGN_CENTER] = ENTRY("center"),
|
|
|
|
[ALIGN_RIGHT] = ENTRY("right"),
|
2022-06-10 06:05:32 +00:00
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-07-13 02:35:23 +00:00
|
|
|
StringEntry lovrMeshMode[] = {
|
|
|
|
[MESH_POINTS] = ENTRY("points"),
|
|
|
|
[MESH_LINES] = ENTRY("lines"),
|
|
|
|
[MESH_TRIANGLES] = ENTRY("triangles"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-08-18 05:33:43 +00:00
|
|
|
StringEntry lovrOriginType[] = {
|
|
|
|
[ORIGIN_ROOT] = ENTRY("root"),
|
|
|
|
[ORIGIN_PARENT] = ENTRY("parent"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-05-01 01:54:29 +00:00
|
|
|
StringEntry lovrPassType[] = {
|
|
|
|
[PASS_RENDER] = ENTRY("render"),
|
|
|
|
[PASS_COMPUTE] = ENTRY("compute"),
|
|
|
|
[PASS_TRANSFER] = ENTRY("transfer"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-05-09 18:47:06 +00:00
|
|
|
StringEntry lovrShaderStage[] = {
|
|
|
|
[STAGE_VERTEX] = ENTRY("vertex"),
|
|
|
|
[STAGE_FRAGMENT] = ENTRY("fragment"),
|
|
|
|
[STAGE_COMPUTE] = ENTRY("compute"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
StringEntry lovrShaderType[] = {
|
|
|
|
[SHADER_GRAPHICS] = ENTRY("graphics"),
|
|
|
|
[SHADER_COMPUTE] = ENTRY("compute"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-05-07 00:26:38 +00:00
|
|
|
StringEntry lovrStackType[] = {
|
|
|
|
[STACK_TRANSFORM] = ENTRY("transform"),
|
2022-07-30 22:03:54 +00:00
|
|
|
[STACK_STATE] = ENTRY("state"),
|
2022-05-07 00:26:38 +00:00
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-05-11 19:50:26 +00:00
|
|
|
StringEntry lovrStencilAction[] = {
|
|
|
|
[STENCIL_KEEP] = ENTRY("keep"),
|
2022-08-27 05:23:04 +00:00
|
|
|
[STENCIL_ZERO] = ENTRY("zero"),
|
2022-05-11 19:50:26 +00:00
|
|
|
[STENCIL_REPLACE] = ENTRY("replace"),
|
|
|
|
[STENCIL_INCREMENT] = ENTRY("increment"),
|
|
|
|
[STENCIL_DECREMENT] = ENTRY("decrement"),
|
|
|
|
[STENCIL_INCREMENT_WRAP] = ENTRY("incrementwrap"),
|
|
|
|
[STENCIL_DECREMENT_WRAP] = ENTRY("decrementwrap"),
|
|
|
|
[STENCIL_INVERT] = ENTRY("invert"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-07-13 02:58:18 +00:00
|
|
|
StringEntry lovrTallyType[] = {
|
2022-07-17 20:17:33 +00:00
|
|
|
[TALLY_TIME] = ENTRY("time"),
|
2022-07-17 18:38:55 +00:00
|
|
|
[TALLY_SHADER] = ENTRY("shader"),
|
2022-07-13 02:58:18 +00:00
|
|
|
[TALLY_PIXEL] = ENTRY("pixel"),
|
2022-07-17 18:38:55 +00:00
|
|
|
{ 0 }
|
2022-07-13 02:58:18 +00:00
|
|
|
};
|
|
|
|
|
2022-04-30 00:12:10 +00:00
|
|
|
StringEntry lovrTextureFeature[] = {
|
|
|
|
[0] = ENTRY("sample"),
|
|
|
|
[1] = ENTRY("filter"),
|
|
|
|
[2] = ENTRY("render"),
|
|
|
|
[3] = ENTRY("blend"),
|
|
|
|
[4] = ENTRY("storage"),
|
|
|
|
[5] = ENTRY("atomic"),
|
|
|
|
[6] = ENTRY("blitsrc"),
|
|
|
|
[7] = ENTRY("blitdst"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-04-30 03:56:23 +00:00
|
|
|
StringEntry lovrTextureType[] = {
|
|
|
|
[TEXTURE_2D] = ENTRY("2d"),
|
|
|
|
[TEXTURE_3D] = ENTRY("3d"),
|
|
|
|
[TEXTURE_CUBE] = ENTRY("cube"),
|
|
|
|
[TEXTURE_ARRAY] = ENTRY("array"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
StringEntry lovrTextureUsage[] = {
|
|
|
|
[0] = ENTRY("sample"),
|
|
|
|
[1] = ENTRY("render"),
|
|
|
|
[2] = ENTRY("storage"),
|
2022-05-07 00:26:59 +00:00
|
|
|
[3] = ENTRY("transfer"),
|
2022-04-30 03:56:23 +00:00
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-06-19 00:41:10 +00:00
|
|
|
StringEntry lovrVerticalAlign[] = {
|
|
|
|
[ALIGN_TOP] = ENTRY("top"),
|
|
|
|
[ALIGN_MIDDLE] = ENTRY("middle"),
|
|
|
|
[ALIGN_BOTTOM] = ENTRY("bottom"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-05-11 19:50:26 +00:00
|
|
|
StringEntry lovrWinding[] = {
|
|
|
|
[WINDING_COUNTERCLOCKWISE] = ENTRY("counterclockwise"),
|
|
|
|
[WINDING_CLOCKWISE] = ENTRY("clockwise"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-05-01 22:47:17 +00:00
|
|
|
StringEntry lovrWrapMode[] = {
|
|
|
|
[WRAP_CLAMP] = ENTRY("clamp"),
|
|
|
|
[WRAP_REPEAT] = ENTRY("repeat"),
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2022-04-26 22:32:54 +00:00
|
|
|
static struct { uint32_t size, scalarAlign, baseAlign, components; } fieldInfo[] = {
|
|
|
|
[FIELD_I8x4] = { 4, 1, 4, 4 },
|
|
|
|
[FIELD_U8x4] = { 4, 1, 4, 4 },
|
|
|
|
[FIELD_SN8x4] = { 4, 1, 4, 4 },
|
|
|
|
[FIELD_UN8x4] = { 4, 1, 4, 4 },
|
|
|
|
[FIELD_UN10x3] = { 4, 4, 4, 3 },
|
|
|
|
[FIELD_I16] = { 2, 2, 2, 1 },
|
|
|
|
[FIELD_I16x2] = { 4, 2, 4, 2 },
|
|
|
|
[FIELD_I16x4] = { 8, 2, 8, 4 },
|
|
|
|
[FIELD_U16] = { 2, 2, 2, 1 },
|
|
|
|
[FIELD_U16x2] = { 4, 2, 4, 2 },
|
|
|
|
[FIELD_U16x4] = { 8, 2, 8, 4 },
|
|
|
|
[FIELD_SN16x2] = { 4, 2, 4, 2 },
|
|
|
|
[FIELD_SN16x4] = { 8, 2, 8, 4 },
|
|
|
|
[FIELD_UN16x2] = { 4, 2, 4, 2 },
|
|
|
|
[FIELD_UN16x4] = { 8, 2, 8, 4 },
|
|
|
|
[FIELD_I32] = { 4, 4, 4, 1 },
|
|
|
|
[FIELD_I32x2] = { 8, 4, 8, 2 },
|
|
|
|
[FIELD_I32x3] = { 12, 4, 16, 3 },
|
|
|
|
[FIELD_I32x4] = { 16, 4, 16, 4 },
|
|
|
|
[FIELD_U32] = { 4, 4, 4, 1 },
|
|
|
|
[FIELD_U32x2] = { 8, 4, 8, 2 },
|
|
|
|
[FIELD_U32x3] = { 12, 4, 16, 3 },
|
|
|
|
[FIELD_U32x4] = { 16, 4, 16, 4 },
|
|
|
|
[FIELD_F16x2] = { 4, 2, 4, 2 },
|
|
|
|
[FIELD_F16x4] = { 8, 2, 8, 4 },
|
|
|
|
[FIELD_F32] = { 4, 4, 4, 1 },
|
|
|
|
[FIELD_F32x2] = { 8, 4, 8, 2 },
|
|
|
|
[FIELD_F32x3] = { 12, 4, 16, 3 },
|
|
|
|
[FIELD_F32x4] = { 16, 4, 16, 4 },
|
|
|
|
[FIELD_MAT2] = { 16, 4, 8, 4 },
|
|
|
|
[FIELD_MAT3] = { 64, 4, 16, 9 },
|
2022-07-10 19:18:31 +00:00
|
|
|
[FIELD_MAT4] = { 64, 4, 16, 16 },
|
|
|
|
[FIELD_INDEX16] = { 2, 2, 2, 1 },
|
|
|
|
[FIELD_INDEX32] = { 4, 4, 4, 1 }
|
2022-04-26 22:32:54 +00:00
|
|
|
};
|
|
|
|
|
2022-06-16 03:46:43 +00:00
|
|
|
static uint32_t luax_checkfieldtype(lua_State* L, int index, uint32_t* nameHash) {
|
2022-04-26 22:32:54 +00:00
|
|
|
size_t length;
|
|
|
|
const char* string = luaL_checklstring(L, index, &length);
|
|
|
|
|
2022-06-16 03:46:43 +00:00
|
|
|
char* colon = strchr(string, ':');
|
|
|
|
|
|
|
|
if (colon) {
|
|
|
|
*nameHash = (uint32_t) hash64(colon + 1, length - (colon + 1 - string));
|
|
|
|
length = colon - string;
|
|
|
|
} else {
|
|
|
|
*nameHash = 0;
|
|
|
|
}
|
|
|
|
|
2022-04-26 22:32:54 +00:00
|
|
|
if (length < 3) {
|
|
|
|
return luaL_error(L, "invalid FieldType '%s'", string), 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Plurals are allowed and ignored
|
|
|
|
if (string[length - 1] == 's') {
|
|
|
|
length--;
|
|
|
|
}
|
|
|
|
|
|
|
|
// x1 is allowed and ignored
|
|
|
|
if (string[length - 2] == 'x' && string[length - 1] == '1') {
|
|
|
|
length -= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// vec[234]
|
|
|
|
if (length == 4 && string[0] == 'v' && string[1] == 'e' && string[2] == 'c' && string[3] >= '2' && string[3] <= '4') {
|
|
|
|
return FIELD_F32x2 + string[3] - '2';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (length == 3 && !memcmp(string, "int", length)) {
|
|
|
|
return FIELD_I32;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (length == 4 && !memcmp(string, "uint", length)) {
|
|
|
|
return FIELD_U32;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (length == 5 && !memcmp(string, "float", length)) {
|
|
|
|
return FIELD_F32;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (length == 5 && !memcmp(string, "color", length)) {
|
|
|
|
return FIELD_UN8x4;
|
|
|
|
}
|
|
|
|
|
2022-08-20 03:51:40 +00:00
|
|
|
if (length == 5 && !memcmp(string, "index", length)) {
|
2022-07-10 19:18:31 +00:00
|
|
|
return FIELD_INDEX32;
|
|
|
|
}
|
|
|
|
|
2022-04-26 22:32:54 +00:00
|
|
|
for (int i = 0; lovrFieldType[i].length; i++) {
|
|
|
|
if (length == lovrFieldType[i].length && !memcmp(string, lovrFieldType[i].string, length)) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return luaL_error(L, "invalid FieldType '%s'", string), 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void luax_checkbufferformat(lua_State* L, int index, BufferInfo* info) {
|
|
|
|
switch (lua_type(L, index)) {
|
|
|
|
case LUA_TNONE:
|
|
|
|
case LUA_TNIL:
|
2022-04-27 07:28:39 +00:00
|
|
|
info->stride = 1;
|
2022-04-26 22:32:54 +00:00
|
|
|
break;
|
|
|
|
case LUA_TSTRING:
|
|
|
|
info->fieldCount = 1;
|
2022-06-16 03:46:43 +00:00
|
|
|
info->fields[0].type = luax_checkfieldtype(L, index, &info->fields[0].hash);
|
2022-07-10 19:35:02 +00:00
|
|
|
info->fields[0].location = 10;
|
2022-04-26 22:32:54 +00:00
|
|
|
info->stride = fieldInfo[info->fields[0].type].size;
|
|
|
|
break;
|
|
|
|
case LUA_TTABLE:
|
|
|
|
lua_getfield(L, index, "layout");
|
|
|
|
BufferLayout layout = luax_checkenum(L, -1, BufferLayout, "packed");
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
int length = info->fieldCount = luax_len(L, index);
|
|
|
|
lovrAssert(info->fieldCount <= COUNTOF(info->fields), "Too many buffer fields (max is %d)", COUNTOF(info->fields));
|
|
|
|
|
|
|
|
uint32_t offset = 0;
|
2022-04-28 22:39:45 +00:00
|
|
|
uint32_t extent = 0;
|
2022-07-10 19:35:02 +00:00
|
|
|
uint32_t location = 10;
|
2022-04-26 22:32:54 +00:00
|
|
|
uint32_t maxAlign = 1;
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
|
|
BufferField* field = &info->fields[i];
|
|
|
|
|
|
|
|
lua_rawgeti(L, index, i + 1);
|
|
|
|
if (lua_istable(L, -1)) {
|
|
|
|
lua_getfield(L, -1, "type");
|
2022-06-26 06:43:24 +00:00
|
|
|
lovrAssert(lua_type(L, -1) == LUA_TSTRING, "When given as a table, Buffer fields must have a 'type' key.");
|
2022-06-16 03:46:43 +00:00
|
|
|
field->type = luax_checkfieldtype(L, -1, &field->hash);
|
2022-04-26 22:32:54 +00:00
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
uint32_t align = layout == LAYOUT_PACKED ? fieldInfo[field->type].scalarAlign : fieldInfo[field->type].baseAlign;
|
|
|
|
maxAlign = MAX(maxAlign, align);
|
|
|
|
|
|
|
|
lua_getfield(L, -1, "offset");
|
|
|
|
if (lua_isnil(L, -1)) {
|
|
|
|
field->offset = ALIGN(offset, align);
|
|
|
|
offset = field->offset + fieldInfo[field->type].size;
|
|
|
|
} else {
|
|
|
|
field->offset = luaL_checkinteger(L, -1);
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, -1, "location");
|
2022-06-16 03:46:43 +00:00
|
|
|
if (lua_type(L, -1) == LUA_TSTRING) {
|
|
|
|
size_t nameLength;
|
|
|
|
const char* name = lua_tolstring(L, -1, &nameLength);
|
|
|
|
field->hash = (uint32_t) hash64(name, nameLength);
|
2022-08-24 02:17:54 +00:00
|
|
|
} else {
|
|
|
|
field->location = lua_isnil(L, -1) ? location++ : luaL_checkinteger(L, -1);
|
2022-06-16 03:46:43 +00:00
|
|
|
}
|
2022-04-26 22:32:54 +00:00
|
|
|
lua_pop(L, 1);
|
|
|
|
} else if (lua_isstring(L, -1)) {
|
2022-06-16 03:46:43 +00:00
|
|
|
FieldType type = luax_checkfieldtype(L, -1, &field->hash);
|
2022-04-26 22:32:54 +00:00
|
|
|
uint32_t align = layout == LAYOUT_PACKED ? fieldInfo[type].scalarAlign : fieldInfo[type].baseAlign;
|
|
|
|
field->offset = ALIGN(offset, align);
|
|
|
|
field->location = location++;
|
|
|
|
field->type = type;
|
|
|
|
offset = field->offset + fieldInfo[type].size;
|
|
|
|
maxAlign = MAX(maxAlign, align);
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
2022-04-28 22:39:45 +00:00
|
|
|
|
|
|
|
extent = MAX(extent, field->offset + fieldInfo[field->type].size);
|
2022-04-26 22:32:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lua_getfield(L, index, "stride");
|
|
|
|
if (lua_isnil(L, -1)) {
|
|
|
|
switch (layout) {
|
|
|
|
case LAYOUT_PACKED: info->stride = offset; break;
|
|
|
|
case LAYOUT_STD140: info->stride = ALIGN(offset, 16); break;
|
|
|
|
case LAYOUT_STD430: info->stride = ALIGN(offset, maxAlign); break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
} else {
|
2022-04-28 22:39:45 +00:00
|
|
|
info->stride = luax_checku32(L, -1);
|
|
|
|
lovrCheck(info->stride > 0, "Buffer stride can not be zero");
|
|
|
|
lovrCheck(info->stride <= extent, "Buffer stride can not be smaller than the size of a single item");
|
2022-04-26 22:32:54 +00:00
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
break;
|
|
|
|
default: luaL_argerror(L, index, "Expected nil, string, or table");
|
|
|
|
}
|
|
|
|
}
|
2017-03-11 11:08:07 +00:00
|
|
|
|
2022-07-10 19:49:11 +00:00
|
|
|
uint32_t luax_getbufferlength(lua_State* L, int index, BufferInfo* info) {
|
|
|
|
switch (lua_type(L, 1)) {
|
|
|
|
case LUA_TNUMBER: return lua_tointeger(L, 1); break;
|
|
|
|
case LUA_TTABLE: {
|
|
|
|
uint32_t length = luax_len(L, 1);
|
|
|
|
|
|
|
|
if (length < info->fieldCount) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
lua_rawgeti(L, 1, 1);
|
|
|
|
if (lua_istable(L, -1)) {
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
uint32_t tableStride = 0;
|
|
|
|
for (uint32_t i = 0, j = 1; i < info->fieldCount; i++) {
|
|
|
|
lua_rawgeti(L, 1, (int) j);
|
|
|
|
if (lua_isuserdata(L, -1)) {
|
|
|
|
tableStride++;
|
|
|
|
j++;
|
|
|
|
} else {
|
|
|
|
uint32_t components = fieldInfo[info->fields[i].type].components;
|
|
|
|
tableStride += components;
|
|
|
|
j += components;
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return length / tableStride;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
Blob* blob = luax_totype(L, 1, Blob);
|
|
|
|
if (blob) {
|
|
|
|
return (uint32_t) blob->size / info->stride;
|
|
|
|
} else {
|
|
|
|
return luax_typeerror(L, 1, "number, table, or Blob");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-11 19:51:13 +00:00
|
|
|
static Canvas luax_checkcanvas(lua_State* L, int index) {
|
2022-05-01 01:54:29 +00:00
|
|
|
Canvas canvas = {
|
|
|
|
.loads = { LOAD_CLEAR, LOAD_CLEAR, LOAD_CLEAR, LOAD_CLEAR },
|
|
|
|
.depth.format = FORMAT_D32F,
|
|
|
|
.depth.load = LOAD_CLEAR,
|
2022-07-17 19:37:59 +00:00
|
|
|
.depth.clear = 0.f,
|
2022-05-01 01:54:29 +00:00
|
|
|
.samples = 4
|
|
|
|
};
|
|
|
|
|
|
|
|
if (lua_type(L, index) == LUA_TSTRING && !strcmp(lua_tostring(L, index), "window")) {
|
2022-08-03 05:00:11 +00:00
|
|
|
canvas.count = 1;
|
2022-08-26 04:57:15 +00:00
|
|
|
canvas.textures[0] = lovrGraphicsGetWindowTexture();
|
|
|
|
lovrGraphicsGetBackgroundColor(canvas.clears[0]);
|
2022-05-01 01:54:29 +00:00
|
|
|
} else if (lua_isuserdata(L, index)) {
|
2022-08-03 05:00:11 +00:00
|
|
|
canvas.count = 1;
|
2022-08-26 04:57:15 +00:00
|
|
|
canvas.textures[0] = luax_checktype(L, index, Texture);
|
|
|
|
lovrGraphicsGetBackgroundColor(canvas.clears[0]);
|
2022-05-01 01:54:29 +00:00
|
|
|
} else if (!lua_istable(L, index)) {
|
2022-05-11 19:51:13 +00:00
|
|
|
luax_typeerror(L, index, "Texture or table");
|
2022-05-01 01:54:29 +00:00
|
|
|
} else {
|
2022-08-03 05:00:11 +00:00
|
|
|
for (uint32_t i = 0; i < 4; i++, canvas.count++) {
|
2022-05-01 01:54:29 +00:00
|
|
|
lua_rawgeti(L, index, i + 1);
|
|
|
|
if (lua_isnil(L, -1)) {
|
|
|
|
break;
|
|
|
|
} else if (lua_type(L, -1) == LUA_TSTRING && !strcmp(lua_tostring(L, -1), "window")) {
|
2022-05-11 22:28:04 +00:00
|
|
|
canvas.textures[i] = lovrGraphicsGetWindowTexture();
|
2022-05-01 01:54:29 +00:00
|
|
|
} else {
|
|
|
|
canvas.textures[i] = luax_checktype(L, -1, Texture);
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
lua_getfield(L, index, "depth");
|
|
|
|
switch (lua_type(L, -1)) {
|
|
|
|
case LUA_TBOOLEAN: canvas.depth.format = lua_toboolean(L, -1) ? canvas.depth.format : 0; break;
|
|
|
|
case LUA_TSTRING: canvas.depth.format = luax_checkenum(L, -1, TextureFormat, NULL); break;
|
|
|
|
case LUA_TUSERDATA: canvas.depth.texture = luax_checktype(L, -1, Texture); break;
|
|
|
|
case LUA_TTABLE:
|
|
|
|
lua_getfield(L, -1, "format");
|
|
|
|
canvas.depth.format = lua_isnil(L, -1) ? canvas.depth.format : luax_checkenum(L, -1, TextureFormat, NULL);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, -1, "texture");
|
|
|
|
canvas.depth.texture = lua_isnil(L, -1) ? NULL : luax_checktype(L, -1, Texture);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, -1, "clear");
|
|
|
|
switch (lua_type(L, -1)) {
|
|
|
|
case LUA_TNIL: break;
|
|
|
|
case LUA_TBOOLEAN: canvas.depth.load = lua_toboolean(L, -1) ? LOAD_DISCARD : LOAD_KEEP; break;
|
|
|
|
case LUA_TNUMBER: canvas.depth.clear = lua_tonumber(L, -1); break;
|
|
|
|
default: lovrThrow("Expected boolean or number for depth clear");
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, index, "clear");
|
|
|
|
if (lua_istable(L, -1)) {
|
|
|
|
lua_rawgeti(L, -1, 1);
|
|
|
|
if (lua_type(L, -1) == LUA_TNUMBER) {
|
|
|
|
lua_rawgeti(L, -2, 2);
|
|
|
|
lua_rawgeti(L, -3, 3);
|
|
|
|
lua_rawgeti(L, -4, 4);
|
|
|
|
canvas.clears[0][0] = luax_checkfloat(L, -4);
|
|
|
|
canvas.clears[0][1] = luax_checkfloat(L, -3);
|
|
|
|
canvas.clears[0][2] = luax_checkfloat(L, -2);
|
|
|
|
canvas.clears[0][3] = luax_optfloat(L, -1, 1.f);
|
|
|
|
lua_pop(L, 4);
|
2022-08-26 04:57:15 +00:00
|
|
|
for (uint32_t i = 1; i < canvas.count; i++) {
|
2022-05-01 01:54:29 +00:00
|
|
|
memcpy(canvas.clears[i], canvas.clears[0], 4 * sizeof(float));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
lua_pop(L, 1);
|
2022-08-26 04:57:15 +00:00
|
|
|
for (uint32_t i = 0; i < canvas.count; i++) {
|
2022-05-01 01:54:29 +00:00
|
|
|
lua_rawgeti(L, -1, i + 1);
|
|
|
|
if (lua_istable(L, -1)) {
|
|
|
|
lua_rawgeti(L, -1, 1);
|
|
|
|
lua_rawgeti(L, -2, 2);
|
|
|
|
lua_rawgeti(L, -3, 3);
|
|
|
|
lua_rawgeti(L, -4, 4);
|
|
|
|
canvas.clears[i][0] = luax_checkfloat(L, -4);
|
|
|
|
canvas.clears[i][1] = luax_checkfloat(L, -3);
|
|
|
|
canvas.clears[i][2] = luax_checkfloat(L, -2);
|
|
|
|
canvas.clears[i][3] = luax_optfloat(L, -1, 1.f);
|
|
|
|
lua_pop(L, 4);
|
|
|
|
} else {
|
|
|
|
canvas.loads[i] = lua_toboolean(L, -1) ? LOAD_DISCARD : LOAD_KEEP;
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
}
|
2022-06-17 06:49:09 +00:00
|
|
|
} else if (lua_isnumber(L, -1) || lua_isuserdata(L, -1)) {
|
2022-07-11 00:07:04 +00:00
|
|
|
luax_optcolor(L, -1, canvas.clears[0]);
|
2022-05-01 01:54:29 +00:00
|
|
|
} else if (!lua_isnil(L, -1)) {
|
|
|
|
LoadAction load = lua_toboolean(L, -1) ? LOAD_DISCARD : LOAD_KEEP;
|
|
|
|
canvas.loads[0] = canvas.loads[1] = canvas.loads[2] = canvas.loads[3] = load;
|
2022-08-26 04:57:15 +00:00
|
|
|
} else {
|
|
|
|
for (uint32_t i = 0; i < canvas.count; i++) {
|
|
|
|
lovrGraphicsGetBackgroundColor(canvas.clears[i]);
|
|
|
|
}
|
2022-05-01 01:54:29 +00:00
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, index, "samples");
|
|
|
|
canvas.samples = lua_isnil(L, -1) ? canvas.samples : lua_tointeger(L, -1);
|
|
|
|
lua_pop(L, 1);
|
2022-06-23 02:05:36 +00:00
|
|
|
|
2022-07-04 22:22:54 +00:00
|
|
|
lua_getfield(L, index, "mipmap");
|
2022-06-23 02:05:36 +00:00
|
|
|
canvas.mipmap = lua_toboolean(L, -1);
|
|
|
|
lua_pop(L, 1);
|
2022-05-01 01:54:29 +00:00
|
|
|
}
|
|
|
|
|
2022-05-11 19:51:13 +00:00
|
|
|
return canvas;
|
2022-05-01 01:54:29 +00:00
|
|
|
}
|
|
|
|
|
2022-06-01 04:33:06 +00:00
|
|
|
uint32_t luax_checkcomparemode(lua_State* L, int index) {
|
|
|
|
size_t length;
|
|
|
|
const char* string = lua_tolstring(L, index, &length);
|
|
|
|
|
|
|
|
if (string && length <= 2) {
|
|
|
|
if (string[0] == '=' && (length == 1 || string[1] == '=')) {
|
|
|
|
return COMPARE_EQUAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((string[0] == '~' || string[0] == '!') && string[1] == '=') {
|
|
|
|
return COMPARE_NEQUAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (string[0] == '<' && length == 1) {
|
|
|
|
return COMPARE_LESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (string[0] == '<' && string[1] == '=') {
|
|
|
|
return COMPARE_LEQUAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (string[0] == '>' && length == 1) {
|
|
|
|
return COMPARE_GREATER;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (string[0] == '>' && string[1] == '=') {
|
|
|
|
return COMPARE_GEQUAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return luax_checkenum(L, index, CompareMode, "none");
|
|
|
|
}
|
|
|
|
|
2022-08-03 05:00:11 +00:00
|
|
|
static void luax_writeshadercache(void) {
|
|
|
|
size_t size;
|
|
|
|
lovrGraphicsGetShaderCache(NULL, &size);
|
|
|
|
|
|
|
|
if (size == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void* data = malloc(size);
|
|
|
|
|
|
|
|
if (!data) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
lovrGraphicsGetShaderCache(data, &size);
|
|
|
|
|
|
|
|
if (size > 0) {
|
|
|
|
luax_writefile(".lovrshadercache", data, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(data);
|
|
|
|
}
|
|
|
|
|
2022-09-10 17:22:52 +00:00
|
|
|
static int l_lovrGraphicsInitialize(lua_State* L) {
|
2022-08-03 05:00:11 +00:00
|
|
|
GraphicsConfig config = {
|
|
|
|
.debug = false,
|
|
|
|
.vsync = false,
|
|
|
|
.stencil = false,
|
|
|
|
.antialias = true
|
|
|
|
};
|
2022-04-21 07:27:13 +00:00
|
|
|
|
2022-08-03 05:05:12 +00:00
|
|
|
bool shaderCache = true;
|
|
|
|
|
2022-04-21 07:27:13 +00:00
|
|
|
luax_pushconf(L);
|
|
|
|
lua_getfield(L, -1, "graphics");
|
|
|
|
if (lua_istable(L, -1)) {
|
|
|
|
lua_getfield(L, -1, "debug");
|
2022-08-03 05:00:11 +00:00
|
|
|
config.debug = lua_toboolean(L, -1);
|
2022-04-21 07:27:13 +00:00
|
|
|
lua_pop(L, 1);
|
2022-05-11 22:28:04 +00:00
|
|
|
|
|
|
|
lua_getfield(L, -1, "vsync");
|
2022-08-03 05:00:11 +00:00
|
|
|
config.vsync = lua_toboolean(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, -1, "stencil");
|
|
|
|
config.stencil = lua_toboolean(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, -1, "antialias");
|
|
|
|
config.antialias = lua_toboolean(L, -1);
|
2022-05-11 22:28:04 +00:00
|
|
|
lua_pop(L, 1);
|
2022-08-03 05:05:12 +00:00
|
|
|
|
|
|
|
lua_getfield(L, -1, "shadercache");
|
|
|
|
shaderCache = lua_toboolean(L, -1);
|
|
|
|
lua_pop(L, 1);
|
2022-04-21 07:27:13 +00:00
|
|
|
}
|
|
|
|
lua_pop(L, 2);
|
|
|
|
|
2022-08-03 05:05:12 +00:00
|
|
|
if (shaderCache) {
|
|
|
|
config.cacheData = luax_readfile(".lovrshadercache", &config.cacheSize);
|
|
|
|
}
|
|
|
|
|
2022-08-09 06:16:34 +00:00
|
|
|
if (lovrGraphicsInit(&config)) {
|
|
|
|
luax_atexit(L, lovrGraphicsDestroy);
|
|
|
|
|
|
|
|
// Finalizers run in the opposite order they were added, so this has to go last
|
|
|
|
if (shaderCache) {
|
|
|
|
luax_atexit(L, luax_writeshadercache);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-23 03:18:34 +00:00
|
|
|
free(config.cacheData);
|
|
|
|
|
2022-04-21 07:27:13 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-04-29 05:30:31 +00:00
|
|
|
static int l_lovrGraphicsSubmit(lua_State* L) {
|
2022-05-11 19:50:49 +00:00
|
|
|
bool table = lua_istable(L, 1);
|
2022-06-26 07:45:49 +00:00
|
|
|
int length = table ? luax_len(L, 1) : lua_gettop(L);
|
|
|
|
uint32_t count = 0;
|
2022-05-11 19:50:49 +00:00
|
|
|
|
|
|
|
Pass* stack[8];
|
2022-06-26 07:45:49 +00:00
|
|
|
Pass** passes = (size_t) length > COUNTOF(stack) ? malloc(length * sizeof(Pass*)) : stack;
|
2022-05-11 19:50:49 +00:00
|
|
|
lovrAssert(passes, "Out of memory");
|
|
|
|
|
|
|
|
if (table) {
|
2022-06-26 07:45:49 +00:00
|
|
|
for (int i = 0; i < length; i++) {
|
2022-05-11 19:50:49 +00:00
|
|
|
lua_rawgeti(L, 1, i + 1);
|
2022-06-26 07:45:49 +00:00
|
|
|
if (lua_toboolean(L, -1)) {
|
|
|
|
passes[count++] = luax_checktype(L, -1, Pass);
|
|
|
|
}
|
2022-05-11 19:50:49 +00:00
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
} else {
|
2022-06-26 07:45:49 +00:00
|
|
|
for (int i = 0; i < length; i++) {
|
|
|
|
if (lua_toboolean(L, i + 1)) {
|
|
|
|
passes[count++] = luax_checktype(L, i + 1, Pass);
|
|
|
|
}
|
2022-05-11 19:50:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lovrGraphicsSubmit(passes, count);
|
|
|
|
if (passes != stack) free(passes);
|
2022-06-09 06:59:48 +00:00
|
|
|
lua_pushboolean(L, true);
|
|
|
|
return 1;
|
2022-04-29 05:30:31 +00:00
|
|
|
}
|
|
|
|
|
2022-08-04 07:06:54 +00:00
|
|
|
static int l_lovrGraphicsPresent(lua_State* L) {
|
|
|
|
lovrGraphicsPresent();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-04-29 05:37:03 +00:00
|
|
|
static int l_lovrGraphicsWait(lua_State* L) {
|
|
|
|
lovrGraphicsWait();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-04-21 09:16:17 +00:00
|
|
|
static int l_lovrGraphicsGetDevice(lua_State* L) {
|
|
|
|
GraphicsDevice device;
|
|
|
|
lovrGraphicsGetDevice(&device);
|
|
|
|
lua_newtable(L);
|
2022-04-22 20:28:59 +00:00
|
|
|
lua_pushinteger(L, device.deviceId), lua_setfield(L, -2, "id");
|
|
|
|
lua_pushinteger(L, device.vendorId), lua_setfield(L, -2, "vendor");
|
2022-04-21 09:16:17 +00:00
|
|
|
lua_pushstring(L, device.name), lua_setfield(L, -2, "name");
|
|
|
|
lua_pushstring(L, device.renderer), lua_setfield(L, -2, "renderer");
|
|
|
|
lua_pushinteger(L, device.subgroupSize), lua_setfield(L, -2, "subgroupSize");
|
2022-04-22 20:28:59 +00:00
|
|
|
lua_pushboolean(L, device.discrete), lua_setfield(L, -2, "discrete");
|
2022-04-21 09:16:17 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_lovrGraphicsGetFeatures(lua_State* L) {
|
|
|
|
GraphicsFeatures features;
|
|
|
|
lovrGraphicsGetFeatures(&features);
|
|
|
|
lua_newtable(L);
|
2022-04-26 22:31:51 +00:00
|
|
|
lua_pushboolean(L, features.textureBC), lua_setfield(L, -2, "textureBC");
|
|
|
|
lua_pushboolean(L, features.textureASTC), lua_setfield(L, -2, "textureASTC");
|
2022-04-21 09:16:17 +00:00
|
|
|
lua_pushboolean(L, features.wireframe), lua_setfield(L, -2, "wireframe");
|
|
|
|
lua_pushboolean(L, features.depthClamp), lua_setfield(L, -2, "depthClamp");
|
|
|
|
lua_pushboolean(L, features.indirectDrawFirstInstance), lua_setfield(L, -2, "indirectDrawFirstInstance");
|
2022-07-17 18:38:55 +00:00
|
|
|
lua_pushboolean(L, features.shaderTally), lua_setfield(L, -2, "shaderTally");
|
2022-04-21 09:16:17 +00:00
|
|
|
lua_pushboolean(L, features.float64), lua_setfield(L, -2, "float64");
|
|
|
|
lua_pushboolean(L, features.int64), lua_setfield(L, -2, "int64");
|
|
|
|
lua_pushboolean(L, features.int16), lua_setfield(L, -2, "int16");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_lovrGraphicsGetLimits(lua_State* L) {
|
|
|
|
GraphicsLimits limits;
|
|
|
|
lovrGraphicsGetLimits(&limits);
|
|
|
|
|
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushinteger(L, limits.textureSize2D), lua_setfield(L, -2, "textureSize2D");
|
|
|
|
lua_pushinteger(L, limits.textureSize3D), lua_setfield(L, -2, "textureSize3D");
|
|
|
|
lua_pushinteger(L, limits.textureSizeCube), lua_setfield(L, -2, "textureSizeCube");
|
|
|
|
lua_pushinteger(L, limits.textureLayers), lua_setfield(L, -2, "textureLayers");
|
|
|
|
|
|
|
|
lua_createtable(L, 3, 0);
|
|
|
|
lua_pushinteger(L, limits.renderSize[0]), lua_rawseti(L, -2, 1);
|
|
|
|
lua_pushinteger(L, limits.renderSize[1]), lua_rawseti(L, -2, 2);
|
|
|
|
lua_pushinteger(L, limits.renderSize[2]), lua_rawseti(L, -2, 3);
|
|
|
|
lua_setfield(L, -2, "renderSize");
|
|
|
|
|
2022-06-01 03:16:16 +00:00
|
|
|
lua_pushinteger(L, limits.uniformBuffersPerStage), lua_setfield(L, -2, "uniformBuffersPerStage");
|
|
|
|
lua_pushinteger(L, limits.storageBuffersPerStage), lua_setfield(L, -2, "storageBuffersPerStage");
|
|
|
|
lua_pushinteger(L, limits.sampledTexturesPerStage), lua_setfield(L, -2, "sampledTexturesPerStage");
|
|
|
|
lua_pushinteger(L, limits.storageTexturesPerStage), lua_setfield(L, -2, "storageTexturesPerStage");
|
|
|
|
lua_pushinteger(L, limits.samplersPerStage), lua_setfield(L, -2, "samplersPerStage");
|
|
|
|
lua_pushinteger(L, limits.resourcesPerShader), lua_setfield(L, -2, "resourcesPerShader");
|
|
|
|
|
2022-04-21 09:16:17 +00:00
|
|
|
lua_pushinteger(L, limits.uniformBufferRange), lua_setfield(L, -2, "uniformBufferRange");
|
|
|
|
lua_pushinteger(L, limits.storageBufferRange), lua_setfield(L, -2, "storageBufferRange");
|
|
|
|
lua_pushinteger(L, limits.uniformBufferAlign), lua_setfield(L, -2, "uniformBufferAlign");
|
|
|
|
lua_pushinteger(L, limits.storageBufferAlign), lua_setfield(L, -2, "storageBufferAlign");
|
|
|
|
lua_pushinteger(L, limits.vertexAttributes), lua_setfield(L, -2, "vertexAttributes");
|
|
|
|
lua_pushinteger(L, limits.vertexBufferStride), lua_setfield(L, -2, "vertexBufferStride");
|
|
|
|
lua_pushinteger(L, limits.vertexShaderOutputs), lua_setfield(L, -2, "vertexShaderOutputs");
|
|
|
|
|
2022-04-26 22:31:51 +00:00
|
|
|
lua_pushinteger(L, limits.clipDistances), lua_setfield(L, -2, "clipDistances");
|
|
|
|
lua_pushinteger(L, limits.cullDistances), lua_setfield(L, -2, "cullDistances");
|
|
|
|
lua_pushinteger(L, limits.clipAndCullDistances), lua_setfield(L, -2, "clipAndCullDistances");
|
|
|
|
|
2022-04-21 09:16:17 +00:00
|
|
|
lua_createtable(L, 3, 0);
|
2022-08-06 20:06:42 +00:00
|
|
|
lua_pushinteger(L, limits.workgroupCount[0]), lua_rawseti(L, -2, 1);
|
|
|
|
lua_pushinteger(L, limits.workgroupCount[1]), lua_rawseti(L, -2, 2);
|
|
|
|
lua_pushinteger(L, limits.workgroupCount[2]), lua_rawseti(L, -2, 3);
|
|
|
|
lua_setfield(L, -2, "workgroupCount");
|
2022-04-21 09:16:17 +00:00
|
|
|
|
|
|
|
lua_createtable(L, 3, 0);
|
2022-08-06 20:06:42 +00:00
|
|
|
lua_pushinteger(L, limits.workgroupSize[0]), lua_rawseti(L, -2, 1);
|
|
|
|
lua_pushinteger(L, limits.workgroupSize[1]), lua_rawseti(L, -2, 2);
|
|
|
|
lua_pushinteger(L, limits.workgroupSize[2]), lua_rawseti(L, -2, 3);
|
|
|
|
lua_setfield(L, -2, "workgroupSize");
|
2022-04-21 09:16:17 +00:00
|
|
|
|
2022-08-06 20:06:42 +00:00
|
|
|
lua_pushinteger(L, limits.totalWorkgroupSize), lua_setfield(L, -2, "totalWorkgroupSize");
|
2022-04-21 09:16:17 +00:00
|
|
|
lua_pushinteger(L, limits.computeSharedMemory), lua_setfield(L, -2, "computeSharedMemory");
|
|
|
|
lua_pushinteger(L, limits.shaderConstantSize), lua_setfield(L, -2, "shaderConstantSize");
|
|
|
|
lua_pushinteger(L, limits.indirectDrawCount), lua_setfield(L, -2, "indirectDrawCount");
|
|
|
|
lua_pushinteger(L, limits.instances), lua_setfield(L, -2, "instances");
|
|
|
|
|
|
|
|
lua_pushnumber(L, limits.anisotropy), lua_setfield(L, -2, "anisotropy");
|
|
|
|
lua_pushnumber(L, limits.pointSize), lua_setfield(L, -2, "pointSize");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-04-30 00:12:10 +00:00
|
|
|
static int l_lovrGraphicsIsFormatSupported(lua_State* L) {
|
|
|
|
TextureFormat format = luax_checkenum(L, 1, TextureFormat, NULL);
|
|
|
|
uint32_t features = 0;
|
|
|
|
int top = lua_gettop(L);
|
|
|
|
for (int i = 2; i <= top; i++) {
|
|
|
|
features |= 1 << luax_checkenum(L, i, TextureFeature, NULL);
|
|
|
|
}
|
|
|
|
bool supported = lovrGraphicsIsFormatSupported(format, features);
|
|
|
|
lua_pushboolean(L, supported);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-08-14 04:10:58 +00:00
|
|
|
static int l_lovrGraphicsGetBackgroundColor(lua_State* L) {
|
2022-08-06 04:05:02 +00:00
|
|
|
float color[4];
|
2022-08-14 04:10:58 +00:00
|
|
|
lovrGraphicsGetBackgroundColor(color);
|
2022-08-06 04:05:02 +00:00
|
|
|
lua_pushnumber(L, color[0]);
|
|
|
|
lua_pushnumber(L, color[1]);
|
|
|
|
lua_pushnumber(L, color[2]);
|
|
|
|
lua_pushnumber(L, color[3]);
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
2022-08-14 04:10:58 +00:00
|
|
|
static int l_lovrGraphicsSetBackgroundColor(lua_State* L) {
|
2022-08-06 04:05:02 +00:00
|
|
|
float color[4];
|
|
|
|
luax_readcolor(L, 1, color);
|
2022-08-14 04:10:58 +00:00
|
|
|
lovrGraphicsSetBackgroundColor(color);
|
2022-08-06 04:05:02 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-03 05:00:11 +00:00
|
|
|
static int l_lovrGraphicsGetWindowPass(lua_State* L) {
|
|
|
|
Pass* pass = lovrGraphicsGetWindowPass();
|
|
|
|
luax_pushtype(L, Pass, pass);
|
|
|
|
return 1;
|
2022-05-11 22:38:01 +00:00
|
|
|
}
|
|
|
|
|
2022-06-21 01:58:12 +00:00
|
|
|
static int l_lovrGraphicsGetDefaultFont(lua_State* L) {
|
|
|
|
Font* font = lovrGraphicsGetDefaultFont();
|
|
|
|
luax_pushtype(L, Font, font);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-06-06 01:56:03 +00:00
|
|
|
static int l_lovrGraphicsGetBuffer(lua_State* L) {
|
2022-04-27 07:28:39 +00:00
|
|
|
BufferInfo info = { 0 };
|
|
|
|
|
|
|
|
luax_checkbufferformat(L, 2, &info);
|
2022-07-10 19:49:11 +00:00
|
|
|
info.length = luax_getbufferlength(L, 1, &info);
|
2022-04-27 07:28:39 +00:00
|
|
|
|
|
|
|
void* pointer;
|
|
|
|
bool hasData = !lua_isnumber(L, 1);
|
2022-04-30 10:06:14 +00:00
|
|
|
Buffer* buffer = lovrGraphicsGetBuffer(&info, hasData ? &pointer : NULL);
|
2022-04-27 07:28:39 +00:00
|
|
|
|
|
|
|
if (hasData) {
|
|
|
|
lua_settop(L, 1);
|
|
|
|
luax_readbufferdata(L, 1, buffer, pointer);
|
|
|
|
}
|
|
|
|
|
|
|
|
luax_pushtype(L, Buffer, buffer);
|
|
|
|
lovrRelease(buffer, lovrBufferDestroy);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-04-30 10:06:14 +00:00
|
|
|
static int l_lovrGraphicsNewBuffer(lua_State* L) {
|
2022-04-26 22:32:54 +00:00
|
|
|
BufferInfo info = { 0 };
|
|
|
|
|
|
|
|
luax_checkbufferformat(L, 2, &info);
|
2022-07-10 19:49:11 +00:00
|
|
|
info.length = luax_getbufferlength(L, 1, &info);
|
2022-04-27 07:28:39 +00:00
|
|
|
|
|
|
|
void* pointer;
|
|
|
|
bool hasData = !lua_isnumber(L, 1);
|
2022-04-30 10:06:14 +00:00
|
|
|
Buffer* buffer = lovrBufferCreate(&info, hasData ? &pointer : NULL);
|
2022-04-27 07:28:39 +00:00
|
|
|
|
|
|
|
if (hasData) {
|
|
|
|
lua_settop(L, 1);
|
|
|
|
luax_readbufferdata(L, 1, buffer, pointer);
|
|
|
|
}
|
2022-04-26 22:32:54 +00:00
|
|
|
|
|
|
|
luax_pushtype(L, Buffer, buffer);
|
|
|
|
lovrRelease(buffer, lovrBufferDestroy);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-04-30 10:06:14 +00:00
|
|
|
static int l_lovrGraphicsNewTexture(lua_State* L) {
|
|
|
|
TextureInfo info = {
|
|
|
|
.type = TEXTURE_2D,
|
|
|
|
.format = FORMAT_RGBA8,
|
|
|
|
.mipmaps = ~0u,
|
|
|
|
.samples = 1,
|
|
|
|
.usage = TEXTURE_SAMPLE,
|
|
|
|
.srgb = true
|
|
|
|
};
|
|
|
|
|
|
|
|
int index = 1;
|
|
|
|
Image* stack[6];
|
|
|
|
Image** images = stack;
|
|
|
|
|
|
|
|
if (lua_isnumber(L, 1)) {
|
|
|
|
info.width = luax_checku32(L, index++);
|
|
|
|
info.height = luax_checku32(L, index++);
|
|
|
|
if (lua_isnumber(L, index)) {
|
2022-07-30 22:08:30 +00:00
|
|
|
info.layers = luax_checku32(L, index++);
|
2022-04-30 10:06:14 +00:00
|
|
|
info.type = TEXTURE_ARRAY;
|
|
|
|
}
|
2022-05-11 19:51:13 +00:00
|
|
|
info.usage |= TEXTURE_RENDER;
|
2022-04-30 10:06:14 +00:00
|
|
|
} else if (lua_istable(L, 1)) {
|
2022-05-01 01:49:46 +00:00
|
|
|
info.imageCount = luax_len(L, index++);
|
|
|
|
images = info.imageCount > COUNTOF(stack) ? malloc(info.imageCount * sizeof(Image*)) : stack;
|
2022-04-30 10:06:14 +00:00
|
|
|
lovrAssert(images, "Out of memory");
|
|
|
|
info.type = TEXTURE_ARRAY;
|
2022-07-30 22:08:30 +00:00
|
|
|
info.layers = info.imageCount;
|
2022-04-30 10:06:14 +00:00
|
|
|
|
2022-05-01 01:49:46 +00:00
|
|
|
if (info.imageCount == 0) {
|
|
|
|
info.imageCount = 6;
|
2022-04-30 10:06:14 +00:00
|
|
|
info.type = TEXTURE_CUBE;
|
|
|
|
const char* faces[6] = { "right", "left", "top", "bottom", "back", "front" };
|
|
|
|
const char* altFaces[6] = { "px", "nx", "py", "ny", "pz", "nz" };
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
|
|
lua_pushstring(L, faces[i]);
|
|
|
|
lua_rawget(L, 1);
|
|
|
|
if (lua_isnil(L, -1)) {
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_pushstring(L, altFaces[i]);
|
|
|
|
lua_rawget(L, 1);
|
|
|
|
}
|
|
|
|
lovrAssert(!lua_isnil(L, -1), "No array texture layers given and cubemap face '%s' missing", faces[i]);
|
|
|
|
images[i] = luax_checkimage(L, -1);
|
|
|
|
}
|
|
|
|
}
|
2022-05-01 01:49:46 +00:00
|
|
|
|
|
|
|
lovrCheck(lovrImageGetLayerCount(images[0]) == 1, "When a list of images is provided, each must have a single layer");
|
2022-04-30 10:06:14 +00:00
|
|
|
} else {
|
2022-05-01 01:49:46 +00:00
|
|
|
info.imageCount = 1;
|
2022-04-30 10:06:14 +00:00
|
|
|
images[0] = luax_checkimage(L, index++);
|
2022-07-30 22:08:30 +00:00
|
|
|
info.layers = lovrImageGetLayerCount(images[0]);
|
2022-04-30 10:06:14 +00:00
|
|
|
if (lovrImageIsCube(images[0])) {
|
|
|
|
info.type = TEXTURE_CUBE;
|
2022-07-30 22:08:30 +00:00
|
|
|
} else if (info.layers > 1) {
|
2022-04-30 10:06:14 +00:00
|
|
|
info.type = TEXTURE_ARRAY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-01 01:49:46 +00:00
|
|
|
if (info.imageCount > 0) {
|
|
|
|
info.images = images;
|
2022-04-30 10:06:14 +00:00
|
|
|
Image* image = images[0];
|
|
|
|
uint32_t levels = lovrImageGetLevelCount(image);
|
|
|
|
info.format = lovrImageGetFormat(image);
|
2022-05-26 06:51:51 +00:00
|
|
|
info.width = lovrImageGetWidth(image, 0);
|
|
|
|
info.height = lovrImageGetHeight(image, 0);
|
2022-04-30 10:06:14 +00:00
|
|
|
info.mipmaps = levels == 1 ? ~0u : levels;
|
|
|
|
info.srgb = lovrImageIsSRGB(image);
|
2022-05-01 01:49:46 +00:00
|
|
|
for (uint32_t i = 1; i < info.imageCount; i++) {
|
2022-05-26 06:51:51 +00:00
|
|
|
lovrAssert(lovrImageGetWidth(images[0], 0) == lovrImageGetWidth(images[i], 0), "Image widths must match");
|
|
|
|
lovrAssert(lovrImageGetHeight(images[0], 0) == lovrImageGetHeight(images[i], 0), "Image heights must match");
|
2022-04-30 10:06:14 +00:00
|
|
|
lovrAssert(lovrImageGetFormat(images[0]) == lovrImageGetFormat(images[i]), "Image formats must match");
|
|
|
|
lovrAssert(lovrImageGetLevelCount(images[0]) == lovrImageGetLevelCount(images[i]), "Image mipmap counts must match");
|
2022-05-01 01:49:46 +00:00
|
|
|
lovrAssert(lovrImageGetLayerCount(images[i]) == 1, "When a list of images are provided, each must have a single layer");
|
2022-04-30 10:06:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lua_istable(L, index)) {
|
|
|
|
lua_getfield(L, index, "type");
|
|
|
|
info.type = lua_isnil(L, -1) ? info.type : luax_checkenum(L, -1, TextureType, NULL);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2022-05-01 01:49:46 +00:00
|
|
|
if (info.imageCount == 0) {
|
2022-04-30 10:06:14 +00:00
|
|
|
lua_getfield(L, index, "format");
|
|
|
|
info.format = lua_isnil(L, -1) ? info.format : luax_checkenum(L, -1, TextureFormat, NULL);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, index, "samples");
|
|
|
|
info.samples = lua_isnil(L, -1) ? info.samples : luax_checku32(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
lua_getfield(L, index, "linear");
|
|
|
|
info.srgb = lua_isnil(L, -1) ? info.srgb : !lua_toboolean(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, index, "mipmaps");
|
|
|
|
if (lua_type(L, -1) == LUA_TNUMBER) {
|
|
|
|
info.mipmaps = lua_tonumber(L, -1);
|
|
|
|
} else if (!lua_isnil(L, -1)) {
|
|
|
|
info.mipmaps = lua_toboolean(L, -1) ? ~0u : 1;
|
|
|
|
} else {
|
|
|
|
info.mipmaps = info.samples > 1 ? 1 : ~0u;
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, index, "usage");
|
|
|
|
switch (lua_type(L, -1)) {
|
|
|
|
case LUA_TSTRING: info.usage = 1 << luax_checkenum(L, -1, TextureUsage, NULL); break;
|
|
|
|
case LUA_TTABLE: {
|
|
|
|
int length = luax_len(L, -1);
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
|
|
lua_rawgeti(L, -1, i + 1);
|
|
|
|
info.usage |= 1 << luax_checkenum(L, -1, TextureUsage, NULL);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2022-05-11 19:51:13 +00:00
|
|
|
case LUA_TNIL: break;
|
2022-04-30 10:06:14 +00:00
|
|
|
default: return luaL_error(L, "Expected Texture usage to be a string, table, or nil");
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, index, "label");
|
|
|
|
info.label = lua_tostring(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
|
2022-07-30 22:08:30 +00:00
|
|
|
if (info.layers == 0) {
|
|
|
|
info.layers = info.type == TEXTURE_CUBE ? 6 : 1;
|
2022-04-30 10:06:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Texture* texture = lovrTextureCreate(&info);
|
|
|
|
|
2022-05-01 01:49:46 +00:00
|
|
|
for (uint32_t i = 0; i < info.imageCount; i++) {
|
|
|
|
lovrRelease(images[i], lovrImageDestroy);
|
2022-04-30 10:06:14 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 01:49:46 +00:00
|
|
|
if (images != stack) {
|
|
|
|
free(images);
|
2022-04-30 10:06:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
luax_pushtype(L, Texture, texture);
|
|
|
|
lovrRelease(texture, lovrTextureDestroy);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-05-01 22:47:17 +00:00
|
|
|
static int l_lovrGraphicsNewSampler(lua_State* L) {
|
|
|
|
SamplerInfo info = {
|
|
|
|
.min = FILTER_LINEAR,
|
|
|
|
.mag = FILTER_LINEAR,
|
|
|
|
.mip = FILTER_LINEAR,
|
|
|
|
.wrap = { WRAP_REPEAT, WRAP_REPEAT, WRAP_REPEAT },
|
|
|
|
.range = { 0.f, -1.f }
|
|
|
|
};
|
|
|
|
|
|
|
|
luaL_checktype(L, 1, LUA_TTABLE);
|
|
|
|
|
|
|
|
lua_getfield(L, 1, "filter");
|
|
|
|
if (lua_isstring(L, -1)) {
|
|
|
|
info.min = info.mag = info.mip = luax_checkenum(L, -1, FilterMode, NULL);
|
|
|
|
} else if (lua_istable(L, -1)) {
|
|
|
|
lua_rawgeti(L, -1, 1);
|
|
|
|
lua_rawgeti(L, -2, 2);
|
|
|
|
lua_rawgeti(L, -3, 3);
|
|
|
|
info.min = luax_checkenum(L, -3, FilterMode, NULL);
|
|
|
|
info.mag = luax_checkenum(L, -2, FilterMode, NULL);
|
|
|
|
info.mip = luax_checkenum(L, -1, FilterMode, NULL);
|
|
|
|
lua_pop(L, 3);
|
|
|
|
} else if (!lua_isnil(L, -1)) {
|
|
|
|
lovrThrow("Expected string or table for Sampler filter");
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, 1, "wrap");
|
|
|
|
if (lua_isstring(L, -1)) {
|
|
|
|
info.wrap[0] = info.wrap[1] = info.wrap[2] = luax_checkenum(L, -1, WrapMode, NULL);
|
|
|
|
} else if (lua_istable(L, -1)) {
|
|
|
|
lua_rawgeti(L, -1, 1);
|
|
|
|
lua_rawgeti(L, -2, 2);
|
|
|
|
lua_rawgeti(L, -3, 3);
|
|
|
|
info.wrap[0] = luax_checkenum(L, -3, WrapMode, NULL);
|
|
|
|
info.wrap[1] = luax_checkenum(L, -2, WrapMode, NULL);
|
|
|
|
info.wrap[2] = luax_checkenum(L, -1, WrapMode, NULL);
|
|
|
|
lua_pop(L, 3);
|
|
|
|
} else if (!lua_isnil(L, -1)) {
|
|
|
|
lovrThrow("Expected string or table for Sampler wrap");
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, 1, "compare");
|
2022-06-01 04:33:06 +00:00
|
|
|
info.compare = luax_checkcomparemode(L, -1);
|
2022-05-01 22:47:17 +00:00
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, 1, "anisotropy");
|
|
|
|
info.anisotropy = luax_optfloat(L, -1, 0.f);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, 1, "mipmaprange");
|
|
|
|
if (!lua_isnil(L, -1)) {
|
|
|
|
lovrAssert(lua_istable(L, -1), "Sampler mipmap range must be nil or a table");
|
|
|
|
lua_rawgeti(L, -1, 1);
|
|
|
|
lua_rawgeti(L, -2, 2);
|
|
|
|
info.range[0] = luax_checkfloat(L, -2);
|
|
|
|
info.range[1] = luax_checkfloat(L, -1);
|
|
|
|
lua_pop(L, 2);
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
Sampler* sampler = lovrSamplerCreate(&info);
|
|
|
|
luax_pushtype(L, Sampler, sampler);
|
|
|
|
lovrRelease(sampler, lovrSamplerDestroy);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-08-02 05:10:06 +00:00
|
|
|
static ShaderSource luax_checkshadersource(lua_State* L, int index, ShaderStage stage, bool* allocated) {
|
2022-07-10 06:09:02 +00:00
|
|
|
ShaderSource source;
|
|
|
|
if (lua_isstring(L, index)) {
|
|
|
|
size_t length;
|
|
|
|
const char* string = lua_tolstring(L, index, &length);
|
|
|
|
if (memchr(string, '\n', MIN(256, length))) {
|
|
|
|
source.code = string;
|
|
|
|
source.size = length;
|
|
|
|
*allocated = false;
|
|
|
|
} else {
|
2022-08-02 05:10:06 +00:00
|
|
|
for (int i = 0; lovrDefaultShader[i].length; i++) {
|
|
|
|
if (lovrDefaultShader[i].length == length && !memcmp(lovrDefaultShader[i].string, string, length)) {
|
2022-08-13 01:26:47 +00:00
|
|
|
*allocated = false;
|
2022-08-02 05:10:06 +00:00
|
|
|
return lovrGraphicsGetDefaultShaderSource(i, stage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-10 06:09:02 +00:00
|
|
|
source.code = luax_readfile(string, &source.size);
|
2022-08-02 05:10:06 +00:00
|
|
|
|
|
|
|
if (source.code) {
|
|
|
|
*allocated = true;
|
|
|
|
} else {
|
|
|
|
luaL_argerror(L, index, "single-line string was not filename or DefaultShader");
|
|
|
|
}
|
2022-07-10 06:09:02 +00:00
|
|
|
}
|
2022-07-07 06:50:43 +00:00
|
|
|
} else if (lua_istable(L, index)) {
|
|
|
|
int length = luax_len(L, index);
|
2022-07-10 06:09:02 +00:00
|
|
|
source.size = length * sizeof(uint32_t);
|
|
|
|
uint32_t* words = malloc(source.size);
|
2022-07-07 06:50:43 +00:00
|
|
|
lovrAssert(words, "Out of memory");
|
2022-07-10 06:09:02 +00:00
|
|
|
source.code = words;
|
|
|
|
*allocated = true;
|
2022-07-07 06:50:43 +00:00
|
|
|
for (int i = 0; i < length; i++) {
|
|
|
|
lua_rawgeti(L, index, i + 1);
|
2022-07-10 06:09:02 +00:00
|
|
|
words[i] = luax_checku32(L, -1);
|
2022-07-07 06:50:43 +00:00
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
2022-07-10 06:09:02 +00:00
|
|
|
} else if (lua_isuserdata(L, index)) {
|
|
|
|
Blob* blob = luax_checktype(L, index, Blob);
|
|
|
|
source.code = blob->data;
|
|
|
|
source.size = blob->size;
|
|
|
|
*allocated = false;
|
2022-05-09 18:47:06 +00:00
|
|
|
}
|
|
|
|
|
2022-07-10 06:09:02 +00:00
|
|
|
ShaderSource bytecode = lovrGraphicsCompileShader(stage, &source);
|
|
|
|
|
|
|
|
if (bytecode.code != source.code) {
|
|
|
|
if (*allocated) free((void*) source.code);
|
|
|
|
*allocated = true;
|
|
|
|
return bytecode;
|
|
|
|
}
|
|
|
|
|
|
|
|
return source;
|
2022-05-09 18:47:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int l_lovrGraphicsCompileShader(lua_State* L) {
|
|
|
|
ShaderStage stage = luax_checkenum(L, 1, ShaderStage, NULL);
|
2022-07-10 06:09:02 +00:00
|
|
|
bool allocated;
|
2022-08-02 05:10:06 +00:00
|
|
|
ShaderSource spirv = luax_checkshadersource(L, 2, stage, &allocated);
|
2022-09-14 00:22:48 +00:00
|
|
|
Blob* blob = lovrBlobCreate((void*) spirv.code, spirv.size, "Compiled Shader Code");
|
|
|
|
luax_pushtype(L, Blob, blob);
|
|
|
|
lovrRelease(blob, lovrBlobDestroy);
|
2022-05-09 18:47:06 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_lovrGraphicsNewShader(lua_State* L) {
|
|
|
|
ShaderInfo info = { 0 };
|
2022-07-10 06:09:02 +00:00
|
|
|
bool allocated[2];
|
2022-05-09 18:47:06 +00:00
|
|
|
int index;
|
|
|
|
|
2022-08-02 05:10:06 +00:00
|
|
|
// If there's only one source given, it could be a DefaultShader or a compute shader
|
2022-07-07 06:50:43 +00:00
|
|
|
if (lua_gettop(L) == 1 || (lua_istable(L, 2) && luax_len(L, 2) == 0)) {
|
2022-08-02 05:10:06 +00:00
|
|
|
if (lua_type(L, 1) == LUA_TSTRING) {
|
|
|
|
size_t length;
|
|
|
|
const char* string = lua_tolstring(L, 1, &length);
|
|
|
|
for (int i = 0; lovrDefaultShader[i].length; i++) {
|
|
|
|
if (lovrDefaultShader[i].length == length && !memcmp(lovrDefaultShader[i].string, string, length)) {
|
|
|
|
info.source[0] = lovrGraphicsGetDefaultShaderSource(i, STAGE_VERTEX);
|
|
|
|
info.source[1] = lovrGraphicsGetDefaultShaderSource(i, STAGE_FRAGMENT);
|
|
|
|
info.type = SHADER_GRAPHICS;
|
2022-08-13 01:26:47 +00:00
|
|
|
allocated[0] = false;
|
|
|
|
allocated[1] = false;
|
2022-08-02 05:10:06 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!info.source[0].code) {
|
|
|
|
info.type = SHADER_COMPUTE;
|
|
|
|
info.source[0] = luax_checkshadersource(L, 1, STAGE_COMPUTE, &allocated[0]);
|
|
|
|
}
|
|
|
|
|
2022-05-09 18:47:06 +00:00
|
|
|
index = 2;
|
|
|
|
} else {
|
|
|
|
info.type = SHADER_GRAPHICS;
|
2022-08-02 05:10:06 +00:00
|
|
|
info.source[0] = luax_checkshadersource(L, 1, STAGE_VERTEX, &allocated[0]);
|
|
|
|
info.source[1] = luax_checkshadersource(L, 2, STAGE_FRAGMENT, &allocated[1]);
|
2022-05-09 18:47:06 +00:00
|
|
|
index = 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
arr_t(ShaderFlag) flags;
|
|
|
|
arr_init(&flags, realloc);
|
|
|
|
|
|
|
|
if (lua_istable(L, index)) {
|
|
|
|
lua_getfield(L, index, "flags");
|
|
|
|
if (!lua_isnil(L, -1)) {
|
|
|
|
luaL_checktype(L, -1, LUA_TTABLE);
|
|
|
|
lua_pushnil(L);
|
|
|
|
while (lua_next(L, -2) != 0) {
|
|
|
|
ShaderFlag flag = { 0 };
|
|
|
|
flag.value = lua_isboolean(L, -1) ? (double) lua_toboolean(L, -1) : lua_tonumber(L, -1);
|
|
|
|
switch (lua_type(L, -2)) {
|
|
|
|
case LUA_TSTRING: flag.name = lua_tostring(L, -2); break;
|
|
|
|
case LUA_TNUMBER: flag.id = lua_tointeger(L, -2); break;
|
|
|
|
default: lovrThrow("Unexpected ShaderFlag key type (%s)", lua_typename(L, lua_type(L, -2)));
|
|
|
|
}
|
|
|
|
arr_push(&flags, flag);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_getfield(L, index, "label");
|
|
|
|
info.label = lua_tostring(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
|
2022-08-07 01:05:30 +00:00
|
|
|
lovrCheck(flags.length < 1000, "Too many Shader flags");
|
|
|
|
|
2022-05-09 18:47:06 +00:00
|
|
|
info.flags = flags.data;
|
2022-08-07 01:05:30 +00:00
|
|
|
info.flagCount = (uint32_t) flags.length;
|
2022-05-09 18:47:06 +00:00
|
|
|
|
2022-07-10 06:09:02 +00:00
|
|
|
Shader* shader = lovrShaderCreate(&info);
|
2022-05-09 18:47:06 +00:00
|
|
|
luax_pushtype(L, Shader, shader);
|
|
|
|
lovrRelease(shader, lovrShaderDestroy);
|
2022-07-10 06:09:02 +00:00
|
|
|
if (allocated[0]) free((void*) info.source[0].code);
|
|
|
|
if (allocated[1]) free((void*) info.source[1].code);
|
|
|
|
arr_free(&flags);
|
2022-05-09 18:47:06 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-06-17 06:49:09 +00:00
|
|
|
static Texture* luax_opttexture(lua_State* L, int index) {
|
|
|
|
if (lua_isnil(L, index)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Texture* texture = luax_totype(L, index, Texture);
|
|
|
|
if (texture) return texture;
|
|
|
|
|
|
|
|
Image* image = luax_checkimage(L, index);
|
|
|
|
|
|
|
|
TextureInfo info = {
|
|
|
|
.type = TEXTURE_2D,
|
|
|
|
.format = lovrImageGetFormat(image),
|
|
|
|
.width = lovrImageGetWidth(image, 0),
|
|
|
|
.height = lovrImageGetHeight(image, 0),
|
2022-07-30 22:08:30 +00:00
|
|
|
.layers = 1,
|
2022-06-17 06:49:09 +00:00
|
|
|
.mipmaps = ~0u,
|
|
|
|
.samples = 1,
|
|
|
|
.usage = TEXTURE_SAMPLE,
|
|
|
|
.srgb = lovrImageIsSRGB(image),
|
|
|
|
.imageCount = 1,
|
|
|
|
.images = &image
|
|
|
|
};
|
|
|
|
|
|
|
|
texture = lovrTextureCreate(&info);
|
|
|
|
lovrRelease(image, lovrImageDestroy);
|
|
|
|
return texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_lovrGraphicsNewMaterial(lua_State* L) {
|
2022-06-21 01:26:15 +00:00
|
|
|
MaterialInfo info;
|
|
|
|
memset(&info, 0, sizeof(info));
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
luaL_checktype(L, 1, LUA_TTABLE);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "color");
|
|
|
|
luax_optcolor(L, -1, info.data.color);
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "glow");
|
|
|
|
if (lua_isnil(L, -1)) {
|
|
|
|
memset(info.data.glow, 0, sizeof(info.data.glow));
|
|
|
|
} else {
|
|
|
|
luax_optcolor(L, -1, info.data.glow);
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "uvShift");
|
|
|
|
if (lua_type(L, -1) == LUA_TNUMBER) {
|
|
|
|
float shift = lua_tonumber(L, -1);
|
|
|
|
info.data.uvShift[0] = shift;
|
|
|
|
info.data.uvShift[1] = shift;
|
|
|
|
} else if (lua_type(L, -1) == LUA_TTABLE) {
|
|
|
|
lua_rawgeti(L, -1, 1);
|
|
|
|
lua_rawgeti(L, -1, 2);
|
|
|
|
info.data.uvShift[0] = luax_optfloat(L, -2, 0.f);
|
|
|
|
info.data.uvShift[1] = luax_optfloat(L, -1, 0.f);
|
|
|
|
lua_pop(L, 2);
|
|
|
|
} else if (!lua_isnil(L, -1)) {
|
|
|
|
float* v = luax_checkvector(L, -1, V_VEC2, "vec2, table, or nil");
|
|
|
|
info.data.uvShift[0] = v[0];
|
|
|
|
info.data.uvShift[1] = v[1];
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "uvScale");
|
|
|
|
if (lua_isnil(L, -1)) {
|
|
|
|
info.data.uvScale[0] = 1.f;
|
|
|
|
info.data.uvScale[1] = 1.f;
|
|
|
|
} else if (lua_isnumber(L, -1)) {
|
|
|
|
float scale = lua_tonumber(L, -1);
|
|
|
|
info.data.uvScale[0] = scale;
|
|
|
|
info.data.uvScale[1] = scale;
|
|
|
|
} else if (lua_type(L, -1) == LUA_TTABLE) {
|
|
|
|
lua_rawgeti(L, -1, 1);
|
|
|
|
lua_rawgeti(L, -1, 2);
|
|
|
|
info.data.uvScale[0] = luax_optfloat(L, -2, 1.f);
|
|
|
|
info.data.uvScale[1] = luax_optfloat(L, -1, 1.f);
|
|
|
|
lua_pop(L, 2);
|
|
|
|
} else {
|
|
|
|
float* v = luax_checkvector(L, -1, V_VEC2, "vec2, table, or nil");
|
|
|
|
info.data.uvScale[0] = v[0];
|
|
|
|
info.data.uvScale[1] = v[1];
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "metalness");
|
|
|
|
info.data.metalness = luax_optfloat(L, -1, 1.f);
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "roughness");
|
|
|
|
info.data.roughness = luax_optfloat(L, -1, 1.f);
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "clearcoat");
|
|
|
|
info.data.clearcoat = luax_optfloat(L, -1, 0.f);
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "clearcoatRoughness");
|
|
|
|
info.data.clearcoatRoughness = luax_optfloat(L, -1, 0.f);
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "occlusionStrength");
|
|
|
|
info.data.occlusionStrength = luax_optfloat(L, -1, 1.f);
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "normalScale");
|
|
|
|
info.data.normalScale = luax_optfloat(L, -1, 1.f);
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "alphaCutoff");
|
|
|
|
info.data.alphaCutoff = luax_optfloat(L, -1, 0.f);
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "texture");
|
|
|
|
info.texture = luax_opttexture(L, -1);
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "glowTexture");
|
|
|
|
info.glowTexture = luax_opttexture(L, -1);
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "metalnessTexture");
|
|
|
|
info.metalnessTexture = luax_opttexture(L, -1);
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "roughnessTexture");
|
|
|
|
info.roughnessTexture = luax_opttexture(L, -1);
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "clearcoatTexture");
|
|
|
|
info.clearcoatTexture = luax_opttexture(L, -1);
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
2022-09-02 22:33:18 +00:00
|
|
|
lua_getfield(L, 1, "occlusionTexture");
|
|
|
|
info.occlusionTexture = luax_opttexture(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2022-09-02 22:05:01 +00:00
|
|
|
lua_getfield(L, 1, "normalTexture");
|
|
|
|
info.normalTexture = luax_opttexture(L, -1);
|
|
|
|
lua_pop(L, 1);
|
2022-06-17 06:49:09 +00:00
|
|
|
|
|
|
|
Material* material = lovrMaterialCreate(&info);
|
|
|
|
luax_pushtype(L, Material, material);
|
|
|
|
lovrRelease(material, lovrMaterialDestroy);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-06-19 00:43:12 +00:00
|
|
|
static int l_lovrGraphicsNewFont(lua_State* L) {
|
|
|
|
FontInfo info = { 0 };
|
|
|
|
|
|
|
|
info.rasterizer = luax_totype(L, 1, Rasterizer);
|
|
|
|
info.spread = 4.;
|
|
|
|
|
|
|
|
if (!info.rasterizer) {
|
|
|
|
Blob* blob = NULL;
|
|
|
|
float size;
|
|
|
|
|
|
|
|
if (lua_type(L, 1) == LUA_TNUMBER || lua_isnoneornil(L, 1)) {
|
2022-07-04 22:22:54 +00:00
|
|
|
size = luax_optfloat(L, 1, 32.);
|
2022-06-27 03:28:30 +00:00
|
|
|
info.spread = luaL_optnumber(L, 2, info.spread);
|
2022-06-19 00:43:12 +00:00
|
|
|
} else {
|
|
|
|
blob = luax_readblob(L, 1, "Font");
|
2022-07-04 22:22:54 +00:00
|
|
|
size = luax_optfloat(L, 2, 32.);
|
2022-06-27 03:28:30 +00:00
|
|
|
info.spread = luaL_optnumber(L, 3, info.spread);
|
2022-06-19 00:43:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
info.rasterizer = lovrRasterizerCreate(blob, size);
|
|
|
|
lovrRelease(blob, lovrBlobDestroy);
|
|
|
|
} else {
|
2022-06-27 03:28:30 +00:00
|
|
|
info.spread = luaL_optnumber(L, 2, info.spread);
|
2022-06-19 00:43:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Font* font = lovrFontCreate(&info);
|
|
|
|
luax_pushtype(L, Font, font);
|
|
|
|
lovrRelease(info.rasterizer, lovrRasterizerDestroy);
|
|
|
|
lovrRelease(font, lovrFontDestroy);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-07-04 00:26:31 +00:00
|
|
|
static int l_lovrGraphicsNewModel(lua_State* L) {
|
|
|
|
ModelInfo info = { 0 };
|
|
|
|
info.data = luax_totype(L, 1, ModelData);
|
|
|
|
info.mipmaps = true;
|
|
|
|
|
|
|
|
if (!info.data) {
|
|
|
|
Blob* blob = luax_readblob(L, 1, "Model");
|
|
|
|
info.data = lovrModelDataCreate(blob, luax_readfile);
|
|
|
|
lovrRelease(blob, lovrBlobDestroy);
|
|
|
|
} else {
|
|
|
|
lovrRetain(info.data);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lua_istable(L, 2)) {
|
|
|
|
lua_getfield(L, 2, "mipmaps");
|
|
|
|
info.mipmaps = lua_isnil(L, -1) || lua_toboolean(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
Model* model = lovrModelCreate(&info);
|
|
|
|
luax_pushtype(L, Model, model);
|
|
|
|
lovrRelease(info.data, lovrModelDataDestroy);
|
|
|
|
lovrRelease(model, lovrModelDestroy);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-07-13 02:58:18 +00:00
|
|
|
static int l_lovrGraphicsNewTally(lua_State* L) {
|
|
|
|
TallyInfo info;
|
|
|
|
info.type = luax_checkenum(L, 1, TallyType, NULL);
|
|
|
|
info.count = luax_checku32(L, 2);
|
|
|
|
info.views = luax_optu32(L, 3, 2);
|
|
|
|
Tally* tally = lovrTallyCreate(&info);
|
|
|
|
luax_pushtype(L, Tally, tally);
|
|
|
|
lovrRelease(tally, lovrTallyDestroy);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-08-26 04:57:15 +00:00
|
|
|
static int l_lovrGraphicsGetPass(lua_State* L) {
|
2022-08-03 05:00:11 +00:00
|
|
|
PassInfo info = { 0 };
|
|
|
|
|
2022-06-17 06:49:09 +00:00
|
|
|
info.type = luax_checkenum(L, 1, PassType, NULL);
|
|
|
|
|
2022-08-03 05:00:11 +00:00
|
|
|
if (info.type == PASS_RENDER) {
|
|
|
|
info.canvas = luax_checkcanvas(L, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lua_istable(L, 2)) {
|
|
|
|
lua_getfield(L, 2, "label");
|
|
|
|
info.label = lua_tostring(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
} else {
|
|
|
|
info.label = NULL;
|
|
|
|
}
|
|
|
|
|
2022-08-26 04:57:15 +00:00
|
|
|
Pass* pass = lovrGraphicsGetPass(&info);
|
2022-06-17 06:49:09 +00:00
|
|
|
luax_pushtype(L, Pass, pass);
|
|
|
|
lovrRelease(pass, lovrPassDestroy);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
static const luaL_Reg lovrGraphics[] = {
|
2022-09-10 17:22:52 +00:00
|
|
|
{ "initialize", l_lovrGraphicsInitialize },
|
2022-04-29 05:30:31 +00:00
|
|
|
{ "submit", l_lovrGraphicsSubmit },
|
2022-08-04 07:06:54 +00:00
|
|
|
{ "present", l_lovrGraphicsPresent },
|
2022-04-29 05:37:03 +00:00
|
|
|
{ "wait", l_lovrGraphicsWait },
|
2022-04-21 09:16:17 +00:00
|
|
|
{ "getDevice", l_lovrGraphicsGetDevice },
|
|
|
|
{ "getFeatures", l_lovrGraphicsGetFeatures },
|
|
|
|
{ "getLimits", l_lovrGraphicsGetLimits },
|
2022-04-30 00:12:10 +00:00
|
|
|
{ "isFormatSupported", l_lovrGraphicsIsFormatSupported },
|
2022-08-14 04:10:58 +00:00
|
|
|
{ "getBackgroundColor", l_lovrGraphicsGetBackgroundColor },
|
|
|
|
{ "setBackgroundColor", l_lovrGraphicsSetBackgroundColor },
|
2022-08-03 05:00:11 +00:00
|
|
|
{ "getWindowPass", l_lovrGraphicsGetWindowPass },
|
2022-06-21 01:58:12 +00:00
|
|
|
{ "getDefaultFont", l_lovrGraphicsGetDefaultFont },
|
2022-06-06 01:56:03 +00:00
|
|
|
{ "getBuffer", l_lovrGraphicsGetBuffer },
|
2022-04-30 10:06:14 +00:00
|
|
|
{ "newBuffer", l_lovrGraphicsNewBuffer },
|
|
|
|
{ "newTexture", l_lovrGraphicsNewTexture },
|
2022-05-01 22:47:17 +00:00
|
|
|
{ "newSampler", l_lovrGraphicsNewSampler },
|
2022-05-09 18:47:06 +00:00
|
|
|
{ "compileShader", l_lovrGraphicsCompileShader },
|
|
|
|
{ "newShader", l_lovrGraphicsNewShader },
|
2022-06-17 06:49:09 +00:00
|
|
|
{ "newMaterial", l_lovrGraphicsNewMaterial },
|
2022-06-19 00:43:12 +00:00
|
|
|
{ "newFont", l_lovrGraphicsNewFont },
|
2022-07-04 00:26:31 +00:00
|
|
|
{ "newModel", l_lovrGraphicsNewModel },
|
2022-07-13 02:58:18 +00:00
|
|
|
{ "newTally", l_lovrGraphicsNewTally },
|
2022-08-26 04:57:15 +00:00
|
|
|
{ "getPass", l_lovrGraphicsGetPass },
|
2017-03-11 11:08:07 +00:00
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
2018-09-27 01:27:38 +00:00
|
|
|
|
2022-04-26 22:32:54 +00:00
|
|
|
extern const luaL_Reg lovrBuffer[];
|
2022-04-30 03:56:23 +00:00
|
|
|
extern const luaL_Reg lovrTexture[];
|
2022-05-01 22:48:41 +00:00
|
|
|
extern const luaL_Reg lovrSampler[];
|
2022-05-09 18:47:06 +00:00
|
|
|
extern const luaL_Reg lovrShader[];
|
2022-06-17 06:49:09 +00:00
|
|
|
extern const luaL_Reg lovrMaterial[];
|
2022-06-19 00:43:12 +00:00
|
|
|
extern const luaL_Reg lovrFont[];
|
2022-07-04 00:26:31 +00:00
|
|
|
extern const luaL_Reg lovrModel[];
|
2022-07-14 07:05:58 +00:00
|
|
|
extern const luaL_Reg lovrReadback[];
|
2022-07-13 02:58:18 +00:00
|
|
|
extern const luaL_Reg lovrTally[];
|
2022-05-01 01:54:29 +00:00
|
|
|
extern const luaL_Reg lovrPass[];
|
2022-04-26 22:32:54 +00:00
|
|
|
|
2019-08-26 22:53:10 +00:00
|
|
|
int luaopen_lovr_graphics(lua_State* L) {
|
2018-09-27 01:27:38 +00:00
|
|
|
lua_newtable(L);
|
2020-08-19 19:12:06 +00:00
|
|
|
luax_register(L, lovrGraphics);
|
2022-04-26 22:32:54 +00:00
|
|
|
luax_registertype(L, Buffer);
|
2022-04-30 03:56:23 +00:00
|
|
|
luax_registertype(L, Texture);
|
2022-05-01 22:48:41 +00:00
|
|
|
luax_registertype(L, Sampler);
|
2022-05-09 18:47:06 +00:00
|
|
|
luax_registertype(L, Shader);
|
2022-06-17 06:49:09 +00:00
|
|
|
luax_registertype(L, Material);
|
2022-06-19 00:43:12 +00:00
|
|
|
luax_registertype(L, Font);
|
2022-07-04 00:26:31 +00:00
|
|
|
luax_registertype(L, Model);
|
2022-07-14 07:05:58 +00:00
|
|
|
luax_registertype(L, Readback);
|
2022-07-13 02:58:18 +00:00
|
|
|
luax_registertype(L, Tally);
|
2022-05-01 01:54:29 +00:00
|
|
|
luax_registertype(L, Pass);
|
2018-09-27 01:27:38 +00:00
|
|
|
return 1;
|
|
|
|
}
|