2019-06-01 11:07:23 +00:00
|
|
|
// SONIC ROBO BLAST 2
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
|
|
|
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
2023-03-31 12:53:31 +00:00
|
|
|
// Copyright (C) 1999-2023 by Sonic Team Junior.
|
2019-06-01 11:07:23 +00:00
|
|
|
//
|
|
|
|
// 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 r_portal.c
|
|
|
|
/// \brief Software renderer portals.
|
|
|
|
|
|
|
|
#include "r_portal.h"
|
|
|
|
#include "r_plane.h"
|
2019-06-01 19:26:25 +00:00
|
|
|
#include "r_main.h"
|
|
|
|
#include "doomstat.h"
|
|
|
|
#include "p_spec.h" // Skybox viewpoints
|
2023-08-24 03:51:52 +00:00
|
|
|
#include "p_slopes.h" // P_GetSectorFloorZAt and P_GetSectorCeilingZAt
|
2021-04-05 14:23:21 +00:00
|
|
|
#include "p_local.h"
|
2019-06-01 11:07:23 +00:00
|
|
|
#include "z_zone.h"
|
2019-06-05 14:35:48 +00:00
|
|
|
#include "r_things.h"
|
2019-06-07 11:10:12 +00:00
|
|
|
#include "r_sky.h"
|
2019-06-01 11:07:23 +00:00
|
|
|
|
|
|
|
UINT8 portalrender; /**< When rendering a portal, it establishes the depth of the current BSP traversal. */
|
|
|
|
|
|
|
|
// Linked list for portals.
|
|
|
|
portal_t *portal_base, *portal_cap;
|
|
|
|
|
|
|
|
line_t *portalclipline;
|
2019-12-11 14:35:34 +00:00
|
|
|
sector_t *portalcullsector;
|
2019-06-01 11:07:23 +00:00
|
|
|
INT32 portalclipstart, portalclipend;
|
|
|
|
|
|
|
|
boolean portalline; // is curline a portal seg?
|
|
|
|
|
|
|
|
void Portal_InitList (void)
|
|
|
|
{
|
|
|
|
portalrender = 0;
|
|
|
|
portal_base = portal_cap = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Store the clipping window for a portal in its given range.
|
|
|
|
*
|
|
|
|
* The window is copied from the current window at the time
|
|
|
|
* the function is called, so it is useful for converting one-sided
|
|
|
|
* lines into portals.
|
|
|
|
*/
|
2019-06-01 19:26:25 +00:00
|
|
|
void Portal_ClipRange (portal_t* portal)
|
2019-06-01 11:07:23 +00:00
|
|
|
{
|
|
|
|
INT32 start = portal->start;
|
|
|
|
INT32 end = portal->end;
|
|
|
|
INT16 *ceil = portal->ceilingclip;
|
|
|
|
INT16 *floor = portal->floorclip;
|
|
|
|
fixed_t *scale = portal->frontscale;
|
|
|
|
|
|
|
|
INT32 i;
|
|
|
|
for (i = 0; i < end-start; i++)
|
|
|
|
{
|
|
|
|
*ceil = ceilingclip[start+i];
|
|
|
|
ceil++;
|
|
|
|
*floor = floorclip[start+i];
|
|
|
|
floor++;
|
|
|
|
*scale = frontscale[start+i];
|
|
|
|
scale++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Apply the clipping window from a portal.
|
|
|
|
*/
|
|
|
|
void Portal_ClipApply (const portal_t* portal)
|
|
|
|
{
|
|
|
|
INT32 i;
|
|
|
|
INT32 start = portal->start;
|
|
|
|
INT32 end = portal->end;
|
|
|
|
INT16 *ceil = portal->ceilingclip;
|
|
|
|
INT16 *floor = portal->floorclip;
|
|
|
|
fixed_t *scale = portal->frontscale;
|
|
|
|
|
|
|
|
for (i = 0; i < end-start; i++)
|
|
|
|
{
|
|
|
|
ceilingclip[start+i] = *ceil;
|
|
|
|
ceil++;
|
|
|
|
floorclip[start+i] = *floor;
|
|
|
|
floor++;
|
|
|
|
frontscale[start+i] = *scale;
|
|
|
|
scale++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// HACKS FOLLOW
|
|
|
|
for (i = 0; i < start; i++)
|
|
|
|
{
|
|
|
|
floorclip[i] = -1;
|
|
|
|
ceilingclip[i] = (INT16)viewheight;
|
|
|
|
}
|
|
|
|
for (i = end; i < vid.width; i++)
|
|
|
|
{
|
|
|
|
floorclip[i] = -1;
|
|
|
|
ceilingclip[i] = (INT16)viewheight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-09 20:48:54 +00:00
|
|
|
static portal_t* Portal_Add (const INT16 x1, const INT16 x2)
|
2019-06-01 11:07:23 +00:00
|
|
|
{
|
|
|
|
portal_t *portal = Z_Malloc(sizeof(portal_t), PU_LEVEL, NULL);
|
2019-06-05 14:35:48 +00:00
|
|
|
INT16 *ceilingclipsave = Z_Malloc(sizeof(INT16)*(x2-x1 + 1), PU_LEVEL, NULL);
|
|
|
|
INT16 *floorclipsave = Z_Malloc(sizeof(INT16)*(x2-x1 + 1), PU_LEVEL, NULL);
|
|
|
|
fixed_t *frontscalesave = Z_Malloc(sizeof(fixed_t)*(x2-x1 + 1), PU_LEVEL, NULL);
|
2019-06-01 11:07:23 +00:00
|
|
|
|
|
|
|
// Linked list.
|
|
|
|
if (!portal_base)
|
|
|
|
{
|
|
|
|
portal_base = portal;
|
|
|
|
portal_cap = portal;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
portal_cap->next = portal;
|
|
|
|
portal_cap = portal;
|
|
|
|
}
|
|
|
|
portal->next = NULL;
|
|
|
|
|
|
|
|
// Store clipping values so they can be restored once the portal is rendered.
|
|
|
|
portal->ceilingclip = ceilingclipsave;
|
|
|
|
portal->floorclip = floorclipsave;
|
|
|
|
portal->frontscale = frontscalesave;
|
|
|
|
portal->start = x1;
|
|
|
|
portal->end = x2;
|
|
|
|
|
|
|
|
// Increase recursion level.
|
|
|
|
portal->pass = portalrender+1;
|
|
|
|
|
|
|
|
return portal;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Portal_Remove (portal_t* portal)
|
|
|
|
{
|
2022-01-25 02:53:09 +00:00
|
|
|
portalcullsector = NULL;
|
2019-06-01 11:07:23 +00:00
|
|
|
portal_base = portal->next;
|
|
|
|
Z_Free(portal->ceilingclip);
|
|
|
|
Z_Free(portal->floorclip);
|
|
|
|
Z_Free(portal->frontscale);
|
|
|
|
Z_Free(portal);
|
|
|
|
}
|
|
|
|
|
2023-08-23 18:04:50 +00:00
|
|
|
static void Portal_GetViewpointForLine(portal_t *portal, line_t *start, line_t *dest)
|
2019-06-01 11:07:23 +00:00
|
|
|
{
|
|
|
|
// Offset the portal view by the linedef centers
|
|
|
|
angle_t dangle = R_PointToAngle2(0,0,dest->dx,dest->dy) - R_PointToAngle2(start->dx,start->dy,0,0);
|
|
|
|
|
|
|
|
fixed_t disttopoint;
|
|
|
|
angle_t angtopoint;
|
|
|
|
|
2023-08-23 18:04:50 +00:00
|
|
|
struct {
|
|
|
|
fixed_t x, y;
|
|
|
|
} dest_c, start_c;
|
2019-06-01 11:07:23 +00:00
|
|
|
|
|
|
|
// looking glass center
|
|
|
|
start_c.x = (start->v1->x + start->v2->x) / 2;
|
|
|
|
start_c.y = (start->v1->y + start->v2->y) / 2;
|
|
|
|
|
|
|
|
// other side center
|
|
|
|
dest_c.x = (dest->v1->x + dest->v2->x) / 2;
|
|
|
|
dest_c.y = (dest->v1->y + dest->v2->y) / 2;
|
|
|
|
|
|
|
|
disttopoint = R_PointToDist2(start_c.x, start_c.y, viewx, viewy);
|
|
|
|
angtopoint = R_PointToAngle2(start_c.x, start_c.y, viewx, viewy);
|
|
|
|
angtopoint += dangle;
|
|
|
|
|
|
|
|
portal->viewx = dest_c.x + FixedMul(FINECOSINE(angtopoint>>ANGLETOFINESHIFT), disttopoint);
|
|
|
|
portal->viewy = dest_c.y + FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint);
|
|
|
|
portal->viewz = viewz + dest->frontsector->floorheight - start->frontsector->floorheight;
|
|
|
|
portal->viewangle = viewangle + dangle;
|
2023-08-23 18:04:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Creates a portal out of two lines and a determined screen range.
|
|
|
|
*
|
|
|
|
* line1 determines the entrance, and line2 the exit.
|
|
|
|
* x1 and x2 determine the screen's column bounds.
|
|
|
|
|
|
|
|
* The view's offset from the entry line center is obtained,
|
|
|
|
* and then rotated&translated to the exit line's center.
|
|
|
|
* When the portal renders, it will create the illusion of
|
|
|
|
* the two lines being seamed together.
|
|
|
|
*/
|
|
|
|
void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, const INT32 x2)
|
|
|
|
{
|
|
|
|
portal_t* portal = Portal_Add(x1, x2);
|
|
|
|
|
|
|
|
line_t* start = &lines[line1];
|
|
|
|
line_t* dest = &lines[line2];
|
|
|
|
|
|
|
|
Portal_GetViewpointForLine(portal, start, dest);
|
2019-06-01 11:07:23 +00:00
|
|
|
|
|
|
|
portal->clipline = line2;
|
2023-08-25 03:47:40 +00:00
|
|
|
portal->is_skybox = false;
|
2023-08-24 03:51:52 +00:00
|
|
|
portal->is_horizon = false;
|
|
|
|
portal->horizon_sector = NULL;
|
2019-06-01 11:07:23 +00:00
|
|
|
|
2019-06-01 19:26:25 +00:00
|
|
|
Portal_ClipRange(portal);
|
2019-06-01 11:07:23 +00:00
|
|
|
|
|
|
|
portalline = true; // this tells R_StoreWallRange that curline is a portal seg
|
|
|
|
}
|
|
|
|
|
2019-06-01 19:26:25 +00:00
|
|
|
/** Store the clipping window for a portal using a visplane.
|
|
|
|
*
|
|
|
|
* Since visplanes top/bottom windows work in an identical way,
|
|
|
|
* it can just be copied almost directly.
|
|
|
|
*/
|
|
|
|
static void Portal_ClipVisplane (const visplane_t* plane, portal_t* portal)
|
|
|
|
{
|
|
|
|
INT16 start = portal->start;
|
|
|
|
INT16 end = portal->end;
|
|
|
|
INT32 i;
|
|
|
|
|
|
|
|
for (i = 0; i < end - start; i++)
|
|
|
|
{
|
2019-06-06 09:26:13 +00:00
|
|
|
// Invalid column.
|
|
|
|
if (plane->top[i + start] == 65535)
|
|
|
|
{
|
|
|
|
portal->ceilingclip[i] = -1;
|
|
|
|
portal->floorclip[i] = -1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
portal->ceilingclip[i] = plane->top[i + start] - 1;
|
2019-06-01 19:26:25 +00:00
|
|
|
portal->floorclip[i] = plane->bottom[i + start] + 1;
|
2019-06-04 19:04:35 +00:00
|
|
|
portal->frontscale[i] = INT32_MAX;
|
2019-06-01 19:26:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern INT32 viewwidth;
|
|
|
|
|
2019-06-07 11:10:12 +00:00
|
|
|
static boolean TrimVisplaneBounds (const visplane_t* plane, INT16* start, INT16* end)
|
2019-06-01 19:26:25 +00:00
|
|
|
{
|
2019-06-07 11:10:12 +00:00
|
|
|
*start = plane->minx;
|
|
|
|
*end = plane->maxx + 1;
|
2019-06-01 11:07:23 +00:00
|
|
|
|
2019-06-06 09:26:13 +00:00
|
|
|
// Visplanes have 1-px pads on their sides (extra columns).
|
|
|
|
// Trim them, else it may render out of bounds.
|
2019-06-07 11:10:12 +00:00
|
|
|
if (*end > viewwidth)
|
|
|
|
*end = viewwidth;
|
|
|
|
|
|
|
|
if (!(*start < *end))
|
|
|
|
return true;
|
2019-06-06 09:26:13 +00:00
|
|
|
|
2019-06-01 19:26:25 +00:00
|
|
|
|
2019-06-05 14:35:48 +00:00
|
|
|
/** Trims a visplane's horizontal gap to match its render area.
|
|
|
|
*
|
|
|
|
* Visplanes' minx/maxx may sometimes exceed the area they're
|
|
|
|
* covering. This merely adjusts the boundaries to the next
|
|
|
|
* valid area.
|
|
|
|
*/
|
|
|
|
|
2019-06-07 11:10:12 +00:00
|
|
|
while (plane->bottom[*start] == 0 && plane->top[*start] == 65535 && *start < *end)
|
2019-06-05 14:35:48 +00:00
|
|
|
{
|
2019-06-07 11:10:12 +00:00
|
|
|
(*start)++;
|
2019-06-05 14:35:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-07 11:10:12 +00:00
|
|
|
while (plane->bottom[*end - 1] == 0 && plane->top[*start] == 65535 && *end > *start)
|
2019-06-05 14:35:48 +00:00
|
|
|
{
|
2019-06-07 11:10:12 +00:00
|
|
|
(*end)--;
|
2019-06-05 14:35:48 +00:00
|
|
|
}
|
|
|
|
|
2019-06-07 11:10:12 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-08-24 20:36:38 +00:00
|
|
|
static void Portal_GetViewpointForSkybox(portal_t *portal)
|
2019-06-07 11:10:12 +00:00
|
|
|
{
|
2019-06-01 19:26:25 +00:00
|
|
|
portal->viewx = skyboxmo[0]->x;
|
|
|
|
portal->viewy = skyboxmo[0]->y;
|
|
|
|
portal->viewz = skyboxmo[0]->z;
|
|
|
|
portal->viewangle = viewangle + skyboxmo[0]->angle;
|
|
|
|
|
2023-08-24 20:36:38 +00:00
|
|
|
mapheader_t *mh = mapheaderinfo[gamemap-1];
|
2019-06-01 19:26:25 +00:00
|
|
|
|
|
|
|
// If a relative viewpoint exists, offset the viewpoint.
|
|
|
|
if (skyboxmo[1])
|
|
|
|
{
|
|
|
|
fixed_t x = 0, y = 0;
|
2019-06-11 12:47:58 +00:00
|
|
|
angle_t ang = skyboxmo[0]->angle>>ANGLETOFINESHIFT;
|
2019-06-01 19:26:25 +00:00
|
|
|
|
|
|
|
if (mh->skybox_scalex > 0)
|
|
|
|
x = (viewx - skyboxmo[1]->x) / mh->skybox_scalex;
|
|
|
|
else if (mh->skybox_scalex < 0)
|
|
|
|
x = (viewx - skyboxmo[1]->x) * -mh->skybox_scalex;
|
|
|
|
|
|
|
|
if (mh->skybox_scaley > 0)
|
|
|
|
y = (viewy - skyboxmo[1]->y) / mh->skybox_scaley;
|
|
|
|
else if (mh->skybox_scaley < 0)
|
|
|
|
y = (viewy - skyboxmo[1]->y) * -mh->skybox_scaley;
|
|
|
|
|
2019-06-11 12:47:58 +00:00
|
|
|
// Apply transform to account for the skybox viewport angle.
|
|
|
|
portal->viewx += FixedMul(x,FINECOSINE(ang)) - FixedMul(y, FINESINE(ang));
|
|
|
|
portal->viewy += FixedMul(x, FINESINE(ang)) + FixedMul(y,FINECOSINE(ang));
|
2019-06-01 19:26:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mh->skybox_scalez > 0)
|
|
|
|
portal->viewz += viewz / mh->skybox_scalez;
|
|
|
|
else if (mh->skybox_scalez < 0)
|
|
|
|
portal->viewz += viewz * -mh->skybox_scalez;
|
|
|
|
}
|
2019-06-07 11:10:12 +00:00
|
|
|
|
2023-08-24 20:36:38 +00:00
|
|
|
/** Creates a skybox portal out of a visplane.
|
|
|
|
*
|
|
|
|
* Applies the necessary offsets and rotation to give
|
|
|
|
* a depth illusion to the skybox.
|
2021-04-05 14:23:21 +00:00
|
|
|
*/
|
2023-08-25 03:57:10 +00:00
|
|
|
static boolean Portal_AddSkybox (const visplane_t* plane)
|
2021-04-05 14:23:21 +00:00
|
|
|
{
|
|
|
|
INT16 start, end;
|
2023-08-24 20:36:38 +00:00
|
|
|
portal_t* portal;
|
2023-08-23 18:04:50 +00:00
|
|
|
|
2021-04-05 14:23:21 +00:00
|
|
|
if (TrimVisplaneBounds(plane, &start, &end))
|
2023-08-25 03:57:10 +00:00
|
|
|
return false;
|
2021-04-05 14:23:21 +00:00
|
|
|
|
2023-08-24 20:36:38 +00:00
|
|
|
portal = Portal_Add(start, end);
|
2021-04-05 14:23:21 +00:00
|
|
|
|
|
|
|
Portal_ClipVisplane(plane, portal);
|
|
|
|
|
2023-08-23 18:04:50 +00:00
|
|
|
portal->clipline = -1;
|
2023-08-25 03:47:40 +00:00
|
|
|
portal->is_skybox = true;
|
2023-08-24 03:51:52 +00:00
|
|
|
portal->is_horizon = false;
|
|
|
|
portal->horizon_sector = NULL;
|
2023-08-23 07:24:06 +00:00
|
|
|
|
2023-08-24 20:36:38 +00:00
|
|
|
Portal_GetViewpointForSkybox(portal);
|
2023-08-25 03:57:10 +00:00
|
|
|
|
|
|
|
return true;
|
2023-08-24 20:36:38 +00:00
|
|
|
}
|
|
|
|
|
2023-08-25 03:18:20 +00:00
|
|
|
static void Portal_GetViewpointForSecPortal(portal_t *portal, sectorportal_t *secportal)
|
2023-08-24 20:36:38 +00:00
|
|
|
{
|
2023-08-25 08:02:23 +00:00
|
|
|
fixed_t x, y, z;
|
|
|
|
angle_t angle;
|
2023-08-24 20:36:38 +00:00
|
|
|
|
2023-08-23 18:04:50 +00:00
|
|
|
switch (secportal->type)
|
2021-04-05 14:23:21 +00:00
|
|
|
{
|
2023-08-23 18:04:50 +00:00
|
|
|
case SECPORTAL_LINE:
|
|
|
|
Portal_GetViewpointForLine(portal, secportal->line.start, secportal->line.dest);
|
|
|
|
return;
|
|
|
|
case SECPORTAL_OBJECT:
|
|
|
|
if (!secportal->mobj || P_MobjWasRemoved(secportal->mobj))
|
|
|
|
return;
|
|
|
|
x = secportal->mobj->x;
|
|
|
|
y = secportal->mobj->y;
|
|
|
|
z = secportal->mobj->z;
|
|
|
|
angle = secportal->mobj->angle;
|
|
|
|
break;
|
|
|
|
case SECPORTAL_FLOOR:
|
|
|
|
x = secportal->sector->soundorg.x;
|
|
|
|
y = secportal->sector->soundorg.y;
|
2023-08-24 03:51:52 +00:00
|
|
|
z = P_GetSectorFloorZAt(secportal->sector, x, y);
|
2023-08-23 18:04:50 +00:00
|
|
|
angle = 0;
|
|
|
|
break;
|
|
|
|
case SECPORTAL_CEILING:
|
|
|
|
x = secportal->sector->soundorg.x;
|
|
|
|
y = secportal->sector->soundorg.y;
|
2023-08-24 03:51:52 +00:00
|
|
|
z = P_GetSectorCeilingZAt(secportal->sector, x, y);
|
|
|
|
angle = 0;
|
|
|
|
break;
|
|
|
|
case SECPORTAL_PLANE:
|
|
|
|
case SECPORTAL_HORIZON:
|
|
|
|
portal->is_horizon = true;
|
2023-08-24 19:04:31 +00:00
|
|
|
portal->horizon_sector = secportal->sector;
|
2023-08-24 20:36:38 +00:00
|
|
|
x = secportal->sector->soundorg.x;
|
|
|
|
y = secportal->sector->soundorg.y;
|
2023-08-24 03:51:52 +00:00
|
|
|
if (secportal->type == SECPORTAL_PLANE)
|
|
|
|
z = -viewz;
|
|
|
|
else
|
|
|
|
z = 0;
|
2023-08-23 18:04:50 +00:00
|
|
|
angle = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
2021-04-05 14:23:21 +00:00
|
|
|
}
|
|
|
|
|
2023-08-25 03:18:20 +00:00
|
|
|
fixed_t refx = secportal->origin.x - viewx;
|
|
|
|
fixed_t refy = secportal->origin.y - viewy;
|
2021-04-05 14:23:21 +00:00
|
|
|
|
2023-08-23 18:04:50 +00:00
|
|
|
// Rotate the X/Y to match the target angle
|
|
|
|
if (angle != 0)
|
|
|
|
{
|
|
|
|
fixed_t tr_x = refx, tr_y = refy;
|
|
|
|
angle_t ang = angle >> ANGLETOFINESHIFT;
|
|
|
|
refx = FixedMul(tr_x, FINECOSINE(ang)) - FixedMul(tr_y, FINESINE(ang));
|
|
|
|
refy = FixedMul(tr_x, FINESINE(ang)) + FixedMul(tr_y, FINECOSINE(ang));
|
|
|
|
}
|
|
|
|
|
|
|
|
portal->viewx = x - refx;
|
|
|
|
portal->viewy = y - refy;
|
|
|
|
portal->viewz = z + viewz;
|
|
|
|
portal->viewangle = angle + viewangle;
|
2021-04-05 14:23:21 +00:00
|
|
|
}
|
|
|
|
|
2023-08-24 20:36:38 +00:00
|
|
|
/** Creates a sector portal out of a visplane.
|
|
|
|
*/
|
2023-08-25 03:57:10 +00:00
|
|
|
static boolean Portal_AddSectorPortal (const visplane_t* plane)
|
2023-08-24 20:36:38 +00:00
|
|
|
{
|
|
|
|
INT16 start, end;
|
|
|
|
sectorportal_t *secportal = plane->portalsector;
|
|
|
|
|
|
|
|
// Shortcut
|
|
|
|
if (secportal->type == SECPORTAL_SKYBOX)
|
|
|
|
{
|
2023-08-25 03:57:10 +00:00
|
|
|
if (cv_skybox.value && skyboxmo[0])
|
|
|
|
return Portal_AddSkybox(plane);
|
|
|
|
return false;
|
2023-08-24 20:36:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (TrimVisplaneBounds(plane, &start, &end))
|
2023-08-25 03:57:10 +00:00
|
|
|
return false;
|
2023-08-24 20:36:38 +00:00
|
|
|
|
|
|
|
portal_t* portal = Portal_Add(start, end);
|
|
|
|
|
|
|
|
Portal_ClipVisplane(plane, portal);
|
|
|
|
|
|
|
|
portal->clipline = -1;
|
|
|
|
portal->is_horizon = false;
|
2023-08-25 03:47:40 +00:00
|
|
|
portal->is_skybox = false;
|
2023-08-24 20:36:38 +00:00
|
|
|
portal->horizon_sector = NULL;
|
|
|
|
|
2023-08-25 03:18:20 +00:00
|
|
|
Portal_GetViewpointForSecPortal(portal, secportal);
|
2023-08-25 03:57:10 +00:00
|
|
|
|
|
|
|
return true;
|
2023-08-24 20:36:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Creates a transferred sector portal.
|
|
|
|
*/
|
2023-08-25 03:18:20 +00:00
|
|
|
void Portal_AddTransferred (UINT32 secportalnum, const INT32 x1, const INT32 x2)
|
2023-08-24 20:36:38 +00:00
|
|
|
{
|
|
|
|
if (secportalnum >= secportalcount)
|
|
|
|
return;
|
|
|
|
|
|
|
|
sectorportal_t *secportal = &secportals[secportalnum];
|
|
|
|
if (!P_IsSectorPortalValid(secportal))
|
|
|
|
return;
|
|
|
|
|
|
|
|
portal_t* portal = Portal_Add(x1, x2);
|
2023-08-25 03:47:40 +00:00
|
|
|
portal->is_skybox = false;
|
2023-08-24 20:36:38 +00:00
|
|
|
portal->is_horizon = false;
|
|
|
|
portal->horizon_sector = NULL;
|
|
|
|
|
|
|
|
if (secportal->type == SECPORTAL_SKYBOX)
|
|
|
|
Portal_GetViewpointForSkybox(portal);
|
|
|
|
else
|
2023-08-25 03:18:20 +00:00
|
|
|
Portal_GetViewpointForSecPortal(portal, secportal);
|
2023-08-24 20:36:38 +00:00
|
|
|
|
|
|
|
if (secportal->type == SECPORTAL_LINE)
|
|
|
|
portal->clipline = secportal->line.dest - lines;
|
|
|
|
else
|
|
|
|
portal->clipline = -1;
|
|
|
|
|
|
|
|
Portal_ClipRange(portal);
|
|
|
|
|
|
|
|
portalline = true;
|
|
|
|
}
|
|
|
|
|
2023-08-25 03:47:40 +00:00
|
|
|
/** Creates portals for the currently existing portal visplanes.
|
2019-06-07 11:10:12 +00:00
|
|
|
* The visplanes are also removed and cleared from the list.
|
|
|
|
*/
|
2023-08-25 03:47:40 +00:00
|
|
|
void Portal_AddPlanePortals (boolean add_skyboxes)
|
2019-06-07 11:10:12 +00:00
|
|
|
{
|
|
|
|
visplane_t *pl;
|
|
|
|
|
2023-08-23 07:24:06 +00:00
|
|
|
for (INT32 i = 0; i < MAXVISPLANES; i++, pl++)
|
2019-06-07 11:10:12 +00:00
|
|
|
{
|
|
|
|
for (pl = visplanes[i]; pl; pl = pl->next)
|
|
|
|
{
|
2023-08-25 03:47:40 +00:00
|
|
|
if (pl->minx >= pl->maxx)
|
|
|
|
continue;
|
|
|
|
|
2023-08-23 07:24:06 +00:00
|
|
|
boolean added_portal = false;
|
2021-04-05 14:23:21 +00:00
|
|
|
|
2023-08-23 16:43:02 +00:00
|
|
|
// Render sector portal if recursiveness limit hasn't been reached
|
|
|
|
if (pl->portalsector && portalrender < cv_maxportals.value)
|
2023-08-25 03:57:10 +00:00
|
|
|
added_portal = Portal_AddSectorPortal(pl);
|
2023-08-23 07:24:06 +00:00
|
|
|
|
2023-08-23 16:43:02 +00:00
|
|
|
// Render skybox portal
|
2023-08-25 03:47:40 +00:00
|
|
|
if (!added_portal && pl->picnum == skyflatnum && add_skyboxes && skyboxmo[0])
|
2023-08-25 03:57:10 +00:00
|
|
|
added_portal = Portal_AddSkybox(pl);
|
2019-06-07 11:10:12 +00:00
|
|
|
|
2021-04-05 14:23:21 +00:00
|
|
|
// don't render this visplane anymore
|
2023-08-23 07:24:06 +00:00
|
|
|
if (added_portal)
|
2021-04-05 14:23:21 +00:00
|
|
|
{
|
2019-06-07 11:10:12 +00:00
|
|
|
pl->minx = 0;
|
|
|
|
pl->maxx = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|