Skip to content

Commit

Permalink
library: return depth from aspixels
Browse files Browse the repository at this point in the history
  • Loading branch information
Adamcake committed Dec 4, 2024
1 parent bc05532 commit 925353d
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 10 deletions.
49 changes: 44 additions & 5 deletions src/library/doc.texi
Original file line number Diff line number Diff line change
Expand Up @@ -1791,14 +1791,53 @@ Returns the X, Y and Z values for this point.
@subsection aspixels

For a point that's been transformed into 3D screen space, this function
returns its X and Y in pixels, with (0, 0) being the top-left of the
game.
returns its X, Y, and depth. X and Y are in pixels with (0, 0) being the
top-left of the inner area of the game window. The the depth value is
logarithmic: -1.0 is very near the camera, 0.0 is about one tile away
from the camera, and +1.0 is the maximum render distance away from the
camera. Depth values outside that range indicate that the point is
probably behind the camera.

This is only useful for a point in model coordinates that has been
transformed by a @ref{render3d-modelmatrix}, then by a
@ref{render3d-viewprojmatrix}. In any other case the result will
@example lua
@verbatim
local xpixel, ypixel, depth = mypoint:aspixels()
if depth >= -1.0 and depth <= 1.0 then
-- pixel coordinates are valid, do something with them
end
@end verbatim
@end example

This is only useful for a point in world coordinates that has been
transformed by a @ref{render3d-viewprojmatrix} (or by a view and
projection matrix separately). In any other case the result will
probably not be meaningful.

To help with understanding everything this function does, here's an
equivalent Lua function with comments:

@example lua
@verbatim
local function aspixels(point)
local x, y, z = point:get()
-- get the X, Y, width and height of the 3D game view
local gx, gy, gw, gh = bolt.gameviewxywh()
-- x is in the range [-1.0, +1.0], so we need to map that range onto
-- the game view, like so:
local pixelx = ((x + 1.0) * gw / 2.0) + gx
-- same as above, but we also need to invert y because GPUs think -1.0
-- is the bottom of the screen, and we want points to be relative to
-- the top-left, not the bottom-left
local pixely = ((-y + 1.0) * gh / 2.0) + gy
-- leave depth as-is
return pixelx, pixely, z
end
@end verbatim
@end example

@node objects-transform
@section Transform

Expand Down
14 changes: 9 additions & 5 deletions src/library/plugin/plugin_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -857,23 +857,27 @@ static int api_point_get(lua_State* state) {

static int api_point_aspixels(lua_State* state) {
const struct Point3D* point = require_self_userdata(state, "aspixels");
double x, y;
int game_view_x, game_view_y, game_view_w, game_view_h;
const struct PluginManagedFunctions* managed_functions = _bolt_plugin_managed_functions();
managed_functions->game_view_rect(&game_view_x, &game_view_y, &game_view_w, &game_view_h);
double x, y, depth;
if (point->integer) {
x = (double)point->xyzh.ints[0];
y = (double)point->xyzh.ints[1];
depth = (double)point->xyzh.ints[2];
} else if (!point->homogenous) {
x = point->xyzh.floats[0];
y = point->xyzh.floats[1];
depth = point->xyzh.floats[2];
} else {
x = point->xyzh.floats[0] / point->xyzh.floats[3];
y = point->xyzh.floats[1] / point->xyzh.floats[3];
depth = point->xyzh.floats[2] / point->xyzh.floats[3];
}
int game_view_x, game_view_y, game_view_w, game_view_h;
const struct PluginManagedFunctions* managed_functions = _bolt_plugin_managed_functions();
managed_functions->game_view_rect(&game_view_x, &game_view_y, &game_view_w, &game_view_h);
lua_pushnumber(state, ((x + 1.0) * game_view_w / 2.0) + (double)game_view_x);
lua_pushnumber(state, ((-y + 1.0) * game_view_h / 2.0) + (double)game_view_y);
return 2;
lua_pushnumber(state, depth);
return 3;
}

#define LENGTH(N1, N2, N3) sqrt((N1 * N1) + (N2 * N2) + (N3 * N3))
Expand Down

0 comments on commit 925353d

Please sign in to comment.