diff options
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | demo/honey.lua | 18 | ||||
-rw-r--r-- | src/gl/data.c | 155 | ||||
-rw-r--r-- | src/gl/data.test.c | 216 | ||||
-rw-r--r-- | src/gl/gl.c | 143 | ||||
-rw-r--r-- | src/gl/gl.h | 1 | ||||
-rw-r--r-- | src/gl/gl.test.c | 1 |
7 files changed, 384 insertions, 151 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 02490f6..dc9a83c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,7 @@ set(HONEY_LIB_FILES ${SRC_ROOT}/gl/gl.c ${SRC_ROOT}/gl/shader.c ${SRC_ROOT}/gl/drawing.c + ${SRC_ROOT}/gl/data.c ${SRC_ROOT}/gl/window.c ) diff --git a/demo/honey.lua b/demo/honey.lua index fce264c..5e14461 100644 --- a/demo/honey.lua +++ b/demo/honey.lua @@ -67,23 +67,23 @@ local vertices = { 0.0, 0.5, 0.0 } -local vertexArray = gl.createVertexArray() +local vertexArray = gl.data.createVertexArray() -local vertexBuffer = gl.createBuffer() -gl.bindVertexArray(vertexArray) +local vertexBuffer = gl.data.createBuffer() +gl.data.bindVertexArray(vertexArray) -gl.bindBuffer(gl.bufferTarget.arrayBuffer, vertexBuffer) +gl.data.bindBuffer(gl.data.bufferTarget.arrayBuffer, vertexBuffer) local err = gl.getError() if err ~= gl.errorType.noError then error(gl.errorName(err)) end -gl.bufferData(gl.bufferTarget.arrayBuffer, gl.dataType.float, vertices, gl.bufferUsage.staticDraw) +gl.data.bufferData(gl.data.bufferTarget.arrayBuffer, gl.dataType.float, vertices, gl.data.bufferUsage.staticDraw) if gl.getError() ~= gl.errorType.noError then error(gl.getError()) end -gl.vertexAttribPointer(0, 3, false, 3, 0) +gl.data.vertexAttribPointer(0, 3, false, 3, 0) if gl.getError() ~= gl.errorType.noError then error(gl.getError()) end -gl.vertexArrayEnableAttrib(0) +gl.data.vertexArrayEnableAttrib(0) if gl.getError() ~= gl.errorType.noError then error(gl.getError()) end -gl.bindBuffer(gl.bufferTarget.arrayBuffer, 0) +gl.data.bindBuffer(gl.data.bufferTarget.arrayBuffer, 0) if gl.getError() ~= gl.errorType.noError then error(gl.getError()) end while not window.shouldClose(w) do @@ -91,7 +91,7 @@ while not window.shouldClose(w) do gl.draw.clear(gl.draw.bufferMask.colorBuffer); gl.shader.use(shader) - gl.bindVertexArray(vertexArray) + gl.data.bindVertexArray(vertexArray) gl.draw.drawArrays(gl.draw.primitiveType.triangles, 0, 3) window.swapBuffers(w) diff --git a/src/gl/data.c b/src/gl/data.c new file mode 100644 index 0000000..f598784 --- /dev/null +++ b/src/gl/data.c @@ -0,0 +1,155 @@ +#include <stdlib.h> +#include <stdbool.h> +#include "gl/glad/glad.h" +#include <GLFW/glfw3.h> +#include <lua.h> +#include <honeysuckle.h> +#include "gl.h" + +int gl_create_buffer(lua_State *L); +int gl_bind_buffer(lua_State *L); +int gl_buffer_data(lua_State *L); + +int gl_vertex_array_create(lua_State *L); +int gl_vertex_array_bind(lua_State *L); +int gl_vertex_attrib_pointer(lua_State *L); +int gl_vertex_array_enable_attrib(lua_State *L); + + +void setup_data(lua_State *L, int gl_index) +{ + int buffer_binding_targets = hs_create_table(L, + hs_str_int("arrayBuffer", GL_ARRAY_BUFFER), + hs_str_int("elementArrayBuffer", GL_ELEMENT_ARRAY_BUFFER), + ); + + int buffer_usage_patterns = hs_create_table(L, + hs_str_int("streamDraw", GL_STREAM_DRAW), + hs_str_int("staticDraw", GL_STATIC_DRAW), + hs_str_int("dynamicDraw", GL_DYNAMIC_DRAW), + ); + + hs_create_table(L, + hs_str_cfunc("createBuffer", gl_create_buffer), + hs_str_cfunc("bindBuffer", gl_bind_buffer), + hs_str_cfunc("bufferData", gl_buffer_data), + + hs_str_cfunc("createVertexArray", gl_vertex_array_create), + hs_str_cfunc("bindVertexArray", gl_vertex_array_bind), + hs_str_cfunc("vertexAttribPointer", gl_vertex_attrib_pointer), + hs_str_cfunc("vertexArrayEnableAttrib", gl_vertex_array_enable_attrib), + + hs_str_tbl("bufferTarget", buffer_binding_targets), + hs_str_tbl("bufferUsage", buffer_usage_patterns), + ); + + lua_setfield(L, gl_index, "data"); +} + + +int gl_create_buffer(lua_State *L) +{ + int buf; + glGenBuffers(1, &buf); + lua_pushinteger(L, buf); + return 1; +} + + +int gl_bind_buffer(lua_State *L) +{ + lua_Integer target, buf; + hs_parse_args(L, hs_int(target), hs_int(buf)); + glBindBuffer(target, buf); + return 0; +} + + +int gl_buffer_data(lua_State *L) +{ + lua_Integer target, type, usage; + int table; + hs_parse_args(L, hs_int(target), hs_int(type), hs_tbl(table), hs_int(usage)); + + if (type != GL_INT && type != GL_FLOAT) { + hs_throw_error(L, "invalid type"); + } + + /* build raw buffer */ + size_t len = lua_objlen(L, table); + void *buf; + if (type == GL_FLOAT) { + float *fbuf = malloc(len * sizeof(float)); + if (fbuf == NULL) + hs_throw_error(L, "failed to allocate intermediary fbuffer"); + for (int i=0; i<len; i++) { + lua_rawgeti(L, table, i+1); + if (!lua_isnumber(L, -1)) { + hs_throw_error(L, "all table items must be numbers (failed at index %d)", i); + } + fbuf[i] = lua_tonumber(L, -1); + lua_pop(L, 1); + } + len = len * sizeof(float); + buf = fbuf; + } + else { + int *ibuf = malloc(len * sizeof(int)); + if (ibuf == NULL) + hs_throw_error(L, "failed to allocate intermediary ibuffer"); + for (int i=0; i<len; i++) { + lua_rawgeti(L, table, i+1); + if (!lua_isnumber(L, -1)) { + hs_throw_error(L, "all table items must be integers (failed at index %d)", i); + } + ibuf[i] = lua_tointeger(L, -1); + lua_pop(L, 1); + } + len = len * sizeof(int); + buf = ibuf; + } + + /* call */ + glBufferData(target, len, buf, usage); + free(buf); + return 0; +} + + +int gl_vertex_array_create(lua_State *L) +{ + int array; + glGenVertexArrays(1, &array); + lua_pushinteger(L, array); + return 1; +} + + +int gl_vertex_array_bind(lua_State *L) +{ + lua_Integer array; + hs_parse_args(L, hs_int(array)); + glBindVertexArray(array); + return 0; +} + + +int gl_vertex_attrib_pointer(lua_State *L) +{ + lua_Integer index, size, stride, offset; + bool normalized; + hs_parse_args(L, hs_int(index), hs_int(size), hs_bool(normalized), hs_int(stride), hs_int(offset)); + glVertexAttribPointer(index, size, GL_FLOAT, + normalized, stride*sizeof(float), + (void*) (offset*sizeof(float))); + return 0; +} + + +int gl_vertex_array_enable_attrib(lua_State *L) +{ + lua_Integer index; + hs_parse_args(L, hs_int(index)); + glEnableVertexAttribArray(index); + return 0; +} diff --git a/src/gl/data.test.c b/src/gl/data.test.c new file mode 100644 index 0000000..143b0ce --- /dev/null +++ b/src/gl/data.test.c @@ -0,0 +1,216 @@ +#include <string.h> +#include <lua.h> +#include <lauxlib.h> +#include <honeysuckle.h> +#include "test/honey-test.h" + + +int mock_glfwInit_(void); +int mock_hs_throw_error_(lua_State *L, const char *str, ...); +void mock_glfwTerminate_(); +void mock_glBufferData_(int, size_t, const void *, int); + +#define DUMMY_FUNCTION(...) + +#define glfwInit mock_glfwInit_ +#define hs_throw_error mock_hs_throw_error_ +#define glfwTerminate mock_glfwTerminate_ +#undef glBufferData +#define glBufferData mock_glBufferData_ +#define setup_shader DUMMY_FUNCTION +#define setup_drawing DUMMY_FUNCTION +#include "gl/gl.c" +#undef glBufferData +#undef glfwTerminate +#undef hs_throw_error +#undef glfwInit + + +lily_mock_t *mock_hs_throw_error = NULL; +static int mock_hs_throw_error_(lua_State *L, const char *str, ...) +{ + struct lily_mock_arg_t args[] = { + { sizeof(const char *), &str } + }; + lily_mock_store_call(mock_hs_throw_error, args); + + lua_pushstring(L, "some error"); + lua_error(L); + + return 0; +} + +lily_mock_t *mock_glBufferData = NULL; +static void mock_glBufferData_(int target, size_t size, const void *data, int usage) +{ + struct lily_mock_arg_t args[] = { + { sizeof(int), &target }, + { sizeof(size_t), &size }, + { sizeof(int), &usage } + }; + lily_mock_store_call(mock_glBufferData, args); + + int use_ints; lily_get_value(mock_glBufferData, int, &use_ints); + + if (use_ints) { + size_t count = size/sizeof(int); + int *numbers = data; + for (int i=0; i<count; i++) { + lily_store_value(mock_glBufferData, int, numbers[i]); + } + } + else { + size_t count = size/sizeof(float); + float *numbers = data; + for (int i=0; i<count; i++) { + lily_store_value(mock_glBufferData, float, numbers[i]); + } + } +} + + +/* ~~~~~~~~ suite ~~~~~~~~ */ + +void gl_init_succeeds() +{ + lily_mock_use(&mock_glfwInit); + lily_mock_use(&mock_hs_throw_error); + + lua_State *L = luaL_newstate(); + lily_store_value(mock_glfwInit, int, 1); + lua_pushcfunction(L, gl_init); + int err = lua_pcall(L, 0, 0, 0); + lua_close(L); + + lily_assert_int_equal(err, 0); + lily_assert_int_equal(mock_glfwInit->n_calls, 1); + lily_assert_int_equal(mock_hs_throw_error->n_calls, 0); +} + + +void gl_init_fails() +{ + lily_mock_use(&mock_glfwInit); + lily_mock_use(&mock_hs_throw_error); + + lua_State *L = luaL_newstate(); + lily_store_value(mock_glfwInit, int, 0); + lua_pushcfunction(L, gl_init); + int err = lua_pcall(L, 0, 0, 0); + lua_close(L); + + lily_assert_int_equal(err, LUA_ERRRUN); + lily_assert_int_equal(mock_hs_throw_error->n_calls, 1); +} + + +void gl_terminate_works() +{ + lily_mock_use(&mock_glfwTerminate); + + lua_State *L = luaL_newstate(); + lua_pushcfunction(L, gl_terminate); + int err = lua_pcall(L, 0, 0, 0); + lua_close(L); + + lily_assert_int_equal(err, 0); + lily_assert_int_equal(mock_glfwTerminate->n_calls, 1); +} + + +void gl_buffer_float_works() +{ + lily_mock_use(&mock_hs_throw_error); + lily_mock_use(&mock_glBufferData); + lily_store_value(mock_glBufferData, int, 0); // use floats + + lua_State *L = luaL_newstate(); + lua_pushcfunction(L, gl_buffer_data); + lua_pushinteger(L, GL_ARRAY_BUFFER); + lua_pushinteger(L, GL_FLOAT); + hs_create_table(L, + hs_int_num(1, 22), + hs_int_num(2, 33), + hs_int_num(3, 44), + ); + lua_pushinteger(L, GL_STATIC_DRAW); + int err = hs_call(L, 4, 0); + lua_close(L); + + lily_assert_int_equal(err, 0); + lily_assert_int_equal(mock_glBufferData->n_calls, 1); + int target; size_t size; int usage; + struct lily_mock_arg_t args[] = { + { sizeof(int), &target }, + { sizeof(size_t), &size }, + { sizeof(int), &usage } + }; + lily_mock_get_call(mock_glBufferData, args, 0); + lily_assert_int_equal(target, GL_ARRAY_BUFFER); + lily_assert_int_equal(size, 3*sizeof(float)); + lily_assert_int_equal(usage, GL_STATIC_DRAW); + + float n; + lily_get_value(mock_glBufferData, float, &n); + lily_assert_float_equal(n, 22, 0.1); + lily_get_value(mock_glBufferData, float, &n); + lily_assert_float_equal(n, 33, 0.1); + lily_get_value(mock_glBufferData, float, &n); + lily_assert_float_equal(n, 44, 0.1); +} + + +void gl_buffer_int_works() +{ + lily_mock_use(&mock_hs_throw_error); + lily_mock_use(&mock_glBufferData); + lily_store_value(mock_glBufferData, int, 1); // use ints + + lua_State *L = luaL_newstate(); + lua_pushcfunction(L, gl_buffer_data); + lua_pushinteger(L, GL_ARRAY_BUFFER); + lua_pushinteger(L, GL_INT); + hs_create_table(L, + hs_int_num(1, 22), + hs_int_num(2, 33), + hs_int_num(3, 44), + ); + lua_pushinteger(L, GL_STATIC_DRAW); + int err = hs_call(L, 4, 0); + lua_close(L); + + lily_assert_int_equal(err, 0); + lily_assert_int_equal(mock_glBufferData->n_calls, 1); + int target; size_t size; int usage; + struct lily_mock_arg_t args[] = { + { sizeof(int), &target }, + { sizeof(size_t), &size }, + { sizeof(int), &usage } + }; + lily_mock_get_call(mock_glBufferData, args, 0); + lily_assert_int_equal(target, GL_ARRAY_BUFFER); + lily_assert_int_equal(size, 3*sizeof(float)); + lily_assert_int_equal(usage, GL_STATIC_DRAW); + + int n; + lily_get_value(mock_glBufferData, int, &n); + lily_assert_int_equal(n, 22); + lily_get_value(mock_glBufferData, int, &n); + lily_assert_int_equal(n, 33); + lily_get_value(mock_glBufferData, int, &n); + lily_assert_int_equal(n, 44); +} + +void suite_gl() +{ + lily_run_test(gl_init_succeeds); + lily_run_test(gl_init_fails); + lily_run_test(gl_terminate_works); + lily_run_test(gl_buffer_float_works); + lily_run_test(gl_buffer_int_works); + + lily_mock_destroy(mock_glfwInit); + lily_mock_destroy(mock_hs_throw_error); + lily_mock_destroy(mock_glfwTerminate); + lily_mock_destroy(mock_glBufferData); +} diff --git a/src/gl/gl.c b/src/gl/gl.c index 876df9d..8a1cb17 100644 --- a/src/gl/gl.c +++ b/src/gl/gl.c @@ -18,16 +18,6 @@ int glad_init(lua_State *L); int gl_terminate(lua_State *L); int gl_get_error(lua_State *L); -/* buffers */ -int gl_create_buffer(lua_State *L); -int gl_bind_buffer(lua_State *L); -int gl_buffer_data(lua_State *L); - -int gl_vertex_array_create(lua_State *L); -int gl_vertex_array_bind(lua_State *L); -int gl_vertex_attrib_pointer(lua_State *L); -int gl_vertex_array_enable_attrib(lua_State *L); - void setup_gl(lua_State *L, int honey_index) { int data_types = hs_create_table(L, @@ -44,17 +34,6 @@ void setup_gl(lua_State *L, int honey_index) hs_str_int("outOfMemory", GL_OUT_OF_MEMORY), ); - int buffer_binding_targets = hs_create_table(L, - hs_str_int("arrayBuffer", GL_ARRAY_BUFFER), - hs_str_int("elementArrayBuffer", GL_ELEMENT_ARRAY_BUFFER), - ); - - int buffer_usage_patterns = hs_create_table(L, - hs_str_int("streamDraw", GL_STREAM_DRAW), - hs_str_int("staticDraw", GL_STATIC_DRAW), - hs_str_int("dynamicDraw", GL_DYNAMIC_DRAW), - ); - int gl_index = hs_create_table(L, hs_str_cfunc("init", gl_init), hs_str_cfunc("initGlad", glad_init), @@ -63,23 +42,11 @@ void setup_gl(lua_State *L, int honey_index) hs_str_tbl("dataType", data_types), hs_str_tbl("errorType", error_types), - - /* buffer */ - hs_str_cfunc("createBuffer", gl_create_buffer), - hs_str_cfunc("bindBuffer", gl_bind_buffer), - hs_str_cfunc("bufferData", gl_buffer_data), - - hs_str_cfunc("createVertexArray", gl_vertex_array_create), - hs_str_cfunc("bindVertexArray", gl_vertex_array_bind), - hs_str_cfunc("vertexAttribPointer", gl_vertex_attrib_pointer), - hs_str_cfunc("vertexArrayEnableAttrib", gl_vertex_array_enable_attrib), - - hs_str_tbl("bufferTarget", buffer_binding_targets), - hs_str_tbl("bufferUsage", buffer_usage_patterns), ); setup_shader(L, gl_index); setup_drawing(L, gl_index); + setup_data(L, gl_index); lua_setfield(L, honey_index, "gl"); } @@ -113,111 +80,3 @@ int gl_get_error(lua_State *L) lua_pushinteger(L, glGetError()); return 1; } - - -int gl_create_buffer(lua_State *L) -{ - int buf; - glGenBuffers(1, &buf); - lua_pushinteger(L, buf); - return 1; -} - - -int gl_bind_buffer(lua_State *L) -{ - lua_Integer target, buf; - hs_parse_args(L, hs_int(target), hs_int(buf)); - glBindBuffer(target, buf); - return 0; -} - - -int gl_buffer_data(lua_State *L) -{ - lua_Integer target, type, usage; - int table; - hs_parse_args(L, hs_int(target), hs_int(type), hs_tbl(table), hs_int(usage)); - - if (type != GL_INT && type != GL_FLOAT) { - hs_throw_error(L, "invalid type"); - } - - /* build raw buffer */ - size_t len = lua_objlen(L, table); - void *buf; - if (type == GL_FLOAT) { - float *fbuf = malloc(len * sizeof(float)); - if (fbuf == NULL) - hs_throw_error(L, "failed to allocate intermediary fbuffer"); - for (int i=0; i<len; i++) { - lua_rawgeti(L, table, i+1); - if (!lua_isnumber(L, -1)) { - hs_throw_error(L, "all table items must be numbers (failed at index %d)", i); - } - fbuf[i] = lua_tonumber(L, -1); - lua_pop(L, 1); - } - len = len * sizeof(float); - buf = fbuf; - } - else { - int *ibuf = malloc(len * sizeof(int)); - if (ibuf == NULL) - hs_throw_error(L, "failed to allocate intermediary ibuffer"); - for (int i=0; i<len; i++) { - lua_rawgeti(L, table, i+1); - if (!lua_isnumber(L, -1)) { - hs_throw_error(L, "all table items must be integers (failed at index %d)", i); - } - ibuf[i] = lua_tointeger(L, -1); - lua_pop(L, 1); - } - len = len * sizeof(int); - buf = ibuf; - } - - /* call */ - glBufferData(target, len, buf, usage); - free(buf); - return 0; -} - - -int gl_vertex_array_create(lua_State *L) -{ - int array; - glGenVertexArrays(1, &array); - lua_pushinteger(L, array); - return 1; -} - - -int gl_vertex_array_bind(lua_State *L) -{ - lua_Integer array; - hs_parse_args(L, hs_int(array)); - glBindVertexArray(array); - return 0; -} - - -int gl_vertex_attrib_pointer(lua_State *L) -{ - lua_Integer index, size, stride, offset; - bool normalized; - hs_parse_args(L, hs_int(index), hs_int(size), hs_bool(normalized), hs_int(stride), hs_int(offset)); - glVertexAttribPointer(index, size, GL_FLOAT, - normalized, stride*sizeof(float), - (void*) (offset*sizeof(float))); - return 0; -} - - -int gl_vertex_array_enable_attrib(lua_State *L) -{ - lua_Integer index; - hs_parse_args(L, hs_int(index)); - glEnableVertexAttribArray(index); - return 0; -} diff --git a/src/gl/gl.h b/src/gl/gl.h index f384c54..766fe63 100644 --- a/src/gl/gl.h +++ b/src/gl/gl.h @@ -6,6 +6,7 @@ void setup_gl(lua_State *L, int honey_index); void setup_shader(lua_State *L, int gl_index); void setup_drawing(lua_State *L, int gl_index); +void setup_data(lua_State *L, int gl_index); void setup_window(lua_State *L, int honey_index); diff --git a/src/gl/gl.test.c b/src/gl/gl.test.c index 363036a..7a687b4 100644 --- a/src/gl/gl.test.c +++ b/src/gl/gl.test.c @@ -20,6 +20,7 @@ void mock_glBufferData_(int, size_t, const void *, int); #define setup_shader DUMMY_FUNCTION #define setup_drawing DUMMY_FUNCTION #include "gl/gl.c" +#include "gl/data.c" #undef glBufferData #undef glfwTerminate #undef hs_throw_error |