diff --git a/doomsday/engine/portable/include/mapdata.hs b/doomsday/engine/portable/include/mapdata.hs index 13ce3b488d..e6471a5c70 100644 --- a/doomsday/engine/portable/include/mapdata.hs +++ b/doomsday/engine/portable/include/mapdata.hs @@ -9,16 +9,9 @@ internal #define LO_prev link[0] #define LO_next link[1] -typedef struct shadowpolyoffset_s { - float offset[2]; -} shadowpolyoffset_t; - -#define MAX_BEXOFFSETS 8 - -typedef struct shadowvert_s { - float inner[2]; - float extended[2]; - shadowpolyoffset_t backExtended[MAX_BEXOFFSETS]; +typedef struct shadowvert_s { + float inner[2]; + float extended[2]; } shadowvert_t; typedef struct lineowner_s { @@ -80,7 +73,6 @@ internal // Seg flags #define SEGF_POLYOBJ 0x1 // Seg is part of a poly object. -#define SEGF_SHADOW 0x2 // Seg casts edge shadows. // Seg frame flags #define SEGINF_FACINGFRONT 0x0001 @@ -107,7 +99,6 @@ struct seg - biastracker_s[3] tracker // 0=middle, 1=top, 2=bottom - vertexillum_s[3][4] illum - short frameFlags - - ushort shadowVisFrame end internal @@ -458,6 +449,7 @@ struct linedef FLOAT float[4] bBox - boolean[DDMAXPLAYERS] mapped // Whether the line has been mapped by each player yet. - mlinedef_t buildData + - ushort[2] shadowVisFrame // Framecount of last time shadows were drawn for this line, for each side [right, left]. end internal diff --git a/doomsday/engine/portable/include/p_maptypes.h b/doomsday/engine/portable/include/p_maptypes.h index 04117e7192..e8f064c9d3 100644 --- a/doomsday/engine/portable/include/p_maptypes.h +++ b/doomsday/engine/portable/include/p_maptypes.h @@ -8,16 +8,9 @@ #define LO_prev link[0] #define LO_next link[1] -typedef struct shadowpolyoffset_s { - float offset[2]; -} shadowpolyoffset_t; - -#define MAX_BEXOFFSETS 8 - typedef struct shadowvert_s { float inner[2]; float extended[2]; - shadowpolyoffset_t backExtended[MAX_BEXOFFSETS]; } shadowvert_t; typedef struct lineowner_s { @@ -78,7 +71,6 @@ typedef struct vertex_s { // Seg flags #define SEGF_POLYOBJ 0x1 // Seg is part of a poly object. -#define SEGF_SHADOW 0x2 // Seg casts edge shadows. // Seg frame flags #define SEGINF_FACINGFRONT 0x0001 @@ -101,7 +93,6 @@ typedef struct seg_s { struct biastracker_s tracker[3]; // 0=middle, 1=top, 2=bottom struct vertexillum_s illum[3][4]; short frameFlags; - unsigned short shadowVisFrame; } seg_t; #define SUBF_MIDPOINT 0x80 // Midpoint is tri-fan centre. @@ -428,6 +419,7 @@ typedef struct linedef_s { float bBox[4]; boolean mapped[DDMAXPLAYERS]; // Whether the line has been mapped by each player yet. mlinedef_t buildData; + unsigned short shadowVisFrame[2]; // Framecount of last time shadows were drawn for this line, for each side [right, left]. } linedef_t; typedef struct mpolyobj_s { diff --git a/doomsday/engine/portable/include/r_data.h b/doomsday/engine/portable/include/r_data.h index 9dbc9fd791..1af7043cca 100644 --- a/doomsday/engine/portable/include/r_data.h +++ b/doomsday/engine/portable/include/r_data.h @@ -175,7 +175,8 @@ typedef struct linkmobj_s { typedef struct shadowlink_s { struct shadowlink_s *next; - seg_t *seg; + linedef_t *lineDef; + byte side; } shadowlink_t; typedef struct subplaneinfo_s { diff --git a/doomsday/engine/portable/include/r_shadow.h b/doomsday/engine/portable/include/r_shadow.h index 34fbdae0f1..4b7e86b47a 100644 --- a/doomsday/engine/portable/include/r_shadow.h +++ b/doomsday/engine/portable/include/r_shadow.h @@ -22,7 +22,7 @@ * Boston, MA 02110-1301 USA */ -/* +/** * r_shadow.h: Runtime Map Shadowing (FakeRadio) */ @@ -30,7 +30,7 @@ #define __DOOMSDAY_REFRESH_SHADOW_H__ void R_InitSectorShadows(void); -sector_t *R_GetShadowSector(seg_t *seg, uint plane, - boolean getLinked); + +boolean R_IsShadowingLinedef(linedef_t *line); #endif diff --git a/doomsday/engine/portable/src/r_shadow.c b/doomsday/engine/portable/src/r_shadow.c index e1475982f2..536eef4347 100644 --- a/doomsday/engine/portable/src/r_shadow.c +++ b/doomsday/engine/portable/src/r_shadow.c @@ -38,18 +38,6 @@ // TYPES ------------------------------------------------------------------- -typedef struct boundary_s { - vec2_t left, right; - vec2_t a, b; -} boundary_t; - -typedef struct segoverlapdata_s { - struct segoverlapdata_s *next; - boundary_t bound; - byte overlap; - seg_t *seg; -} segoverlapdata_t; - // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -64,72 +52,8 @@ typedef struct segoverlapdata_s { static zblockset_t *shadowLinksBlockSet; -static segoverlapdata_t *unusedList = NULL; - // CODE -------------------------------------------------------------------- -static __inline segoverlapdata_t* allocSegOverlapData(void) -{ - return M_Malloc(sizeof(segoverlapdata_t)); -} - -static __inline void freeSegOverlapData(segoverlapdata_t* data) -{ - M_Free(data); -} - -static segoverlapdata_t *createOverlapDataForSeg(seg_t *seg) -{ - segoverlapdata_t *data; - - // Have we got a reusable overlapdata? - if(unusedList) - { - data = unusedList; - unusedList = unusedList->next; - } - else - { - data = allocSegOverlapData(); - } - - data->seg = seg; - data->overlap = 0; - data->next = NULL; - - return data; -} - -static void destroyOverlapData(segoverlapdata_t *data) -{ - if(data) - freeSegOverlapData(data); -} - -static void linkOverlapDataToList(segoverlapdata_t **list, - segoverlapdata_t *data) -{ - data->next = (*list); - (*list) = data; -} - -static void destroyOverlapList(segoverlapdata_t **list, boolean reuse) -{ - segoverlapdata_t *data, *next; - - data = (*list); - while(data) - { - next = data->next; - if(reuse) - linkOverlapDataToList(&unusedList, data); - else - destroyOverlapData(data); - data = next; - } - (*list) = NULL; -} - /** * Line1 and line2 are the (dx,dy)s for two lines, connected at the * origin (0,0). Dist1 and dist2 are the distances from these lines. @@ -137,8 +61,9 @@ static void destroyOverlapList(segoverlapdata_t **list, boolean reuse) * from line2, while also being the nearest point to the origin (in * case the lines are parallel). */ -void R_CornerNormalPoint(const pvec2_t line1, float dist1, const pvec2_t line2, - float dist2, pvec2_t point, pvec2_t lp, pvec2_t rp) +void R_CornerNormalPoint(const pvec2_t line1, float dist1, + const pvec2_t line2, float dist2, pvec2_t point, + pvec2_t lp) { float len1, len2, plen; vec2_t origin = { 0, 0 }, norm1, norm2; @@ -160,8 +85,6 @@ void R_CornerNormalPoint(const pvec2_t line1, float dist1, const pvec2_t line2, V2_Copy(point, norm1); if(lp) V2_Copy(lp, norm1); - if(rp) - V2_Copy(rp, norm1); return; } @@ -170,84 +93,20 @@ void R_CornerNormalPoint(const pvec2_t line1, float dist1, const pvec2_t line2, if(point) V2_Intersection(norm1, line1, norm2, line2, point); - // Do we need to calculate the extended points, too? Check that - // the extensions don't bleed too badly outside the legal shadow + // Do we need to calculate the extended point, too? Check that + // the extension does not bleed too badly outside the legal shadow // area. if(lp) { - V2_Intersection(origin, line1, norm2, line2, lp); + V2_Intersection(origin, line2, norm2, line1, lp); plen = V2_Length(lp); - if(plen > 0 && plen > len1) - { - V2_Scale(lp, len1 / plen); - } - } - if(rp) - { - V2_Intersection(norm1, line1, origin, line2, rp); - plen = V2_Length(rp); if(plen > 0 && plen > len2) { - V2_Scale(rp, len2 / plen); + V2_Scale(lp, len2 / plen); } } } -void R_ShadowDelta(pvec2_t delta, linedef_t *line, sector_t *frontSector) -{ - if(line->L_frontsector == frontSector) - { - delta[VX] = line->dX; - delta[VY] = line->dY; - } - else - { - delta[VX] = -line->dX; - delta[VY] = -line->dY; - } -} - -/** - * Returns a pointer to the sector the shadow polygon belongs in. - */ -sector_t *R_GetShadowSector(seg_t *seg, uint pln, boolean getLinked) -{ - if(getLinked) - return R_GetLinkedSector(seg->subsector, pln); - return (seg->SG_frontsector); -} - -boolean R_ShadowCornerDeltas(pvec2_t left, pvec2_t right, seg_t *seg, - boolean leftCorner) -{ - sector_t *sector = R_GetShadowSector(seg, 0, false); - linedef_t *neighbor; - int side = seg->side; - - // The line itself. - R_ShadowDelta(leftCorner ? right : left, seg->lineDef, sector); - - // The neighbor. - neighbor = R_FindLineNeighbor(seg->subsector->sector, - seg->lineDef, - seg->lineDef->vo[side^!leftCorner], - !leftCorner, NULL); - if(!neighbor) - { - // Should never happen... - Con_Message("R_ShadowCornerDeltas: No %s neighbor for line %u!\n", - leftCorner? "left":"right", - (uint) GET_LINE_IDX(seg->lineDef)); - return false; - } - - R_ShadowDelta(leftCorner ? left : right, neighbor, sector); - - // The left side is always flipped. - V2_Scale(left, -1); - return true; -} - /** * @return The width (world units) of the shadow edge. * It is scaled depending on the length of the edge. @@ -272,151 +131,68 @@ float R_ShadowEdgeWidth(const pvec2_t edge) } /** - * Sets the shadow edge offsets. If the associated line does not have - * neighbors, it can't have a shadow. + * Updates all the shadow offsets for the given vertex. + * + * \pre Lineowner rings MUST be set up. + * + * @param vtx Ptr to the vertex being updated. */ -void R_ShadowEdges(seg_t *seg) +void R_UpdateVertexShadowOffsets(vertex_t *vtx) { - vec2_t left, right; - int edge, side = seg->side; - uint i, count; - linedef_t *line = seg->lineDef; - lineowner_t *base, *p, *boundryOwner = NULL; - boolean done; - lineowner_t *vo; - - for(edge = 0; edge < 2; ++edge) // left and right + vec2_t left, right; + + if(vtx->numLineOwners > 0) { - vo = seg->lineDef->L_vo(edge^side); + lineowner_t *own, *base; - // The inside corner: - if(R_ShadowCornerDeltas(left, right, seg, edge == 0)) + own = base = vtx->lineOwners; + do { - R_CornerNormalPoint(left, R_ShadowEdgeWidth(left), right, - R_ShadowEdgeWidth(right), vo->shadowOffsets.inner, - edge == 0 ? vo->shadowOffsets.extended : NULL, - edge == 1 ? vo->shadowOffsets.extended : NULL); - } - else - { // An error in the map. Set the inside corner to the extoffset. - V2_Copy(vo->shadowOffsets.inner, - vo->shadowOffsets.extended); - } + linedef_t *lineB = own->lineDef; + linedef_t *lineA = own->LO_next->lineDef; - // The back extended offset(s): - // Determine how many we'll need. - base = R_GetVtxLineOwner(line->L_v(edge^side), line); - count = 0; - done = false; - p = base->link[!edge]; - while(p != base && !done) - { - if(!(p->lineDef->L_frontside && p->lineDef->L_backside && - p->lineDef->L_frontsector == p->lineDef->L_backsector)) + if(lineB->L_v1 == vtx) { - if(count == 0) - { // Found the boundry line. - boundryOwner = p; - } - - if(!p->lineDef->L_frontside || !p->lineDef->L_backside) - done = true; // Found the last one. - else - count++; + right[VX] = lineB->dX; + right[VY] = lineB->dY; + } + else + { + right[VX] = -lineB->dX; + right[VY] = -lineB->dY; } - if(!done) - p = p->link[!edge]; - } - - // It is not always possible to calculate the back-extended - // offset. - if(count == 0) - { - // No back-extended, just use the plain extended offset. - V2_Copy(vo->shadowOffsets.backExtended[0].offset, - vo->shadowOffsets.extended); - } - else - { - // We need at least one back extended offset. - sector_t *sector = R_GetShadowSector(seg, 0, false); - linedef_t *neighbor; - boolean leftCorner = (edge == 0); - pvec2_t delta; - sector_t *orientSec; - - // The line itself. - R_ShadowDelta(leftCorner ? right : left, line, sector); + if(lineA->L_v1 == vtx) + { + left[VX] = -lineA->dX; + left[VY] = -lineA->dY; + } + else + { + left[VX] = lineA->dX; + left[VY] = lineA->dY; + } // The left side is always flipped. - if(!leftCorner) - V2_Scale(left, -1); + V2_Scale(left, -1); - if(boundryOwner->lineDef->L_frontsector == sector) - orientSec = (boundryOwner->lineDef->L_backside? boundryOwner->lineDef->L_backsector : NULL); - else - orientSec = (boundryOwner->lineDef->L_frontside? boundryOwner->lineDef->L_frontsector : NULL); + R_CornerNormalPoint(left, R_ShadowEdgeWidth(left), right, + R_ShadowEdgeWidth(right), + own->shadowOffsets.inner, + own->shadowOffsets.extended); - p = boundryOwner; - for(i = 0; i < count && i < MAX_BEXOFFSETS; ++i) - { - byte otherside; - // Get the next back neighbor. - neighbor = NULL; - p = p->link[!edge]; - do - { - if(!(p->lineDef->L_frontside && p->lineDef->L_backside && - p->lineDef->L_frontsector == p->lineDef->L_backsector)) - neighbor = p->lineDef; - else - p = p->link[!edge]; - } while(!neighbor); - - // The back neighbor delta. - delta = (leftCorner ? left : right); - otherside = neighbor->L_v1 == line->L_v(edge^!side); - if(neighbor->L_side(otherside) && - orientSec == neighbor->L_sector(otherside)) - { - delta[VX] = neighbor->dX; - delta[VY] = neighbor->dY; - } - else - { - delta[VX] = -neighbor->dX; - delta[VY] = -neighbor->dY; - } - - // The left side is always flipped. - if(leftCorner) - V2_Scale(left, -1); - - R_CornerNormalPoint(left, R_ShadowEdgeWidth(left), - right, R_ShadowEdgeWidth(right), - vo->shadowOffsets.backExtended[i].offset, - NULL, NULL); - - // Update orientSec ready for the next iteration? - if(i < count - 1) - { - if(neighbor->L_frontsector == orientSec) - orientSec = (neighbor->L_backside? neighbor->L_backsector : NULL); - else - orientSec = (neighbor->L_frontside? neighbor->L_frontsector : NULL); - } - } - } + own = own->LO_next; + } while(own != base); } } /** * Link a seg to an arbitary subsector for the purposes of shadowing. */ -void R_LinkShadow(seg_t *seg, subsector_t *subsector) +static void linkShadowLineDefToSSec(linedef_t *line, byte side, + subsector_t *subsector) { - shadowlink_t *link; + shadowlink_t *link; #ifdef _DEBUG // Check the links for dupes! @@ -424,7 +200,7 @@ void R_LinkShadow(seg_t *seg, subsector_t *subsector) shadowlink_t *i; for(i = subsector->shadows; i; i = i->next) - if(i->seg == seg) + if(i->lineDef == line && i->side == side) Con_Error("R_LinkShadow: Already here!!\n"); } #endif @@ -435,247 +211,43 @@ for(i = subsector->shadows; i; i = i->next) // The links are stored into a linked list. link->next = subsector->shadows; subsector->shadows = link; - link->seg = seg; + link->lineDef = line; + link->side = side; } +typedef struct shadowlinkerparms_s { + linedef_t *lineDef; + byte side; +} shadowlinkerparms_t; + /** * If the shadow polygon (parm) contacts the subsector, link the poly * to the subsector's shadow list. */ boolean RIT_ShadowSubsectorLinker(subsector_t *subsector, void *parm) { - seg_t *seg = (seg_t*) parm; + shadowlinkerparms_t *data = (shadowlinkerparms_t*) parm; - R_LinkShadow(seg, subsector); + linkShadowLineDefToSSec(data->lineDef, data->side, subsector); return true; } /** - * Moves inoffset appropriately. - * - * @return @c true, if overlap resolving should continue to another - * round of iteration. - */ -boolean R_ResolveStep(const pvec2_t outer, const pvec2_t inner, - pvec2_t offset) -{ -#define RESOLVE_STEP 2 - - float span, distance; - boolean iterCont = true; - - span = distance = V2_Distance(outer, inner); - if(span == 0) - return false; - - distance /= 2; - iterCont = false; - - V2_Scale(offset, distance / span); - return iterCont; - -#undef RESOLVE_STEP -} - -/** - * The array of polys given as the parameter contains the shadow polygons - * of one sector. If the polygons overlap, we will iteratively resolve the - * overlaps by moving the inner corner points closer to the outer corner - * points. Other corner points remain unmodified. + * Does the given linedef qualify as an edge shadow caster? */ -void R_ResolveOverlaps(segoverlapdata_t **list, sector_t *sector) +boolean R_IsShadowingLinedef(linedef_t *line) { -#define OVERLAP_LEFT 0x01 -#define OVERLAP_RIGHT 0x02 -#define OVERLAP_ALL (OVERLAP_LEFT | OVERLAP_RIGHT) -#define EPSILON .01f - - boolean done; - int tries; - uint i; - float s, t; - vec2_t a, b; - linedef_t *line; - segoverlapdata_t *data; - - if(!list) - return; - - // We don't want to stay here forever. - done = false; - for(tries = 0; tries < 100 && !done; ++tries) + if(line) { - // We will set this to false if we notice that overlaps still - // exist. - done = true; - - // Calculate the boundaries. - for(data = (*list); data; data = data->next) + if(!LINE_SELFREF(line) && + !(line->vo[0]->LO_next->lineDef == line || + line->vo[1]->LO_next->lineDef == line)) { - seg_t *seg = data->seg; - boundary_t *bound = &data->bound; - byte side = seg->side; - vertex_t *vtx0, *vtx1; - - vtx0 = seg->lineDef->L_v(side); - vtx1 = seg->lineDef->L_v(side^1); - - V2_Set(bound->left, vtx0->V_pos[VX], vtx0->V_pos[VY]); - V2_Sum(bound->a, seg->lineDef->L_vo(side)->shadowOffsets.inner, - bound->left); - - V2_Set(bound->right, vtx1->V_pos[VX], vtx1->V_pos[VY]); - V2_Sum(bound->b, seg->lineDef->L_vo(side^1)->shadowOffsets.inner, - bound->right); - - data->overlap = 0; - } - - // Find the overlaps. - for(data = (*list); data; data = data->next) - { - seg_t *seg = data->seg; - boundary_t *bound = &data->bound; - - for(i = 0; i < sector->lineDefCount; ++i) - { - line = sector->lineDefs[i]; - if(seg->lineDef == line) - continue; - - if(LINE_SELFREF(line)) - continue; - - if((data->overlap & OVERLAP_ALL) == OVERLAP_ALL) - break; - - V2_Set(a, line->L_v1pos[VX], line->L_v1pos[VY]); - V2_Set(b, line->L_v2pos[VX], line->L_v2pos[VY]); - - // Try the left edge of the shadow. - V2_Intercept2(bound->left, bound->a, a, b, NULL, &s, &t); - if(s > 0 && s < 1 && t >= EPSILON && t <= 1 - EPSILON) - data->overlap |= OVERLAP_LEFT; - - // Try the right edge of the shadow. - V2_Intercept2(bound->right, bound->b, a, b, NULL, &s, &t); - if(s > 0 && s < 1 && t >= EPSILON && t <= 1 - EPSILON) - data->overlap |= OVERLAP_RIGHT; - } - } - - // Adjust the overlapping inner points. - for(data = (*list); data; data = data->next) - { - seg_t *seg = data->seg; - boundary_t *bound = &data->bound; - byte side = seg->side; - - if(data->overlap & OVERLAP_LEFT) - { - if(R_ResolveStep(bound->left, bound->a, - seg->lineDef->L_vo(side)->shadowOffsets.inner)) - done = false; - } - - if(data->overlap & OVERLAP_RIGHT) - { - if(R_ResolveStep(bound->right, bound->b, - seg->lineDef->L_vo(side^1)->shadowOffsets.inner)) - done = false; - } - } - } - -#undef OVERLAP_LEFT -#undef OVERLAP_RIGHT -#undef OVERLAP_ALL -#undef EPSILON -} - -/** - * Find all segs that will cast fakeradio edge shadows. - */ -uint R_FindShadowEdges(void) -{ - uint i, counter = 0; - segoverlapdata_t *list = NULL; - - unusedList = NULL; - - for(i = 0; i < numSectors; ++i) - { - sector_t *sec = SECTOR_PTR(i); - subsector_t **ssecp; - uint numShadowSegsInSector = 0; - - // Use validCount to make sure we only allocate one shadowpoly - // per line, side. - ++validCount; - - // Iterate all the subsectors of the sector. - ssecp = sec->ssectors; - while(*ssecp) - { - subsector_t *ssec = *ssecp; - seg_t **segp; - - // Iterate all the segs of the subsector. - segp = ssec->segs; - while(*segp) - { - seg_t *seg = *segp; - - // Minisegs don't get shadows, even then, only one. - if(seg->lineDef && seg->side == 0 && - !((seg->lineDef->validCount == validCount) || - LINE_SELFREF(seg->lineDef))) - { - linedef_t *line = seg->lineDef; - boolean frontside = (line->L_frontsector == sec); - - // If the line hasn't got two neighbors, it won't get a - // shadow. - if(!(line->vo[0]->LO_next->lineDef == line || - line->vo[1]->LO_next->lineDef == line)) - { - segoverlapdata_t *data; - - // This seg will get a shadow. Increment counter (we'll - // return this count). - seg->flags |= SEGF_SHADOW; - numShadowSegsInSector++; - line->validCount = validCount; - - // The outer vertices are just the beginning and end of - // the line. - R_ShadowEdges(seg); - data = createOverlapDataForSeg(seg); - linkOverlapDataToList(&list, data); - } - } - - *segp++; - } - - *ssecp++; - } - - if(numShadowSegsInSector > 0) - { - // Make sure they don't overlap each other. - R_ResolveOverlaps(&list, sec); - - destroyOverlapList(&list, true); - counter += numShadowSegsInSector; + return true; } } - destroyOverlapList(&unusedList, false); - - VERBOSE(Con_Printf("R_FindShadowEdges: Shadowing segs #%i .\n", counter)); - - return counter; + return false; } /** @@ -686,54 +258,65 @@ void R_InitSectorShadows(void) { uint startTime = Sys_GetRealTime(); - uint i; + uint i, j; vec2_t bounds[2], point; - byte side; vertex_t *vtx0, *vtx1; + lineowner_t *vo0, *vo1; + shadowlinkerparms_t data; - // Find all segs that will cast fakeradio edge shadows. - R_FindShadowEdges(); + for(i = 0; i < numVertexes; ++i) + { + R_UpdateVertexShadowOffsets(VERTEX_PTR(i)); + } /** * The algorithm: * * 1. Use the subsector blockmap to look for all the blocks that are - * within the shadow's bounding box. + * within the linedef's shadow bounding box. * - * 2. Check the subsectors whose sector == shadow's sector. + * 2. Check the subsectors whose sector is the same as the linedef. * - * 3. If one of the shadow's points is in the subsector, or the - * shadow's edges cross one of the subsector's edges (not parallel), - * link the shadow to the subsector. + * 3. If any of the shadow points are in the subsector, or any of the + * shadow edges cross one of the subsector's edges (not parallel), + * link the linedef to the subsector. */ shadowLinksBlockSet = Z_BlockCreate(sizeof(shadowlink_t), 1024, PU_LEVEL); - for(i = 0; i < numSegs; ++i) + for(i = 0; i < numLineDefs; ++i) { - seg_t *seg = &segs[i]; + linedef_t *line = LINE_PTR(i); - if(seg->flags & SEGF_SHADOW) - { - side = seg->side; - vtx0 = seg->lineDef->L_v(0^side); - vtx1 = seg->lineDef->L_v(1^side); + if(R_IsShadowingLinedef(line)) + for(j = 0; j < 2; ++j) + { + if(!line->L_side(j)) + continue; - V2_Set(point, vtx0->V_pos[VX], vtx0->V_pos[VY]); - V2_InitBox(bounds, point); + vtx0 = line->L_v(j); + vtx1 = line->L_v(j^1); + vo0 = line->L_vo(j); + vo1 = line->L_vo(j^1)->LO_prev; - // Use the extended points, they are wider than inoffsets. - V2_Sum(point, point, seg->lineDef->L_vo(side)->shadowOffsets.extended); - V2_AddToBox(bounds, point); + // Use the extended points, they are wider than inoffsets. + V2_Set(point, vtx0->V_pos[VX], vtx0->V_pos[VY]); + V2_InitBox(bounds, point); - V2_Set(point, vtx1->V_pos[VX], vtx1->V_pos[VY]); - V2_AddToBox(bounds, point); + V2_Sum(point, point, vo0->shadowOffsets.extended); + V2_AddToBox(bounds, point); - V2_Sum(point, point, seg->lineDef->L_vo(side^1)->shadowOffsets.extended); - V2_AddToBox(bounds, point); + V2_Set(point, vtx1->V_pos[VX], vtx1->V_pos[VY]); + V2_AddToBox(bounds, point); - P_SubsectorsBoxIteratorv(bounds, R_GetShadowSector(seg, 0, false), - RIT_ShadowSubsectorLinker, seg); - } + V2_Sum(point, point, vo1->shadowOffsets.extended); + V2_AddToBox(bounds, point); + + data.lineDef = line; + data.side = j; + + P_SubsectorsBoxIteratorv(bounds, line->L_sector(j), + RIT_ShadowSubsectorLinker, &data); + } } // How much time did we spend? diff --git a/doomsday/engine/portable/src/rend_fakeradio.c b/doomsday/engine/portable/src/rend_fakeradio.c index 2398ef87ad..21b011a5ce 100644 --- a/doomsday/engine/portable/src/rend_fakeradio.c +++ b/doomsday/engine/portable/src/rend_fakeradio.c @@ -1194,9 +1194,10 @@ static uint radioEdgeHackType(linedef_t *line, sector_t *front, sector_t *back, * Calculate the corner coordinates and add a new shadow polygon to the * rendering lists. */ -static void radioAddShadowEdge(seg_t *seg, boolean isCeiling, +static void radioAddShadowEdge(const linedef_t *line, byte side, vec2_t inner[2], vec2_t outer[2], float z, - float darkness, float sideOpen[2]) + float darkness, float sideOpen[2], + boolean isCeiling) { static const uint floorIndices[][4] = {{0, 1, 2, 3}, {1, 2, 3, 0}}; static const uint ceilIndices[][4] = {{0, 3, 2, 1}, {1, 0, 3, 2}}; @@ -1206,7 +1207,6 @@ static void radioAddShadowEdge(seg_t *seg, boolean isCeiling, rendpoly_t *q; rendpoly_vertex_t *vtx; float shadowAlpha; - byte side = seg->side; vertex_t *vtx0, *vtx1; // Sector lightlevel affects the darkness of the shadows. @@ -1214,8 +1214,8 @@ static void radioAddShadowEdge(seg_t *seg, boolean isCeiling, darkness = 1; shadowAlpha = shadowDark * darkness; - vtx0 = seg->lineDef->L_v(side^0); - vtx1 = seg->lineDef->L_v(side^1); + vtx0 = line->L_v(side^0); + vtx1 = line->L_v(side^1); // What vertex winding order? // (for best results, the cross edge should always be the shortest). @@ -1303,12 +1303,11 @@ static void radioSubsectorEdges(const subsector_t *subsector) uint i, pln, hack, side; float open, sideOpen[2], vec[3]; float fz, bz, bhz, plnHeight; - sector_t *shadowSec, *front, *back; + sector_t *front, *back; linedef_t *line, *neighbors[2]; surface_t *suf; shadowlink_t *link; vec2_t inner[2], outer[2]; - seg_t *seg; boolean workToDo = false; BEGIN_PROF( PROF_RADIO_SUBSECTOR ); @@ -1350,27 +1349,26 @@ BEGIN_PROF( PROF_RADIO_SUBSECTOR ); if(!workToDo) return; - // We need to check all the segs linked to this subsector for the - // purpose of fakeradio shadow polys. + // We need to check all the shadow lines linked to this subsector for + // the purpose of fakeradio shadowing. for(link = subsector->shadows; link != NULL; link = link->next) { // Already rendered during the current frame? We only want to // render each shadow once per frame. - if(link->seg->shadowVisFrame == (ushort) frameCount) + if(link->lineDef->shadowVisFrame[link->side] == (ushort) frameCount) continue; - seg = link->seg; - // Now it will be rendered. - seg->shadowVisFrame = (ushort) frameCount; - line = seg->lineDef; - side = seg->side; + link->lineDef->shadowVisFrame[link->side] = (ushort) frameCount; + + line = link->lineDef; + side = link->side; // Find the neighbors of this edge. for(i = 0; i < 2; ++i) { neighbors[i] = - R_FindLineNeighbor(seg->subsector->sector, line, + R_FindLineNeighbor(line->L_sector(side), line, line->L_vo(side^i), i, NULL); } @@ -1381,12 +1379,10 @@ BEGIN_PROF( PROF_RADIO_SUBSECTOR ); // Determine the openness of the line. If this edge is open, // there won't be a shadow at all. Open neighbours cause some - // changes in the polygon corner - // vertices (placement, colour). + // changes in the polygon corner vertices (placement, colour). - shadowSec = R_GetShadowSector(seg, pln, true); suf = &subsector->sector->planes[pln]->surface; - plnHeight = shadowSec->SP_planevisheight(pln); + plnHeight = line->L_sector(side)->SP_planevisheight(pln); vec[VZ] = vy - plnHeight; // Glowing surfaces or missing textures shouldn't have shadows. @@ -1400,13 +1396,13 @@ BEGIN_PROF( PROF_RADIO_SUBSECTOR ); { if(side == 0) { - front = shadowSec; + front = line->L_sector(side); back = line->L_backsector; } else { front = line->L_frontsector; - back = shadowSec; + back = line->L_sector(side); } } else @@ -1434,10 +1430,12 @@ BEGIN_PROF( PROF_RADIO_SUBSECTOR ); { float pos; linedef_t *neighbor = neighbors[i]; + lineowner_t *vo; if(neighbor && neighbor->L_backside) { - uint side2 = (neighbor->L_frontsector != shadowSec); + uint side2 = + (neighbor->L_frontsector != line->L_sector(side)); front = neighbor->L_sector(side2); back = neighbor->L_sector(side2 ^ 1); @@ -1454,108 +1452,22 @@ BEGIN_PROF( PROF_RADIO_SUBSECTOR ); pos = sideOpen[i]; - if(pos < 1) // Nearly closed. - { - V2_Sum(inner[i], seg->lineDef->L_vpos(i^side), - seg->lineDef->L_vo(i^side)->shadowOffsets.inner); - } - else if(pos == 1) // Same height on both sides. - { // We need to use a back extended offset but which one? - - /** - * \todo This determination logic is called for each shadow - * edge connected on the XY plane twice (once for each side). - * Instead, we should reuse the same offset by pre-determining - * before we get here. - */ - - // Walk around the vertex and choose the bextoffset for the - // back neighbor at which plane heights differ. - lineowner_t *base, *p; - vertex_t *vtx = seg->lineDef->L_v(i^side); - uint id; - boolean found; - - base = R_GetVtxLineOwner(vtx, seg->lineDef); - p = base->link[!i]; - id = 0; - found = false; - while(p != base && !found) - { - if(!(p->lineDef->L_frontside && p->lineDef->L_backside && - p->lineDef->L_frontsector == p->lineDef->L_backsector)) - { - if(!p->lineDef->L_backside) - { - if((pln && - p->lineDef->L_frontsector->SP_ceilvisheight == plnHeight) || - (!pln && - p->lineDef->L_frontsector->SP_floorvisheight == plnHeight)) - found = true; - } - else - { - vertex_t *pvtx[2]; - - pvtx[0] = p->lineDef->L_v1; - pvtx[1] = p->lineDef->L_v2; - - if((pln && - ((p->lineDef->L_frontsector->SP_ceilvisheight < plnHeight || - p->lineDef->L_backsector->SP_ceilvisheight < plnHeight) || - ((pvtx[i^1] == vtx && - p->lineDef->L_backsector->SP_floorvisheight >= - seg->subsector->sector->SP_ceilvisheight) || - (pvtx[i] == vtx && - p->lineDef->L_frontsector->SP_floorvisheight >= - seg->subsector->sector->SP_ceilvisheight)))) || - (!pln && - ((p->lineDef->L_frontsector->SP_floorvisheight > plnHeight || - p->lineDef->L_backsector->SP_floorvisheight > plnHeight) || - ((pvtx[i^1] == vtx && - p->lineDef->L_backsector->SP_ceilvisheight <= - seg->subsector->sector->SP_floorvisheight) || - (pvtx[i] == vtx && - p->lineDef->L_frontsector->SP_ceilvisheight <= - seg->subsector->sector->SP_floorvisheight)))) || - Rend_DoesMidTextureFillGap(p->lineDef, pvtx[i] == vtx)) - { - found = true; - } - } - - if(!found) - id++; - } - - if(!p->lineDef->L_backside) - break; - - if(!found) - p = p->link[!i]; - } + vo = line->L_vo(i^side); + if(i) + vo = vo->LO_prev; - if(found) - { - // id is now the index + 1 into the side's bextoffset array. - V2_Sum(inner[i], seg->lineDef->L_vpos(i^side), - seg->lineDef->L_vo(i^side)->shadowOffsets.backExtended[id-1].offset); - } - else // Its an open edge. - { - V2_Sum(inner[i], seg->lineDef->L_vpos(i^side), - seg->lineDef->L_vo(i^side)->shadowOffsets.extended); - } + if(pos <= 1) // Nearly closed. + { + V2_Sum(inner[i], line->L_vpos(i^side), vo->shadowOffsets.inner); } else // Fully, unquestionably open. { - V2_Sum(inner[i], seg->lineDef->L_vpos(i^side), - seg->lineDef->L_vo(i^side)->shadowOffsets.extended); + V2_Sum(inner[i], line->L_vpos(i^side), vo->shadowOffsets.extended); } } - radioAddShadowEdge(seg, pln, inner, outer, plnHeight, - 1 - open, sideOpen); + radioAddShadowEdge(line, side, inner, outer, plnHeight, + 1 - open, sideOpen, pln); } }