diff --git a/src/library/gl.c b/src/library/gl.c index 727beae..0b0b9b8 100644 --- a/src/library/gl.c +++ b/src/library/gl.c @@ -1,6 +1,8 @@ #include "gl.h" +#include "plugin.h" #include "rwlock.h" +#include #include #include @@ -156,7 +158,7 @@ uint8_t _bolt_get_attr_binding(struct GLContext* c, const struct GLAttrBinding* return 1; } -uint8_t _bolt_get_attr_binding_int(struct GLContext* c, const struct GLAttrBinding* binding, size_t index, size_t num_out, uint32_t* out) { +uint8_t _bolt_get_attr_binding_int(struct GLContext* c, const struct GLAttrBinding* binding, size_t index, size_t num_out, int32_t* out) { struct GLArrayBuffer* buffer = binding->buffer; if (!buffer || !buffer->data) return 0; uintptr_t buf_offset = binding->offset + (binding->stride * index); @@ -165,22 +167,22 @@ uint8_t _bolt_get_attr_binding_int(struct GLContext* c, const struct GLAttrBindi if (!binding->normalise) { switch (binding->type) { case GL_UNSIGNED_BYTE: - for (size_t i = 0; i < num_out; i += 1) out[i] = (uint32_t)*(uint8_t*)(ptr + i); + for (size_t i = 0; i < num_out; i += 1) out[i] = (int32_t)*(uint8_t*)(ptr + i); break; case GL_UNSIGNED_SHORT: - for (size_t i = 0; i < num_out; i += 1) out[i] = (uint32_t)*(uint16_t*)(ptr + (i * 2)); + for (size_t i = 0; i < num_out; i += 1) out[i] = (int32_t)*(uint16_t*)(ptr + (i * 2)); break; case GL_UNSIGNED_INT: - for (size_t i = 0; i < num_out; i += 1) out[i] = (uint32_t)*(uint32_t*)(ptr + (i * 4)); + for (size_t i = 0; i < num_out; i += 1) out[i] = (int32_t)*(uint32_t*)(ptr + (i * 4)); break; case GL_BYTE: - for (size_t i = 0; i < num_out; i += 1) out[i] = (uint32_t)*(int8_t*)(ptr + i); + for (size_t i = 0; i < num_out; i += 1) out[i] = (int32_t)*(int8_t*)(ptr + i); break; case GL_SHORT: - for (size_t i = 0; i < num_out; i += 1) out[i] = (uint32_t)*(int16_t*)(ptr + (i * 2)); + for (size_t i = 0; i < num_out; i += 1) out[i] = (int32_t)*(int16_t*)(ptr + (i * 2)); break; case GL_INT: - for (size_t i = 0; i < num_out; i += 1) out[i] = (uint32_t)*(int32_t*)(ptr + (i * 4)); + for (size_t i = 0; i < num_out; i += 1) out[i] = (int32_t)*(int32_t*)(ptr + (i * 4)); break; default: return 0; @@ -314,10 +316,56 @@ struct GLVertexArray* _bolt_context_get_vao(struct GLContext* c, unsigned int in return ret; } - -void _bolt_mul_vec4_mat4(const float x, const float y, const float z, const float w, const float* mat4, float* out_vec4) { - out_vec4[0] = (mat4[0] * x) + (mat4[4] * y) + (mat4[8] * z) + (mat4[12] * w); - out_vec4[1] = (mat4[1] * x) + (mat4[5] * y) + (mat4[9] * z) + (mat4[13] * w); - out_vec4[2] = (mat4[2] * x) + (mat4[6] * y) + (mat4[10] * z) + (mat4[14] * w); - out_vec4[3] = (mat4[3] * x) + (mat4[7] * y) + (mat4[11] * z) + (mat4[15] * w); +void _bolt_gl_plugin_drawelements_xy(const struct RenderBatch2D* batch, size_t index, void* userdata, int32_t* out) { + struct GLPluginDrawElementsUserData* data = userdata; + if (!_bolt_get_attr_binding_int(data->c, data->position, index, 2, out)) { + float pos[2]; + _bolt_get_attr_binding(data->c, data->position, index, 2, pos); + out[0] = (int32_t)roundf(pos[0]); + out[1] = (int32_t)roundf(pos[1]); + } } + +void _bolt_gl_plugin_drawelements_atlas_xy(const struct RenderBatch2D* batch, size_t index, void* userdata, int32_t* out) { + struct GLPluginDrawElementsUserData* data = userdata; + float xy[2]; + _bolt_get_attr_binding(data->c, data->atlas_min, index, 2, xy); + // these are negative for some reason + out[0] = -(int32_t)roundf(xy[0] * data->atlas->width); + out[1] = -(int32_t)roundf(xy[1] * data->atlas->height); +} + +void _bolt_gl_plugin_drawelements_atlas_wh(const struct RenderBatch2D* batch, size_t index, void* userdata, int32_t* out) { + struct GLPluginDrawElementsUserData* data = userdata; + float wh[2]; + _bolt_get_attr_binding(data->c, data->atlas_size, index, 2, wh); + // these are negative for some reason + out[0] = -(int32_t)roundf(wh[0] * data->atlas->width); + out[1] = -(int32_t)roundf(wh[1] * data->atlas->height); +} + +void _bolt_gl_plugin_drawelements_uv(const struct RenderBatch2D* batch, size_t index, void* userdata, double* out) { + struct GLPluginDrawElementsUserData* data = userdata; + float uv[2]; + _bolt_get_attr_binding(data->c, data->tex_uv, index, 2, uv); + out[0] = (double)uv[0]; + out[1] = (double)uv[1]; +} + +void _bolt_gl_plugin_drawelements_colour(const struct RenderBatch2D* batch, size_t index, void* userdata, double* out) { + struct GLPluginDrawElementsUserData* data = userdata; + float colour[4]; + _bolt_get_attr_binding(data->c, data->colour, index, 4, colour); + // these are ABGR for some reason + out[0] = (double)colour[3]; + out[1] = (double)colour[2]; + out[2] = (double)colour[1]; + out[3] = (double)colour[0]; +} + +//void _bolt_mul_vec4_mat4(const float x, const float y, const float z, const float w, const float* mat4, float* out_vec4) { +// out_vec4[0] = (mat4[0] * x) + (mat4[4] * y) + (mat4[8] * z) + (mat4[12] * w); +// out_vec4[1] = (mat4[1] * x) + (mat4[5] * y) + (mat4[9] * z) + (mat4[13] * w); +// out_vec4[2] = (mat4[2] * x) + (mat4[6] * y) + (mat4[10] * z) + (mat4[14] * w); +// out_vec4[3] = (mat4[3] * x) + (mat4[7] * y) + (mat4[11] * z) + (mat4[15] * w); +//} diff --git a/src/library/gl.h b/src/library/gl.h index 6e048e5..70f6aea 100644 --- a/src/library/gl.h +++ b/src/library/gl.h @@ -7,6 +7,7 @@ #include "../../modules/hashmap/hashmap.h" #include "rwlock.h" struct hashmap; +struct RenderBatch2D; /* consts used from libgl */ #define GL_TEXTURE 5890 @@ -146,9 +147,26 @@ void _bolt_make_context_current(void*); void _bolt_destroy_context(void*); void _bolt_set_attr_binding(struct GLContext*, struct GLAttrBinding*, unsigned int, int, const void*, unsigned int, uint32_t, uint8_t); uint8_t _bolt_get_attr_binding(struct GLContext*, const struct GLAttrBinding*, size_t, size_t, float*); -uint8_t _bolt_get_attr_binding_int(struct GLContext*, const struct GLAttrBinding*, size_t, size_t, uint32_t*); +uint8_t _bolt_get_attr_binding_int(struct GLContext*, const struct GLAttrBinding*, size_t, size_t, int32_t*); uint32_t _bolt_binding_for_buffer(uint32_t); -void _bolt_mul_vec4_mat4(const float x, const float y, const float z, const float w, const float* mat4, float* out_vec4); + +/* plugin library interop stuff */ + +struct GLPluginDrawElementsUserData { + struct GLContext* c; + unsigned short* indices; + struct GLTexture2D* atlas; + struct GLAttrBinding* position; + struct GLAttrBinding* atlas_min; + struct GLAttrBinding* atlas_size; + struct GLAttrBinding* tex_uv; + struct GLAttrBinding* colour; +}; +void _bolt_gl_plugin_drawelements_xy(const struct RenderBatch2D*, size_t index, void* userdata, int32_t* out); +void _bolt_gl_plugin_drawelements_atlas_xy(const struct RenderBatch2D*, size_t index, void* userdata, int32_t* out); +void _bolt_gl_plugin_drawelements_atlas_wh(const struct RenderBatch2D*, size_t index, void* userdata, int32_t* out); +void _bolt_gl_plugin_drawelements_uv(const struct RenderBatch2D*, size_t index, void* userdata, double* out); +void _bolt_gl_plugin_drawelements_colour(const struct RenderBatch2D*, size_t index, void* userdata, double* out); #endif diff --git a/src/library/plugin.c b/src/library/plugin.c index 758c307..c1e26a6 100644 --- a/src/library/plugin.c +++ b/src/library/plugin.c @@ -45,9 +45,19 @@ void _bolt_plugin_init() { lua_pushstring(state, BATCH2D_META_REGISTRYNAME); lua_newtable(state); lua_pushstring(state, "__index"); - lua_newtable(state); + + lua_createtable(state, 0, 8); API_ADD_SUB(vertexcount, batch2d) API_ADD_SUB(verticesperimage, batch2d) + API_ADD_SUB(vertexxy, batch2d) + API_ADD_SUB(vertexatlasxy, batch2d) + API_ADD_SUB(vertexatlaswh, batch2d) + API_ADD_SUB(vertexuv, batch2d) + API_ADD_SUB(vertexcolour, batch2d) + lua_pushstring(state, "vertexcolor"); + lua_pushcfunction(state, api_batch2d_vertexcolour); + lua_settable(state, -3); + lua_settable(state, -3); lua_settable(state, LUA_REGISTRYINDEX); @@ -86,7 +96,12 @@ void _bolt_plugin_close() { uint64_t _bolt_plugin_add(const char* lua) { // load the user-provided string as a lua function, putting that function on the stack - luaL_loadstring(state, lua); + if (luaL_loadstring(state, lua)) { + const char* e = lua_tolstring(state, -1, 0); + printf("plugin load error: %s\n", e); + lua_pop(state, 1); + return 0; + } // create a new env for this plugin, and store it as registry["bolt"][i] where `i` is a unique ID const uint64_t plugin_id = next_plugin_id; @@ -276,3 +291,60 @@ static int api_batch2d_verticesperimage(lua_State* state) { lua_pushinteger(state, batch->vertices_per_icon); return 1; } + +static int api_batch2d_vertexxy(lua_State* state) { + _bolt_check_argc(state, 2, "batch2d_vertexxy"); + struct RenderBatch2D* batch = lua_touserdata(state, 1); + const lua_Integer index = lua_tointeger(state, 2); + int32_t xy[2]; + batch->functions.xy(batch, index - 1, batch->functions.userdata, xy); + lua_pushinteger(state, xy[0]); + lua_pushinteger(state, xy[1]); + return 2; +} + +static int api_batch2d_vertexatlasxy(lua_State* state) { + _bolt_check_argc(state, 2, "batch2d_vertexatlasxy"); + struct RenderBatch2D* batch = lua_touserdata(state, 1); + const lua_Integer index = lua_tointeger(state, 2); + int32_t xy[2]; + batch->functions.atlas_xy(batch, index - 1, batch->functions.userdata, xy); + lua_pushinteger(state, xy[0]); + lua_pushinteger(state, xy[1]); + return 2; +} + +static int api_batch2d_vertexatlaswh(lua_State* state) { + _bolt_check_argc(state, 2, "batch2d_vertexatlaswh"); + struct RenderBatch2D* batch = lua_touserdata(state, 1); + const lua_Integer index = lua_tointeger(state, 2); + int32_t wh[2]; + batch->functions.atlas_wh(batch, index - 1, batch->functions.userdata, wh); + lua_pushinteger(state, wh[0]); + lua_pushinteger(state, wh[1]); + return 2; +} + +static int api_batch2d_vertexuv(lua_State* state) { + _bolt_check_argc(state, 2, "batch2d_vertexuv"); + struct RenderBatch2D* batch = lua_touserdata(state, 1); + const lua_Integer index = lua_tointeger(state, 2); + double uv[2]; + batch->functions.uv(batch, index - 1, batch->functions.userdata, uv); + lua_pushnumber(state, uv[0]); + lua_pushnumber(state, uv[1]); + return 2; +} + +static int api_batch2d_vertexcolour(lua_State* state) { + _bolt_check_argc(state, 4, "batch2d_vertexcolour"); + struct RenderBatch2D* batch = lua_touserdata(state, 1); + const lua_Integer index = lua_tointeger(state, 2); + double colour[4]; + batch->functions.colour(batch, index - 1, batch->functions.userdata, colour); + lua_pushnumber(state, colour[0]); + lua_pushnumber(state, colour[1]); + lua_pushnumber(state, colour[2]); + lua_pushnumber(state, colour[3]); + return 4; +} diff --git a/src/library/plugin.h b/src/library/plugin.h index 21fc258..ed94f7d 100644 --- a/src/library/plugin.h +++ b/src/library/plugin.h @@ -1,15 +1,41 @@ #ifndef _BOLT_LIBRARY_PLUGIN_H_ #define _BOLT_LIBRARY_PLUGIN_H_ +#include #include +struct RenderBatch2D; + +/// Struct containing callbacks for general-purpose accessing of vertex info from any backend. +/// Functions will be called with four params: batch pointer, index, the specified userdata, +/// and an output pointer, which must be able to index the returned number of items. +struct Vertex2DFunctions { + /// Userdata which will be passed to the functions contained in this struct. + void* userdata; + + /// Returns the vertex X and Y, in screen coordinates. + void (*xy)(const struct RenderBatch2D*, size_t index, void* userdata, int32_t* out); + + /// Returns the X and Y of the texture image associated with this vertex, in pixel coordinates. + void (*atlas_xy)(const struct RenderBatch2D*, size_t index, void* userdata, int32_t* out); + + /// Returns the W and H of the texture image associated with this vertex, in pixel coordinates. + void (*atlas_wh)(const struct RenderBatch2D*, size_t index, void* userdata, int32_t* out); + + /// Returns the U and V of this vertex in pixel coordinates, normalised from 0.0 to 1.0 within + /// the sub-image specified by atlas xy and wh. + void (*uv)(const struct RenderBatch2D*, size_t index, void* userdata, double* out); + + /// Returns the RGBA colour of this vertex, each one normalised from 0.0 to 1.0. + void (*colour)(const struct RenderBatch2D*, size_t index, void* userdata, double* out); +}; + struct RenderBatch2D { - uint16_t* indices; - uint8_t* texture; - uint32_t tex_width; - uint32_t tex_height; + uint32_t atlas_width; + uint32_t atlas_height; uint32_t index_count; uint32_t vertices_per_icon; + struct Vertex2DFunctions functions; }; /// Init the plugin library. Call _bolt_plugin_close at the end of execution, and don't double-init. diff --git a/src/library/plugin_api.h b/src/library/plugin_api.h index 4a6039b..f21b22d 100644 --- a/src/library/plugin_api.h +++ b/src/library/plugin_api.h @@ -105,3 +105,31 @@ static int api_batch2d_vertexcount(lua_State*); /// to draw a solid rectangle, e.g. using GL_TRIANGLE_STRIP), then that will be indicated here, so /// it's recommended to use this function instead of hard-coding the number 6. static int api_batch2d_verticesperimage(lua_State*); + +/// [-2, +2, -] +/// Given an index of a vertex in a batch, returns its X and Y in screen coordinates. +static int api_batch2d_vertexxy(lua_State*); + +/// [-2, +2, -] +/// Given an index of a vertex in a batch, returns the X and Y of its associated image in the +/// batch's texture atlas, in pixel coordinates. +static int api_batch2d_vertexatlasxy(lua_State*); + +/// [-2, +2, -] +/// Given an index of a vertex in a batch, returns the width and height of its associated image in +/// the batch's texture atlas, in pixel coordinates. +static int api_batch2d_vertexatlaswh(lua_State*); + +/// [-2, +2, -] +/// Given an index of a vertex in a batch, returns the vertex's associated "UV" coordinates. +/// +/// The values will be floating-point numbers in the range 0.0 - 1.0. They are relative to the +/// position of the overall image in the texture atlas, queried by vertexatlasxy and vertexatlaswh. +static int api_batch2d_vertexuv(lua_State*); + +/// [-2, +4, -] +/// Given an index of a vertex in a batch, returns the red, green, blue and alpha values for that +/// vertex, in that order. All four values will be floating-point numbers in the range 0.0 - 1.0. +/// +/// Also aliased as "vertexcolor" to keep the Americans happy. +static int api_batch2d_vertexcolour(lua_State*);