library: most of the item icon APIs

This commit is contained in:
Adam
2024-11-30 19:12:45 +00:00
parent e59b7296ec
commit 6d63aeabeb
9 changed files with 526 additions and 66 deletions

View File

@@ -51,6 +51,7 @@ static void hook_glTexSubImage2D(GLenum, GLint, GLint, GLint, GLsizei, GLsizei,
static void hook_glDeleteTextures(GLsizei, const GLuint*);
static void hook_glClear(GLbitfield);
static void hook_glViewport(GLint, GLint, GLsizei, GLsizei);
static void hook_glTexParameteri(GLenum, GLenum, GLint);
static HGLRC __stdcall hook_wglCreateContextAttribsARB(HDC, HGLRC, const int*);
@@ -105,7 +106,7 @@ DWORD __stdcall BOLT_STUB_ENTRYNAME(struct PluginInjectParams* data) {
libgl.GenTextures = (void(*)(GLsizei, GLuint*))data->pGetProcAddress(libgl_module, "glGenTextures");
libgl.GetError = (GLenum(*)(void))data->pGetProcAddress(libgl_module, "glGetError");
libgl.ReadPixels = (void(*)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, void*))data->pGetProcAddress(libgl_module, "glReadPixels");
libgl.TexParameteri = (void(*)(GLenum, GLenum, GLfloat))data->pGetProcAddress(libgl_module, "glTexParameteri");
libgl.TexParameteri = (void(*)(GLenum, GLenum, GLint))data->pGetProcAddress(libgl_module, "glTexParameteri");
libgl.TexSubImage2D = (void(*)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const void*))data->pGetProcAddress(libgl_module, "glTexSubImage2D");
libgl.Viewport = (void(*)(GLint, GLint, GLsizei, GLsizei))data->pGetProcAddress(libgl_module, "glViewport");
@@ -135,6 +136,7 @@ DWORD __stdcall BOLT_STUB_ENTRYNAME(struct PluginInjectParams* data) {
FNHOOK(glDrawArrays)
FNHOOK(glTexSubImage2D)
FNHOOK(glDeleteTextures)
FNHOOK(glTexParameteri)
FNHOOK(glClear)
FNHOOK(glViewport)
}
@@ -388,6 +390,13 @@ static void hook_glDeleteTextures(GLsizei n, const GLuint* textures) {
LOG("glDeleteTextures end\n");
}
static void hook_glTexParameteri(GLenum target, GLenum pname, GLint param) {
LOG("glTexParameteri\n");
libgl.TexParameteri(target, pname, param);
_bolt_gl_onTexParameteri(target, pname, param);
LOG("glTexParameteri end\n");
}
static void hook_glClear(GLbitfield mask) {
LOG("glClear\n");
libgl.Clear(mask);

View File

@@ -566,6 +566,26 @@ end)
It's @strong{not safe} to use an event object after the event handler
has returned.
@node functions-onrendericon
@section onrendericon
Sets an event handler for item icon render events. The function will
overwrite any previous event handler, or, if it's not a function, then
any previous event handler will be deleted. See
@ref{objects-renderitemicon,, Render Item Icon Event} for documentation
on this event object.
@example lua
@verbatim
bolt.onrendericon(function (event)
-- ...
end)
@end verbatim
@end example
It's @strong{not safe} to use an event object after the event handler
has returned.
@node functions-onminimap
@section onminimap
@@ -2039,15 +2059,16 @@ vertex coordinates and texture data can be queried, along with its
animation data if the model is animated.
Bolt has a complex set of functions for doing calculations with 3D space
data. Render3D's @ref{render3d-vertexxyz,,vertexxyz} function returns
static model data which will always be the same for two instances of the
same model even if they're placed differently, scaled or rotated
differently, doing different animations, etc. To get the model's
position in world space, use @ref{render3d-modelmatrix,,modelmatrix}:
data. Render3D's @ref{render3d-vertexpoint,,vertexpoint} function
returns static model data which will always be the same for two
instances of the same model even if they're placed differently, scaled
or rotated differently, doing different animations, etc. To get the
model's position in world space, use @ref{render3d-modelmatrix,,
modelmatrix}:
@example lua
@verbatim
local modelpoint = myevent:vertexxyz(1)
local modelpoint = myevent:vertexpoint(1)
local worldpoint = modelpoint:transform(myevent:modelmatrix())
@end verbatim
@end example
@@ -2072,7 +2093,7 @@ must be applied before any of the other transforms.
@example lua
@verbatim
local modelpoint = myevent:vertexxyz(1)
local modelpoint = myevent:vertexpoint(1)
local animatedpoint = modelpoint:transform(myevent:vertexanimation(1))
local worldpoint = animatedpoint:transform(myevent:modelmatrix())
@end verbatim
@@ -2117,8 +2138,8 @@ local count = event:vertexcount()
@end verbatim
@end example
@node render3d-vertexxyz
@subsection vertexxyz
@node render3d-vertexpoint
@subsection vertexpoint
Given a vertex number, returns a @ref{objects-point,,Point object}
representing the vertex's model coordinates, according to the static
@@ -2126,7 +2147,7 @@ model data.
@example lua
@verbatim
local modelpoint = event:vertexxyz(1)
local modelpoint = event:vertexpoint(1)
@end verbatim
@end example
@@ -2140,7 +2161,7 @@ points from model coordinates into world coordinates.
@example lua
@verbatim
local modelmatrix = event:modelmatrix()
local modelpoint = event:vertexxyz(1)
local modelpoint = event:vertexpoint(1)
local worldpoint = modelpoint:transform(modelmatrix)
@end verbatim
@end example
@@ -2319,6 +2340,162 @@ end
@end verbatim
@end example
@node objects-renderitemicon
@section Render Item Icon Event
A render-item-icon event comes from @ref{functions-onrendericon}. It
occurs when an item icon is rendered to the game view. Item icons refer
to items appearing in the UI, such as the player's inventory, equipment
screen, or action bar slots. These appear to be 2D images but in reality
they're "snapshots" of the item's 3D models, which can make them very
difficult to work with compared to a normal 2D image. Bolt attempts to
simplify this by storing some of the details of the models rendered at
the time when the icon is created, and allows plugins to query this
stored data. However this means that some data is missing compared to
a Render3D event; most notably, the texture data is currently not saved.
An icon may contain any number of models, and each vertex in each model
may be queried using the functions of this event.
@example lua
@verbatim
bolt.onrendericon(function (event)
for model = 1, event:modelcount() do
for vertex = 1, event:modelvertexcount(model) do
let point = event:modelvertexpoint(model, vertex)
-- ...
end
end
end)
@end verbatim
@end example
The view and projection matrix used when pre-rendering the item can also
be queried for each model. There's no model matrix for this process, so
the model coordinates are treated as if they were the world coordinates.
Some items, especially most weapons' off-hand variants, use the same
item model viewed from a different camera angle, which means the only
way to differentiate between them is to @ref{transform-decompose} the
view matrix.
It's @strong{not safe} to use an event object after the event handler
has returned.
@node renderitemicon-xywh
@subsection xywh
Returns the x, y, width and height of where this icon is being drawn on
the screen, in pixel coordinates. The X and Y are relative to the
top-left pixel of the inner area of the window.
@example lua
@verbatim
local x, y, width, height = event:xywh()
@end verbatim
@end example
@node renderitemicon-modelcount
@subsection modelcount
Returns the number of 3D models that were rendered to this icon.
@example lua
@verbatim
for model = 1, event:modelcount() do
-- ...
end
@end verbatim
@end example
@node renderitemicon-modelvertexcount
@subsection modelvertexcount
Given a model index, returns the number of vertices in that model.
@example lua
@verbatim
for model = 1, event:modelcount() do
for vertex = 1, event:modelvertexcount(model) do
-- ...
end
end
@end verbatim
@end example
@node renderitemicon-modelvertexpoint
@subsection modelvertexpoint
Given a model number and vertex number, returns a @ref{objects-point}
representing the vertex's model coordinates.
@example lua
@verbatim
local point = event:modelvertexpoint(model, vertex)
@end verbatim
@end example
@node renderitemicon-modelvertexcolour
@subsection modelvertexcolour
Given a model number and a vertex number, 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.
These values are multiplied with the texture, so values less than 1.0
will darken the texture (or make it more transparent in the case of the
alpha channel). A common use for this is to draw differently "tinted"
versions of the same model using the same texture.
@example lua
@verbatim
local red, green, blue, alpha = event:modelvertexcolour(model, vertex)
@end verbatim
@end example
@node renderitemicon-modelvertexcolor
@subsection modelvertexcolor
Alias for @ref{renderitemicon-modelvertexcolour}
@node renderitemicon-modelviewmatrix
@subsection modelviewmatrix
Given a model number, returns a @ref{objects-transform} representing the
view matrix that was used to render it.
@example lua
@verbatim
local viewmatrix = event:modelviewmatrix(model)
@end verbatim
@end example
@node renderitemicon-modelprojectionmatrix
@subsection modelprojectionmatrix
Given a model number, returns a @ref{objects-transform} representing the
projection matrix that was used to render it.
@example lua
@verbatim
local projmatrix = event:modelprojectionmatrix(model)
@end verbatim
@end example
@node renderitemicon-modelviewprojmatrix
@subsection modelviewprojmatrix
Given a model number, returns a @ref{objects-transform} representing the
combined view and projection matrices, commonly called the "viewproj
matrix", that was used to render that model. These are pre-multiplied
in the shader, so using the viewproj matrix is more efficient than using
the view and projection matrices separately.
@example lua
@verbatim
local viewprojmatrix = event:modelviewprojmatrix(model)
@end verbatim
@end example
@node objects-minimap
@section Minimap Event
@@ -2393,7 +2570,7 @@ has returned.
Returns the new x, y, width and height that the window was repositioned
to.
@example
@example lua
@verbatim
local newx, newy, newwidth, newheight = event:xywh()
@end verbatim
@@ -2405,7 +2582,7 @@ local newx, newy, newwidth, newheight = event:xywh()
Returns a boolean value indicating whether the window changed size. If
true, the contents of the window were cleared and need to be redrawn.
@example
@example lua
@verbatim
if event:didresize() then
-- re-draw something to the window
@@ -2433,7 +2610,7 @@ has returned.
Returns the x and y for this mouse event in pixels, relative to the
top-left of the window that it relates to.
@example
@example lua
@verbatim
local x, y = event:xy()
@end verbatim
@@ -2445,7 +2622,7 @@ local x, y = event:xy()
Returns a boolean value indicating whether @code{ctrl} was held when
this event was fired.
@example
@example lua
@verbatim
local ctrl = event:ctrl()
@end verbatim
@@ -2457,7 +2634,7 @@ local ctrl = event:ctrl()
Returns a boolean value indicating whether @code{shift} was held when
this event was fired.
@example
@example lua
@verbatim
local shift = event:shift()
@end verbatim
@@ -2470,7 +2647,7 @@ Returns a boolean value indicating whether the meta key (also known as
super, command, or the "windows key") was held when this event was
fired.
@example
@example lua
@verbatim
local meta = event:meta()
@end verbatim
@@ -2482,7 +2659,7 @@ local meta = event:meta()
Returns a boolean value indicating whether @code{alt} was held when this
event was fired.
@example
@example lua
@verbatim
local alt = event:alt()
@end verbatim
@@ -2494,7 +2671,7 @@ local alt = event:alt()
Returns a boolean value indicating whether caps lock was on when this
event was fired.
@example
@example lua
@verbatim
local capslock = event:capslock()
@end verbatim
@@ -2506,7 +2683,7 @@ local capslock = event:capslock()
Returns a boolean value indicating whether numlock was on when this
event was fired.
@example
@example lua
@verbatim
local numlock = event:numlock()
@end verbatim
@@ -2519,7 +2696,7 @@ Returns three boolean values indicating whether each primary mouse
button was held when this event fired, in the order: left, right,
middle.
@example
@example lua
@verbatim
local lmb, rmb, mmb = event:buttons()
@end verbatim
@@ -2548,7 +2725,7 @@ has returned.
Returns the x and y for this mouse event in pixels, relative to the
top-left of the window that it relates to.
@example
@example lua
@verbatim
local x, y = event:xy()
@end verbatim
@@ -2560,7 +2737,7 @@ local x, y = event:xy()
Returns a boolean value indicating whether @code{ctrl} was held when
this event was fired.
@example
@example lua
@verbatim
local ctrl = event:ctrl()
@end verbatim
@@ -2572,7 +2749,7 @@ local ctrl = event:ctrl()
Returns a boolean value indicating whether @code{shift} was held when
this event was fired.
@example
@example lua
@verbatim
local shift = event:shift()
@end verbatim
@@ -2585,7 +2762,7 @@ Returns a boolean value indicating whether the meta key (also known as
super, command, or the "windows key") was held when this event was
fired.
@example
@example lua
@verbatim
local meta = event:meta()
@end verbatim
@@ -2597,7 +2774,7 @@ local meta = event:meta()
Returns a boolean value indicating whether @code{alt} was held when this
event was fired.
@example
@example lua
@verbatim
local alt = event:alt()
@end verbatim
@@ -2609,7 +2786,7 @@ local alt = event:alt()
Returns a boolean value indicating whether caps lock was on when this
event was fired.
@example
@example lua
@verbatim
local capslock = event:capslock()
@end verbatim
@@ -2621,7 +2798,7 @@ local capslock = event:capslock()
Returns a boolean value indicating whether numlock was on when this
event was fired.
@example
@example lua
@verbatim
local numlock = event:numlock()
@end verbatim
@@ -2634,7 +2811,7 @@ Returns three boolean values indicating whether each primary mouse
button was held when this event fired, in the order: left, right,
middle.
@example
@example lua
@verbatim
local lmb, rmb, mmb = event:buttons()
@end verbatim
@@ -2664,7 +2841,7 @@ has returned.
Returns the x and y for this mouse event in pixels, relative to the
top-left of the window that it relates to.
@example
@example lua
@verbatim
local x, y = event:xy()
@end verbatim
@@ -2676,7 +2853,7 @@ local x, y = event:xy()
Returns a boolean value indicating whether @code{ctrl} was held when
this event was fired.
@example
@example lua
@verbatim
local ctrl = event:ctrl()
@end verbatim
@@ -2688,7 +2865,7 @@ local ctrl = event:ctrl()
Returns a boolean value indicating whether @code{shift} was held when
this event was fired.
@example
@example lua
@verbatim
local shift = event:shift()
@end verbatim
@@ -2701,7 +2878,7 @@ Returns a boolean value indicating whether the meta key (also known as
super, command, or the "windows key") was held when this event was
fired.
@example
@example lua
@verbatim
local meta = event:meta()
@end verbatim
@@ -2713,7 +2890,7 @@ local meta = event:meta()
Returns a boolean value indicating whether @code{alt} was held when this
event was fired.
@example
@example lua
@verbatim
local alt = event:alt()
@end verbatim
@@ -2725,7 +2902,7 @@ local alt = event:alt()
Returns a boolean value indicating whether caps lock was on when this
event was fired.
@example
@example lua
@verbatim
local capslock = event:capslock()
@end verbatim
@@ -2737,7 +2914,7 @@ local capslock = event:capslock()
Returns a boolean value indicating whether numlock was on when this
event was fired.
@example
@example lua
@verbatim
local numlock = event:numlock()
@end verbatim
@@ -2750,7 +2927,7 @@ Returns three boolean values indicating whether each primary mouse
button was held when this event fired, in the order: left, right,
middle.
@example
@example lua
@verbatim
local lmb, rmb, mmb = event:buttons()
@end verbatim
@@ -2763,7 +2940,7 @@ Returns a boolean value representing the scroll direction. False means
scrolling down, toward the user, and true means scrolling up, away from
the user.
@example
@example lua
@verbatim
local direction = event:direction()
@end verbatim
@@ -2785,7 +2962,7 @@ has returned.
Returns the x and y for this mouse event in pixels, relative to the
top-left of the window that it relates to.
@example
@example lua
@verbatim
local x, y = event:xy()
@end verbatim
@@ -2797,7 +2974,7 @@ local x, y = event:xy()
Returns a boolean value indicating whether @code{ctrl} was held when
this event was fired.
@example
@example lua
@verbatim
local ctrl = event:ctrl()
@end verbatim
@@ -2809,7 +2986,7 @@ local ctrl = event:ctrl()
Returns a boolean value indicating whether @code{shift} was held when
this event was fired.
@example
@example lua
@verbatim
local shift = event:shift()
@end verbatim
@@ -2822,7 +2999,7 @@ Returns a boolean value indicating whether the meta key (also known as
super, command, or the "windows key") was held when this event was
fired.
@example
@example lua
@verbatim
local meta = event:meta()
@end verbatim
@@ -2834,7 +3011,7 @@ local meta = event:meta()
Returns a boolean value indicating whether @code{alt} was held when this
event was fired.
@example
@example lua
@verbatim
local alt = event:alt()
@end verbatim
@@ -2846,7 +3023,7 @@ local alt = event:alt()
Returns a boolean value indicating whether caps lock was on when this
event was fired.
@example
@example lua
@verbatim
local capslock = event:capslock()
@end verbatim
@@ -2858,7 +3035,7 @@ local capslock = event:capslock()
Returns a boolean value indicating whether numlock was on when this
event was fired.
@example
@example lua
@verbatim
local numlock = event:numlock()
@end verbatim
@@ -2871,7 +3048,7 @@ Returns three boolean values indicating whether each primary mouse
button was held when this event fired, in the order: left, right,
middle.
@example
@example lua
@verbatim
local lmb, rmb, mmb = event:buttons()
@end verbatim

