mirror of https://github.com/bjornbytes/lovr.git
Custom Buffer vertex attribute formats;
This commit is contained in:
parent
6c4100e7fb
commit
7cd168aa46
|
@ -2,13 +2,36 @@
|
|||
#include "graphics.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
Buffer* lovrBufferCreate(int size, BufferDrawMode drawMode, BufferUsage usage) {
|
||||
Buffer* lovrBufferCreate(int size, BufferFormat* format, BufferDrawMode drawMode, BufferUsage usage) {
|
||||
Buffer* buffer = malloc(sizeof(Buffer));
|
||||
|
||||
vec_init(&buffer->map);
|
||||
vec_init(&buffer->format);
|
||||
|
||||
if (format) {
|
||||
vec_extend(&buffer->format, format);
|
||||
} else {
|
||||
BufferAttribute position = { .name = "position", .type = BUFFER_FLOAT, .size = 3 };
|
||||
BufferAttribute normal = { .name = "normal", .type = BUFFER_FLOAT, .size = 3 };
|
||||
BufferAttribute texCoord = { .name = "texCoord", .type = BUFFER_FLOAT, .size = 2 };
|
||||
vec_push(&buffer->format, position);
|
||||
vec_push(&buffer->format, normal);
|
||||
vec_push(&buffer->format, texCoord);
|
||||
}
|
||||
|
||||
int stride = 0;
|
||||
int i;
|
||||
BufferAttribute attribute;
|
||||
vec_foreach(&buffer->format, attribute, i) {
|
||||
stride += attribute.size * sizeof(attribute.type);
|
||||
}
|
||||
|
||||
buffer->size = size;
|
||||
buffer->stride = stride;
|
||||
buffer->data = malloc(buffer->size * buffer->stride);
|
||||
buffer->scratchVertex = malloc(buffer->stride);
|
||||
buffer->drawMode = drawMode;
|
||||
buffer->usage = usage;
|
||||
buffer->size = size;
|
||||
buffer->data = malloc(buffer->size * 3 * sizeof(GLfloat));
|
||||
buffer->vao = 0;
|
||||
buffer->vbo = 0;
|
||||
buffer->ibo = 0;
|
||||
|
@ -18,12 +41,9 @@ Buffer* lovrBufferCreate(int size, BufferDrawMode drawMode, BufferUsage usage) {
|
|||
|
||||
glGenBuffers(1, &buffer->vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffer->vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, buffer->size * 3 * sizeof(GLfloat), buffer->data, buffer->usage);
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, buffer->size * buffer->stride, buffer->data, buffer->usage);
|
||||
glGenVertexArrays(1, &buffer->vao);
|
||||
|
||||
vec_init(&buffer->map);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
@ -31,15 +51,20 @@ void lovrBufferDestroy(Buffer* buffer) {
|
|||
glDeleteBuffers(1, &buffer->vbo);
|
||||
glDeleteVertexArrays(1, &buffer->vao);
|
||||
vec_deinit(&buffer->map);
|
||||
vec_deinit(&buffer->format);
|
||||
free(buffer->scratchVertex);
|
||||
free(buffer->data);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void lovrBufferDraw(Buffer* buffer) {
|
||||
int usingIbo = buffer->map.length > 0;
|
||||
|
||||
lovrGraphicsPrepare();
|
||||
glBindVertexArray(buffer->vao);
|
||||
glEnableVertexAttribArray(0);
|
||||
int usingIbo = buffer->map.length > 0;
|
||||
for (int i = 0; i < buffer->format.length; i++) {
|
||||
glEnableVertexAttribArray(i);
|
||||
}
|
||||
|
||||
int start, count;
|
||||
if (buffer->isRangeEnabled) {
|
||||
|
@ -57,7 +82,10 @@ void lovrBufferDraw(Buffer* buffer) {
|
|||
} else {
|
||||
glDrawArrays(buffer->drawMode, start, count);
|
||||
}
|
||||
glDisableVertexAttribArray(0);
|
||||
}
|
||||
|
||||
BufferFormat lovrBufferGetVertexFormat(Buffer* buffer) {
|
||||
return buffer->format;
|
||||
}
|
||||
|
||||
BufferDrawMode lovrBufferGetDrawMode(Buffer* buffer) {
|
||||
|
@ -73,21 +101,36 @@ int lovrBufferGetVertexCount(Buffer* buffer) {
|
|||
return buffer->size;
|
||||
}
|
||||
|
||||
void lovrBufferGetVertex(Buffer* buffer, int index, float* x, float* y, float* z) {
|
||||
*x = buffer->data[3 * index + 0];
|
||||
*y = buffer->data[3 * index + 1];
|
||||
*z = buffer->data[3 * index + 2];
|
||||
int lovrBufferGetVertexSize(Buffer* buffer) {
|
||||
return buffer->stride;
|
||||
}
|
||||
|
||||
void lovrBufferSetVertex(Buffer* buffer, int index, float x, float y, float z) {
|
||||
buffer->data[3 * index + 0] = x;
|
||||
buffer->data[3 * index + 1] = y;
|
||||
buffer->data[3 * index + 2] = z;
|
||||
void* lovrBufferGetScratchVertex(Buffer* buffer) {
|
||||
return buffer->scratchVertex;
|
||||
}
|
||||
|
||||
void lovrBufferGetVertex(Buffer* buffer, int index, void* dest) {
|
||||
if (index >= buffer->size) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(dest, buffer->data + index * buffer->stride, buffer->stride);
|
||||
}
|
||||
|
||||
void lovrBufferSetVertex(Buffer* buffer, int index, void* data) {
|
||||
memcpy(buffer->data + index * buffer->stride, data, buffer->stride);
|
||||
|
||||
glBindVertexArray(buffer->vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffer->vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, buffer->size * 3 * sizeof(GLfloat), buffer->data, buffer->usage);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
glBufferData(GL_ARRAY_BUFFER, buffer->size * buffer->stride, buffer->data, buffer->usage);
|
||||
|
||||
int i;
|
||||
BufferAttribute attribute;
|
||||
size_t offset = 0;
|
||||
vec_foreach(&buffer->format, attribute, i) {
|
||||
glVertexAttribPointer(i, attribute.size, attribute.type, GL_FALSE, buffer->stride, (void*) offset);
|
||||
offset += attribute.size + sizeof(attribute.type);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int* lovrBufferGetVertexMap(Buffer* buffer, int* count) {
|
||||
|
|
|
@ -16,9 +16,25 @@ typedef enum {
|
|||
BUFFER_STREAM = GL_STREAM_DRAW
|
||||
} BufferUsage;
|
||||
|
||||
typedef enum {
|
||||
BUFFER_FLOAT = GL_FLOAT,
|
||||
BUFFER_BYTE = GL_BYTE
|
||||
} BufferAttributeType;
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
BufferAttributeType type;
|
||||
int size;
|
||||
} BufferAttribute;
|
||||
|
||||
typedef vec_t(BufferAttribute) BufferFormat;
|
||||
|
||||
typedef struct {
|
||||
int size;
|
||||
GLfloat* data;
|
||||
int stride;
|
||||
void* data;
|
||||
void* scratchVertex;
|
||||
BufferFormat format;
|
||||
BufferDrawMode drawMode;
|
||||
BufferUsage usage;
|
||||
GLuint vao;
|
||||
|
@ -31,14 +47,17 @@ typedef struct {
|
|||
} Buffer;
|
||||
#endif
|
||||
|
||||
Buffer* lovrBufferCreate(int size, BufferDrawMode drawMode, BufferUsage usage);
|
||||
Buffer* lovrBufferCreate(int size, BufferFormat* format, BufferDrawMode drawMode, BufferUsage usage);
|
||||
void lovrBufferDestroy(Buffer* buffer);
|
||||
void lovrBufferDraw(Buffer* buffer);
|
||||
BufferFormat lovrBufferGetVertexFormat(Buffer* buffer);
|
||||
BufferDrawMode lovrBufferGetDrawMode(Buffer* buffer);
|
||||
int lovrBufferSetDrawMode(Buffer* buffer, BufferDrawMode drawMode);
|
||||
int lovrBufferGetVertexCount(Buffer* buffer);
|
||||
void lovrBufferGetVertex(Buffer* buffer, int index, float* x, float* y, float* z);
|
||||
void lovrBufferSetVertex(Buffer* buffer, int index, float x, float y, float z);
|
||||
int lovrBufferGetVertexSize(Buffer* buffer);
|
||||
void* lovrBufferGetScratchVertex(Buffer* buffer);
|
||||
void lovrBufferGetVertex(Buffer* buffer, int index, void* dest);
|
||||
void lovrBufferSetVertex(Buffer* buffer, int index, void* vertex);
|
||||
unsigned int* lovrBufferGetVertexMap(Buffer* buffer, int* count);
|
||||
void lovrBufferSetVertexMap(Buffer* buffer, unsigned int* map, int count);
|
||||
char lovrBufferIsRangeEnabled(Buffer* buffer);
|
||||
|
|
|
@ -13,6 +13,60 @@ void luax_pushbuffer(lua_State* L, Buffer* buffer) {
|
|||
*userdata = buffer;
|
||||
}
|
||||
|
||||
int luax_pushbuffervertex(lua_State* L, void* vertex, BufferFormat format) {
|
||||
int count = 0;
|
||||
int i;
|
||||
BufferAttribute attribute;
|
||||
vec_foreach(&format, attribute, i) {
|
||||
for (int j = 0; j < attribute.size; j++) {
|
||||
if (attribute.type == BUFFER_FLOAT) {
|
||||
lua_pushnumber(L, *((float*)vertex));
|
||||
vertex += sizeof(float);
|
||||
} else if (attribute.type == BUFFER_BYTE) {
|
||||
lua_pushnumber(L, *((unsigned char*)vertex));
|
||||
vertex += sizeof(unsigned char);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void luax_checkbufferformat(lua_State* L, int index, BufferFormat* format) {
|
||||
if (!lua_istable(L, index)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int length = lua_objlen(L, index);
|
||||
for (int i = 0; i < length; i++) {
|
||||
lua_rawgeti(L, index, i + 1);
|
||||
|
||||
if (!lua_istable(L, -1) || lua_objlen(L, -1) != 3) {
|
||||
luaL_error(L, "Expected vertex format specified as tables containing name, data type, and size");
|
||||
return;
|
||||
}
|
||||
|
||||
lua_rawgeti(L, -1, 1);
|
||||
lua_rawgeti(L, -2, 2);
|
||||
lua_rawgeti(L, -3, 3);
|
||||
|
||||
const char* name = lua_tostring(L, -3);
|
||||
const char* userAttributeType = lua_tostring(L, -2);
|
||||
int size = lua_tointeger(L, -1);
|
||||
|
||||
BufferAttributeType* type = (BufferAttributeType*) map_get(&BufferAttributeTypes, userAttributeType);
|
||||
if (!type) {
|
||||
luaL_error(L, "Invalid buffer attribute type: '%s'", userAttributeType);
|
||||
return;
|
||||
}
|
||||
|
||||
BufferAttribute attribute = { .name = name, .type = *type, .size = size };
|
||||
vec_push(format, attribute);
|
||||
|
||||
lua_pop(L, 4);
|
||||
}
|
||||
}
|
||||
|
||||
Buffer* luax_checkbuffer(lua_State* L, int index) {
|
||||
return *(Buffer**) luaL_checkudata(L, index, "Buffer");
|
||||
}
|
||||
|
@ -95,21 +149,71 @@ int l_lovrBufferGetVertexCount(lua_State* L) {
|
|||
int l_lovrBufferGetVertex(lua_State* L) {
|
||||
Buffer* buffer = luax_checkbuffer(L, 1);
|
||||
int index = luaL_checkint(L, 2) - 1;
|
||||
float x, y, z;
|
||||
lovrBufferGetVertex(buffer, index, &x, &y, &z);
|
||||
lua_pushnumber(L, x);
|
||||
lua_pushnumber(L, y);
|
||||
lua_pushnumber(L, z);
|
||||
return 3;
|
||||
void* vertex = lovrBufferGetScratchVertex(buffer);
|
||||
lovrBufferGetVertex(buffer, index, vertex);
|
||||
BufferFormat format = lovrBufferGetVertexFormat(buffer);
|
||||
return luax_pushbuffervertex(L, vertex, format);
|
||||
}
|
||||
|
||||
int l_lovrBufferSetVertex(lua_State* L) {
|
||||
Buffer* buffer = luax_checkbuffer(L, 1);
|
||||
int index = luaL_checkint(L, 2) - 1;
|
||||
float x = luaL_checknumber(L, 3);
|
||||
float y = luaL_checknumber(L, 4);
|
||||
float z = luaL_checknumber(L, 5);
|
||||
lovrBufferSetVertex(buffer, index, x, y, z);
|
||||
BufferFormat format = lovrBufferGetVertexFormat(buffer);
|
||||
void* vertex = lovrBufferGetScratchVertex(buffer);
|
||||
|
||||
if (lua_istable(L, 3)) {
|
||||
int tableCount = lua_objlen(L, 3);
|
||||
int tableIndex = 1;
|
||||
void* v = vertex;
|
||||
int i;
|
||||
BufferAttribute attribute;
|
||||
|
||||
vec_foreach(&format, attribute, i) {
|
||||
for (int j = 0; j < attribute.size; j++) {
|
||||
if (attribute.type == BUFFER_FLOAT) {
|
||||
float value = 0.f;
|
||||
if (tableIndex <= tableCount) {
|
||||
lua_rawgeti(L, 3, tableIndex++);
|
||||
value = lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
*((float*) v) = value;
|
||||
v += sizeof(float);
|
||||
} else if (attribute.type == BUFFER_BYTE) {
|
||||
unsigned char value = 255;
|
||||
if (tableIndex <= tableCount) {
|
||||
lua_rawgeti(L, 3, tableIndex++);
|
||||
value = lua_tointeger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
*((unsigned char*) v) = value;
|
||||
v += sizeof(unsigned char);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int argumentCount = lua_gettop(L);
|
||||
int argumentIndex = 3;
|
||||
void* v = vertex;
|
||||
int i;
|
||||
BufferAttribute attribute;
|
||||
|
||||
vec_foreach(&format, attribute, i) {
|
||||
for (int j = 0; j < attribute.size; j++) {
|
||||
if (attribute.type == BUFFER_FLOAT) {
|
||||
*((float*) v) = argumentIndex <= argumentCount ? lua_tonumber(L, argumentIndex++) : 0.f;
|
||||
v += sizeof(float);
|
||||
} else if (attribute.type == BUFFER_BYTE) {
|
||||
*((char*) v) = argumentIndex <= argumentCount ? lua_tointeger(L, argumentIndex++) : 255;
|
||||
v += sizeof(char);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lovrBufferSetVertex(buffer, index, vertex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include "../graphics/buffer.h"
|
||||
|
||||
void luax_pushbuffer(lua_State* L, Buffer* buffer);
|
||||
int luax_pushvertex(lua_State* L, void* vertex, BufferFormat format);
|
||||
void luax_checkbufferformat(lua_State* L, int index, BufferFormat* format);
|
||||
Buffer* luax_checkbuffer(lua_State* L, int index);
|
||||
int luax_destroybuffer(lua_State* L);
|
||||
extern const luaL_Reg lovrBuffer[];
|
||||
|
|
|
@ -51,6 +51,10 @@ int l_lovrGraphicsInit(lua_State* L) {
|
|||
luaRegisterType(L, "Model", lovrModel, luax_destroymodel);
|
||||
luaRegisterType(L, "Shader", lovrShader, luax_destroyshader);
|
||||
|
||||
map_init(&BufferAttributeTypes);
|
||||
map_set(&BufferAttributeTypes, "float", BUFFER_FLOAT);
|
||||
map_set(&BufferAttributeTypes, "byte", BUFFER_BYTE);
|
||||
|
||||
map_init(&BufferDrawModes);
|
||||
map_set(&BufferDrawModes, "points", BUFFER_POINTS);
|
||||
map_set(&BufferDrawModes, "strip", BUFFER_TRIANGLE_STRIP);
|
||||
|
@ -402,45 +406,96 @@ int l_lovrGraphicsGetDimensions(lua_State* L) {
|
|||
}
|
||||
|
||||
int l_lovrGraphicsNewBuffer(lua_State* L) {
|
||||
const char* userDrawMode = luaL_optstring(L, 2, "fan");
|
||||
int size;
|
||||
int dataIndex = 0;
|
||||
int drawModeIndex = 2;
|
||||
BufferFormat format;
|
||||
vec_init(&format);
|
||||
|
||||
if (lua_isnumber(L, 1)) {
|
||||
size = lua_tointeger(L, 1);
|
||||
} else if (lua_istable(L, 1)) {
|
||||
drawModeIndex++;
|
||||
if (lua_isnumber(L, 2)) {
|
||||
luax_checkbufferformat(L, 1, &format);
|
||||
size = lua_tointeger(L, 2);
|
||||
dataIndex = 0;
|
||||
} else if (lua_istable(L, 2)) {
|
||||
luax_checkbufferformat(L, 1, &format);
|
||||
size = lua_objlen(L, 2);
|
||||
dataIndex = 2;
|
||||
} else {
|
||||
size = lua_objlen(L, 1);
|
||||
dataIndex = 1;
|
||||
}
|
||||
} else {
|
||||
luaL_argerror(L, 1, "table or number expected");
|
||||
}
|
||||
|
||||
const char* userDrawMode = luaL_optstring(L, drawModeIndex, "fan");
|
||||
BufferDrawMode* drawMode = (BufferDrawMode*) map_get(&BufferDrawModes, userDrawMode);
|
||||
if (!drawMode) {
|
||||
return luaL_error(L, "Invalid buffer draw mode: '%s'", userDrawMode);
|
||||
}
|
||||
|
||||
const char* userUsage = luaL_optstring(L, 3, "dynamic");
|
||||
const char* userUsage = luaL_optstring(L, drawModeIndex + 1, "dynamic");
|
||||
BufferUsage* usage = (BufferUsage*) map_get(&BufferUsages, userUsage);
|
||||
if (!usage) {
|
||||
return luaL_error(L, "Invalid buffer usage: '%s'", userUsage);
|
||||
}
|
||||
|
||||
int size;
|
||||
Buffer* buffer = lovrBufferCreate(size, format.length ? &format : NULL, *drawMode, *usage);
|
||||
|
||||
if (lua_isnumber(L, 1)) {
|
||||
size = lua_tonumber(L, 1);
|
||||
} else if (lua_istable(L, 1)) {
|
||||
size = lua_objlen(L, 1);
|
||||
} else {
|
||||
return luaL_argerror(L, 1, "table or number expected");
|
||||
}
|
||||
if (dataIndex) {
|
||||
void* vertex = lovrBufferGetScratchVertex(buffer);
|
||||
int length = lua_objlen(L, dataIndex);
|
||||
BufferFormat format = lovrBufferGetVertexFormat(buffer);
|
||||
|
||||
Buffer* buffer = lovrBufferCreate(size, *drawMode, *usage);
|
||||
for (int i = 0; i < length; i++) {
|
||||
lua_rawgeti(L, dataIndex, i + 1);
|
||||
|
||||
if (lua_istable(L, 1)) {
|
||||
float x, y, z;
|
||||
for (int i = 0; i < size; i++) {
|
||||
lua_rawgeti(L, 1, i + 1);
|
||||
lua_rawgeti(L, -1, 1);
|
||||
lua_rawgeti(L, -2, 2);
|
||||
lua_rawgeti(L, -3, 3);
|
||||
x = lua_tonumber(L, -3);
|
||||
y = lua_tonumber(L, -2);
|
||||
z = lua_tonumber(L, -1);
|
||||
lovrBufferSetVertex(buffer, i, x, y, z);
|
||||
lua_pop(L, 4);
|
||||
if (!lua_istable(L, -1)) {
|
||||
return luaL_error(L, "Vertex information should be specified as a table");
|
||||
}
|
||||
|
||||
int tableCount = lua_objlen(L, -1);
|
||||
int tableIndex = 1;
|
||||
void* v = vertex;
|
||||
int j;
|
||||
BufferAttribute attribute;
|
||||
|
||||
vec_foreach(&format, attribute, j) {
|
||||
for (int k = 0; k < attribute.size; k++) {
|
||||
if (attribute.type == BUFFER_FLOAT) {
|
||||
float value = 0.f;
|
||||
if (tableIndex <= tableCount) {
|
||||
lua_rawgeti(L, -1, tableIndex++);
|
||||
value = lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
*((float*) v) = value;
|
||||
v += sizeof(float);
|
||||
} else if (attribute.type == BUFFER_BYTE) {
|
||||
unsigned char value = 255;
|
||||
if (tableIndex <= tableCount) {
|
||||
lua_rawgeti(L, 3, tableIndex++);
|
||||
value = lua_tointeger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
*((unsigned char*) v) = value;
|
||||
v += sizeof(unsigned char);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lovrBufferSetVertex(buffer, i, vertex);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
vec_deinit(&format);
|
||||
luax_pushbuffer(L, buffer);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <lualib.h>
|
||||
#include "../vendor/map/map.h"
|
||||
|
||||
map_int_t BufferAttributeTypes;
|
||||
map_int_t BufferDrawModes;
|
||||
map_int_t BufferUsages;
|
||||
map_int_t DrawModes;
|
||||
|
|
Loading…
Reference in New Issue