Custom Buffer vertex attribute formats;

This commit is contained in:
bjorn 2016-10-09 17:40:02 -07:00
parent 6c4100e7fb
commit 7cd168aa46
6 changed files with 281 additions and 57 deletions

View File

@ -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) {

View File

@ -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);

View File

@ -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;
}

View File

@ -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[];

View File

@ -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;
}

View File

@ -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;