diff --git a/extras/conf/udb/Includes/SRB222_misc.cfg b/extras/conf/udb/Includes/SRB222_misc.cfg index 18bb0aec7..2fb863921 100644 --- a/extras/conf/udb/Includes/SRB222_misc.cfg +++ b/extras/conf/udb/Includes/SRB222_misc.cfg @@ -461,6 +461,7 @@ enums 2 = "Skybox"; 3 = "Plane"; 4 = "Horizon"; + 5 = "Transfer to line"; 7 = "Sector"; 8 = "Object"; } diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 5b8f1178d..1d5543202 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -577,7 +577,7 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool for (i = 0; i < subsector->numlines; i++, line++) { - if (!line->glseg && line->linedef->special == HORIZONSPECIAL && R_PointOnSegSide(dup_viewx, dup_viewy, line) == 0) + if (!line->glseg && line->linedef->special == SPECIAL_HORIZON_LINE && R_PointOnSegSide(dup_viewx, dup_viewy, line) == 0) { P_ClosestPointOnLine(viewx, viewy, line->linedef, &v); dist = FIXED_TO_FLOAT(R_PointToDist(v.x, v.y)); @@ -1466,7 +1466,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom else { // Single sided line... Deal only with the middletexture (if one exists) - if (gl_midtexture && gl_linedef->special != HORIZONSPECIAL) // (Ignore horizon line for OGL) + if (gl_midtexture && gl_linedef->special != SPECIAL_HORIZON_LINE) // (Ignore horizon line for OGL) { fixed_t texturevpeg; diff --git a/src/p_map.c b/src/p_map.c index 132a3cf85..b7fcbb2dd 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -3473,7 +3473,7 @@ static void PTR_GlideClimbTraverse(line_t *li) } // see about climbing on the wall - if (!(checkline->flags & ML_NOCLIMB) && checkline->special != HORIZONSPECIAL) + if (!(checkline->flags & ML_NOCLIMB) && checkline->special != SPECIAL_HORIZON_LINE) { boolean canclimb; angle_t climbangle, climbline; diff --git a/src/p_saveg.c b/src/p_saveg.c index b3ac59e81..80b111946 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -886,6 +886,7 @@ static void P_NetUnArchiveWaypoints(void) #define LD_ARGS 0x10 #define LD_STRINGARGS 0x20 #define LD_EXECUTORDELAY 0x40 +#define LD_TRANSFPORTAL 0x80 static boolean P_AreArgsEqual(const line_t *li, const line_t *spawnli) { @@ -1312,6 +1313,9 @@ static void ArchiveLines(void) if (li->executordelay != spawnli->executordelay) diff2 |= LD_EXECUTORDELAY; + if (li->secportal != spawnli->secportal) + diff2 |= LD_TRANSFPORTAL; + if (li->sidenum[0] != 0xffff) { si = &sides[li->sidenum[0]]; @@ -1402,6 +1406,8 @@ static void ArchiveLines(void) } if (diff2 & LD_EXECUTORDELAY) WRITEINT32(save_p, li->executordelay); + if (diff2 & LD_TRANSFPORTAL) + WRITEUINT32(save_p, li->secportal); } } WRITEUINT16(save_p, 0xffff); @@ -1486,7 +1492,8 @@ static void UnArchiveLines(void) } if (diff2 & LD_EXECUTORDELAY) li->executordelay = READINT32(save_p); - + if (diff2 & LD_TRANSFPORTAL) + li->secportal = READUINT32(save_p); } } diff --git a/src/p_setup.c b/src/p_setup.c index 565a44eae..88cd74ed0 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1108,6 +1108,7 @@ static void P_InitializeLinedef(line_t *ld) ld->polyobj = NULL; ld->callcount = 0; + ld->secportal = UINT32_MAX; // cph 2006/09/30 - fix sidedef errors right away. // cph 2002/07/20 - these errors are fatal if not fixed, so apply them diff --git a/src/p_spec.c b/src/p_spec.c index d6b7b18b6..e1dd6bcec 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -6214,7 +6214,7 @@ UINT32 P_NewSectorPortal(void) return (UINT32)i; } -static boolean P_IsSectorPortalValid(sectorportal_t *secportal) +boolean P_IsSectorPortalValid(sectorportal_t *secportal) { if (secportal == NULL) return false; @@ -6325,28 +6325,59 @@ static void P_DoPortalCopyFromLine(sector_t *dest_sector, int plane_type, int ta } } -static sectorportal_t *P_SectorGetFloorPortalOrCreate(sector_t *sector) +static sectorportal_t *P_SectorGetFloorPortalOrCreate(sector_t *sector, UINT32 *result) { - sectorportal_t *secportal = P_SectorGetFloorPortal(sector); - if (secportal == NULL) + *result = sector->portal_floor; + + if (*result >= secportalcount) { - sector->portal_floor = P_NewSectorPortal(); - return &secportals[sector->portal_floor]; + *result = P_NewSectorPortal(); + sector->portal_floor = *result; } - return secportal; + return &secportals[sector->portal_floor]; } -static sectorportal_t *P_SectorGetCeilingPortalOrCreate(sector_t *sector) +static sectorportal_t *P_SectorGetCeilingPortalOrCreate(sector_t *sector, UINT32 *result) { - sectorportal_t *secportal = P_SectorGetCeilingPortal(sector); - if (secportal == NULL) + *result = sector->portal_floor; + + if (*result >= secportalcount) { - sector->portal_ceiling = P_NewSectorPortal(); - return &secportals[sector->portal_ceiling]; + *result = P_NewSectorPortal(); + sector->portal_ceiling = *result; } - return secportal; + return &secportals[sector->portal_ceiling]; +} + +static void P_CopySectorPortalToLines(UINT32 portal_num, int sector_tag) +{ + for (size_t i = 0; i < numlines; i++) + { + if (lines[i].special != SPECIAL_SECTOR_SETPORTAL) + continue; + + if (lines[i].args[1] != TMSECPORTAL_COPY_PORTAL_TO_LINE) + continue; + + if (lines[i].args[3] != sector_tag) + continue; + + if (lines[i].args[0] != 0) + { + INT32 linenum = -1; + TAG_ITER_LINES(lines[i].args[0], linenum) + { + lines[linenum].secportal = portal_num; + } + } + else + { + // Just transfer it to this line + lines[i].secportal = portal_num; + } + } } /** After the map has loaded, scans for specials that spawn 3Dfloors and @@ -6514,7 +6545,7 @@ void P_SpawnSpecials(boolean fromnetsave) P_AddCameraScanner(§ors[sec], §ors[s], R_PointToAngle2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y)); break; - case 6: // Sector portal + case SPECIAL_SECTOR_SETPORTAL: // Sector portal { int target_sector_tag = lines[i].args[0]; int portal_type = lines[i].args[1]; @@ -6530,28 +6561,32 @@ void P_SpawnSpecials(boolean fromnetsave) ceiling = plane_type == TMP_CEILING; } + UINT32 portal_num = UINT32_MAX; + // Eternity's floor and horizon portal types if (portal_type == TMSECPORTAL_PLANE || portal_type == TMSECPORTAL_HORIZON) { secportaltype_e type = portal_type == TMSECPORTAL_HORIZON ? SECPORTAL_HORIZON : SECPORTAL_PLANE; if (floor) { - sectorportal_t *floorportal = P_SectorGetFloorPortalOrCreate(lines[i].frontsector); + sectorportal_t *floorportal = P_SectorGetFloorPortalOrCreate(lines[i].frontsector, &portal_num); floorportal->type = type; floorportal->sector = lines[i].frontsector; + P_CopySectorPortalToLines(portal_num, target_sector_tag); } if (ceiling) { - sectorportal_t *ceilportal = P_SectorGetCeilingPortalOrCreate(lines[i].frontsector); + sectorportal_t *ceilportal = P_SectorGetCeilingPortalOrCreate(lines[i].frontsector, &portal_num); ceilportal->type = type; ceilportal->sector = lines[i].frontsector; + P_CopySectorPortalToLines(portal_num, target_sector_tag); } break; } INT32 s1 = -1; - TAG_ITER_SECTORS(target_sector_tag, s1) // Target sector tag + TAG_ITER_SECTORS(target_sector_tag, s1) { sector_t *target_sector = §ors[s1]; @@ -6561,7 +6596,7 @@ void P_SpawnSpecials(boolean fromnetsave) INT32 linenum = -1; TAG_ITER_LINES(misc, linenum) { - if (lines[linenum].special == 6 + if (lines[linenum].special == SPECIAL_SECTOR_SETPORTAL && lines[linenum].args[0] == target_sector_tag && lines[linenum].args[1] == portal_type && lines[linenum].args[2] == plane_type @@ -6569,17 +6604,19 @@ void P_SpawnSpecials(boolean fromnetsave) { if (floor) { - sectorportal_t *floorportal = P_SectorGetFloorPortalOrCreate(target_sector); + sectorportal_t *floorportal = P_SectorGetFloorPortalOrCreate(target_sector, &portal_num); floorportal->type = SECPORTAL_LINE; floorportal->line.start = &lines[i]; floorportal->line.dest = &lines[linenum]; + P_CopySectorPortalToLines(portal_num, target_sector_tag); } if (ceiling) { - sectorportal_t *ceilportal = P_SectorGetCeilingPortalOrCreate(target_sector); + sectorportal_t *ceilportal = P_SectorGetCeilingPortalOrCreate(target_sector, &portal_num); ceilportal->type = SECPORTAL_LINE; ceilportal->line.start = &lines[i]; ceilportal->line.dest = &lines[linenum]; + P_CopySectorPortalToLines(portal_num, target_sector_tag); } } } @@ -6589,13 +6626,15 @@ void P_SpawnSpecials(boolean fromnetsave) { if (floor) { - sectorportal_t *floorportal = P_SectorGetFloorPortalOrCreate(target_sector); + sectorportal_t *floorportal = P_SectorGetFloorPortalOrCreate(target_sector, &portal_num); floorportal->type = SECPORTAL_SKYBOX; + P_CopySectorPortalToLines(portal_num, target_sector_tag); } if (ceiling) { - sectorportal_t *ceilportal = P_SectorGetCeilingPortalOrCreate(target_sector); + sectorportal_t *ceilportal = P_SectorGetCeilingPortalOrCreate(target_sector, &portal_num); ceilportal->type = SECPORTAL_SKYBOX; + P_CopySectorPortalToLines(portal_num, target_sector_tag); } } // Plane portal @@ -6607,15 +6646,17 @@ void P_SpawnSpecials(boolean fromnetsave) sector_t *view_sector = §ors[s2]; if (floor) { - sectorportal_t *floorportal = P_SectorGetFloorPortalOrCreate(target_sector); + sectorportal_t *floorportal = P_SectorGetFloorPortalOrCreate(target_sector, &portal_num); floorportal->type = SECPORTAL_CEILING; floorportal->sector = view_sector; + P_CopySectorPortalToLines(portal_num, target_sector_tag); } if (ceiling) { - sectorportal_t *ceilportal = P_SectorGetCeilingPortalOrCreate(target_sector); + sectorportal_t *ceilportal = P_SectorGetCeilingPortalOrCreate(target_sector, &portal_num); ceilportal->type = SECPORTAL_FLOOR; ceilportal->sector = view_sector; + P_CopySectorPortalToLines(portal_num, target_sector_tag); } } } @@ -6627,15 +6668,17 @@ void P_SpawnSpecials(boolean fromnetsave) break; if (floor) { - sectorportal_t *floorportal = P_SectorGetFloorPortalOrCreate(target_sector); + sectorportal_t *floorportal = P_SectorGetFloorPortalOrCreate(target_sector, &portal_num); floorportal->type = SECPORTAL_OBJECT; P_SetTarget(&floorportal->mobj, mobj); + P_CopySectorPortalToLines(portal_num, target_sector_tag); } if (ceiling) { - sectorportal_t *ceilportal = P_SectorGetCeilingPortalOrCreate(target_sector); + sectorportal_t *ceilportal = P_SectorGetCeilingPortalOrCreate(target_sector, &portal_num); ceilportal->type = SECPORTAL_OBJECT; P_SetTarget(&ceilportal->mobj, mobj); + P_CopySectorPortalToLines(portal_num, target_sector_tag); } } } @@ -7448,7 +7491,7 @@ void P_SpawnSpecials(boolean fromnetsave) // Copy portals for (i = 0; i < numlines; i++) { - if (lines[i].special != 6) + if (lines[i].special != SPECIAL_SECTOR_SETPORTAL) continue; int portal_type = lines[i].args[1]; @@ -7470,7 +7513,6 @@ void P_SpawnSpecials(boolean fromnetsave) TAG_ITER_SECTORS(target_sector_tag, s1) P_DoPortalCopyFromLine(§ors[s1], plane_type, tag_to_copy); } - break; } if (!fromnetsave) diff --git a/src/p_spec.h b/src/p_spec.h index 87f9951a6..3bbaba58b 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -483,9 +483,8 @@ typedef enum TMSECPORTAL_SKYBOX = 2, TMSECPORTAL_PLANE = 3, TMSECPORTAL_HORIZON = 4, - // The two portal types below are unimplemented TMSECPORTAL_COPY_PORTAL_TO_LINE = 5, - TMSECPORTAL_INTERACTIVE = 6, + TMSECPORTAL_INTERACTIVE = 6, // unimplemented // The two portal types below are new to SRB2 TMSECPORTAL_SECTOR = 7, TMSECPORTAL_OBJECT = 8 @@ -543,6 +542,8 @@ boolean P_IsFlagAtBase(mobjtype_t flag); void P_InitSectorPortals(void); UINT32 P_NewSectorPortal(void); +boolean P_IsSectorPortalValid(sectorportal_t *secportal); + sectorportal_t *P_SectorGetFloorPortal(sector_t *sector); sectorportal_t *P_SectorGetCeilingPortal(sector_t *sector); diff --git a/src/r_bsp.c b/src/r_bsp.c index 91b4fdbc0..4bb0e290c 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -458,7 +458,7 @@ static void R_AddLine(seg_t *line) return; backsector = line->backsector; - horizonline = line->linedef->special == HORIZONSPECIAL; + horizonline = line->linedef->special == SPECIAL_HORIZON_LINE; bothceilingssky = bothfloorssky = false; // Portal line @@ -484,6 +484,15 @@ static void R_AddLine(seg_t *line) } } } + // Transferred portal + else if (line->linedef->secportal != UINT32_MAX && line->side == 0) + { + if (portalrender < cv_maxportals.value) + { + Portal_AddTransferred(line->linedef-lines, line->linedef->secportal, x1, x2); + goto clipsolid; + } + } // Single sided line? if (!backsector) diff --git a/src/r_defs.h b/src/r_defs.h index b6ea8d6e5..865776146 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -536,7 +536,9 @@ typedef enum ST_NEGATIVE } slopetype_t; -#define HORIZONSPECIAL 41 +#define SPECIAL_HORIZON_LINE 41 + +#define SPECIAL_SECTOR_SETPORTAL 6 #define NUMLINEARGS 10 #define NUMLINESTRINGARGS 2 @@ -577,6 +579,8 @@ typedef struct line_s polyobj_t *polyobj; // Belongs to a polyobject? INT16 callcount; // no. of calls left before triggering, for the "X calls" linedef specials, defaults to 0 + + UINT32 secportal; // transferred sector portal } line_t; typedef struct diff --git a/src/r_portal.c b/src/r_portal.c index 327821b9d..f66424ab6 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -263,30 +263,14 @@ static boolean TrimVisplaneBounds (const visplane_t* plane, INT16* start, INT16* return false; } -/** Creates a skybox portal out of a visplane. - * - * Applies the necessary offsets and rotation to give - * a depth illusion to the skybox. - */ -void Portal_AddSkybox (const visplane_t* plane) +static void Portal_GetViewpointForSkybox(portal_t *portal) { - INT16 start, end; - mapheader_t *mh; - portal_t* portal; - - if (TrimVisplaneBounds(plane, &start, &end)) - return; - - portal = Portal_Add(start, end); - - Portal_ClipVisplane(plane, portal); - portal->viewx = skyboxmo[0]->x; portal->viewy = skyboxmo[0]->y; portal->viewz = skyboxmo[0]->z; portal->viewangle = viewangle + skyboxmo[0]->angle; - mh = mapheaderinfo[gamemap-1]; + mapheader_t *mh = mapheaderinfo[gamemap-1]; // If a relative viewpoint exists, offset the viewpoint. if (skyboxmo[1]) @@ -313,31 +297,22 @@ void Portal_AddSkybox (const visplane_t* plane) portal->viewz += viewz / mh->skybox_scalez; else if (mh->skybox_scalez < 0) portal->viewz += viewz * -mh->skybox_scalez; - - portal->clipline = -1; - portal->is_horizon = false; - portal->horizon_sector = NULL; } -/** Creates a sector portal out of a visplane. +/** Creates a skybox portal out of a visplane. + * + * Applies the necessary offsets and rotation to give + * a depth illusion to the skybox. */ -void Portal_AddSectorPortal (const visplane_t* plane) +void Portal_AddSkybox (const visplane_t* plane) { INT16 start, end; - fixed_t x, y, z, angle; - sectorportal_t *secportal = plane->portalsector; - - // Shortcut - if (secportal->type == SECPORTAL_SKYBOX) - { - Portal_AddSkybox(plane); - return; - } + portal_t* portal; if (TrimVisplaneBounds(plane, &start, &end)) return; - portal_t* portal = Portal_Add(start, end); + portal = Portal_Add(start, end); Portal_ClipVisplane(plane, portal); @@ -345,6 +320,13 @@ void Portal_AddSectorPortal (const visplane_t* plane) portal->is_horizon = false; portal->horizon_sector = NULL; + Portal_GetViewpointForSkybox(portal); +} + +static void Portal_GetViewpointForSecPortal(portal_t *portal, sectorportal_t *secportal, fixed_t origin_x, fixed_t origin_y) +{ + fixed_t x, y, z, angle; + switch (secportal->type) { case SECPORTAL_LINE: @@ -374,8 +356,8 @@ void Portal_AddSectorPortal (const visplane_t* plane) case SECPORTAL_HORIZON: portal->is_horizon = true; portal->horizon_sector = secportal->sector; - x = plane->sector->soundorg.x; - y = plane->sector->soundorg.y; + x = secportal->sector->soundorg.x; + y = secportal->sector->soundorg.y; if (secportal->type == SECPORTAL_PLANE) z = -viewz; else @@ -386,8 +368,8 @@ void Portal_AddSectorPortal (const visplane_t* plane) return; } - fixed_t refx = plane->sector->soundorg.x - viewx; - fixed_t refy = plane->sector->soundorg.y - viewy; + fixed_t refx = origin_x - viewx; + fixed_t refy = origin_y - viewy; // Rotate the X/Y to match the target angle if (angle != 0) @@ -404,6 +386,70 @@ void Portal_AddSectorPortal (const visplane_t* plane) portal->viewangle = angle + viewangle; } +/** Creates a sector portal out of a visplane. + */ +void Portal_AddSectorPortal (const visplane_t* plane) +{ + INT16 start, end; + sectorportal_t *secportal = plane->portalsector; + + // Shortcut + if (secportal->type == SECPORTAL_SKYBOX) + { + Portal_AddSkybox(plane); + return; + } + + if (TrimVisplaneBounds(plane, &start, &end)) + return; + + portal_t* portal = Portal_Add(start, end); + + Portal_ClipVisplane(plane, portal); + + portal->clipline = -1; + portal->is_horizon = false; + portal->horizon_sector = NULL; + + Portal_GetViewpointForSecPortal(portal, secportal, plane->sector->soundorg.x, plane->sector->soundorg.y); +} + +/** Creates a transferred sector portal. + */ +void Portal_AddTransferred (const INT32 linenum, UINT32 secportalnum, const INT32 x1, const INT32 x2) +{ + if (secportalnum >= secportalcount) + return; + + sectorportal_t *secportal = &secportals[secportalnum]; + if (!P_IsSectorPortalValid(secportal)) + return; + + portal_t* portal = Portal_Add(x1, x2); + + portal->is_horizon = false; + portal->horizon_sector = NULL; + + if (secportal->type == SECPORTAL_SKYBOX) + Portal_GetViewpointForSkybox(portal); + else + { + line_t *line = &lines[linenum]; + fixed_t refx = (line->v1->x + line->v2->x) / 2; + fixed_t refy = (line->v1->y + line->v2->y) / 2; + Portal_GetViewpointForSecPortal(portal, secportal, refx, refy); + } + + if (secportal->type == SECPORTAL_LINE) + portal->clipline = secportal->line.dest - lines; + else + portal->clipline = -1; + + Portal_ClipRange(portal); + + portalline = true; +} + /** Creates portals for the currently existing sky visplanes. * The visplanes are also removed and cleared from the list. */ diff --git a/src/r_portal.h b/src/r_portal.h index 1a8291f3c..7e0f63fe1 100644 --- a/src/r_portal.h +++ b/src/r_portal.h @@ -58,6 +58,7 @@ void Portal_Remove (portal_t* portal); void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, const INT32 x2); void Portal_AddSkybox (const visplane_t* plane); void Portal_AddSectorPortal (const visplane_t* plane); +void Portal_AddTransferred (const INT32 linenum, UINT32 secportalnum, const INT32 x1, const INT32 x2); void Portal_ClipRange (portal_t* portal); void Portal_ClipApply (const portal_t* portal);