diff options
author | sanine <sanine.not@pm.me> | 2022-08-23 13:38:27 -0500 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2022-08-23 13:38:27 -0500 |
commit | 3afbf2a13b2dada445fb667bf25600407fea480a (patch) | |
tree | 551329e6f74fc9f177616de0d6739e8b5331ae96 /src/gl | |
parent | 261e3f991221fbad6bbf262f5e65b773e4b6c73e (diff) | |
parent | 25ed7eb9f84e9a822f698ad803901fbb2a5354cf (diff) |
:wMerge branch 'gl-window' into main
Diffstat (limited to 'src/gl')
-rw-r--r-- | src/gl/CMakeLists.txt | 20 | ||||
-rw-r--r-- | src/gl/data.c | 156 | ||||
-rw-r--r-- | src/gl/data.test.c | 216 | ||||
-rw-r--r-- | src/gl/drawing.c | 81 | ||||
-rw-r--r-- | src/gl/gl.c | 83 | ||||
-rw-r--r-- | src/gl/gl.h | 14 | ||||
-rw-r--r-- | src/gl/gl.test.c | 237 | ||||
-rw-r--r-- | src/gl/shader.c | 180 | ||||
-rw-r--r-- | src/gl/texture.c | 116 | ||||
-rw-r--r-- | src/gl/window.c | 233 | ||||
-rw-r--r-- | src/gl/window.test.c | 430 |
11 files changed, 1264 insertions, 502 deletions
diff --git a/src/gl/CMakeLists.txt b/src/gl/CMakeLists.txt new file mode 100644 index 0000000..c1c3db0 --- /dev/null +++ b/src/gl/CMakeLists.txt @@ -0,0 +1,20 @@ +project(honey_engine) + +set (GL ${CMAKE_CURRENT_LIST_DIR}) + +target_sources(honey PUBLIC + ${GL}/data.c + ${GL}/drawing.c + ${GL}/shader.c + ${GL}/window.c + ${GL}/texture.c + ${GL}/gl.c + ${GL}/glad/glad.c +) + + +target_sources(test PUBLIC + ${GL}/glad/glad.c + ${GL}/gl.test.c + ${GL}/window.test.c +) diff --git a/src/gl/data.c b/src/gl/data.c new file mode 100644 index 0000000..a9d0324 --- /dev/null +++ b/src/gl/data.c @@ -0,0 +1,156 @@ +#include <stdlib.h> +#include <stdbool.h> +#include "gl/glad/glad.h" +#include <GLFW/glfw3.h> +#include <lua.h> +#include <honeysuckle.h> +#include "util/util.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 tbl = hs_create_table(L, + /* functions */ + hs_str_cfunc("GenBuffers", gl_create_buffer), + hs_str_cfunc("BindBuffer", gl_bind_buffer), + hs_str_cfunc("BufferData", gl_buffer_data), + + hs_str_cfunc("GenVertexArrays", gl_vertex_array_create), + hs_str_cfunc("BindVertexArray", gl_vertex_array_bind), + hs_str_cfunc("VertexAttribPointer", gl_vertex_attrib_pointer), + hs_str_cfunc("EnableVertexAttribArray", gl_vertex_array_enable_attrib), + + /******** enums ********/ + /* buffer bind targets */ + hs_str_int("ARRAY_BUFFER", GL_ARRAY_BUFFER), + hs_str_int("ELEMENT_ARRAY_BUFFER", GL_ELEMENT_ARRAY_BUFFER), + + /* buffer usage patters */ + hs_str_int("STREAM_DRAW", GL_STREAM_DRAW), + hs_str_int("STATIC_DRAW", GL_STATIC_DRAW), + hs_str_int("DYNAMIC_DRAW", GL_DYNAMIC_DRAW), + ); + + append_table(L, gl_index, tbl); + lua_pop(L, 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; +} + + +#define GET_BUFFER_TYPE(type, name, conversion) \ + void * get_buffer_ ## name (lua_State *L, size_t *sz, int tbl) { \ + size_t len = lua_objlen(L, tbl); \ + *sz = len * sizeof(type); \ + type *buf = malloc(*sz); \ + if (buf == NULL) \ + hs_throw_error(L, "failed to allocate intermediary buffer"); \ + for (int i=0; i<len; i++) { \ + lua_rawgeti(L, tbl, i+1); \ + if (!lua_isnumber(L, -1)) \ + hs_throw_error(L, "all elements must be numbers (failed at index %d)", i); \ + buf[i] = conversion(L, -1); \ + lua_pop(L, 1); \ + } \ + return buf; \ + } + +GET_BUFFER_TYPE(unsigned int, uint, lua_tointeger) +GET_BUFFER_TYPE(int, int, lua_tointeger) +GET_BUFFER_TYPE(float, float, lua_tonumber) + +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)); + + /* build raw buffer */ + void *buf; size_t len; + switch(type) { + case GL_UNSIGNED_INT: + buf = get_buffer_uint(L, &len, table); + break; + + case GL_INT: + buf = get_buffer_int(L, &len, table); + break; + + case GL_FLOAT: + buf = get_buffer_float(L, &len, table); + break; + + default: + hs_throw_error(L, "invalid type"); + } + + /* 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/drawing.c b/src/gl/drawing.c new file mode 100644 index 0000000..e6b1e13 --- /dev/null +++ b/src/gl/drawing.c @@ -0,0 +1,81 @@ +#include "gl/glad/glad.h" +#include <GLFW/glfw3.h> +#include <lua.h> +#include <honeysuckle.h> +#include "util/util.h" + +int gl_set_viewport(lua_State *L); +int gl_draw_arrays(lua_State *L); +int gl_draw_elements(lua_State *L); +int gl_set_clear_color(lua_State *L); +int gl_clear(lua_State *L); + +void setup_drawing(lua_State *L, int gl_index) +{ + int tbl = hs_create_table(L, + /* functions */ + hs_str_cfunc("DrawArrays", gl_draw_arrays), + hs_str_cfunc("DrawElements", gl_draw_elements), + hs_str_cfunc("ClearColor", gl_set_clear_color), + hs_str_cfunc("Clear", gl_clear), + hs_str_cfunc("Viewport", gl_set_viewport), + + /******** enums ********/ + /* rendering primitives */ + hs_str_int("POINTS", GL_POINTS), + hs_str_int("LINES", GL_LINES), + hs_str_int("TRIANGLES", GL_TRIANGLES), + + /* clear bitmasks */ + hs_str_int("COLOR_BUFFER_BIT", GL_COLOR_BUFFER_BIT), + hs_str_int("DEPTH_BUFFER_BIT", GL_DEPTH_BUFFER_BIT), + hs_str_int("STENCIL_BUFFER_BIT", GL_STENCIL_BUFFER_BIT), + ); + + append_table(L, gl_index, tbl); + lua_pop(L, 1); +} + +int gl_set_clear_color(lua_State *L) +{ + lua_Number r, g, b, a; + hs_parse_args(L, hs_num(r), hs_num(g), hs_num(b), hs_num(a)); + glClearColor(r, g, b, a); + return 0; +} + + +int gl_clear(lua_State *L) +{ + lua_Integer mask; + hs_parse_args(L, hs_int(mask)); + glClear(mask); + return 0; +} + + +int gl_draw_arrays(lua_State *L) +{ + lua_Integer mode, first, count; + hs_parse_args(L, hs_int(mode), hs_int(first), hs_int(count)); + glDrawArrays(mode, first, count); + return 0; +} + + +int gl_draw_elements(lua_State *L) +{ + lua_Integer mode, count, type, offset; + hs_parse_args(L, hs_int(mode), hs_int(count), hs_int(type), hs_int(offset)); + glDrawElements(mode, count, type, (const void*)offset); + return 0; +} + + +int gl_set_viewport(lua_State *L) +{ + lua_Integer x, y, w, h; + hs_parse_args(L, hs_int(x), hs_int(y), hs_int(w), hs_int(h)); + glViewport(x, y, w, h); + return 0; +} diff --git a/src/gl/gl.c b/src/gl/gl.c new file mode 100644 index 0000000..4639d48 --- /dev/null +++ b/src/gl/gl.c @@ -0,0 +1,83 @@ +#include <stdlib.h> +#include <stdbool.h> +#include "gl/glad/glad.h" +#include <GLFW/glfw3.h> +#include <lua.h> +#include <honeysuckle.h> +#include "gl.h" + +/* needs to be here because glad uses macros to define glBufferData */ +#ifdef HONEY_TEST_H +#undef glBufferData +#define glBufferData mock_glBufferData_ +#endif + + +int gl_init(lua_State *L); +int glad_init(lua_State *L); +int gl_terminate(lua_State *L); +int gl_get_error(lua_State *L); + +void setup_gl(lua_State *L, int honey_index) +{ + int gl_index = hs_create_table(L, + /* functions */ + hs_str_cfunc("Init", gl_init), + hs_str_cfunc("InitGlad", glad_init), + hs_str_cfunc("Terminate", gl_terminate), + hs_str_cfunc("GetError", gl_get_error), + + /******** enums ********/ + /* data types */ + hs_str_int("UNSIGNED_BYTE", GL_UNSIGNED_BYTE), + hs_str_int("UNSIGNED_INT", GL_UNSIGNED_INT), + hs_str_int("INT", GL_INT), + hs_str_int("FLOAT", GL_FLOAT), + + /* error types */ + hs_str_int("NO_ERROR", GL_NO_ERROR), + hs_str_int("INVALID_ENUM", GL_INVALID_ENUM), + hs_str_int("INVALID_VALUE", GL_INVALID_VALUE), + hs_str_int("INVALID_OPERATION", GL_INVALID_OPERATION), + hs_str_int("INVALID_FRAMEBUFFER_OPERATION", GL_INVALID_FRAMEBUFFER_OPERATION), + hs_str_int("OUT_OF_MEMORY", GL_OUT_OF_MEMORY), + ); + + setup_shader(L, gl_index); + setup_drawing(L, gl_index); + setup_data(L, gl_index); + setup_texture(L, gl_index); + + lua_setfield(L, honey_index, "gl"); +} + + +int gl_init(lua_State *L) +{ + if (!glfwInit()) { + hs_throw_error(L, "failed to initialize GLFW"); + } + return 0; +} + + +int glad_init(lua_State *L) +{ + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { + hs_throw_error(L, "failed to initialize GLAD"); + } +} + + +int gl_terminate(lua_State *L) +{ + glfwTerminate(); + return 0; +} + + +int gl_get_error(lua_State *L) +{ + lua_pushinteger(L, glGetError()); + return 1; +} diff --git a/src/gl/gl.h b/src/gl/gl.h new file mode 100644 index 0000000..8aa1ef7 --- /dev/null +++ b/src/gl/gl.h @@ -0,0 +1,14 @@ +#ifndef HONEY_GL_H +#define HONEY_GL_H + +#include <lua.h> + +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_texture(lua_State *L, int gl_index); + +void setup_window(lua_State *L, int honey_index); + +#endif diff --git a/src/gl/gl.test.c b/src/gl/gl.test.c new file mode 100644 index 0000000..488126f --- /dev/null +++ b/src/gl/gl.test.c @@ -0,0 +1,237 @@ +#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_ +#define setup_shader DUMMY_FUNCTION +#define setup_drawing DUMMY_FUNCTION +#define setup_texture DUMMY_FUNCTION +#include "gl/gl.c" +#include "gl/data.c" +#undef glBufferData +#undef glfwTerminate +#undef hs_throw_error +#undef glfwInit + + +lily_mock_t *mock_glfwInit = NULL; +int mock_glfwInit_() +{ + struct lily_mock_arg_t args[] = {}; + lily_mock_store_call(mock_glfwInit, args); + + int result; + lily_get_value(mock_glfwInit, int, &result); + return result; +} + + +lily_mock_t *mock_hs_throw_error = NULL; +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_glfwTerminate = NULL; +void mock_glfwTerminate_() +{ + struct lily_mock_arg_t args[] = {}; + lily_mock_store_call(mock_glfwTerminate, args); +} + + +lily_mock_t *mock_glBufferData = NULL; +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/shader.c b/src/gl/shader.c new file mode 100644 index 0000000..3732aff --- /dev/null +++ b/src/gl/shader.c @@ -0,0 +1,180 @@ +#include "gl/glad/glad.h" +#include <GLFW/glfw3.h> +#include <lua.h> +#include <honeysuckle.h> +#include "util/util.h" + +int gl_create_shader(lua_State *L); +int gl_shader_set_source(lua_State *L); +int gl_shader_compile(lua_State *L); +int gl_shader_delete(lua_State *L); + +int gl_program_create(lua_State *L); +int gl_program_attach_shader(lua_State *L); +int gl_program_link(lua_State *L); +int gl_program_use(lua_State *L); + +int gl_uniform_get_location(lua_State *L); +int gl_uniform_1i(lua_State *L); +int gl_uniform_4f(lua_State *L); + +int gl_uniform_matrix_4fv(lua_State *L); + + +void setup_shader(lua_State *L, int gl_index) +{ + int tbl = hs_create_table(L, + /* functions */ + hs_str_cfunc("CreateShader", gl_create_shader), + hs_str_cfunc("ShaderSource", gl_shader_set_source), + hs_str_cfunc("CompileShader", gl_shader_compile), + hs_str_cfunc("DeleteShader", gl_shader_delete), + + hs_str_cfunc("CreateProgram", gl_program_create), + hs_str_cfunc("AttachShader", gl_program_attach_shader), + hs_str_cfunc("LinkProgram", gl_program_link), + hs_str_cfunc("UseProgram", gl_program_use), + + hs_str_cfunc("GetUniformLocation", gl_uniform_get_location), + hs_str_cfunc("Uniform1i", gl_uniform_1i), + hs_str_cfunc("Uniform4f", gl_uniform_4f), + + hs_str_cfunc("UniformMatrix4fv", gl_uniform_matrix_4fv), + + /******** enums ********/ + /* shader types */ + hs_str_int("VERTEX_SHADER", GL_VERTEX_SHADER), + hs_str_int("FRAGMENT_SHADER", GL_FRAGMENT_SHADER), + ); + + append_table(L, gl_index, tbl); + lua_pop(L, 1); +} + + +int gl_create_shader(lua_State *L) +{ + lua_Integer type; + hs_parse_args(L, hs_int(type)); + lua_Integer shader = glCreateShader(type); + lua_pushinteger(L, shader); + return 1; +} + + +int gl_shader_set_source(lua_State *L) +{ + lua_Integer shader; + char *code; + hs_parse_args(L, hs_int(shader), hs_str(code)); + glShaderSource(shader, 1, (const GLchar * const*)&code, NULL); + return 0; +} + + +int gl_shader_compile(lua_State *L) +{ + lua_Integer shader; + hs_parse_args(L, hs_int(shader)); + glCompileShader(shader); + int success; char log[1024]; + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(shader, 1024, NULL, log); + hs_throw_error(L, "shader compilation failed: %s", log); + } + return 0; +} + + +int gl_shader_delete(lua_State *L) +{ + lua_Integer shader; + hs_parse_args(L, hs_int(shader)); + glDeleteShader(shader); + return 0; +} + + +int gl_program_create(lua_State *L) +{ + lua_Integer program = glCreateProgram(); + lua_pushinteger(L, program); + return 1; +} + + +int gl_program_attach_shader(lua_State *L) +{ + lua_Integer program, shader; + hs_parse_args(L, hs_int(program), hs_int(shader)), + glAttachShader(program, shader); + return 0; +} + + +int gl_program_link(lua_State *L) +{ + lua_Integer program; + hs_parse_args(L, hs_int(program)); + glLinkProgram(program); + int success; char log[1024]; + glGetProgramiv(program, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(program, 1024, NULL, log); + hs_throw_error(L, "shader linking failed: %s", log); + } + return 0; +} + + +int gl_program_use(lua_State *L) +{ + lua_Integer program; + hs_parse_args(L, hs_int(program)); + glUseProgram(program); + return 0; +} + + +int gl_uniform_get_location(lua_State *L) +{ + lua_Integer program; + char *name; + hs_parse_args(L, hs_int(program), hs_str(name)); + int location = glGetUniformLocation(program, (const GLchar*)name); + lua_pushinteger(L, location); + return 1; +} + + +int gl_uniform_1i(lua_State *L) +{ + lua_Integer location, v0; + hs_parse_args(L, hs_int(location), hs_int(v0)); + glUniform1i(location, v0); + return 0; +} + + +int gl_uniform_4f(lua_State *L) +{ + lua_Integer location; + lua_Number v0, v1, v2, v3; + hs_parse_args(L, hs_int(location), hs_num(v0), hs_num(v1), hs_num(v2), hs_num(v3)); + glUniform4f(location, v0, v1, v2, v3); + return 0; +} + + +int gl_uniform_matrix_4fv(lua_State *L) +{ + lua_Integer location; + bool transpose; + void *ptr; + hs_parse_args(L, hs_int(location), hs_bool(transpose), hs_user(ptr)); + + float *value = ptr; + glUniformMatrix4fv(location, 1, transpose, value); + return 0; +} diff --git a/src/gl/texture.c b/src/gl/texture.c new file mode 100644 index 0000000..f9a65b3 --- /dev/null +++ b/src/gl/texture.c @@ -0,0 +1,116 @@ +#include "gl/glad/glad.h" +#include <GLFW/glfw3.h> +#include <lua.h> +#include <honeysuckle.h> +#include "util/util.h" + + +int gl_texture_create(lua_State *L); +int gl_texture_bind(lua_State *L); +int gl_texture_image_2d(lua_State *L); +int gl_texture_generate_mipmaps(lua_State *L); +int gl_texture_set_active(lua_State *L); +int gl_tex_parameter_i(lua_State *L); + + +void setup_texture(lua_State *L, int gl_index) +{ + int tbl = hs_create_table(L, + /* functions */ + hs_str_cfunc("GenTextures", gl_texture_create), + hs_str_cfunc("BindTexture", gl_texture_bind), + hs_str_cfunc("TexImage2D", gl_texture_image_2d), + hs_str_cfunc("GenerateMipmap", gl_texture_generate_mipmaps), + hs_str_cfunc("ActiveTexture", gl_texture_set_active), + hs_str_cfunc("TexParameteri", gl_tex_parameter_i), + + /******** enums ********/ + /* texture binding targets */ + hs_str_int("TEXTURE_2D", GL_TEXTURE_2D), + + /* texture data formats */ + hs_str_int("RGB", GL_RGB), + hs_str_int("RGBA", GL_RGBA), + + /* texture parameters */ + hs_str_int("TEXTURE_WRAP_S", GL_TEXTURE_WRAP_S), + hs_str_int("TEXTURE_WRAP_T", GL_TEXTURE_WRAP_T), + hs_str_int("TEXTURE_MIN_FILTER", GL_TEXTURE_MIN_FILTER), + hs_str_int("TEXTURE_MAG_FILTER", GL_TEXTURE_MAG_FILTER), + + /* wrapping types */ + hs_str_int("REPEAT", GL_REPEAT), + + /* filter types */ + hs_str_int("NEAREST", GL_NEAREST), + hs_str_int("LINEAR", GL_LINEAR), + ); + + append_table(L, gl_index, tbl); + lua_pop(L, 1); +} + + +int gl_texture_create(lua_State *L) +{ + unsigned int texture; + glGenTextures(1, &texture); + lua_pushinteger(L, texture); + return 1; +} + + +int gl_texture_bind(lua_State *L) +{ + lua_Integer target, texture; + hs_parse_args(L, hs_int(target), hs_int(texture)); + glBindTexture(target, texture); + return 0; +} + + +int gl_texture_image_2d(lua_State *L) +{ + lua_Integer target, mipmap_level, + internal_format, + width, height, + format, type; + void *data; + hs_parse_args(L, + hs_int(target), hs_int(mipmap_level), + hs_int(internal_format), + hs_int(width), hs_int(height), + hs_int(format), hs_int(type), + hs_light(data) + ); + + glTexImage2D(target, mipmap_level, internal_format, width, height, 0, format, type, data); + return 0; +} + + +int gl_texture_generate_mipmaps(lua_State *L) +{ + lua_Integer target; + hs_parse_args(L, hs_int(target)); + glGenerateMipmap(target); + return 0; +} + + +int gl_texture_set_active(lua_State *L) +{ + lua_Integer unit; + hs_parse_args(L, hs_int(unit)); + glActiveTexture(GL_TEXTURE0 + unit); + return 0; +} + + +int gl_tex_parameter_i(lua_State *L) +{ + lua_Integer target, pname, param; + hs_parse_args(L, hs_int(target), hs_int(pname), hs_int(param)); + glTexParameteri(target, pname, param); + return 0; +} diff --git a/src/gl/window.c b/src/gl/window.c index e16b330..fd13022 100644 --- a/src/gl/window.c +++ b/src/gl/window.c @@ -1,104 +1,175 @@ +#include <stdlib.h> #include "gl/glad/glad.h" #include <GLFW/glfw3.h> #include <lua.h> #include <honeysuckle.h> -/* build a table of all possible window hints */ -void create_glfw_window_hints_table(lua_State *L) +struct window_data { + lua_State *L; + int framebuffer_size_callback; +}; + +struct window_data * create_window_data(lua_State *L) { - /* hint keys */ - hs_create_table(L, - /* window hints */ - hs_str_int("resizable", GLFW_RESIZABLE), - hs_str_int("visible", GLFW_VISIBLE), - hs_str_int("decorated", GLFW_DECORATED), - hs_str_int("focused", GLFW_FOCUSED), - hs_str_int("autoIconify", GLFW_AUTO_ICONIFY), - hs_str_int("floating", GLFW_FLOATING), - hs_str_int("maximized", GLFW_MAXIMIZED), - hs_str_int("centerCursor", GLFW_CENTER_CURSOR), - hs_str_int("transparentFramebuffer", GLFW_TRANSPARENT_FRAMEBUFFER), - hs_str_int("focusOnShow", GLFW_FOCUS_ON_SHOW), - hs_str_int("scaleToMonitor", GLFW_SCALE_TO_MONITOR), - - /* framebuffer hints */ - hs_str_int("redBits", GLFW_RED_BITS), - hs_str_int("greenBits", GLFW_GREEN_BITS), - hs_str_int("blueBits", GLFW_BLUE_BITS), - hs_str_int("alphaBits", GLFW_ALPHA_BITS), - hs_str_int("depthBits", GLFW_DEPTH_BITS), - hs_str_int("stereoscopic", GLFW_STEREO), - hs_str_int("samples", GLFW_SAMPLES), - hs_str_int("srgbCapable", GLFW_SRGB_CAPABLE), - hs_str_int("doubleBuffer", GLFW_DOUBLEBUFFER), - - /* monitor & context hints */ - hs_str_int("refreshRate", GLFW_REFRESH_RATE), - hs_str_int("clientApi", GLFW_CLIENT_API), - hs_str_int("contextCreationApi", GLFW_CONTEXT_CREATION_API), + struct window_data *wdata = malloc(sizeof(struct window_data)); + if (wdata == NULL) + return NULL; + wdata->L = L; + wdata->framebuffer_size_callback = LUA_NOREF; + return wdata; +} + +int window_create(lua_State *L); +int window_destroy(lua_State *L); +int window_make_context_current(lua_State *L); +int window_set_hint(lua_State *L); +int window_should_close(lua_State *L); +int window_poll_events(lua_State *L); +int window_swap_buffers(lua_State *L); +int window_set_framebuffer_size_callback(lua_State *L); +int window_get_time(lua_State *L); + + + +void setup_window(lua_State *L, int honey_index) +{ + int hint_types = hs_create_table(L, hs_str_int("contextVersionMajor", GLFW_CONTEXT_VERSION_MAJOR), hs_str_int("contextVersionMinor", GLFW_CONTEXT_VERSION_MINOR), - hs_str_int("forwardCompatible", GLFW_OPENGL_FORWARD_COMPAT), - hs_str_int("debugContext", GLFW_OPENGL_DEBUG_CONTEXT), - hs_str_int("profile", GLFW_OPENGL_PROFILE), - hs_str_int("contextRobustness", GLFW_CONTEXT_ROBUSTNESS), - hs_str_int("contextReleaseBehavior", GLFW_CONTEXT_RELEASE_BEHAVIOR), - hs_str_int("noError", GLFW_CONTEXT_NO_ERROR) + hs_str_int("openGlProfile", GLFW_OPENGL_PROFILE), + ); + + int profile_types = hs_create_table(L, + hs_str_int("openGlCoreProfile", GLFW_OPENGL_CORE_PROFILE), ); - /* special hint values */ hs_create_table(L, - hs_str_int("dontCare", GLFW_DONT_CARE), - - /* client api */ - hs_str_int("glApi", GLFW_OPENGL_API), - hs_str_int("glesApi", GLFW_OPENGL_ES_API), - hs_str_int("noApi", GLFW_NO_API), - - /* context api */ - hs_str_int("nativeApi", GLFW_NATIVE_CONTEXT_API), - hs_str_int("eglApi", GLFW_EGL_CONTEXT_API), - hs_str_int("osMesaApi", GLFW_OSMESA_CONTEXT_API), - - /* robustness */ - hs_str_int("noRobustness", GLFW_NO_ROBUSTNESS), - hs_str_int("noResetNotification", GLFW_NO_RESET_NOTIFICATION), - hs_str_int("loseContextOnReset", GLFW_LOSE_CONTEXT_ON_RESET), - - /* context release */ - hs_str_int("anyBehavior", GLFW_ANY_RELEASE_BEHAVIOR), - hs_str_int("flush", GLFW_RELEASE_BEHAVIOR_FLUSH), - hs_str_int("none", GLFW_RELEASE_BEHAVIOR_NONE), - - /* profile */ - hs_str_int("anyProfile", GLFW_OPENGL_ANY_PROFILE), - hs_str_int("compatabilityProfile", GLFW_OPENGL_COMPAT_PROFILE), - hs_str_int("coreProfile", GLFW_OPENGL_CORE_PROFILE) + hs_str_cfunc("create", window_create), + hs_str_cfunc("destroy", window_destroy), + hs_str_cfunc("makeContextCurrent", window_make_context_current), + hs_str_cfunc("setHint", window_set_hint), + hs_str_cfunc("shouldClose", window_should_close), + hs_str_cfunc("pollEvents", window_poll_events), + hs_str_cfunc("swapBuffers", window_swap_buffers), + hs_str_cfunc("setFramebufferSizeCallback", window_set_framebuffer_size_callback), + hs_str_cfunc("getTime", window_get_time), + + hs_str_tbl("hintType", hint_types), + hs_str_tbl("profileType", profile_types), ); + lua_setfield(L, honey_index, "window"); } -int gl_init(lua_State *L) +static void framebuffer_size_callback_(GLFWwindow *win, int width, int height) { - if (glfwInit() != GLFW_TRUE) { - hs_throw_error(L, "failed to initialize GLFW"); + struct window_data *wdata = glfwGetWindowUserPointer(win); + if (wdata->framebuffer_size_callback != LUA_NOREF) { + hs_rload(wdata->L, wdata->framebuffer_size_callback); + lua_pushlightuserdata(wdata->L, win); + lua_pushinteger(wdata->L, width); + lua_pushinteger(wdata->L, height); + hs_call(wdata->L, 3, 0); } - return 0; } +int window_create(lua_State *L) +{ + lua_Integer width, height; + char *title; + hs_parse_args(L, hs_int(width), hs_int(height), hs_str(title)); + + GLFWwindow *win = glfwCreateWindow(width, height, title, NULL, NULL); + if (win == NULL) + hs_throw_error(L, "failed to create window"); + + struct window_data *wdata = create_window_data(L); + glfwSetWindowUserPointer(win, wdata); -lua_Integer tointeger(lua_State *L, int index) + glfwSetFramebufferSizeCallback(win, framebuffer_size_callback_); + + lua_pushlightuserdata(L, win); + return 1; +} + + +int window_destroy(lua_State *L) { - if (lua_isboolean(L, index)) { - return lua_toboolean(L, index); - } - else if (lua_isnumber(L, index)) { - return lua_tointeger(L, index); - } - else { - hs_throw_error(L, - "expected boolean or number; got %s instead", - lua_typename(L, lua_type(L, index)) - ); + void *ptr; + hs_parse_args(L, hs_light(ptr)); + GLFWwindow *win = ptr; + void *wdata = glfwGetWindowUserPointer(win); + if (wdata != NULL) { + free(wdata); + glfwSetWindowUserPointer(win, NULL); } + glfwDestroyWindow(win); + return 0; +} + + +int window_make_context_current(lua_State *L) +{ + void *ptr; + hs_parse_args(L, hs_light(ptr)); + GLFWwindow *win = ptr; + glfwMakeContextCurrent(win); + return 0; +} + + +int window_set_hint(lua_State *L) +{ + lua_Integer hint, value; + hs_parse_args(L, hs_int(hint), hs_int(value)); + glfwWindowHint(hint, value); + return 0; +} + + +int window_should_close(lua_State *L) +{ + void *ptr; + hs_parse_args(L, hs_light(ptr)); + GLFWwindow *win = ptr; + lua_pushboolean(L, glfwWindowShouldClose(win)); + return 1; +} + + +int window_poll_events(lua_State *L) +{ + glfwPollEvents(); + return 0; +} + + +int window_swap_buffers(lua_State *L) +{ + void *ptr; + hs_parse_args(L, hs_light(ptr)); + GLFWwindow *win = ptr; + glfwSwapBuffers(win); + return 0; +} + + +int window_set_framebuffer_size_callback(lua_State *L) +{ + void *ptr; + int func; + hs_parse_args(L, hs_light(ptr), hs_func(func)); + GLFWwindow *win = ptr; + struct window_data *wdata = glfwGetWindowUserPointer(win); + + lua_pushvalue(L, func); + wdata->framebuffer_size_callback = hs_rstore(L); + return 0; +} + + +int window_get_time(lua_State *L) +{ + lua_pushnumber(L, glfwGetTime()); + return 1; } diff --git a/src/gl/window.test.c b/src/gl/window.test.c index 6b8e091..505c876 100644 --- a/src/gl/window.test.c +++ b/src/gl/window.test.c @@ -1,436 +1,24 @@ -#include <string.h> +#include <stdlib.h> #include <lua.h> -#include <lauxlib.h> #include <honeysuckle.h> #include "test/honey-test.h" -int mock_glfwInit(); -int mock_hs_throw_error(lua_State *L, const char *format_string, ...); -#define glfwInit mock_glfwInit -#define hs_throw_error mock_hs_throw_error -#include "gl/window.c" -#undef glfwInit -#undef hs_throw_error +#include "window.c" -lily_mock_t *mock_glfwInit_data = NULL; -int mock_glfwInit() -{ - lily_mock_call(mock_glfwInit_data, NULL); - - int result; - mock_dequeue(mock_glfwInit, int, &result); - return result; -} - -lily_mock_t *mock_hs_throw_error_data = NULL; -int mock_hs_throw_error(lua_State *L, const char *format_string, ...) -{ - /* to avoid basically just re-implementing printf parsing here, - i am limiting this function to be able to receive strings only */ - - /* count format specifiers */ - char *ptr = strchr(format_string, '%'); - int n_args = 0; - while (ptr != NULL) { - n_args += 1; - ptr = strchr(ptr+1, '%'); - } - - /* store arguments */ - struct lily_mock_arg_t args[] = { - { sizeof(const char*), &format_string }, - { sizeof(int), &n_args }, - }; - lily_mock_call(mock_hs_throw_error_data, args); - - /* store format arguments */ - va_list vl; - va_start(vl, format_string); - for (int i=0; i<n_args; i++) { - char *str = va_arg(vl, char*); - mock_enqueue(mock_hs_throw_error, char*, str); - } -} - - -/* ~~~~~~~~ TESTS ~~~~~~~~ */ -void gl_init_succeeds(); -void gl_init_fail_glfwInit(); -void glfw_window_hints_table(); -void tointeger_parses_bool(); -void tointeger_parses_int(); -void tointeger_fails_other(); - -void suite_window() -{ - lily_run_test(gl_init_succeeds); - lily_run_test(gl_init_fail_glfwInit); - lily_run_test(glfw_window_hints_table); - lily_run_test(tointeger_parses_bool); - lily_run_test(tointeger_parses_int); - lily_run_test(tointeger_fails_other); - - CLEAN_MOCK(mock_glfwInit); - CLEAN_MOCK(mock_hs_throw_error); -} - - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - - -void gl_init_succeeds() -{ - USE_MOCK(mock_glfwInit); - USE_MOCK(mock_hs_throw_error); - - /* queue success */ - mock_enqueue(mock_glfwInit, int, GLFW_TRUE); - gl_init(NULL); - - lily_assert_int_equal(mock_glfwInit_data->n_calls, 1); - lily_assert_int_equal(mock_hs_throw_error_data->n_calls, 0); -} - - -void gl_init_fail_glfwInit() -{ - USE_MOCK(mock_glfwInit); - USE_MOCK(mock_hs_throw_error); - - /* queue failure */ - mock_enqueue(mock_glfwInit, int, GLFW_FALSE); - gl_init(NULL); - - lily_assert_int_equal(mock_glfwInit_data->n_calls, 1); - lily_assert_int_equal(mock_hs_throw_error_data->n_calls, 1); - - const char *fmt; int argc; - struct lily_mock_arg_t args[] = { - { sizeof(const char*), &fmt }, - { sizeof(int), &argc }, - }; - lily_get_call(mock_hs_throw_error_data, args, 0); - - lily_assert_string_equal((char*) fmt, "failed to initialize GLFW"); -} - - -int get_int(lua_State *L, int table_index, const char *key) -{ - lua_getfield(L, table_index, key); - lily_assert_msg(lua_isnumber(L, -1), LILY_LOCATION, "key %s is not a number", key); - int n = lua_tointeger(L, -1); - lua_pop(L, 1); - return n; -} - -#define CHECK_VALUE(str, num) \ - do { \ - int value = get_int(L, 1, str); \ - lily_assert_int_equal(value, num); \ - } while(0) - -void glfw_window_hints_table() +void create_window_data_works() { lua_State *L = luaL_newstate(); + struct window_data *wdata = create_window_data(L); - lily_assert_int_equal(lua_gettop(L), 0); - create_glfw_window_hints_table(L); - lily_assert_int_equal(lua_gettop(L), 2); - lily_assert_true(lua_istable(L, 1)); - - /* window hints */ - lily_assert_int_equal( - get_int(L, 1, "resizable"), - GLFW_RESIZABLE - ); - - lily_assert_int_equal( - get_int(L, 1, "visible"), - GLFW_VISIBLE - ); - - lily_assert_int_equal( - get_int(L, 1, "decorated"), - GLFW_DECORATED - ); - - lily_assert_int_equal( - get_int(L, 1, "focused"), - GLFW_FOCUSED - ); - - lily_assert_int_equal( - get_int(L, 1, "autoIconify"), - GLFW_AUTO_ICONIFY - ); - - lily_assert_int_equal( - get_int(L, 1, "floating"), - GLFW_FLOATING - ); - - lily_assert_int_equal( - get_int(L, 1, "maximized"), - GLFW_MAXIMIZED - ); - - lily_assert_int_equal( - get_int(L, 1, "centerCursor"), - GLFW_CENTER_CURSOR - ); - - lily_assert_int_equal( - get_int(L, 1, "transparentFramebuffer"), - GLFW_TRANSPARENT_FRAMEBUFFER - ); - - lily_assert_int_equal( - get_int(L, 1, "focusOnShow"), - GLFW_FOCUS_ON_SHOW - ); - - lily_assert_int_equal( - get_int(L, 1, "scaleToMonitor"), - GLFW_SCALE_TO_MONITOR - ); - - - /* framebuffer hints */ - /* (don't expose accumulation or auxiliary buffer hints) */ - lily_assert_int_equal( - get_int(L, 1, "redBits"), - GLFW_RED_BITS - ); - - lily_assert_int_equal( - get_int(L, 1, "greenBits"), - GLFW_GREEN_BITS - ); - - lily_assert_int_equal( - get_int(L, 1, "blueBits"), - GLFW_BLUE_BITS - ); - - lily_assert_int_equal( - get_int(L, 1, "alphaBits"), - GLFW_ALPHA_BITS - ); - - lily_assert_int_equal( - get_int(L, 1, "depthBits"), - GLFW_DEPTH_BITS - ); - - lily_assert_int_equal( - get_int(L, 1, "stereoscopic"), - GLFW_STEREO - ); - - lily_assert_int_equal( - get_int(L, 1, "samples"), - GLFW_SAMPLES - ); - - lily_assert_int_equal( - get_int(L, 1, "srgbCapable"), - GLFW_SRGB_CAPABLE - ); - - lily_assert_int_equal( - get_int(L, 1, "doubleBuffer"), - GLFW_DOUBLEBUFFER - ); - - - /* monitor & context hints */ - lily_assert_int_equal( - get_int(L, 1, "refreshRate"), - GLFW_REFRESH_RATE - ); - - lily_assert_int_equal( - get_int(L, 1, "clientApi"), - GLFW_CLIENT_API - ); - - lily_assert_int_equal( - get_int(L, 1, "contextCreationApi"), - GLFW_CONTEXT_CREATION_API - ); - - lily_assert_int_equal( - get_int(L, 1, "contextVersionMajor"), - GLFW_CONTEXT_VERSION_MAJOR - ); - - lily_assert_int_equal( - get_int(L, 1, "contextVersionMinor"), - GLFW_CONTEXT_VERSION_MINOR - ); - - lily_assert_int_equal( - get_int(L, 1, "forwardCompatible"), - GLFW_OPENGL_FORWARD_COMPAT - ); - - lily_assert_int_equal( - get_int(L, 1, "debugContext"), - GLFW_OPENGL_DEBUG_CONTEXT - ); - - lily_assert_int_equal( - get_int(L, 1, "profile"), - GLFW_OPENGL_PROFILE - ); - - lily_assert_int_equal( - get_int(L, 1, "contextRobustness"), - GLFW_CONTEXT_ROBUSTNESS - ); - - lily_assert_int_equal( - get_int(L, 1, "contextReleaseBehavior"), - GLFW_CONTEXT_RELEASE_BEHAVIOR - ); - - lily_assert_int_equal( - get_int(L, 1, "noError"), - GLFW_CONTEXT_NO_ERROR - ); - - - /* special hint values */ - - lily_assert_int_equal( - get_int(L, 2, "dontCare"), - GLFW_DONT_CARE - ); - - /* client api */ - lily_assert_int_equal( - get_int(L, 2, "glApi"), - GLFW_OPENGL_API - ); - - lily_assert_int_equal( - get_int(L, 2, "glesApi"), - GLFW_OPENGL_ES_API - ); - - lily_assert_int_equal( - get_int(L, 2, "noApi"), - GLFW_NO_API - ); - - /* context api */ - lily_assert_int_equal( - get_int(L, 2, "nativeApi"), - GLFW_NATIVE_CONTEXT_API - ); - - lily_assert_int_equal( - get_int(L, 2, "eglApi"), - GLFW_EGL_CONTEXT_API - ); - - lily_assert_int_equal( - get_int(L, 2, "osMesaApi"), - GLFW_OSMESA_CONTEXT_API - ); - - /* robustness */ - lily_assert_int_equal( - get_int(L, 2, "noRobustness"), - GLFW_NO_ROBUSTNESS - ); - - lily_assert_int_equal( - get_int(L, 2, "noResetNotification"), - GLFW_NO_RESET_NOTIFICATION - ); - - lily_assert_int_equal( - get_int(L, 2, "loseContextOnReset"), - GLFW_LOSE_CONTEXT_ON_RESET - ); - - /* release */ - lily_assert_int_equal( - get_int(L, 2, "anyBehavior"), - GLFW_ANY_RELEASE_BEHAVIOR - ); - - lily_assert_int_equal( - get_int(L, 2, "flush"), - GLFW_RELEASE_BEHAVIOR_FLUSH - ); - - lily_assert_int_equal( - get_int(L, 2, "none"), - GLFW_RELEASE_BEHAVIOR_NONE - ); - - /* profile */ - lily_assert_int_equal( - get_int(L, 2, "anyProfile"), - GLFW_OPENGL_ANY_PROFILE - ); - - lily_assert_int_equal( - get_int(L, 2, "compatabilityProfile"), - GLFW_OPENGL_COMPAT_PROFILE - ); - - lily_assert_int_equal( - get_int(L, 2, "coreProfile"), - GLFW_OPENGL_CORE_PROFILE - ); - - lua_close(L); -} - - -void tointeger_parses_bool() -{ - USE_MOCK(mock_hs_throw_error); - lua_State *L = luaL_newstate(); - - lua_pushboolean(L, 0); - lily_assert_false(lua_toboolean(L, -1)); - lily_assert_int_equal(tointeger(L, -1), 0); - - lua_pushboolean(L, 1); - lily_assert_true(lua_toboolean(L, -1)); - lily_assert_int_equal(tointeger(L, -1), 1); - + lily_assert_ptr_equal(L, wdata->L); + lily_assert_int_equal(wdata->framebuffer_size_callback, LUA_NOREF); lua_close(L); + free(wdata); } -void tointeger_parses_int() -{ - USE_MOCK(mock_hs_throw_error); - lua_State *L = luaL_newstate(); - - lua_pushinteger(L, 234); - lua_pushinteger(L, 55555); - - lily_assert_int_equal(tointeger(L, -2), 234); - lily_assert_int_equal(tointeger(L, -1), 55555); - - lua_close(L); -} - - -void tointeger_fails_other() +void suite_window() { - USE_MOCK(mock_hs_throw_error); - lua_State *L = luaL_newstate(); - - lua_pushstring(L, "hey there babe"); - tointeger(L, -1); - lily_assert_int_equal(mock_hs_throw_error_data->n_calls, 1); + lily_run_test(create_window_data_works); } |