From 0d4379634ab7000cf1e7fdb475e29073246cd0f5 Mon Sep 17 00:00:00 2001 From: danij Date: Sun, 4 Feb 2007 22:54:33 +0000 Subject: [PATCH] Revised R_InitLineNeighbors() to make use of vertex lineowners. In doing so, the majority of the visual fakeradio glitches when playing maps utilizing DOOM renderer hacks have been resolved (the old code was sometimes finding the wrong line neighbors). Is also noticeably quicker as we don't have to traverse all the lines in a sector for each vertex for each side, for each neighbor. Fixed a bug in R_RationalizeSectors() which could result in an infinite loop in complex maps (e.g. bludwrks.wad). Began changing the method used to support linked planes to a per-subsector (group) based design. Currently waiting on an algorithm to find the subsectors which have at least one seg belonging to linedefs detected in R_RationalizeSectors() and seperating into groups. Atm, subsectors of a sector are simply added to the same group. Added cvar "rend-dev-surface-linked" for debug; temporarily disable the visual results of linked surfaces. Various other minor tweaks/optimizations. --- doomsday/engine/data/cphelp.txt | 3 + doomsday/engine/portable/include/mapdata.hs | 621 +++++++++--------- doomsday/engine/portable/include/p_mapdata.h | 10 - doomsday/engine/portable/include/p_maptypes.h | 23 +- doomsday/engine/portable/include/r_data.h | 1 + doomsday/engine/portable/include/r_shadow.h | 3 +- doomsday/engine/portable/include/r_world.h | 2 +- .../engine/portable/include/rend_fakeradio.h | 2 +- doomsday/engine/portable/include/rend_main.h | 1 + doomsday/engine/portable/src/dam_main.c | 17 +- doomsday/engine/portable/src/p_data.c | 4 +- doomsday/engine/portable/src/r_main.c | 30 +- doomsday/engine/portable/src/r_shadow.c | 131 ++-- doomsday/engine/portable/src/r_world.c | 580 ++++++++-------- doomsday/engine/portable/src/rend_dyn.c | 18 +- doomsday/engine/portable/src/rend_fakeradio.c | 253 ++++--- doomsday/engine/portable/src/rend_main.c | 62 +- 17 files changed, 920 insertions(+), 841 deletions(-) diff --git a/doomsday/engine/data/cphelp.txt b/doomsday/engine/data/cphelp.txt index 5b08e157f9..e9a8575cd0 100644 --- a/doomsday/engine/data/cphelp.txt +++ b/doomsday/engine/data/cphelp.txt @@ -610,6 +610,9 @@ desc = 1=Render player view in wireframe mode. [rend-dev-framecount] desc = Frame counter. +[rend-dev-surface-linked] +desc = 1=Disable linked surfaces for render. + [rend-info-lums] desc = 1=Print lumobj count after rendering a frame. diff --git a/doomsday/engine/portable/include/mapdata.hs b/doomsday/engine/portable/include/mapdata.hs index c3f2636de5..3d98f8e2fb 100644 --- a/doomsday/engine/portable/include/mapdata.hs +++ b/doomsday/engine/portable/include/mapdata.hs @@ -1,302 +1,319 @@ -# $Id$ -# Runtime map data defitions. Processed by the makedmt.py script. - -struct vertex - FLOAT float[2] pos - - uint numsecowners // Number of sector owners. - - uint* secowners // Sector indices [numsecowners] size. - - uint numlineowners // Number of line owners. - - lineowner_s* lineowners // Lineowner base ptr [numlineowners] size. A doubly, circularly linked list. The base is the line with the lowest angle and the next-most with the largest angle. - - boolean anchored // One or more of our line owners are one-sided. -end - -internal -// Helper macros for accessing seg data elements. -#define FRONT 0 -#define BACK 1 - -#define SG_v1 v[0] -#define SG_v2 v[1] -#define SG_frontsector sec[FRONT] -#define SG_backsector sec[BACK] - -// Seg frame flags -#define SEGINF_FACINGFRONT 0x0001 -#define SEGINF_BACKSECSKYFIX 0x0002 -end - -struct seg - PTR vertex_s*[2] v // [Start, End] of the segment. - FLOAT float length // Accurate length of the segment (v1 -> v2). - FLOAT float offset - PTR side_s* sidedef - PTR line_s* linedef - PTR sector_s*[2] sec - ANGLE angle_t angle - BYTE byte flags - - short frameflags - - biastracker_s[3] tracker // 0=top, 1=middle, 2=bottom - - vertexillum_s[3][4] illum - - uint updated - - biasaffection_s[MAX_BIAS_AFFECTED] affected -end - -struct subsector - PTR sector_s* sector - UINT uint segcount - PTR seg_s* firstseg - PTR polyobj_s* poly // NULL, if there is no polyobj. - BYTE byte flags - - ushort numverts - - fvertex_t* verts // A sorted list of edge vertices. - - fvertex_t bbox[2] // Min and max points. - - fvertex_t midpoint // Center of vertices. - - subplaneinfo_s** planes - - ushort numvertices - - fvertex_s* vertices - - int validcount - - shadowlink_s* shadows -end - -internal -// Surface flags. -#define SUF_TEXFIX 0x1 // Current texture is a fix replacement - // (not sent to clients, returned via DMU etc). -#define SUF_GLOW 0x2 // Surface glows (full bright). -#define SUF_BLEND 0x4 // Surface possibly has a blended texture. -#define SUF_NO_RADIO 0x8 // No fakeradio for this surface. -end - -struct surface - INT int flags // SUF_ flags - - int oldflags - SHORT short texture - - short oldtexture - - boolean isflat // true if current texture is a flat - - boolean oldisflat - - float[3] normal // Surface normal - - float[3] oldnormal - FLOAT float[2] texmove // Texture movement X and Y - - float[2] oldtexmove - FLOAT float offx // Texture x offset - - float oldoffx - FLOAT float offy // Texture y offset - - float oldoffy - BYTE byte[4] rgba // Surface color tint - - byte[4] oldrgba - - translation_s* xlat -end - -struct plane - FLOAT float height // Current height - - float[2] oldheight - - surface_t surface - FLOAT float glow // Glow amount - BYTE byte[3] glowrgb // Glow color - FLOAT float target // Target height - FLOAT float speed // Move speed - PTR degenmobj_t soundorg // Sound origin for plane - PTR sector_s* sector // Owner of the plane (temp) - - float visheight // Visible plane height (smoothed) - - float visoffset - - sector_s* linked // Plane attached to another sector. -end - -internal -// Helper macros for accessing sector floor/ceiling plane data elements. -#define SP_ceilsurface planes[PLN_CEILING]->surface -#define SP_ceilheight planes[PLN_CEILING]->height -#define SP_ceilnormal planes[PLN_CEILING]->normal -#define SP_ceilpic planes[PLN_CEILING]->surface.texture -#define SP_ceilisflat planes[PLN_CEILING]->surface.isflat -#define SP_ceiloffx planes[PLN_CEILING]->surface.offx -#define SP_ceiloffy planes[PLN_CEILING]->surface.offy -#define SP_ceilrgb planes[PLN_CEILING]->surface.rgba -#define SP_ceilglow planes[PLN_CEILING]->glow -#define SP_ceilglowrgb planes[PLN_CEILING]->glowrgb -#define SP_ceiltarget planes[PLN_CEILING]->target -#define SP_ceilspeed planes[PLN_CEILING]->speed -#define SP_ceiltexmove planes[PLN_CEILING]->surface.texmove -#define SP_ceilsoundorg planes[PLN_CEILING]->soundorg -#define SP_ceilvisheight planes[PLN_CEILING]->visheight -#define SP_ceillinked planes[PLN_CEILING]->linked - -#define SP_floorsurface planes[PLN_FLOOR]->surface -#define SP_floorheight planes[PLN_FLOOR]->height -#define SP_floornormal planes[PLN_FLOOR]->normal -#define SP_floorpic planes[PLN_FLOOR]->surface.texture -#define SP_floorisflat planes[PLN_FLOOR]->surface.isflat -#define SP_flooroffx planes[PLN_FLOOR]->surface.offx -#define SP_flooroffy planes[PLN_FLOOR]->surface.offy -#define SP_floorrgb planes[PLN_FLOOR]->surface.rgba -#define SP_floorglow planes[PLN_FLOOR]->glow -#define SP_floorglowrgb planes[PLN_FLOOR]->glowrgb -#define SP_floortarget planes[PLN_FLOOR]->target -#define SP_floorspeed planes[PLN_FLOOR]->speed -#define SP_floortexmove planes[PLN_FLOOR]->surface.texmove -#define SP_floorsoundorg planes[PLN_FLOOR]->soundorg -#define SP_floorvisheight planes[PLN_FLOOR]->visheight -#define SP_floorlinked planes[PLN_FLOOR]->linked - -#define SECT_PLANE_HEIGHT(x, n) (x->planes[n]->visheight) -end - -internal -// Sector frame flags -#define SIF_VISIBLE 0x1 // Sector is visible on this frame. -#define SIF_FRAME_CLEAR 0x1 // Flags to clear before each frame. -#define SIF_LIGHT_CHANGED 0x2 - -// Sector flags. -#define SECF_INVIS_FLOOR 0x1 -#define SECF_INVIS_CEILING 0x2 -end - -struct sector - SHORT short lightlevel - - int oldlightlevel - BYTE byte[3] rgb - - byte[3] oldrgb - INT int validcount // if == validcount, already checked. - PTR mobj_s* thinglist // List of mobjs in the sector. - UINT uint linecount - PTR line_s** Lines // [linecount] size. - UINT uint subscount - PTR subsector_s** subsectors // [subscount] size. - - skyfix_t[2] skyfix // floor, ceiling. - PTR degenmobj_t soundorg - - FLOAT float[NUM_REVERB_DATA] reverb - - int[4] blockbox // Mapblock bounding box. - UINT uint planecount - - plane_s** planes // [planecount] size. - - sector_s* containsector // Sector that contains this (if any). - - boolean permanentlink - - boolean unclosed // An unclosed sector (some sort of fancy hack). - - boolean selfRefHack // A self-referencing hack sector which ISNT enclosed by the sector referenced. Bounding box for the sector. - - float[4] bounds // Bounding box for the sector - - int frameflags - - int addspritecount // frame number of last R_AddSprites - - sector_s* lightsource // Main sky light source - - uint blockcount // Number of gridblocks in the sector. - - uint changedblockcount // Number of blocks to mark changed. - - ushort* blocks // Light grid block indices. -end - -internal -// Parts of a wall segment. -typedef enum segsection_e { - SEG_MIDDLE, - SEG_TOP, - SEG_BOTTOM -} segsection_t; - -// Helper macros for accessing sidedef top/middle/bottom section data elements. -#define SW_middlesurface sections[SEG_MIDDLE] -#define SW_middleflags sections[SEG_MIDDLE].flags -#define SW_middlepic sections[SEG_MIDDLE].texture -#define SW_middleisflat sections[SEG_MIDDLE].isflat -#define SW_middlenormal sections[SEG_MIDDLE].normal -#define SW_middletexmove sections[SEG_MIDDLE].texmove -#define SW_middleoffx sections[SEG_MIDDLE].offx -#define SW_middleoffy sections[SEG_MIDDLE].offy -#define SW_middlergba sections[SEG_MIDDLE].rgba -#define SW_middletexlat sections[SEG_MIDDLE].xlat - -#define SW_topsurface sections[SEG_TOP] -#define SW_topflags sections[SEG_TOP].flags -#define SW_toppic sections[SEG_TOP].texture -#define SW_topisflat sections[SEG_TOP].isflat -#define SW_topnormal sections[SEG_TOP].normal -#define SW_toptexmove sections[SEG_TOP].texmove -#define SW_topoffx sections[SEG_TOP].offx -#define SW_topoffy sections[SEG_TOP].offy -#define SW_toprgba sections[SEG_TOP].rgba -#define SW_toptexlat sections[SEG_TOP].xlat - -#define SW_bottomsurface sections[SEG_BOTTOM] -#define SW_bottomflags sections[SEG_BOTTOM].flags -#define SW_bottompic sections[SEG_BOTTOM].texture -#define SW_bottomisflat sections[SEG_BOTTOM].isflat -#define SW_bottomnormal sections[SEG_BOTTOM].normal -#define SW_bottomtexmove sections[SEG_BOTTOM].texmove -#define SW_bottomoffx sections[SEG_BOTTOM].offx -#define SW_bottomoffy sections[SEG_BOTTOM].offy -#define SW_bottomrgba sections[SEG_BOTTOM].rgba -#define SW_bottomtexlat sections[SEG_BOTTOM].xlat - -// Side frame flags -#define SIDEINF_TOPPVIS 0x0001 -#define SIDEINF_MIDDLEPVIS 0x0002 -#define SIDEINF_BOTTOMPVIS 0x0004 -end - -struct side - - surface_t[3] sections - BLENDMODE blendmode_t blendmode - PTR sector_s* sector - SHORT short flags - - short frameflags - - line_s*[2] neighbor // Left and right neighbour. - - boolean[2] pretendneighbor // If true, neighbor is not a "real" neighbor (it does not share a line with this side's sector). - - sector_s*[2] proxsector // Sectors behind the neighbors. - - line_s*[2] backneighbor // Neighbour in the backsector (if any). - - line_s*[2] alignneighbor // Aligned left and right neighbours. -end - -internal -// Helper macros for accessing linedef data elements. -#define L_v1 v[0] -#define L_v2 v[1] -#define L_vo1 vo[0] -#define L_vo2 vo[1] -#define L_frontsector sec[FRONT] -#define L_backsector sec[BACK] -#define L_frontside sides[FRONT] -#define L_backside sides[BACK] -end - -struct line - PTR vertex_s*[2] v - SHORT short flags - PTR sector_s*[2] sec // [front, back] sectors. - FLOAT float dx - FLOAT float dy - INT slopetype_t slopetype - INT int validcount - PTR side_s*[2] sides - FIXED fixed_t[4] bbox - - lineowner_s*[2] vo // Links to vertex line owner nodes [left, right] - - float length // Accurate length - - binangle_t angle // Calculated from front side's normal - - boolean selfrefhackroot // This line is the root of a self-referencing hack sector -end - -struct polyobj - UINT uint numsegs - PTR seg_s** segs - INT int validcount - PTR degenmobj_t startSpot - ANGLE angle_t angle - INT int tag // reference tag assigned in HereticEd - - ddvertex_t* originalPts // used as the base for the rotations - - ddvertex_t* prevPts // use to restore the old point values - FIXED fixed_t[4] bbox - - fvertex_t dest - INT int speed // Destination XY and speed. - ANGLE angle_t destAngle // Destination angle. - ANGLE angle_t angleSpeed // Rotation speed. - BOOL boolean crush // should the polyobj attempt to crush mobjs? - INT int seqType - FIXED fixed_t size // polyobj size (area of POLY_AREAUNIT == size of FRACUNIT) - PTR void* specialdata // pointer a thinker, if the poly is moving -end - -struct node - FLOAT float x // Partition line. - FLOAT float y // Partition line. - FLOAT float dx // Partition line. - FLOAT float dy // Partition line. - FLOAT float[2][4] bbox // Bounding box for each child. - UINT uint[2] children // If NF_SUBSECTOR it's a subsector. -end +# $Id$ +# Runtime map data defitions. Processed by the makedmt.py script. + +struct vertex + FLOAT float[2] pos + - uint numsecowners // Number of sector owners. + - uint* secowners // Sector indices [numsecowners] size. + - uint numlineowners // Number of line owners. + - lineowner_s* lineowners // Lineowner base ptr [numlineowners] size. A doubly, circularly linked list. The base is the line with the lowest angle and the next-most with the largest angle. + - boolean anchored // One or more of our line owners are one-sided. +end + +internal +// Helper macros for accessing seg data elements. +#define FRONT 0 +#define BACK 1 + +#define SG_v1 v[0] +#define SG_v2 v[1] +#define SG_frontsector sec[FRONT] +#define SG_backsector sec[BACK] + +// Seg frame flags +#define SEGINF_FACINGFRONT 0x0001 +#define SEGINF_BACKSECSKYFIX 0x0002 +end + +struct seg + PTR vertex_s*[2] v // [Start, End] of the segment. + FLOAT float length // Accurate length of the segment (v1 -> v2). + FLOAT float offset + PTR side_s* sidedef + PTR line_s* linedef + PTR sector_s*[2] sec + ANGLE angle_t angle + BYTE byte flags + - short frameflags + - biastracker_s[3] tracker // 0=top, 1=middle, 2=bottom + - vertexillum_s[3][4] illum + - uint updated + - biasaffection_s[MAX_BIAS_AFFECTED] affected +end + +struct subsector + PTR sector_s* sector + UINT uint segcount + PTR seg_s* firstseg + PTR polyobj_s* poly // NULL, if there is no polyobj. + BYTE byte flags + - ushort numverts + - fvertex_t* verts // A sorted list of edge vertices. + - fvertex_t bbox[2] // Min and max points. + - fvertex_t midpoint // Center of vertices. + - subplaneinfo_s** planes + - ushort numvertices + - fvertex_s* vertices + - int validcount + - shadowlink_s* shadows + - uint group +end + +internal +// Surface flags. +#define SUF_TEXFIX 0x1 // Current texture is a fix replacement + // (not sent to clients, returned via DMU etc). +#define SUF_GLOW 0x2 // Surface glows (full bright). +#define SUF_BLEND 0x4 // Surface possibly has a blended texture. +#define SUF_NO_RADIO 0x8 // No fakeradio for this surface. +end + +struct surface + INT int flags // SUF_ flags + - int oldflags + SHORT short texture + - short oldtexture + - boolean isflat // true if current texture is a flat + - boolean oldisflat + - float[3] normal // Surface normal + - float[3] oldnormal + FLOAT float[2] texmove // Texture movement X and Y + - float[2] oldtexmove + FLOAT float offx // Texture x offset + - float oldoffx + FLOAT float offy // Texture y offset + - float oldoffy + BYTE byte[4] rgba // Surface color tint + - byte[4] oldrgba + - translation_s* xlat +end + +internal +enum { + PLN_FLOOR, + PLN_CEILING, + NUM_PLANE_TYPES +}; + +typedef struct skyfix_s { + float offset; +} skyfix_t; +end + +struct plane + FLOAT float height // Current height + - float[2] oldheight + - surface_t surface + FLOAT float glow // Glow amount + BYTE byte[3] glowrgb // Glow color + FLOAT float target // Target height + FLOAT float speed // Move speed + PTR degenmobj_t soundorg // Sound origin for plane + PTR sector_s* sector // Owner of the plane (temp) + - float visheight // Visible plane height (smoothed) + - float visoffset +end + +internal +// Helper macros for accessing sector floor/ceiling plane data elements. +#define SP_ceilsurface planes[PLN_CEILING]->surface +#define SP_ceilheight planes[PLN_CEILING]->height +#define SP_ceilnormal planes[PLN_CEILING]->normal +#define SP_ceilpic planes[PLN_CEILING]->surface.texture +#define SP_ceilisflat planes[PLN_CEILING]->surface.isflat +#define SP_ceiloffx planes[PLN_CEILING]->surface.offx +#define SP_ceiloffy planes[PLN_CEILING]->surface.offy +#define SP_ceilrgb planes[PLN_CEILING]->surface.rgba +#define SP_ceilglow planes[PLN_CEILING]->glow +#define SP_ceilglowrgb planes[PLN_CEILING]->glowrgb +#define SP_ceiltarget planes[PLN_CEILING]->target +#define SP_ceilspeed planes[PLN_CEILING]->speed +#define SP_ceiltexmove planes[PLN_CEILING]->surface.texmove +#define SP_ceilsoundorg planes[PLN_CEILING]->soundorg +#define SP_ceilvisheight planes[PLN_CEILING]->visheight + +#define SP_floorsurface planes[PLN_FLOOR]->surface +#define SP_floorheight planes[PLN_FLOOR]->height +#define SP_floornormal planes[PLN_FLOOR]->normal +#define SP_floorpic planes[PLN_FLOOR]->surface.texture +#define SP_floorisflat planes[PLN_FLOOR]->surface.isflat +#define SP_flooroffx planes[PLN_FLOOR]->surface.offx +#define SP_flooroffy planes[PLN_FLOOR]->surface.offy +#define SP_floorrgb planes[PLN_FLOOR]->surface.rgba +#define SP_floorglow planes[PLN_FLOOR]->glow +#define SP_floorglowrgb planes[PLN_FLOOR]->glowrgb +#define SP_floortarget planes[PLN_FLOOR]->target +#define SP_floorspeed planes[PLN_FLOOR]->speed +#define SP_floortexmove planes[PLN_FLOOR]->surface.texmove +#define SP_floorsoundorg planes[PLN_FLOOR]->soundorg +#define SP_floorvisheight planes[PLN_FLOOR]->visheight + +#define SECT_PLANE_HEIGHT(x, n) (x->planes[n]->visheight) +end + +internal +// Sector frame flags +#define SIF_VISIBLE 0x1 // Sector is visible on this frame. +#define SIF_FRAME_CLEAR 0x1 // Flags to clear before each frame. +#define SIF_LIGHT_CHANGED 0x2 + +// Sector flags. +#define SECF_INVIS_FLOOR 0x1 +#define SECF_INVIS_CEILING 0x2 + +typedef struct ssecgroup_s { + struct sector_s** linked; // [sector->planecount] size. + // Plane attached to another sector. +} ssecgroup_t; +end + +struct sector + SHORT short lightlevel + - int oldlightlevel + BYTE byte[3] rgb + - byte[3] oldrgb + INT int validcount // if == validcount, already checked. + PTR mobj_s* thinglist // List of mobjs in the sector. + UINT uint linecount + PTR line_s** Lines // [linecount] size. + UINT uint subscount + PTR subsector_s** subsectors // [subscount] size. + - uint subsgroupcount + - ssecgroup_t* subsgroups // [subsgroupcount] size. + - skyfix_t[2] skyfix // floor, ceiling. + PTR degenmobj_t soundorg + + FLOAT float[NUM_REVERB_DATA] reverb + - int[4] blockbox // Mapblock bounding box. + UINT uint planecount + - plane_s** planes // [planecount] size. + - sector_s* containsector // Sector that contains this (if any). + - boolean permanentlink + - boolean unclosed // An unclosed sector (some sort of fancy hack). + - boolean selfRefHack // A self-referencing hack sector which ISNT enclosed by the sector referenced. Bounding box for the sector. + - float[4] bounds // Bounding box for the sector + - int frameflags + - int addspritecount // frame number of last R_AddSprites + - sector_s* lightsource // Main sky light source + - uint blockcount // Number of gridblocks in the sector. + - uint changedblockcount // Number of blocks to mark changed. + - ushort* blocks // Light grid block indices. +end + +internal +// Parts of a wall segment. +typedef enum segsection_e { + SEG_MIDDLE, + SEG_TOP, + SEG_BOTTOM +} segsection_t; + +// Helper macros for accessing sidedef top/middle/bottom section data elements. +#define SW_middlesurface sections[SEG_MIDDLE] +#define SW_middleflags sections[SEG_MIDDLE].flags +#define SW_middlepic sections[SEG_MIDDLE].texture +#define SW_middleisflat sections[SEG_MIDDLE].isflat +#define SW_middlenormal sections[SEG_MIDDLE].normal +#define SW_middletexmove sections[SEG_MIDDLE].texmove +#define SW_middleoffx sections[SEG_MIDDLE].offx +#define SW_middleoffy sections[SEG_MIDDLE].offy +#define SW_middlergba sections[SEG_MIDDLE].rgba +#define SW_middletexlat sections[SEG_MIDDLE].xlat + +#define SW_topsurface sections[SEG_TOP] +#define SW_topflags sections[SEG_TOP].flags +#define SW_toppic sections[SEG_TOP].texture +#define SW_topisflat sections[SEG_TOP].isflat +#define SW_topnormal sections[SEG_TOP].normal +#define SW_toptexmove sections[SEG_TOP].texmove +#define SW_topoffx sections[SEG_TOP].offx +#define SW_topoffy sections[SEG_TOP].offy +#define SW_toprgba sections[SEG_TOP].rgba +#define SW_toptexlat sections[SEG_TOP].xlat + +#define SW_bottomsurface sections[SEG_BOTTOM] +#define SW_bottomflags sections[SEG_BOTTOM].flags +#define SW_bottompic sections[SEG_BOTTOM].texture +#define SW_bottomisflat sections[SEG_BOTTOM].isflat +#define SW_bottomnormal sections[SEG_BOTTOM].normal +#define SW_bottomtexmove sections[SEG_BOTTOM].texmove +#define SW_bottomoffx sections[SEG_BOTTOM].offx +#define SW_bottomoffy sections[SEG_BOTTOM].offy +#define SW_bottomrgba sections[SEG_BOTTOM].rgba +#define SW_bottomtexlat sections[SEG_BOTTOM].xlat + +// Side frame flags +#define SIDEINF_TOPPVIS 0x0001 +#define SIDEINF_MIDDLEPVIS 0x0002 +#define SIDEINF_BOTTOMPVIS 0x0004 +end + +struct side + - surface_t[3] sections + BLENDMODE blendmode_t blendmode + PTR sector_s* sector + SHORT short flags + - short frameflags + - line_s*[2] neighbor // Left and right neighbour. + - boolean[2] pretendneighbor // If true, neighbor is not a "real" neighbor (it does not share a line with this side's sector). + - sector_s*[2] proxsector // Sectors behind the neighbors. + - line_s*[2] backneighbor // Neighbour in the backsector (if any). + - line_s*[2] alignneighbor // Aligned left and right neighbours. +end + +internal +// Helper macros for accessing linedef data elements. +#define L_v1 v[0] +#define L_v2 v[1] +#define L_vo1 vo[0] +#define L_vo2 vo[1] +#define L_frontsector sec[FRONT] +#define L_backsector sec[BACK] +#define L_frontside sides[FRONT] +#define L_backside sides[BACK] +end + +struct line + PTR vertex_s*[2] v + SHORT short flags + PTR sector_s*[2] sec // [front, back] sectors. + FLOAT float dx + FLOAT float dy + INT slopetype_t slopetype + INT int validcount + PTR side_s*[2] sides + FIXED fixed_t[4] bbox + - lineowner_s*[2] vo // Links to vertex line owner nodes [left, right] + - float length // Accurate length + - binangle_t angle // Calculated from front side's normal + - boolean selfrefhackroot // This line is the root of a self-referencing hack sector +end + +struct polyobj + UINT uint numsegs + PTR seg_s** segs + INT int validcount + PTR degenmobj_t startSpot + ANGLE angle_t angle + INT int tag // reference tag assigned in HereticEd + - ddvertex_t* originalPts // used as the base for the rotations + - ddvertex_t* prevPts // use to restore the old point values + FIXED fixed_t[4] bbox + - fvertex_t dest + INT int speed // Destination XY and speed. + ANGLE angle_t destAngle // Destination angle. + ANGLE angle_t angleSpeed // Rotation speed. + BOOL boolean crush // should the polyobj attempt to crush mobjs? + INT int seqType + FIXED fixed_t size // polyobj size (area of POLY_AREAUNIT == size of FRACUNIT) + PTR void* specialdata // pointer a thinker, if the poly is moving +end + +struct node + FLOAT float x // Partition line. + FLOAT float y // Partition line. + FLOAT float dx // Partition line. + FLOAT float dy // Partition line. + FLOAT float[2][4] bbox // Bounding box for each child. + UINT uint[2] children // If NF_SUBSECTOR it's a subsector. +end diff --git a/doomsday/engine/portable/include/p_mapdata.h b/doomsday/engine/portable/include/p_mapdata.h index a89a44ba25..008aa1eec0 100644 --- a/doomsday/engine/portable/include/p_mapdata.h +++ b/doomsday/engine/portable/include/p_mapdata.h @@ -101,16 +101,6 @@ typedef struct fvertex_s { float pos[2]; } fvertex_t; -enum { - PLN_FLOOR, - PLN_CEILING, - NUM_PLANE_TYPES -}; - -typedef struct skyfix_s { - float offset; -} skyfix_t; - #include "p_maptypes.h" /* diff --git a/doomsday/engine/portable/include/p_maptypes.h b/doomsday/engine/portable/include/p_maptypes.h index fcc57f7c92..35965a280b 100644 --- a/doomsday/engine/portable/include/p_maptypes.h +++ b/doomsday/engine/portable/include/p_maptypes.h @@ -61,6 +61,7 @@ typedef struct subsector_s { struct fvertex_s* vertices; int validcount; struct shadowlink_s* shadows; + unsigned int group; } subsector_t; // Surface flags. @@ -91,6 +92,16 @@ typedef struct surface_s { struct translation_s* xlat; } surface_t; +enum { + PLN_FLOOR, + PLN_CEILING, + NUM_PLANE_TYPES +}; + +typedef struct skyfix_s { + float offset; +} skyfix_t; + typedef struct plane_s { runtime_mapdata_header_t header; float height; // Current height @@ -104,7 +115,6 @@ typedef struct plane_s { struct sector_s* sector; // Owner of the plane (temp) float visheight; // Visible plane height (smoothed) float visoffset; - struct sector_s* linked; // Plane attached to another sector. } plane_t; // Helper macros for accessing sector floor/ceiling plane data elements. @@ -123,7 +133,6 @@ typedef struct plane_s { #define SP_ceiltexmove planes[PLN_CEILING]->surface.texmove #define SP_ceilsoundorg planes[PLN_CEILING]->soundorg #define SP_ceilvisheight planes[PLN_CEILING]->visheight -#define SP_ceillinked planes[PLN_CEILING]->linked #define SP_floorsurface planes[PLN_FLOOR]->surface #define SP_floorheight planes[PLN_FLOOR]->height @@ -140,7 +149,6 @@ typedef struct plane_s { #define SP_floortexmove planes[PLN_FLOOR]->surface.texmove #define SP_floorsoundorg planes[PLN_FLOOR]->soundorg #define SP_floorvisheight planes[PLN_FLOOR]->visheight -#define SP_floorlinked planes[PLN_FLOOR]->linked #define SECT_PLANE_HEIGHT(x, n) (x->planes[n]->visheight) @@ -153,6 +161,11 @@ typedef struct plane_s { #define SECF_INVIS_FLOOR 0x1 #define SECF_INVIS_CEILING 0x2 +typedef struct ssecgroup_s { + struct sector_s** linked; // [sector->planecount] size. + // Plane attached to another sector. +} ssecgroup_t; + typedef struct sector_s { runtime_mapdata_header_t header; short lightlevel; @@ -165,6 +178,8 @@ typedef struct sector_s { struct line_s** Lines; // [linecount] size. unsigned int subscount; struct subsector_s** subsectors; // [subscount] size. + unsigned int subsgroupcount; + ssecgroup_t* subsgroups; // [subsgroupcount] size. skyfix_t skyfix[2]; // floor, ceiling. degenmobj_t soundorg; float reverb[NUM_REVERB_DATA]; @@ -254,6 +269,8 @@ typedef struct side_s { #define L_frontside sides[FRONT] #define L_backside sides[BACK] +#define LINE_NEIGHBOR(line, side) (side? line->vo[side]->next->line : line->vo[side]->prev->line) + typedef struct line_s { runtime_mapdata_header_t header; struct vertex_s* v[2]; diff --git a/doomsday/engine/portable/include/r_data.h b/doomsday/engine/portable/include/r_data.h index 583016cd7c..9c24ccd966 100644 --- a/doomsday/engine/portable/include/r_data.h +++ b/doomsday/engine/portable/include/r_data.h @@ -186,6 +186,7 @@ typedef struct linkmobj_s { typedef struct shadowpoly_s { struct line_s *line; + struct subsector_s *ssec; short flags; ushort visframe; // Last visible frame (for rendering). struct vertex_s *outer[2]; // Left and right. diff --git a/doomsday/engine/portable/include/r_shadow.h b/doomsday/engine/portable/include/r_shadow.h index a97e095f0a..9662b249c5 100644 --- a/doomsday/engine/portable/include/r_shadow.h +++ b/doomsday/engine/portable/include/r_shadow.h @@ -31,6 +31,7 @@ void R_InitSectorShadows(void); line_t *R_GetShadowNeighbor(shadowpoly_t *poly, boolean left, boolean back); -sector_t *R_GetShadowSector(shadowpoly_t *poly); +sector_t *R_GetShadowSector(shadowpoly_t *poly, uint plane, + boolean getLinked); #endif diff --git a/doomsday/engine/portable/include/r_world.h b/doomsday/engine/portable/include/r_world.h index 57445d5a10..2a406f2b95 100644 --- a/doomsday/engine/portable/include/r_world.h +++ b/doomsday/engine/portable/include/r_world.h @@ -46,7 +46,7 @@ void R_SetupLevel(int mode, int flags); void R_InitLinks(void); void R_SetupFog(void); void R_SetupSky(void); -sector_t *R_GetLinkedSector(sector_t *startsec, uint plane); +sector_t *R_GetLinkedSector(subsector_t *startssec, uint plane); void R_UpdatePlanes(void); void R_ClearSectorFlags(void); void R_SkyFix(boolean fixFloors, boolean fixCeilings); diff --git a/doomsday/engine/portable/include/rend_fakeradio.h b/doomsday/engine/portable/include/rend_fakeradio.h index c649895758..2c21d03f3c 100644 --- a/doomsday/engine/portable/include/rend_fakeradio.h +++ b/doomsday/engine/portable/include/rend_fakeradio.h @@ -30,7 +30,7 @@ void Rend_RadioRegister(void); void Rend_RadioInitForFrame(void); -void Rend_RadioInitForSector(sector_t *sector); +void Rend_RadioInitForSubsector(subsector_t *sector); void Rend_RadioWallSection(const seg_t *seg, rendpoly_t *origQuad); void Rend_RadioSubsectorEdges(subsector_t *subsector); diff --git a/doomsday/engine/portable/include/rend_main.h b/doomsday/engine/portable/include/rend_main.h index 5156daa987..ff6d7d16c1 100644 --- a/doomsday/engine/portable/include/rend_main.h +++ b/doomsday/engine/portable/include/rend_main.h @@ -43,6 +43,7 @@ extern int missileBlend, litSprites; extern boolean usingFog; extern byte fogColor[4]; extern int r_ambient; +extern byte devNoLinkedSurfaces; extern signed short lightRangeModMatrix[MOD_RANGE][255]; diff --git a/doomsday/engine/portable/src/dam_main.c b/doomsday/engine/portable/src/dam_main.c index 77ecc85a75..7ece238c62 100644 --- a/doomsday/engine/portable/src/dam_main.c +++ b/doomsday/engine/portable/src/dam_main.c @@ -1836,6 +1836,7 @@ static void allocateMapData(gamemap_t *map) subsector_t *ssec = &map->subsectors[k]; ssec->header.type = DMU_SUBSECTOR; + ssec->group = 0; } // Nodes. @@ -2641,9 +2642,6 @@ static void finalizeMapData(gamemap_t *map) for(j = 0, seg = ss->firstseg; j < ss->segcount; ++j, seg++) if(seg->sidedef) { -#if _DEBUG -ASSERT_DMU_TYPE(seg->sidedef->sector, DMU_SECTOR); -#endif ss->sector = seg->sidedef->sector; ss->sector->subscount++; break; @@ -2710,6 +2708,12 @@ ASSERT_DMU_TYPE(seg->sidedef->sector, DMU_SECTOR); if(ssecsInSector[i] != sec->subscount) Con_Error("finalizeMapData: miscounted subsectors"); // Hmm? Unusual... + sec->subsgroupcount = 1; + sec->subsgroups = Z_Malloc(sizeof(ssecgroup_t) * sec->subsgroupcount, PU_LEVEL, 0); + sec->subsgroups[0].linked = Z_Malloc(sizeof(sector_t*) * sec->planecount, PU_LEVEL, 0); + for(k = 0; k < sec->planecount; ++k) + sec->subsgroups[0].linked[k] = NULL; + if(sec->linecount != 0) { M_ClearBox(bbox); @@ -2755,17 +2759,16 @@ ASSERT_DMU_TYPE(seg->sidedef->sector, DMU_SECTOR); sec->soundorg.pos[VZ] = FLT2FIX((sec->SP_ceilheight - sec->SP_floorheight) / 2); - // Set the position of the sound origin for all plane sound origins. + // Set the position of the sound origin for all plane sound origins + // and target heights of all planes. for(k = 0; k < sec->planecount; ++k) { sec->planes[k]->soundorg.pos[VX] = sec->soundorg.pos[VX]; sec->planes[k]->soundorg.pos[VY] = sec->soundorg.pos[VY]; sec->planes[k]->soundorg.pos[VZ] = FLT2FIX(sec->planes[k]->height); - } - // Set target heights of all planes. - for(k = 0; k < sec->planecount; ++k) sec->planes[k]->target = sec->planes[k]->height; + } } M_Free(linesInSector); diff --git a/doomsday/engine/portable/src/p_data.c b/doomsday/engine/portable/src/p_data.c index c22a34d643..0d5d97b581 100644 --- a/doomsday/engine/portable/src/p_data.c +++ b/doomsday/engine/portable/src/p_data.c @@ -174,9 +174,7 @@ void P_PlaneChanged(sector_t *sector, uint plane) back = sector->Lines[i]->sides[1]; if(!front || !front->sector || - front->sector->planes[plane]->linked || - !back || !back->sector || - back->sector->planes[plane]->linked) + !back || !back->sector) continue; // Do as in the original Doom if the texture has not been defined - diff --git a/doomsday/engine/portable/src/r_main.c b/doomsday/engine/portable/src/r_main.c index 08cb9977ef..549d817e0e 100644 --- a/doomsday/engine/portable/src/r_main.c +++ b/doomsday/engine/portable/src/r_main.c @@ -350,12 +350,7 @@ void R_NewSharpWorld(void) if(resetNextViewer) resetNextViewer = 2; -/* - if(useVSync) - gl.Enable(DGL_VSYNC); - else - gl.Disable(DGL_VSYNC); -*/ + R_GetSharpView(&sharpView, viewplayer); // Update the camera angles that will be used when the camera is @@ -386,12 +381,13 @@ void R_NewSharpWorld(void) plane->oldheight[0] = plane->oldheight[1]; plane->oldheight[1] = plane->height; - if(fabs(plane->oldheight[0] - plane->oldheight[1]) >= - MAX_SMOOTH_PLANE_MOVE) - { - // Too fast: make an instantaneous jump. - plane->oldheight[0] = plane->oldheight[1]; - } + if(plane->oldheight[0] != plane->oldheight[1]) + if(fabs(plane->oldheight[0] - plane->oldheight[1]) >= + MAX_SMOOTH_PLANE_MOVE) + { + // Too fast: make an instantaneous jump. + plane->oldheight[0] = plane->oldheight[1]; + } } } } @@ -448,15 +444,7 @@ void R_SetupWorldFrame(void) plane->height; // Visible plane height. - if(!plane->linked) - { - plane->visheight = plane->height + plane->visoffset; - } - else - { - plane->visheight = - R_GetLinkedSector(plane->linked, j)->planes[j]->height; - } + plane->visheight = plane->height + plane->visoffset; } } } diff --git a/doomsday/engine/portable/src/r_shadow.c b/doomsday/engine/portable/src/r_shadow.c index ab8d1ed628..999ae65dfa 100644 --- a/doomsday/engine/portable/src/r_shadow.c +++ b/doomsday/engine/portable/src/r_shadow.c @@ -57,6 +57,10 @@ typedef struct boundary_s { static zblockset_t *shadowLinksBlockSet; +static boundary_t *boundaries = NULL; +static byte *overlaps = NULL; +static uint boundaryNum; + // CODE -------------------------------------------------------------------- /** @@ -150,8 +154,10 @@ line_t *R_GetShadowNeighbor(shadowpoly_t *poly, boolean left, boolean back) /** * Returns a pointer to the sector the shadow polygon belongs in. */ -sector_t *R_GetShadowSector(shadowpoly_t *poly) +sector_t *R_GetShadowSector(shadowpoly_t *poly, uint pln, boolean getLinked) { + if(getLinked) + return R_GetLinkedSector(poly->ssec, pln); return (poly->line->sec[poly->flags & SHPF_FRONTSIDE ? FRONT : BACK]); } @@ -171,7 +177,7 @@ sector_t *R_GetShadowProximity(shadowpoly_t *poly, boolean left) boolean R_ShadowCornerDeltas(pvec2_t left, pvec2_t right, shadowpoly_t *poly, boolean leftCorner, boolean back) { - sector_t *sector = R_GetShadowSector(poly); + sector_t *sector = R_GetShadowSector(poly, 0, false); line_t *neighbor; // The line itself. @@ -397,24 +403,22 @@ boolean R_ResolveStep(const pvec2_t outer, const pvec2_t inner, pvec2_t offset) return iterCont; } -/* - * 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. +/** + * 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. */ -void R_ResolveOverlaps(shadowpoly_t *polys, int count, sector_t *sector) +void R_ResolveOverlaps(shadowpoly_t *polys, uint count, sector_t *sector) { #define OVERLAP_LEFT 0x01 #define OVERLAP_RIGHT 0x02 #define OVERLAP_ALL (OVERLAP_LEFT | OVERLAP_RIGHT) #define EPSILON .01f boolean done; - int i, tries; - uint k; - boundary_t *boundaries, *bound; //, *other; - byte *overlaps; + int tries; + uint i, k; + boundary_t *bound; //, *other; float s, t; vec2_t a, b; line_t *line; @@ -423,8 +427,13 @@ void R_ResolveOverlaps(shadowpoly_t *polys, int count, sector_t *sector) if(!count) return; - boundaries = M_Malloc(sizeof(*boundaries) * count); - overlaps = M_Malloc(count); + // Need to enlarge the boundry+overlap buffers? + if(count > boundaryNum) + { + boundaries = M_Realloc(boundaries, sizeof(*boundaries) * count); + overlaps = M_Realloc(overlaps, count); + boundaryNum = count; + } // We don't want to stay here forever. done = false; @@ -497,9 +506,6 @@ void R_ResolveOverlaps(shadowpoly_t *polys, int count, sector_t *sector) } } } - - M_Free(boundaries); - M_Free(overlaps); } /** @@ -508,49 +514,71 @@ void R_ResolveOverlaps(shadowpoly_t *polys, int count, sector_t *sector) */ uint R_MakeShadowEdges(shadowpoly_t *storage) { - uint i, j, counter; + uint i, j, k, counter; sector_t *sector; line_t *line; side_t *side; + subsector_t *ssec; + seg_t *seg; boolean frontside; shadowpoly_t *poly, *sectorFirst, *allocator = storage; + if(allocator) + boundaryNum = 0; + for(i = 0, counter = 0; i < numsectors; ++i) { sector = SECTOR_PTR(i); sectorFirst = allocator; - // Iterate all the lines of the sector. - for(j = 0; j < sector->linecount; ++j) + // Use validcount to make sure we only allocate one shadowpoly + // per line, side. + ++validcount; + + // Iterate all the subsectors of the sector. + for(j = 0; j < sector->subscount; ++j) { - line = sector->Lines[j]; - frontside = (line->L_frontsector == sector); - side = line->sides[frontside ? FRONT:BACK]; + ssec = sector->subsectors[j]; + // Iterate all the segs of the subsector. + for(k = 0, seg = ssec->firstseg; k < ssec->segcount; ++k, seg++) + { + if(!seg->linedef) + continue; // minisegs don't get shadows. - // If the line hasn't got two neighbors, it won't get a - // shadow. - if(!side || !side->neighbor[0] || !side->neighbor[1]) - continue; + line = seg->linedef; + if(line->validcount == validcount) + continue; // already has a shadow poly. - // This side will get a shadow. Increment counter (we'll - // return this count). - counter++; + frontside = (line->L_frontsector == sector); + side = line->sides[frontside ? FRONT:BACK]; - if(!allocator) - continue; + // If the line hasn't got two neighbors, it won't get a + // shadow. + if(!side || !side->neighbor[0] || !side->neighbor[1]) + continue; - // Get a new shadow poly. - poly = allocator++; + // This side will get a shadow. Increment counter (we'll + // return this count). + counter++; + line->validcount = validcount; - poly->line = line; - poly->flags = (frontside ? SHPF_FRONTSIDE : 0); - poly->visframe = framecount - 1; + if(!allocator) + continue; - // The outer vertices are just the beginning and end of - // the line. - R_OrderVertices(line, sector, poly->outer); + // Get a new shadow poly. + poly = allocator++; - R_ShadowEdges(poly); + poly->line = line; + poly->ssec = ssec; + poly->flags = (frontside ? SHPF_FRONTSIDE : 0); + poly->visframe = framecount - 1; + + // The outer vertices are just the beginning and end of + // the line. + R_OrderVertices(line, sector, poly->outer); + + R_ShadowEdges(poly); + } } if(allocator) @@ -560,6 +588,21 @@ uint R_MakeShadowEdges(shadowpoly_t *storage) R_ResolveOverlaps(sectorFirst, allocator - sectorFirst, sector); } } + + // If we have resolved overlaps; free tempoary storage used in process. + if(allocator) + { + if(boundaries) + { + M_Free(boundaries); + boundaries = NULL; + } + if(overlaps) + { + M_Free(overlaps); + overlaps = NULL; + } + } return counter; } @@ -579,7 +622,7 @@ void R_InitSectorShadows(void) maxCount = R_MakeShadowEdges(NULL); // Allocate just enough memory. - shadows = Z_Calloc(sizeof(shadowpoly_t) * maxCount, PU_LEVEL, NULL); + shadows = Z_Calloc(sizeof(shadowpoly_t) * maxCount, PU_LEVELSTATIC, NULL); VERBOSE(Con_Printf("R_InitSectorShadows: %i shadowpolys.\n", maxCount)); // This'll make 'em for real. @@ -614,7 +657,7 @@ void R_InitSectorShadows(void) V2_Sum(point, point, poly->extoffset[1]); V2_AddToBox(bounds, point); - P_SubsectorBoxIteratorv(bounds, R_GetShadowSector(poly), + P_SubsectorBoxIteratorv(bounds, R_GetShadowSector(poly, 0, false), RIT_ShadowSubsectorLinker, poly); } diff --git a/doomsday/engine/portable/src/r_world.c b/doomsday/engine/portable/src/r_world.c index f6be3163ce..d6546d2857 100644 --- a/doomsday/engine/portable/src/r_world.c +++ b/doomsday/engine/portable/src/r_world.c @@ -65,7 +65,7 @@ typedef struct { // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- static void R_PrepareSubsector(subsector_t *sub); -static void R_FindLineNeighbors(sector_t *sector, line_t *line, +static void R_FindLineNeighbors(sector_t *sector, line_t *line, int side, struct line_s **neighbors, int alignment); // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- @@ -100,33 +100,6 @@ static float mapBounds[4]; # pragma optimize("g", off) #endif -/** - * We mustn't create links which form loops. This will start looking - * from destlink, and if it finds startsec we're in trouble. - */ -static boolean R_IsValidLink(sector_t *startsec, sector_t *destlink, - int plane) -{ - sector_t *sec = destlink; - sector_t *link; - - for(;;) - { - // Advance to the linked sector. - if(!sec->planes[plane]->linked) - break; - link = sec->planes[plane]->linked; - - // Is there an illegal linkage? - if(sec == link || startsec == link) - return false; - sec = link; - } - - // No problems encountered. - return true; -} - /** * Called whenever the sector changes. * @@ -139,12 +112,15 @@ static boolean R_IsValidLink(sector_t *startsec, sector_t *destlink, */ static void R_SetSectorLinks(sector_t *sec) { - uint k; + uint i, j, k; sector_t *back; line_t *lin; boolean hackfloor, hackceil; side_t *sid, *frontsid, *backsid; sector_t *floorlink_candidate = 0, *ceillink_candidate = 0; + seg_t *seg; + subsector_t *sub; + ssecgroup_t *ssgrp; // Must have a valid sector! if(!sec || !sec->linecount || sec->permanentlink) @@ -152,93 +128,117 @@ static void R_SetSectorLinks(sector_t *sec) hackfloor = (!R_IsSkySurface(&sec->SP_floorsurface)); hackceil = (!R_IsSkySurface(&sec->SP_ceilsurface)); - for(k = 0; k < sec->linecount; ++k) + if(hackfloor || hackceil) + for(i = 0; i < sec->subsgroupcount; ++i) { - lin = sec->Lines[k]; if(!hackfloor && !hackceil) break; - // We are only interested in two-sided lines. - if(!(lin->L_frontsector && lin->L_backsector)) - continue; - // Check the vertex line owners for both verts. - // We are only interested in lines that do NOT share either vertex - // with a one-sided line (ie, its not "anchored"). - if(lin->L_v1->anchored || lin->L_v2->anchored) - return; - - // Check which way the line is facing. - sid = lin->L_frontside; - if(sid->sector == sec) + ssgrp = &sec->subsgroups[i]; + for(k = 0; k < sec->subscount; ++k) { - frontsid = sid; - backsid = lin->L_backside; - } - else - { - frontsid = lin->L_backside; - backsid = sid; - } - back = backsid->sector; - if(back == sec) - return; - - // Check that there is something on the other side. - if(back->SP_ceilheight == back->SP_floorheight) - return; - // Check the conditions that prevent the invis plane. - if(back->SP_floorheight == sec->SP_floorheight) - { - hackfloor = false; + if(!hackfloor && !hackceil) + break; + + sub = sec->subsectors[k]; + // Must be in the same group. + if(sub->group != i) + continue; + + for(j = 0, seg = sub->firstseg; j < sub->segcount; ++j, seg++) + { + if(!hackfloor && !hackceil) + break; + + lin = seg->linedef; + + if(!lin) + continue; // minisegs don't count. + + // We are only interested in two-sided lines. + if(!(lin->L_frontsector && lin->L_backsector)) + continue; + + // Check the vertex line owners for both verts. + // We are only interested in lines that do NOT share either vertex + // with a one-sided line (ie, its not "anchored"). + if(lin->L_v1->anchored || lin->L_v2->anchored) + return; + + // Check which way the line is facing. + sid = lin->L_frontside; + if(sid->sector == sec) + { + frontsid = sid; + backsid = lin->L_backside; + } + else + { + frontsid = lin->L_backside; + backsid = sid; + } + back = backsid->sector; + if(back == sec) + return; + + // Check that there is something on the other side. + if(back->SP_ceilheight == back->SP_floorheight) + return; + // Check the conditions that prevent the invis plane. + if(back->SP_floorheight == sec->SP_floorheight) + { + hackfloor = false; + } + else + { + if(back->SP_floorheight > sec->SP_floorheight) + sid = frontsid; + else + sid = backsid; + + if((sid->SW_bottompic && !(sid->SW_bottomflags & SUF_TEXFIX)) || + (sid->SW_middlepic && !(sid->SW_middleflags & SUF_TEXFIX))) + hackfloor = false; + else + floorlink_candidate = back; + } + + if(back->SP_ceilheight == sec->SP_ceilheight) + hackceil = false; + else + { + if(back->SP_ceilheight < sec->SP_ceilheight) + sid = frontsid; + else + sid = backsid; + + if((sid->SW_toppic && !(sid->SW_topflags & SUF_TEXFIX)) || + (sid->SW_middlepic && !(sid->SW_middleflags & SUF_TEXFIX))) + hackceil = false; + else + ceillink_candidate = back; + } + } } - else + if(hackfloor) { - if(back->SP_floorheight > sec->SP_floorheight) - sid = frontsid; - else - sid = backsid; + if(floorlink_candidate == sec->containsector) + ssgrp->linked[PLN_FLOOR] = floorlink_candidate; - if((sid->SW_bottompic && !(sid->SW_bottomflags & SUF_TEXFIX)) || - (sid->SW_middlepic && !(sid->SW_middleflags & SUF_TEXFIX))) - hackfloor = false; - else if(R_IsValidLink(sec, back, PLN_FLOOR)) - floorlink_candidate = back; + /* if(floorlink_candidate) + Con_Printf("LF:%i->%i\n", + i, GET_SECTOR_IDX(floorlink_candidate)); */ } - - if(back->SP_ceilheight == sec->SP_ceilheight) - hackceil = false; - else + if(hackceil) { - if(back->SP_ceilheight < sec->SP_ceilheight) - sid = frontsid; - else - sid = backsid; + if(ceillink_candidate == sec->containsector) + ssgrp->linked[PLN_CEILING] = ceillink_candidate; - if((sid->SW_toppic && !(sid->SW_topflags & SUF_TEXFIX)) || - (sid->SW_middlepic && !(sid->SW_middleflags & SUF_TEXFIX))) - hackceil = false; - else if(R_IsValidLink(sec, back, PLN_CEILING)) - ceillink_candidate = back; + /* if(ceillink_candidate) + Con_Printf("LC:%i->%i\n", + i, GET_SECTOR_IDX(ceillink_candidate)); */ } } - if(hackfloor) - { - if(floorlink_candidate == sec->containsector) - sec->planes[PLN_FLOOR]->linked = floorlink_candidate; - - /* if(floorlink_candidate) - Con_Printf("LF:%i->%i\n", - i, GET_SECTOR_IDX(floorlink_candidate)); */ - } - if(hackceil) - { - if(ceillink_candidate == sec->containsector) - sec->planes[PLN_CEILING]->linked = ceillink_candidate; - - /* if(ceillink_candidate) - Con_Printf("LC:%i->%i\n", - i, GET_SECTOR_IDX(ceillink_candidate)); */ - } } #ifdef MSVC @@ -616,7 +616,7 @@ static fvertex_t *edgeClipper(uint *numpoints, fvertex_t *points, for(k = 0; k < num; ++k) { - int startIdx = k, endIdx = k + 1; + uint startIdx = k, endIdx = k + 1; // Check the end index. if(endIdx == num) @@ -1111,9 +1111,9 @@ static void R_SetVertexSectorOwner(vertex_t *vtx, ownerlist_t *ownerList, * Generates an array of sector references for each vertex. The list * includes all the sectors the vertex belongs to. * - * Generates an array of line references for each vertex. The list - * includes all the lines the vertex belongs to sorted by angle. - * (the list is arranged in clockwise order, east = 0). + * Generates an array of line references for each vertex. The list includes + * all the lines the vertex belongs to sorted by angle, (the list is + * arranged in clockwise order, east = 0). */ static void R_BuildVertexOwners(void) { @@ -1125,8 +1125,7 @@ static void R_BuildVertexOwners(void) ownerlist_t *vtxSecOwnerLists; // Allocate memory for vertex sector owner processing. - vtxSecOwnerLists = M_Malloc(sizeof(ownerlist_t) * numvertexes); - memset(vtxSecOwnerLists, 0, sizeof(ownerlist_t) * numvertexes); + vtxSecOwnerLists = M_Calloc(sizeof(ownerlist_t) * numvertexes); for(i = 0, sec = sectors; i < numsectors; ++i, sec++) { @@ -1149,8 +1148,8 @@ static void R_BuildVertexOwners(void) } } - // Now "harden" the sector owner linked lists into arrays and free as we go. - // We also need to sort line owners and then finish the rings. + // Now "harden" the sector owner linked lists into arrays and free as + // we go. Also need to sort line owners and then finish the rings. for(i = 0; i < numvertexes; ++i) { vertex_t *v = VERTEX_PTR(i); @@ -1185,8 +1184,8 @@ static void R_BuildVertexOwners(void) sortLineOwners(v->lineowners, lineAngleSorter); // Finish the linking job - // They are only singly linked atm, we need them to be doubly and - // circularly linked. + // They are only singly linked atm, we need them to be doubly + // and circularly linked. last = v->lineowners; p = last->next; while(p) @@ -1199,20 +1198,21 @@ static void R_BuildVertexOwners(void) v->lineowners->prev = last; #if _DEBUG +if(verbose >= 2) { // For checking the line owner link rings are formed correctly. lineowner_t *base; uint idx; -VERBOSE2( Con_Message("Vertex #%i: line owners #%i\n", i, v->numlineowners) ); +Con_Message("Vertex #%i: line owners #%i\n", i, v->numlineowners); p = base = v->lineowners; idx = 0; do { - VERBOSE2( Con_Message(" %i: p = %i, this = %i, n = %i\n", idx, - GET_LINE_IDX(p->prev->line), - GET_LINE_IDX(p->line), - GET_LINE_IDX(p->next->line)) ); + Con_Message(" %i: p = %i, this = %i, n = %i\n", idx, + GET_LINE_IDX(p->prev->line), + GET_LINE_IDX(p->line), + GET_LINE_IDX(p->next->line)); p = p->next; idx++; } while(p != base); @@ -1384,8 +1384,14 @@ static void R_BuildSectorLinks(void) // Link all planes permanently. sec->permanentlink = true; // Only floor and ceiling can be linked, not all planes inbetween. - sec->SP_floorlinked = sec->containsector; - sec->SP_ceillinked = sec->containsector; + for(k = 0; k < sec->subsgroupcount; ++k) + { + ssecgroup_t *ssgrp = &sec->subsgroups[k]; + uint p; + + for(p = 0; p < sec->planecount; ++p) + ssgrp->linked[p] = sec->containsector; + } Con_Printf("Linking S%i planes permanently to S%i\n", i, GET_SECTOR_IDX(sec->containsector)); @@ -1434,7 +1440,7 @@ static void R_InitPlaneIllumination(subsector_t *sub, uint planeid) } } -static void R_InitPlanePolys(subsector_t *subsector) +static void R_InitSubsectorPoly(subsector_t *subsector) { uint numvrts, i; fvertex_t *vrts, *vtx, *pv; @@ -1480,15 +1486,6 @@ static void R_InitPlanePolys(subsector_t *subsector) // Re-add the first vertex so the triangle fan wraps around. memcpy(pv, &subsector->vertices[1], sizeof(*pv)); } - - // Initialize the illumination for the subsector. - for(i = 0; i < subsector->sector->planecount; ++i) - R_InitPlaneIllumination(subsector, i); - - // FIXME: $nplanes - // Initialize the plane types. - subsector->planes[PLN_FLOOR]->type = PLN_FLOOR; - subsector->planes[PLN_CEILING]->type = PLN_CEILING; } static void R_BuildSubsectorPolys(void) @@ -1504,12 +1501,23 @@ static void R_BuildSubsectorPolys(void) { sub = SUBSECTOR_PTR(i); - sub->planes = Z_Malloc(sub->sector->planecount * sizeof(subplaneinfo_t*), - PU_LEVEL, NULL); + R_InitSubsectorPoly(sub); + + sub->planes = + Z_Malloc(sub->sector->planecount * sizeof(subplaneinfo_t*), + PU_LEVEL, NULL); for(k = 0; k < sub->sector->planecount; ++k) - sub->planes[k] = Z_Calloc(sizeof(subplaneinfo_t), PU_LEVEL, NULL); + { + sub->planes[k] = + Z_Calloc(sizeof(subplaneinfo_t), PU_LEVEL, NULL); - R_InitPlanePolys(sub); + // Initialize the illumination for the subsector. + R_InitPlaneIllumination(sub, k); + } + // FIXME: $nplanes + // Initialize the plane types. + sub->planes[PLN_FLOOR]->type = PLN_FLOOR; + sub->planes[PLN_CEILING]->type = PLN_CEILING; } #ifdef _DEBUG @@ -1677,6 +1685,10 @@ void R_RationalizeSectors(void) // Mark this sector as a self-referencing hack. sec->selfRefHack = true; + // We'll use validcount to ensure we only attempt to find + // each hack group once. + ++validcount; + // Now look for lines connected to this root line (and any // subsequent lines that connect to those) that match the // requirements for a selfreferencing hack. @@ -1690,7 +1702,7 @@ void R_RationalizeSectors(void) if(!lin->selfrefhackroot) continue; - if(lin->validcount) + if(lin->validcount == validcount) continue; // We've already found this hack group. for(l = 0; l < 2; ++l) @@ -1780,7 +1792,7 @@ void R_RationalizeSectors(void) if(!found) p2 = p2->next; - } while(!found && p2 != base); + } while(!found && p2 != base2); } if(!found) @@ -1811,7 +1823,7 @@ void R_RationalizeSectors(void) GET_SECTOR_IDX(sec))); // Use validcount to mark them as done. - collectedLines[o]->validcount = true; + collectedLines[o]->validcount = validcount; } // We are done with this group, don't collect. @@ -1990,9 +2002,9 @@ void R_SetupSky(void) } /** - * Returns pointers to the line's vertices in such a fashion that - * verts[0] is the leftmost vertex and verts[1] is the rightmost - * vertex, when the line lies at the edge of `sector.' + * Returns pointers to the line's vertices in such a fashion that verts[0] + * is the leftmost vertex and verts[1] is the rightmost vertex, when the + * line lies at the edge of `sector.' */ void R_OrderVertices(line_t *line, const sector_t *sector, vertex_t *verts[2]) { @@ -2009,94 +2021,67 @@ void R_OrderVertices(line_t *line, const sector_t *sector, vertex_t *verts[2]) } /** - * A neighbour is a line that shares a vertex with 'line', and faces - * the specified sector. Finds both the left and right neighbours. + * A neighbour is a line that shares a vertex with 'line', and faces the + * specified sector. */ -static void R_FindLineNeighbors(sector_t *sector, line_t *line, - line_t **neighbors, int alignment) +line_t *R_FindLineNeighbor(sector_t *sector, line_t *line, lineowner_t *own, + boolean antiClockwise) { - uint j; - line_t *other; - vertex_t *vtx[2]; + lineowner_t *cown = antiClockwise? own->prev : own->next; + line_t *other = cown->line; - // We want to know which vertex is the leftmost/rightmost one. - R_OrderVertices(line, sector, vtx); + if(other == line) + return NULL; - // Find the real neighbours, which are in the same sector - // as this line. - for(j = 0; j < sector->linecount; ++j) + if((other->L_frontsector == sector || + (other->L_backsector && other->L_backsector == sector)) && + other->L_frontsector != other->L_backsector) { - other = sector->Lines[j]; - if(other == line) - continue; - - // Is this a valid neighbour? - if(other->L_frontsector == other->L_backsector) - continue; - - // Do we need to test the line alignment? - if(alignment) - { -#define SEP 10 - binangle_t diff = line->angle - other->angle; - - /*if(!(diff < SEP && diff > BANG_MAX - SEP) && - !(diff < BANG_180 + SEP && diff > BANG_180 - SEP)) - continue; // Misaligned. */ - - if(alignment < 0) - diff -= BANG_180; - if(other->L_frontsector != sector) - diff -= BANG_180; - if(!(diff < SEP || diff > BANG_MAX - SEP)) - continue; // Misaligned. - } - - // It's our 'left' neighbour if it shares v1. - if(other->v[0] == vtx[0] || other->v[1] == vtx[0]) - neighbors[0] = other; - - // It's our 'right' neighbour if it shares v2. - if(other->v[0] == vtx[1] || other->v[1] == vtx[1]) - neighbors[1] = other; - - // Do we have everything we want? - if(neighbors[0] && neighbors[1]) - break; + return other; } -} -static boolean R_IsEquivalent(line_t *a, line_t *b) -{ - return ((a->v[0] == b->v[0] && a->v[1] == b->v[1]) || - (a->v[0] == b->v[1] && a->v[1] == b->v[0])); + // Not suitable, try the next. + return R_FindLineNeighbor(sector, line, cown, antiClockwise); } /** - * Browse through the lines in backSector. The backNeighbor is the - * line that 1) isn't realNeighbor and 2) connects to commonVertex. + * A side's alignneighbor is a line that shares a vertex with 'line' and + * whos orientation is aligned with it (thus, making it unnecessary to have + * a shadow between them. In practice, they would be considered a single, + * long sidedef by the shadow generator). */ -static void R_FindBackNeighbor(sector_t *backSector, line_t *self, - line_t *realNeighbor, vertex_t *commonVertex, - line_t **backNeighbor) +line_t *R_FindLineAlignNeighbor(sector_t *sec, line_t *line, + lineowner_t *own, boolean antiClockwise, + int alignment) { - uint i; - line_t *line; +#define SEP 10 + lineowner_t *cown = antiClockwise? own->prev : own->next; + line_t *other = cown->line; + binangle_t diff; + uint candIDX = GET_LINE_IDX(other); + + if(other == line) + return NULL; - for(i = 0; i < backSector->linecount; ++i) + if(!(other->L_backsector && + other->L_backsector == other->L_frontsector)) { - line = backSector->Lines[i]; - if(R_IsEquivalent(line, realNeighbor) || R_IsEquivalent(line, self)) - continue; - if(line->selfrefhackroot) - continue; + diff = line->angle - other->angle; - if(line->L_v1 == commonVertex || line->L_v2 == commonVertex) - { - *backNeighbor = line; - return; - } + if(alignment < 0) + diff -= BANG_180; + if(other->L_frontsector != sec) + diff -= BANG_180; + if(diff < SEP || diff > BANG_MAX - SEP) + return other; } + + // Can't step over non-twosided lines. + if(!other->L_backsector || !other->L_frontsector) + return NULL; + + // Not suitable, try the next. + return R_FindLineAlignNeighbor(sec, line, cown, antiClockwise, alignment); } /** @@ -2106,11 +2091,11 @@ void R_InitLineNeighbors(void) { uint startTime = Sys_GetRealTime(); - uint i, k, j, m; + uint i, k, j, m, sid; line_t *line, *other; sector_t *sector; side_t *side; - vertex_t *vertices[2], *vtx; + vertex_t *vtx; // Find neighbours. We'll do this sector by sector. for(k = 0; k < numsectors; ++k) @@ -2121,107 +2106,98 @@ void R_InitLineNeighbors(void) line = sector->Lines[i]; // Which side is this? - side = line->sides[line->L_frontsector == sector? FRONT:BACK]; - - R_FindLineNeighbors(sector, line, side->neighbor, 0); - - R_OrderVertices(line, sector, vertices); + sid = (line->L_frontsector == sector? FRONT:BACK); + side = line->sides[sid]; - // Figure out the sectors in the proximity. for(j = 0; j < 2; ++j) { + side->neighbor[j] = + R_FindLineNeighbor(sector, line, line->vo[sid^j], j); + + // Figure out the sectors in the proximity. // Neighbour must be two-sided. if(side->neighbor[j] && side->neighbor[j]->L_frontsector && side->neighbor[j]->L_backsector && !side->neighbor[j]->selfrefhackroot) { - side->proxsector[j] = - side->neighbor[j]->sec[side->neighbor[j]->L_frontsector == sector ? BACK:FRONT]; + int nSide = + (side->neighbor[j]->L_frontsector == sector ? BACK:FRONT); + + side->proxsector[j] = side->neighbor[j]->sec[nSide]; // Find the backneighbour. They are the // neighbouring lines in the backsectors of the // neighbour lines. - R_FindBackNeighbor(side->proxsector[j], line, - side->neighbor[j], vertices[j], - &side->backneighbor[j]); -/* -#if _DEBUG -assert(side->backneighbor[j] != line); -#endif -*/ + side->backneighbor[j] = + R_FindLineNeighbor(side->proxsector[j], + side->neighbor[j], + side->neighbor[j]->vo[nSide^j], + j); } else { side->proxsector[j] = NULL; } - } - // Look for aligned neighbours. They are side-specific. - for(j = 0; j < 2; ++j) - { - vtx = vertices[j]; - for(m = 0; m < vtx->numsecowners; ++m) - { - R_FindLineNeighbors(SECTOR_PTR(vtx->secowners[m]), line, - side->alignneighbor, - (side == line->L_frontside? 1:-1)); - } + // Look for aligned neighbours. They are side-specific. + side->alignneighbor[j] = + R_FindLineAlignNeighbor(sector, line, line->vo[sid^j], j, + (side == line->L_frontside? 1:-1)); + // Alignneighbors can't be backneighbors. + if(side->alignneighbor[j] == side->backneighbor[j]) + side->alignneighbor[j] = NULL; } - // Attempt to find "pretend" neighbors for this line, if "real" + // Attempt to find "pretend" neighbours for this line, if "real" // ones have not been found. - // NOTE: selfrefhackroot lines don't have neighbors. - // They can only be "pretend" neighbors. + // NOTE: selfrefhackroot lines don't have neighbours. + // They can only be "pretend" neighbours. - // Pretend neighbors are selfrefhackroot lines but BOTH vertices + // Pretend neighbours are selfrefhackroot lines but BOTH vertices // are owned by this sector and ONE of the vertexes is owned by // this line. if((!side->neighbor[0] || !side->neighbor[1]) && !line->selfrefhackroot) { - boolean ok, ok2; - // Check all lines. - for(j = 0; j < numlines; ++j) + uint v; + boolean done, ok; + lineowner_t *own; + + for(j = 0; j < 2; ++j) { - other = LINE_PTR(j); - if(other->selfrefhackroot && - (other->L_v1 == line->L_v1 || other->L_v1 == line->L_v2 || - other->L_v2 == line->L_v1 || other->L_v2 == line->L_v2)) + if(!side->neighbor[j]) { - ok = ok2 = false; - vtx = other->L_v1; - for(m = 0; m < vtx->numsecowners && !ok; ++m) - if(vtx->secowners[m] == k) // k == sector id - ok = true; - - if(ok) - { - vtx = other->L_v2; - for(m = 0; m < vtx->numsecowners && !ok2; ++m) - if(vtx->secowners[m] == k) // k == sector id - ok2 = true; - } - - if(ok && ok2) + own = line->vo[sid^j]; + done = false; + do { -#if _DEBUG -VERBOSE2(Con_Message("L%i is a pretend neighbor to L%i\n", - GET_LINE_IDX(other), GET_LINE_IDX(line))); -#endif - - if(other->v[0] == vertices[0] || - other->v[1] == vertices[0]) - { - side->neighbor[0] = other; - side->pretendneighbor[0] = true; - } - else + other = own->line; + if(other->selfrefhackroot && + (other->L_v1 == line->L_v1 || other->L_v1 == line->L_v2 || + other->L_v2 == line->L_v1 || other->L_v2 == line->L_v2)) { - side->neighbor[1] = other; - side->pretendneighbor[1] = true; + for(v = 0; v < 2; ++v) + { + ok = false; + vtx = other->v[v]; + for(m = 0; m < vtx->numsecowners && !ok; ++m) + if(vtx->secowners[m] == k) // k == sector id + ok = true; + if(!ok) + break; + } + + if(ok) + { + side->neighbor[j] = other; + side->pretendneighbor[j] = true; + done = true; + } } - } + + own = own->next; + } while(own->line != line && !done); } } } @@ -2245,12 +2221,17 @@ if(verbose >= 1) continue; side = line->sides[k]; + if(side->alignneighbor[0] || side->alignneighbor[1]) Con_Printf("Line %i/%i: l=%i r=%i\n", i, k, (side->alignneighbor[0] ? GET_LINE_IDX(side->alignneighbor[0]) : -1), (side->alignneighbor[1] ? GET_LINE_IDX(side->alignneighbor[1]) : -1)); + + if(side->neighbor[k] && side->pretendneighbor[k]) + Con_Printf(" has a pretend neighbor, line %i\n", + GET_LINE_IDX(side->neighbor[k])); } } } @@ -2565,28 +2546,14 @@ void R_ClearSectorFlags(void) } } -sector_t *R_GetLinkedSector(sector_t *startsec, uint plane) +sector_t *R_GetLinkedSector(subsector_t *startssec, uint plane) { - sector_t *sec = startsec; - sector_t *link; - - for(;;) - { - if(!sec->planes[plane]->linked) - return sec; - link = sec->planes[plane]->linked; + ssecgroup_t *ssgrp = &startssec->sector->subsgroups[startssec->group]; -#ifdef _DEBUG - if(sec == link || startsec == link) - { - Con_Error("R_GetLinkedSector: linked to self! (%s)\n", - (plane == PLN_FLOOR ? "flr" : - plane == PLN_CEILING ? "ceil" : "mid")); - return startsec; - } -#endif - sec = link; - } + if(!devNoLinkedSurfaces && ssgrp->linked[plane]) + return ssgrp->linked[plane]; + else + return startssec->sector; } void R_UpdateAllSurfaces(boolean forceUpdate) @@ -2819,8 +2786,13 @@ void R_UpdateSector(sector_t* sec, boolean forceUpdate) if(!sec->permanentlink) // Assign new links { // Only floor and ceiling can be linked, not all inbetween - sec->SP_floorlinked = NULL; - sec->SP_ceillinked = NULL; + for(i = 0; i < sec->subsgroupcount; ++i) + { + ssecgroup_t *ssgrp = &sec->subsgroups[i]; + + ssgrp->linked[PLN_FLOOR] = NULL; + ssgrp->linked[PLN_CEILING] = NULL; + } R_SetSectorLinks(sec); } } diff --git a/doomsday/engine/portable/src/rend_dyn.c b/doomsday/engine/portable/src/rend_dyn.c index cc907cbe98..395e9957cc 100644 --- a/doomsday/engine/portable/src/rend_dyn.c +++ b/doomsday/engine/portable/src/rend_dyn.c @@ -437,7 +437,7 @@ static boolean DL_SegTexCoords(float *t, float top, float bottom, /** * The front sector must be given because of polyobjs. */ -static void DL_ProcessWallSeg(lumobj_t *lum, seg_t *seg, sector_t *frontsec) +static void DL_ProcessWallSeg(lumobj_t *lum, seg_t *seg, subsector_t *ssec) { #define SMIDDLE 0x1 #define STOP 0x2 @@ -453,9 +453,12 @@ static void DL_ProcessWallSeg(lumobj_t *lum, seg_t *seg, sector_t *frontsec) uint segindex = GET_SEG_IDX(seg); boolean backSide = false; DGLubyte lumRGB[3]; + sector_t *frontsec = ssec->sector, *linkSec; - fceil = frontsec->SP_ceilvisheight; - ffloor = frontsec->SP_floorvisheight; + linkSec = R_GetLinkedSector(ssec, PLN_CEILING); + fceil = linkSec->SP_ceilvisheight; + linkSec = R_GetLinkedSector(ssec, PLN_FLOOR); + ffloor = linkSec->SP_floorvisheight; // A zero-volume sector? if(fceil <= ffloor) @@ -1498,14 +1501,14 @@ static boolean DL_LightSegIteratorFunc(lumobj_t *lum, subsector_t *ssec) for(j = 0, seg = ssec->firstseg; j < ssec->segcount; ++j, seg++) { if(seg->linedef) // "minisegs" have no linedefs. - DL_ProcessWallSeg(lum, seg, ssec->sector); + DL_ProcessWallSeg(lum, seg, ssec); } // Is there a polyobj on board? Light it, too. if(ssec->poly) for(j = 0; j < ssec->poly->numsegs; ++j) { - DL_ProcessWallSeg(lum, ssec->poly->segs[j], ssec->sector); + DL_ProcessWallSeg(lum, ssec->poly->segs[j], ssec); } return true; @@ -1537,7 +1540,7 @@ void DL_ProcessSubsector(subsector_t *ssec) uint num, ssecidx = GET_SUBSECTOR_IDX(ssec); seg_t *seg; lumcontact_t *con; - sector_t *sect = ssec->sector; + sector_t *sect = ssec->sector, *linkSec; planeitervars_t *pVars; // Do we need to enlarge the planeVars buffer? @@ -1574,7 +1577,8 @@ void DL_ProcessSubsector(subsector_t *ssec) num = sect->planecount; for(pln = 0, pVars = planeVars; pln < num; pVars++, ++pln) { - pVars->height = SECT_PLANE_HEIGHT(sect, pln); + linkSec = R_GetLinkedSector(ssec, pln); + pVars->height = SECT_PLANE_HEIGHT(linkSec, pln); pVars->isLit = (!R_IsSkySurface(§->planes[pln]->surface)); pVars->decorMap = 0; diff --git a/doomsday/engine/portable/src/rend_fakeradio.c b/doomsday/engine/portable/src/rend_fakeradio.c index dcf9534b7c..70b28db3ef 100644 --- a/doomsday/engine/portable/src/rend_fakeradio.c +++ b/doomsday/engine/portable/src/rend_fakeradio.c @@ -132,9 +132,10 @@ void Rend_RadioInitForFrame(void) * Before calling the other rendering routines, this must be called to * initialize the state of the FakeRadio renderer. */ -void Rend_RadioInitForSector(sector_t *sector) +void Rend_RadioInitForSubsector(subsector_t *ssec) { - int sectorlight = sector->lightlevel; + sector_t *linkSec; + int sectorlight = ssec->sector->lightlevel; Rend_ApplyLightAdaptation(§orlight); @@ -148,13 +149,15 @@ void Rend_RadioInitForSector(sector_t *sector) return; // No point drawing shadows in a PITCH black sector. // Visible plane heights. - fFloor = sector->SP_floorvisheight; - fCeil = sector->SP_ceilvisheight; + linkSec = R_GetLinkedSector(ssec, PLN_FLOOR); + fFloor = linkSec->SP_floorvisheight; + linkSec = R_GetLinkedSector(ssec, PLN_CEILING); + fCeil = linkSec->SP_ceilvisheight; if(fCeil <= fFloor) return; // A closed sector. - frontSector = sector; + frontSector = ssec->sector; // Determine the shadow properties. // FIXME: Make cvars out of constants. @@ -320,7 +323,7 @@ static float Rend_RadioLineCorner(line_t *self, line_t *other, // The corner between the walls faces outwards. return -1; } - else if(diff == 180) + else if(diff == BANG_180) { return 0; } @@ -726,7 +729,8 @@ void Rend_RadioWallSection(const seg_t *seg, rendpoly_t *origQuad) spans[i].length = seg->linedef->length; spans[i].shift = seg->offset; } - + //if(GET_LINE_IDX(seg->linedef) == 128) + // Con_Message("found\n"); Rend_RadioScanEdges(topCn, botCn, sideCn, seg->linedef, sideNum, spans); // Back sector visible plane heights. @@ -1153,76 +1157,75 @@ void Rend_RadioWallSection(const seg_t *seg, rendpoly_t *origQuad) * openness value of one means that the other edge is at the same height as * this one. 2 means that the other edge is past our height ("clearly open"). */ -static float Rend_RadioEdgeOpenness(line_t *line, int backside, - boolean isCeiling) +static float radioEdgeOpenness(float fz, float bz, float bhz) { - sector_t *front = line->sec[backside]; - sector_t *back = line->sec[backside ^ 1]; - side_t *fside; - float fz, bhz, bz; // Front and back Z height + if(fz <= bz - EDGE_OPEN_THRESHOLD || fz >= bhz) + return 0; // Fully closed. - if(!back) - return 0; // No backsector, this is a one-sided wall. + if(fz >= bhz - EDGE_OPEN_THRESHOLD) + return (bhz - fz) / EDGE_OPEN_THRESHOLD; - fside = line->sides[backside]; + if(fz <= bz) + return 1 - (bz - fz) / EDGE_OPEN_THRESHOLD; - if(isCeiling) - { - fz = -front->SP_ceilvisheight; - bz = -back->SP_ceilvisheight; - bhz = -back->SP_floorvisheight; + if(fz <= bz + EDGE_OPEN_THRESHOLD) + return 1 + (fz - bz) / EDGE_OPEN_THRESHOLD; + + // Fully open! + return 2; +} - if(fz < bz && fside->SW_toppic == 0) - return 2; // Consider it fully open. +static void setRelativeHeights(sector_t *front, sector_t *back, + boolean isCeiling, + float *fz, float *bz, float *bhz) +{ + if(fz) + { + *fz = front->planes[isCeiling? PLN_CEILING:PLN_FLOOR]->visheight; + if(isCeiling) + *fz = -(*fz); } - else + if(bz) { - fz = front->SP_floorvisheight; - bz = back->SP_floorvisheight; - bhz = back->SP_ceilvisheight; - - // If theres a missing texture and the visible heights are - // different - never consider this edge for a plane shadow. - // TODO: does not consider any replacements we might make in - // Rend_RenderWallSeg to fix the missing texture... - if(fz < bz && fside->SW_bottompic == 0) - return 2; // Consider it fully open. + *bz = back->planes[isCeiling? PLN_CEILING:PLN_FLOOR]->visheight; + if(isCeiling) + *bz = -(*bz); } - - // Is the back sector closed? - if(back->SP_floorvisheight >= back->SP_ceilvisheight) + if(bhz) { - if((!isCeiling && - R_IsSkySurface(&front->SP_ceilsurface) && - R_IsSkySurface(&back->SP_ceilsurface)) || - (isCeiling && - R_IsSkySurface(&front->SP_floorsurface) && - R_IsSkySurface(&back->SP_floorsurface))) - return 2; // Consider it fully open. - else - return 0; + *bhz = back->planes[isCeiling? PLN_FLOOR:PLN_CEILING]->visheight; + if(isCeiling) + *bhz = -(*bhz); } +} - if(fz <= bz - EDGE_OPEN_THRESHOLD || fz >= bhz) - return 0; // Fully closed. +static uint radioEdgeHackType(line_t *line, sector_t *front, sector_t *back, + int backside, boolean isCeiling, float fz, + float bz) +{ + surface_t *surface = &line->sides[backside? BACK:FRONT]-> + sections[isCeiling? SEG_TOP:SEG_BOTTOM]; + + if(fz < bz && surface->texture == 0 && !(surface->flags & SUF_TEXFIX)) + return 3; // Consider it fully open. + + // Is the back sector closed? + if(front->SP_floorvisheight >= back->SP_ceilvisheight) + if(R_IsSkySurface(&front->planes[isCeiling? PLN_FLOOR:PLN_CEILING]->surface)) + { + if(R_IsSkySurface(&back->planes[isCeiling? PLN_FLOOR:PLN_CEILING]->surface)) + return 3; // Consider it fully open. + } + else + return 1; // Consider it fully closed. // Check for unmasked midtextures on twosided lines that completely // fill the gap between floor and ceiling (we don't want to give away // the location of any secret areas (false walls)). if(Rend_DoesMidTextureFillGap(line, backside)) - return 0; + return 1; // Consider it fully closed. - if(fz >= bhz - EDGE_OPEN_THRESHOLD) - return (bhz - fz) / EDGE_OPEN_THRESHOLD; - - if(fz <= bz) - return 1 - (bz - fz) / EDGE_OPEN_THRESHOLD; - - if(fz <= bz + EDGE_OPEN_THRESHOLD) - return 1 + (fz - bz) / EDGE_OPEN_THRESHOLD; - - // Fully open! - return 2; + return 0; } /** @@ -1230,21 +1233,18 @@ static float Rend_RadioEdgeOpenness(line_t *line, int backside, * rendering lists. */ static void Rend_RadioAddShadowEdge(shadowpoly_t *shadow, boolean isCeiling, - float darkness, float sideOpen[2]) + float darkness, float sideOpen[2], float z) { rendpoly_t *q; rendpoly_vertex_t *vtx; - sector_t *sector; - float z, pos; - uint i, *idx; - uint floorIndices[] = { 0, 1, 2, 3 }; - uint ceilIndices[] = { 0, 3, 2, 1 }; - vec2_t inner[2]; - - // This is the sector the shadow is actually in. - sector = shadow->line->sec[shadow->flags & SHPF_FRONTSIDE ? FRONT:BACK]; - - z = sector->planes[isCeiling]->visheight; + float pos; + uint i; + // Winding: 0 = left, 1 = right + uint wind; + const uint *idx; + 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}}; + vec2_t inner[2]; // Sector lightlevel affects the darkness of the shadows. if(darkness > 1) @@ -1260,22 +1260,27 @@ static void Rend_RadioAddShadowEdge(shadowpoly_t *shadow, boolean isCeiling, { /*V2_Lerp(inner[i], shadow->inoffset[i], shadow->bextoffset[i], pos);*/ - V2_Copy(inner[i], shadow->inoffset[i]); + V2_Sum(inner[i], shadow->outer[i]->pos, shadow->inoffset[i]); } else if(pos == 1) // Same height on both sides. { - V2_Copy(inner[i], shadow->bextoffset[i]); + V2_Sum(inner[i], shadow->outer[i]->pos, shadow->bextoffset[i]); } else // Fully, unquestionably open. { if(pos > 2) pos = 2; /*V2_Lerp(inner[i], shadow->bextoffset[i], shadow->extoffset[i], pos - 1); */ - V2_Copy(inner[i], shadow->extoffset[i]); + V2_Sum(inner[i], shadow->outer[i]->pos, shadow->extoffset[i]); } } - // Initialize the rendpoly. + // What vertex winding order? + // (for best results, the cross edge should always be the shortest). + wind = (V2_Distance(inner[1], shadow->outer[1]->pos) > + V2_Distance(inner[0], shadow->outer[0]->pos)? 1 : 0); + + // Initialize the rendpoly. q = R_AllocRendPoly(RP_FLAT, false, 4); q->flags = RPF_SHADOW; memset(&q->tex, 0, sizeof(q->tex)); @@ -1286,7 +1291,7 @@ static void Rend_RadioAddShadowEdge(shadowpoly_t *shadow, boolean isCeiling, memset(q->vertices, 0, q->numvertices * sizeof(rendpoly_vertex_t)); vtx = q->vertices; - idx = (isCeiling ? ceilIndices : floorIndices); + idx = (isCeiling ? ceilIndices[wind] : floorIndices[wind]); // Left outer corner. vtx[idx[0]].pos[VX] = shadow->outer[0]->pos[VX]; @@ -1307,13 +1312,13 @@ static void Rend_RadioAddShadowEdge(shadowpoly_t *shadow, boolean isCeiling, vtx[idx[1]].color.rgba[CA] *= 1 - sideOpen[1]; // Right inner corner. - vtx[idx[2]].pos[VX] = vtx[idx[1]].pos[VX] + inner[1][VX]; - vtx[idx[2]].pos[VY] = vtx[idx[1]].pos[VY] + inner[1][VY]; + vtx[idx[2]].pos[VX] = inner[1][VX]; + vtx[idx[2]].pos[VY] = inner[1][VY]; vtx[idx[2]].pos[VZ] = z; // Left inner corner. - vtx[idx[3]].pos[VX] = vtx[idx[0]].pos[VX] + inner[0][VX]; - vtx[idx[3]].pos[VY] = vtx[idx[0]].pos[VY] + inner[0][VY]; + vtx[idx[3]].pos[VX] = inner[0][VX]; + vtx[idx[3]].pos[VY] = inner[0][VY]; vtx[idx[3]].pos[VZ] = z; RL_AddPoly(q); @@ -1329,14 +1334,14 @@ static void Rend_RadioAddShadowEdge(shadowpoly_t *shadow, boolean isCeiling, */ void Rend_RadioSubsectorEdges(subsector_t *subsector) { + uint i, pln, hack, side; + float open, sideOpen[2], vec[3]; + float fz, bz, bhz, plnHeight; + sector_t *shadowSec, *front, *back; + line_t *line; + surface_t *suf; shadowlink_t *link; shadowpoly_t *shadow; - sector_t *sector; - line_t *neighbor; - float open, sideOpen[2]; - int i; - uint pln; - float vec[3]; if(!rendFakeRadio || levelFullBright) return; @@ -1360,42 +1365,86 @@ BEGIN_PROF( PROF_RADIO_SUBSECTOR ); // neighbours cause some changes in the polygon corner // vertices (placement, colour). - sector = R_GetShadowSector(shadow); - vec[VX] = vx - subsector->midpoint.pos[VX]; vec[VY] = vz - subsector->midpoint.pos[VY]; for(pln = 0; pln < subsector->sector->planecount; ++pln) { - vec[VZ] = vy - SECT_PLANE_HEIGHT(subsector->sector, pln); + suf = &subsector->sector->planes[pln]->surface; + + shadowSec = R_GetShadowSector(shadow, pln, true); + plnHeight = SECT_PLANE_HEIGHT(shadowSec, pln); + vec[VZ] = vy - plnHeight; // Glowing surfaces or missing textures shouldn't have shadows. - if((subsector->sector->planes[pln]->surface.flags & SUF_NO_RADIO) || + if((suf->flags & SUF_NO_RADIO) || !Rend_RadioNonGlowingFlat(subsector->sector, pln)) continue; // Don't bother with planes facing away from the camera. - if(M_DotProduct(vec, subsector->sector->planes[pln]->surface.normal) < 0) + if(M_DotProduct(vec, suf->normal) < 0) continue; - open = - Rend_RadioEdgeOpenness(shadow->line, - (shadow->flags & SHPF_FRONTSIDE) == 0, - pln); + line = shadow->line; + if(line->L_backsector) + { + side = (shadow->flags & SHPF_FRONTSIDE) == 0; + if(subsector->sector->subsgroups[subsector->group].linked[pln]) + { + if(side == 0) + { + front = shadowSec; + back = line->sec[side ^ 1]; + } + else + { + front = line->sec[side]; + back = shadowSec; + } + } + else + { + front = line->sec[side]; + back = line->sec[side ^ 1]; + } + setRelativeHeights(front, back, pln, &fz, &bz, &bhz); + + hack = + radioEdgeHackType(line, front, back, side, pln, fz, bz); + if(hack) + open = hack - 1; + else + open = radioEdgeOpenness(fz, bz, bhz); + } + else + open = 0; + if(open >= 1) continue; // What about the neighbours? for(i = 0; i < 2; ++i) { - neighbor = R_GetShadowNeighbor(shadow, i == 0, false); - sideOpen[i] = - Rend_RadioEdgeOpenness(neighbor, - neighbor->L_frontsector != sector, - pln); + line = R_GetShadowNeighbor(shadow, i == 0, false); + if(line->L_backsector) + { + side = (line->L_frontsector != shadowSec); + front = line->sec[side]; + back = line->sec[side ^ 1]; + setRelativeHeights(front, back, pln, &fz, &bz, &bhz); + + hack = radioEdgeHackType(line, front, back, side, pln, fz, bz); + if(hack) + sideOpen[i] = hack - 1; + else + sideOpen[i] = radioEdgeOpenness(fz, bz, bhz); + } + else + sideOpen[i] = 0; } - Rend_RadioAddShadowEdge(shadow, pln, 1 - open, sideOpen); + Rend_RadioAddShadowEdge(shadow, pln, 1 - open, sideOpen, + plnHeight); } } diff --git a/doomsday/engine/portable/src/rend_main.c b/doomsday/engine/portable/src/rend_main.c index 6aa5bfe7f0..e3bbf35436 100644 --- a/doomsday/engine/portable/src/rend_main.c +++ b/doomsday/engine/portable/src/rend_main.c @@ -141,7 +141,8 @@ static byte bottomColor[3]; // Current sector light color. const byte *sLightColor; -static byte devNoTexFix = 0; +byte devNoTexFix = 0; +byte devNoLinkedSurfaces = 0; // CODE -------------------------------------------------------------------- @@ -172,6 +173,7 @@ void Rend_Register(void) C_VAR_INT("rend-dev-light-modmatrix", &debugLightModMatrix, CVF_NO_ARCHIVE, 0, 1); C_VAR_BYTE("rend-dev-tex-showfix", &devNoTexFix, 0, 0, 1); + C_VAR_BYTE("rend-dev-surface-linked", &devNoLinkedSurfaces, 0, 0, 1); RL_Register(); DL_Register(); @@ -1104,7 +1106,7 @@ static void Rend_SetSurfaceColorsForSide(side_t *side) /** * Renders the given single-sided seg into the world. */ -static void Rend_RenderSSWallSeg(seg_t *seg, sector_t *frontsec) +static void Rend_RenderSSWallSeg(seg_t *seg, subsector_t *ssec) { int surfaceFlags; surface_t *surface; @@ -1114,6 +1116,7 @@ static void Rend_RenderSSWallSeg(seg_t *seg, sector_t *frontsec) rendpoly_t *quad; float *vBL, *vBR, *vTL, *vTR; boolean backSide = true; + sector_t *frontsec = ssec->sector, *fflinkSec, *fclinkSec; sid = seg->linedef->sides[0]; backsid = seg->linedef->sides[1]; @@ -1129,8 +1132,10 @@ static void Rend_RenderSSWallSeg(seg_t *seg, sector_t *frontsec) else side = backsid; - ffloor = frontsec->SP_floorvisheight; - fceil = frontsec->SP_ceilvisheight; + fflinkSec = R_GetLinkedSector(ssec, PLN_FLOOR); + ffloor = fflinkSec->SP_floorvisheight; + fclinkSec = R_GetLinkedSector(ssec, PLN_CEILING); + fceil = fclinkSec->SP_ceilvisheight; fsh = fceil - ffloor; // Init the quad. @@ -1219,7 +1224,7 @@ static void Rend_RenderSSWallSeg(seg_t *seg, sector_t *frontsec) /** * Renders wall sections for given two-sided seg. */ -static void Rend_RenderWallSeg(seg_t *seg, sector_t *frontsec) +static void Rend_RenderWallSeg(seg_t *seg, subsector_t *ssec) { int surfaceFlags; int solidSeg = false; // -1 means NEVER. @@ -1231,6 +1236,7 @@ static void Rend_RenderWallSeg(seg_t *seg, sector_t *frontsec) rendpoly_t *quad; float *vBL, *vBR, *vTL, *vTR; boolean backSide = true; + sector_t *frontsec = ssec->sector, *fflinkSec, *fclinkSec; backsec = seg->SG_backsector; sid = seg->linedef->sides[0]; @@ -1252,8 +1258,10 @@ static void Rend_RenderWallSeg(seg_t *seg, sector_t *frontsec) side->SW_middlepic == 0) return; // Ugh... an obvious wall seg hack. Best take no chances... - ffloor = frontsec->SP_floorvisheight; - fceil = frontsec->SP_ceilvisheight; + fflinkSec = R_GetLinkedSector(ssec, PLN_FLOOR); + ffloor = fflinkSec->SP_floorvisheight; + fclinkSec = R_GetLinkedSector(ssec, PLN_CEILING); + fceil = fclinkSec->SP_ceilvisheight; fsh = fceil - ffloor; bceil = backsec->SP_ceilvisheight; @@ -1858,7 +1866,7 @@ static void Rend_OccludeSubsector(subsector_t *sub, boolean forward_facing) static void Rend_RenderPlane(subplaneinfo_t *plane, subsector_t *subsector) { - sector_t *sector = subsector->sector, *link = NULL; + sector_t *sector = subsector->sector; int surfaceFlags; float height; surface_t *surface; @@ -1866,27 +1874,11 @@ static void Rend_RenderPlane(subplaneinfo_t *plane, subsector_t *subsector) int flags; sector_t *polySector; - // Determine the height of the plane. - if(splane->linked) - { - polySector = link = - R_GetLinkedSector(splane->linked, plane->type); - - height = SECT_PLANE_HEIGHT(link, plane->type); - // Add the skyfix - height += link->skyfix[plane->type].offset; - - surface = &link->planes[plane->type]->surface; - } - else - { - polySector = sector; - height = splane->visheight; - // Add the skyfix - height += sector->skyfix[plane->type].offset; - - surface = §or->planes[plane->type]->surface; - } + polySector = R_GetLinkedSector(subsector, plane->type); + height = SECT_PLANE_HEIGHT(polySector, plane->type); + // Add the skyfix + height += polySector->skyfix[plane->type].offset; + surface = &polySector->planes[plane->type]->surface; // We don't render planes for unclosed sectors when the polys would // be added to the skymask (a DOOM.EXE renderer hack). @@ -1971,16 +1963,16 @@ static void Rend_RenderSubsector(uint ssecidx) // Retrieve the sector light color. sLightColor = R_GetSectorLightColor(sect); + Rend_MarkSegsFacingFront(ssec); + // Dynamic lights. if(useDynLights) DL_ProcessSubsector(ssec); // Prepare for FakeRadio. - Rend_RadioInitForSector(sect); + Rend_RadioInitForSubsector(ssec); Rend_RadioSubsectorEdges(ssec); - Rend_MarkSegsFacingFront(ssec); - Rend_OccludeSubsector(ssec, false); DL_ClipInSubsector(ssecidx); Rend_OccludeSubsector(ssec, true); @@ -2015,9 +2007,9 @@ static void Rend_RenderSubsector(uint ssecidx) if(seg->frameflags & SEGINF_FACINGFRONT) { if(!seg->SG_backsector || !seg->SG_frontsector) - Rend_RenderSSWallSeg(seg, sect); + Rend_RenderSSWallSeg(seg, ssec); else - Rend_RenderWallSeg(seg, sect); + Rend_RenderWallSeg(seg, ssec); } } @@ -2030,7 +2022,7 @@ static void Rend_RenderSubsector(uint ssecidx) // Let's first check which way this seg is facing. if(seg->frameflags & SEGINF_FACINGFRONT) - Rend_RenderSSWallSeg(seg, sect); + Rend_RenderSSWallSeg(seg, ssec); } }