diff --git a/src/hardware/CMakeLists.txt b/src/hardware/CMakeLists.txt index 38358debe..c9590410d 100644 --- a/src/hardware/CMakeLists.txt +++ b/src/hardware/CMakeLists.txt @@ -18,5 +18,6 @@ target_sources(BLANKART PRIVATE hw_plane.c hw_segs.c hw_shaders.c + hw_portal.c r_opengl/r_opengl.c ) diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 1ec637413..8eea81149 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -116,6 +116,38 @@ typedef struct gl_vissprite_s void HWR_ObjectLightLevelPost(gl_vissprite_t *spr, const sector_t *sector, INT32 *lightlevel, boolean model); +typedef struct +{ + // Viewport. + fixed_t viewx; + fixed_t viewy; + fixed_t viewz; + angle_t viewangle; + + seg_t *seg; // seg that is used for drawing to the stencil buffer + line_t *clipline; + + // angles for the left and right edges of the portal + // relative to the viewpoint + angle_t angle1; + angle_t angle2; +} gl_portal_t; + +typedef struct +{ + gl_portal_t *portals; + unsigned int size; + unsigned int capacity; +} gl_portal_array_t; + +// -------- +// hw_main.c +// ------- + +void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolean is_skybox, boolean timing, gl_portal_t *rootportal); +void HWR_PrepareTransform(player_t *player, boolean is_skybox); +void HWR_ResetClipper(void); + // -------- // hw_map.c // -------- @@ -230,6 +262,32 @@ UINT32 HWR_SortVisSprites(void); void HWR_DrawSprites(void); void HWR_ProjectBoundingBox(mobj_t *thing); +// -------- +// hw_portal.c +// -------- + +#define INIT_PORTAL_ARRAY_SIZE 4 + +void HWR_PortalFrame(gl_portal_t *portal, boolean set_culling); +gl_portal_array_t *HWR_GetPortalArray(void); +boolean HWR_AddPortal(line_t *start, line_t *dest, seg_t *seg); +void HWR_ClearPortals(void); +void HWR_PortalClipping(gl_portal_t *portal); +void HWR_RenderPortalSeg(seg_t *seg); +void HWR_SetStencilState(INT32 state); +void HWR_RenderDepthEraser(boolean visible); +void HWR_RenderPortal(gl_portal_t *portal, gl_portal_t *rootportal, player_t *player, boolean is_skybox); + +extern INT32 gl_portal_level; + +extern boolean gl_drawing_stencil; +extern sector_t *gl_portalcullsector; +extern line_t *gl_portalclipline; + +extern boolean gl_printportals; +extern INT32 gl_debugportal; + + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index f5362a7ae..172fc0d3d 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -111,195 +111,6 @@ static float gl_fovlud; static angle_t gl_aimingangle; -/* Portal stuff */ - -// TODO probably put this to a separate file? - -typedef struct -{ - // Viewport. - fixed_t viewx; - fixed_t viewy; - fixed_t viewz; - angle_t viewangle; - - seg_t *seg; // seg that is used for drawing to the stencil buffer - line_t *clipline; - - // angles for the left and right edges of the portal - // relative to the viewpoint - angle_t angle1; - angle_t angle2; -} gl_portal_t; - -#define INIT_PORTAL_ARRAY_SIZE 4 -typedef struct -{ - gl_portal_t *portals; - unsigned int size; - unsigned int capacity; -} gl_portal_array_t; - -// TODO magic number 16 -gl_portal_array_t gl_portal_arrays[MAXPORTALS_CAP+1] = {0}; - -INT32 gl_portal_level = 0; // portal recursion level - -boolean gl_drawing_stencil = false; // used when drawing segs to stencil buffer -sector_t *gl_portalcullsector = NULL; -line_t *gl_portalclipline = NULL; - -// debug tools -boolean gl_printportals = false; // print info about portals on this frame -INT32 gl_debugportal = 0; // hide main viewpoint and only render this portal without stencil - -static void HWR_PortalFrame(gl_portal_t *portal, boolean set_culling) -{ - viewx = portal->viewx; - viewy = portal->viewy; - viewz = portal->viewz; - - viewangle = portal->viewangle; - viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); - viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); - - // set_culling will be true if RenderBSPNode is about to be called - // so need to enable portal culling for that - if (set_culling) - { - gl_portalcullsector = portal->clipline->frontsector; - gl_portalclipline = portal->clipline; - } -} - -// get currently used portal array -static gl_portal_array_t *HWR_GetPortalArray(void) -{ - INT32 level = gl_portal_level; - if (gl_rendering_skybox) - level++; - return &gl_portal_arrays[level]; -} - -// TODO move to r_main.c next to fixed point functions? - -// More precise version of R_PointToAngle2 using floats and atan2. -static angle_t R_PointToAngle2Precise(fixed_t pviewx, fixed_t pviewy, fixed_t x, fixed_t y) -{ - fixed_t dx = x - pviewx; - fixed_t dy = y - pviewy; - float radians; - - if (!dx && !dy) - return 0; - - // no need for correct scale with FIXED_TO_FLOAT here - // since we're just calculating the angle - radians = atan2(dy, dx); - - return (angle_t)(radians / M_PI * ANGLE_180); -} - -// More precise version of R_PointToDist2 using floats and sqrt. -static fixed_t R_PointToDist2Precise(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1) -{ - // float-fixed conversions can be omitted here - // because they cancel each other out in this case - - float dx = px1 - px2; - float dy = py1 - py2; - double result = sqrt(dx*dx + dy*dy); - - return (fixed_t)result; -} - -boolean HWR_AddPortal(line_t *start, line_t *dest, seg_t *seg) -{ - gl_portal_array_t *array; - gl_portal_t *portal; - - angle_t dangle; - fixed_t disttopoint; - angle_t angtopoint; - vertex_t dest_c, start_c; - - if ((gl_portal_level + gl_rendering_skybox) >= cv_maxportals.value || - (gl_debugportal && - (gl_debugportal != (start-lines) || gl_portal_level))) - { - return false; - } - if (gl_debugportal) - gl_debugportal = -1; // skip other portal segs from the same line - - array = HWR_GetPortalArray(); - - // yet another dynamic array - if (!array->portals) - { - array->capacity = INIT_PORTAL_ARRAY_SIZE; - array->portals = Z_Malloc(sizeof(gl_portal_t) * array->capacity, PU_LEVEL, - &array->portals); - } - else if (array->size == array->capacity) - { - array->capacity *= 2; - array->portals = Z_Realloc(array->portals, sizeof(gl_portal_t) * array->capacity, - PU_LEVEL, &array->portals); - } - - portal = &array->portals[array->size++]; - - // Most fixed-point calculations and trigonometric function tables are replaced by - // floats and cmath library calls in this part to improve the precision of the - // location and angle of the new viewpoint. - // - // This reduces artefacts on the edges of portals, showing thin lines/pixels - // of the underlying graphics. (for example the sky texture) It's not 100% - // perfectly aligned and artefact-free, but looks noticeably - // better than the original code. I'm not even sure if it's this - // code or the nodebuilder or hw_map or something else causing the remaining issues.. - //#define R_PointToAngle2Precise R_PointToAngle2 - //#define R_PointToDist2Precise R_PointToDist2 - dangle = R_PointToAngle2Precise(0,0,dest->dx,dest->dy) - R_PointToAngle2Precise(start->dx,start->dy,0,0); - - // looking glass center - start_c.x = start->v1->x/2 + start->v2->x/2; - start_c.y = start->v1->y/2 + start->v2->y/2; - - // other side center - dest_c.x = dest->v1->x/2 + dest->v2->x/2; - dest_c.y = dest->v1->y/2 + dest->v2->y/2; - - disttopoint = R_PointToDist2Precise(start_c.x, start_c.y, viewx, viewy); - angtopoint = R_PointToAngle2Precise(start_c.x, start_c.y, viewx, viewy); - angtopoint += dangle; - - float fang = ((float)angtopoint / 4294967296.0f) * 2.0f * M_PI; - - //portal->viewx = dest_c.x + FixedMul(FINECOSINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); - //portal->viewy = dest_c.y + FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); - //portal->viewx = dest_c.x + FixedMul(FLOAT_TO_FIXED(cos(fang)), disttopoint); - //portal->viewy = dest_c.y + FixedMul(FLOAT_TO_FIXED(sin(fang)), disttopoint); - // cos and sin are just scaling disttopoint so no need for float-fixed conversions - portal->viewx = dest_c.x + (fixed_t)(cos(fang) * disttopoint); - portal->viewy = dest_c.y + (fixed_t)(sin(fang) * disttopoint); - portal->viewz = viewz + dest->frontsector->floorheight - start->frontsector->floorheight; - portal->viewangle = viewangle + dangle; - portal->seg = seg; - portal->clipline = dest; - - portal->angle1 = R_PointToAngle64(seg->v1->x, seg->v1->y) + dangle; - portal->angle2 = R_PointToAngle64(seg->v2->x, seg->v2->y) + dangle; - - return true; -} - -static void HWR_ClearPortals(void) -{ - HWR_GetPortalArray()->size = 0; -} - // ========================================================================== // Lighting // ========================================================================== @@ -618,7 +429,7 @@ void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox, gl_aimingangle = temp_aimingangle; } -static void HWR_ResetClipper(void) +void HWR_ResetClipper(void) { angle_t a1 = gld_FrustumAngle(gl_aimingangle); gld_clipper_Clear(); @@ -628,12 +439,6 @@ static void HWR_ResetClipper(void) #endif } -// clip the area outside the portal destination window -static void HWR_PortalClipping(gl_portal_t *portal) -{ - gld_clipper_SafeAddClipRange(portal->angle1, portal->angle2); -} - // Tells the backend are shaders being used for 3d rendering. static void HWR_SetShaderState(void) { @@ -642,7 +447,7 @@ static void HWR_SetShaderState(void) // prepare all transform related variables based on the current "frame" // (R_SetupFrame etc) -static void HWR_PrepareTransform(player_t *player, boolean is_skybox) +void HWR_PrepareTransform(player_t *player, boolean is_skybox) { UINT8 viewnum = R_GetViewNumber(); camera_t *thiscam = &camera[viewnum]; @@ -707,88 +512,7 @@ static void HWR_LeaveSkyboxState(void) gl_rendering_skybox = false; } -static void HWR_RenderPortalSeg(seg_t *seg) -{ - gl_drawing_stencil = true; - gl_curline = seg; - gl_frontsector = seg->frontsector; - gl_backsector = seg->backsector; - HWR_ProcessSeg(); - gl_drawing_stencil = false; - // need to work around the r_opengl PF_Invisible bug with this call - // similarly as in the linkdraw hack in HWR_DrawSprites - GL_SetBlend(PF_Translucent|PF_Occlude|PF_Masked); -} - -static void HWR_SetStencilState(INT32 state) -{ - GL_SetStencilMode(state, gl_portal_level); -} - -// clear the depth buffer from the stenciled area so portal -// content doesn't get clipped by previous buffer content -// (glClear ignores the stencil buffer so can't be used for this purpose) -static void HWR_RenderDepthEraser(boolean visible) -{ - FOutVector verts[4] = {0}; - FBITFIELD blendflags = PF_Occlude|PF_NoDepthTest|PF_NoTexture|PF_NoAlphaTest; - if (!visible) - blendflags |= PF_Invisible; - // so this is apparently how you draw the far clipping plane when - // pfnSetTransform(NULL) is active - const float a = FAR_CLIPPING_PLANE; - verts[0].x = -a; verts[0].y = -a; verts[0].z = a; - verts[1].x = -a; verts[1].y = a; verts[1].z = a; - verts[2].x = a; verts[2].y = a; verts[2].z = a; - verts[3].x = a; verts[3].y = -a; verts[3].z = a; - GL_SetTransform(NULL); - GL_DrawPolygon(NULL, verts, 4, blendflags); -} - -static void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolean is_skybox, boolean timing, gl_portal_t *rootportal); - -static void HWR_RenderPortal(gl_portal_t *portal, gl_portal_t *rootportal, player_t *player, boolean is_skybox) -{ - HWR_PushSpriteState(); - HWR_PushDrawNodeState(); - - if (!gl_debugportal) - { - HWR_SetStencilState(HWD_STENCIL_PORTAL_BEGIN); - HWR_RenderPortalSeg(portal->seg); - } - - gl_portal_level++; - if (!gl_debugportal) - HWR_SetStencilState(HWD_STENCIL_PORTAL_INSIDE); - - HWR_RenderDepthEraser(true); - - HWR_PortalFrame(portal, true); - HWR_RenderViewpoint(player, true, is_skybox, false, portal); - // restore previous frame and transform - if (rootportal) - HWR_PortalFrame(rootportal, false); - else if (is_skybox) - R_SkyboxFrame(viewssnum); - else - R_SetupFrame(viewssnum, is_skybox); - HWR_PrepareTransform(player, is_skybox); - GL_SetTransform(&atransform); - HWR_ResetClipper(); - - if (!gl_debugportal) - { - HWR_SetStencilState(HWD_STENCIL_PORTAL_FINISH); - HWR_RenderPortalSeg(portal->seg); - } - gl_portal_level--; - - HWR_PopSpriteState(); - HWR_PopDrawNodeState(); -} - -static void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolean is_skybox, boolean timing, gl_portal_t *rootportal) +void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolean is_skybox, boolean timing, gl_portal_t *rootportal) { unsigned int i; gl_portal_array_t *portal_array; diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index cce9daf45..d367d3e98 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -164,21 +164,6 @@ extern boolean gl_shadersavailable; extern boolean gl_rendering_skybox; -/* Portal stuff */ - -// TODO probably put this to a separate file? - -boolean HWR_AddPortal(line_t *start, line_t *dest, seg_t *seg); - -extern INT32 gl_portal_level; - -extern boolean gl_drawing_stencil; -extern sector_t *gl_portalcullsector; -extern line_t *gl_portalclipline; - -extern boolean gl_printportals; -extern INT32 gl_debugportal; - #ifdef __cplusplus } // extern "C" #endif diff --git a/src/hardware/hw_portal.c b/src/hardware/hw_portal.c new file mode 100644 index 000000000..6b16f9481 --- /dev/null +++ b/src/hardware/hw_portal.c @@ -0,0 +1,235 @@ +// BLANKART +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file hw_portal.c +/// \brief Visual Portal rendering + +#ifdef HWRENDER +#include "hw_glob.h" +#include "hw_clip.h" +#include "hw_gpu.h" +#include "../r_local.h" +#include "../g_game.h" +#include "../r_fps.h" +#include "../z_zone.h" + +// TODO magic number 16 +gl_portal_array_t gl_portal_arrays[MAXPORTALS_CAP+1] = {0}; + +INT32 gl_portal_level = 0; // portal recursion level + +boolean gl_drawing_stencil = false; // used when drawing segs to stencil buffer +sector_t *gl_portalcullsector = NULL; +line_t *gl_portalclipline = NULL; + +// debug tools +boolean gl_printportals = false; // print info about portals on this frame +INT32 gl_debugportal = 0; // hide main viewpoint and only render this portal without stencil + +void HWR_PortalFrame(gl_portal_t *portal, boolean set_culling) +{ + viewx = portal->viewx; + viewy = portal->viewy; + viewz = portal->viewz; + + viewangle = portal->viewangle; + viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); + viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); + + // set_culling will be true if RenderBSPNode is about to be called + // so need to enable portal culling for that + if (set_culling) + { + gl_portalcullsector = portal->clipline->frontsector; + gl_portalclipline = portal->clipline; + } +} + +// get currently used portal array +gl_portal_array_t *HWR_GetPortalArray(void) +{ + INT32 level = gl_portal_level; + if (gl_rendering_skybox) + level++; + return &gl_portal_arrays[level]; +} + +boolean HWR_AddPortal(line_t *start, line_t *dest, seg_t *seg) +{ + gl_portal_array_t *array; + gl_portal_t *portal; + + angle_t dangle; + fixed_t disttopoint; + angle_t angtopoint; + vertex_t dest_c, start_c; + + if ((gl_portal_level + gl_rendering_skybox) >= cv_maxportals.value || + (gl_debugportal && + (gl_debugportal != (start-lines) || gl_portal_level))) + { + return false; + } + if (gl_debugportal) + gl_debugportal = -1; // skip other portal segs from the same line + + array = HWR_GetPortalArray(); + + // yet another dynamic array + if (!array->portals) + { + array->capacity = INIT_PORTAL_ARRAY_SIZE; + array->portals = Z_Malloc(sizeof(gl_portal_t) * array->capacity, PU_LEVEL, + &array->portals); + } + else if (array->size == array->capacity) + { + array->capacity *= 2; + array->portals = Z_Realloc(array->portals, sizeof(gl_portal_t) * array->capacity, + PU_LEVEL, &array->portals); + } + + portal = &array->portals[array->size++]; + + // Most fixed-point calculations and trigonometric function tables are replaced by + // floats and cmath library calls in this part to improve the precision of the + // location and angle of the new viewpoint. + // + // This reduces artefacts on the edges of portals, showing thin lines/pixels + // of the underlying graphics. (for example the sky texture) It's not 100% + // perfectly aligned and artefact-free, but looks noticeably + // better than the original code. I'm not even sure if it's this + // code or the nodebuilder or hw_map or something else causing the remaining issues.. + //#define R_PointToAngle2Precise R_PointToAngle2 + //#define R_PointToDist2Precise R_PointToDist2 + dangle = R_PointToAngle2Precise(0,0,dest->dx,dest->dy) - R_PointToAngle2Precise(start->dx,start->dy,0,0); + + // looking glass center + start_c.x = start->v1->x/2 + start->v2->x/2; + start_c.y = start->v1->y/2 + start->v2->y/2; + + // other side center + dest_c.x = dest->v1->x/2 + dest->v2->x/2; + dest_c.y = dest->v1->y/2 + dest->v2->y/2; + + disttopoint = R_PointToDist2Precise(start_c.x, start_c.y, viewx, viewy); + angtopoint = R_PointToAngle2Precise(start_c.x, start_c.y, viewx, viewy); + angtopoint += dangle; + + float fang = ((float)angtopoint / 4294967296.0f) * 2.0f * M_PI; + + //portal->viewx = dest_c.x + FixedMul(FINECOSINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); + //portal->viewy = dest_c.y + FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); + //portal->viewx = dest_c.x + FixedMul(FLOAT_TO_FIXED(cos(fang)), disttopoint); + //portal->viewy = dest_c.y + FixedMul(FLOAT_TO_FIXED(sin(fang)), disttopoint); + // cos and sin are just scaling disttopoint so no need for float-fixed conversions + portal->viewx = dest_c.x + (fixed_t)(cos(fang) * disttopoint); + portal->viewy = dest_c.y + (fixed_t)(sin(fang) * disttopoint); + portal->viewz = viewz + dest->frontsector->floorheight - start->frontsector->floorheight; + portal->viewangle = viewangle + dangle; + portal->seg = seg; + portal->clipline = dest; + + portal->angle1 = R_PointToAngle64(seg->v1->x, seg->v1->y) + dangle; + portal->angle2 = R_PointToAngle64(seg->v2->x, seg->v2->y) + dangle; + + return true; +} + +void HWR_ClearPortals(void) +{ + HWR_GetPortalArray()->size = 0; +} + +// clip the area outside the portal destination window +void HWR_PortalClipping(gl_portal_t *portal) +{ + gld_clipper_SafeAddClipRange(portal->angle1, portal->angle2); +} + +void HWR_RenderPortalSeg(seg_t *seg) +{ + gl_drawing_stencil = true; + gl_curline = seg; + gl_frontsector = seg->frontsector; + gl_backsector = seg->backsector; + HWR_ProcessSeg(); + gl_drawing_stencil = false; + // need to work around the r_opengl PF_Invisible bug with this call + // similarly as in the linkdraw hack in HWR_DrawSprites + GL_SetBlend(PF_Translucent|PF_Occlude|PF_Masked); +} + +void HWR_SetStencilState(INT32 state) +{ + GL_SetStencilMode(state, gl_portal_level); +} + +// clear the depth buffer from the stenciled area so portal +// content doesn't get clipped by previous buffer content +// (glClear ignores the stencil buffer so can't be used for this purpose) +void HWR_RenderDepthEraser(boolean visible) +{ + FOutVector verts[4] = {0}; + FBITFIELD blendflags = PF_Occlude|PF_NoDepthTest|PF_NoTexture|PF_NoAlphaTest; + if (!visible) + blendflags |= PF_Invisible; + // so this is apparently how you draw the far clipping plane when + // pfnSetTransform(NULL) is active + const float a = FAR_CLIPPING_PLANE; + verts[0].x = -a; verts[0].y = -a; verts[0].z = a; + verts[1].x = -a; verts[1].y = a; verts[1].z = a; + verts[2].x = a; verts[2].y = a; verts[2].z = a; + verts[3].x = a; verts[3].y = -a; verts[3].z = a; + GL_SetTransform(NULL); + GL_DrawPolygon(NULL, verts, 4, blendflags); +} + +void HWR_RenderPortal(gl_portal_t *portal, gl_portal_t *rootportal, player_t *player, boolean is_skybox) +{ + HWR_PushSpriteState(); + HWR_PushDrawNodeState(); + + if (!gl_debugportal) + { + HWR_SetStencilState(HWD_STENCIL_PORTAL_BEGIN); + HWR_RenderPortalSeg(portal->seg); + } + + gl_portal_level++; + if (!gl_debugportal) + HWR_SetStencilState(HWD_STENCIL_PORTAL_INSIDE); + + HWR_RenderDepthEraser(true); + + HWR_PortalFrame(portal, true); + HWR_RenderViewpoint(player, true, is_skybox, false, portal); + // restore previous frame and transform + if (rootportal) + HWR_PortalFrame(rootportal, false); + else if (is_skybox) + R_SkyboxFrame(viewssnum); + else + R_SetupFrame(viewssnum, is_skybox); + HWR_PrepareTransform(player, is_skybox); + GL_SetTransform(&atransform); + HWR_ResetClipper(); + + if (!gl_debugportal) + { + HWR_SetStencilState(HWD_STENCIL_PORTAL_FINISH); + HWR_RenderPortalSeg(portal->seg); + } + gl_portal_level--; + + HWR_PopSpriteState(); + HWR_PopDrawNodeState(); +} + +#endif diff --git a/src/r_main.cpp b/src/r_main.cpp index c5849d980..72e71387f 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -412,6 +412,36 @@ angle_t R_PointToAngleFloat2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2) #undef ANGLE_180_DOUBLE #undef ANGLE_360_DOUBLE +// More precise version of R_PointToAngle2 using floats and atan2. +angle_t R_PointToAngle2Precise(fixed_t pviewx, fixed_t pviewy, fixed_t x, fixed_t y) +{ + fixed_t dx = x - pviewx; + fixed_t dy = y - pviewy; + float radians; + + if (!dx && !dy) + return 0; + + // no need for correct scale with FIXED_TO_FLOAT here + // since we're just calculating the angle + radians = atan2(dy, dx); + + return (angle_t)(radians / M_PI * ANGLE_180); +} + +// More precise version of R_PointToDist2 using floats and sqrt. +fixed_t R_PointToDist2Precise(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1) +{ + // float-fixed conversions can be omitted here + // because they cancel each other out in this case + + float dx = px1 - px2; + float dy = py1 - py2; + double result = sqrt(dx*dx + dy*dy); + + return (fixed_t)result; +} + // // R_ScaleFromGlobalAngle // Returns the texture mapping scale for the current line (horizontal span) diff --git a/src/r_main.h b/src/r_main.h index d5af7669a..e2b606935 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -88,6 +88,8 @@ angle_t R_PointToAnglePlayer(player_t *player, fixed_t x, fixed_t y); angle_t R_PointToAngle64(INT64 x, INT64 y); angle_t R_PointToAngle2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1); angle_t R_PointToAngleFloat2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); +angle_t R_PointToAngle2Precise(fixed_t pviewx, fixed_t pviewy, fixed_t x, fixed_t y); +fixed_t R_PointToDist2Precise(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1); #define R_PointToDist(x, y) R_PointToDist2(viewx, viewy, x, y) #define R_PointToDist2(px2, py2, px1, py1) FixedHypot((px1) - (px2), (py1) - (py2))