2006-04-13 20:47:06 +00:00
|
|
|
// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
|
2021-03-24 18:45:42 +00:00
|
|
|
// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
|
2006-04-13 20:47:06 +00:00
|
|
|
// Ken Silverman's official web site: "http://www.advsys.net/ken"
|
|
|
|
// See the included license file "BUILDLIC.TXT" for license info.
|
|
|
|
//
|
|
|
|
// This file has been modified from Ken Silverman's original release
|
2012-03-12 04:47:04 +00:00
|
|
|
// by Jonathon Fowler (jf@jonof.id.au)
|
2018-11-05 07:28:01 +00:00
|
|
|
// by the EDuke32 team (development@voidpoint.com)
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2018-11-18 18:09:48 +00:00
|
|
|
#define engine_c_
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2020-03-29 12:01:46 +00:00
|
|
|
#include "gl_load.h"
|
2006-04-13 20:47:06 +00:00
|
|
|
#include "build.h"
|
2020-09-06 10:44:58 +00:00
|
|
|
#include "automap.h"
|
2019-12-17 22:25:07 +00:00
|
|
|
|
2020-01-28 09:31:59 +00:00
|
|
|
#include "imagehelpers.h"
|
2018-11-18 18:09:48 +00:00
|
|
|
#include "engine_priv.h"
|
|
|
|
#include "palette.h"
|
2019-10-23 16:36:48 +00:00
|
|
|
#include "gamecvars.h"
|
2019-11-06 22:40:10 +00:00
|
|
|
#include "c_console.h"
|
|
|
|
#include "v_2ddrawer.h"
|
2019-11-08 22:02:52 +00:00
|
|
|
#include "v_draw.h"
|
2019-11-10 09:01:31 +00:00
|
|
|
#include "stats.h"
|
2020-10-04 16:31:48 +00:00
|
|
|
#include "razemenu.h"
|
2019-12-26 13:04:53 +00:00
|
|
|
#include "version.h"
|
2020-05-25 15:11:32 +00:00
|
|
|
#include "earcut.hpp"
|
2020-08-12 20:52:41 +00:00
|
|
|
#include "gamestate.h"
|
2020-08-28 07:06:49 +00:00
|
|
|
#include "inputstate.h"
|
|
|
|
#include "printf.h"
|
2020-11-10 21:07:45 +00:00
|
|
|
#include "gamecontrol.h"
|
2021-03-15 22:46:03 +00:00
|
|
|
#include "render.h"
|
2021-03-18 09:19:13 +00:00
|
|
|
#include "gamefuncs.h"
|
2021-04-05 11:55:36 +00:00
|
|
|
#include "hw_voxels.h"
|
2021-12-03 19:20:33 +00:00
|
|
|
#include "coreactor.h"
|
2018-11-18 18:09:48 +00:00
|
|
|
|
2011-03-04 08:50:58 +00:00
|
|
|
#ifdef USE_OPENGL
|
2011-10-02 07:18:17 +00:00
|
|
|
# include "mdsprite.h"
|
2008-12-02 10:44:39 +00:00
|
|
|
# include "polymost.h"
|
2019-12-23 18:37:40 +00:00
|
|
|
#include "v_video.h"
|
2019-10-04 16:12:03 +00:00
|
|
|
#include "../../glbackend/glbackend.h"
|
2020-03-29 12:01:46 +00:00
|
|
|
#include "gl_renderer.h"
|
2008-05-10 01:29:37 +00:00
|
|
|
#endif
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2020-01-28 21:41:07 +00:00
|
|
|
int32_t mdtims, omdtims;
|
2020-01-28 21:54:57 +00:00
|
|
|
|
|
|
|
float fcosglobalang, fsinglobalang;
|
2021-02-25 11:16:21 +00:00
|
|
|
float fydimen, fviewingrange;
|
2020-01-28 21:41:07 +00:00
|
|
|
|
2018-02-15 03:49:23 +00:00
|
|
|
uint8_t globalr = 255, globalg = 255, globalb = 255;
|
|
|
|
|
2015-05-19 22:05:20 +00:00
|
|
|
int16_t pskybits_override = -1;
|
2019-06-25 11:29:42 +00:00
|
|
|
static int16_t radarang[1280];
|
2012-11-05 02:49:08 +00:00
|
|
|
|
2019-04-18 17:24:30 +00:00
|
|
|
// adapted from build.c
|
2019-08-27 06:52:42 +00:00
|
|
|
static void getclosestpointonwall_internal(vec2_t const p, int32_t const dawall, vec2_t *const closest)
|
2019-04-18 17:24:30 +00:00
|
|
|
{
|
2019-06-25 11:28:25 +00:00
|
|
|
vec2_t const w = wall[dawall].pos;
|
2021-12-01 23:54:11 +00:00
|
|
|
vec2_t const w2 = wall[dawall].point2Wall()->pos;
|
2021-12-22 09:28:51 +00:00
|
|
|
vec2_t const d = { w2.X - w.X, w2.Y - w.Y };
|
2019-04-18 17:24:30 +00:00
|
|
|
|
2021-12-22 09:28:51 +00:00
|
|
|
int64_t i = d.X * ((int64_t)p.X - w.X) + d.Y * ((int64_t)p.Y - w.Y);
|
2019-04-18 17:24:30 +00:00
|
|
|
|
|
|
|
if (i <= 0)
|
|
|
|
{
|
|
|
|
*closest = w;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-12-22 09:28:51 +00:00
|
|
|
int64_t const j = (int64_t)d.X * d.X + (int64_t)d.Y * d.Y;
|
2019-04-18 17:24:30 +00:00
|
|
|
|
|
|
|
if (i >= j)
|
|
|
|
{
|
|
|
|
*closest = w2;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-07 23:06:24 +00:00
|
|
|
i = ((i << 15) / j) << 15;
|
2019-04-18 17:24:30 +00:00
|
|
|
|
2021-12-22 09:28:51 +00:00
|
|
|
*closest = { (int32_t)(w.X + ((d.X * i) >> 30)), (int32_t)(w.Y + ((d.Y * i) >> 30)) };
|
2019-04-18 17:24:30 +00:00
|
|
|
}
|
2011-03-02 21:21:47 +00:00
|
|
|
|
2021-03-19 14:12:54 +00:00
|
|
|
int32_t xdimen = -1, xdimenscale, xdimscale;
|
2014-11-28 08:14:00 +00:00
|
|
|
float fxdimen = -1.f;
|
2011-09-15 17:02:52 +00:00
|
|
|
int32_t ydimen;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2020-10-07 02:28:38 +00:00
|
|
|
int32_t globalposx, globalposy, globalposz;
|
2020-09-01 13:00:35 +00:00
|
|
|
fixed_t qglobalhoriz;
|
2014-10-25 03:32:26 +00:00
|
|
|
float fglobalposx, fglobalposy, fglobalposz;
|
2009-01-09 09:29:17 +00:00
|
|
|
int16_t globalang, globalcursectnum;
|
2020-09-01 13:00:35 +00:00
|
|
|
fixed_t qglobalang;
|
2020-09-20 18:39:11 +00:00
|
|
|
int32_t globalpal, globalfloorpal, cosglobalang, singlobalang;
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t cosviewingrangeglobalang, sinviewingrangeglobalang;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2020-07-03 07:38:42 +00:00
|
|
|
int32_t viewingrangerecip;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2012-01-26 21:58:08 +00:00
|
|
|
int32_t globalshade, globalorientation;
|
|
|
|
int16_t globalpicnum;
|
2020-07-14 15:35:19 +00:00
|
|
|
|
2012-01-26 21:58:08 +00:00
|
|
|
|
2014-04-05 11:28:06 +00:00
|
|
|
static int32_t globaly1, globalx2;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2011-03-13 11:59:32 +00:00
|
|
|
int16_t pointhighlight=-1, linehighlight=-1, highlightcnt=0;
|
2012-01-26 21:58:08 +00:00
|
|
|
|
|
|
|
static int16_t numhits;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Internal Engine Functions
|
|
|
|
//
|
|
|
|
|
2021-12-04 18:08:50 +00:00
|
|
|
BEGIN_BLD_NS
|
|
|
|
int qanimateoffs(int a1, int a2);
|
|
|
|
END_BLD_NS
|
2015-01-04 18:45:00 +00:00
|
|
|
|
2020-03-29 12:55:09 +00:00
|
|
|
//
|
|
|
|
// animateoffs (internal)
|
|
|
|
//
|
|
|
|
int32_t animateoffs(int const tilenum, int fakevar)
|
|
|
|
{
|
2021-12-04 18:08:50 +00:00
|
|
|
if (isBlood())
|
2020-03-29 12:55:09 +00:00
|
|
|
{
|
2021-12-04 18:08:50 +00:00
|
|
|
return Blood::qanimateoffs(tilenum, fakevar);
|
2020-03-29 12:55:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int const animnum = picanm[tilenum].num;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2020-03-29 12:55:09 +00:00
|
|
|
if (animnum <= 0)
|
|
|
|
return 0;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2020-08-25 21:57:27 +00:00
|
|
|
int const i = (int) I_GetBuildTime() >> (picanm[tilenum].sf & PICANM_ANIMSPEED_MASK);
|
2020-03-29 12:55:09 +00:00
|
|
|
int offs = 0;
|
|
|
|
|
|
|
|
switch (picanm[tilenum].sf & PICANM_ANIMTYPE_MASK)
|
|
|
|
{
|
|
|
|
case PICANM_ANIMTYPE_OSC:
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2020-03-29 12:55:09 +00:00
|
|
|
int k = (i % (animnum << 1));
|
|
|
|
offs = (k < animnum) ? k : (animnum << 1) - k;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PICANM_ANIMTYPE_FWD: offs = i % (animnum + 1); break;
|
|
|
|
case PICANM_ANIMTYPE_BACK: offs = -(i % (animnum + 1)); break;
|
|
|
|
}
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2020-03-29 12:55:09 +00:00
|
|
|
return offs;
|
|
|
|
}
|
2014-12-05 23:12:36 +00:00
|
|
|
|
2018-04-12 21:03:47 +00:00
|
|
|
static int32_t engineLoadTables(void)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2012-09-02 14:08:43 +00:00
|
|
|
static char tablesloaded = 0;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
|
|
|
if (tablesloaded == 0)
|
|
|
|
{
|
2012-09-02 14:08:43 +00:00
|
|
|
int32_t i;
|
|
|
|
|
|
|
|
for (i=0; i<=512; i++)
|
2021-11-02 22:31:09 +00:00
|
|
|
sintable[i] = int(sin(i * BAngRadian) * +SINTABLEUNIT);
|
2012-09-02 14:08:43 +00:00
|
|
|
for (i=513; i<1024; i++)
|
|
|
|
sintable[i] = sintable[1024-i];
|
|
|
|
for (i=1024; i<2048; i++)
|
|
|
|
sintable[i] = -sintable[i-1024];
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2012-09-02 14:08:43 +00:00
|
|
|
for (i=0; i<640; i++)
|
2020-11-22 08:20:16 +00:00
|
|
|
radarang[i] = atan((639.5 - i) / 160.) * (-64. / BAngRadian);
|
2012-09-02 14:08:43 +00:00
|
|
|
for (i=0; i<640; i++)
|
|
|
|
radarang[1279-i] = -radarang[i];
|
|
|
|
|
2006-04-13 20:47:06 +00:00
|
|
|
tablesloaded = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// lintersect (internal)
|
|
|
|
//
|
2019-04-05 17:45:16 +00:00
|
|
|
int32_t lintersect(const int32_t originX, const int32_t originY, const int32_t originZ,
|
|
|
|
const int32_t destX, const int32_t destY, const int32_t destZ,
|
|
|
|
const int32_t lineStartX, const int32_t lineStartY, const int32_t lineEndX, const int32_t lineEndY,
|
|
|
|
int32_t *intersectionX, int32_t *intersectionY, int32_t *intersectionZ)
|
2007-12-12 17:42:14 +00:00
|
|
|
{
|
2019-04-05 17:45:16 +00:00
|
|
|
const vec2_t ray = { destX-originX,
|
|
|
|
destY-originY };
|
|
|
|
const vec2_t lineVec = { lineEndX-lineStartX,
|
|
|
|
lineEndY-lineStartY };
|
|
|
|
const vec2_t originDiff = { lineStartX-originX,
|
|
|
|
lineStartY-originY };
|
2015-01-11 04:56:58 +00:00
|
|
|
|
2021-12-22 09:28:51 +00:00
|
|
|
const int32_t rayCrossLineVec = ray.X*lineVec.Y - ray.Y*lineVec.X;
|
|
|
|
const int32_t originDiffCrossRay = originDiff.X*ray.Y - originDiff.Y*ray.X;
|
2015-01-11 04:56:58 +00:00
|
|
|
|
2019-04-05 17:45:16 +00:00
|
|
|
if (rayCrossLineVec == 0)
|
2018-05-15 16:45:34 +00:00
|
|
|
{
|
2019-09-22 19:26:07 +00:00
|
|
|
if (originDiffCrossRay != 0 || enginecompatibility_mode != ENGINECOMPATIBILITY_NONE)
|
2019-04-05 17:45:16 +00:00
|
|
|
{
|
|
|
|
// line segments are parallel
|
|
|
|
return 0;
|
|
|
|
}
|
2018-12-15 01:40:31 +00:00
|
|
|
|
2019-04-05 17:45:16 +00:00
|
|
|
// line segments are collinear
|
2021-12-22 09:28:51 +00:00
|
|
|
const int32_t rayLengthSquared = ray.X*ray.X + ray.Y*ray.Y;
|
|
|
|
const int32_t rayDotOriginDiff = ray.X*originDiff.X + ray.Y*originDiff.Y;
|
|
|
|
const int32_t rayDotLineEndDiff = rayDotOriginDiff + ray.X*lineVec.X + ray.Y*lineVec.Y;
|
2019-04-05 17:45:19 +00:00
|
|
|
int64_t t = min(rayDotOriginDiff, rayDotLineEndDiff);
|
2019-04-05 17:45:16 +00:00
|
|
|
if (rayDotOriginDiff < 0)
|
|
|
|
{
|
|
|
|
if (rayDotLineEndDiff < 0)
|
|
|
|
return 0;
|
2018-12-15 01:40:31 +00:00
|
|
|
|
2019-04-05 17:45:16 +00:00
|
|
|
t = 0;
|
|
|
|
}
|
|
|
|
else if (rayDotOriginDiff > rayLengthSquared)
|
|
|
|
{
|
|
|
|
if (rayDotLineEndDiff > rayLengthSquared)
|
|
|
|
return 0;
|
2018-12-15 01:40:31 +00:00
|
|
|
|
2019-04-05 17:45:16 +00:00
|
|
|
t = rayDotLineEndDiff;
|
|
|
|
}
|
2020-07-14 18:21:16 +00:00
|
|
|
t = (t << 24) / rayLengthSquared;
|
2019-04-05 17:45:19 +00:00
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
*intersectionX = originX + MulScale(ray.X, t, 24);
|
2021-12-22 09:28:51 +00:00
|
|
|
*intersectionY = originY + MulScale(ray.Y, t, 24);
|
2021-01-04 11:36:54 +00:00
|
|
|
*intersectionZ = originZ + MulScale(destZ-originZ, t, 24);
|
2018-12-15 01:40:31 +00:00
|
|
|
|
2019-04-05 17:45:16 +00:00
|
|
|
return 1;
|
2018-05-15 16:45:34 +00:00
|
|
|
}
|
2018-12-15 01:40:31 +00:00
|
|
|
|
2021-12-22 09:28:51 +00:00
|
|
|
const int32_t originDiffCrossLineVec = originDiff.X*lineVec.Y - originDiff.Y*lineVec.X;
|
2019-04-05 17:45:16 +00:00
|
|
|
static const int32_t signBit = 1u<<31u;
|
2019-04-05 17:45:19 +00:00
|
|
|
// Any point on either line can be expressed as p+t*r and q+u*s
|
|
|
|
// The two line segments intersect when we can find a t & u such that p+t*r = q+u*s
|
|
|
|
// If the point is outside of the bounds of the line segment, we know we don't have an intersection.
|
2019-04-05 17:45:16 +00:00
|
|
|
// t is < 0 if (originDiffCrossLineVec^rayCrossLineVec) & signBit)
|
|
|
|
// u is < 0 if (originDiffCrossRay^rayCrossLineVec) & signBit
|
2021-01-04 12:02:00 +00:00
|
|
|
// t is > 1 if abs(originDiffCrossLineVec) > abs(rayCrossLineVec)
|
|
|
|
// u is > 1 if abs(originDiffCrossRay) > abs(rayCrossLineVec)
|
2019-04-05 17:45:19 +00:00
|
|
|
// where int32_t u = tabledivide64(((int64_t) originDiffCrossRay) << 24L, rayCrossLineVec);
|
|
|
|
if (((originDiffCrossLineVec^rayCrossLineVec) & signBit) ||
|
|
|
|
((originDiffCrossRay^rayCrossLineVec) & signBit) ||
|
2021-01-04 12:02:00 +00:00
|
|
|
abs(originDiffCrossLineVec) > abs(rayCrossLineVec) ||
|
|
|
|
abs(originDiffCrossRay) > abs(rayCrossLineVec))
|
2019-04-05 17:45:16 +00:00
|
|
|
{
|
|
|
|
// line segments do not overlap
|
|
|
|
return 0;
|
|
|
|
}
|
2019-04-05 17:45:19 +00:00
|
|
|
|
2020-07-14 18:21:16 +00:00
|
|
|
int64_t t = (int64_t(originDiffCrossLineVec) << 24) / rayCrossLineVec;
|
2019-04-05 17:45:19 +00:00
|
|
|
// For sake of completeness/readability, alternative to the above approach for an early out & avoidance of an extra division:
|
|
|
|
|
2021-12-22 09:26:51 +00:00
|
|
|
*intersectionX = originX + MulScale(ray.X, t, 24);
|
2021-12-22 09:28:51 +00:00
|
|
|
*intersectionY = originY + MulScale(ray.Y, t, 24);
|
2021-01-04 11:36:54 +00:00
|
|
|
*intersectionZ = originZ + MulScale(destZ-originZ, t, 24);
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2015-01-11 04:56:58 +00:00
|
|
|
return 1;
|
2010-09-27 21:52:04 +00:00
|
|
|
}
|
|
|
|
|
2006-04-13 20:47:06 +00:00
|
|
|
//
|
|
|
|
// rintersect (internal)
|
|
|
|
//
|
2021-07-04 11:05:33 +00:00
|
|
|
// returns: -1 if didn't intersect, coefficient (x3--x4 fraction)<<16 else
|
2016-06-21 00:33:30 +00:00
|
|
|
int32_t rintersect(int32_t x1, int32_t y1, int32_t z1,
|
2019-06-25 11:28:40 +00:00
|
|
|
int32_t vx, int32_t vy, int32_t vz,
|
2016-06-21 00:33:30 +00:00
|
|
|
int32_t x3, int32_t y3, int32_t x4, int32_t y4,
|
|
|
|
int32_t *intx, int32_t *inty, int32_t *intz)
|
2007-12-12 17:42:14 +00:00
|
|
|
{
|
|
|
|
//p1 towards p2 is a ray
|
2012-06-13 23:13:39 +00:00
|
|
|
|
2019-06-25 11:28:40 +00:00
|
|
|
int64_t const x34=x3-x4, y34=y3-y4;
|
|
|
|
int64_t const x31=x3-x1, y31=y3-y1;
|
|
|
|
|
|
|
|
int64_t const bot = vx*y34 - vy*x34;
|
|
|
|
int64_t const topt = x31*y34 - y31*x34;
|
2013-03-24 18:55:40 +00:00
|
|
|
|
|
|
|
if (bot == 0)
|
|
|
|
return -1;
|
2012-06-13 23:13:39 +00:00
|
|
|
|
2019-06-25 11:28:40 +00:00
|
|
|
int64_t const topu = vx*y31 - vy*x31;
|
|
|
|
|
|
|
|
if (bot > 0 && (topt < 0 || topu < 0 || topu >= bot))
|
|
|
|
return -1;
|
|
|
|
else if (bot < 0 && (topt > 0 || topu > 0 || topu <= bot))
|
|
|
|
return -1;
|
|
|
|
|
2020-09-13 18:15:46 +00:00
|
|
|
int64_t t = (topt << 16) / bot;
|
|
|
|
*intx = x1 + ((vx*t) >> 16);
|
|
|
|
*inty = y1 + ((vy*t) >> 16);
|
|
|
|
*intz = z1 + ((vz*t) >> 16);
|
2012-06-13 23:13:39 +00:00
|
|
|
|
2020-09-13 18:15:46 +00:00
|
|
|
t = (topu << 16) / bot;
|
2019-06-25 11:28:40 +00:00
|
|
|
|
2020-08-30 21:34:40 +00:00
|
|
|
assert((unsigned)t < 65536);
|
2012-10-14 20:41:34 +00:00
|
|
|
|
|
|
|
return t;
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
2015-05-27 08:47:34 +00:00
|
|
|
//
|
|
|
|
// multi-pskies
|
|
|
|
//
|
|
|
|
|
2018-04-12 21:03:47 +00:00
|
|
|
psky_t * tileSetupSky(int32_t const tilenum)
|
2015-05-27 08:47:34 +00:00
|
|
|
{
|
2020-07-14 22:06:19 +00:00
|
|
|
for (auto& sky : multipskies)
|
|
|
|
if (tilenum == sky.tilenum)
|
|
|
|
{
|
|
|
|
return &sky;
|
|
|
|
}
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2020-07-14 22:06:19 +00:00
|
|
|
multipskies.Reserve(1);
|
|
|
|
multipskies.Last() = {};
|
|
|
|
multipskies.Last().tilenum = tilenum;
|
|
|
|
multipskies.Last().yscale = 65536;
|
|
|
|
return &multipskies.Last();
|
|
|
|
}
|
2015-05-27 08:47:34 +00:00
|
|
|
|
2021-05-08 20:08:05 +00:00
|
|
|
psky_t * defineSky(int32_t const tilenum, int horiz, int lognumtiles, const uint16_t *tileofs, int yoff, int yoff2)
|
2020-07-14 22:06:19 +00:00
|
|
|
{
|
|
|
|
auto sky = tileSetupSky(tilenum);
|
|
|
|
sky->horizfrac = horiz;
|
|
|
|
sky->lognumtiles = lognumtiles;
|
|
|
|
sky->yoffs = yoff;
|
2021-05-08 20:08:05 +00:00
|
|
|
sky->yoffs2 = yoff2 == 0x7fffffff ? yoff : yoff2;
|
2020-07-14 22:06:19 +00:00
|
|
|
memcpy(sky->tileofs, tileofs, 2 << lognumtiles);
|
|
|
|
return sky;
|
|
|
|
}
|
2015-05-27 08:47:34 +00:00
|
|
|
|
2020-07-14 22:06:19 +00:00
|
|
|
// Get properties of parallaxed sky to draw.
|
|
|
|
// Returns: pointer to tile offset array. Sets-by-pointer the other three.
|
2021-05-08 20:08:05 +00:00
|
|
|
const int16_t* getpsky(int32_t picnum, int32_t* dapyscale, int32_t* dapskybits, int32_t* dapyoffs, int32_t* daptileyscale, bool alt)
|
2020-07-14 22:06:19 +00:00
|
|
|
{
|
|
|
|
psky_t const* const psky = getpskyidx(picnum);
|
|
|
|
|
|
|
|
if (dapskybits)
|
|
|
|
*dapskybits = (pskybits_override == -1 ? psky->lognumtiles : pskybits_override);
|
|
|
|
if (dapyscale)
|
|
|
|
*dapyscale = (parallaxyscale_override == 0 ? psky->horizfrac : parallaxyscale_override);
|
|
|
|
if (dapyoffs)
|
2021-05-08 20:08:05 +00:00
|
|
|
*dapyoffs = (alt? psky->yoffs2 : psky->yoffs) + parallaxyoffs_override;
|
2020-07-14 22:06:19 +00:00
|
|
|
if (daptileyscale)
|
|
|
|
*daptileyscale = psky->yscale;
|
|
|
|
|
|
|
|
return psky->tileofs;
|
2015-05-27 08:47:34 +00:00
|
|
|
}
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2020-07-14 22:06:19 +00:00
|
|
|
|
2006-04-13 20:47:06 +00:00
|
|
|
//
|
|
|
|
// initengine
|
|
|
|
//
|
2018-04-12 21:03:47 +00:00
|
|
|
int32_t engineInit(void)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2021-04-05 11:55:36 +00:00
|
|
|
engineLoadTables();
|
2012-12-14 19:28:05 +00:00
|
|
|
g_visibility = 512;
|
2006-04-24 19:04:22 +00:00
|
|
|
return 0;
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-08 22:07:56 +00:00
|
|
|
//
|
|
|
|
// inside
|
|
|
|
//
|
|
|
|
// See http://fabiensanglard.net/duke3d/build_engine_internals.php,
|
|
|
|
// "Inside details" for the idea behind the algorithm.
|
|
|
|
|
2021-12-06 17:17:45 +00:00
|
|
|
int32_t inside(int32_t x, int32_t y, const sectortype* sect)
|
2021-11-08 22:07:56 +00:00
|
|
|
{
|
2021-12-06 17:17:45 +00:00
|
|
|
if (sect)
|
2021-11-08 22:07:56 +00:00
|
|
|
{
|
2021-12-06 17:17:45 +00:00
|
|
|
unsigned cnt = 0;
|
|
|
|
vec2_t xy = { x, y };
|
|
|
|
for(auto& wal : wallsofsector(sect))
|
2021-11-08 22:07:56 +00:00
|
|
|
{
|
2021-12-06 17:17:45 +00:00
|
|
|
vec2_t v1 = wal.pos - xy;
|
|
|
|
vec2_t v2 = wal.point2Wall()->pos - xy;
|
2021-11-08 22:07:56 +00:00
|
|
|
|
|
|
|
// If their signs differ[*], ...
|
|
|
|
//
|
|
|
|
// [*] where '-' corresponds to <0 and '+' corresponds to >=0.
|
|
|
|
// Equivalently, the branch is taken iff
|
|
|
|
// y1 != y2 AND y_m <= y < y_M,
|
|
|
|
// where y_m := min(y1, y2) and y_M := max(y1, y2).
|
2021-12-22 09:28:51 +00:00
|
|
|
if ((v1.Y^v2.Y) < 0)
|
|
|
|
cnt ^= (((v1.X^v2.X) >= 0) ? v1.X : (v1.X*v2.Y-v2.X*v1.Y)^v2.Y);
|
2021-11-08 22:07:56 +00:00
|
|
|
}
|
|
|
|
return cnt>>31;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
2019-09-21 11:02:17 +00:00
|
|
|
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2020-08-30 21:34:40 +00:00
|
|
|
int32_t getangle(int32_t xvect, int32_t yvect)
|
2012-09-02 14:12:01 +00:00
|
|
|
{
|
2015-01-11 04:56:58 +00:00
|
|
|
int32_t rv;
|
|
|
|
|
|
|
|
if ((xvect | yvect) == 0)
|
|
|
|
rv = 0;
|
|
|
|
else if (xvect == 0)
|
|
|
|
rv = 512 + ((yvect < 0) << 10);
|
|
|
|
else if (yvect == 0)
|
|
|
|
rv = ((xvect < 0) << 10);
|
|
|
|
else if (xvect == yvect)
|
|
|
|
rv = 256 + ((xvect < 0) << 10);
|
|
|
|
else if (xvect == -yvect)
|
|
|
|
rv = 768 + ((xvect > 0) << 10);
|
2021-01-04 12:02:00 +00:00
|
|
|
else if (abs(xvect) > abs(yvect))
|
2021-01-04 12:34:55 +00:00
|
|
|
rv = ((radarang[640 + Scale(160, yvect, xvect)] >> 6) + ((xvect < 0) << 10)) & 2047;
|
|
|
|
else rv = ((radarang[640 - Scale(160, xvect, yvect)] >> 6) + 512 + ((yvect < 0) << 10)) & 2047;
|
2015-01-11 04:56:58 +00:00
|
|
|
|
|
|
|
return rv;
|
2012-09-02 14:12:01 +00:00
|
|
|
}
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2020-04-17 13:21:22 +00:00
|
|
|
|
2012-11-17 19:46:43 +00:00
|
|
|
// Gets the BUILD unit height and z offset of a sprite.
|
|
|
|
// Returns the z offset, 'height' may be NULL.
|
2019-04-18 17:25:24 +00:00
|
|
|
int32_t spriteheightofsptr(uspriteptr_t spr, int32_t *height, int32_t alsotileyofs)
|
2011-03-02 21:21:47 +00:00
|
|
|
{
|
2012-11-17 19:46:43 +00:00
|
|
|
int32_t hei, zofs=0;
|
2012-11-25 13:18:57 +00:00
|
|
|
const int32_t picnum=spr->picnum, yrepeat=spr->yrepeat;
|
2011-03-23 17:41:01 +00:00
|
|
|
|
2020-05-23 22:27:24 +00:00
|
|
|
hei = (tileHeight(picnum)*yrepeat)<<2;
|
2019-03-19 17:08:12 +00:00
|
|
|
if (height != NULL)
|
|
|
|
*height = hei;
|
2011-03-02 21:21:47 +00:00
|
|
|
|
2021-12-18 16:35:01 +00:00
|
|
|
if (spr->cstat & CSTAT_SPRITE_YCENTER)
|
2012-11-17 19:46:43 +00:00
|
|
|
zofs = hei>>1;
|
2011-09-04 19:44:51 +00:00
|
|
|
|
2012-11-17 19:46:43 +00:00
|
|
|
// NOTE: a positive per-tile yoffset translates the sprite into the
|
|
|
|
// negative world z direction (i.e. upward).
|
|
|
|
if (alsotileyofs)
|
2020-05-24 10:31:38 +00:00
|
|
|
zofs -= tileTopOffset(picnum) *yrepeat<<2;
|
2012-11-17 19:46:37 +00:00
|
|
|
|
2012-11-17 19:46:43 +00:00
|
|
|
return zofs;
|
2011-03-02 21:21:47 +00:00
|
|
|
}
|
|
|
|
|
2006-04-13 20:47:06 +00:00
|
|
|
//
|
|
|
|
// nextsectorneighborz
|
|
|
|
//
|
2012-08-26 22:15:02 +00:00
|
|
|
// -1: ceiling or up
|
|
|
|
// 1: floor or down
|
2021-12-11 12:58:37 +00:00
|
|
|
sectortype* nextsectorneighborzptr(sectortype* sectp, int refz, int topbottom, int direction)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2021-12-11 12:58:37 +00:00
|
|
|
int nextz = (direction==1) ? INT32_MAX : INT32_MIN;
|
|
|
|
sectortype* sectortouse = nullptr;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2021-12-11 12:58:37 +00:00
|
|
|
for(auto& wal : wallsofsector(sectp))
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2021-12-11 12:58:37 +00:00
|
|
|
if (wal.twoSided())
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2021-12-11 12:58:37 +00:00
|
|
|
auto ns = wal.nextSector();
|
|
|
|
|
|
|
|
const int32_t testz = (topbottom == 1) ? ns->floorz : ns->ceilingz;
|
2012-08-26 22:15:02 +00:00
|
|
|
|
2014-01-31 21:12:56 +00:00
|
|
|
const int32_t update = (direction == 1) ?
|
2014-03-25 21:04:33 +00:00
|
|
|
(nextz > testz && testz > refz) :
|
|
|
|
(nextz < testz && testz < refz);
|
2012-08-26 22:15:02 +00:00
|
|
|
|
2014-01-31 21:12:56 +00:00
|
|
|
if (update)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2012-08-26 22:15:02 +00:00
|
|
|
nextz = testz;
|
2014-01-31 21:12:56 +00:00
|
|
|
sectortouse = ns;
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
}
|
2007-12-12 17:42:14 +00:00
|
|
|
}
|
2014-01-31 21:12:56 +00:00
|
|
|
return sectortouse;
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// cansee
|
|
|
|
//
|
2019-09-22 19:26:07 +00:00
|
|
|
|
2021-12-05 21:01:02 +00:00
|
|
|
int cansee(int x1, int y1, int z1, sectortype* sect1, int x2, int y2, int z2, sectortype* sect2)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2021-12-05 21:01:02 +00:00
|
|
|
if (!sect1 || !sect2) return false;
|
|
|
|
|
2012-11-17 19:46:47 +00:00
|
|
|
const int32_t x21 = x2-x1, y21 = y2-y1, z21 = z2-z1;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2012-11-17 19:46:47 +00:00
|
|
|
if (x1 == x2 && y1 == y2)
|
|
|
|
return (sect1 == sect2);
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2021-12-05 21:01:02 +00:00
|
|
|
BFSSectorSearch search(sect1);
|
2011-07-01 17:15:07 +00:00
|
|
|
|
2021-12-05 21:01:02 +00:00
|
|
|
while (auto sec = search.GetNext())
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2019-04-18 17:25:24 +00:00
|
|
|
uwallptr_t wal;
|
2021-12-14 09:15:58 +00:00
|
|
|
int cnt;
|
2021-11-26 19:55:13 +00:00
|
|
|
for (cnt=sec->wallnum,wal=(uwallptr_t)sec->firstWall(); cnt>0; cnt--,wal++)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2021-11-26 19:55:13 +00:00
|
|
|
auto const wal2 = (uwallptr_t)wal->point2Wall();
|
2021-12-22 09:59:50 +00:00
|
|
|
const int32_t x31 = wal->pos.X-x1, x34 = wal->pos.X-wal2->pos.X;
|
2012-11-17 19:46:47 +00:00
|
|
|
const int32_t y31 = wal->y-y1, y34 = wal->y-wal2->y;
|
|
|
|
|
2021-12-05 21:01:02 +00:00
|
|
|
int32_t x, y, z, t, bot;
|
2012-11-17 19:46:47 +00:00
|
|
|
int32_t cfz[2];
|
2006-04-13 20:47:06 +00:00
|
|
|
|
|
|
|
bot = y21*x34-x21*y34; if (bot <= 0) continue;
|
2012-06-13 23:13:39 +00:00
|
|
|
// XXX: OVERFLOW
|
2006-04-13 20:47:06 +00:00
|
|
|
t = y21*x31-x21*y31; if ((unsigned)t >= (unsigned)bot) continue;
|
2011-07-01 17:15:07 +00:00
|
|
|
t = y31*x34-x31*y34;
|
|
|
|
if ((unsigned)t >= (unsigned)bot)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2011-07-01 17:15:07 +00:00
|
|
|
|
2021-12-18 14:16:31 +00:00
|
|
|
if (!wal->twoSided() || wal->cstat & CSTAT_WALL_1WAY)
|
2021-12-05 21:01:02 +00:00
|
|
|
return 0;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2021-01-04 11:51:41 +00:00
|
|
|
t = DivScale(t,bot, 24);
|
2021-01-04 11:36:54 +00:00
|
|
|
x = x1 + MulScale(x21,t, 24);
|
|
|
|
y = y1 + MulScale(y21,t, 24);
|
|
|
|
z = z1 + MulScale(z21,t, 24);
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2021-12-05 21:01:02 +00:00
|
|
|
getzsofslopeptr(sec, x,y, &cfz[0],&cfz[1]);
|
2011-07-01 17:15:07 +00:00
|
|
|
|
2013-04-12 11:59:22 +00:00
|
|
|
if (z <= cfz[0] || z >= cfz[1])
|
2011-07-01 17:15:07 +00:00
|
|
|
{
|
2013-04-15 10:48:09 +00:00
|
|
|
return 0;
|
2011-07-01 17:15:07 +00:00
|
|
|
}
|
|
|
|
|
2021-12-05 21:01:02 +00:00
|
|
|
auto nexts = wal->nextSector();
|
|
|
|
getzsofslopeptr(nexts, x,y, &cfz[0],&cfz[1]);
|
2013-04-15 10:48:09 +00:00
|
|
|
if (z <= cfz[0] || z >= cfz[1])
|
|
|
|
return 0;
|
2011-07-01 17:15:07 +00:00
|
|
|
|
2021-11-18 00:20:46 +00:00
|
|
|
search.Add(nexts);
|
2011-07-01 17:15:07 +00:00
|
|
|
}
|
|
|
|
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
2021-11-18 00:20:46 +00:00
|
|
|
return search.Check(sect2);
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// neartag
|
|
|
|
//
|
2012-11-17 19:46:47 +00:00
|
|
|
|
2021-12-03 23:38:11 +00:00
|
|
|
void neartag(const vec3_t& sv, sectortype* sect, int ange, HitInfoBase& result, int neartagrange, int tagsearch)
|
|
|
|
{
|
2021-01-04 11:36:54 +00:00
|
|
|
const int32_t vx = MulScale(bcos(ange), neartagrange, 14);
|
|
|
|
const int32_t vy = MulScale(bsin(ange), neartagrange, 14);
|
2021-12-22 09:40:26 +00:00
|
|
|
vec3_t hitv = { sv.X+vx, sv.Y+vy, 0 };
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2021-12-03 23:38:11 +00:00
|
|
|
result.clearObj();
|
2021-12-22 09:36:09 +00:00
|
|
|
result.hitpos.X = 0;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2021-12-03 23:38:11 +00:00
|
|
|
if (!sect || (tagsearch & 3) == 0)
|
2012-11-17 19:46:47 +00:00
|
|
|
return;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2021-12-03 23:38:11 +00:00
|
|
|
BFSSectorSearch search(sect);
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2021-12-03 23:38:11 +00:00
|
|
|
while (auto dasect = search.GetNext())
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2021-12-03 23:38:11 +00:00
|
|
|
for (auto& w : wallsofsector(dasect))
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2021-12-03 23:38:11 +00:00
|
|
|
auto wal = &w;
|
2021-11-26 19:55:13 +00:00
|
|
|
auto const wal2 = (uwallptr_t)wal->point2Wall();
|
2021-12-03 23:38:11 +00:00
|
|
|
const auto nextsect = wal->nextSector();
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2021-12-22 09:59:50 +00:00
|
|
|
const int32_t x1 = wal->pos.X, y1 = wal->y, x2 = wal2->pos.X, y2 = wal2->y;
|
2012-11-17 19:46:47 +00:00
|
|
|
int32_t intx, inty, intz, good = 0;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2021-12-03 23:38:11 +00:00
|
|
|
if (wal->twoSided())
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2021-12-03 23:38:11 +00:00
|
|
|
if ((tagsearch & 1) && nextsect->lotag) good |= 1;
|
|
|
|
if ((tagsearch & 2) && nextsect->hitag) good |= 1;
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
2012-11-17 19:46:47 +00:00
|
|
|
|
2021-12-03 23:38:11 +00:00
|
|
|
if ((tagsearch & 1) && wal->lotag) good |= 2;
|
|
|
|
if ((tagsearch & 2) && wal->hitag) good |= 2;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2021-12-03 23:38:11 +00:00
|
|
|
if ((good == 0) && (!wal->twoSided())) continue;
|
2021-12-22 09:40:26 +00:00
|
|
|
if ((coord_t)(x1 - sv.X) * (y2 - sv.Y) < (coord_t)(x2 - sv.X) * (y1 - sv.Y)) continue;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2021-12-22 09:41:47 +00:00
|
|
|
if (lintersect(sv.X, sv.Y, sv.Z, hitv.X, hitv.Y, hitv.Z, x1, y1, x2, y2, &intx, &inty, &intz) == 1)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
|
|
|
if (good != 0)
|
|
|
|
{
|
2021-12-03 23:38:11 +00:00
|
|
|
if (good & 1) result.hitSector = nextsect;
|
|
|
|
if (good & 2) result.hitWall = wal;
|
2021-12-22 09:40:26 +00:00
|
|
|
result.hitpos.X = DMulScale(intx - sv.X, bcos(ange), inty - sv.Y, bsin(ange), 14);
|
2021-12-22 09:41:47 +00:00
|
|
|
hitv.X = intx; hitv.Y = inty; hitv.Z = intz;
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
2012-11-17 19:46:47 +00:00
|
|
|
|
2021-12-03 23:38:11 +00:00
|
|
|
if (wal->twoSided())
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2021-12-03 23:38:11 +00:00
|
|
|
search.Add(nextsect);
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-17 19:46:47 +00:00
|
|
|
if (tagsearch & 4)
|
|
|
|
continue; // skip sprite search
|
2011-03-04 08:50:58 +00:00
|
|
|
|
2021-12-03 23:38:11 +00:00
|
|
|
TSectIterator<DCoreActor> it(dasect);
|
|
|
|
while (auto actor = it.Next())
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2021-12-03 23:38:11 +00:00
|
|
|
auto const spr = &actor->s();
|
2012-11-17 19:46:47 +00:00
|
|
|
|
2021-09-05 10:25:52 +00:00
|
|
|
if (spr->cstat2 & CSTAT2_SPRITE_NOFIND)
|
2021-04-17 07:37:38 +00:00
|
|
|
continue;
|
2012-02-20 19:54:24 +00:00
|
|
|
|
2012-11-25 13:18:57 +00:00
|
|
|
if (((tagsearch&1) && spr->lotag) || ((tagsearch&2) && spr->hitag))
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2019-08-09 09:28:27 +00:00
|
|
|
if (try_facespr_intersect(spr, sv, vx, vy, 0, &hitv, 1))
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2021-12-03 23:38:11 +00:00
|
|
|
result.hitActor = actor;
|
2021-12-22 09:40:26 +00:00
|
|
|
result.hitpos.X = DMulScale(hitv.X-sv.X, bcos(ange), hitv.Y-sv.Y, bsin(ange), 14);
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-12-12 17:42:14 +00:00
|
|
|
}
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// dragpoint
|
|
|
|
//
|
2021-11-18 00:15:18 +00:00
|
|
|
void dragpoint(int w, int32_t dax, int32_t day)
|
2011-04-14 20:48:08 +00:00
|
|
|
{
|
2021-12-21 09:51:41 +00:00
|
|
|
BFSSearch walbitmap(wall.Size());
|
2021-11-18 00:15:18 +00:00
|
|
|
int clockwise = 0;
|
|
|
|
const int tmpstartwall = w;
|
|
|
|
int cnt = 16384; // limit the number of iterations.
|
2011-04-14 20:48:08 +00:00
|
|
|
|
2021-11-18 00:15:18 +00:00
|
|
|
while (1)
|
2011-04-14 20:48:08 +00:00
|
|
|
{
|
2021-11-26 19:55:13 +00:00
|
|
|
auto wal = &wall[w];
|
2021-12-17 17:22:42 +00:00
|
|
|
wal->move(dax, day);
|
2021-11-18 00:15:18 +00:00
|
|
|
walbitmap.Set(w);
|
2011-04-14 20:48:08 +00:00
|
|
|
|
2021-11-18 00:15:18 +00:00
|
|
|
if (!clockwise) //search points CCW
|
2011-04-14 20:48:08 +00:00
|
|
|
{
|
2021-11-26 19:55:13 +00:00
|
|
|
if (wal->nextwall >= 0)
|
|
|
|
w = wall[wal->nextwall].point2;
|
2021-11-18 00:15:18 +00:00
|
|
|
else
|
2011-04-14 20:48:08 +00:00
|
|
|
{
|
2021-11-18 00:15:18 +00:00
|
|
|
w = tmpstartwall;
|
|
|
|
clockwise = 1;
|
2011-04-14 20:48:08 +00:00
|
|
|
}
|
2021-11-18 00:15:18 +00:00
|
|
|
}
|
2011-04-14 20:48:08 +00:00
|
|
|
|
2021-11-18 00:15:18 +00:00
|
|
|
cnt--;
|
|
|
|
if (cnt==0)
|
|
|
|
{
|
|
|
|
Printf("dragpoint %d: infinite loop!\n", w);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (clockwise)
|
|
|
|
{
|
2021-12-17 17:22:42 +00:00
|
|
|
auto thelastwall = wall[w].lastWall();
|
|
|
|
if (thelastwall->nextwall >= 0)
|
|
|
|
w = thelastwall->nextwall;
|
2021-11-18 00:15:18 +00:00
|
|
|
else
|
2011-11-01 22:01:35 +00:00
|
|
|
break;
|
2021-11-18 00:15:18 +00:00
|
|
|
}
|
2011-11-01 22:01:35 +00:00
|
|
|
|
2021-11-18 00:15:18 +00:00
|
|
|
if (walbitmap.Check(w))
|
|
|
|
{
|
2011-11-01 22:01:35 +00:00
|
|
|
if (clockwise)
|
2021-11-18 00:15:18 +00:00
|
|
|
break;
|
2011-11-01 22:01:35 +00:00
|
|
|
|
2021-11-18 00:15:18 +00:00
|
|
|
w = tmpstartwall;
|
|
|
|
clockwise = 1;
|
|
|
|
continue;
|
2011-04-14 20:48:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2016-06-21 00:33:30 +00:00
|
|
|
////////// UPDATESECTOR* FAMILY OF FUNCTIONS //////////
|
|
|
|
|
|
|
|
/* Different "is inside" predicates.
|
|
|
|
* NOTE: The redundant bound checks are expected to be optimized away in the
|
|
|
|
* inlined code. */
|
2010-10-28 20:17:22 +00:00
|
|
|
|
2016-06-21 00:33:30 +00:00
|
|
|
/* NOTE: no bound check */
|
2019-12-07 23:49:56 +00:00
|
|
|
static inline int inside_z_p(int32_t const x, int32_t const y, int32_t const z, int const sectnum)
|
2016-06-21 00:33:30 +00:00
|
|
|
{
|
|
|
|
int32_t cz, fz;
|
2021-12-17 20:42:57 +00:00
|
|
|
getzsofslopeptr(§or[sectnum], x, y, &cz, &fz);
|
2019-04-06 06:37:42 +00:00
|
|
|
return (z >= cz && z <= fz && inside_p(x, y, sectnum));
|
2016-06-21 00:33:30 +00:00
|
|
|
}
|
2012-10-01 17:52:09 +00:00
|
|
|
|
2019-08-27 06:52:42 +00:00
|
|
|
int32_t getwalldist(vec2_t const in, int const wallnum)
|
2019-04-18 17:24:30 +00:00
|
|
|
{
|
|
|
|
vec2_t closest;
|
2019-04-19 08:31:47 +00:00
|
|
|
getclosestpointonwall_internal(in, wallnum, &closest);
|
2021-12-22 09:28:51 +00:00
|
|
|
return abs(closest.X - in.X) + abs(closest.Y - in.Y);
|
2019-04-18 17:24:30 +00:00
|
|
|
}
|
|
|
|
|
2019-08-27 06:52:42 +00:00
|
|
|
int32_t getwalldist(vec2_t const in, int const wallnum, vec2_t * const out)
|
2019-08-04 02:51:59 +00:00
|
|
|
{
|
|
|
|
getclosestpointonwall_internal(in, wallnum, out);
|
2021-12-22 09:28:51 +00:00
|
|
|
return abs(out->X - in.X) + abs(out->Y - in.Y);
|
2019-08-04 02:51:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-08-27 06:52:42 +00:00
|
|
|
int32_t getsectordist(vec2_t const in, int const sectnum, vec2_t * const out /*= nullptr*/)
|
2019-04-18 17:24:30 +00:00
|
|
|
{
|
2021-12-22 09:28:51 +00:00
|
|
|
if (inside_p(in.X, in.Y, sectnum))
|
2019-04-19 08:31:47 +00:00
|
|
|
{
|
|
|
|
if (out)
|
|
|
|
*out = in;
|
2019-04-18 17:24:30 +00:00
|
|
|
return 0;
|
2019-04-19 08:31:47 +00:00
|
|
|
}
|
2019-04-18 17:24:30 +00:00
|
|
|
|
|
|
|
int32_t distance = INT32_MAX;
|
|
|
|
|
2019-04-19 08:31:47 +00:00
|
|
|
vec2_t closest = {};
|
2019-04-18 17:24:30 +00:00
|
|
|
|
2021-12-01 23:34:31 +00:00
|
|
|
for (auto& wal : wallsofsector(sectnum))
|
2019-04-18 17:24:30 +00:00
|
|
|
{
|
2019-04-19 08:31:47 +00:00
|
|
|
vec2_t p;
|
2021-12-01 23:34:31 +00:00
|
|
|
int32_t const walldist = getwalldist(in, wallnum(&wal), &p);
|
2019-04-19 08:31:47 +00:00
|
|
|
|
|
|
|
if (walldist < distance)
|
|
|
|
{
|
|
|
|
distance = walldist;
|
|
|
|
closest = p;
|
|
|
|
}
|
2019-04-18 17:24:30 +00:00
|
|
|
}
|
|
|
|
|
2019-04-19 08:31:47 +00:00
|
|
|
if (out)
|
|
|
|
*out = closest;
|
|
|
|
|
2019-04-18 17:24:30 +00:00
|
|
|
return distance;
|
|
|
|
}
|
|
|
|
|
2019-07-19 01:46:32 +00:00
|
|
|
|
2021-11-29 23:14:45 +00:00
|
|
|
template<class Inside>
|
|
|
|
void updatesectorneighborz(int32_t const x, int32_t const y, int32_t const z, int* const sectnum, int32_t maxDistance, Inside checker)
|
2019-07-19 01:46:32 +00:00
|
|
|
{
|
|
|
|
int const initialsectnum = *sectnum;
|
|
|
|
|
2021-11-29 23:08:24 +00:00
|
|
|
if ((validSectorIndex(initialsectnum)))
|
2019-07-19 01:46:32 +00:00
|
|
|
{
|
2021-11-29 23:14:45 +00:00
|
|
|
if (checker(x, y, z, initialsectnum))
|
2019-07-19 01:46:32 +00:00
|
|
|
return;
|
|
|
|
|
2021-12-21 09:51:41 +00:00
|
|
|
BFSSearch search(sector.Size(), *sectnum);
|
2019-07-19 01:46:32 +00:00
|
|
|
|
2021-11-29 23:08:24 +00:00
|
|
|
int iter = 0;
|
2021-11-16 23:20:31 +00:00
|
|
|
for (unsigned listsectnum; (listsectnum = search.GetNext()) != BFSSearch::EOL;)
|
2019-07-19 01:46:32 +00:00
|
|
|
{
|
2021-11-29 23:14:45 +00:00
|
|
|
if (checker(x, y, z, listsectnum))
|
2021-11-16 23:20:31 +00:00
|
|
|
{
|
|
|
|
*sectnum = listsectnum;
|
|
|
|
return;
|
|
|
|
}
|
2019-07-19 01:46:32 +00:00
|
|
|
|
2021-11-16 23:20:31 +00:00
|
|
|
for (auto& wal : wallsofsector(listsectnum))
|
|
|
|
{
|
2021-11-29 23:08:24 +00:00
|
|
|
if (wal.nextsector >= 0 && (iter == 0 || getsectordist({ x, y }, wal.nextsector) <= maxDistance))
|
2021-11-16 23:20:31 +00:00
|
|
|
search.Add(wal.nextsector);
|
|
|
|
}
|
2021-11-29 23:08:24 +00:00
|
|
|
iter++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*sectnum = -1;
|
|
|
|
}
|
|
|
|
|
2021-11-29 23:14:45 +00:00
|
|
|
void updatesectorneighbor(int32_t const x, int32_t const y, int* const sectnum, int32_t maxDistance)
|
2021-11-29 23:08:24 +00:00
|
|
|
{
|
2021-11-29 23:14:45 +00:00
|
|
|
updatesectorneighborz(x, y, 0, sectnum, maxDistance, inside_p0);
|
|
|
|
}
|
2021-11-29 23:08:24 +00:00
|
|
|
|
|
|
|
|
2021-11-29 23:14:45 +00:00
|
|
|
//
|
|
|
|
// updatesector[z]
|
|
|
|
//
|
|
|
|
void updatesector(int32_t const x, int32_t const y, int * const sectnum)
|
|
|
|
{
|
|
|
|
int sect = *sectnum;
|
2021-11-29 23:08:24 +00:00
|
|
|
|
2021-11-29 23:14:45 +00:00
|
|
|
updatesectorneighbor(x, y, §, MAXUPDATESECTORDIST);
|
|
|
|
if (sect != -1)
|
|
|
|
SET_AND_RETURN(*sectnum, sect);
|
2021-11-29 23:08:24 +00:00
|
|
|
|
2021-11-29 23:14:45 +00:00
|
|
|
// we need to support passing in a sectnum of -1, unfortunately
|
|
|
|
|
2021-12-21 09:51:41 +00:00
|
|
|
for (int i = (int)sector.Size() - 1; i >= 0; --i)
|
2021-11-29 23:14:45 +00:00
|
|
|
if (inside_p(x, y, i))
|
|
|
|
SET_AND_RETURN(*sectnum, i);
|
|
|
|
|
|
|
|
*sectnum = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void updatesectorz(int32_t const x, int32_t const y, int32_t const z, int* const sectnum)
|
|
|
|
{
|
|
|
|
int sect = *sectnum;
|
|
|
|
|
|
|
|
updatesectorneighborz(x, y, z, §, MAXUPDATESECTORDIST, inside_z_p);
|
|
|
|
if (sect != -1)
|
|
|
|
SET_AND_RETURN(*sectnum, sect);
|
|
|
|
|
|
|
|
|
|
|
|
// we need to support passing in a sectnum of -1, unfortunately
|
2021-12-21 09:51:41 +00:00
|
|
|
for (int i = (int)sector.Size() - 1; i >= 0; --i)
|
2021-11-29 23:14:45 +00:00
|
|
|
if (inside_z_p(x, y, z, i))
|
|
|
|
SET_AND_RETURN(*sectnum, i);
|
2019-07-19 01:46:32 +00:00
|
|
|
|
|
|
|
*sectnum = -1;
|
|
|
|
}
|
|
|
|
|
2021-11-29 23:14:45 +00:00
|
|
|
|
2006-04-13 20:47:06 +00:00
|
|
|
//
|
|
|
|
// rotatepoint
|
|
|
|
//
|
2019-04-18 17:24:10 +00:00
|
|
|
void rotatepoint(vec2_t const pivot, vec2_t p, int16_t const daang, vec2_t * const p2)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2020-11-14 09:00:37 +00:00
|
|
|
int const dacos = bcos(daang);
|
|
|
|
int const dasin = bsin(daang);
|
2021-12-22 09:26:51 +00:00
|
|
|
p.X -= pivot.X;
|
2021-12-22 09:28:51 +00:00
|
|
|
p.Y -= pivot.Y;
|
|
|
|
p2->X = DMulScale(p.X, dacos, -p.Y, dasin, 14) + pivot.X;
|
|
|
|
p2->Y = DMulScale(p.Y, dacos, p.X, dasin, 14) + pivot.Y;
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// setview
|
|
|
|
//
|
2018-04-12 21:02:51 +00:00
|
|
|
void videoSetViewableArea(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2021-12-22 09:26:51 +00:00
|
|
|
windowxy1.X = x1;
|
2021-12-22 09:28:51 +00:00
|
|
|
windowxy1.Y = y1;
|
2021-12-22 09:26:51 +00:00
|
|
|
windowxy2.X = x2;
|
2021-12-22 09:28:51 +00:00
|
|
|
windowxy2.Y = y2;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2021-03-19 14:12:54 +00:00
|
|
|
xdimen = (x2-x1)+1;
|
2006-04-13 20:47:06 +00:00
|
|
|
ydimen = (y2-y1)+1;
|
|
|
|
|
2014-10-25 03:27:35 +00:00
|
|
|
fxdimen = (float) xdimen;
|
|
|
|
fydimen = (float) ydimen;
|
2018-04-12 21:02:51 +00:00
|
|
|
videoSetCorrectedAspect();
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-11-21 18:30:27 +00:00
|
|
|
#include "v_2ddrawer.h"
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2020-01-01 11:01:26 +00:00
|
|
|
|
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
//MUST USE RESTOREFORDRAWROOMS AFTER DRAWING
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2020-03-29 12:01:46 +00:00
|
|
|
static int32_t setviewcnt = 0; // interface layers use this now
|
|
|
|
static int32_t bakxsiz, bakysiz;
|
|
|
|
static vec2_t bakwindowxy1, bakwindowxy2;
|
|
|
|
|
2006-04-13 20:47:06 +00:00
|
|
|
//
|
|
|
|
// setviewtotile
|
|
|
|
//
|
2020-06-14 19:57:21 +00:00
|
|
|
FCanvasTexture* renderSetTarget(int16_t tilenume)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2020-06-14 19:57:21 +00:00
|
|
|
auto tex = tileGetTexture(tilenume);
|
|
|
|
if (!tex || !tex->isHardwareCanvas()) return nullptr;
|
|
|
|
auto canvas = static_cast<FCanvasTexture*>(tex->GetTexture());
|
|
|
|
if (!canvas) return nullptr;
|
|
|
|
int xsiz = tex->GetTexelWidth(), ysiz = tex->GetTexelHeight();
|
|
|
|
if (setviewcnt > 0 || xsiz <= 0 || ysiz <= 0)
|
|
|
|
return nullptr;
|
2014-09-30 04:06:32 +00:00
|
|
|
|
2020-03-29 12:01:46 +00:00
|
|
|
//DRAWROOMS TO TILE BACKUP&SET CODE
|
|
|
|
bakxsiz = xdim; bakysiz = ydim;
|
|
|
|
bakwindowxy1 = windowxy1;
|
|
|
|
bakwindowxy2 = windowxy2;
|
2014-09-30 04:06:32 +00:00
|
|
|
|
2006-04-13 20:47:06 +00:00
|
|
|
setviewcnt++;
|
|
|
|
|
2020-06-14 19:57:21 +00:00
|
|
|
xdim = ysiz;
|
|
|
|
ydim = xsiz;
|
|
|
|
videoSetViewableArea(0,0,ysiz-1,xsiz-1);
|
2018-04-12 21:03:47 +00:00
|
|
|
renderSetAspect(65536,65536);
|
2020-06-14 19:57:21 +00:00
|
|
|
return canvas;
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// setviewback
|
|
|
|
//
|
2020-03-29 12:01:46 +00:00
|
|
|
void renderRestoreTarget()
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
|
|
|
if (setviewcnt <= 0) return;
|
|
|
|
setviewcnt--;
|
|
|
|
|
2020-03-29 12:01:46 +00:00
|
|
|
xdim = bakxsiz;
|
|
|
|
ydim = bakysiz;
|
2021-12-22 09:28:51 +00:00
|
|
|
videoSetViewableArea(bakwindowxy1.X,bakwindowxy1.Y,
|
|
|
|
bakwindowxy2.X,bakwindowxy2.Y);
|
2012-12-14 19:28:17 +00:00
|
|
|
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-04-05 11:55:36 +00:00
|
|
|
int tilehasmodelorvoxel(int const tilenume, int pal)
|
|
|
|
{
|
|
|
|
return
|
|
|
|
(mdinited && hw_models && tile2model[Ptile2tile(tilenume, pal)].modelid != -1) ||
|
|
|
|
(r_voxels && tiletovox[tilenume] != -1);
|
|
|
|
}
|
2021-11-29 23:08:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
CCMD(updatesectordebug)
|
|
|
|
{
|
|
|
|
int sect = 319;
|
|
|
|
updatesector(1792, 24334, §);
|
|
|
|
int blah = sect;
|
|
|
|
}
|