diff --git a/src/library/gl.c b/src/library/gl.c index c811599..7cf458c 100644 --- a/src/library/gl.c +++ b/src/library/gl.c @@ -1237,6 +1237,7 @@ void _bolt_gl_onDrawElements(uint32_t mode, unsigned int count, uint32_t type, c batch.texture_functions.id = _bolt_gl_plugin_texture_id; batch.texture_functions.size = _bolt_gl_plugin_texture_size; batch.texture_functions.compare = _bolt_gl_plugin_texture_compare; + batch.texture_functions.data = _bolt_gl_plugin_texture_data; _bolt_plugin_handle_2d(&batch); } @@ -1279,6 +1280,7 @@ void _bolt_gl_onDrawElements(uint32_t mode, unsigned int count, uint32_t type, c render.texture_functions.id = _bolt_gl_plugin_texture_id; 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; _bolt_plugin_handle_3d(&render); } @@ -1496,6 +1498,12 @@ uint8_t _bolt_gl_plugin_texture_compare(void* userdata, size_t x, size_t y, size return !memcmp(tex->data + start_offset, data, len); } +uint8_t* _bolt_gl_plugin_texture_data(void* userdata, size_t x, size_t y) { + const struct GLPluginTextureUserData* data = userdata; + const struct GLTexture2D* tex = data->tex; + return tex->data + (tex->width * y * 4) + (x * 4); +} + void _bolt_gl_plugin_surface_init(struct SurfaceFunctions* functions, unsigned int width, unsigned int height) { struct PluginSurfaceUserdata* userdata = malloc(sizeof(struct PluginSurfaceUserdata)); struct GLContext* c = _bolt_context(); diff --git a/src/library/gl.h b/src/library/gl.h index ad232a9..6fd627d 100644 --- a/src/library/gl.h +++ b/src/library/gl.h @@ -316,6 +316,7 @@ struct GLPluginTextureUserData { size_t _bolt_gl_plugin_texture_id(void* userdata); void _bolt_gl_plugin_texture_size(void* userdata, size_t* out); uint8_t _bolt_gl_plugin_texture_compare(void* userdata, size_t x, size_t y, size_t len, const unsigned char* data); +uint8_t* _bolt_gl_plugin_texture_data(void* userdata, size_t x, size_t y); void _bolt_gl_plugin_surface_init(struct SurfaceFunctions* out, unsigned int width, unsigned int height); void _bolt_gl_plugin_surface_destroy(void* userdata); diff --git a/src/library/plugin.c b/src/library/plugin.c index b661373..bef7591 100644 --- a/src/library/plugin.c +++ b/src/library/plugin.c @@ -122,6 +122,7 @@ void _bolt_plugin_init(void (*_surface_init)(struct SurfaceFunctions*, unsigned API_ADD_SUB(textureid, batch2d) API_ADD_SUB(texturesize, batch2d) API_ADD_SUB(texturecompare, batch2d) + API_ADD_SUB(texturedata, batch2d) API_ADD_SUB_ALIAS(vertexcolour, vertexcolor, batch2d) lua_settable(state, -3); lua_settable(state, LUA_REGISTRYINDEX); @@ -140,6 +141,7 @@ void _bolt_plugin_init(void (*_surface_init)(struct SurfaceFunctions*, unsigned API_ADD_SUB(textureid, render3d) API_ADD_SUB(texturesize, render3d) API_ADD_SUB(texturecompare, render3d) + API_ADD_SUB(texturedata, render3d) API_ADD_SUB_ALIAS(vertexcolour, vertexcolor, render3d) lua_settable(state, -3); lua_settable(state, LUA_REGISTRYINDEX); @@ -438,6 +440,17 @@ static int api_batch2d_texturecompare(lua_State* state) { return 1; } +static int api_batch2d_texturedata(lua_State* state) { + _bolt_check_argc(state, 4, "batch2d_texturedata"); + struct RenderBatch2D* render = lua_touserdata(state, 1); + const size_t x = lua_tointeger(state, 2); + const size_t y = lua_tointeger(state, 3); + const size_t len = lua_tointeger(state, 4); + const uint8_t* ret = render->texture_functions.data(render->texture_functions.userdata, x, y); + lua_pushlstring(state, (const char*)ret, len); + return 1; +} + static int api_minimap_angle(lua_State* state) { _bolt_check_argc(state, 1, "minimap_angle"); struct RenderMinimapEvent* render = lua_touserdata(state, 1); @@ -604,3 +617,14 @@ static int api_render3d_texturecompare(lua_State* state) { lua_pushboolean(state, match); return 1; } + +static int api_render3d_texturedata(lua_State* state) { + _bolt_check_argc(state, 4, "render3d_texturedata"); + struct Render3D* render = lua_touserdata(state, 1); + const size_t x = lua_tointeger(state, 2); + const size_t y = lua_tointeger(state, 3); + const size_t len = lua_tointeger(state, 4); + const uint8_t* ret = render->texture_functions.data(render->texture_functions.userdata, x, y); + lua_pushlstring(state, (const char*)ret, len); + return 1; +} diff --git a/src/library/plugin.h b/src/library/plugin.h index 781158f..3d27696 100644 --- a/src/library/plugin.h +++ b/src/library/plugin.h @@ -74,6 +74,10 @@ struct TextureFunctions { /// Note that changing the in-game "texture compression" setting will change the contents of /// the texture for some images and therefore change the result of this comparison. uint8_t (*compare)(void* userdata, size_t x, size_t y, size_t len, const unsigned char* data); + + /// Fetches a pointer to the texture's pixel data at coordinates x and y. Doesn't do any checks + /// on whether x and y are in-bounds. Data is always RGBA and pixel rows are always contiguous. + uint8_t* (*data)(void* userdata, size_t x, size_t y); }; /// Struct containing "vtable" callback information for surfaces. diff --git a/src/library/plugin_api.h b/src/library/plugin_api.h index 28dcd79..b1cf3cc 100644 --- a/src/library/plugin_api.h +++ b/src/library/plugin_api.h @@ -213,7 +213,7 @@ static int api_batch2d_texturesize(lua_State*); /// [-4, +1, -] /// Compares a section of the texture atlas for this batch to some RGBA data. For example: /// -/// `batch:comparetexture(64, 128, {0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF})` +/// `batch:texturecompare(64, 128, {0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF})` /// /// This would check if the pixels at 64,128 and 65,128 are red. The bytes must match exactly /// for the function to return true, otherwise it will return false. @@ -223,6 +223,18 @@ static int api_batch2d_texturesize(lua_State*); /// but can only be done one row at a time. static int api_batch2d_texturecompare(lua_State*); +/// [-4, +1, -] +/// Gets the RGBA data starting at a given coordinate of the texture atlas, for example: +/// +/// `batch:texturedata(64, 128, 8)` +/// +/// This would return RGBA data for eight bytes, i.e. the two pixels at (64,128) and (65,128), +/// encoded as a Lua string. +/// +/// 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_batch2d_texturedata(lua_State*); + /// [-1, +1, -] /// Returns the angle at which the minimap background image is being rendered, in radians. /// @@ -318,7 +330,7 @@ static int api_render3d_texturesize(lua_State*); /// [-4, +1, -] /// Compares a section of the texture atlas for this render to some RGBA data. For example: /// -/// `render:comparetexture(64, 128, {0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF})` +/// `render:texturecompare(64, 128, {0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF})` /// /// This would check if the pixels at 64,128 and 65,128 are red. The bytes must match exactly /// for the function to return true, otherwise it will return false. @@ -327,3 +339,15 @@ static int api_render3d_texturesize(lua_State*); /// block of pixels at once by this method is relatively fast, but can only be done one row at a /// time. static int api_render3d_texturecompare(lua_State*); + +/// [-4, +1, -] +/// Gets the RGBA data starting at a given coordinate of the texture atlas, for example: +/// +/// `render:texturedata(64, 128, 8)` +/// +/// This would return RGBA data for eight bytes, i.e. the two pixels at (64,128) and (65,128), +/// encoded as a Lua string. +/// +/// 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*);