From 41bdade88cca8a28048b94bdff53d033d9be477a Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 15 Mar 2024 03:29:22 +0000 Subject: [PATCH] library: 3D vertex manipulation functions --- src/library/gl.c | 55 +++++++++++++++++++++++++++++++++++++++- src/library/gl.h | 8 ++++++ src/library/plugin.c | 43 ++++++++++++++++++++++++++++++- src/library/plugin.h | 16 ++++++++++++ src/library/plugin_api.h | 15 +++++++++++ 5 files changed, 135 insertions(+), 2 deletions(-) diff --git a/src/library/gl.c b/src/library/gl.c index 7cf458c..fbbf715 100644 --- a/src/library/gl.c +++ b/src/library/gl.c @@ -1246,13 +1246,16 @@ void _bolt_gl_onDrawElements(uint32_t mode, unsigned int count, uint32_t type, c int draw_tex; gl.GetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &draw_tex); if (draw_tex == c->target_3d_tex) { - int atlas, settings_atlas; + int atlas, settings_atlas, ubo_binding, ubo_view_index, ubo_viewport_index; float atlas_meta[4]; gl.GetUniformiv(c->bound_program->id, c->bound_program->loc_uTextureAtlas, &atlas); gl.GetUniformiv(c->bound_program->id, c->bound_program->loc_uTextureAtlasSettings, &settings_atlas); gl.GetUniformfv(c->bound_program->id, c->bound_program->loc_uAtlasMeta, atlas_meta); struct GLTexture2D* tex = c->texture_units[atlas]; struct GLTexture2D* tex_settings = c->texture_units[settings_atlas]; + gl.GetActiveUniformBlockiv(c->bound_program->id, c->bound_program->block_index_ViewTransforms, GL_UNIFORM_BLOCK_BINDING, &ubo_binding); + gl.GetIntegeri_v(GL_UNIFORM_BUFFER_BINDING, ubo_binding, &ubo_view_index); + const float* view_proj_matrix = (float*)(_bolt_context_get_buffer(c, ubo_view_index)->data + c->bound_program->offset_uViewProjMatrix); struct GLPluginDrawElementsVertex3DUserData vertex_userdata; vertex_userdata.c = c; @@ -1268,6 +1271,10 @@ void _bolt_gl_onDrawElements(uint32_t mode, unsigned int count, uint32_t type, c struct GLPluginTextureUserData tex_userdata; tex_userdata.tex = tex; + struct GLPlugin3DMatrixUserData matrix_userdata; + gl.GetUniformfv(c->bound_program->id, c->bound_program->loc_uModelMatrix, matrix_userdata.model_matrix); + memcpy(matrix_userdata.viewproj_matrix, view_proj_matrix, 16 * sizeof(float)); + struct Render3D render; render.vertex_count = count; render.vertex_functions.userdata = &vertex_userdata; @@ -1281,6 +1288,10 @@ void _bolt_gl_onDrawElements(uint32_t mode, unsigned int count, uint32_t type, c render.texture_functions.size = _bolt_gl_plugin_texture_size; render.texture_functions.compare = _bolt_gl_plugin_texture_compare; render.texture_functions.data = _bolt_gl_plugin_texture_data; + render.matrix_functions.userdata = &matrix_userdata; + render.matrix_functions.to_world_space = _bolt_gl_plugin_matrix3d_toworldspace; + render.matrix_functions.to_screen_space = _bolt_gl_plugin_matrix3d_toscreenspace; + render.matrix_functions.world_pos = _bolt_gl_plugin_matrix3d_worldpos; _bolt_plugin_handle_3d(&render); } @@ -1473,6 +1484,48 @@ void _bolt_gl_plugin_drawelements_vertex3d_colour(size_t index, void* userdata, out[3] = (double)colour[0]; } +void _bolt_gl_plugin_matrix3d_toworldspace(int x, int y, int z, void* userdata, double* out) { + const struct GLPlugin3DMatrixUserData* data = userdata; + const double dx = (double)x; + const double dy = (double)y; + const double dz = (double)z; + const float* mmx = data->model_matrix; + const double outx = (dx * (double)mmx[0]) + (dy * mmx[4]) + (dz * mmx[8]) + mmx[12]; + const double outy = (dx * (double)mmx[1]) + (dy * mmx[5]) + (dz * mmx[9]) + mmx[13]; + const double outz = (dx * (double)mmx[2]) + (dy * mmx[6]) + (dz * mmx[10]) + mmx[14]; + const double homogenous = (dx * (double)mmx[3]) + (dy * mmx[7]) + (dz * mmx[11]) + mmx[15]; + out[0] = outx / homogenous; + out[1] = outy / homogenous; + out[2] = outz / homogenous; +} + +void _bolt_gl_plugin_matrix3d_toscreenspace(int x, int y, int z, void* userdata, double* out) { + const struct GLContext* c = _bolt_context(); + struct GLPlugin3DMatrixUserData* data = userdata; + const double dx = (double)x; + const double dy = (double)y; + const double dz = (double)z; + const float* mmx = data->model_matrix; + const float* vpmx = data->viewproj_matrix; + const double mx = (dx * (double)mmx[0]) + (dy * (double)mmx[4]) + (dz * (double)mmx[8]) + (double)mmx[12]; + const double my = (dx * (double)mmx[1]) + (dy * (double)mmx[5]) + (dz * (double)mmx[9]) + (double)mmx[13]; + const double mz = (dx * (double)mmx[2]) + (dy * (double)mmx[6]) + (dz * (double)mmx[10]) + (double)mmx[14]; + const double mh = (dx * (double)mmx[3]) + (dy * (double)mmx[7]) + (dz * (double)mmx[11]) + (double)mmx[15]; + const double outx = (mx * (double)vpmx[0]) + (my * (double)vpmx[4]) + (mz * (double)vpmx[8]) + (mh * (double)vpmx[12]); + const double outy = (mx * (double)vpmx[1]) + (my * (double)vpmx[5]) + (mz * (double)vpmx[9]) + (mh * (double)vpmx[13]); + const double homogenous = (mx * (double)vpmx[3]) + (my * (double)vpmx[7]) + (mz * (double)vpmx[11]) + (mh * (double)vpmx[15]); + out[0] = (((outx / homogenous) + 1.0) * c->game_view_w / 2.0) + (double)c->game_view_x; + out[1] = (((-outy / homogenous) + 1.0) * c->game_view_h / 2.0) + (double)c->game_view_y; +} + +void _bolt_gl_plugin_matrix3d_worldpos(void* userdata, double* out) { + struct GLPlugin3DMatrixUserData* data = userdata; + const float* mmx = data->model_matrix; + out[0] = (double)data->model_matrix[12]; + out[1] = (double)data->model_matrix[13]; + out[2] = (double)data->model_matrix[14]; +} + size_t _bolt_gl_plugin_texture_id(void* userdata) { const struct GLPluginTextureUserData* data = userdata; return data->tex->id; diff --git a/src/library/gl.h b/src/library/gl.h index 6fd627d..2e00ff7 100644 --- a/src/library/gl.h +++ b/src/library/gl.h @@ -310,6 +310,14 @@ void _bolt_gl_plugin_drawelements_vertex3d_meta_xywh(size_t meta, void* userdata void _bolt_gl_plugin_drawelements_vertex3d_uv(size_t index, void* userdata, double* out); void _bolt_gl_plugin_drawelements_vertex3d_colour(size_t index, void* userdata, double* out); +struct GLPlugin3DMatrixUserData { + float model_matrix[16]; + float viewproj_matrix[16]; +}; +void _bolt_gl_plugin_matrix3d_toworldspace(int x, int y, int z, void* userdata, double* out); +void _bolt_gl_plugin_matrix3d_toscreenspace(int x, int y, int z, void* userdata, double* out); +void _bolt_gl_plugin_matrix3d_worldpos(void* userdata, double* out); + struct GLPluginTextureUserData { struct GLTexture2D* tex; }; diff --git a/src/library/plugin.c b/src/library/plugin.c index bef7591..6b3ec26 100644 --- a/src/library/plugin.c +++ b/src/library/plugin.c @@ -131,7 +131,7 @@ void _bolt_plugin_init(void (*_surface_init)(struct SurfaceFunctions*, unsigned lua_pushstring(state, RENDER3D_META_REGISTRYNAME); lua_newtable(state); lua_pushstring(state, "__index"); - lua_createtable(state, 0, 10); + lua_createtable(state, 0, 13); API_ADD_SUB(vertexcount, render3d) API_ADD_SUB(vertexxyz, render3d) API_ADD_SUB(vertexmeta, render3d) @@ -142,6 +142,9 @@ void _bolt_plugin_init(void (*_surface_init)(struct SurfaceFunctions*, unsigned API_ADD_SUB(texturesize, render3d) API_ADD_SUB(texturecompare, render3d) API_ADD_SUB(texturedata, render3d) + API_ADD_SUB(toworldspace, render3d) + API_ADD_SUB(toscreenspace, render3d) + API_ADD_SUB(worldposition, render3d) API_ADD_SUB_ALIAS(vertexcolour, vertexcolor, render3d) lua_settable(state, -3); lua_settable(state, LUA_REGISTRYINDEX); @@ -628,3 +631,41 @@ static int api_render3d_texturedata(lua_State* state) { lua_pushlstring(state, (const char*)ret, len); return 1; } + +static int api_render3d_toworldspace(lua_State* state) { + _bolt_check_argc(state, 4, "render3d_toworldspace"); + struct Render3D* render = lua_touserdata(state, 1); + const int x = lua_tointeger(state, 2); + const int y = lua_tointeger(state, 3); + const int z = lua_tointeger(state, 4); + double out[3]; + render->matrix_functions.to_world_space(x, y, z, render->matrix_functions.userdata, out); + lua_pushnumber(state, out[0]); + lua_pushnumber(state, out[1]); + lua_pushnumber(state, out[2]); + return 3; +} + +static int api_render3d_toscreenspace(lua_State* state) { + _bolt_check_argc(state, 4, "render3d_toscreenspace"); + struct Render3D* render = lua_touserdata(state, 1); + const int x = lua_tointeger(state, 2); + const int y = lua_tointeger(state, 3); + const int z = lua_tointeger(state, 4); + double out[2]; + render->matrix_functions.to_screen_space(x, y, z, render->matrix_functions.userdata, out); + lua_pushnumber(state, out[0]); + lua_pushnumber(state, out[1]); + return 2; +} + +static int api_render3d_worldposition(lua_State* state) { + _bolt_check_argc(state, 1, "render3d_worldposition"); + struct Render3D* render = lua_touserdata(state, 1); + double out[3]; + render->matrix_functions.world_pos(render->matrix_functions.userdata, out); + lua_pushnumber(state, out[0]); + lua_pushnumber(state, out[1]); + lua_pushnumber(state, out[2]); + return 3; +} diff --git a/src/library/plugin.h b/src/library/plugin.h index 3d27696..015a896 100644 --- a/src/library/plugin.h +++ b/src/library/plugin.h @@ -80,6 +80,21 @@ struct TextureFunctions { uint8_t* (*data)(void* userdata, size_t x, size_t y); }; +/// Struct containing "vtable" callback information for 3D renders' transformation matrices. +struct Render3DMatrixFunctions { + /// Userdata which will be passed to the functions contained in this struct. + void* userdata; + + /// Converts an XYZ coordinate from model space to world space. + void (*to_world_space)(int x, int y, int z, void* userdata, double* out); + + /// Converts an XYZ coordinate from model space to screen space in pixels. + void (*to_screen_space)(int x, int y, int z, void* userdata, double* out); + + /// Gets the world-space coordinate equivalent to (0,0,0) in model space. + void (*world_pos)(void* userdata, double* out); +}; + /// Struct containing "vtable" callback information for surfaces. struct SurfaceFunctions { /// Userdata which will be passed to the functions contained in this struct. @@ -107,6 +122,7 @@ struct Render3D { uint32_t vertex_count; struct Vertex3DFunctions vertex_functions; struct TextureFunctions texture_functions; + struct Render3DMatrixFunctions matrix_functions; }; struct RenderMinimapEvent { diff --git a/src/library/plugin_api.h b/src/library/plugin_api.h index b1cf3cc..fe3409f 100644 --- a/src/library/plugin_api.h +++ b/src/library/plugin_api.h @@ -351,3 +351,18 @@ static int api_render3d_texturecompare(lua_State*); /// Encoding Lua strings is computationally expensive, and indexing the data one byte at a time is /// even more so. Unless you really need to do that, use `texturecompare()` instead. static int api_render3d_texturedata(lua_State*); + +/// [-4, +3, -] +/// Converts an XYZ coordinate from model space to world space using this render's model matrix. +static int api_render3d_toworldspace(lua_State*); + +/// [-4, +2, -] +/// Converts an XYZ coordinate from model space to screen space using this render's model, view, +/// and projection matrices. Output is in pixels. +static int api_render3d_toscreenspace(lua_State*); + +/// [-1, +3, -] +/// Returns the world coordinates this model is being rendered at. +/// +/// Equivalent to `render:toworldspace(0, 0, 0)` +static int api_render3d_worldposition(lua_State*);