diff --git a/extras/conf/udb/Includes/SRB222_linedefs.cfg b/extras/conf/udb/Includes/SRB222_linedefs.cfg index 680778623..152cafe21 100644 --- a/extras/conf/udb/Includes/SRB222_linedefs.cfg +++ b/extras/conf/udb/Includes/SRB222_linedefs.cfg @@ -10,6 +10,45 @@ udmf prefix = "(0)"; } + 6 + { + title = "Sector Set Portal"; + prefix = "(6)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Portal type"; + type = 11; + enum + { + 0 = "Link to portal with same tag"; + 1 = "Copy portal from second tag"; + 2 = "Skybox portal"; + 3 = "Plane portal"; + 4 = "Horizon portal"; + 5 = "Copy portal to line"; + 6 = "Interactive portal (unimplemented)"; + 7 = "Link to sector with second tag"; + 8 = "Link to object with second tag"; + } + } + arg2 + { + title = "Affected planes"; + type = 11; + enum = "floorceiling"; + } + arg3 + { + title = "Misc"; + tooltip = "For type 0 portal: specifies whether the line belongs to the sector viewed\nthrough the portal (1) or the sector in which the portal is seen (0).\nFor type 1 portal: specifies the sector tag of the portal to copy.\nFor type 7 portal: specifies the sector tag to make a portal to.\nFor type 8 portal: specifies the object tag to make a portal to."; + } + } + 7 { title = "Sector Flat Alignment"; diff --git a/src/deh_tables.c b/src/deh_tables.c index b53cd00c8..6d29fa2c7 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4291,7 +4291,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_POLYANCHOR", "MT_POLYSPAWN", - // Skybox objects + // Portal objects "MT_SKYBOX", // Debris diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 60a5b2562..d448aa55e 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -566,7 +566,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)); @@ -1139,9 +1139,6 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom INT32 gl_toptexture = 0, gl_bottomtexture = 0; fixed_t texturevpeg; - boolean bothceilingssky = false; // turned on if both back and front ceilings are sky - boolean bothfloorssky = false; // likewise, but for floors - SLOPEPARAMS(gl_backsector->c_slope, worldhigh, worldhighslope, gl_backsector->ceilingheight) SLOPEPARAMS(gl_backsector->f_slope, worldlow, worldlowslope, gl_backsector->floorheight) @@ -1506,7 +1503,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) { grTex = HWR_GetTexture(gl_midtexture); xscale = FixedToFloat(gl_sidedef->scalex_mid); @@ -1885,12 +1882,6 @@ static boolean CheckClip(seg_t * seg, sector_t * afrontsector, sector_t * abacks { fixed_t frontf1,frontf2, frontc1, frontc2; // front floor/ceiling ends fixed_t backf1, backf2, backc1, backc2; // back floor ceiling ends - boolean bothceilingssky = false, bothfloorssky = false; - - if (abacksector->ceilingpic == skyflatnum && afrontsector->ceilingpic == skyflatnum) - bothceilingssky = true; - if (abacksector->floorpic == skyflatnum && afrontsector->floorpic == skyflatnum) - bothfloorssky = true; // GZDoom method of sloped line clipping @@ -2409,6 +2400,7 @@ static void HWR_AddLine(seg_t * line) #endif gl_backsector = line->backsector; + bothceilingssky = bothfloorssky = false; #ifdef NEWCLIP if (!line->backsector) @@ -2417,13 +2409,14 @@ static void HWR_AddLine(seg_t * line) } else { - boolean bothceilingssky = false, bothfloorssky = false; - gl_backsector = R_FakeFlat(gl_backsector, &tempsec, NULL, NULL, true); - if (gl_backsector->ceilingpic == skyflatnum && gl_frontsector->ceilingpic == skyflatnum) + if (gl_backsector->ceilingpic == skyflatnum && gl_frontsector->ceilingpic == skyflatnum + && !(P_SectorHasCeilingPortal(gl_backsector) || P_SectorHasCeilingPortal(gl_frontsector))) bothceilingssky = true; - if (gl_backsector->floorpic == skyflatnum && gl_frontsector->floorpic == skyflatnum) + + if (gl_backsector->floorpic == skyflatnum && gl_frontsector->floorpic == skyflatnum + && !(P_SectorHasFloorPortal(gl_backsector) || P_SectorHasFloorPortal(gl_frontsector))) bothfloorssky = true; if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then @@ -3020,64 +3013,16 @@ static void HWR_Subsector(size_t num) } //SoM: 4/7/2000: Test to make Boom water work in Hardware mode. - gl_frontsector = R_FakeFlat(gl_frontsector, &tempsec, &floorlightlevel, - &ceilinglightlevel, false); - //FIXME: Use floorlightlevel and ceilinglightlevel insted of lightlevel. + gl_frontsector = R_FakeFlat(gl_frontsector, &tempsec, &floorlightlevel, &ceilinglightlevel, false); floorcolormap = ceilingcolormap = gl_frontsector->extra_colormap; - // ------------------------------------------------------------------------ - // sector lighting, DISABLED because it's done in HWR_StoreWallRange - // ------------------------------------------------------------------------ - /// \todo store a RGBA instead of just intensity, allow coloured sector lighting - //light = (FUBYTE)(sub->sector->lightlevel & 0xFF) / 255.0f; - //gl_cursectorlight.red = light; - //gl_cursectorlight.green = light; - //gl_cursectorlight.blue = light; - //gl_cursectorlight.alpha = light; - -// ----- end special tricks ----- cullFloorHeight = P_GetSectorFloorZAt (gl_frontsector, viewx, viewy); cullCeilingHeight = P_GetSectorCeilingZAt(gl_frontsector, viewx, viewy); locFloorHeight = P_GetSectorFloorZAt (gl_frontsector, gl_frontsector->soundorg.x, gl_frontsector->soundorg.y); locCeilingHeight = P_GetSectorCeilingZAt(gl_frontsector, gl_frontsector->soundorg.x, gl_frontsector->soundorg.y); - if (gl_frontsector->ffloors) - { - boolean anyMoved = gl_frontsector->moved; - - if (anyMoved == false) - { - for (rover = gl_frontsector->ffloors; rover; rover = rover->next) - { - sector_t *controlSec = §ors[rover->secnum]; - if (controlSec->moved == true) - { - anyMoved = true; - break; - } - } - } - - if (anyMoved == true) - { - gl_frontsector->numlights = sub->sector->numlights = 0; - R_Prep3DFloors(gl_frontsector); - sub->sector->lightlist = gl_frontsector->lightlist; - sub->sector->numlights = gl_frontsector->numlights; - sub->sector->moved = gl_frontsector->moved = false; - } - - light = R_GetPlaneLight(gl_frontsector, locFloorHeight, false); - if (gl_frontsector->floorlightsec == -1 && !gl_frontsector->floorlightabsolute) - floorlightlevel = max(0, min(255, *gl_frontsector->lightlist[light].lightlevel + gl_frontsector->floorlightlevel)); - floorcolormap = *gl_frontsector->lightlist[light].extra_colormap; - - light = R_GetPlaneLight(gl_frontsector, locCeilingHeight, false); - if (gl_frontsector->ceilinglightsec == -1 && !gl_frontsector->ceilinglightabsolute) - ceilinglightlevel = max(0, min(255, *gl_frontsector->lightlist[light].lightlevel + gl_frontsector->ceilinglightlevel)); - ceilingcolormap = *gl_frontsector->lightlist[light].extra_colormap; - } + R_CheckSectorLightLists(sub->sector, gl_frontsector, &floorlightlevel, &ceilinglightlevel, &floorcolormap, &ceilingcolormap); sub->sector->extra_colormap = gl_frontsector->extra_colormap; diff --git a/src/info.h b/src/info.h index a2d87dbdc..20a0a4b8a 100644 --- a/src/info.h +++ b/src/info.h @@ -5123,7 +5123,7 @@ typedef enum mobj_type MT_POLYANCHOR, MT_POLYSPAWN, - // Skybox objects + // Portal objects MT_SKYBOX, // Debris diff --git a/src/p_map.c b/src/p_map.c index e01798054..1888d92af 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -3477,7 +3477,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 0f3668f5a..41d7e3c80 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -41,20 +41,19 @@ UINT8 *save_p; // Block UINT32s to attempt to ensure that the correct data is // being sent and received -#define ARCHIVEBLOCK_MISC 0x7FEEDEED -#define ARCHIVEBLOCK_PLAYERS 0x7F448008 -#define ARCHIVEBLOCK_WORLD 0x7F8C08C0 -#define ARCHIVEBLOCK_POBJS 0x7F928546 -#define ARCHIVEBLOCK_THINKERS 0x7F37037C -#define ARCHIVEBLOCK_SPECIALS 0x7F228378 -#define ARCHIVEBLOCK_EMBLEMS 0x7F4A5445 +#define ARCHIVEBLOCK_MISC 0x7FEEDEED +#define ARCHIVEBLOCK_PLAYERS 0x7F448008 +#define ARCHIVEBLOCK_WORLD 0x7F8C08C0 +#define ARCHIVEBLOCK_POBJS 0x7F928546 +#define ARCHIVEBLOCK_THINKERS 0x7F37037C +#define ARCHIVEBLOCK_SPECIALS 0x7F228378 +#define ARCHIVEBLOCK_EMBLEMS 0x7F4A5445 +#define ARCHIVEBLOCK_SECPORTALS 0x7FBE34C9 // Note: This cannot be bigger // than an UINT16 typedef enum { -// RFLAGPOINT = 0x01, -// BFLAGPOINT = 0x02, CAPSULE = 0x04, AWAYVIEW = 0x08, FIRSTAXIS = 0x10, @@ -853,33 +852,43 @@ static void P_NetUnArchiveWaypoints(void) #define SD_DIFF3 0x80 // diff3 flags -#define SD_TAGLIST 0x01 -#define SD_COLORMAP 0x02 +#define SD_TAGLIST 0x01 +#define SD_COLORMAP 0x02 #define SD_CRUMBLESTATE 0x04 -#define SD_FLOORLIGHT 0x08 -#define SD_CEILLIGHT 0x10 -#define SD_FLAG 0x20 -#define SD_SPECIALFLAG 0x40 -#define SD_DIFF4 0x80 +#define SD_FLOORLIGHT 0x08 +#define SD_CEILLIGHT 0x10 +#define SD_FLAG 0x20 +#define SD_SPECIALFLAG 0x40 +#define SD_DIFF4 0x80 -//diff4 flags +// diff4 flags #define SD_DAMAGETYPE 0x01 #define SD_TRIGGERTAG 0x02 #define SD_TRIGGERER 0x04 -#define SD_GRAVITY 0x08 -#define SD_FXSCALE 0x10 -#define SD_FYSCALE 0x20 -#define SD_CXSCALE 0x40 -#define SD_CYSCALE 0x80 +#define SD_FXSCALE 0x08 +#define SD_FYSCALE 0x10 +#define SD_CXSCALE 0x20 +#define SD_CYSCALE 0x40 +#define SD_DIFF5 0x80 +// diff5 flags +#define SD_GRAVITY 0x01 +#define SD_FLOORPORTAL 0x02 +#define SD_CEILPORTAL 0x04 + +// diff1 flags #define LD_FLAG 0x01 #define LD_SPECIAL 0x02 #define LD_CLLCOUNT 0x04 #define LD_ARGS 0x08 #define LD_STRINGARGS 0x10 -#define LD_EXECUTORDELAY 0x20 -#define LD_SIDE1 0x40 -#define LD_SIDE2 0x80 +#define LD_SIDE1 0x20 +#define LD_SIDE2 0x40 +#define LD_DIFF2 0x80 + +// diff2 flags +#define LD_EXECUTORDELAY 0x01 +#define LD_TRANSFPORTAL 0x02 // sidedef flags enum @@ -1028,11 +1037,11 @@ static void ArchiveSectors(void) size_t i, j; const sector_t *ss = sectors; const sector_t *spawnss = spawnsectors; - UINT8 diff, diff2, diff3, diff4; + UINT8 diff, diff2, diff3, diff4, diff5; for (i = 0; i < numsectors; i++, ss++, spawnss++) { - diff = diff2 = diff3 = diff4 = 0; + diff = diff2 = diff3 = diff4 = diff5 = 0; if (ss->floorheight != spawnss->floorheight) diff |= SD_FLOORHT; if (ss->ceilingheight != spawnss->ceilingheight) @@ -1094,11 +1103,18 @@ static void ArchiveSectors(void) if (ss->triggerer != spawnss->triggerer) diff4 |= SD_TRIGGERER; if (ss->gravity != spawnss->gravity) - diff4 |= SD_GRAVITY; + diff5 |= SD_GRAVITY; + if (ss->portal_floor != spawnss->portal_floor) + diff5 |= SD_FLOORPORTAL; + if (ss->portal_ceiling != spawnss->portal_ceiling) + diff5 |= SD_CEILPORTAL; if (ss->ffloors && CheckFFloorDiff(ss)) diff |= SD_FFLOORS; + if (diff5) + diff4 |= SD_DIFF5; + if (diff4) diff3 |= SD_DIFF4; @@ -1118,6 +1134,8 @@ static void ArchiveSectors(void) WRITEUINT8(save_p, diff3); if (diff3 & SD_DIFF4) WRITEUINT8(save_p, diff4); + if (diff4 & SD_DIFF5) + WRITEUINT8(save_p, diff5); if (diff & SD_FLOORHT) WRITEFIXED(save_p, ss->floorheight); if (diff & SD_CEILHT) @@ -1174,8 +1192,6 @@ static void ArchiveSectors(void) WRITEINT16(save_p, ss->triggertag); if (diff4 & SD_TRIGGERER) WRITEUINT8(save_p, ss->triggerer); - if (diff4 & SD_GRAVITY) - WRITEFIXED(save_p, ss->gravity); if (diff4 & SD_FXSCALE) WRITEFIXED(save_p, ss->floorxscale); if (diff4 & SD_FYSCALE) @@ -1184,6 +1200,12 @@ static void ArchiveSectors(void) WRITEFIXED(save_p, ss->ceilingxscale); if (diff4 & SD_CYSCALE) WRITEFIXED(save_p, ss->ceilingyscale); + if (diff5 & SD_GRAVITY) + WRITEFIXED(save_p, ss->gravity); + if (diff5 & SD_FLOORPORTAL) + WRITEUINT32(save_p, ss->portal_floor); + if (diff5 & SD_CEILPORTAL) + WRITEUINT32(save_p, ss->portal_ceiling); if (diff & SD_FFLOORS) ArchiveFFloors(ss); } @@ -1196,7 +1218,7 @@ static void UnArchiveSectors(void) { UINT32 i; UINT16 j; - UINT8 diff, diff2, diff3, diff4; + UINT8 diff, diff2, diff3, diff4, diff5; for (;;) { i = READUINT32(save_p); @@ -1220,6 +1242,10 @@ static void UnArchiveSectors(void) diff4 = READUINT8(save_p); else diff4 = 0; + if (diff4 & SD_DIFF5) + diff5 = READUINT8(save_p); + else + diff5 = 0; if (diff & SD_FLOORHT) sectors[i].floorheight = READFIXED(save_p); @@ -1303,8 +1329,6 @@ static void UnArchiveSectors(void) sectors[i].triggertag = READINT16(save_p); if (diff4 & SD_TRIGGERER) sectors[i].triggerer = READUINT8(save_p); - if (diff4 & SD_GRAVITY) - sectors[i].gravity = READFIXED(save_p); if (diff4 & SD_FXSCALE) sectors[i].floorxscale = READFIXED(save_p); if (diff4 & SD_FYSCALE) @@ -1313,6 +1337,12 @@ static void UnArchiveSectors(void) sectors[i].ceilingxscale = READFIXED(save_p); if (diff4 & SD_CYSCALE) sectors[i].ceilingyscale = READFIXED(save_p); + if (diff5 & SD_GRAVITY) + sectors[i].gravity = READFIXED(save_p); + if (diff5 & SD_FLOORPORTAL) + sectors[i].portal_floor = READUINT32(save_p); + if (diff5 & SD_CEILPORTAL) + sectors[i].portal_ceiling = READUINT32(save_p); if (diff & SD_FFLOORS) UnArchiveFFloors(§ors[i]); @@ -1409,13 +1439,14 @@ static void ArchiveLines(void) size_t i; const line_t *li = lines; const line_t *spawnli = spawnlines; - UINT8 diff; - UINT32 diff2; - UINT32 diff3; + UINT8 diff, diff2; + UINT32 side1diff; + UINT32 side2diff; for (i = 0; i < numlines; i++, spawnli++, li++) { - diff = diff2 = diff3 = 0; + diff = diff2 = 0; + side1diff = side2diff = 0; if (li->special != spawnli->special) diff |= LD_SPECIAL; @@ -1430,25 +1461,33 @@ static void ArchiveLines(void) diff |= LD_STRINGARGS; if (li->executordelay != spawnli->executordelay) - diff |= LD_EXECUTORDELAY; + diff2 |= LD_EXECUTORDELAY; + + if (li->secportal != spawnli->secportal) + diff2 |= LD_TRANSFPORTAL; if (li->sidenum[0] != NO_SIDEDEF) { - diff2 = GetSideDiff(&sides[li->sidenum[0]], &spawnsides[li->sidenum[0]]); - if (diff2) + side1diff = GetSideDiff(&sides[li->sidenum[0]], &spawnsides[li->sidenum[0]]); + if (side1diff) diff |= LD_SIDE1; } if (li->sidenum[1] != NO_SIDEDEF) { - diff3 = GetSideDiff(&sides[li->sidenum[1]], &spawnsides[li->sidenum[1]]); - if (diff3) + side2diff = GetSideDiff(&sides[li->sidenum[1]], &spawnsides[li->sidenum[1]]); + if (side2diff) diff |= LD_SIDE2; } + if (diff2) + diff |= LD_DIFF2; + if (diff) { WRITEUINT32(save_p, i); WRITEUINT8(save_p, diff); + if (diff & LD_DIFF2) + WRITEUINT8(save_p, diff2); if (diff & LD_FLAG) WRITEINT16(save_p, li->flags); if (diff & LD_SPECIAL) @@ -1480,12 +1519,14 @@ static void ArchiveLines(void) WRITECHAR(save_p, li->stringargs[j][k]); } } - if (diff & LD_EXECUTORDELAY) - WRITEINT32(save_p, li->executordelay); if (diff & LD_SIDE1) - ArchiveSide(&sides[li->sidenum[0]], diff2); + ArchiveSide(&sides[li->sidenum[0]], side1diff); if (diff & LD_SIDE2) - ArchiveSide(&sides[li->sidenum[1]], diff3); + ArchiveSide(&sides[li->sidenum[1]], side2diff); + if (diff2 & LD_EXECUTORDELAY) + WRITEINT32(save_p, li->executordelay); + if (diff2 & LD_TRANSFPORTAL) + WRITEUINT32(save_p, li->secportal); } } WRITEUINT32(save_p, 0xffffffff); @@ -1537,7 +1578,7 @@ static void UnArchiveLines(void) { UINT32 i; line_t *li; - UINT8 diff; + UINT8 diff, diff2; for (;;) { @@ -1549,6 +1590,10 @@ static void UnArchiveLines(void) I_Error("Invalid line number %u from server", i); diff = READUINT8(save_p); + if (diff & LD_DIFF2) + diff2 = READUINT8(save_p); + else + diff2 = 0; li = &lines[i]; if (diff & LD_FLAG) @@ -1584,12 +1629,14 @@ static void UnArchiveLines(void) li->stringargs[j][len] = '\0'; } } - if (diff & LD_EXECUTORDELAY) - li->executordelay = READINT32(save_p); if (diff & LD_SIDE1) UnArchiveSide(&sides[li->sidenum[0]]); if (diff & LD_SIDE2) UnArchiveSide(&sides[li->sidenum[1]]); + if (diff2 & LD_EXECUTORDELAY) + li->executordelay = READINT32(save_p); + if (diff2 & LD_TRANSFPORTAL) + li->secportal = READUINT32(save_p); } } @@ -4851,6 +4898,86 @@ static inline void P_NetUnArchiveEmblems(void) } } +static void P_NetArchiveSectorPortals(void) +{ + WRITEUINT32(save_p, ARCHIVEBLOCK_SECPORTALS); + + WRITEUINT32(save_p, secportalcount); + + for (size_t i = 0; i < secportalcount; i++) + { + UINT8 type = secportals[i].type; + + WRITEUINT8(save_p, type); + WRITEFIXED(save_p, secportals[i].origin.x); + WRITEFIXED(save_p, secportals[i].origin.y); + + switch (type) + { + case SECPORTAL_LINE: + WRITEUINT32(save_p, SaveLine(secportals[i].line.start)); + WRITEUINT32(save_p, SaveLine(secportals[i].line.dest)); + break; + case SECPORTAL_PLANE: + case SECPORTAL_HORIZON: + case SECPORTAL_FLOOR: + case SECPORTAL_CEILING: + WRITEUINT32(save_p, SaveSector(secportals[i].sector)); + break; + case SECPORTAL_OBJECT: + if (secportals[i].mobj && !P_MobjWasRemoved(secportals[i].mobj)) + SaveMobjnum(secportals[i].mobj); + else + WRITEUINT32(save_p, 0); + break; + default: + break; + } + } +} + +static void P_NetUnArchiveSectorPortals(void) +{ + if (READUINT32(save_p) != ARCHIVEBLOCK_SECPORTALS) + I_Error("Bad $$$.sav at archive block Secportals"); + + Z_Free(secportals); + P_InitSectorPortals(); + + UINT32 count = READUINT32(save_p); + + for (UINT32 i = 0; i < count; i++) + { + UINT32 id = P_NewSectorPortal(); + + sectorportal_t *secportal = &secportals[id]; + + secportal->type = READUINT8(save_p); + secportal->origin.x = READFIXED(save_p); + secportal->origin.y = READFIXED(save_p); + + switch (secportal->type) + { + case SECPORTAL_LINE: + secportal->line.start = LoadLine(READUINT32(save_p)); + secportal->line.dest = LoadLine(READUINT32(save_p)); + break; + case SECPORTAL_PLANE: + case SECPORTAL_HORIZON: + case SECPORTAL_FLOOR: + case SECPORTAL_CEILING: + secportal->sector = LoadSector(READUINT32(save_p)); + break; + case SECPORTAL_OBJECT: + id = READUINT32(save_p); + secportal->mobj = (id == 0) ? NULL : P_FindNewPosition(id); + break; + default: + break; + } + } +} + static inline void P_ArchiveLuabanksAndConsistency(void) { UINT8 i, banksinuse = NUM_LUABANKS; @@ -4937,6 +5064,7 @@ void P_SaveNetGame(boolean resending) P_NetArchiveSpecials(); P_NetArchiveColormaps(); P_NetArchiveWaypoints(); + P_NetArchiveSectorPortals(); } LUA_Archive(); @@ -4977,6 +5105,7 @@ boolean P_LoadNetGame(boolean reloading) P_NetUnArchiveSpecials(); P_NetUnArchiveColormaps(); P_NetUnArchiveWaypoints(); + P_NetUnArchiveSectorPortals(); P_RelinkPointers(); P_FinishMobjs(); } diff --git a/src/p_setup.c b/src/p_setup.c index 9ae73c18b..1c0315847 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -993,6 +993,9 @@ static void P_InitializeSector(sector_t *ss) ss->lightingdata = NULL; ss->fadecolormapdata = NULL; + ss->portal_floor = UINT32_MAX; + ss->portal_ceiling = UINT32_MAX; + ss->heightsec = -1; ss->camsec = -1; @@ -1110,6 +1113,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 @@ -7883,6 +7887,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) P_InitThinkers(); R_InitMobjInterpolators(); P_InitCachedActions(); + P_InitSectorPortals(); // internal game map maplumpname = G_BuildMapName(gamemap); diff --git a/src/p_spec.c b/src/p_spec.c index 3dbbc5352..7bec07c92 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -52,6 +52,10 @@ mobj_t *skyboxmo[2]; // current skybox mobjs: 0 = viewpoint, 1 = centerpoint mobj_t *skyboxviewpnts[16]; // array of MT_SKYBOX viewpoint mobjs mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs +size_t secportalcount; +size_t secportalcapacity; +sectorportal_t *secportals; + /** Animated texture descriptor * This keeps track of an animated texture or an animated flat. * \sa P_UpdateSpecials, P_InitPicAnims, animdef_t @@ -6199,6 +6203,196 @@ fixed_t P_GetSectorGravityFactor(sector_t *sec) return sec->gravity; } +void P_InitSectorPortals(void) +{ + secportalcount = 0; + secportalcapacity = 0; + secportals = NULL; +} + +UINT32 P_NewSectorPortal(void) +{ + size_t i = secportalcount++; + if (i == UINT32_MAX) + I_Error("Too many sector portals"); + + if (secportalcapacity == 0 || secportalcount == secportalcapacity) + { + secportalcapacity = secportalcapacity ? (secportalcapacity * 2) : 16; + secportals = Z_Realloc(secportals, secportalcapacity * sizeof(sectorportal_t), PU_LEVEL, NULL); + } + + secportals[i].type = SECPORTAL_NONE; + + return (UINT32)i; +} + +boolean P_IsSectorPortalValid(sectorportal_t *secportal) +{ + if (secportal == NULL) + return false; + + switch (secportal->type) + { + case SECPORTAL_LINE: + case SECPORTAL_FLOOR: + case SECPORTAL_CEILING: + return true; + case SECPORTAL_OBJECT: + return secportal->mobj && !P_MobjWasRemoved(secportal->mobj); + case SECPORTAL_SKYBOX: + return skyboxmo[0] && !P_MobjWasRemoved(skyboxmo[0]); + case SECPORTAL_PLANE: + case SECPORTAL_HORIZON: + return true; + default: + return false; + } +} + +boolean P_SectorHasPortal(sector_t *sector) +{ + return P_SectorHasFloorPortal(sector) || P_SectorHasCeilingPortal(sector); +} + +sectorportal_t *P_SectorGetFloorPortal(sector_t *sector) +{ + UINT32 num = sector->portal_floor; + if (num >= secportalcount) + return NULL; + + return &secportals[num]; +} + +sectorportal_t *P_SectorGetCeilingPortal(sector_t *sector) +{ + UINT32 num = sector->portal_ceiling; + if (num >= secportalcount) + return NULL; + + return &secportals[num]; +} + +boolean P_SectorHasFloorPortal(sector_t *sector) +{ + return P_IsSectorPortalValid(P_SectorGetFloorPortal(sector)); +} + +boolean P_SectorHasCeilingPortal(sector_t *sector) +{ + return P_IsSectorPortalValid(P_SectorGetCeilingPortal(sector)); +} + +boolean P_CompareSectorPortals(sectorportal_t *a, sectorportal_t *b) +{ + if (a == NULL && b == NULL) + return true; + else if (!a || !b) + return false; + else if (a->type != b->type) + return false; + + switch (a->type) + { + case SECPORTAL_LINE: + return a->line.start == b->line.start && a->line.dest == b->line.dest; + case SECPORTAL_FLOOR: + case SECPORTAL_CEILING: + return a->sector == b->sector; + case SECPORTAL_OBJECT: + return a->mobj == b->mobj; + default: + return true; + } +} + +static mobj_t *P_GetMobjByTag(INT32 tag) +{ + INT32 mtnum = -1; + + TAG_ITER_THINGS(tag, mtnum) + { + mobj_t *mo = mapthings[mtnum].mobj; + if (mo) + return mo; + } + + return NULL; +} + +static void P_DoPortalCopyFromLine(sector_t *dest_sector, int plane_type, int tag) +{ + INT32 secnum = -1; + TAG_ITER_SECTORS(tag, secnum) + { + sector_t *src_sector = §ors[secnum]; + if (plane_type == TMP_FLOOR || plane_type == TMP_BOTH) + dest_sector->portal_floor = src_sector->portal_floor; + if (plane_type == TMP_CEILING || plane_type == TMP_BOTH) + dest_sector->portal_ceiling = src_sector->portal_ceiling; + } +} + +static sectorportal_t *P_SectorGetPortalOrCreate(sector_t *sector, UINT32 *num, UINT32 *result) +{ + sectorportal_t *secportal = NULL; + + if (*num >= secportalcount) + { + *num = P_NewSectorPortal(); + secportal = &secportals[*num]; + secportal->origin.x = sector->soundorg.x; + secportal->origin.y = sector->soundorg.y; + *result = *num; + } + else + { + *result = *num; + secportal = &secportals[*num]; + } + + return secportal; +} + +static sectorportal_t *P_SectorGetFloorPortalOrCreate(sector_t *sector, UINT32 *result) +{ + return P_SectorGetPortalOrCreate(sector, §or->portal_floor, result); +} + +static sectorportal_t *P_SectorGetCeilingPortalOrCreate(sector_t *sector, UINT32 *result) +{ + return P_SectorGetPortalOrCreate(sector, §or->portal_ceiling, result); +} + +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 * thinkers. * @@ -6365,6 +6559,146 @@ 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 SPECIAL_SECTOR_SETPORTAL: // Sector portal + { + int target_sector_tag = lines[i].args[0]; + int portal_type = lines[i].args[1]; + int plane_type = lines[i].args[2]; + int misc = lines[i].args[3]; + + boolean floor, ceiling; + if (plane_type == TMP_BOTH) + floor = ceiling = true; + else + { + floor = plane_type == TMP_FLOOR; + 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, &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, &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) + { + sector_t *target_sector = §ors[s1]; + + // Line portal + if (portal_type == TMSECPORTAL_NORMAL) + { + INT32 linenum = -1; + TAG_ITER_LINES(misc, linenum) + { + 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 + && lines[linenum].args[3] == 1) + { + if (floor) + { + 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, &portal_num); + ceilportal->type = SECPORTAL_LINE; + ceilportal->line.start = &lines[i]; + ceilportal->line.dest = &lines[linenum]; + P_CopySectorPortalToLines(portal_num, target_sector_tag); + } + } + } + } + // Skybox portal + else if (portal_type == TMSECPORTAL_SKYBOX) + { + if (floor) + { + 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, &portal_num); + ceilportal->type = SECPORTAL_SKYBOX; + P_CopySectorPortalToLines(portal_num, target_sector_tag); + } + } + // Plane portal + else if (portal_type == TMSECPORTAL_SECTOR) + { + INT32 s2 = -1; + TAG_ITER_SECTORS(misc, s2) // Sector tag to make a portal to + { + sector_t *view_sector = §ors[s2]; + if (floor) + { + 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, &portal_num); + ceilportal->type = SECPORTAL_FLOOR; + ceilportal->sector = view_sector; + P_CopySectorPortalToLines(portal_num, target_sector_tag); + } + } + } + // Use mobj as viewpoint + else if (portal_type == TMSECPORTAL_OBJECT) + { + mobj_t *mobj = P_GetMobjByTag(misc); + if (!mobj) + break; + if (floor) + { + 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, &portal_num); + ceilportal->type = SECPORTAL_OBJECT; + P_SetTarget(&ceilportal->mobj, mobj); + P_CopySectorPortalToLines(portal_num, target_sector_tag); + } + } + } + break; + } + case 7: // Flat alignment - redone by toast { // Set calculated offsets such that line's v1 is the apparent origin @@ -7140,10 +7474,6 @@ void P_SpawnSpecials(boolean fromnetsave) } } - - - - // Allocate each list for (i = 0; i < numsectors; i++) if(secthinkers[i].thinkers) @@ -7172,6 +7502,33 @@ void P_SpawnSpecials(boolean fromnetsave) } } + // Copy portals + for (i = 0; i < numlines; i++) + { + if (lines[i].special != SPECIAL_SECTOR_SETPORTAL) + continue; + + int portal_type = lines[i].args[1]; + if (portal_type != TMSECPORTAL_COPIED) + continue; + + int target_sector_tag = lines[i].args[0]; + int plane_type = lines[i].args[2]; + int tag_to_copy = lines[i].args[3]; + + if (plane_type == 3) + plane_type = TMP_BOTH; + + if (target_sector_tag == 0) + P_DoPortalCopyFromLine(lines[i].frontsector, plane_type, tag_to_copy); + else + { + INT32 s1 = -1; + TAG_ITER_SECTORS(target_sector_tag, s1) + P_DoPortalCopyFromLine(§ors[s1], plane_type, tag_to_copy); + } + } + if (!fromnetsave) P_RunLevelLoadExecutors(); } diff --git a/src/p_spec.h b/src/p_spec.h index 50ab6410f..3bbaba58b 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -21,6 +21,10 @@ extern mobj_t *skyboxmo[2]; // current skybox mobjs: 0 = viewpoint, 1 = centerpo extern mobj_t *skyboxviewpnts[16]; // array of MT_SKYBOX viewpoint mobjs extern mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs +extern size_t secportalcount; +extern size_t secportalcapacity; +extern sectorportal_t *secportals; + // Amount (dx, dy) vector linedef is shifted right to get scroll amount #define SCROLL_SHIFT 5 @@ -472,6 +476,20 @@ typedef enum TMB_MODULATE = 4, } textmapblendmodes_t; +typedef enum +{ + TMSECPORTAL_NORMAL = 0, + TMSECPORTAL_COPIED = 1, + TMSECPORTAL_SKYBOX = 2, + TMSECPORTAL_PLANE = 3, + TMSECPORTAL_HORIZON = 4, + TMSECPORTAL_COPY_PORTAL_TO_LINE = 5, + TMSECPORTAL_INTERACTIVE = 6, // unimplemented + // The two portal types below are new to SRB2 + TMSECPORTAL_SECTOR = 7, + TMSECPORTAL_OBJECT = 8 +} textmapsecportaltype_t; + // GETSECSPECIAL (specialval, section) // // Pulls out the special # from a particular section. @@ -521,6 +539,19 @@ INT32 P_FindMinSurroundingLight(sector_t *sector, INT32 max); void P_SetupSignExit(player_t *player); 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); + +boolean P_SectorHasPortal(sector_t *sector); +boolean P_SectorHasFloorPortal(sector_t *sector); +boolean P_SectorHasCeilingPortal(sector_t *sector); +boolean P_CompareSectorPortals(sectorportal_t *a, sectorportal_t *b); + boolean P_IsMobjTouchingSectorPlane(mobj_t *mo, sector_t *sec); boolean P_IsMobjTouching3DFloor(mobj_t *mo, ffloor_t *ffloor, sector_t *sec); boolean P_IsMobjTouchingPolyobj(mobj_t *mo, polyobj_t *po, sector_t *polysec); diff --git a/src/r_bsp.c b/src/r_bsp.c index d99de5981..918dc40b0 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -36,6 +36,11 @@ drawseg_t *curdrawsegs = NULL; /**< This is used to handle multiple lists for ma drawseg_t *drawsegs = NULL; drawseg_t *ds_p = NULL; +boolean bothceilingssky = false; // turned on if both back and front ceilings are sky +boolean bothfloorssky = false; // likewise, but for floors + +boolean horizonline = false; + // indicates doors closed wrt automap bugfix: INT32 doorclosed; @@ -366,6 +371,11 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, boolean R_IsEmptyLine(seg_t *line, sector_t *front, sector_t *back) { + if (P_SectorHasPortal(front) && !P_SectorHasPortal(back)) + return false; + else if (!P_SectorHasPortal(front) && P_SectorHasPortal(back)) + return false; + return ( !line->polyseg && back->ceilingpic == front->ceilingpic @@ -407,7 +417,6 @@ static void R_AddLine(seg_t *line) INT32 x1, x2; angle_t angle1, angle2, span, tspan; static sector_t tempsec; - boolean bothceilingssky = false, bothfloorssky = false; portalline = false; @@ -465,6 +474,8 @@ static void R_AddLine(seg_t *line) return; backsector = line->backsector; + horizonline = line->linedef->special == SPECIAL_HORIZON_LINE; + bothceilingssky = bothfloorssky = false; // Portal line if (line->linedef->special == 40 && line->side == 0) @@ -489,6 +500,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->secportal, x1, x2); + goto clipsolid; + } + } // Single sided line? if (!backsector) @@ -498,9 +518,15 @@ static void R_AddLine(seg_t *line) doorclosed = 0; - if (backsector->ceilingpic == skyflatnum && frontsector->ceilingpic == skyflatnum) + // hack to allow height changes in outdoor areas + // This is what gets rid of the upper textures if there should be sky + if (backsector->ceilingpic == skyflatnum && frontsector->ceilingpic == skyflatnum + && !(P_SectorHasCeilingPortal(backsector) || P_SectorHasCeilingPortal(frontsector))) bothceilingssky = true; - if (backsector->floorpic == skyflatnum && frontsector->floorpic == skyflatnum) + + // likewise, but for floors and upper textures + if (backsector->floorpic == skyflatnum && frontsector->floorpic == skyflatnum + && !(P_SectorHasFloorPortal(backsector) || P_SectorHasFloorPortal(frontsector))) bothfloorssky = true; if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then @@ -585,7 +611,6 @@ static void R_AddLine(seg_t *line) // Reject empty lines used for triggers and special events. // Identical floor and ceiling on both sides, identical light levels on both sides, // and no middle texture. - if (R_IsEmptyLine(line, frontsector, backsector)) return; @@ -880,66 +905,32 @@ static void R_Subsector(size_t num) floorcenterz = P_GetSectorFloorZAt (frontsector, frontsector->soundorg.x, frontsector->soundorg.y); ceilingcenterz = P_GetSectorCeilingZAt(frontsector, frontsector->soundorg.x, frontsector->soundorg.y); - // Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps. - if (frontsector->ffloors) - { - boolean anyMoved = frontsector->moved; - - if (anyMoved == false) - { - for (rover = frontsector->ffloors; rover; rover = rover->next) - { - sector_t *controlSec = §ors[rover->secnum]; - - if (controlSec->moved == true) - { - anyMoved = true; - break; - } - } - } - - if (anyMoved == true) - { - frontsector->numlights = sub->sector->numlights = 0; - R_Prep3DFloors(frontsector); - sub->sector->lightlist = frontsector->lightlist; - sub->sector->numlights = frontsector->numlights; - sub->sector->moved = frontsector->moved = false; - } - - light = R_GetPlaneLight(frontsector, floorcenterz, false); - if (frontsector->floorlightsec == -1 && !frontsector->floorlightabsolute) - floorlightlevel = max(0, min(255, *frontsector->lightlist[light].lightlevel + frontsector->floorlightlevel)); - floorcolormap = *frontsector->lightlist[light].extra_colormap; - light = R_GetPlaneLight(frontsector, ceilingcenterz, false); - if (frontsector->ceilinglightsec == -1 && !frontsector->ceilinglightabsolute) - ceilinglightlevel = max(0, min(255, *frontsector->lightlist[light].lightlevel + frontsector->ceilinglightlevel)); - ceilingcolormap = *frontsector->lightlist[light].extra_colormap; - } + R_CheckSectorLightLists(sub->sector, frontsector, &floorlightlevel, &ceilinglightlevel, &floorcolormap, &ceilingcolormap); sub->sector->extra_colormap = frontsector->extra_colormap; if (P_GetSectorFloorZAt(frontsector, viewx, viewy) < viewz || frontsector->floorpic == skyflatnum + || P_SectorHasFloorPortal(frontsector) || (frontsector->heightsec != -1 && sectors[frontsector->heightsec].ceilingpic == skyflatnum)) { - floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel, + floorplane = R_FindPlane(frontsector, frontsector->floorheight, frontsector->floorpic, floorlightlevel, frontsector->floorxoffset, frontsector->flooryoffset, frontsector->floorxscale, frontsector->flooryscale, frontsector->floorangle, - floorcolormap, NULL, NULL, frontsector->f_slope); + floorcolormap, NULL, NULL, frontsector->f_slope, P_SectorGetFloorPortal(frontsector)); } else floorplane = NULL; if (P_GetSectorCeilingZAt(frontsector, viewx, viewy) > viewz || frontsector->ceilingpic == skyflatnum + || P_SectorHasCeilingPortal(frontsector) || (frontsector->heightsec != -1 && sectors[frontsector->heightsec].floorpic == skyflatnum)) { - ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic, ceilinglightlevel, + ceilingplane = R_FindPlane(frontsector, frontsector->ceilingheight, frontsector->ceilingpic, ceilinglightlevel, frontsector->ceilingxoffset, frontsector->ceilingyoffset, frontsector->ceilingxscale, frontsector->ceilingyscale, frontsector->ceilingangle, - ceilingcolormap, NULL, NULL, frontsector->c_slope); + ceilingcolormap, NULL, NULL, frontsector->c_slope, P_SectorGetCeilingPortal(frontsector)); } else ceilingplane = NULL; @@ -980,10 +971,10 @@ static void R_Subsector(size_t num) light = R_GetPlaneLight(frontsector, planecenterz, viewz < heightcheck); - ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic, + ffloor[numffloors].plane = R_FindPlane(rover->master->frontsector, *rover->bottomheight, *rover->bottompic, *frontsector->lightlist[light].lightlevel, *rover->bottomxoffs, *rover->bottomyoffs, *rover->bottomxscale, *rover->bottomyscale, *rover->bottomangle, - *frontsector->lightlist[light].extra_colormap, rover, NULL, *rover->b_slope); + *frontsector->lightlist[light].extra_colormap, rover, NULL, *rover->b_slope, NULL); ffloor[numffloors].slope = *rover->b_slope; @@ -1010,10 +1001,10 @@ static void R_Subsector(size_t num) { light = R_GetPlaneLight(frontsector, planecenterz, viewz < heightcheck); - ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic, + ffloor[numffloors].plane = R_FindPlane(rover->master->frontsector, *rover->topheight, *rover->toppic, *frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topxscale, *rover->topyscale, *rover->topangle, - *frontsector->lightlist[light].extra_colormap, rover, NULL, *rover->t_slope); + *frontsector->lightlist[light].extra_colormap, rover, NULL, *rover->t_slope, NULL); ffloor[numffloors].slope = *rover->t_slope; @@ -1053,18 +1044,17 @@ static void R_Subsector(size_t num) && (viewz < polysec->floorheight)) { light = R_GetPlaneLight(frontsector, polysec->floorheight, viewz < polysec->floorheight); - ffloor[numffloors].plane = R_FindPlane(polysec->floorheight, polysec->floorpic, + ffloor[numffloors].plane = R_FindPlane(polysec, polysec->floorheight, polysec->floorpic, (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->floorxoffset, polysec->flooryoffset, polysec->floorxscale, polysec->flooryscale, polysec->floorangle-po->angle, (light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po, - NULL); // will ffloors be slopable eventually? + NULL, NULL); ffloor[numffloors].height = polysec->floorheight; ffloor[numffloors].polyobj = po; ffloor[numffloors].slope = NULL; - //ffloor[numffloors].ffloor = rover; po->visplane = ffloor[numffloors].plane; numffloors++; } @@ -1079,18 +1069,17 @@ static void R_Subsector(size_t num) && (viewz > polysec->ceilingheight)) { light = R_GetPlaneLight(frontsector, polysec->floorheight, viewz < polysec->floorheight); - ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic, + ffloor[numffloors].plane = R_FindPlane(polysec, polysec->ceilingheight, polysec->ceilingpic, (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->ceilingxoffset, polysec->ceilingyoffset, polysec->ceilingxscale, polysec->ceilingyscale, polysec->ceilingangle-po->angle, (light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po, - NULL); // will ffloors be slopable eventually? + NULL, NULL); ffloor[numffloors].polyobj = po; ffloor[numffloors].height = polysec->ceilingheight; ffloor[numffloors].slope = NULL; - //ffloor[numffloors].ffloor = rover; po->visplane = ffloor[numffloors].plane; numffloors++; } @@ -1099,18 +1088,18 @@ static void R_Subsector(size_t num) } } - // killough 9/18/98: Fix underwater slowdown, by passing real sector - // instead of fake one. Improve sprite lighting by basing sprite - // lightlevels on floor & ceiling lightlevels in the surrounding area. - // - // 10/98 killough: - // - // NOTE: TeamTNT fixed this bug incorrectly, messing up sprite lighting!!! - // That is part of the 242 effect!!! If you simply pass sub->sector to - // the old code you will not get correct lighting for underwater sprites!!! - // Either you must pass the fake sector and handle validcount here, on the - // real sector, or you must account for the lighting in some other way, - // like passing it as an argument. + // killough 9/18/98: Fix underwater slowdown, by passing real sector + // instead of fake one. Improve sprite lighting by basing sprite + // lightlevels on floor & ceiling lightlevels in the surrounding area. + // + // 10/98 killough: + // + // NOTE: TeamTNT fixed this bug incorrectly, messing up sprite lighting!!! + // That is part of the 242 effect!!! If you simply pass sub->sector to + // the old code you will not get correct lighting for underwater sprites!!! + // Either you must pass the fake sector and handle validcount here, on the + // real sector, or you must account for the lighting in some other way, + // like passing it as an argument. R_AddSprites(sub->sector, (floorlightlevel+ceilinglightlevel)/2); firstseg = NULL; @@ -1121,7 +1110,6 @@ static void R_Subsector(size_t num) while (count--) { -// CONS_Debug(DBG_GAMELOGIC, "Adding normal line %d...(%d)\n", line->linedef-lines, leveltime); if (!line->glseg && !line->polyseg) // ignore segs that belong to polyobjects R_AddLine(line); line++; @@ -1129,6 +1117,51 @@ static void R_Subsector(size_t num) } } +void R_CheckSectorLightLists(sector_t *sector, sector_t *fakeflat, INT32 *floorlightlevel, INT32 *ceilinglightlevel, extracolormap_t **floorcolormap, extracolormap_t **ceilingcolormap) +{ + // Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps. + if (fakeflat->ffloors) + { + fixed_t floorcenterz = P_GetSectorFloorZAt (fakeflat, fakeflat->soundorg.x, fakeflat->soundorg.y); + fixed_t ceilingcenterz = P_GetSectorCeilingZAt(fakeflat, fakeflat->soundorg.x, fakeflat->soundorg.y); + + boolean anyMoved = fakeflat->moved; + + if (anyMoved == false) + { + for (ffloor_t *rover = fakeflat->ffloors; rover; rover = rover->next) + { + sector_t *controlSec = §ors[rover->secnum]; + + if (controlSec->moved == true) + { + anyMoved = true; + break; + } + } + } + + if (anyMoved == true) + { + fakeflat->numlights = sector->numlights = 0; + R_Prep3DFloors(fakeflat); + sector->lightlist = fakeflat->lightlist; + sector->numlights = fakeflat->numlights; + sector->moved = fakeflat->moved = false; + } + + INT32 light = R_GetPlaneLight(fakeflat, floorcenterz, false); + if (fakeflat->floorlightsec == -1 && !fakeflat->floorlightabsolute) + *floorlightlevel = max(0, min(255, *fakeflat->lightlist[light].lightlevel + fakeflat->floorlightlevel)); + *floorcolormap = *fakeflat->lightlist[light].extra_colormap; + + light = R_GetPlaneLight(fakeflat, ceilingcenterz, false); + if (fakeflat->ceilinglightsec == -1 && !fakeflat->ceilinglightabsolute) + *ceilinglightlevel = max(0, min(255, *fakeflat->lightlist[light].lightlevel + fakeflat->ceilinglightlevel)); + *ceilingcolormap = *fakeflat->lightlist[light].extra_colormap; + } +} + // // R_Prep3DFloors // @@ -1314,3 +1347,59 @@ void R_RenderBSPNode(INT32 bspnum) R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); } + +void R_RenderPortalHorizonLine(sector_t *sector) +{ + INT32 floorlightlevel, ceilinglightlevel; + static sector_t tempsec; // Deep water hack + extracolormap_t *floorcolormap; + extracolormap_t *ceilingcolormap; + + frontsector = sector; + backsector = NULL; + + // Deep water/fake ceiling effect. + frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel, &ceilinglightlevel, false); + + floorcolormap = ceilingcolormap = frontsector->extra_colormap; + + R_CheckSectorLightLists(sector, frontsector, &floorlightlevel, &ceilinglightlevel, &floorcolormap, &ceilingcolormap); + + sector->extra_colormap = frontsector->extra_colormap; + + if (P_GetSectorFloorZAt(frontsector, viewx, viewy) < viewz + || frontsector->floorpic == skyflatnum + || (frontsector->heightsec != -1 && sectors[frontsector->heightsec].ceilingpic == skyflatnum)) + { + floorplane = R_FindPlane(frontsector, frontsector->floorheight, frontsector->floorpic, floorlightlevel, + frontsector->floorxoffset, frontsector->flooryoffset, frontsector->floorxscale, frontsector->flooryscale, + frontsector->floorangle, floorcolormap, NULL, NULL, NULL, NULL); + } + else + floorplane = NULL; + + if (P_GetSectorCeilingZAt(frontsector, viewx, viewy) > viewz + || frontsector->ceilingpic == skyflatnum + || (frontsector->heightsec != -1 && sectors[frontsector->heightsec].floorpic == skyflatnum)) + { + ceilingplane = R_FindPlane(frontsector, frontsector->ceilingheight, frontsector->ceilingpic, + ceilinglightlevel, frontsector->ceilingxoffset, frontsector->ceilingxscale, frontsector->ceilingyscale, + frontsector->ceilingyoffset, frontsector->ceilingangle, + ceilingcolormap, NULL, NULL, NULL, NULL); + } + else + ceilingplane = NULL; + + numffloors = 0; + portalline = false; + doorclosed = 0; + bothceilingssky = bothfloorssky = false; + horizonline = true; + + firstseg = NULL; + curline = &segs[0]; + + R_ClipSolidWallSegment(portalclipstart, portalclipend); + + curline = NULL; +} diff --git a/src/r_bsp.h b/src/r_bsp.h index 55199405a..44ddd0b1b 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -25,13 +25,17 @@ extern sector_t *frontsector; extern sector_t *backsector; extern boolean portalline; // is curline a portal seg? -// drawsegs are allocated on the fly... see r_segs.c - extern INT32 checkcoord[12][4]; extern drawseg_t *curdrawsegs; extern drawseg_t *drawsegs; extern drawseg_t *ds_p; + +extern boolean bothceilingssky; +extern boolean bothfloorssky; + +extern boolean horizonline; + extern INT32 doorclosed; // BSP? @@ -39,6 +43,7 @@ void R_ClearClipSegs(void); void R_PortalClearClipSegs(INT32 start, INT32 end); void R_ClearDrawSegs(void); void R_RenderBSPNode(INT32 bspnum); +void R_RenderPortalHorizonLine(sector_t *sector); void R_SortPolyObjects(subsector_t *sub); @@ -52,4 +57,5 @@ boolean R_IsEmptyLine(seg_t *line, sector_t *front, sector_t *back); INT32 R_GetPlaneLight(sector_t *sector, fixed_t planeheight, boolean underside); void R_Prep3DFloors(sector_t *sector); +void R_CheckSectorLightLists(sector_t *sector, sector_t *fakeflat, INT32 *floorlightlevel, INT32 *ceilinglightlevel, extracolormap_t **floorcolormap, extracolormap_t **ceilingcolormap); #endif diff --git a/src/r_defs.h b/src/r_defs.h index bce045ab4..2931eb1c8 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -211,6 +211,34 @@ typedef enum BT_STRONG, } busttype_e; +typedef enum +{ + SECPORTAL_LINE, // Works similar to a line portal + SECPORTAL_SKYBOX, // Uses the skybox object as the reference view + SECPORTAL_PLANE, // Eternity Engine's plane portal type + SECPORTAL_HORIZON, // Eternity Engine's horizon portal type + SECPORTAL_OBJECT, // Uses an object as the reference view + SECPORTAL_FLOOR, // Uses a sector as the reference view; the view height is aligned with the sector's floor + SECPORTAL_CEILING, // Uses a sector as the reference view; the view height is aligned with the sector's ceiling + SECPORTAL_NONE = 0xFF +} secportaltype_e; + +typedef struct sectorportal_s +{ + secportaltype_e type; + union { + struct { + struct line_s *start; + struct line_s *dest; + } line; + struct sector_s *sector; + struct mobj_s *mobj; + }; + struct { + fixed_t x, y; + } origin; +} sectorportal_t; + typedef struct ffloor_s { fixed_t *topheight; @@ -505,6 +533,10 @@ typedef struct sector_s // colormap structure extracolormap_t *spawn_extra_colormap; + + // portals + UINT32 portal_floor; + UINT32 portal_ceiling; } sector_t; // @@ -518,7 +550,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 @@ -561,6 +595,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_main.c b/src/r_main.c index 125f80b78..94116f8fd 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1534,9 +1534,8 @@ void R_RenderPlayerView(player_t *player) ps_numsprites.value.i = numvisiblesprites; - // Add skybox portals caused by sky visplanes. - if (cv_skybox.value && skyboxmo[0]) - Portal_AddSkyboxPortals(); + // Add portals caused by visplanes. + Portal_AddPlanePortals(cv_skybox.value); // Portal rendering. Hijacks the BSP traversal. PS_START_TIMING(ps_sw_portaltime); @@ -1569,9 +1568,21 @@ void R_RenderPlayerView(player_t *player) Mask_Pre(&masks[nummasks - 1]); curdrawsegs = ds_p; - // Render the BSP from the new viewpoint, and clip - // any sprites with the new clipsegs and window. - R_RenderBSPNode((INT32)numnodes - 1); + if (portal->is_horizon) + { + // If the portal is a plane or a horizon portal, then we just render a horizon line + R_RenderPortalHorizonLine(portal->horizon_sector); + } + else + { + // Render the BSP from the new viewpoint, and clip + // any sprites with the new clipsegs and window. + R_RenderBSPNode((INT32)numnodes - 1); + } + + // Don't add skybox portals while already rendering a skybox view, because that'll cause an infinite loop + Portal_AddPlanePortals(cv_skybox.value && !portal->is_skybox); + Mask_Post(&masks[nummasks - 1]); R_ClipSprites(ds_p - (masks[nummasks - 1].drawsegs[1] - masks[nummasks - 1].drawsegs[0]), portal); diff --git a/src/r_plane.c b/src/r_plane.c index 08e147c89..612c650fc 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -368,10 +368,10 @@ static visplane_t *new_visplane(unsigned hash) // Same height, same flattexture, same lightlevel. // If not, allocates another of them. // -visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, +visplane_t *R_FindPlane(sector_t *sector, fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, fixed_t xscale, fixed_t yscale, angle_t plangle, extracolormap_t *planecolormap, - ffloor_t *pfloor, polyobj_t *polyobj, pslope_t *slope) + ffloor_t *pfloor, polyobj_t *polyobj, pslope_t *slope, sectorportal_t *portalsector) { visplane_t *check; unsigned hash; @@ -430,7 +430,8 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, && check->viewangle == viewangle && check->plangle == plangle && check->slope == slope - && check->polyobj == polyobj) + && check->polyobj == polyobj + && P_CompareSectorPortals(check->portalsector, portalsector)) { return check; } @@ -459,6 +460,8 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, check->viewz = viewz; check->viewangle = viewangle; check->plangle = plangle; + check->sector = sector; + check->portalsector = portalsector; check->polyobj = polyobj; check->slope = slope; @@ -537,8 +540,10 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop) new_pl->viewz = pl->viewz; new_pl->viewangle = pl->viewangle; new_pl->plangle = pl->plangle; + new_pl->sector = pl->sector; new_pl->polyobj = pl->polyobj; new_pl->slope = pl->slope; + new_pl->portalsector = pl->portalsector; pl = new_pl; pl->minx = start; pl->maxx = stop; diff --git a/src/r_plane.h b/src/r_plane.h index 5ce49e3cc..69620f25e 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -51,9 +51,11 @@ typedef struct visplane_s fixed_t xoffs, yoffs; // Scrolling flats. fixed_t xscale, yscale; + sector_t *sector; struct ffloor_s *ffloor; polyobj_t *polyobj; pslope_t *slope; + sectorportal_t *portalsector; } visplane_t; extern visplane_t *visplanes[MAXVISPLANES]; @@ -71,8 +73,9 @@ void R_ClearPlanes(void); void R_ClearFFloorClips (void); void R_DrawPlanes(void); -visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, fixed_t xscale, fixed_t yscale, - angle_t plangle, extracolormap_t *planecolormap, ffloor_t *ffloor, polyobj_t *polyobj, pslope_t *slope); +visplane_t *R_FindPlane(sector_t *sector, fixed_t height, INT32 picnum, INT32 lightlevel, + fixed_t xoff, fixed_t yoff, fixed_t xscale, fixed_t yscale, angle_t plangle, + extracolormap_t *planecolormap, ffloor_t *ffloor, polyobj_t *polyobj, pslope_t *slope, sectorportal_t *portalsector); visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop); void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop); void R_PlaneBounds(visplane_t *plane); diff --git a/src/r_portal.c b/src/r_portal.c index e594f960a..4d042cae3 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -16,6 +16,8 @@ #include "r_main.h" #include "doomstat.h" #include "p_spec.h" // Skybox viewpoints +#include "p_slopes.h" // P_GetSectorFloorZAt and P_GetSectorCeilingZAt +#include "p_local.h" #include "z_zone.h" #include "r_things.h" #include "r_sky.h" @@ -140,30 +142,17 @@ void Portal_Remove (portal_t* portal) Z_Free(portal); } -/** 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) +static void Portal_GetViewpointForLine(portal_t *portal, line_t *start, line_t *dest) { - portal_t* portal = Portal_Add(x1, x2); - // Offset the portal view by the linedef centers - line_t* start = &lines[line1]; - line_t* dest = &lines[line2]; - 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; - vertex_t dest_c, start_c; + struct { + fixed_t x, y; + } dest_c, start_c; // looking glass center start_c.x = (start->v1->x + start->v2->x) / 2; @@ -181,8 +170,31 @@ void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, con portal->viewy = dest_c.y + FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); portal->viewz = viewz + dest->frontsector->floorheight - start->frontsector->floorheight; portal->viewangle = viewangle + dangle; +} + +/** 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); portal->clipline = line2; + portal->is_skybox = false; + portal->is_horizon = false; + portal->horizon_sector = NULL; Portal_ClipRange(portal); @@ -252,30 +264,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]) @@ -302,34 +298,192 @@ 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; } -/** Creates portals for the currently existing sky visplanes. +/** Creates a skybox portal out of a visplane. + * + * Applies the necessary offsets and rotation to give + * a depth illusion to the skybox. + */ +static boolean Portal_AddSkybox (const visplane_t* plane) +{ + INT16 start, end; + portal_t* portal; + + if (TrimVisplaneBounds(plane, &start, &end)) + return false; + + portal = Portal_Add(start, end); + + Portal_ClipVisplane(plane, portal); + + portal->clipline = -1; + portal->is_skybox = true; + portal->is_horizon = false; + portal->horizon_sector = NULL; + + Portal_GetViewpointForSkybox(portal); + + return true; +} + +static void Portal_GetViewpointForSecPortal(portal_t *portal, sectorportal_t *secportal) +{ + fixed_t x, y, z; + angle_t angle; + + switch (secportal->type) + { + 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; + z = P_GetSectorFloorZAt(secportal->sector, x, y); + angle = 0; + break; + case SECPORTAL_CEILING: + x = secportal->sector->soundorg.x; + y = secportal->sector->soundorg.y; + z = P_GetSectorCeilingZAt(secportal->sector, x, y); + angle = 0; + break; + case SECPORTAL_PLANE: + case SECPORTAL_HORIZON: + portal->is_horizon = true; + portal->horizon_sector = secportal->sector; + x = secportal->sector->soundorg.x; + y = secportal->sector->soundorg.y; + if (secportal->type == SECPORTAL_PLANE) + z = -viewz; + else + z = 0; + angle = 0; + break; + default: + return; + } + + fixed_t refx = secportal->origin.x - viewx; + fixed_t refy = secportal->origin.y - viewy; + + // 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; +} + +/** Creates a sector portal out of a visplane. + */ +static boolean Portal_AddSectorPortal (const visplane_t* plane) +{ + INT16 start, end; + sectorportal_t *secportal = plane->portalsector; + + // Shortcut + if (secportal->type == SECPORTAL_SKYBOX) + { + if (cv_skybox.value && skyboxmo[0]) + return Portal_AddSkybox(plane); + return false; + } + + if (TrimVisplaneBounds(plane, &start, &end)) + return false; + + portal_t* portal = Portal_Add(start, end); + + Portal_ClipVisplane(plane, portal); + + portal->clipline = -1; + portal->is_horizon = false; + portal->is_skybox = false; + portal->horizon_sector = NULL; + + Portal_GetViewpointForSecPortal(portal, secportal); + + return true; +} + +/** Creates a transferred sector portal. + */ +void Portal_AddTransferred (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_skybox = false; + portal->is_horizon = false; + portal->horizon_sector = NULL; + + if (secportal->type == SECPORTAL_SKYBOX) + Portal_GetViewpointForSkybox(portal); + else + Portal_GetViewpointForSecPortal(portal, secportal); + + 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 portal visplanes. * The visplanes are also removed and cleared from the list. */ -void Portal_AddSkyboxPortals (void) +void Portal_AddPlanePortals (boolean add_skyboxes) { visplane_t *pl; - INT32 i; - UINT16 count = 0; - for (i = 0; i < MAXVISPLANES; i++, pl++) + for (INT32 i = 0; i < MAXVISPLANES; i++, pl++) { for (pl = visplanes[i]; pl; pl = pl->next) { - if (pl->picnum == skyflatnum) - { - Portal_AddSkybox(pl); + if (pl->minx >= pl->maxx) + continue; + boolean added_portal = false; + + // Render sector portal if recursiveness limit hasn't been reached + if (pl->portalsector && portalrender < cv_maxportals.value) + added_portal = Portal_AddSectorPortal(pl); + + // Render skybox portal + if (!added_portal && pl->picnum == skyflatnum && add_skyboxes && skyboxmo[0]) + added_portal = Portal_AddSkybox(pl); + + // don't render this visplane anymore + if (added_portal) + { pl->minx = 0; pl->maxx = -1; - - count++; } } } - - CONS_Debug(DBG_RENDER, "Skybox portals: %d\n", count); } diff --git a/src/r_portal.h b/src/r_portal.h index f90f05fbc..2485e45a7 100644 --- a/src/r_portal.h +++ b/src/r_portal.h @@ -30,6 +30,12 @@ typedef struct portal_s fixed_t viewz; angle_t viewangle; + // For horizon portals + boolean is_horizon; + sector_t *horizon_sector; + + boolean is_skybox; + UINT8 pass; /**< Keeps track of the portal's recursion depth. */ INT32 clipline; /**< Optional clipline for line-based portals. */ @@ -49,13 +55,13 @@ extern line_t *portalclipline; extern sector_t *portalcullsector; extern INT32 portalclipstart, portalclipend; -void Portal_InitList (void); -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_InitList (void); +void Portal_Remove (portal_t* portal); +void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, const INT32 x2); +void Portal_AddTransferred (UINT32 secportalnum, const INT32 x1, const INT32 x2); void Portal_ClipRange (portal_t* portal); void Portal_ClipApply (const portal_t* portal); -void Portal_AddSkyboxPortals (void); +void Portal_AddPlanePortals (boolean add_skyboxes); #endif diff --git a/src/r_segs.c b/src/r_segs.c index ecc49fbc2..62fea352f 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -1867,9 +1867,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) else { // two sided line - boolean bothceilingssky = false; // turned on if both back and front ceilings are sky - boolean bothfloorssky = false; // likewise, but for floors - SLOPEPARAMS(backsector->c_slope, worldhigh, worldhighslope, backsector->ceilingheight) SLOPEPARAMS(backsector->f_slope, worldlow, worldlowslope, backsector->floorheight) worldhigh -= viewz; @@ -1877,21 +1874,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) worldlow -= viewz; worldlowslope -= viewz; - // hack to allow height changes in outdoor areas - // This is what gets rid of the upper textures if there should be sky - if (frontsector->ceilingpic == skyflatnum - && backsector->ceilingpic == skyflatnum) - { - bothceilingssky = true; - } - - // likewise, but for floors and upper textures - if (frontsector->floorpic == skyflatnum - && backsector->floorpic == skyflatnum) - { - bothfloorssky = true; - } - ds_p->sprtopclip = ds_p->sprbottomclip = NULL; ds_p->silhouette = 0; @@ -1991,6 +1973,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) || backsector->floorlightsec != frontsector->floorlightsec //SoM: 4/3/2000: Check for colormaps || frontsector->extra_colormap != backsector->extra_colormap + || !P_CompareSectorPortals(P_SectorGetFloorPortal(frontsector), P_SectorGetFloorPortal(backsector)) || (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags))) { markfloor = true; @@ -2026,9 +2009,10 @@ void R_StoreWallRange(INT32 start, INT32 stop) || backsector->ceilinglightsec != frontsector->ceilinglightsec //SoM: 4/3/2000: Check for colormaps || frontsector->extra_colormap != backsector->extra_colormap + || !P_CompareSectorPortals(P_SectorGetCeilingPortal(frontsector), P_SectorGetCeilingPortal(backsector)) || (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags))) { - markceiling = true; + markceiling = true; } else { @@ -2478,7 +2462,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) worldtopslope >>= 4; worldbottomslope >>= 4; - if (linedef->special == HORIZONSPECIAL) { // HORIZON LINES + if (horizonline) { // HORIZON LINES topstep = bottomstep = 0; topfrac = bottomfrac = (centeryfrac>>4); topfrac++; // Prevent 1px HOM @@ -2579,7 +2563,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) { ffloor[i].f_pos >>= 4; ffloor[i].f_pos_slope >>= 4; - if (linedef->special == HORIZONSPECIAL) // Horizon lines extend FOFs in contact with them too. + if (horizonline) // Horizon lines extend FOFs in contact with them too. { ffloor[i].f_step = 0; ffloor[i].f_frac = (centeryfrac>>4);