View File

@@ -138,6 +138,7 @@ static void _bolt_gl_plugin_game_view_rect(int* x, int* y, int* w, int* h);
#define VAO_LIST_CAPACITY 256 * 256
#define CONTEXTS_CAPACITY 64 // not growable so we just have to hard-code a number and hope it's enough forever
#define GAME_MINIMAP_BIG_SIZE 2048
#define GAME_ITEM_ICON_SIZE 64
static struct GLContext contexts[CONTEXTS_CAPACITY];
// since GL contexts are bound only to the thread that binds them, we use thread-local storage (TLS)
@@ -824,9 +825,11 @@ static void _bolt_glTexStorage2D(GLenum target, GLsizei levels, GLenum internalf
if (target == GL_TEXTURE_2D) {
struct GLTexture2D* tex = c->texture_units[c->active_texture];
free(tex->data);
tex->data = malloc(width * height * 4);
tex->data = calloc(width * height * 4, sizeof(*tex->data));
tex->internalformat = internalformat;
tex->width = width;
tex->height = height;
tex->icon.model_count = 0;
}
LOG("glTexStorage2D end\n");
}
@@ -1042,14 +1045,29 @@ static void _bolt_glCopyImageSubData(
gl.CopyImageSubData(srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth);
struct GLContext* c = _bolt_context();
if (srcTarget == GL_TEXTURE_2D && dstTarget == GL_TEXTURE_2D && srcLevel == 0 && dstLevel == 0) {
const struct GLTexture2D* src = _bolt_context_get_texture(c, srcName);
const struct GLTexture2D* dst = _bolt_context_get_texture(c, dstName);
struct GLTexture2D* src = _bolt_context_get_texture(c, srcName);
struct GLTexture2D* dst = _bolt_context_get_texture(c, dstName);
if (!c->does_blit_3d_target && c->depth_of_field_enabled && dst->id == c->depth_of_field_sSourceTex) {
if (srcX == 0 && srcY == 0 && dstX == 0 && dstY == 0 && src->width == dst->width && src->height == dst->height && src->width == srcWidth && src->height == srcHeight) {
printf("copy to depth-of-field tex from tex %i\n", src->id);
c->does_blit_3d_target = true;
c->target_3d_tex = src->id;
}
} else if (src->icon.model_count && dst->width > GAME_ITEM_ICON_SIZE && dst->height > GAME_ITEM_ICON_SIZE) {
if (!dst->icons) {
dst->icons = hashmap_new(sizeof(struct ItemIcon), 256, 0, 0, _bolt_plugin_itemicon_hash, _bolt_plugin_itemicon_compare, NULL, NULL);
}
src->icon.x = dstX;
src->icon.y = dstY;
src->icon.w = srcWidth;
src->icon.h = srcHeight;
const struct ItemIcon* old_icon = hashmap_set(dst->icons, &src->icon);
if (old_icon) {
for (size_t i = 0; i < old_icon->model_count; i += 1) {
free(old_icon->models[i].vertices);
}
}
src->icon.model_count = 0;
} else if (src->id != c->target_3d_tex) {
for (GLsizei i = 0; i < srcHeight; i += 1) {
memcpy(dst->data + (dstY * dst->width * 4) + (dstX * 4), src->data + (srcY * src->width * 4) + (srcX * 4), srcWidth * 4);
@@ -1343,6 +1361,9 @@ void _bolt_gl_onGenTextures(GLsizei n, GLuint* textures) {
for (GLsizei i = 0; i < n; i += 1) {
struct GLTexture2D* tex = calloc(1, sizeof(struct GLTexture2D));
tex->id = textures[i];
tex->internalformat = -1;
tex->compare_mode = -1;
tex->icons = NULL;
tex->is_minimap_tex_big = 0;
tex->is_minimap_tex_small = 0;
hashmap_set(c->textures->map, &tex);
@@ -1434,11 +1455,11 @@ void _bolt_gl_onDrawElements(GLenum mode, GLsizei count, GLenum type, const void
_bolt_plugin_handle_minimap(&render);
}
}
} else {
} else if (c->current_draw_framebuffer == 0) {
struct GLPluginDrawElementsVertex2DUserData vertex_userdata;
vertex_userdata.c = c;
vertex_userdata.indices = (unsigned short*)((uint8_t*)element_buffer->data + (uintptr_t)indices_offset);
vertex_userdata.atlas = c->texture_units[diffuse_map];
vertex_userdata.indices = indices;
vertex_userdata.atlas = tex;
vertex_userdata.position = &attributes[c->bound_program->loc_aVertexPosition2D];
vertex_userdata.atlas_min = &attributes[c->bound_program->loc_aTextureUVAtlasMin];
vertex_userdata.atlas_size = &attributes[c->bound_program->loc_aTextureUVAtlasExtents];
@@ -1465,7 +1486,49 @@ void _bolt_gl_onDrawElements(GLenum mode, GLsizei count, GLenum type, const void
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_render2d(&batch);
if (tex->icons) {
size_t batch_start = 0;
for (size_t i = 0; i < count; i += batch.vertices_per_icon) {
float xy[2];
float wh[2];
_bolt_get_attr_binding(c, vertex_userdata.atlas_min, indices[i], 2, xy);
_bolt_get_attr_binding(c, vertex_userdata.atlas_size, indices[i], 2, wh);
const struct ItemIcon dummy_icon = {
.x = (uint16_t)roundf(xy[0] * tex->width),
.y = (uint16_t)roundf(xy[1] * tex->height),
.w = (uint16_t)roundf(fabs(wh[0]) * tex->width),
.h = (uint16_t)roundf(fabs(wh[1]) * tex->height),
};
const struct ItemIcon* icon = hashmap_get(tex->icons, &dummy_icon);
if (icon) {
batch.index_count = i - batch_start;
if (batch.index_count) {
vertex_userdata.indices = indices + batch_start;
_bolt_plugin_handle_render2d(&batch);
}
int32_t xy0[2];
int32_t xy2[2];
_bolt_get_attr_binding_int(c, vertex_userdata.position, i, 2, xy0);
_bolt_get_attr_binding_int(c, vertex_userdata.position, i + 2, 2, xy2);
struct RenderItemIconEvent event;
event.icon = icon;
event.target_x = (int16_t)xy0[0];
event.target_y = (int16_t)(batch.screen_height - xy0[1]);
event.target_w = xy2[0] - xy0[0];
event.target_h = xy0[1] - xy2[1];
_bolt_plugin_handle_rendericon(&event);
batch_start = i + batch.vertices_per_icon;
}
}
if (batch_start < count) {
batch.index_count = count - batch_start;
vertex_userdata.indices = indices + batch_start;
_bolt_plugin_handle_render2d(&batch);
}
} else {
_bolt_plugin_handle_render2d(&batch);
}
}
}
if (type == GL_UNSIGNED_SHORT && mode == GL_TRIANGLES && c->bound_program->is_3d) {
@@ -1486,7 +1549,7 @@ void _bolt_gl_onDrawElements(GLenum mode, GLsizei count, GLenum type, const void
struct GLPluginDrawElementsVertex3DUserData vertex_userdata;
vertex_userdata.c = c;
vertex_userdata.indices = (unsigned short*)((uint8_t*)element_buffer->data + (uintptr_t)indices_offset);
vertex_userdata.indices = indices;
vertex_userdata.atlas_scale = roundf(atlas_meta[1]);
vertex_userdata.atlas = tex;
vertex_userdata.settings_atlas = tex_settings;
@@ -1529,6 +1592,30 @@ void _bolt_gl_onDrawElements(GLenum mode, GLsizei count, GLenum type, const void
render.matrix_functions.viewproj_matrix = _bolt_gl_plugin_matrix3d_viewproj;
_bolt_plugin_handle_render3d(&render);
} else {
struct GLTexture2D* tex = _bolt_context_get_texture(c, draw_tex);
if (tex && tex->compare_mode == GL_NONE && tex->internalformat == GL_RGBA8 && tex->width == GAME_ITEM_ICON_SIZE && tex->height == GAME_ITEM_ICON_SIZE && tex->icon.model_count < MAX_MODELS_PER_ICON) {
struct ItemIconModel* model = &tex->icon.models[tex->icon.model_count];
tex->icon.model_count += 1;
GLfloat model_matrix[16];
GLint ubo_binding, ubo_view_index;
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 uint8_t* ubo_view_buf = (uint8_t*)_bolt_context_get_buffer(c, ubo_view_index)->data;
gl.GetUniformfv(c->bound_program->id, c->bound_program->loc_uModelMatrix, model_matrix);
for (size_t i = 0; i < 16; i += 1) {
model->view_matrix.matrix[i] = (double)*(float*)(ubo_view_buf + c->bound_program->offset_uViewMatrix);
model->projection_matrix.matrix[i] = (double)*(float*)(ubo_view_buf + c->bound_program->offset_uProjectionMatrix);
model->viewproj_matrix.matrix[i] = (double)*(float*)(ubo_view_buf + c->bound_program->offset_uViewProjMatrix);
}
model->vertex_count = count;
model->vertices = malloc(sizeof(*model->vertices) * count);
for (size_t i = 0; i < count; i += 1) {
_bolt_get_attr_binding_int(c, &attributes[c->bound_program->loc_aVertexPosition_BoneLabel], indices[i], 4, model->vertices[i].point.xyzh.ints);
_bolt_get_attr_binding(c, &attributes[c->bound_program->loc_aVertexColour], indices[i], 4, model->vertices[i].rgba);
model->vertices[i].point.integer = true;
}
}
}
}
}
@@ -1659,6 +1746,20 @@ void _bolt_gl_onDeleteTextures(GLsizei n, const GLuint* textures) {
const GLuint* ptr = &textures[i];
struct GLTexture2D* const* texture = hashmap_delete(c->textures->map, &ptr);
free((*texture)->data);
if ((*texture)->icons) {
size_t iter = 0;
void* item;
while (hashmap_iter((*texture)->icons, &iter, &item)) {
const struct ItemIcon* icon = (struct ItemIcon*)item;
for (size_t i = 0; i < icon->model_count; i += 1) {
free(icon->models[i].vertices);
}
}
hashmap_free((*texture)->icons);
}
for (size_t i = 0; i < (*texture)->icon.model_count; i += 1) {
free((*texture)->icon.models[i].vertices);
}
free(*texture);
}
_bolt_rwlock_unlock_write(&c->textures->rwlock);
@@ -1672,6 +1773,10 @@ void _bolt_gl_onClear(GLbitfield mask) {
struct GLTexture2D* tex = _bolt_context_get_texture(c, draw_tex);
if (tex) {
tex->is_minimap_tex_big = 0;
for (size_t i = 0; i < tex->icon.model_count; i += 1) {
free(tex->icon.models[i].vertices);
}
tex->icon.model_count = 0;
}
}
}
@@ -1684,6 +1789,14 @@ void _bolt_gl_onViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
c->viewport_h = height;
}
void _bolt_gl_onTexParameteri(GLenum target, GLenum pname, GLint param) {
if (target == GL_TEXTURE_2D && pname == GL_TEXTURE_COMPARE_MODE) {
struct GLContext* c = _bolt_context();
struct GLTexture2D* tex = c->texture_units[c->active_texture];
tex->compare_mode = param;
}
}
static void _bolt_gl_plugin_drawelements_vertex2d_xy(size_t index, void* userdata, int32_t* out) {
struct GLPluginDrawElementsVertex2DUserData* data = userdata;
if (_bolt_get_attr_binding_int(data->c, data->position, data->indices[index], 2, out)) {
@@ -1739,10 +1852,10 @@ static void _bolt_gl_plugin_drawelements_vertex3d_xyz(size_t index, void* userda
if (!_bolt_get_attr_binding_int(data->c, data->xyz_bone, data->indices[index], 3, out->xyzh.ints)) {
float pos[3];
_bolt_get_attr_binding(data->c, data->xyz_bone, data->indices[index], 3, pos);
out->xyzh.ints[0] = (double)pos[0];
out->xyzh.ints[1] = (double)pos[1];
out->xyzh.ints[2] = (double)pos[2];
out->xyzh.ints[3] = 1.0;
out->xyzh.floats[0] = (double)pos[0];
out->xyzh.floats[1] = (double)pos[1];
out->xyzh.floats[2] = (double)pos[2];
out->xyzh.floats[3] = 1.0;
out->integer = false;
}
}

View File

@@ -5,8 +5,8 @@
#include "../../modules/hashmap/hashmap.h"
#include "rwlock/rwlock.h"
#include "plugin/plugin.h"
struct hashmap;
struct SurfaceFunctions;
/* types from gl.h */
typedef unsigned int GLenum;
@@ -97,12 +97,13 @@ struct GLLibFunctions {
void (*GenTextures)(GLsizei, GLuint*);
GLenum (*GetError)(void);
void (*ReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, void*);
void (*TexParameteri)(GLenum, GLenum, GLfloat);
void (*TexParameteri)(GLenum, GLenum, GLint);
void (*TexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const void*);
void (*Viewport)(GLint, GLint, GLsizei, GLsizei);
};
/* consts used from libgl */
#define GL_NONE 0
#define GL_TEXTURE 5890
#define GL_TEXTURE_2D 3553
#define GL_RGB 6407
@@ -158,6 +159,7 @@ struct GLLibFunctions {
#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 36048
#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 36049
#define GL_MAX_VERTEX_ATTRIBS 34921
#define GL_TEXTURE_COMPARE_MODE 34892
/* bolt re-implementation of some gl objects, storing only the things we need */
@@ -177,6 +179,10 @@ struct GLTexture2D {
GLsizei height;
double minimap_center_x;
double minimap_center_y;
GLenum internalformat;
GLint compare_mode;
struct ItemIcon icon;
struct hashmap* icons;
uint8_t is_minimap_tex_big;
uint8_t is_minimap_tex_small;
};
@@ -325,11 +331,14 @@ void _bolt_gl_onClear(GLbitfield);
/// Call this in response to glViewport, which needs to be hooked from libgl.
void _bolt_gl_onViewport(GLint, GLint, GLsizei, GLsizei);
/// Call this in response to glTexParameteri, which needs to be hooked from libgl.
void _bolt_gl_onTexParameteri(GLenum, GLenum, GLint);
/* plugin library interop stuff */
struct GLPluginDrawElementsVertex2DUserData {
struct GLContext* c;
unsigned short* indices;
const unsigned short* indices;
struct GLTexture2D* atlas;
struct GLAttrBinding* position;
struct GLAttrBinding* atlas_min;
@@ -341,7 +350,7 @@ struct GLPluginDrawElementsVertex2DUserData {
struct GLPluginDrawElementsVertex3DUserData {
struct GLContext* c;
unsigned short* indices;
const unsigned short* indices;
int atlas_scale;
struct GLTexture2D* atlas;
struct GLTexture2D* settings_atlas;

View File

@@ -109,6 +109,20 @@ static uint64_t _bolt_plugin_map_hash(const void* item, uint64_t seed0, uint64_t
return hashmap_sip(&p->id, sizeof(p->id), seed0, seed1);
}
int _bolt_plugin_itemicon_compare(const void* a, const void* b, void* udata) {
const struct ItemIcon* i1 = a;
const struct ItemIcon* i2 = b;
uint64_t xywh1, xywh2;
memcpy(&xywh1, &i1->x, sizeof xywh1);
memcpy(&xywh2, &i2->x, sizeof xywh2);
return xywh2 - xywh1;
}
uint64_t _bolt_plugin_itemicon_hash(const void* item, uint64_t seed0, uint64_t seed1) {
const struct ItemIcon* icon = item;
return hashmap_sip(&icon->x, 4 * sizeof icon->x, seed0, seed1);
}
static struct hashmap* plugins;
#define DEFINE_CALLBACK(APINAME, STRUCTNAME) \
@@ -1110,6 +1124,7 @@ uint8_t _bolt_plugin_handle_mouse_event(struct MouseEvent* event, ptrdiff_t bool
DEFINE_CALLBACK_STATIC(swapbuffers, SwapBuffersEvent)
DEFINE_CALLBACK(render2d, RenderBatch2D)
DEFINE_CALLBACK(render3d, Render3D)
DEFINE_CALLBACK(rendericon, RenderItemIconEvent)
DEFINE_CALLBACK(minimap, RenderMinimapEvent)
DEFINE_CALLBACK(mousemotion, MouseMotionEvent)
DEFINE_CALLBACK(mousebutton, MouseButtonEvent)
@@ -1203,6 +1218,7 @@ _bolt_api_push_metatable_##NAME(plugin->state); \
lua_settable(plugin->state, LUA_REGISTRYINDEX);
SETMETA(render2d)
SETMETA(render3d)
SETMETA(rendericon)
SETMETA(minimap)
SETMETA(point)
SETMETA(transform)

View File

@@ -16,6 +16,8 @@ struct lua_State;
#define GRAB_TYPE_START 1
#define GRAB_TYPE_STOP 2
#define MAX_MODELS_PER_ICON 8
// a currently-running plugin.
// note "path" is not null-terminated, and must always be converted to use '/' as path-separators
// and must always end with a trailing separator by the time it's received by this process.
@@ -270,6 +272,39 @@ struct Render3D {
struct Render3DMatrixFunctions matrix_functions;
};
struct ItemIconVertex {
struct Point3D point;
uint16_t bone_id;
float rgba[4];
};
struct ItemIconModel {
uint32_t vertex_count;
struct ItemIconVertex* vertices;
struct Transform3D view_matrix;
struct Transform3D projection_matrix;
struct Transform3D viewproj_matrix;
};
struct ItemIcon {
uint16_t x;
uint16_t y;
uint16_t w;
uint16_t h;
uint8_t model_count;
struct ItemIconModel models[MAX_MODELS_PER_ICON];
};
int _bolt_plugin_itemicon_compare(const void* a, const void* b, void* udata);
uint64_t _bolt_plugin_itemicon_hash(const void* item, uint64_t seed0, uint64_t seed1);
struct RenderItemIconEvent {
const struct ItemIcon* icon;
uint16_t target_x;
uint16_t target_y;
uint16_t target_w;
uint16_t target_h;
};
struct RenderMinimapEvent {
double angle;
double scale;
@@ -361,6 +396,9 @@ void _bolt_plugin_handle_render2d(struct RenderBatch2D*);
/// Sends a Render3D to all plugins.
void _bolt_plugin_handle_render3d(struct Render3D*);
/// Sends a RenderItemIconEvent to all plugins.
void _bolt_plugin_handle_rendericon(struct RenderItemIconEvent*);
/// Sends a RenderMinimap to all plugins.
void _bolt_plugin_handle_minimap(struct RenderMinimapEvent*);

View File

@@ -174,6 +174,7 @@ static int api_buffer_set##FNAME(lua_State* state) { \
DEFINE_CALLBACK(swapbuffers)
DEFINE_CALLBACK(render2d)
DEFINE_CALLBACK(render3d)
DEFINE_CALLBACK(rendericon)
DEFINE_CALLBACK(minimap)
DEFINE_CALLBACK(mousemotion)
DEFINE_CALLBACK(mousebutton)
@@ -1051,8 +1052,8 @@ static int api_render3d_vertexcount(lua_State* state) {
return 1;
}
static int api_render3d_vertexxyz(lua_State* state) {
const struct Render3D* render = require_self_userdata(state, "vertexxyz");
static int api_render3d_vertexpoint(lua_State* state) {
const struct Render3D* render = require_self_userdata(state, "vertexpoint");
const lua_Integer index = lua_tointeger(state, 2);
struct Point3D* point = lua_newuserdata(state, sizeof(struct Point3D));
render->vertex_functions.xyz(index - 1, render->vertex_functions.userdata, point);
@@ -1199,6 +1200,79 @@ static int api_render3d_animated(lua_State* state) {
return 1;
}
static int api_rendericon_xywh(lua_State* state) {
const struct RenderItemIconEvent* event = require_self_userdata(state, "xywh");
lua_pushinteger(state, event->target_x);
lua_pushinteger(state, event->target_y);
lua_pushinteger(state, event->target_w);
lua_pushinteger(state, event->target_h);
return 4;
}
static int api_rendericon_modelcount(lua_State* state) {
const struct RenderItemIconEvent* event = require_self_userdata(state, "modelcount");
lua_pushinteger(state, event->icon->model_count);
return 1;
}
static int api_rendericon_modelvertexcount(lua_State* state) {
const struct RenderItemIconEvent* event = require_self_userdata(state, "modelvertexcount");
const size_t model = luaL_checkinteger(state, 2);
lua_pushinteger(state, event->icon->models[model - 1].vertex_count);
return 1;
}
static int api_rendericon_modelvertexpoint(lua_State* state) {
const struct RenderItemIconEvent* event = require_self_userdata(state, "modelvertexpoint");
const size_t model = luaL_checkinteger(state, 2);
const size_t vertex = luaL_checkinteger(state, 3);
struct Point3D* point = lua_newuserdata(state, sizeof(struct Point3D));
*point = event->icon->models[model - 1].vertices[vertex - 1].point;
lua_getfield(state, LUA_REGISTRYINDEX, "pointmeta");
lua_setmetatable(state, -2);
return 1;
}
static int api_rendericon_modelvertexcolour(lua_State* state) {
const struct RenderItemIconEvent* event = require_self_userdata(state, "modelvertexpoint");
const size_t model = luaL_checkinteger(state, 2);
const size_t vertex = luaL_checkinteger(state, 3);
for (size_t i = 0; i < 4; i += 1) {
lua_pushnumber(state, event->icon->models[model - 1].vertices[vertex - 1].rgba[i]);
}
return 4;
}
static int api_rendericon_modelviewmatrix(lua_State* state) {
const struct RenderItemIconEvent* event = require_self_userdata(state, "modelviewmatrix");
const size_t model = luaL_checkinteger(state, 2);
struct Transform3D* transform = lua_newuserdata(state, sizeof(struct Transform3D));
*transform = event->icon->models[model - 1].view_matrix;
lua_getfield(state, LUA_REGISTRYINDEX, "transformmeta");
lua_setmetatable(state, -2);
return 1;
}
static int api_rendericon_modelprojectionmatrix(lua_State* state) {
const struct RenderItemIconEvent* event = require_self_userdata(state, "modelprojectionmatrix");
const size_t model = luaL_checkinteger(state, 2);
struct Transform3D* transform = lua_newuserdata(state, sizeof(struct Transform3D));
*transform = event->icon->models[model - 1].projection_matrix;
lua_getfield(state, LUA_REGISTRYINDEX, "transformmeta");
lua_setmetatable(state, -2);
return 1;
}
static int api_rendericon_modelviewprojmatrix(lua_State* state) {
const struct RenderItemIconEvent* event = require_self_userdata(state, "modelviewprojmatrix");
const size_t model = luaL_checkinteger(state, 2);
struct Transform3D* transform = lua_newuserdata(state, sizeof(struct Transform3D));
*transform = event->icon->models[model - 1].viewproj_matrix;
lua_getfield(state, LUA_REGISTRYINDEX, "transformmeta");
lua_setmetatable(state, -2);
return 1;
}
static int api_repositionevent_xywh(lua_State* state) {
const struct RepositionEvent* event = require_self_userdata(state, "xywh");
lua_pushinteger(state, event->x);
@@ -1480,6 +1554,7 @@ static struct ApiFuncTemplate bolt_functions[] = {
BOLTFUNC(onrender2d),
BOLTFUNC(onrender3d),
BOLTFUNC(onrendericon),
BOLTFUNC(onminimap),
BOLTFUNC(onswapbuffers),
BOLTFUNC(onmousemotion),
@@ -1530,7 +1605,7 @@ static struct ApiFuncTemplate render2d_functions[] = {
static struct ApiFuncTemplate render3d_functions[] = {
BOLTFUNC(vertexcount, render3d),
BOLTFUNC(vertexxyz, render3d),
BOLTFUNC(vertexpoint, render3d),
BOLTFUNC(modelmatrix, render3d),
BOLTFUNC(viewmatrix, render3d),
BOLTFUNC(projectionmatrix, render3d),
@@ -1548,6 +1623,18 @@ static struct ApiFuncTemplate render3d_functions[] = {
BOLTALIAS(vertexcolour, vertexcolor, render3d),
};
static struct ApiFuncTemplate rendericon_functions[] = {
BOLTFUNC(xywh, rendericon),
BOLTFUNC(modelcount, rendericon),
BOLTFUNC(modelvertexcount, rendericon),
BOLTFUNC(modelvertexpoint, rendericon),
BOLTFUNC(modelvertexcolour, rendericon),
BOLTFUNC(modelviewmatrix, rendericon),
BOLTFUNC(modelprojectionmatrix, rendericon),
BOLTFUNC(modelviewprojmatrix, rendericon),
BOLTALIAS(modelvertexcolour, modelvertexcolor, rendericon),
};
static struct ApiFuncTemplate minimap_functions[] = {
BOLTFUNC(angle, minimap),
BOLTFUNC(scale, minimap),
@@ -1712,6 +1799,7 @@ void _bolt_api_push_metatable_##NAME(lua_State* state) { \
DEFPUSHMETA(render2d)
DEFPUSHMETA(render3d)
DEFPUSHMETA(rendericon)
DEFPUSHMETA(minimap)
DEFPUSHMETA(point)
DEFPUSHMETA(transform)

View File

@@ -37,6 +37,7 @@ struct ExternalBrowser {
void _bolt_api_push_bolt_table(lua_State*);
void _bolt_api_push_metatable_render2d(lua_State*);
void _bolt_api_push_metatable_render3d(lua_State*);
void _bolt_api_push_metatable_rendericon(lua_State*);
void _bolt_api_push_metatable_minimap(lua_State*);
void _bolt_api_push_metatable_point(lua_State*);
void _bolt_api_push_metatable_transform(lua_State*);

View File

@@ -361,6 +361,13 @@ void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
LOG("glViewport end\n");
}
void glTexParameteri(GLenum target, GLenum pname, GLint param) {
LOG("glTexParameteri\n");
libgl.TexParameteri(target, pname, param);
_bolt_gl_onTexParameteri(target, pname, param);
LOG("glTexParameteri end\n");
}
void* eglGetProcAddress(const char* name) {
LOG("eglGetProcAddress('%s')\n", name);
void* ret = _bolt_gl_GetProcAddress(name);
@@ -739,6 +746,8 @@ static void* _bolt_dl_lookup(void* handle, const char* symbol) {
if (strcmp(symbol, "glTexSubImage2D") == 0) return glTexSubImage2D;
if (strcmp(symbol, "glDeleteTextures") == 0) return glDeleteTextures;
if (strcmp(symbol, "glClear") == 0) return glClear;
if (strcmp(symbol, "glViewport") == 0) return glViewport;
if (strcmp(symbol, "glTexParameteri") == 0) return glTexParameteri;
} else if (handle == libxcb_addr) {
if (strcmp(symbol, "xcb_poll_for_event") == 0) return xcb_poll_for_event;
if (strcmp(symbol, "xcb_poll_for_queued_event") == 0) return xcb_poll_for_queued_event;