diff --git a/doomsday/engine/api/doomsday.def b/doomsday/engine/api/doomsday.def index c30f4d3bdf..7037e31b18 100644 --- a/doomsday/engine/api/doomsday.def +++ b/doomsday/engine/api/doomsday.def @@ -153,7 +153,7 @@ EXPORTS P_AccurateDistance @57 NONAME P_ApproxDistance @58 NONAME P_ApproxDistance3 @243 NONAME - P_PointOnLineSide @59 NONAME + P_PointOnLinedefSide @59 NONAME P_BoxOnLineSide @60 NONAME P_MakeDivline @61 NONAME P_PointOnDivlineSide @62 NONAME diff --git a/doomsday/engine/api/doomsday.h b/doomsday/engine/api/doomsday.h index 4e9cb29801..723ae76cb3 100644 --- a/doomsday/engine/api/doomsday.h +++ b/doomsday/engine/api/doomsday.h @@ -143,7 +143,7 @@ extern "C" { void B_FormEventString(char *buff, evtype_t type, evstate_t state, int data1); int B_BindingsForCommand(const char *cmd, char *buf, int bufSize); - int B_BindingsForControl(int localPlayer, const char *controlName, char *buf, + int B_BindingsForControl(int localPlayer, const char *controlName, char *buf, int bufSize); void DD_AddBindClass(struct bindclass_s *); boolean DD_SetBindClass(unsigned int classID, int type); @@ -209,7 +209,7 @@ extern "C" { float P_AccurateDistance(float dx, float dy); float P_ApproxDistance(float dx, float dy); float P_ApproxDistance3(float dx, float dy, float dz); - int P_PointOnLineSide(float x, float y, + int P_PointOnLinedefSide(float x, float y, struct linedef_s *line); int P_BoxOnLineSide(float *tmbox, struct linedef_s *ld); void P_MakeDivline(struct linedef_s *li, divline_t *dl); diff --git a/doomsday/engine/data/cphelp.txt b/doomsday/engine/data/cphelp.txt index 0508c56d31..f66715368b 100644 --- a/doomsday/engine/data/cphelp.txt +++ b/doomsday/engine/data/cphelp.txt @@ -642,6 +642,9 @@ desc = Dynamic lights color blending mode: 0=normal, 1=additive, 2=no blending. [rend-light-bright] desc = Intensity factor for dynamic lights. +[rend-light-fog-bright] +desc = Brightness of dynamic lights when fog is enabled. + [rend-light-num] desc = The maximum number of dynamic lights. 0=no limit. @@ -687,8 +690,6 @@ desc = Max height of wall glow (default: 100). [rend-glow-scale] desc = A multiplier for glow height (default: 1). -[rend-glow-fog-bright] -desc = Brightness of wall glow when fog is enabled. [rend-halo] desc = Number of flares to draw per light. diff --git a/doomsday/engine/defs/flags.ded b/doomsday/engine/defs/flags.ded index 5136d41245..1d50894672 100644 --- a/doomsday/engine/defs/flags.ded +++ b/doomsday/engine/defs/flags.ded @@ -31,8 +31,8 @@ Flag { # Allow using decoration with external resources. } # Lights -Flag { ID = "lgf_nohalo"; Value = 0x100; } -Flag { ID = "lgf_dontturnhalo"; Value = 0x200; } +Flag { ID = "lgf_nohalo"; Value = 0x1; } +Flag { ID = "lgf_dontturnhalo"; Value = 0x2; } # Map Info Flag { ID = "mif_fog"; Value = 0x1; } diff --git a/doomsday/engine/portable/include/m_vector.h b/doomsday/engine/portable/include/m_vector.h index 1c3d14fbce..cded085e22 100644 --- a/doomsday/engine/portable/include/m_vector.h +++ b/doomsday/engine/portable/include/m_vector.h @@ -4,7 +4,7 @@ * Online License Link: http://www.gnu.org/licenses/gpl.html * *\author Copyright © 2004-2008 Jaakko Keränen - *\author Copyright © 2006-2007 Daniel Swanson + *\author Copyright © 2006-2008 Daniel Swanson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,7 +22,7 @@ * Boston, MA 02110-1301 USA */ -/* +/** * m_vector.h: Vector Math */ @@ -48,22 +48,22 @@ void V2_Scale(pvec2_t vector, float scalar); void V2_Rotate(pvec2_t vec, float radians); void V2_Sum(pvec2_t dest, const pvec2_t src1, const pvec2_t src2); void V2_Subtract(pvec2_t dest, const pvec2_t src1, - const pvec2_t src2); + const pvec2_t src2); float V2_DotProduct(const pvec2_t a, const pvec2_t b); float V2_ScalarProject(const pvec2_t a, const pvec2_t b); void V2_Project(pvec2_t dest, const pvec2_t a, const pvec2_t b); boolean V2_IsParallel(const pvec2_t a, const pvec2_t b); boolean V2_IsZero(const pvec2_t vec); float V2_Intersection(const pvec2_t p1, const pvec2_t delta1, - const pvec2_t p2, const pvec2_t delta2, - pvec2_t point); + const pvec2_t p2, const pvec2_t delta2, + pvec2_t point); float V2_Intercept(const pvec2_t a, const pvec2_t b, const pvec2_t c, - const pvec2_t d, pvec2_t point); + const pvec2_t d, pvec2_t point); boolean V2_Intercept2(const pvec2_t a, const pvec2_t b, - const pvec2_t c, const pvec2_t d, pvec2_t point, - float *abFrac, float *cdFrac); + const pvec2_t c, const pvec2_t d, pvec2_t point, + float *abFrac, float *cdFrac); void V2_Lerp(pvec2_t dest, const pvec2_t a, const pvec2_t b, - float c); + float c); void V2_InitBox(arvec2_t box, const pvec2_t point); void V2_AddToBox(arvec2_t box, const pvec2_t point); @@ -88,6 +88,7 @@ float V3_ClosestPointOnPlane(pvec3_t dest, const pvec3_t planeNormal, const pvec3_t planePoint, const pvec3_t arbPoint); +int V3_MajorAxis(const pvec3_t vec); boolean V3_IsZero(const pvec3_t vec); void V3_Lerp(pvec3_t dest, const pvec3_t a, const pvec3_t b, float c); diff --git a/doomsday/engine/portable/include/mapdata.hs b/doomsday/engine/portable/include/mapdata.hs index 8a283f1095..11ed7fcabf 100644 --- a/doomsday/engine/portable/include/mapdata.hs +++ b/doomsday/engine/portable/include/mapdata.hs @@ -107,19 +107,21 @@ end struct subsector UINT uint segCount - PTR seg_s** segs // [segcount] size. - PTR polyobj_s* polyObj // NULL, if there is no polyobj. + PTR seg_s** segs // [segcount] size. + PTR polyobj_s* polyObj // NULL, if there is no polyobj. PTR sector_s* sector - uint inSectorID - int flags - int validCount - uint group - uint[NUM_REVERB_DATA] reverb - - fvertex_t bBox[2] // Min and max points. - - fvertex_t midPoint // Center of vertices. + - fvertex_t bBox[2] // Min and max points. + - float[2] worldGridOffset // Offset to align the top left of the bBox to the world grid. + - fvertex_t midPoint // Center of vertices. - ushort numVertices - - fvertex_s** vertices // [numvertices] size + - fvertex_s** vertices // [numvertices] size - shadowlink_s* shadows + end public diff --git a/doomsday/engine/portable/include/p_maptypes.h b/doomsday/engine/portable/include/p_maptypes.h index dead67acd6..9d627c8047 100644 --- a/doomsday/engine/portable/include/p_maptypes.h +++ b/doomsday/engine/portable/include/p_maptypes.h @@ -109,6 +109,7 @@ typedef struct subsector_s { unsigned int group; unsigned int reverb[NUM_REVERB_DATA]; fvertex_t bBox[2]; // Min and max points. + float worldGridOffset[2]; // Offset to align the top left of the bBox to the world grid. fvertex_t midPoint; // Center of vertices. unsigned short numVertices; struct fvertex_s** vertices; // [numvertices] size diff --git a/doomsday/engine/portable/include/p_maputil.h b/doomsday/engine/portable/include/p_maputil.h index f08f1b96b4..a32dc9ea66 100644 --- a/doomsday/engine/portable/include/p_maputil.h +++ b/doomsday/engine/portable/include/p_maputil.h @@ -47,8 +47,8 @@ float P_ApproxDistance3(float dx, float dy, float dz); void P_LineUnitVector(linedef_t *line, float *unitvec); float P_MobjPointDistancef(mobj_t *start, mobj_t *end, float *fixpoint); -int P_PointOnLineSide(float x, float y, linedef_t *line); -int P_PointOnLineSide2(double pointX, double pointY, +int P_PointOnLinedefSide(float x, float y, linedef_t *line); +int P_PointOnLinedefSide2(double pointX, double pointY, double lineDX, double lineDY, double linePerp, double lineLength, double epsilon); @@ -62,7 +62,7 @@ int P_BoxOnLineSide3(const int bbox[4], double lineSX, void P_MakeDivline(linedef_t *li, divline_t *dl); int P_PointOnDivlineSide(float x, float y, divline_t *line); float P_InterceptVector(divline_t *v2, divline_t *v1); -int P_FloatPointOnLineSide(fvertex_t *pnt, fdivline_t *dline); +int P_PointOnDivLineSidef(fvertex_t *pnt, fdivline_t *dline); float P_FloatInterceptVertex(fvertex_t *start, fvertex_t *end, fdivline_t *fdiv, fvertex_t *inter); void P_LineOpening(linedef_t *linedef); diff --git a/doomsday/engine/portable/include/r_data.h b/doomsday/engine/portable/include/r_data.h index 255e66f55b..a223c5b0d9 100644 --- a/doomsday/engine/portable/include/r_data.h +++ b/doomsday/engine/portable/include/r_data.h @@ -91,7 +91,7 @@ typedef struct walldiv_s { typedef struct rendpoly_wall_s { float length; - walldiv_t divs[2]; // For wall segments (two vertices). + walldiv_t divs[2]; // For wall segments (two vertices). } rendpoly_wall_t; // rendpoly_params_t is only for convenience; the data written in the rendering @@ -99,15 +99,16 @@ typedef struct rendpoly_wall_s { typedef struct rendpoly_params_s { boolean isWall; rendpolytype_t type; - short flags; // RPF_*. - float texOffset[2]; // Texture coordinates for left/top - // (in real texcoords). + short flags; // RPF_*. + float texOrigin[2][3]; // Used in texture coordinate calculation. + float texOffset[2]; // Texture coordinates for left/top + // (in real texcoords). gltexture_t tex; gltexture_t interTex; - float interPos; // Blending strength (0..1). - uint lightListIdx; // List of lights that affect this poly. - blendmode_t blendMode; // Primitive-specific blending mode. - rendpoly_wall_t* wall; // Wall specific data if any. + float interPos; // Blending strength (0..1). + uint lightListIdx; // List of lights that affect this poly. + blendmode_t blendMode; // Primitive-specific blending mode. + rendpoly_wall_t* wall; // Wall specific data if any. } rendpoly_params_t; // This is the dummy mobj_t used for blockring roots. diff --git a/doomsday/engine/portable/include/r_lumobjs.h b/doomsday/engine/portable/include/r_lumobjs.h index c7ed00f20a..c544b2728b 100644 --- a/doomsday/engine/portable/include/r_lumobjs.h +++ b/doomsday/engine/portable/include/r_lumobjs.h @@ -32,45 +32,49 @@ // Lumobj Flags. #define LUMF_USED 0x1 #define LUMF_RENDERED 0x2 -#define LUMF_CLIPPED 0x4 // Hidden by world geometry. -#define LUMF_NOHALO 0x100 -#define LUMF_DONTTURNHALO 0x200 +#define LUMF_CLIPPED 0x4 // Hidden by world geometry. + +// lumobj, omni flags +#define LUMOF_NOHALO 0x1 +#define LUMOF_DONTTURNHALO 0x2 // Lumobject types. typedef enum { - LT_OMNI, // Omni (spherical) light. - LT_PLANE // Planar light. + LT_OMNI, // Omni (spherical) light. + LT_PLANE, // Planar light. } lumtype_t; // Helper macros for accessing lum data. #define LUM_OMNI(x) (&((x)->data.omni)) #define LUM_PLANE(x) (&((x)->data.plane)) -typedef struct lumobj_s { // For dynamic lighting. +typedef struct lumobj_s { lumtype_t type; - int flags; // LUMF_* flags. - float pos[3]; // Center of the light. - float color[3]; + int flags; // LUMF_* flags. + float pos[3]; // Center of the obj. float distanceToViewer; subsector_t *subsector; union lumobj_data_u { struct lumobj_omni_s { - int radius; // Radius for this omnilight source. - float zOff; // Offset to center from pos[VZ]. - DGLuint tex; // Lightmap texture. - DGLuint floorTex, ceilTex; // Lightmaps for floor/ceil. + int flags; // LUMOF_* flags. + float color[3]; + int radius; // Radius for this omnilight source. + float zOff; // Offset to center from pos[VZ]. + DGLuint tex; // Lightmap texture. + DGLuint floorTex, ceilTex; // Lightmaps for floor/ceil. // For flares (halos). int flareSize; byte haloFactor; float xOff; - DGLuint flareTex; // Flaremap if flareCustom ELSE (flaretexName id. - // Zero = automatical) - boolean flareCustom; // True id flareTex is a custom flare graphic - float flareMul; // Flare brightness factor. + DGLuint flareTex; // Flaremap if flareCustom ELSE (flaretexName id. + // Zero = automatical) + boolean flareCustom; // True id flareTex is a custom flare graphic + float flareMul; // Flare brightness factor. } omni; struct lumobj_plane_s { + float color[3]; float intensity; DGLuint tex; float normal[3]; @@ -117,5 +121,7 @@ boolean LO_LumobjsRadiusIterator(subsector_t *subsector, float x, float void LO_ClipInSubsector(uint ssecidx); void LO_ClipBySight(uint ssecidx); +#if _DEBUG void LO_DrawLumobjs(void); #endif +#endif diff --git a/doomsday/engine/portable/include/rend_dyn.h b/doomsday/engine/portable/include/rend_dyn.h index fc0cd952fa..1e362bc2d1 100644 --- a/doomsday/engine/portable/include/rend_dyn.h +++ b/doomsday/engine/portable/include/rend_dyn.h @@ -4,7 +4,7 @@ * Online License Link: http://www.gnu.org/licenses/gpl.html * *\author Copyright © 2003-2008 Jaakko Keränen - *\author Copyright © 2006-2007 Daniel Swanson + *\author Copyright © 2006-2008 Daniel Swanson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,9 +32,9 @@ #include "p_object.h" #include "rend_list.h" -#define DYN_ASPECT 1.1f // 1.2f is just too round for Doom. +#define DYN_ASPECT (1.1f) // 1.2f is just too round for Doom. -#define MAX_GLOWHEIGHT 1024.0f // Absolute max glow height +#define MAX_GLOWHEIGHT (1024.0f) // Absolute max glow height. /** * The data of a projected dynamic light is stored in this structure. @@ -47,11 +47,10 @@ typedef struct dynlight_s { DGLuint texture; } dynlight_t; -extern int useDynLights, dlBlend; -extern float dlFactor; -extern int useWallGlow, glowHeightMax; -extern float glowHeightFactor; -extern float glowFogBright; +extern int useDynLights, dlBlend; +extern float dlFactor, dlFogBright; +extern int useWallGlow, glowHeightMax; +extern float glowHeightFactor; // Initialization void DL_Register(void); @@ -61,12 +60,12 @@ void DL_InitForMap(void); void DL_InitForNewFrame(void); // Action. -uint DL_ProcessSegSection(seg_t *seg, float bottom, float top, +uint DL_ProcessSegSection(seg_t* seg, float bottom, float top, boolean sortBrightestFirst); -uint DL_ProcessSubSectorPlane(subsector_t *subsector, uint plane); +uint DL_ProcessSubSectorPlane(subsector_t* ssec, uint plane); // Helpers. -boolean DL_ListIterator(uint listIdx, void *data, - boolean (*func) (const dynlight_t *, void *data)); +boolean DL_ListIterator(uint listIdx, void* data, + boolean (*func) (const dynlight_t*, void*)); #endif diff --git a/doomsday/engine/portable/src/bsp_node.c b/doomsday/engine/portable/src/bsp_node.c index 3199133e02..5c9a2b471b 100644 --- a/doomsday/engine/portable/src/bsp_node.c +++ b/doomsday/engine/portable/src/bsp_node.c @@ -80,7 +80,7 @@ static hedge_t **hEdgeSortBuf; static __inline int pointOnHEdgeSide(double x, double y, const hedge_t *part) { - return P_PointOnLineSide2(x, y, part->pDX, part->pDY, part->pPerp, + return P_PointOnLinedefSide2(x, y, part->pDX, part->pDY, part->pPerp, part->pLength, DIST_EPSILON); } diff --git a/doomsday/engine/portable/src/edit_map.c b/doomsday/engine/portable/src/edit_map.c index d34ff3ff1e..1038c4f0e2 100644 --- a/doomsday/engine/portable/src/edit_map.c +++ b/doomsday/engine/portable/src/edit_map.c @@ -27,6 +27,8 @@ // HEADER FILES ------------------------------------------------------------ +#include + #include "de_base.h" #include "de_play.h" #include "de_bsp.h" @@ -965,6 +967,10 @@ static void updateSSecMidPoint(subsector_t *sub) sub->midPoint.pos[VX] /= sub->segCount; // num vertices. sub->midPoint.pos[VY] /= sub->segCount; + + // Calculate the worldwide grid offset. + sub->worldGridOffset[VX] = fmod(sub->bBox[0].pos[VX], 64); + sub->worldGridOffset[VY] = fmod(sub->bBox[1].pos[VY], 64); } static void prepareSubSectors(gamemap_t *map) diff --git a/doomsday/engine/portable/src/gl_texmanager.c b/doomsday/engine/portable/src/gl_texmanager.c index 654f886f45..c8e2405621 100644 --- a/doomsday/engine/portable/src/gl_texmanager.c +++ b/doomsday/engine/portable/src/gl_texmanager.c @@ -286,15 +286,15 @@ static void LoadPalette(void) int i, c; byte *playPal; byte palData[256 * 3]; - double invGamma; + double invGamma; palLump = W_GetNumForName(PALLUMPNAME); playPal = GL_GetPalette(); // Clamp to a sane range. - invGamma = 1.0f - MINMAX_OF(0, texGamma, 1); - for(i = 0; i < 256; ++i) - gammaTable[i] = (byte)(255.0f * pow(i / 255.0f, invGamma)); + invGamma = 1.0f - MINMAX_OF(0, texGamma, 1); + for(i = 0; i < 256; ++i) + gammaTable[i] = (byte)(255.0f * pow(i / 255.0f, invGamma)); // Prepare the color table. for(i = 0; i < 256; ++i) @@ -3170,9 +3170,14 @@ DGLuint GL_PrepareMaterial2(struct material_s* mat) // The generator will be determined now. for(i = 0, def = defs.ptcGens; i < defs.count.ptcGens.num; ++i, def++) { - material_t *defMat = - R_GetMaterialByNum(R_MaterialNumForName(def->materialName, - def->materialType)); + material_t* defMat; + + if(!(def->materialName && def->materialName[0])) + continue; + + defMat = R_GetMaterialByNum( + R_MaterialNumForName(def->materialName, + def->materialType)); if(def->flags & PGF_GROUP) { @@ -3218,7 +3223,8 @@ DGLuint GL_PrepareMaterial2(struct material_s* mat) if(result) { // We need to update the associated enhancements. - ded_decor_t *def = Def_GetDecoration(mat, result == 2); + ded_decor_t* def = + Def_GetDecoration(mat, result == 2); mat->flags &= ~MATF_GLOW; if(def) diff --git a/doomsday/engine/portable/src/m_vector.c b/doomsday/engine/portable/src/m_vector.c index 7ba2c6c8f0..14d919c5cf 100644 --- a/doomsday/engine/portable/src/m_vector.c +++ b/doomsday/engine/portable/src/m_vector.c @@ -4,7 +4,7 @@ * Online License Link: http://www.gnu.org/licenses/gpl.html * *\author Copyright © 2003-2008 Jaakko Keränen - *\author Copyright © 2006-2007 Daniel Swanson + *\author Copyright © 2006-2008 Daniel Swanson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -127,10 +127,11 @@ void V2_Scale(pvec2_t vec, float scalar) */ void V2_Rotate(pvec2_t vec, float radians) { - const float c = cos(radians); - const float s = sin(radians); - float x = c * vec[VX] - s * vec[VY]; - float y = s * vec[VX] + c * vec[VY]; + const float c = cos(radians); + const float s = sin(radians); + float x = c * vec[VX] - s * vec[VY]; + float y = s * vec[VX] + c * vec[VY]; + vec[VX] = x; vec[VY] = y; } @@ -166,8 +167,8 @@ float V2_DotProduct(const pvec2_t a, const pvec2_t b) */ float V2_ScalarProject(const pvec2_t a, const pvec2_t b) { - float dot; - float len = V2_Length(b); + float dot; + float len = V2_Length(b); if(len == 0) return 0; @@ -182,7 +183,7 @@ float V2_ScalarProject(const pvec2_t a, const pvec2_t b) */ void V2_Project(pvec2_t dest, const pvec2_t a, const pvec2_t b) { - float div = V2_DotProduct(b, b); + float div = V2_DotProduct(b, b); if(div == 0) { @@ -194,13 +195,15 @@ void V2_Project(pvec2_t dest, const pvec2_t a, const pvec2_t b) } /** - * @return @c true, if the two vectors are parallel. + * @return @c true, if the two vectors are parallel. */ boolean V2_IsParallel(const pvec2_t a, const pvec2_t b) { - float aLen = V2_Length(a); - float bLen = V2_Length(b); - float dot; +#define EPSILON .9999f + + float aLen = V2_Length(a); + float bLen = V2_Length(b); + float dot; // Both must be non-zero vectors. if(aLen == 0 || bLen == 0) @@ -209,12 +212,13 @@ boolean V2_IsParallel(const pvec2_t a, const pvec2_t b) dot = V2_DotProduct(a, b) / aLen / bLen; // If it's close enough, we'll consider them parallel. -#define EPSILON .9999f return dot > EPSILON || dot < -EPSILON; + +#undef EPSILON } /** - * @return @c true, if the vector is a zero vector. + * @return @c true, if the vector is a zero vector. */ boolean V2_IsZero(const pvec2_t vec) { @@ -225,7 +229,7 @@ boolean V2_IsZero(const pvec2_t vec) * Determine where the two lines cross each other. Notice that the * lines are defined with a point and a vector. * - * @return A scaling factor for the first line. + * @return A scaling factor for the first line. */ float V2_Intersection(const pvec2_t p1, const pvec2_t delta1, const pvec2_t p2, const pvec2_t delta2, pvec2_t point) @@ -236,12 +240,13 @@ float V2_Intersection(const pvec2_t p1, const pvec2_t delta1, const pvec2_t p2, * (XB-XA)(YD-YC)-(YB-YA)(XD-XC) */ - float r, div = delta1[VX] * delta2[VY] - delta1[VY] * delta2[VX]; - int i; + float r, div; + int i; + + div = delta1[VX] * delta2[VY] - delta1[VY] * delta2[VX]; if(div == 0) - { - // Special case: lines are parallel. + { // Special case: lines are parallel. r = 0; } else @@ -273,7 +278,7 @@ float V2_Intersection(const pvec2_t p1, const pvec2_t delta1, const pvec2_t p2, float V2_Intercept(const pvec2_t a, const pvec2_t b, const pvec2_t c, const pvec2_t d, pvec2_t point) { - vec2_t ab, cd; + vec2_t ab, cd; ab[0] = b[VX] - a[VX]; ab[1] = b[VY] - a[VY]; @@ -284,13 +289,13 @@ float V2_Intercept(const pvec2_t a, const pvec2_t b, const pvec2_t c, } /** - * @return @c true, if the two lines intercept. + * @return @c true, if the two lines intercept. */ boolean V2_Intercept2(const pvec2_t a, const pvec2_t b, const pvec2_t c, const pvec2_t d, pvec2_t point, float *abFrac, float *cdFrac) { - float ab, cd; + float ab, cd; ab = V2_Intercept(a, b, c, d, point); cd = V2_Intercept(c, d, a, b, NULL); @@ -308,7 +313,7 @@ boolean V2_Intercept2(const pvec2_t a, const pvec2_t b, const pvec2_t c, */ void V2_Lerp(pvec2_t dest, const pvec2_t a, const pvec2_t b, float c) { - uint i; + uint i; for(i = 0; i < 2; ++i) { @@ -371,7 +376,7 @@ float V3_Length(const pvec3_t vec) */ float V3_Distance(const pvec3_t a, const pvec3_t b) { - vec3_t vec; + vec3_t vec; V3_Subtract(vec, b, a); return V3_Length(vec); @@ -380,11 +385,11 @@ float V3_Distance(const pvec3_t a, const pvec3_t b) /** * Normalize a 3-dimensional vector. * - * @return The length of the vector. + * @return The length of the vector. */ float V3_Normalize(pvec3_t vec) { - float len = V3_Length(vec); + float len = V3_Length(vec); if(len != 0) { @@ -446,9 +451,9 @@ float V3_DotProduct(const pvec3_t a, const pvec3_t b) /** * Calculate the cross product of two vectors. * - * @param dest Result will be written back here. - * @param src1 First vector. - * @param src2 Second vector. + * @param dest Result will be written back here. + * @param src1 First vector. + * @param src2 Second vector. */ void V3_CrossProduct(pvec3_t dest, const pvec3_t src1, const pvec3_t src2) { @@ -460,15 +465,15 @@ void V3_CrossProduct(pvec3_t dest, const pvec3_t src1, const pvec3_t src2) /** * Cross product of two vectors composed of three points. * - * @param dest Result will be written back here. - * @param v1 First vector. - * @param v2 Second vector. - * @param v3 Third vector. + * @param dest Result will be written back here. + * @param v1 First vector. + * @param v2 Second vector. + * @param v3 Third vector. */ void V3_PointCrossProduct(pvec3_t dest, const pvec3_t v1, const pvec3_t v2, const pvec3_t v3) { - vec3_t a, b; + vec3_t a, b; V3_Subtract(a, v2, v1); V3_Subtract(b, v3, v1); @@ -486,13 +491,12 @@ void V3_PointCrossProduct(pvec3_t dest, const pvec3_t v1, const pvec3_t v2, * @return Distance from the closest point on the plane to the * specified arbitary point. */ -float V3_ClosestPointOnPlane(pvec3_t dest, - const pvec3_t planeNormal, +float V3_ClosestPointOnPlane(pvec3_t dest, const pvec3_t planeNormal, const pvec3_t planePoint, const pvec3_t arbPoint) { - vec3_t pvec; - float distance; + vec3_t pvec; + float distance; V3_Subtract(pvec, arbPoint, planePoint); distance = V3_DotProduct(planeNormal, pvec); @@ -505,7 +509,25 @@ float V3_ClosestPointOnPlane(pvec3_t dest, } /** - * @return @c true, if the vector is a zero vector. + * Determine which axis of the given vector is the major. + */ +int V3_MajorAxis(const pvec3_t vec) +{ + int axis = VX; + vec3_t fn; + + V3_Set(fn, fabsf(vec[VX]), fabsf(vec[VY]), fabsf(vec[VZ])); + + if(fn[VY] > fn[axis]) + axis = VY; + if(fn[VZ] > fn[axis]) + axis = VZ; + + return axis; +} + +/** + * @return @c true, if the vector is a zero vector. */ boolean V3_IsZero(const pvec3_t vec) { @@ -517,7 +539,7 @@ boolean V3_IsZero(const pvec3_t vec) */ void V3_Lerp(pvec3_t dest, const pvec3_t a, const pvec3_t b, float c) { - uint i; + uint i; for(i = 0; i < 3; ++i) { diff --git a/doomsday/engine/portable/src/p_maputil.c b/doomsday/engine/portable/src/p_maputil.c index f414d1d5a7..3d8daa777d 100644 --- a/doomsday/engine/portable/src/p_maputil.c +++ b/doomsday/engine/portable/src/p_maputil.c @@ -163,31 +163,11 @@ float P_MobjPointDistancef(mobj_t* start, mobj_t* end, float* fixpoint) } /** - * Determines on which side of dline the point is. Returns true if the - * point is on the line or on the right side. + * Lines start, end and fdiv must intersect. */ #ifdef _MSC_VER # pragma optimize("g", off) #endif -int P_FloatPointOnLineSide(fvertex_t* pnt, fdivline_t* dline) -{ - /* - (AY-CY)(BX-AX)-(AX-CX)(BY-AY) - s = ----------------------------- - L**2 - - If s<0 C is left of AB (you can just check the numerator) - If s>0 C is right of AB - If s=0 C is on AB - */ - // We'll return false if the point c is on the left side. - return ((dline->pos[VY] - pnt->pos[VY]) * dline->dX - - (dline->pos[VX] - pnt->pos[VX]) * dline->dY >= 0); -} - -/** - * Lines start, end and fdiv must intersect. - */ float P_FloatInterceptVertex(fvertex_t* start, fvertex_t* end, fdivline_t* fdiv, fvertex_t* inter) { @@ -213,20 +193,47 @@ float P_FloatInterceptVertex(fvertex_t* start, fvertex_t* end, inter->pos[VY] = ay + r * (by - ay); return r; } + +/** + * @return Non-zero if the point is on the right side of the + * specified line. + */ +int P_PointOnLineSide(float x, float y, float lX, float lY, float lDX, + float lDY) +{ + /* + (AY-CY)(BX-AX)-(AX-CX)(BY-AY) + s = ----------------------------- + L**2 + + If s<0 C is left of AB (you can just check the numerator) + If s>0 C is right of AB + If s=0 C is on AB + */ + return ((lY - y) * lDX - (lX - x) * lDY >= 0); +} #ifdef _MSC_VER # pragma optimize("", on) #endif /** - * Returns 0 or 1 + * Determines on which side of dline the point is. Returns true if the + * point is on the line or on the right side. */ -int P_PointOnLineSide(float x, float y, linedef_t* line) +int P_PointOnDivLineSidef(fvertex_t* pnt, fdivline_t* dline) { - vertex_t* vtx1 = line->L_v1; + return P_PointOnLineSide(pnt->pos[VX], pnt->pos[VY], dline->pos[VX], + dline->pos[VY], dline->dX, dline->dY); +} - return !line->dX? x <= vtx1->V_pos[VX]? line->dY > 0 : line->dY < - 0 : !line->dY? y <= vtx1->V_pos[VY]? line->dX < 0 : line->dX > - 0 : (y - vtx1->V_pos[VY]) * line->dX >= line->dY * (x - vtx1->V_pos[VX]); +/** + * @return Non-zero if the point is on the right side of the + * specified line. + */ +int P_PointOnLinedefSide(float x, float y, linedef_t* line) +{ + return P_PointOnLineSide(x, y, line->L_v1pos[VX], line->L_v1pos[VY], + line->dX, line->dY); } /** @@ -243,7 +250,7 @@ int P_PointOnLineSide(float x, float y, linedef_t* line) * @c 0= intersects. * @c >0= on right side. */ -int P_PointOnLineSide2(double pointX, double pointY, double lineDX, +int P_PointOnLinedefSide2(double pointX, double pointY, double lineDX, double lineDY, double linePerp, double lineLength, double epsilon) { @@ -309,13 +316,13 @@ int P_BoxOnLineSide3(const int bbox[4], double lineSX, double lineSY, } else if(lineDX * lineDY > 0) { // Positive slope. - p1 = P_PointOnLineSide2(x1, y2, lineDX, lineDY, linePerp, lineLength, epsilon); - p2 = P_PointOnLineSide2(x2, y1, lineDX, lineDY, linePerp, lineLength, epsilon); + p1 = P_PointOnLinedefSide2(x1, y2, lineDX, lineDY, linePerp, lineLength, epsilon); + p2 = P_PointOnLinedefSide2(x2, y1, lineDX, lineDY, linePerp, lineLength, epsilon); } else { // Negative slope. - p1 = P_PointOnLineSide2(x1, y1, lineDX, lineDY, linePerp, lineLength, epsilon); - p2 = P_PointOnLineSide2(x2, y2, lineDX, lineDY, linePerp, lineLength, epsilon); + p1 = P_PointOnLinedefSide2(x1, y1, lineDX, lineDY, linePerp, lineLength, epsilon); + p2 = P_PointOnLinedefSide2(x2, y2, lineDX, lineDY, linePerp, lineLength, epsilon); } if(p1 == p2) @@ -352,12 +359,12 @@ int P_BoxOnLineSide2(float xl, float xh, float yl, float yh, (p = xh < lx) ? p ^ (ld->dY < 0) : -1; } case ST_POSITIVE: - return P_PointOnLineSide(xh, yl, ld) == - (p = P_PointOnLineSide(xl, yh, ld)) ? p : -1; + return P_PointOnLinedefSide(xh, yl, ld) == + (p = P_PointOnLinedefSide(xl, yh, ld)) ? p : -1; case ST_NEGATIVE: - return (P_PointOnLineSide(xl, yl, ld)) == - (p = P_PointOnLineSide(xh, yh, ld)) ? p : -1; + return (P_PointOnLinedefSide(xl, yl, ld)) == + (p = P_PointOnLinedefSide(xh, yh, ld)) ? p : -1; } } @@ -1057,9 +1064,9 @@ boolean PIT_AddLineIntercepts(linedef_t* ld, void* data) } else { - s[0] = P_PointOnLineSide(FIX2FLT(traceLOS.pos[VX]), + s[0] = P_PointOnLinedefSide(FIX2FLT(traceLOS.pos[VX]), FIX2FLT(traceLOS.pos[VY]), ld); - s[1] = P_PointOnLineSide(FIX2FLT(traceLOS.pos[VX] + traceLOS.dX), + s[1] = P_PointOnLinedefSide(FIX2FLT(traceLOS.pos[VX] + traceLOS.dX), FIX2FLT(traceLOS.pos[VY] + traceLOS.dY), ld); } diff --git a/doomsday/engine/portable/src/p_mobj.c b/doomsday/engine/portable/src/p_mobj.c index b7bf997d9e..6b4677581e 100644 --- a/doomsday/engine/portable/src/p_mobj.c +++ b/doomsday/engine/portable/src/p_mobj.c @@ -612,7 +612,7 @@ static void wallMomSlide(linedef_t *ld) return; } - side = P_PointOnLineSide(slideMo->pos[VX], slideMo->pos[VY], ld); + side = P_PointOnLinedefSide(slideMo->pos[VX], slideMo->pos[VY], ld); lineangle = R_PointToAngle2(0, 0, ld->dX, ld->dY); if(side == 1) @@ -644,7 +644,7 @@ static boolean slideTraverse(intercept_t *in) if(!(li->inFlags & LF_TWOSIDED)) { - if(P_PointOnLineSide(slideMo->pos[VX], + if(P_PointOnLinedefSide(slideMo->pos[VX], slideMo->pos[VY], li)) { // The back side. return true; // Continue iteration. diff --git a/doomsday/engine/portable/src/p_particle.c b/doomsday/engine/portable/src/p_particle.c index ec8a544e9d..c2493ca98c 100644 --- a/doomsday/engine/portable/src/p_particle.c +++ b/doomsday/engine/portable/src/p_particle.c @@ -507,10 +507,10 @@ static void P_NewParticle(ptcgen_t *gen) /** * Choosing the XY spot is a bit more difficult. * But we must be fast and only sufficiently accurate. - * + * * \fixme Nothing prevents spawning on the wrong side (or inside) * of one-sided walls (large diagonal subsectors!). - */ + */ box = gen->sector->bBox; for(i = 0; i < 5; ++i) // Try a couple of times (max). { @@ -631,8 +631,8 @@ boolean PIT_CheckLinePtc(linedef_t *ld, void *data) } // Movement must cross the line. - if(P_PointOnLineSide(FIX2FLT(tmpx1), FIX2FLT(tmpy1), ld) == - P_PointOnLineSide(FIX2FLT(tmpx2), FIX2FLT(tmpy2), ld)) + if(P_PointOnLinedefSide(FIX2FLT(tmpx1), FIX2FLT(tmpy1), ld) == + P_PointOnLinedefSide(FIX2FLT(tmpx2), FIX2FLT(tmpy2), ld)) return true; // We are possibly hitting something here. diff --git a/doomsday/engine/portable/src/r_lumobjs.c b/doomsday/engine/portable/src/r_lumobjs.c index e09097ccc5..1ef2653696 100644 --- a/doomsday/engine/portable/src/r_lumobjs.c +++ b/doomsday/engine/portable/src/r_lumobjs.c @@ -31,6 +31,7 @@ #include #include "de_base.h" +#include "de_dgl.h" #include "de_refresh.h" #include "de_render.h" #include "de_graphics.h" @@ -60,8 +61,8 @@ typedef struct { } lightconfig_t; typedef struct lumlink_s { - struct lumlink_s *next; // Next in the same DL block, or NULL. - struct lumlink_s *ssNext; // Next in the same subsector, or NULL. + struct lumlink_s* next; // Next in the same DL block, or NULL. + struct lumlink_s* ssNext; // Next in the same subsector, or NULL. lumobj_t lum; } lumlink_t; @@ -69,14 +70,14 @@ typedef struct lumlink_s { typedef struct contactfinder_data_s { vec2_t box[2]; boolean didSpread; - lumobj_t *lum; + lumobj_t* lum; int firstValid; } contactfinder_data_t; typedef struct objcontact_s { - struct objcontact_s *next; // Next in the subsector. - struct objcontact_s *nextUsed; // Next used contact. - void *data; + struct objcontact_s* next; // Next in the subsector. + struct objcontact_s* nextUsed; // Next used contact. + void* data; } objcontact_t; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- @@ -92,37 +93,37 @@ extern int useBias; // PUBLIC DATA DEFINITIONS ------------------------------------------------- boolean loInited = false; -uint loMaxLumobjs = 0; +uint loMaxLumobjs = 0; -int loMaxRadius = 256; // Dynamic lights maximum radius. -float loRadiusFactor = 3; -int loMinRadForBias = 136; // Lights smaller than this will NEVER +int loMaxRadius = 256; // Dynamic lights maximum radius. +float loRadiusFactor = 3; +int loMinRadForBias = 136; // Lights smaller than this will NEVER // be converted to BIAS sources. -int useMobjAutoLights = true; // Enable automaticaly calculated lights - // attached to mobjs. -byte rendInfoLums = false; +int useMobjAutoLights = true; // Enable automaticaly calculated lights + // attached to mobjs. +byte rendInfoLums = false; // PRIVATE DATA DEFINITIONS ------------------------------------------------ -static lumlink_t *luminousList = NULL; +static lumlink_t* luminousList = NULL; static uint numLuminous = 0, maxLuminous = 0; -static lumlink_t **loBlockLinks = 0; +static lumlink_t** loBlockLinks = 0; static fixed_t loBlockOrig[3]; -static int loBlockWidth, loBlockHeight; // In 128 blocks. +static int loBlockWidth, loBlockHeight; // In 128 blocks. -static lumlink_t **loSubLinks = 0; +static lumlink_t** loSubLinks = 0; // A frameCount for each block. Used to prevent multiple processing of // a block during one frame. -static int *spreadBlocks; +static int* spreadBlocks; // List of unused and used obj-subsector contacts. -static objcontact_t *contFirst, *contCursor; +static objcontact_t* contFirst, *contCursor; // List of obj contacts for each subsector. -static objcontact_t **subContacts; +static objcontact_t** subContacts; // CODE -------------------------------------------------------------------- @@ -142,14 +143,14 @@ void LO_Register(void) /** * Link the given objcontact node to list. */ -static __inline void linkContact(objcontact_t *con, objcontact_t **list, +static __inline void linkContact(objcontact_t* con, objcontact_t** list, uint index) { con->next = list[index]; list[index] = con; } -static void linkObjToSubSector(objcontact_t *node, uint index) +static void linkObjToSubSector(objcontact_t* node, uint index) { linkContact(node, &subContacts[index], 0); } @@ -162,9 +163,9 @@ static void linkObjToSubSector(objcontact_t *node, uint index) * * @return Ptr to the new objcontact. */ -static objcontact_t *newContact(void *data) +static objcontact_t* newContact(void* data) { - objcontact_t *con; + objcontact_t* con; if(contCursor == NULL) { @@ -189,14 +190,14 @@ static objcontact_t *newContact(void *data) * * @return Ptr to the lumnode at the given index. */ -static __inline lumlink_t *getLumNode(uint idx) +static __inline lumlink_t* getLumNode(uint idx) { return &luminousList[idx]; } void LO_InitForMap(void) { - gamemap_t *map = P_GetCurrentMap(); + gamemap_t* map = P_GetCurrentMap(); float min[3], max[3]; // First initialize the subsector links (root pointers). @@ -288,7 +289,7 @@ uint LO_GetNumLuminous(void) */ uint LO_NewLuminous(lumtype_t type) { - lumlink_t *node, *newList; + lumlink_t* node, *newList; numLuminous++; @@ -329,7 +330,7 @@ uint LO_NewLuminous(lumtype_t type) * * @return Ptr to the lumobj with the given 1-based index. */ -lumobj_t *LO_GetLuminous(uint idx) +lumobj_t* LO_GetLuminous(uint idx) { if(!(idx == 0 || idx > numLuminous)) return &getLumNode(idx - 1)->lum; @@ -343,7 +344,7 @@ lumobj_t *LO_GetLuminous(uint idx) * * @param mo Ptr to the mobj to register. */ -void LO_AddLuminous(mobj_t *mo) +void LO_AddLuminous(mobj_t* mo) { mo->light = 0; @@ -356,13 +357,13 @@ void LO_AddLuminous(mobj_t *mo) int flags = 0; int radius, flareSize; float rgb[3]; - lumobj_t *l; + lumobj_t* l; lightconfig_t cf; - ded_light_t *def = 0; - spritedef_t *sprDef; - spriteframe_t *sprFrame; - spritetex_t *sprTex; - material_t *mat; + ded_light_t* def = 0; + spritedef_t* sprDef; + spriteframe_t* sprFrame; + spritetex_t* sprTex; + material_t* mat; // Are the automatically calculated light values for fullbright // sprite frames in use? @@ -485,8 +486,7 @@ void LO_AddLuminous(mobj_t *mo) mo->light = LO_NewLuminous(LT_OMNI); l = LO_GetLuminous(mo->light); - l->flags = flags; - l->flags |= LUMF_CLIPPED; + l->flags = LUMF_CLIPPED; l->pos[VX] = mo->pos[VX]; l->pos[VY] = mo->pos[VY]; l->pos[VZ] = mo->pos[VZ]; @@ -497,6 +497,7 @@ void LO_AddLuminous(mobj_t *mo) mo->pos[VZ] - viewZ); l->subsector = mo->subsector; + LUM_OMNI(l)->flags = flags; LUM_OMNI(l)->haloFactor = mo->haloFactor; LUM_OMNI(l)->zOff = center; LUM_OMNI(l)->xOff = xOff; @@ -509,7 +510,7 @@ void LO_AddLuminous(mobj_t *mo) LUM_OMNI(l)->flareMul = 1; LUM_OMNI(l)->flareSize = flareSize; for(i = 0; i < 3; ++i) - l->color[i] = rgb[i]; + LUM_OMNI(l)->color[i] = rgb[i]; if(def) { @@ -518,7 +519,7 @@ void LO_AddLuminous(mobj_t *mo) LUM_OMNI(l)->floorTex = def->down.tex; if(def->flare.disabled) - l->flags |= LUMF_NOHALO; + LUM_OMNI(l)->flags |= LUMOF_NOHALO; else { LUM_OMNI(l)->flareCustom = def->flare.custom; @@ -529,15 +530,14 @@ void LO_AddLuminous(mobj_t *mo) { // Use the same default light texture for all directions. LUM_OMNI(l)->tex = LUM_OMNI(l)->ceilTex = - LUM_OMNI(l)->floorTex = - GL_PrepareLSTexture(LST_DYNAMIC); + LUM_OMNI(l)->floorTex = GL_PrepareLSTexture(LST_DYNAMIC); } } } -boolean LOIT_LinkObjToSubSector(subsector_t *subsector, void *data) +boolean LOIT_LinkObjToSubSector(subsector_t* subsector, void* data) { - objcontact_t *con = newContact(data); + objcontact_t* con = newContact(data); // Link it to the contact list for this subsector. linkObjToSubSector(con, GET_SUBSECTOR_IDX(subsector)); @@ -554,7 +554,7 @@ boolean LOIT_LinkObjToSubSector(subsector_t *subsector, void *data) * @param box Subsectors within this bounding box will be processed. * @param sector Ptr to the sector to check for contacts. */ -static void contactSector(lumobj_t *lum, const arvec2_t box, sector_t *sector) +static void contactSector(lumobj_t* lum, const arvec2_t box, sector_t* sector) { P_SubsectorsBoxIteratorv(box, sector, LOIT_LinkObjToSubSector, lum); } @@ -569,17 +569,17 @@ static void contactSector(lumobj_t *lum, const arvec2_t box, sector_t *sector) * @return @c true, because this function is also used as an * iterator. */ -boolean LOIT_ContactFinder(linedef_t *line, void *data) +boolean LOIT_ContactFinder(linedef_t* line, void* data) { - contactfinder_data_t *light = data; - sector_t *source, *dest; + contactfinder_data_t* light = data; + sector_t* source, *dest; float distance; - vertex_t *vtx; - lumobj_t *l; + vertex_t* vtx; + lumobj_t* l; - if(light->lum->type != LT_OMNI) - return true; // Only interested in omni lights. l = light->lum; + if(l->type != LT_OMNI) + return true; // Only interested in omni lights. if(!line->L_backside || !line->L_frontside || line->L_frontsector == line->L_backsector) @@ -678,7 +678,7 @@ boolean LOIT_ContactFinder(linedef_t *line, void *data) * * @param lum Ptr to lumobj to find subsector contacts for. */ -static void findContacts(lumobj_t *lum) +static void findContacts(lumobj_t* lum) { int firstValid; contactfinder_data_t light; @@ -687,12 +687,12 @@ static void findContacts(lumobj_t *lum) static uint numSpreads = 0, numFinds = 0; if(lum->type != LT_OMNI) - return; // Only omni lights spread. + return; // Only omni lights and decals spread. firstValid = ++validCount; - // Use a slightly smaller radius than what the light really is. - radius = LUM_OMNI(lum)->radius * 0.9f; + // Use a slightly smaller radius than what the lumobj really is. + radius = LUM_OMNI(lum)->radius * .9f; // Do the sector spread. Begin from the light's own sector. lum->subsector->sector->validCount = validCount; @@ -708,7 +708,7 @@ static void findContacts(lumobj_t *lum) numFinds++; - // We'll keep doing this until the light has spreaded everywhere + // We'll keep doing this until the lumobj has spreaded everywhere // inside the bounding box. do { @@ -739,11 +739,11 @@ if(!((numFinds + 1) % 1000)) * * @param subsector Ptr to the subsector to spread the lumobj contacts of. */ -static void spreadLumobjsInSubSector(subsector_t *subsector) +static void spreadLumobjsInSubSector(subsector_t* subsector) { int xl, xh, yl, yh, x, y; - int *count; - lumlink_t *iter; + int* count; + lumlink_t* iter; xl = X_TO_DLBX(FLT2FIX(subsector->bBox[0].pos[VX] - loMaxRadius)); xh = X_TO_DLBX(FLT2FIX(subsector->bBox[1].pos[VX] + loMaxRadius)); @@ -782,10 +782,10 @@ static void spreadLumobjsInSubSector(subsector_t *subsector) /** * Used to sort lumobjs by distance from viewpoint. */ -static int C_DECL lumobjSorter(const void *e1, const void *e2) +static int C_DECL lumobjSorter(const void* e1, const void* e2) { - lumobj_t *lum1 = &getLumNode(*(const ushort *) e1)->lum; - lumobj_t *lum2 = &getLumNode(*(const ushort *) e2)->lum; + lumobj_t* lum1 = &getLumNode(*(const ushort *) e1)->lum; + lumobj_t* lum2 = &getLumNode(*(const ushort *) e2)->lum; if(lum1->distanceToViewer > lum2->distanceToViewer) return 1; @@ -802,11 +802,11 @@ static int C_DECL lumobjSorter(const void *e1, const void *e2) */ static void linkLuminous(void) { -#define MAX_LUMS 8192 // Normally 100-200, heavy: 1000 +#define MAX_LUMS (8192) // Normally 100-200, heavy: 1000 int bx, by; uint i, num = numLuminous; - lumlink_t **root, *node; + lumlink_t** root, *node; ushort order[MAX_LUMS]; // Should the proper order be determined? @@ -853,7 +853,7 @@ static void linkLuminous(void) * * @param ssec Ptr to the subsector to process. */ -void LO_InitForSubsector(subsector_t *ssec) +void LO_InitForSubsector(subsector_t* ssec) { if(!useDynLights && !useWallGlow) return; // Disabled. @@ -868,10 +868,10 @@ void LO_InitForSubsector(subsector_t *ssec) * * @param ssec Ptr to the subsector to process. */ -static void createGlowLightPerPlaneForSubSector(subsector_t *ssec) +static void createGlowLightPerPlaneForSubSector(subsector_t* ssec) { uint g; - plane_t *glowPlanes[2], *pln; + plane_t* glowPlanes[2], *pln; glowPlanes[PLN_FLOOR] = R_GetLinkedSector(ssec, PLN_FLOOR)->planes[PLN_FLOOR]; glowPlanes[PLN_CEILING] = R_GetLinkedSector(ssec, PLN_CEILING)->planes[PLN_CEILING]; @@ -890,7 +890,7 @@ static void createGlowLightPerPlaneForSubSector(subsector_t *ssec) light = LO_NewLuminous(LT_PLANE); l = LO_GetLuminous(light); - l->flags = LUMF_NOHALO | LUMF_CLIPPED; + l->flags = LUMF_CLIPPED; l->pos[VX] = ssec->midPoint.pos[VX]; l->pos[VY] = ssec->midPoint.pos[VY]; l->pos[VZ] = pln->visHeight; @@ -906,9 +906,9 @@ static void createGlowLightPerPlaneForSubSector(subsector_t *ssec) l->pos[VZ] - viewZ); l->subsector = ssec; - l->color[CR] = pln->glowRGB[CR]; - l->color[CG] = pln->glowRGB[CG]; - l->color[CB] = pln->glowRGB[CB]; + LUM_PLANE(l)->color[CR] = pln->glowRGB[CR]; + LUM_PLANE(l)->color[CG] = pln->glowRGB[CG]; + LUM_PLANE(l)->color[CB] = pln->glowRGB[CB]; LUM_PLANE(l)->intensity = pln->glow; LUM_PLANE(l)->tex = GL_PrepareLSTexture(LST_GRADIENT); @@ -944,7 +944,7 @@ END_PROF( PROF_DYN_INIT_DEL ); void LO_AddLuminousMobjs(void) { uint i; - sector_t *seciter; + sector_t* seciter; if(!useDynLights && !useWallGlow) return; @@ -991,11 +991,11 @@ BEGIN_PROF( PROF_DYN_INIT_LINK ); END_PROF( PROF_DYN_INIT_LINK ); } -boolean LO_IterateSubsectorContacts(subsector_t *ssec, - boolean (*func) (void *, void *), - void *data) +boolean LO_IterateSubsectorContacts(subsector_t* ssec, + boolean (*func) (void*, void*), + void* data) { - objcontact_t *con; + objcontact_t* con; for(con = subContacts[GET_SUBSECTOR_IDX(ssec)]; con; con = con->next) { @@ -1009,14 +1009,14 @@ boolean LO_IterateSubsectorContacts(subsector_t *ssec, typedef struct lumobjiterparams_s { float origin[2]; float radius; - void *data; - boolean (*func) (lumobj_t *, float, void *data); + void* data; + boolean (*func) (lumobj_t*, float, void* data); } lumobjiterparams_t; -boolean LOIT_RadiusLumobjs(void *ptr, void *data) +boolean LOIT_RadiusLumobjs(void* ptr, void* data) { - lumobj_t *lum = (lumobj_t*) ptr; - lumobjiterparams_t *params = data; + lumobj_t* lum = (lumobj_t*) ptr; + lumobjiterparams_t* params = data; float dist = P_ApproxDistance(lum->pos[VX] - params->origin[VX], lum->pos[VY] - params->origin[VY]); @@ -1039,9 +1039,9 @@ boolean LOIT_RadiusLumobjs(void *ptr, void *data) * * @return @c true, iff every callback returns @c true, else @c false. */ -boolean LO_LumobjsRadiusIterator(subsector_t *ssec, float x, float y, - float radius, void *data, - boolean (*func) (lumobj_t *, float, void *data)) +boolean LO_LumobjsRadiusIterator(subsector_t* ssec, float x, float y, + float radius, void* data, + boolean (*func) (lumobj_t*, float, void*)) { lumobjiterparams_t params; @@ -1059,18 +1059,18 @@ boolean LO_LumobjsRadiusIterator(subsector_t *ssec, float x, float y, } /** - * Clip lights by subsector. + * Clip lumobjs by subsector. * * @param ssecidx Subsector index in which lights will be clipped. */ void LO_ClipInSubsector(uint ssecidx) { - lumlink_t *lumi; // Lum Iterator, or 'snow' in Finnish. :-) + lumlink_t* lumi; // Lum Iterator, or 'snow' in Finnish. :-) // Determine which dynamic light sources in the subsector get clipped. for(lumi = loSubLinks[ssecidx]; lumi; lumi = lumi->ssNext) { - lumobj_t *lobj = &lumi->lum; + lumobj_t* lobj = &lumi->lum; if(lobj->type != LT_OMNI) continue; // Only interested in omnilights. @@ -1081,43 +1081,44 @@ void LO_ClipInSubsector(uint ssecidx) // LO_AddLuminous! if(!C_IsPointVisible(lobj->pos[VX], lobj->pos[VY], lobj->pos[VZ] + LUM_OMNI(lobj)->zOff)) - lobj->flags |= LUMF_CLIPPED; // Won't have a halo. + lobj->flags |= LUMF_CLIPPED; // Won't have a halo. } } /** - * In the situation where a subsector contains both dynamic lights and - * a polyobj, the lights must be clipped more carefully. Here we - * check if the line of sight intersects any of the polyobj segs that - * face the camera. + * In the situation where a subsector contains both lumobjs and a polyobj, + * the lumobjs must be clipped more carefully. Here we check if the line of + * sight intersects any of the polyobj segs that face the camera. * - * @param ssecidx Subsector index in which lights will be clipped. + * @param ssecidx Subsector index in which lumobjs will be clipped. */ void LO_ClipBySight(uint ssecidx) { uint num; vec2_t eye; - subsector_t *ssec = SUBSECTOR_PTR(ssecidx); - lumlink_t *lumi; + subsector_t* ssec = SUBSECTOR_PTR(ssecidx); + lumlink_t* lumi; // Only checks the polyobj. - if(ssec->polyObj == NULL) return; + if(ssec->polyObj == NULL) + return; V2_Set(eye, vx, vz); num = ssec->polyObj->numSegs; for(lumi = loSubLinks[ssecidx]; lumi; lumi = lumi->ssNext) { - lumobj_t *lobj = &lumi->lum; + lumobj_t* lobj = &lumi->lum; if(!(lobj->flags & LUMF_CLIPPED)) { uint i; + // We need to figure out if any of the polyobj's segments lies - // between the viewpoint and the light source. + // between the viewpoint and the lumobj. for(i = 0; i < num; ++i) { - seg_t *seg = ssec->polyObj->segs[i]; + seg_t* seg = ssec->polyObj->segs[i]; // Ignore segs facing the wrong way. if(seg->frameFlags & SEGINF_FACINGFRONT) @@ -1136,3 +1137,108 @@ void LO_ClipBySight(uint ssecidx) } } } + +#if _DEBUG +void LO_DrawLumobjs(void) +{ + static const float black[4] = { 0, 0, 0, 0 }; + static const float white[4] = { 1, 1, 1, 1 }; + float color[4]; + uint i; + + DGL_Disable(DGL_TEXTURING); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + for(i = 0; i < numLuminous; ++i) + { + lumobj_t* lum = &luminousList[i].lum; + vec3_t lumCenter; + + if(!(lum->type == LT_OMNI || lum->type == LT_PLANE)) + continue; + + V3_Copy(lumCenter, lum->pos); + if(lum->type == LT_OMNI) + lumCenter[VZ] += LUM_OMNI(lum)->zOff; + + DGL_MatrixMode(DGL_MODELVIEW); + DGL_PushMatrix(); + + DGL_Translatef(lumCenter[VX], lumCenter[VZ], lumCenter[VY]); + + switch(lum->type) + { + case LT_OMNI: + { + float scale = LUM_OMNI(lum)->radius; + + color[CR] = LUM_OMNI(lum)->color[CR]; + color[CG] = LUM_OMNI(lum)->color[CG]; + color[CB] = LUM_OMNI(lum)->color[CB]; + color[CA] = 1; + + DGL_Begin(DGL_LINES); + { + DGL_Color4fv(black); + DGL_Vertex3f(-scale, 0, 0); + DGL_Color4fv(color); + DGL_Vertex3f(0, 0, 0); + DGL_Vertex3f(0, 0, 0); + DGL_Color4fv(black); + DGL_Vertex3f(scale, 0, 0); + + DGL_Vertex3f(0, -scale, 0); + DGL_Color4fv(color); + DGL_Vertex3f(0, 0, 0); + DGL_Vertex3f(0, 0, 0); + DGL_Color4fv(black); + DGL_Vertex3f(0, scale, 0); + + DGL_Vertex3f(0, 0, -scale); + DGL_Color4fv(color); + DGL_Vertex3f(0, 0, 0); + DGL_Vertex3f(0, 0, 0); + DGL_Color4fv(black); + DGL_Vertex3f(0, 0, scale); + } + DGL_End(); + break; + } + + case LT_PLANE: + { + float scale = LUM_PLANE(lum)->intensity * 10; + + color[CR] = LUM_PLANE(lum)->color[CR]; + color[CG] = LUM_PLANE(lum)->color[CG]; + color[CB] = LUM_PLANE(lum)->color[CB]; + color[CA] = 1; + + DGL_Begin(DGL_LINES); + { + DGL_Color4fv(black); + DGL_Vertex3f(scale * LUM_PLANE(lum)->normal[VX], + scale * LUM_PLANE(lum)->normal[VZ], + scale * LUM_PLANE(lum)->normal[VY]); + DGL_Color4fv(color); + DGL_Vertex3f(0, 0, 0); + + } + DGL_End(); + break; + } + + default: + break; + } + + DGL_MatrixMode(DGL_MODELVIEW); + DGL_PopMatrix(); + } + + glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + DGL_Enable(DGL_TEXTURING); +} +#endif diff --git a/doomsday/engine/portable/src/r_things.c b/doomsday/engine/portable/src/r_things.c index 5ac03b6e2f..66e03742a4 100644 --- a/doomsday/engine/portable/src/r_things.c +++ b/doomsday/engine/portable/src/r_things.c @@ -987,12 +987,15 @@ static void glowLightSetup(vlight_t *light) /** * Iterator for processing light sources around a vissprite. */ -boolean visSpriteLightIterator(lumobj_t *lum, float xyDist, void *data) +boolean visSpriteLightIterator(lumobj_t* lum, float xyDist, void *data) { float dist; float glowHeight; boolean addLight = false; - vlightiterparams_t *params = (vlightiterparams_t*) data; + vlightiterparams_t* params = (vlightiterparams_t*) data; + + if(!(lum->type == LT_OMNI || lum->type == LT_PLANE)) + return true; // Continue iteration. // Is the light close enough to make the list? switch(lum->type) @@ -1011,7 +1014,8 @@ boolean visSpriteLightIterator(lumobj_t *lum, float xyDist, void *data) case LT_PLANE: if(LUM_PLANE(lum)->intensity && - (lum->color[0] > 0 || lum->color[1] > 0|| lum->color[2] > 0)) + (LUM_PLANE(lum)->color[0] > 0 || LUM_PLANE(lum)->color[1] > 0 || + LUM_PLANE(lum)->color[2] > 0)) { // Floor glow glowHeight = @@ -1084,8 +1088,9 @@ boolean visSpriteLightIterator(lumobj_t *lum, float xyDist, void *data) light->worldVector[VZ] = -LUM_PLANE(lum)->normal[VZ]; dist = 1 - dist / glowHeight; - scaleFloatRGB(light->color, lum->color, dist); - R_ScaleAmbientRGB(params->ambientColor, lum->color, dist / 3); + scaleFloatRGB(light->color, LUM_PLANE(lum)->color, dist); + R_ScaleAmbientRGB(params->ambientColor, + LUM_PLANE(lum)->color, dist / 3); break; default: @@ -1208,7 +1213,7 @@ void R_CollectAffectingLights(const collectaffectinglights_params_t *params, light->vector[c] = (params->center[c] - lightCenter[c]) / light->approxDist; // ...and the color of the light. - light->color[c] = l->color[c] * intensity; + light->color[c] = LUM_OMNI(l)->color[c] * intensity; } } else diff --git a/doomsday/engine/portable/src/rend_decor.c b/doomsday/engine/portable/src/rend_decor.c index 979abfc2e4..354078b83a 100644 --- a/doomsday/engine/portable/src/rend_decor.c +++ b/doomsday/engine/portable/src/rend_decor.c @@ -26,11 +26,13 @@ /** * rend_decor.c: Decorations * - * Surface decorations (dynamic lights). + * Surface decorations. */ // HEADER FILES ------------------------------------------------------------ +#include + #include "de_base.h" #include "de_play.h" #include "de_refresh.h" @@ -48,19 +50,19 @@ typedef struct decorsource_s { float pos[3]; float maxDist; - const surface_t *surface; - subsector_t *subsector; + const surface_t* surface; + subsector_t* subsector; decortype_t type; union decorsource_data_s { struct decorsource_data_light_s { - const ded_decorlight_t *def; + const ded_decorlight_t* def; } light; struct decorsource_data_model_s { - struct modeldef_s *mf; + struct modeldef_s* mf; float pitch, yaw; } model; } data; - struct decorsource_s *next; + struct decorsource_s* next; } decorsource_t; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- @@ -81,8 +83,8 @@ float decorFadeAngle = .1f; // PRIVATE DATA DEFINITIONS ------------------------------------------------ static uint numDecorLightSources; -static decorsource_t *sourceFirst = NULL, *sourceLast = NULL; -static decorsource_t *sourceCursor = NULL; +static decorsource_t* sourceFirst = NULL, *sourceLast = NULL; +static decorsource_t* sourceCursor = NULL; // CODE -------------------------------------------------------------------- @@ -108,7 +110,7 @@ static void clearDecorations(void) * limit condition. */ static float checkSectorLight(float lightlevel, - const ded_decorlight_t *lightDef) + const ded_decorlight_t* lightDef) { float factor; @@ -130,15 +132,15 @@ static float checkSectorLight(float lightlevel, return factor; } -static void projectDecoration(decorsource_t *src) +static void projectDecoration(decorsource_t* src) { + uint i; float v1[2]; uint light; - lumobj_t *l; - vissprite_t *vis; + lumobj_t* l; + vissprite_t* vis; float distance = Rend_PointDist3D(src->pos); float fadeMul = 1, flareMul = 1, brightness; - uint i; // Is the point in range? if(distance > src->maxDist) @@ -252,7 +254,7 @@ static void projectDecoration(decorsource_t *src) if(src->data.light.def->flare.disabled) { - l->flags |= LUMF_NOHALO; + LUM_OMNI(l)->flags |= LUMOF_NOHALO; } else { @@ -263,7 +265,7 @@ static void projectDecoration(decorsource_t *src) LUM_OMNI(l)->flareMul = flareMul; for(i = 0; i < 3; ++i) - l->color[i] = src->data.light.def->color[i] * fadeMul; + LUM_OMNI(l)->color[i] = src->data.light.def->color[i] * fadeMul; l->distanceToViewer = distance; @@ -277,7 +279,7 @@ static void projectDecoration(decorsource_t *src) */ void Rend_ProjectDecorations(void) { - decorsource_t *src; + decorsource_t* src; for(src = sourceFirst; src != sourceCursor; src = src->next) { @@ -288,9 +290,9 @@ void Rend_ProjectDecorations(void) /** * Create a new source for a light decoration. */ -static decorsource_t *addDecoration(void) +static decorsource_t* addDecoration(void) { - decorsource_t *src; + decorsource_t* src; if(numDecorLightSources > MAX_SOURCES) return NULL; @@ -325,11 +327,11 @@ static decorsource_t *addDecoration(void) /** * A decoration is created at the specified coordinates. */ -static void createSurfaceDecoration(const surface_t *suf, - const surfacedecor_t *dec, +static void createSurfaceDecoration(const surface_t* suf, + const surfacedecor_t* dec, const float maxDist) { - decorsource_t *source = addDecoration(); + decorsource_t* source = addDecoration(); if(!source) return; // Out of sources! @@ -356,7 +358,7 @@ static void createSurfaceDecoration(const surface_t *suf, } } -boolean R_IsValidModelDecoration(const ded_decormodel_t *modelDef) +boolean R_IsValidModelDecoration(const ded_decormodel_t* modelDef) { return ((modelDef && modelDef->id && modelDef->id[0])? true : false); } @@ -372,7 +374,7 @@ boolean R_ProjectSurfaceDecorations(surface_t* suf, void* context) for(i = 0; i < suf->numDecorations; ++i) { - const surfacedecor_t *d = &suf->decorations[i]; + const surfacedecor_t* d = &suf->decorations[i]; switch(d->type) { @@ -396,7 +398,7 @@ boolean R_ProjectSurfaceDecorations(surface_t* suf, void* context) /** * Determine proper skip values. */ -static void getDecorationSkipPattern(const int patternSkip[2], int *skip) +static void getDecorationSkipPattern(const int patternSkip[2], int* skip) { uint i; @@ -410,19 +412,264 @@ static void getDecorationSkipPattern(const int patternSkip[2], int *skip) } } +static uint generateDecorLights(const ded_decorlight_t* def, + surface_t* suf, const pvec3_t v1, + const pvec3_t v2, float width, float height, + const pvec3_t delta, int axis, + float offsetS, float offsetT, sector_t* sec) +{ + uint num; + float s, t; // Horizontal and vertical offset. + vec3_t posBase, pos; + float patternW, patternH; + int skip[2]; + + if(!R_IsValidLightDecoration(def)) + return 0; + + // Skip must be at least one. + getDecorationSkipPattern(def->patternSkip, skip); + patternW = suf->material->width * skip[0]; + patternH = suf->material->height * skip[1]; + + V3_Set(posBase, def->elevation * suf->normal[VX], + def->elevation * suf->normal[VY], + def->elevation * suf->normal[VZ]); + V3_Sum(posBase, posBase, v1); + + // Let's see where the top left light is. + s = M_CycleIntoRange(def->pos[0] - suf->visOffset[0] - + suf->material->width * def->patternOffset[0] + + offsetS, patternW); + num = 0; + for(; s < width; s += patternW) + { + t = M_CycleIntoRange(def->pos[1] - suf->visOffset[1] - + suf->material->height * def->patternOffset[1] + + offsetT, patternH); + + for(; t < height; t += patternH) + { + surfacedecor_t* d; + float offS = s / width, offT = t / height; + + V3_Set(pos, delta[VX] * offS, + delta[VY] * (axis == VZ? offT : offS), + delta[VZ] * (axis == VZ? offS : offT)); + V3_Sum(pos, posBase, pos); + + if(sec) + { + // The point must be inside the correct sector. + if(!R_IsPointInSector(pos[VX], pos[VY], sec)) + continue; + } + + if(NULL != (d = R_CreateSurfaceDecoration(DT_LIGHT, suf))) + { + V3_Copy(d->pos, pos); + d->subsector = R_PointInSubsector(d->pos[VX], d->pos[VY]); + DEC_LIGHT(d)->def = def; + + R_SurfaceListAdd(decoratedSurfaceList, suf); + + num++; + } + } + } + + return num; +} + +static uint generateDecorModels(const ded_decormodel_t* def, + surface_t* suf, const pvec3_t v1, + const pvec3_t v2, float width, float height, + const pvec3_t delta, int axis, + float offsetS, float offsetT, sector_t* sec) +{ + uint num; + modeldef_t* mf; + float pitch, yaw; + float patternW, patternH; + float s, t; // Horizontal and vertical offset. + vec3_t posBase, pos; + int skip[2]; + + if(!R_IsValidModelDecoration(def)) + return 0; + + if((mf = R_CheckIDModelFor(def->id)) == NULL) + return 0; + + yaw = R_MovementYaw(suf->normal[VX], suf->normal[VY]); + if(axis == VZ) + yaw += 90; + pitch = R_MovementPitch(suf->normal[VX], suf->normal[VY], + suf->normal[VZ]); + + // Skip must be at least one. + getDecorationSkipPattern(def->patternSkip, skip); + patternW = suf->material->width * skip[0]; + patternH = suf->material->height * skip[1]; + + V3_Set(posBase, def->elevation * suf->normal[VX], + def->elevation * suf->normal[VY], + def->elevation * suf->normal[VZ]); + V3_Sum(posBase, posBase, v1); + + // Let's see where the top left light is. + s = M_CycleIntoRange(def->pos[0] - suf->visOffset[0] - + suf->material->width * def->patternOffset[0] + + offsetS, patternW); + num = 0; + for(; s < width; s += patternW) + { + t = M_CycleIntoRange(def->pos[1] - suf->visOffset[1] - + suf->material->height * def->patternOffset[1] + + offsetT, patternH); + + for(; t < height; t += patternH) + { + surfacedecor_t *d; + float offS = s / width, offT = t / height; + + V3_Set(pos, delta[VX] * offS, + delta[VY] * (axis == VZ? offT : offS), + delta[VZ] * (axis == VZ? offS : offT)); + V3_Sum(pos, posBase, pos); + + if(sec) + { + // The point must be inside the correct sector. + if(!R_IsPointInSector(pos[VX], pos[VY], sec)) + continue; + } + + if(NULL != (d = R_CreateSurfaceDecoration(DT_MODEL, suf))) + { + V3_Copy(d->pos, pos); + d->subsector = R_PointInSubsector(d->pos[VX], d->pos[VY]); + DEC_MODEL(d)->def = def; + DEC_MODEL(d)->mf = mf; + DEC_MODEL(d)->pitch = pitch; + DEC_MODEL(d)->yaw = yaw; + + R_SurfaceListAdd(decoratedSurfaceList, suf); + + num++; + } + } + } + + return num; +} + /** - * Generate decorations for the specified section of a sidedef. + * Generate decorations for the specified surface. */ -static void updateSideSectionDecorations(sidedef_t *side, - segsection_t section) +static void updateSurfaceDecorations(surface_t* suf, float offsetS, + float offsetT, vec3_t v1, vec3_t v2, + sector_t* sec, boolean visible) { - linedef_t* line = side->segs[0]->lineDef; - float bottom, top; - sector_t* highSector, *lowSector; - float frontCeil, frontFloor, backCeil, backFloor; - boolean visible = false; + vec3_t delta; + + R_ClearSurfaceDecorations(suf); + R_SurfaceListRemove(decoratedSurfaceList, suf); + + V3_Subtract(delta, v2, v1); + + if(visible && suf->material && + (delta[VX] * delta[VY] != 0 || + delta[VX] * delta[VZ] != 0 || + delta[VY] * delta[VZ] != 0)) + { + uint i; + float matW, matH, width, height; + int axis = V3_MajorAxis(suf->normal); + const ded_decor_t* def = R_MaterialGetDecoration(suf->material); + + if(def) + { + matW = suf->material->current->width; + matH = suf->material->current->height; + if(axis == VX || axis == VY) + { + width = sqrt(delta[VX] * delta[VX] + delta[VY] * delta[VY]); + height = delta[VZ]; + } + else + { + width = sqrt(delta[VX] * delta[VX]); + height = delta[VY]; + } + if(width < 0) + width = -width; + if(height < 0) + height = -height; + + // Generate a number of models. + for(i = 0; i < DED_DECOR_NUM_MODELS; ++i) + { + generateDecorModels(&def->models[i], suf, v1, v2, width, + height, delta, axis, offsetS, offsetT, + sec); + } + + // Generate a number of lights. + for(i = 0; i < DED_DECOR_NUM_LIGHTS; ++i) + { + generateDecorLights(&def->lights[i], suf, v1, v2, width, + height, delta, axis, offsetS, offsetT, + sec); + } + } + } + + suf->flags &= ~SUF_UPDATE_DECORATIONS; +} + +/** + * Generate decorations for a plane. + */ +static void updatePlaneDecorations(plane_t* pln) +{ + sector_t* sec = pln->sector; + surface_t* suf = &pln->surface; + vec3_t v1, v2; + float offsetS, offsetT; + + if(pln->type == PLN_FLOOR) + { + V3_Set(v1, sec->bBox[BOXLEFT], sec->bBox[BOXTOP], pln->visHeight); + V3_Set(v2, sec->bBox[BOXRIGHT], sec->bBox[BOXBOTTOM], pln->visHeight); + } + else + { + V3_Set(v1, sec->bBox[BOXLEFT], sec->bBox[BOXBOTTOM], pln->visHeight); + V3_Set(v2, sec->bBox[BOXRIGHT], sec->bBox[BOXTOP], pln->visHeight); + } + + offsetS = -fmod(sec->bBox[BOXLEFT], 64); + offsetT = -fmod(sec->bBox[BOXBOTTOM], 64); + + updateSurfaceDecorations(suf, offsetS, offsetT, v1, v2, sec, true); +} + +static void updateSideSectionDecorations(sidedef_t* side, segsection_t section) +{ + linedef_t* line; surface_t* suf; + vec3_t v1, v2; + float offsetS, offsetT; + boolean visible = false; + sector_t* highSector, *lowSector; + float frontCeil, frontFloor, backCeil, backFloor, bottom, + top; + if(!side->segs || !side->segs[0]) + return; + + line = side->segs[0]->lineDef; frontCeil = line->L_frontsector->SP_ceilvisheight; frontFloor = line->L_frontsector->SP_floorvisheight; @@ -489,360 +736,58 @@ static void updateSideSectionDecorations(sidedef_t *side, break; } - R_ClearSurfaceDecorations(suf); - R_SurfaceListRemove(decoratedSurfaceList, suf); - - // Is this a valid section? - if(visible && suf->material && bottom < top && line->length > 0) + if(visible && suf->material) { - float lh, s, t; // Horizontal and vertical offset. - float posBase[2], pos[3]; - float surfTexW, surfTexH, patternW, patternH; - int skip[2]; - uint i; - vertex_t* v[2]; - float delta[2]; - float offsetY; - const ded_decor_t* def = R_MaterialGetDecoration(suf->material); - - if(def) + if(line->L_backside) { - if(line->L_backside) + if(suf == &side->SW_topsurface) { - if(suf == &side->SW_topsurface) + if(line->flags & DDLF_DONTPEGTOP) { - if(line->flags & DDLF_DONTPEGTOP) - { - offsetY = 0; - } - else - { - offsetY = -suf->material->current->height + (top - bottom); - } + offsetT = 0; } - else // Its a bottom section. + else { - if(line->flags & DDLF_DONTPEGBOTTOM) - offsetY = (top - bottom); - else - offsetY = 0; + offsetT = -suf->material->current->height + (top - bottom); } } - else + else // Its a bottom section. { if(line->flags & DDLF_DONTPEGBOTTOM) - { - offsetY = -suf->material->current->height + (top - bottom); - } + offsetT = (top - bottom); else - { - offsetY = 0; - } + offsetT = 0; } - - // Let's see which sidedef is present. - if(line->L_backside && line->L_backside == side) + } + else + { + if(line->flags & DDLF_DONTPEGBOTTOM) { - // Flip vertices, this is the backside. - v[0] = line->L_v2; - v[1] = line->L_v1; + offsetT = -suf->material->current->height + (top - bottom); } else { - v[0] = line->L_v1; - v[1] = line->L_v2; - } - - delta[VX] = v[1]->V_pos[VX] - v[0]->V_pos[VX]; - delta[VY] = v[1]->V_pos[VY] - v[0]->V_pos[VY]; - - // Height of the section. - lh = top - bottom; - - // Setup the global texture info variables. - surfTexW = suf->material->current->width; - surfTexH = suf->material->current->height; - - // Generate a number of models. - for(i = 0; i < DED_DECOR_NUM_MODELS; ++i) - { - const ded_decormodel_t* modelDef = &def->models[i]; - modeldef_t* mf; - float pitch, yaw; - - if(!R_IsValidModelDecoration(modelDef)) - break; - - if((mf = R_CheckIDModelFor(modelDef->id)) == NULL) - break; - - yaw = R_MovementYaw(suf->normal[VX], suf->normal[VY]); - pitch = R_MovementPitch(suf->normal[VX], suf->normal[VY], - suf->normal[VZ]); - - // Skip must be at least one. - getDecorationSkipPattern(modelDef->patternSkip, skip); - - posBase[VX] = v[0]->V_pos[VX] + modelDef->elevation * suf->normal[VX]; - posBase[VY] = v[0]->V_pos[VY] + modelDef->elevation * suf->normal[VY]; - - patternW = surfTexW * skip[VX]; - patternH = surfTexH * skip[VY]; - - // Let's see where the top left light is. - s = M_CycleIntoRange(modelDef->pos[VX] - suf->visOffset[VX] - - surfTexW * modelDef->patternOffset[VX], - patternW); - - for(; s < line->length; s += patternW) - { - subsector_t *subsector; - - t = M_CycleIntoRange(modelDef->pos[VY] - suf->visOffset[VY] - - surfTexH * modelDef->patternOffset[VY] + - offsetY, patternH); - - pos[VX] = posBase[VX] + delta[VX] * s / line->length; - pos[VY] = posBase[VY] + delta[VY] * s / line->length; - subsector = R_PointInSubsector(pos[VX], pos[VY]); - - for(; t < lh; t += patternH) - { - surfacedecor_t *d; - - pos[VZ] = top - t; - - if(NULL != (d = R_CreateSurfaceDecoration(DT_MODEL, suf))) - { - d->pos[VX] = pos[VX]; - d->pos[VY] = pos[VY]; - d->pos[VZ] = pos[VZ]; - d->subsector = subsector; - - DEC_MODEL(d)->mf = mf; - DEC_MODEL(d)->def = modelDef; - DEC_MODEL(d)->pitch = pitch; - DEC_MODEL(d)->yaw = yaw; - R_SurfaceListAdd(decoratedSurfaceList, suf); - } - } - } - } - - // Generate a number of lights. - for(i = 0; i < DED_DECOR_NUM_LIGHTS; ++i) - { - const ded_decorlight_t* lightDef = def->lights + i; - - // No more? - if(!R_IsValidLightDecoration(lightDef)) - break; - - // Skip must be at least one. - getDecorationSkipPattern(lightDef->patternSkip, skip); - - posBase[VX] = v[0]->V_pos[VX] + lightDef->elevation * suf->normal[VX]; - posBase[VY] = v[0]->V_pos[VY] + lightDef->elevation * suf->normal[VZ]; - - patternW = surfTexW * skip[VX]; - patternH = surfTexH * skip[VY]; - - // Let's see where the top left light is. - s = M_CycleIntoRange(lightDef->pos[VX] - suf->visOffset[VX] - - surfTexW * lightDef->patternOffset[VX], - patternW); - - for(; s < line->length; s += patternW) - { - subsector_t *subsector; - - t = M_CycleIntoRange(lightDef->pos[VY] - suf->visOffset[VY] - - surfTexH * lightDef->patternOffset[VY] + - offsetY, patternH); - - pos[VX] = posBase[VX] + delta[VX] * s / line->length; - pos[VY] = posBase[VY] + delta[VY] * s / line->length; - subsector = R_PointInSubsector(pos[VX], pos[VY]); - - for(; t < lh; t += patternH) - { - surfacedecor_t *d; - - pos[VZ] = top - t; - - if(NULL != (d = R_CreateSurfaceDecoration(DT_LIGHT, suf))) - { - d->pos[VX] = pos[VX]; - d->pos[VY] = pos[VY]; - d->pos[VZ] = pos[VZ]; - d->subsector = subsector; - - DEC_LIGHT(d)->def = lightDef; - R_SurfaceListAdd(decoratedSurfaceList, suf); - } - } - } + offsetT = 0; } } - } - - suf->flags &= ~SUF_UPDATE_DECORATIONS; -} -/** - * Generate decorations for a plane. - */ -static void updatePlaneDecorations(plane_t* pln) -{ - uint i; - sector_t* sec = pln->sector; - surface_t* suf = &pln->surface; - float pos[3], tileSize = 64; - int skip[2]; - const ded_decor_t* def; - - R_ClearSurfaceDecorations(suf); - R_SurfaceListRemove(decoratedSurfaceList, suf); - - def = R_MaterialGetDecoration(pln->PS_material); - if(def) - { - // Generate a number of models. - for(i = 0; i < DED_DECOR_NUM_MODELS; ++i) + // Let's see which sidedef is present. + if(line->L_backside && line->L_backside == side) { - const ded_decormodel_t* modelDef = &def->models[i]; - modeldef_t* mf; - float pitch, yaw; - - if(!R_IsValidModelDecoration(modelDef)) - break; - - if((mf = R_CheckIDModelFor(modelDef->id)) == NULL) - break; - - yaw = 90 + R_MovementYaw(suf->normal[VX], - suf->normal[VY]); - pitch = R_MovementPitch(suf->normal[VX], suf->normal[VY], - suf->normal[VZ]); - - // Skip must be at least one. - getDecorationSkipPattern(modelDef->patternSkip, skip); - - pos[VY] = - (int) (sec->bBox[BOXBOTTOM] / tileSize) * tileSize - pln->PS_visoffset[VY] - - modelDef->pos[VY] - modelDef->patternOffset[VY] * tileSize; - - while(pos[VY] > sec->bBox[BOXBOTTOM]) - pos[VY] -= tileSize * skip[VY]; - - for(; pos[VY] < sec->bBox[BOXTOP]; pos[VY] += tileSize * skip[VY]) - { - if(pos[VY] < sec->bBox[BOXBOTTOM]) - continue; - - pos[VX] = - (int) (sec->bBox[BOXLEFT] / tileSize) * tileSize - pln->PS_visoffset[VX] + - modelDef->pos[VX] - modelDef->patternOffset[VX] * tileSize; - - while(pos[VX] > sec->bBox[BOXLEFT]) - pos[VX] -= tileSize * skip[VX]; - - for(; pos[VX] < sec->bBox[BOXRIGHT]; - pos[VX] += tileSize * skip[VX]) - { - surfacedecor_t *d; - - if(pos[VX] < sec->bBox[BOXLEFT]) - continue; - - // The point must be inside the correct sector. - if(!R_IsPointInSector(pos[VX], pos[VY], sec)) - continue; - - pos[VZ] = - pln->visHeight + modelDef->elevation * suf->normal[VZ]; - - if(NULL != (d = R_CreateSurfaceDecoration(DT_MODEL, suf))) - { - d->pos[VX] = pos[VX]; - d->pos[VY] = pos[VY]; - d->pos[VZ] = pos[VZ]; - d->subsector = R_PointInSubsector(d->pos[VX], d->pos[VY]); - - DEC_MODEL(d)->def = modelDef; - DEC_MODEL(d)->mf = mf; - DEC_MODEL(d)->pitch = pitch; - DEC_MODEL(d)->yaw = yaw; - - R_SurfaceListAdd(decoratedSurfaceList, suf); - } - } - } + // Flip vertices, this is the backside. + V3_Set(v1, line->L_v2pos[VX], line->L_v2pos[VY], top); + V3_Set(v2, line->L_v1pos[VX], line->L_v1pos[VY], bottom); } - - // Generate a number of lights. - for(i = 0; i < DED_DECOR_NUM_LIGHTS; ++i) + else { - const ded_decorlight_t* lightDef = &def->lights[i]; - - // No more? - if(!R_IsValidLightDecoration(lightDef)) - break; - - // Skip must be at least one. - getDecorationSkipPattern(lightDef->patternSkip, skip); - - pos[VY] = - (int) (sec->bBox[BOXBOTTOM] / tileSize) * tileSize - pln->PS_visoffset[VY] - - lightDef->pos[VY] - lightDef->patternOffset[VY] * tileSize; - - while(pos[VY] > sec->bBox[BOXBOTTOM]) - pos[VY] -= tileSize * skip[VY]; - - for(; pos[VY] < sec->bBox[BOXTOP]; pos[VY] += tileSize * skip[VY]) - { - if(pos[VY] < sec->bBox[BOXBOTTOM]) - continue; - - pos[VX] = - (int) (sec->bBox[BOXLEFT] / tileSize) * tileSize - pln->PS_visoffset[VX] + - lightDef->pos[VX] - lightDef->patternOffset[VX] * tileSize; - - while(pos[VX] > sec->bBox[BOXLEFT]) - pos[VX] -= tileSize * skip[VX]; - - for(; pos[VX] < sec->bBox[BOXRIGHT]; - pos[VX] += tileSize * skip[VX]) - { - surfacedecor_t *d; - - if(pos[VX] < sec->bBox[BOXLEFT]) - continue; - - // The point must be inside the correct sector. - if(!R_IsPointInSector(pos[VX], pos[VY], sec)) - continue; - - pos[VZ] = - pln->visHeight + lightDef->elevation * suf->normal[VZ]; - - if(NULL != (d = R_CreateSurfaceDecoration(DT_LIGHT, suf))) - { - d->pos[VX] = pos[VX]; - d->pos[VY] = pos[VY]; - d->pos[VZ] = pos[VZ]; - d->subsector = R_PointInSubsector(d->pos[VX], d->pos[VY]); - - DEC_LIGHT(d)->def = lightDef; - - R_SurfaceListAdd(decoratedSurfaceList, suf); - } - } - } + V3_Set(v1, line->L_v1pos[VX], line->L_v1pos[VY], top); + V3_Set(v2, line->L_v2pos[VX], line->L_v2pos[VY], bottom); } } - suf->flags &= ~SUF_UPDATE_DECORATIONS; + offsetS = 0; + + updateSurfaceDecorations(suf, offsetS, offsetT, v1, v2, NULL, visible); } void Rend_UpdateSurfaceDecorations(void) diff --git a/doomsday/engine/portable/src/rend_dyn.c b/doomsday/engine/portable/src/rend_dyn.c index b26a865c9c..4e9c16110f 100644 --- a/doomsday/engine/portable/src/rend_dyn.c +++ b/doomsday/engine/portable/src/rend_dyn.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "de_base.h" #include "de_console.h" @@ -46,10 +47,15 @@ // TYPES ------------------------------------------------------------------- typedef struct dynnode_s { - struct dynnode_s *next, *nextUsed; + struct dynnode_s* next, *nextUsed; dynlight_t dyn; } dynnode_t; +typedef struct dynlist_s { + boolean sortBrightestFirst; + dynnode_t* head; +} dynlist_t; + // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -60,21 +66,22 @@ typedef struct dynnode_s { // PUBLIC DATA DEFINITIONS ------------------------------------------------- -int useDynLights = true, dlBlend = 0; -float dlFactor = 0.7f; // was 0.6f -int useWallGlow = true; -float glowHeightFactor = 3; // glow height as a multiplier -int glowHeightMax = 100; // 100 is the default (0-1024) -float glowFogBright = .15f; +int useDynLights = true, dlBlend = 0; +float dlFactor = .7f; +float dlFogBright = .15f; + +int useWallGlow = true; +float glowHeightFactor = 3; // Glow height as a multiplier. +int glowHeightMax = 100; // 100 is the default (0-1024). // PRIVATE DATA DEFINITIONS ------------------------------------------------ // Dynlight nodes. -static dynnode_t *dynFirst, *dynCursor; +static dynnode_t* dynFirst, *dynCursor; // Surface light link lists. static uint numDynlightLinkLists = 0, dynlightLinkListCursor = 0; -static dynnode_t **dynlightLinkLists; +static dynlist_t* dynlightLinkLists; // CODE -------------------------------------------------------------------- @@ -85,18 +92,28 @@ void DL_Register(void) C_VAR_INT("rend-glow-wall", &useWallGlow, 0, 0, 1); C_VAR_INT("rend-glow-height", &glowHeightMax, 0, 0, 1024); C_VAR_FLOAT("rend-glow-scale", &glowHeightFactor, 0, 0.1f, 10); - C_VAR_FLOAT("rend-glow-fog-bright", &glowFogBright, 0, 0, 1); C_VAR_INT("rend-light", &useDynLights, 0, 0, 1); C_VAR_INT("rend-light-blend", &dlBlend, 0, 0, 2); - C_VAR_FLOAT("rend-light-bright", &dlFactor, 0, 0, 1); + C_VAR_FLOAT("rend-light-fog-bright", &dlFogBright, 0, 0, 1); C_VAR_INT("rend-light-multitex", &useMultiTexLights, 0, 0, 1); + C_VAR_INT("rend-mobj-light-auto", &useMobjAutoLights, 0, 0, 1); LO_Register(); Rend_DecorRegister(); } +/** + * Initialize the dynlight system in preparation for rendering view(s) of the + * game world. Called by R_InitLevel(). + */ +void DL_InitForMap(void) +{ + dynlightLinkLists = NULL; + numDynlightLinkLists = 0, dynlightLinkListCursor = 0; +} + /** * Moves all used dynlight nodes to the list of unused nodes, so they * can be reused. @@ -109,12 +126,44 @@ void DL_InitForNewFrame(void) // Clear the surface light link lists. dynlightLinkListCursor = 0; if(numDynlightLinkLists) - memset(dynlightLinkLists, 0, numDynlightLinkLists * sizeof(dynnode_t*)); + memset(dynlightLinkLists, 0, numDynlightLinkLists * sizeof(dynlist_t)); +} + +/** + * Create a new dynlight list. + * + * @param sortBrightestFirst Nodes in the list will be auto-sorted when + * added by the brightness of the associated dynlight + * in descending order. + * @return Identifier for the new list. + */ +static uint newDynlightList(boolean sortBrightestFirst) +{ + dynlist_t* list; + + // Ran out of light link lists? + if(++dynlightLinkListCursor >= numDynlightLinkLists) + { + uint newNum = numDynlightLinkLists * 2; + + if(!newNum) + newNum = 2; + + dynlightLinkLists = + Z_Realloc(dynlightLinkLists, newNum * sizeof(dynlist_t), PU_LEVEL); + numDynlightLinkLists = newNum; + } + + list = &dynlightLinkLists[dynlightLinkListCursor-1]; + list->head = NULL; + list->sortBrightestFirst = sortBrightestFirst; + + return dynlightLinkListCursor - 1; } -static dynnode_t *newDynNode(void) +static dynnode_t* newDynNode(void) { - dynnode_t *node; + dynnode_t* node; // Have we run out of nodes? if(dynCursor == NULL) @@ -132,17 +181,17 @@ static dynnode_t *newDynNode(void) } node->next = NULL; - return node; + return node; } /** * Returns a new dynlight node. If the list of unused nodes is empty, * a new node is created. */ -static dynnode_t *newDynLight(float *s, float *t) +static dynnode_t* newDynLight(float* s, float* t) { - dynnode_t *node = newDynNode(); - dynlight_t *dyn = &node->dyn; + dynnode_t* node = newDynNode(); + dynlight_t* dyn = &node->dyn; if(s) { @@ -158,27 +207,17 @@ static dynnode_t *newDynLight(float *s, float *t) return node; } -/** - * Link the given dynlight node to list. - */ -static void __inline linkDynNode(dynnode_t *node, dynnode_t **list, uint index) -{ - node->next = list[index]; - list[index] = node; -} - -static void linkToSurfaceLightList(dynnode_t *node, uint listIndex, - boolean sortBrightestFirst) +static void linkDynNodeToList(dynnode_t* node, uint listIndex) { - dynnode_t **list = &dynlightLinkLists[listIndex]; + dynlist_t* list = &dynlightLinkLists[listIndex]; - if(sortBrightestFirst && *list) + if(list->sortBrightestFirst && list->head) { - float light = - (node->dyn.color[0] + node->dyn.color[1] + node->dyn.color[2]) / 3; - dynnode_t *last, *iter; + float light = (node->dyn.color[0] + + node->dyn.color[1] + node->dyn.color[2]) / 3; + dynnode_t* last, *iter; - last = iter = *list; + last = iter = list->head; do { // Is this brighter than the one being added? @@ -197,8 +236,8 @@ static void linkToSurfaceLightList(dynnode_t *node, uint listIndex, } while(iter); } - node->next = *list; - *list = node; + node->next = list->head; + list->head = node; } /** @@ -209,7 +248,7 @@ static void linkToSurfaceLightList(dynnode_t *node, uint listIndex, * @param lum Ptr to the lumobj from which the color will be used. * @param light The light value to be used in the calculation. */ -static void calcDynLightColor(float *outRGB, const lumobj_t *lum, float light) +static void calcDynLightColor(float* outRGB, const float* inRGB, float light) { uint i; @@ -219,28 +258,18 @@ static void calcDynLightColor(float *outRGB, const lumobj_t *lum, float light) light = 1; light *= dlFactor; - // If fog is enabled, make the light dimmer. - // \fixme This should be a cvar. + // In fog, additive blending is used. The normal fog color + // is way too bright. if(usingFog) - light *= .5f; // Would be too much. + light *= dlFogBright; // Would be too much. // Multiply with the light color. for(i = 0; i < 3; ++i) { - outRGB[i] = light * lum->color[i]; + outRGB[i] = light * inRGB[i]; } } -/** - * Initialize the dynlight system in preparation for rendering view(s) of the - * game world. Called by R_InitLevel(). - */ -void DL_InitForMap(void) -{ - dynlightLinkLists = NULL; - numDynlightLinkLists = 0, dynlightLinkListCursor = 0; -} - /** * Project the given planelight onto the specified seg. If it would be lit, * a new dynlight node will be created and returned. @@ -251,21 +280,15 @@ void DL_InitForMap(void) * * @return Ptr to the projected light, ELSE @c NULL. */ -static dynnode_t *projectPlaneGlowOnSegSection(const lumobj_t *lum, float bottom, - float top) +static dynnode_t* projectPlaneGlowOnSegSection(const lumobj_t* lum, + float bottom, float top) { - uint i; float glowHeight; - dynlight_t *dyn; - dynnode_t *node; float s[2], t[2]; if(bottom >= top) return NULL; // No height. - if(!LUM_PLANE(lum)->tex) - return NULL; - glowHeight = (MAX_GLOWHEIGHT * LUM_PLANE(lum)->intensity) * glowHeightFactor; @@ -281,260 +304,207 @@ static dynnode_t *projectPlaneGlowOnSegSection(const lumobj_t *lum, float bottom { // Light is cast downwards. t[1] = t[0] = (lum->pos[VZ] - top) / glowHeight; t[1]+= (top - bottom) / glowHeight; - - if(t[0] > 1 || t[1] < 0) - return NULL; } else { // Light is cast upwards. t[0] = t[1] = (bottom - lum->pos[VZ]) / glowHeight; t[0]+= (top - bottom) / glowHeight; - - if(t[1] > 1 || t[0] < 0) - return NULL; } + if(!(t[0] <= 1 || t[1] >= 0)) + return NULL; // Is above/below on the Y axis. + // The horizontal direction is easy. s[0] = 0; s[1] = 1; - node = newDynLight(s, t); - dyn = &node->dyn; - dyn->texture = LUM_PLANE(lum)->tex; - - for(i = 0; i < 3; ++i) - { - dyn->color[i] = lum->color[i] * dlFactor; - - // In fog, additive blending is used. The normal fog color - // is way too bright. - if(usingFog) - dyn->color[i] *= glowFogBright; - } - - return node; -} - -/** - * Project the given omnilight onto the specified seg. If it would be lit, a new - * dynlight node will be created and returned. - * - * @param lum Ptr to the lumobj lighting the seg. - * @param seg Ptr to the seg being lit. - * @param bottom Z height (bottom) of the section being lit. - * @param top Z height (top) of the section being lit. - * - * @return Ptr to the projected light, ELSE @c NULL. - */ -static dynnode_t *projectOmniLightOnSegSection(const lumobj_t *lum, seg_t *seg, - float bottom, float top) -{ - float s[2], t[2]; - float dist, pntLight[2]; - dynlight_t *dyn; - dynnode_t *node; - float lumRGB[3], lightVal; - float radius, radiusX2; - - if(!LUM_OMNI(lum)->tex) - return NULL; - - radius = LUM_OMNI(lum)->radius / DYN_ASPECT; - radiusX2 = 2 * radius; - - if(bottom >= top || radiusX2 == 0) - return NULL; - - // Clip to the valid z height range first. - t[0] = (lum->pos[VZ] + LUM_OMNI(lum)->zOff + radius - top) / radiusX2; - t[1] = t[0] + (top - bottom) / radiusX2; - - if(!(t[0] < 1 && t[1] > 0)) - return NULL; - - pntLight[VX] = lum->pos[VX]; - pntLight[VY] = lum->pos[VY]; - - // Calculate 2D distance between seg and light source. - dist = ((seg->SG_v1pos[VY] - pntLight[VY]) * (seg->SG_v2pos[VX] - seg->SG_v1pos[VX]) - - (seg->SG_v1pos[VX] - pntLight[VX]) * (seg->SG_v2pos[VY] - seg->SG_v1pos[VY])) - / seg->length; - - // Is it close enough and on the right side? - if(dist < 0 || dist > LUM_OMNI(lum)->radius) - return NULL; // Nope. - - lightVal = LUM_FACTOR(dist, LUM_OMNI(lum)->radius); - - if(lightVal < .05f) - return NULL; // Too dim to see. - - // Do a scalar projection for the offset. - s[0] = (-((seg->SG_v1pos[VY] - pntLight[VY]) * (seg->SG_v1pos[VY] - seg->SG_v2pos[VY]) - - (seg->SG_v1pos[VX] - pntLight[VX]) * (seg->SG_v2pos[VX] - seg->SG_v1pos[VX])) - / seg->length + - LUM_OMNI(lum)->radius) / (2 * LUM_OMNI(lum)->radius); - - s[1] = s[0] + seg->length / (2 * LUM_OMNI(lum)->radius); - - // Would the light be visible? - if(s[0] >= 1 || s[1] <= 0) - return NULL; // Is left/right of the seg on the X/Y plane. - - calcDynLightColor(lumRGB, lum, lightVal); - - node = newDynLight(s, t); - dyn = &node->dyn; - memcpy(dyn->color, lumRGB, sizeof(float) * 3); - dyn->texture = LUM_OMNI(lum)->tex; - - return node; + return newDynLight(s, t); } /** - * Process the given lumobj to maybe add a dynamic light for the plane. + * Given a normalized normal, construct up and right vectors, oriented to + * the original normal. Note all vectors and normals are in world-space. * - * @param lum Ptr to the lumobj on which the dynlight will be based. + * @param up The up vector will be written back here. + * @param right The right vector will be written back here. + * @param normal Normal to construct vectors for. */ -static dynnode_t *projectOmniLightOnSubSectorPlane(const lumobj_t *lum, - float normal[3], - float height) +static void buildUpRight(pvec3_t up, pvec3_t right, const pvec3_t normal) { - DGLuint lightTex; - float diff, lightStrength, srcRadius; - float s[2], t[2]; - float pos[3]; - - pos[VX] = lum->pos[VX]; - pos[VY] = lum->pos[VY]; - pos[VZ] = lum->pos[VZ]; - - // Center the Z. - pos[VZ] += LUM_OMNI(lum)->zOff; - srcRadius = LUM_OMNI(lum)->radius / 4; - if(srcRadius == 0) - srcRadius = 1; - - // Determine on which side of the plane the light is. - lightTex = 0; - lightStrength = 0; - - if(normal[VZ] > 0) - { - if((lightTex = LUM_OMNI(lum)->floorTex) != 0) + const vec3_t rotm[3] = { + {0.f, 0.f, 1.f}, + {0.f, 0.f, 1.f}, + {0.f, 0.f, 1.f} + }; + int axis = VX; + vec3_t fn; + + V3_Set(fn, fabsf(normal[VX]), fabsf(normal[VY]), fabsf(normal[VZ])); + + if(fn[VY] > fn[axis]) + axis = VY; + if(fn[VZ] > fn[axis]) + axis = VZ; + + if(fabsf(fn[VX] - 1.0f) < FLT_EPSILON || + fabsf(fn[VY] - 1.0f) < FLT_EPSILON || + fabsf(fn[VZ] - 1.0f) < FLT_EPSILON) + { // We must build the right vector manually. + if(axis == VX && normal[VX] > 0.f) { - if(pos[VZ] > height) - lightStrength = 1; - else if(pos[VZ] > height - srcRadius) - lightStrength = 1 - (height - pos[VZ]) / srcRadius; + V3_Set(right, 0.f, 1.f, 0.f); } - } - else - { - if((lightTex = LUM_OMNI(lum)->ceilTex) != 0) + else if(axis == VX) { - if(pos[VZ] < height) - lightStrength = 1; - else if(pos[VZ] < height + srcRadius) - lightStrength = 1 - (pos[VZ] - height) / srcRadius; + V3_Set(right, 0.f, -1.f, 0.f); } - } - - // Is there light in this direction? Is it strong enough? - if(!lightTex || !lightStrength) - return NULL; - // Check that the height difference is tolerable. - if(normal[VZ] > 0) - diff = pos[VZ] - height; - else - diff = height - pos[VZ]; - - // Clamp it. - if(diff < 0) - diff = 0; - - if(diff < LUM_OMNI(lum)->radius) - { - float lightVal = - LUM_FACTOR(diff, LUM_OMNI(lum)->radius); + if(axis == VY && normal[VY] > 0.f) + { + V3_Set(right, -1.f, 0.f, 0.f); + } + else if(axis == VY) + { + V3_Set(right, 1.f, 0.f, 0.f); + } - if(lightVal >= .05f) + if(axis == VZ) { - dynlight_t *dyn; - dynnode_t *node; - - // Calculate dynlight position. It may still be outside - // the bounding box the subsector. - s[0] = -pos[VX] + LUM_OMNI(lum)->radius; - t[0] = pos[VY] + LUM_OMNI(lum)->radius; - s[1] = t[1] = 1.0f / (2 * LUM_OMNI(lum)->radius); - - // A dynamic light will be generated. - node = newDynLight(s, t); - dyn = &node->dyn; - dyn->texture = lightTex; - - calcDynLightColor(dyn->color, lum, lightVal * lightStrength); - return node; + V3_Set(right, 1.f, 0.f, 0.f); } } + else + { // Can use a cross product of the surface normal. + V3_CrossProduct(right, (const pvec3_t) rotm[axis], normal); + V3_Normalize(right); + } - return NULL; + V3_CrossProduct(up, right, normal); + V3_Normalize(up); } -static uint newDynlightList(void) +/** + * Generate texcoords on surface centered on point. + * + * @param point Point on surface around which texture is centered. + * @param scale Scale multiplier for texture. + * @param s Texture s coords written back here. + * @param t Texture t coords written back here. + * @param v1 Top left vertex of the surface being projected on. + * @param v2 Bottom right vertex of the surface being projected on. + * @param normal Normal of the surface being projected on. + * + * @return @c true, if the generated coords are within bounds. + */ +static boolean genTexCoords(const pvec3_t point, float scale, + pvec2_t s, pvec2_t t, const pvec3_t v1, + const pvec3_t v2, const pvec3_t normal) { - // Ran out of light link lists? - if(++dynlightLinkListCursor >= numDynlightLinkLists) - { - uint i; - uint newNum = numDynlightLinkLists * 2; - dynnode_t **newList; + vec3_t vToPoint, right, up; - if(!newNum) - newNum = 2; + buildUpRight(up, right, normal); + V3_Subtract(vToPoint, v1, point); + s[0] = V3_DotProduct(vToPoint, right) * scale + .5f; + t[0] = V3_DotProduct(vToPoint, up) * scale + .5f; - newList = Z_Calloc(newNum * sizeof(dynnode_t*), PU_LEVEL, 0); + V3_Subtract(vToPoint, v2, point); + s[1] = V3_DotProduct(vToPoint, right) * scale + .5f; + t[1] = V3_DotProduct(vToPoint, up) * scale + .5f; - // Copy existing links. - for(i = 0; i < dynlightLinkListCursor - 1; ++i) - { - newList[i] = dynlightLinkLists[i]; - } + // Would the light be visible? + if(!(s[0] <= 1 || s[1] >= 0)) + return false; // Is right/left on the X axis. - if(dynlightLinkLists) - Z_Free(dynlightLinkLists); - dynlightLinkLists = newList; - numDynlightLinkLists = newNum; - } + if(!(t[0] <= 1 || t[1] >= 0)) + return false; // Is above/below on the Y axis. - return dynlightLinkListCursor - 1; + return true; } -typedef struct seglumobjiterparams_s { - seg_t *seg; - float bottom, top; +typedef struct surfacelumobjiterparams_s { + vec3_t v1, v2; + vec3_t normal; boolean sortBrightestFirst; boolean haveList; uint listIdx; -} seglumobjiterparams_t; + boolean isPlane; + byte useTex; /* For omni lights: + @c 0 = side tex, @c 1 = floortex, @c 2 = ceiltex. */ +} surfacelumobjiterparams_t; -boolean DLIT_SegLumobjContacts(void *ptr, void *data) +boolean DLIT_SurfaceLumobjContacts(void* ptr, void* data) { - lumobj_t *lum = (lumobj_t*) ptr; - dynnode_t *node = NULL; - seglumobjiterparams_t *params = data; + lumobj_t* lum = (lumobj_t*) ptr; + dynnode_t* node = NULL; + surfacelumobjiterparams_t* params = data; + DGLuint tex = 0; + float lightBrightness = 1; + float* lightRGB; + + if(!(lum->type == LT_OMNI || lum->type == LT_PLANE)) + return true; // Continue iteration. switch(lum->type) { case LT_OMNI: - node = projectOmniLightOnSegSection(lum, params->seg, - params->bottom, params->top); + switch(params->useTex) + { + case 0: + default: tex = LUM_OMNI(lum)->tex; break; + case 1: tex = LUM_OMNI(lum)->floorTex; break; + case 2: tex = LUM_OMNI(lum)->ceilTex; break; + } + + lightRGB = LUM_OMNI(lum)->color; + + if(tex) + { + vec3_t lumCenter, vToLum; + + V3_Set(lumCenter, lum->pos[VX], lum->pos[VY], + lum->pos[VZ] + LUM_OMNI(lum)->zOff); + + // On the right side? + V3_Subtract(vToLum, params->v1, lumCenter); + if(V3_DotProduct(vToLum, params->normal) < 0.f) + { + float dist; + vec3_t point; + + // Calculate 3D distance between surface and lumobj. + V3_ClosestPointOnPlane(point, params->normal, params->v1, lumCenter); + dist = V3_Distance(point, lumCenter); + if(dist > 0 && dist <= LUM_OMNI(lum)->radius) + { + lightBrightness = LUM_FACTOR(dist, LUM_OMNI(lum)->radius); + + if(lightBrightness >= .05f) + { + vec2_t s, t; + float scale = + 1.0f / ((2.f * LUM_OMNI(lum)->radius) - dist); + + if(genTexCoords(point, scale, s, t, params->v1, + params->v2, params->normal)) + { + node = newDynLight(s, t); + } + } + } + } + } break; case LT_PLANE: - node = projectPlaneGlowOnSegSection(lum, params->bottom, params->top); + if(!params->isPlane) // Plannar glows don't currently affect planes. + tex = LUM_PLANE(lum)->tex; + + if(tex) + { + lightRGB = LUM_PLANE(lum)->color; + + node = projectPlaneGlowOnSegSection(lum, params->v2[VZ], params->v1[VZ]); + } break; default: @@ -544,26 +514,46 @@ boolean DLIT_SegLumobjContacts(void *ptr, void *data) } if(node) - { // Got a list for this surface yet? + { + dynlight_t* dyn = &node->dyn; + + dyn->texture = tex; + calcDynLightColor(dyn->color, lightRGB, lightBrightness); + + // Got a list for this surface yet? if(!params->haveList) { - params->listIdx = newDynlightList(); + params->listIdx = + newDynlightList(params->sortBrightestFirst); params->haveList = true; } - linkToSurfaceLightList(node, params->listIdx, params->sortBrightestFirst); + linkDynNodeToList(node, params->listIdx); } return true; // Continue iteration. } +static uint processSubSector(subsector_t* ssec, surfacelumobjiterparams_t* params) +{ + // Process each lumobj contacting the subsector. + LO_IterateSubsectorContacts(ssec, DLIT_SurfaceLumobjContacts, params); + + // Did we generate a light list? + if(params->haveList) + return params->listIdx + 1; + + return 0; // Nope. +} + /** * Process dynamic lights for the specified seg. */ -uint DL_ProcessSegSection(seg_t *seg, float bottom, float top, +uint DL_ProcessSegSection(seg_t* seg, float bottom, float top, boolean sortBrightestFirst) { - seglumobjiterparams_t params; + sidedef_t* side; + surfacelumobjiterparams_t params; if(!useDynLights && !useWallGlow) return 0; // Disabled. @@ -571,76 +561,26 @@ uint DL_ProcessSegSection(seg_t *seg, float bottom, float top, if(!seg || !seg->subsector) return 0; - params.bottom = bottom; - params.top = top; - params.seg = seg; + side = SEG_SIDEDEF(seg); + + V3_Set(params.v1, seg->SG_v1pos[VX], seg->SG_v1pos[VY], top); + V3_Set(params.v2, seg->SG_v2pos[VX], seg->SG_v2pos[VY], bottom); + params.normal[VX] = side->SW_middlenormal[VX]; + params.normal[VY] = side->SW_middlenormal[VY]; + params.normal[VZ] = side->SW_middlenormal[VZ]; params.sortBrightestFirst = sortBrightestFirst; params.haveList = false; params.listIdx = 0; + params.useTex = 0; + params.isPlane = false; - // Process each lumobj contacting the subsector. - LO_IterateSubsectorContacts(seg->subsector, DLIT_SegLumobjContacts, - (void*) ¶ms); - - // Did we generate a light list? - if(params.haveList) - return params.listIdx + 1; - - return 0; // Nope. + return processSubSector(seg->subsector, ¶ms); } -typedef struct planelumobjiterparams_s { - float normal[3]; - float height; - boolean sortBrightestFirst; - boolean haveList; - uint listIdx; -} planelumobjiterparams_t; - -boolean DLIT_PlaneLumobjContacts(void *ptr, void *data) +uint DL_ProcessSubSectorPlane(subsector_t* ssec, uint plane) { - lumobj_t *lum = (lumobj_t*) ptr; - planelumobjiterparams_t *params = data; - dynnode_t *node = NULL; - - switch(lum->type) - { - case LT_OMNI: - node = projectOmniLightOnSubSectorPlane(lum, params->normal, - params->height); - break; - - case LT_PLANE: // Planar lights don't affect planes currently. - node = NULL; - break; - - default: - Con_Error("DLIT_PlaneLumobjContacts: Invalid value, lum->type = %i.", - (int) lum->type); - break; - } - - if(node) - { - // Got a list for this surface yet? - if(!params->haveList) - { - params->listIdx = newDynlightList(); - params->haveList = true; - } - - // Link to this plane's list. - linkToSurfaceLightList(node, params->listIdx, params->sortBrightestFirst); - } - - return true; // Continue iteration. -} - -uint DL_ProcessSubSectorPlane(subsector_t *ssec, uint plane) -{ - sector_t *linkSec; - float height; - boolean isLit; + plane_t* pln; + surfacelumobjiterparams_t params; if(!useDynLights && !useWallGlow) return 0; // Disabled. @@ -648,49 +588,35 @@ uint DL_ProcessSubSectorPlane(subsector_t *ssec, uint plane) if(!ssec) return 0; - // Sanity check. - assert(plane < ssec->sector->planeCount); + assert(plane < ssec->sector->planeCount); // Sanity check. - linkSec = R_GetLinkedSector(ssec, plane); - if(R_IsSkySurface(&linkSec->SP_planesurface(plane))) - return 0; + pln = R_GetLinkedSector(ssec, plane)->SP_plane(plane); - // View height might prevent us from seeing the light. - isLit = true; - height = linkSec->SP_planevisheight(plane); - if(linkSec->SP_plane(plane)->PS_normal[VZ] > 0) + if(pln->type == PLN_FLOOR) { - if(vy < height) - isLit = false; + V3_Set(params.v1, ssec->bBox[0].pos[VX], ssec->bBox[1].pos[VY], + pln->visHeight); + V3_Set(params.v2, ssec->bBox[1].pos[VX], ssec->bBox[0].pos[VY], + pln->visHeight); } else { - if(vy > height) - isLit = false; + V3_Set(params.v1, ssec->bBox[0].pos[VX], ssec->bBox[0].pos[VY], + pln->visHeight); + V3_Set(params.v2, ssec->bBox[1].pos[VX], ssec->bBox[1].pos[VY], + pln->visHeight); } - if(isLit) - { - planelumobjiterparams_t params; - - params.normal[VX] = linkSec->SP_plane(plane)->PS_normal[VX]; - params.normal[VY] = linkSec->SP_plane(plane)->PS_normal[VY]; - params.normal[VZ] = linkSec->SP_plane(plane)->PS_normal[VZ]; - params.height = height; - params.sortBrightestFirst = false; - params.haveList = false; - params.listIdx = 0; - - // Process each lumobj contacting the subsector. - LO_IterateSubsectorContacts(ssec, DLIT_PlaneLumobjContacts, - (void*) ¶ms); - - // Did we generate a light list? - if(params.haveList) - return params.listIdx + 1; - } + params.normal[VX] = pln->PS_normal[VX]; + params.normal[VY] = pln->PS_normal[VY]; + params.normal[VZ] = pln->PS_normal[VZ]; + params.sortBrightestFirst = false; + params.haveList = false; + params.listIdx = 0; + params.useTex = (pln->type == PLN_CEILING? 2 : 1); + params.isPlane = true; - return 0; // Nope. + return processSubSector(ssec, ¶ms); } /** @@ -702,17 +628,17 @@ uint DL_ProcessSubSectorPlane(subsector_t *ssec, uint plane) * * @return @c true, iff every callback returns @c true. */ -boolean DL_ListIterator(uint listIdx, void *data, - boolean (*func) (const dynlight_t *, void *data)) +boolean DL_ListIterator(uint listIdx, void* data, + boolean (*func) (const dynlight_t*, void*)) { - dynnode_t *node; + dynnode_t* node; boolean retVal, isDone; if(listIdx == 0 || listIdx > numDynlightLinkLists) return true; listIdx--; - node = dynlightLinkLists[listIdx]; + node = dynlightLinkLists[listIdx].head; retVal = true; isDone = false; while(node && !isDone) diff --git a/doomsday/engine/portable/src/rend_fakeradio.c b/doomsday/engine/portable/src/rend_fakeradio.c index 8822a1fc05..9b066d7f7a 100644 --- a/doomsday/engine/portable/src/rend_fakeradio.c +++ b/doomsday/engine/portable/src/rend_fakeradio.c @@ -651,6 +651,17 @@ static void renderShadowSeg(const rvertex_t* rvertices, params.tex.width = p->texWidth; params.tex.height = p->texHeight; params.tex.masked = false; + + // Top left. + params.texOrigin[0][VX] = rvertices[1].pos[VX]; + params.texOrigin[0][VY] = rvertices[1].pos[VY]; + params.texOrigin[0][VZ] = rvertices[1].pos[VZ]; + + // Bottom right. + params.texOrigin[1][VX] = rvertices[2].pos[VX]; + params.texOrigin[1][VY] = rvertices[2].pos[VY]; + params.texOrigin[1][VZ] = rvertices[2].pos[VZ]; + params.texOffset[VX] = p->texOffset[VX]; params.texOffset[VY] = p->texOffset[VY]; diff --git a/doomsday/engine/portable/src/rend_halo.c b/doomsday/engine/portable/src/rend_halo.c index b26da328e4..33ab7bfcfe 100644 --- a/doomsday/engine/portable/src/rend_halo.c +++ b/doomsday/engine/portable/src/rend_halo.c @@ -175,7 +175,7 @@ boolean H_RenderHalo(float x, float y, float z, lumobj_t *lum, return false; } - if((lum->flags & LUMF_NOHALO) || lum->distanceToViewer <= 0 || + if((LUM_OMNI(lum)->flags & LUMOF_NOHALO) || lum->distanceToViewer <= 0 || (haloFadeMax && lum->distanceToViewer > haloFadeMax)) return false; @@ -198,7 +198,7 @@ boolean H_RenderHalo(float x, float y, float z, lumobj_t *lum, leftOff[i] = viewUpVec[i] + viewSideVec[i]; rightOff[i] = viewUpVec[i] - viewSideVec[i]; // Convert the color to floating point. - color[i] = lum->color[i]; + color[i] = LUM_OMNI(lum)->color[i]; } // Setup the proper DGL state. @@ -238,7 +238,7 @@ boolean H_RenderHalo(float x, float y, float z, lumobj_t *lum, { // Now halopos is a normalized version of the mirror vector. // Both vectors are on the view plane. - if(!(lum->flags & LUMF_DONTTURNHALO)) + if(!(LUM_OMNI(lum)->flags & LUMOF_DONTTURNHALO)) { turnAngle = M_DotProduct(haloPos, viewUpVec); if(turnAngle > 1) @@ -394,7 +394,7 @@ boolean H_RenderHalo(float x, float y, float z, lumobj_t *lum, // take a hint... (or then something's changing the wrapping // mode inadvertently) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); + GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); diff --git a/doomsday/engine/portable/src/rend_list.c b/doomsday/engine/portable/src/rend_list.c index 0bdf98de62..fd53e9ad36 100644 --- a/doomsday/engine/portable/src/rend_list.c +++ b/doomsday/engine/portable/src/rend_list.c @@ -82,7 +82,7 @@ END_PROF_TIMERS() #define DCF_SET_LIGHT_ENV (DCF_SET_LIGHT_ENV0 | DCF_SET_LIGHT_ENV1) #define DCF_JUST_ONE_LIGHT 0x00000010 #define DCF_MANY_LIGHTS 0x00000020 -#define DCF_SET_BLEND_MODE 0x00000040 // primitive-specific blending +#define DCF_SET_BLEND_MODE 0x00000040 // Primitive-specific blending. #define DCF_SKIP 0x80000000 // TYPES ------------------------------------------------------------------- @@ -114,19 +114,19 @@ typedef enum listmode_e { // Types of rendering primitives. typedef enum primtype_e { - PT_TRIANGLE_STRIP, // Used for most stuff. + PT_TRIANGLE_STRIP, // Used for most stuff. PT_FAN, PT_DOUBLE_FAN, } primtype_t; // Texture coordinate array indices. enum { - TCA_MAIN, // Main texture. - TCA_BLEND, // Blendtarget texture. - TCA_DETAIL, // Detail texture coordinates. - TCA_BLEND_DETAIL, // Blendtarget's detail texture coordinates. - TCA_LIGHT, // Glow texture coordinates. - //TCA_SHINY, // Shiny surface coordinates. + TCA_MAIN, // Main texture. + TCA_BLEND, // Blendtarget texture. + TCA_DETAIL, // Detail texture coordinates. + TCA_BLEND_DETAIL, // Blendtarget's detail texture coordinates. + TCA_LIGHT, // Glow texture coordinates. + //TCA_SHINY, // Shiny surface coordinates. NUM_TEXCOORD_ARRAYS }; @@ -157,7 +157,7 @@ typedef struct primhdr_s { // All indices in the range indices[0]...indices[n] are used by this // primitive (some are shared). ushort numIndices; - uint *indices; + uint* indices; // First index of the other fan in a Double Fan. ushort beginOther; @@ -201,8 +201,8 @@ typedef struct { const rvertex_t* rvertices; const rendpoly_params_t* polyParams; primhdr_t* hdr; - DGLuint lastDynTexture; - rendlist_t* lastDynList; + DGLuint lastTexture; + rendlist_t* lastList; } dynlightiterparams_t; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- @@ -331,7 +331,7 @@ static void addMaskedPoly(const rvertex_t* rvertices, params->tex.height; vis->data.wall.blendMode = params->blendMode; - // \fixme Semitransparent masked polys arn't lit atm + //// \fixme Semitransparent masked polys arn't lit atm if(!(params->flags & RPF_GLOW) && params->lightListIdx && numTexUnits > 1 && envModAdd && !(rcolors[0].rgba[CA] < 1)) { @@ -428,7 +428,7 @@ static void clearVertices(void) static void destroyVertices(void) { - int i; + uint i; numVertices = maxVertices = 0; M_Free(vertices); @@ -494,7 +494,7 @@ static void destroyList(rendlist_t* rl) static void deleteHash(listhash_t* hash) { - int i; + uint i; rendlist_t* list, *next; for(i = 0; i < RL_HASH_SIZE; ++i) @@ -558,7 +558,7 @@ static void rewindList(rendlist_t* rl) static void rewindHash(listhash_t* hash) { - int i; + uint i; rendlist_t* list; for(i = 0; i < RL_HASH_SIZE; ++i) @@ -687,13 +687,13 @@ static rendlist_t* getListFor(const rendpoly_params_t* params, return dest; } -static rendlist_t* getLightListFor(DGLuint texture) +static rendlist_t* getListInHashFor(DGLuint texture, listhash_t* lHash) { listhash_t* hash; rendlist_t* dest; // Find/create a list in the hash. - hash = &dynHash[texture % RL_HASH_SIZE]; + hash = &lHash[texture % RL_HASH_SIZE]; for(dest = hash->first; dest; dest = dest->next) { if(dest->tex.id == texture) @@ -794,8 +794,7 @@ static void allocateIndices(rendlist_t* list, uint numIndices) list->last->indices = indices; } -static void quadTexCoords(gl_texcoord_t* tc, - const rvertex_t* rvertices, +static void quadTexCoords(gl_texcoord_t* tc, const rvertex_t* rverts, const rendpoly_params_t* params, const gltexture_t* tex) { @@ -813,12 +812,12 @@ static void quadTexCoords(gl_texcoord_t* tc, if(params->flags & RPF_HORIZONTAL) { // Special horizontal coordinates for wall shadows. - tc[0].st[0] = params->texOffset[VY] / height; - tc[2].st[0] = params->texOffset[VY] / height; - tc[0].st[1] = params->texOffset[VX] / width; - tc[1].st[1] = params->texOffset[VX] / width; - tc[1].st[0] = tc[0].st[0] + (rvertices[1].pos[VZ] - rvertices[0].pos[VZ]) / height; - tc[3].st[0] = tc[0].st[0] + (rvertices[3].pos[VZ] - rvertices[2].pos[VZ]) / height; + tc[0].st[0] = tc[2].st[0] = + rverts[0].pos[VX] - params->texOrigin[0][VX] + params->texOffset[VY] / height; + tc[0].st[1] = tc[1].st[1] = + rverts[0].pos[VY] - params->texOrigin[0][VY] + params->texOffset[VX] / width; + tc[1].st[0] = tc[0].st[0] + (rverts[1].pos[VZ] - params->texOrigin[0][VZ]) / height; + tc[3].st[0] = tc[0].st[0] + (rverts[3].pos[VZ] - params->texOrigin[0][VZ]) / height; tc[3].st[1] = tc[0].st[1] + params->wall->length / width; tc[2].st[1] = tc[0].st[1] + params->wall->length / width; return; @@ -826,17 +825,19 @@ static void quadTexCoords(gl_texcoord_t* tc, } else { - // Normally the texture's width and height are considered - // constant inside a rendering list. + // Normally the texture's width and height are considered constant + // inside a rendering list. width = tex->width; height = tex->height; } - tc[0].st[0] = tc[1].st[0] = params->texOffset[VX] / width; - tc[3].st[1] = tc[1].st[1] = params->texOffset[VY] / height; + tc[0].st[0] = tc[1].st[0] = + rverts[0].pos[VX] - params->texOrigin[0][VX] + params->texOffset[VX] / width; + tc[3].st[1] = tc[1].st[1] = + rverts[0].pos[VY] - params->texOrigin[0][VY] + params->texOffset[VY] / height; tc[3].st[0] = tc[2].st[0] = tc[0].st[0] + params->wall->length / width; - tc[2].st[1] = tc[3].st[1] + (rvertices[1].pos[VZ] - rvertices[0].pos[VZ]) / height; - tc[0].st[1] = tc[3].st[1] + (rvertices[3].pos[VZ] - rvertices[2].pos[VZ]) / height; + tc[2].st[1] = tc[3].st[1] + (rverts[1].pos[VZ] - rverts[0].pos[VZ]) / height; + tc[0].st[1] = tc[3].st[1] + (rverts[3].pos[VZ] - rverts[2].pos[VZ]) / height; } static float shinyVertical(float dy, float dx) @@ -910,8 +911,10 @@ static void quadDetailTexCoords(gl_texcoord_t* tc, { float mul = tex->detail->scale * detailScale; - tc[1].st[0] = tc[0].st[0] = params->texOffset[VX] / tex->detail->width; - tc[1].st[1] = tc[3].st[1] = params->texOffset[VY] / tex->detail->height; + tc[1].st[0] = tc[0].st[0] = + rvertices[0].pos[VX] - params->texOrigin[0][VX] + params->texOffset[VX] / tex->detail->width; + tc[1].st[1] = tc[3].st[1] = + rvertices[0].pos[VY] - params->texOrigin[0][VY] + params->texOffset[VY] / tex->detail->height; tc[3].st[0] = tc[2].st[0] = (tc[1].st[0] + params->wall->length / tex->detail->width) * mul; tc[2].st[1] = @@ -976,15 +979,14 @@ static void quadLightCoords(gl_texcoord_t* tc, const float s[2], tc[2].st[1] = tc[0].st[1] = t[1]; } -static void flatShinyTexCoords(gl_texcoord_t* tc, const float xy[2], - float height) +static void flatShinyTexCoords(gl_texcoord_t* tc, const float xyz[3]) { vec2_t view, start; float distance; float offset; // View vector. - V2_Set(view, vx - xy[VX], vz - xy[VY]); + V2_Set(view, vx - xyz[VX], vz - xyz[VY]); distance = V2_Normalize(view); if(distance < 10) @@ -997,11 +999,11 @@ static void flatShinyTexCoords(gl_texcoord_t* tc, const float xy[2], // Offset from the normal view plane. V2_Set(start, vx, vz); - offset = ((start[VY] - xy[VY]) * sin(.4f)/*viewFrontVec[VX]*/ - - (start[VX] - xy[VX]) * cos(.4f)/*viewFrontVec[VZ]*/); + offset = ((start[VY] - xyz[VY]) * sin(.4f)/*viewFrontVec[VX]*/ - + (start[VX] - xyz[VX]) * cos(.4f)/*viewFrontVec[VZ]*/); tc->st[0] = ((shinyVertical(offset, distance) - .5f) * 2) + .5f; - tc->st[1] = shinyVertical(vy - height, distance); + tc->st[1] = shinyVertical(vy - xyz[VZ], distance); } static void flatDetailTexCoords(gl_texcoord_t* tc, const float xy[2], @@ -1314,6 +1316,7 @@ static void writeFlat(primhdr_t* hdr, const rendlist_t* list, uint base, { const rvertex_t* vtx = &rvertices[i]; const rcolor_t* rcolor = &rcolors[i]; + float xyz[3]; // Coordinates. v = &vertices[base + i]; @@ -1326,6 +1329,10 @@ static void writeFlat(primhdr_t* hdr, const rendlist_t* list, uint base, continue; } + xyz[VX] = vtx->pos[VX] - params->texOrigin[0][VX]; + xyz[VY] = vtx->pos[VY] - params->texOrigin[0][VY]; + xyz[VZ] = vtx->pos[VZ] - params->texOrigin[0][VZ]; + // Primary texture coordinates. if(list->tex.id) { @@ -1333,52 +1340,59 @@ static void writeFlat(primhdr_t* hdr, const rendlist_t* list, uint base, if(!(params->flags & RPF_SHINY)) { // Normal texture coordinates. tc->st[0] = - (vtx->pos[VX] + params->texOffset[VX]) / + (xyz[VX] + params->texOffset[VX]) / ((params->flags & RPF_SHADOW) ? params->tex.width : list->tex.width); tc->st[1] = - (-vtx->pos[VY] - params->texOffset[VY]) / + (-xyz[VY] - params->texOffset[VY]) / ((params->flags & RPF_SHADOW) ? params->tex.height : list->tex.height); } else { // Calculate shiny coordinates. - flatShinyTexCoords(tc, vtx->pos, vtx->pos[VZ]); + flatShinyTexCoords(tc, xyz); } } // Detail texture coordinates. if(list->tex.detail) { - flatDetailTexCoords(&texCoords[TCA_DETAIL][base + i], vtx->pos, + flatDetailTexCoords(&texCoords[TCA_DETAIL][base + i], xyz, params, &list->tex); } if(list->interTex.detail) { flatDetailTexCoords(&texCoords[TCA_BLEND_DETAIL][base + i], - vtx->pos, params, &list->interTex); + xyz, params, &list->interTex); } // Light coordinates. if(list->last->numLights > 0 && IS_MTEX_LIGHTS) { + float width, height; + tc = &texCoords[TCA_LIGHT][base + i]; - tc->st[0] = (vtx->pos[VX] + list->last->modTexTC[0][0]) * - list->last->modTexTC[0][1]; - tc->st[1] = (-vtx->pos[VY] + list->last->modTexTC[1][0]) * - list->last->modTexTC[1][1]; + + width = params->texOrigin[1][VX] - params->texOrigin[0][VX]; + height = params->texOrigin[1][VY] - params->texOrigin[0][VY]; + + tc->st[0] = ((params->texOrigin[1][VX] - vtx->pos[VX]) / width * list->last->modTexTC[0][0]) + + ((vtx->pos[VX] - params->texOrigin[0][VX]) / width * list->last->modTexTC[0][1]); + tc->st[1] = ((params->texOrigin[1][VY] - vtx->pos[VY]) / height * list->last->modTexTC[1][0]) + + ((vtx->pos[VY] - params->texOrigin[0][VY]) / height * list->last->modTexTC[1][1]); } // Blend texture coordinates. if(list->interTex.id) { tc = &texCoords[TCA_BLEND][base + i]; - tc->st[0] = (vtx->pos[VX] + params->texOffset[VX]) / + + tc->st[0] = (xyz[VX] + params->texOffset[VX]) / ((params->flags & RPF_SHINY)? params->tex.width : list->interTex.width); tc->st[1] = - (-vtx->pos[VY] - params->texOffset[VY]) / + (-xyz[VY] - params->texOffset[VY]) / ((params->flags & RPF_SHINY)? params->tex.height : list->interTex.height); } @@ -1430,7 +1444,7 @@ static void writeDynLight(rendlist_t* list, const dynlight_t* dyn, // Each vertex uses the light's color. col = &colors[base + i]; for(c = 0; c < 3; ++c) - col->rgba[c] = (byte) (255 * dyn->color[c]); + col->rgba[c] = (DGLubyte) (255 * MINMAX_OF(0, dyn->color[c], 1)); col->rgba[3] = 255; } @@ -1438,11 +1452,19 @@ static void writeDynLight(rendlist_t* list, const dynlight_t* dyn, tc = &texCoords[TCA_MAIN][base]; if(params->type == RP_FLAT) { + float width, height; + + width = params->texOrigin[1][VX] - params->texOrigin[0][VX]; + height = params->texOrigin[1][VY] - params->texOrigin[0][VY]; + num = prim->primSize; for(i = 0; i < num; ++i) { - tc[i].st[0] = (vertices[base + i].xyz[0] + dyn->s[0]) * dyn->s[1]; - tc[i].st[1] = (-vertices[base + i].xyz[2] + dyn->t[0]) * dyn->t[1]; + tc[i].st[0] = ((params->texOrigin[1][VX] - rvertices[i].pos[VX]) / width * dyn->s[0]) + + ((rvertices[i].pos[VX] - params->texOrigin[0][VX]) / width * dyn->s[1]); + + tc[i].st[1] = ((params->texOrigin[1][VY] - rvertices[i].pos[VY]) / height * dyn->t[0]) + + ((rvertices[i].pos[VY] - params->texOrigin[0][VY]) / height * dyn->t[1]); } } else @@ -1509,20 +1531,21 @@ boolean RLIT_DynLightWrite(const dynlight_t* dyn, void* data) // If multitexturing is in use, we skip the first light. if(!(IS_MTEX_LIGHTS && params->lastIdx == 0)) { - rendlist_t* dynList; + rendlist_t* list; // If the texture is the same as the last, the list will be too. - if(params->lastDynTexture == dyn->texture) + if(params->lastTexture == dyn->texture) { - dynList = params->lastDynList; + list = params->lastList; } else { - dynList = params->lastDynList = getLightListFor(dyn->texture); - params->lastDynTexture = dyn->texture; + list = params->lastList = + getListInHashFor(dyn->texture, dynHash); + params->lastTexture = dyn->texture; } - writeDynLight(dynList, dyn, params->hdr, params->rvertices, + writeDynLight(list, dyn, params->hdr, params->rvertices, params->polyParams); params->hdr->numLights++; } @@ -1541,7 +1564,6 @@ void RL_AddPoly(const rvertex_t* rvertices, const rcolor_t* rcolors, rendlist_t* li; primhdr_t* hdr; boolean useLights = false; - dynlightiterparams_t dlparams; if(numVertices < 3) return; // huh? @@ -1560,30 +1582,30 @@ BEGIN_PROF( PROF_RL_ADD_POLY ); // Are lights allowed? if(!(params->flags & (RPF_SKY_MASK | RPF_SHADOW | RPF_SHINY))) { + if(!(params->flags & RPF_GLOW)) + useLights = (params->lightListIdx? true : false); + // In multiplicative mode, glowing surfaces are fullbright. // Rendering lights on them would be pointless. - if(!IS_MUL || !(params->flags & RPF_GLOW)) + if(IS_MUL && useLights) { // Surfaces lit by dynamic lights may need to be rendered // differently than non-lit surfaces. - if(params->lightListIdx) - { - uint i; - float avglightlevel = 0; + uint i; + float avglightlevel = 0; - // Determine the average light level of this rend poly, - // if too bright; do not bother with lights. - for(i = 0; i < numVertices; ++i) - { - avglightlevel += rcolors[i].rgba[CR]; - avglightlevel += rcolors[i].rgba[CG]; - avglightlevel += rcolors[i].rgba[CB]; - } - avglightlevel /= (float) numVertices * 3; - - if(avglightlevel < 0.98f) - useLights = true; + // Determine the average light level of this rend poly, + // if too bright; do not bother with lights. + for(i = 0; i < numVertices; ++i) + { + avglightlevel += rcolors[i].rgba[CR]; + avglightlevel += rcolors[i].rgba[CG]; + avglightlevel += rcolors[i].rgba[CB]; } + avglightlevel /= (float) numVertices * 3; + + if(avglightlevel > 0.98f) + useLights = false; } } @@ -1664,8 +1686,10 @@ END_PROF( PROF_RL_GET_LIST ); // it's skipped. if(useLights) { - dlparams.lastDynTexture = 0; - dlparams.lastDynList = NULL; + dynlightiterparams_t dlparams; + + dlparams.lastTexture = 0; + dlparams.lastList = NULL; dlparams.rvertices = rvertices; dlparams.polyParams = params; dlparams.hdr = hdr; @@ -1750,9 +1774,9 @@ static void drawPrimitives(int conditions, rendlist_t *list) glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, hdr->modColor); // Make sure the light is not repeated. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); + GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); + GL_CLAMP_TO_EDGE); } if(conditions & DCF_SET_BLEND_MODE) @@ -1887,9 +1911,9 @@ static int setupListState(listmode_t mode, rendlist_t *list) RL_Bind(list->tex.id, list->tex.magMode); // Make sure the texture is not repeated. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); + GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); + GL_CLAMP_TO_EDGE); return 0; case LM_BLENDED_MOD_TEXTURE: @@ -1992,9 +2016,9 @@ static int setupListState(listmode_t mode, rendlist_t *list) // The intertex holds the info for the mask texture. RL_BindTo(1, list->interTex.id, list->tex.magMode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, - GL_REPEAT); + GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, - GL_REPEAT); + GL_REPEAT); setEnvAlpha(1.0f); case LM_ALL_SHINY: case LM_SHINY: @@ -2002,9 +2026,9 @@ static int setupListState(listmode_t mode, rendlist_t *list) list->tex.magMode); // Make sure the texture is not clamped. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, - GL_REPEAT); + GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, - GL_REPEAT); + GL_REPEAT); // Render all primitives. if(mode == LM_ALL_SHINY) return DCF_SET_BLEND_MODE; @@ -2170,6 +2194,7 @@ static void setupPassState(listmode_t mode) glDepthMask(GL_FALSE); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); + if(usingFog) { DGL_Enable(DGL_FOG); @@ -2510,7 +2535,7 @@ BEGIN_PROF( PROF_RL_RENDER_LIGHT ); renderLists(LM_BLENDED_FIRST_LIGHT, lists, count); } } - else // Multitexturing is not available for lights. + else // Multitexturing is not available for lights. { if(IS_MUL) { diff --git a/doomsday/engine/portable/src/rend_main.c b/doomsday/engine/portable/src/rend_main.c index 3fce485c63..d71cc0ecab 100644 --- a/doomsday/engine/portable/src/rend_main.c +++ b/doomsday/engine/portable/src/rend_main.c @@ -861,6 +861,7 @@ typedef struct { rendpolytype_t type; short flags; // RPF_*. + float texOrigin[2][3]; float texOffset[2]; // Texture coordinates for left/top // (in real texcoords). const float* normal; // Surface normal. @@ -898,6 +899,7 @@ typedef struct { typedef struct { rendpolytype_t type; short flags; // RPF_*. + float texOrigin[2][3]; float texOffset[2]; // Texture coordinates for left/top // (in real texcoords). const float* normal; @@ -1031,6 +1033,16 @@ static void renderSegSection2(const rvertex_t* rvertices, uint numVertices, else memset(params.wall->divs, 0, sizeof(params.wall->divs)); + // Top left. + params.texOrigin[0][VX] = p->texOrigin[0][VX]; + params.texOrigin[0][VY] = p->texOrigin[0][VY]; + params.texOrigin[0][VZ] = p->texOrigin[0][VZ]; + + // Bottom right. + params.texOrigin[1][VX] = p->texOrigin[1][VX]; + params.texOrigin[1][VY] = p->texOrigin[1][VY]; + params.texOrigin[1][VZ] = p->texOrigin[1][VZ]; + params.texOffset[VX] = p->texOffset[VX]; params.texOffset[VY] = p->texOffset[VY]; @@ -1167,6 +1179,16 @@ static void renderPlane2(const rvertex_t* rvertices, uint numVertices, params.isWall = false; params.wall = NULL; + // Top left. + params.texOrigin[0][VX] = p->texOrigin[0][VX]; + params.texOrigin[0][VY] = p->texOrigin[0][VY]; + params.texOrigin[0][VZ] = p->texOrigin[0][VZ]; + + // Bottom right. + params.texOrigin[1][VX] = p->texOrigin[1][VX]; + params.texOrigin[1][VY] = p->texOrigin[1][VY]; + params.texOrigin[1][VZ] = p->texOrigin[1][VZ]; + params.texOffset[VX] = p->texOffset[VX]; params.texOffset[VY] = p->texOffset[VY]; @@ -1265,6 +1287,16 @@ static boolean doRenderSeg(seg_t* seg, segsection_t section, params.frontSec = seg->SG_frontsector; params.backSec = seg->SG_backsector; + // Top left. + params.texOrigin[0][VX] = rvertices[1].pos[VX]; + params.texOrigin[0][VY] = rvertices[1].pos[VY]; + params.texOrigin[0][VZ] = rvertices[1].pos[VZ]; + + // Bottom right. + params.texOrigin[1][VX] = rvertices[2].pos[VX]; + params.texOrigin[1][VY] = rvertices[2].pos[VY]; + params.texOrigin[1][VZ] = rvertices[2].pos[VZ]; + // Fill in the remaining params data. if(skyMask || R_IsSkySurface(surface)) { @@ -2189,6 +2221,21 @@ static void Rend_RenderPlane(subsector_t* subsector, uint planeID) params.mapObject = subsector; params.elmIdx = plane->planeID; + // Set the texture origin. + params.texOrigin[0][VX] = subsector->bBox[0].pos[VX]; + params.texOrigin[1][VX] = subsector->bBox[1].pos[VX]; + if(plane->type == PLN_FLOOR) + { + params.texOrigin[0][VY] = subsector->bBox[1].pos[VY]; + params.texOrigin[1][VY] = subsector->bBox[0].pos[VY]; + } + else + { // Y is flipped for the ceiling. + params.texOrigin[0][VY] = subsector->bBox[0].pos[VY]; + params.texOrigin[1][VY] = subsector->bBox[1].pos[VY]; + } + params.texOrigin[0][VZ] = params.texOrigin[1][VZ] = height; + // Check for sky. if(R_IsSkySurface(surface)) { @@ -2315,6 +2362,15 @@ static void Rend_RenderPlane(subsector_t* subsector, uint planeID) params.alpha = surface->rgba[CA]; } + // Add the Y offset to orient the Y flipped texture. + if(plane->type == PLN_CEILING) + params.texOffset[VY] -= subsector->bBox[1].pos[VY] - + subsector->bBox[0].pos[VY]; + + // Add the additional offset to align with the worldwide grid. + params.texOffset[VX] += subsector->worldGridOffset[VX]; + params.texOffset[VY] += subsector->worldGridOffset[VY]; + Rend_PreparePlane(rvertices, numVertices, height, subsector, !(surface->normal[VZ] > 0)); @@ -2508,6 +2564,129 @@ static void Rend_RenderNode(uint bspnum) } } +static void drawNormal(vec3_t origin, vec3_t normal, float scalar) +{ + float black[4] = { 0, 0, 0, 0 }; + float red[4] = { 1, 0, 0, 1 }; + + DGL_MatrixMode(DGL_MODELVIEW); + DGL_PushMatrix(); + + DGL_Translatef(origin[VX], origin[VZ], origin[VY]); + + DGL_Begin(DGL_LINES); + { + DGL_Color4fv(black); + DGL_Vertex3f(scalar * normal[VX], + scalar * normal[VZ], + scalar * normal[VY]); + DGL_Color4fv(red); + DGL_Vertex3f(0, 0, 0); + + } + DGL_End(); + + DGL_MatrixMode(DGL_MODELVIEW); + DGL_PopMatrix(); +} + +#if _DEBUG +static void Rend_RenderNormals(void) +{ +#define NORM_TAIL_LENGTH (20) + + uint i; + + DGL_Disable(DGL_TEXTURING); + glDisable(GL_CULL_FACE); + + for(i = 0; i < numSegs; ++i) + { + seg_t* seg = &segs[i]; + sidedef_t* side; + surface_t* suf; + vec3_t origin; + float bottom, top; + float scale = NORM_TAIL_LENGTH; + + if(!seg->lineDef) + continue; + + side = SEG_SIDEDEF(seg); + suf = NULL; + + if(!seg->SG_frontsector || !seg->SG_backsector) + { + bottom = side->sector->SP_floorvisheight; + top = side->sector->SP_ceilvisheight; + suf = &side->SW_middlesurface; + } + else + { + // Top: + if(seg->SG_backsector->SP_ceilvisheight < + seg->SG_frontsector->SP_ceilvisheight) + { + bottom = seg->SG_backsector->SP_ceilvisheight; + top = seg->SG_frontsector->SP_ceilvisheight; + suf = &side->SW_topsurface; + } + + if(side->SW_middlesurface.material) + { + top = seg->SG_frontsector->SP_ceilvisheight; + bottom = seg->SG_frontsector->SP_floorvisheight; + suf = &side->SW_middlesurface; + } + + if(seg->SG_backsector->SP_floorvisheight > + seg->SG_frontsector->SP_floorvisheight) + { + bottom = seg->SG_frontsector->SP_floorvisheight; + top = seg->SG_backsector->SP_floorvisheight; + suf = &side->SW_bottomsurface; + } + } + + if(suf) + { + V3_Set(origin, + seg->SG_v1pos[VX] + (seg->SG_v2pos[VX] - seg->SG_v1pos[VX]) / 2, + seg->SG_v1pos[VY] + (seg->SG_v2pos[VY] - seg->SG_v1pos[VY]) / 2, + bottom + (top - bottom) / 2); + drawNormal(origin, suf->normal, scale); + } + } + + for(i = 0; i < numSSectors; ++i) + { + uint j; + subsector_t* ssec = &ssectors[i]; + + for(j = 0; j < ssec->sector->planeCount; ++j) + { + vec3_t origin; + plane_t* pln = ssec->sector->SP_plane(j); + float scale = NORM_TAIL_LENGTH; + + V3_Set(origin, ssec->midPoint.pos[VX], ssec->midPoint.pos[VY], + pln->visHeight); + if(pln->type == PLN_FLOOR) + origin[VZ] += ssec->sector->skyFix[0].offset; + else if(pln->type == PLN_CEILING) + origin[VZ] += ssec->sector->skyFix[1].offset; + + drawNormal(origin, pln->PS_normal, scale); + } + } + + glEnable(GL_CULL_FACE); + DGL_Enable(DGL_TEXTURING); + +#undef NORM_TAIL_LENGTH +} +#endif + void Rend_RenderMap(void) { binangle_t viewside; @@ -2545,7 +2724,6 @@ void Rend_RenderMap(void) { // Clear the projected dynlight lists. DL_InitForNewFrame(); - // Clear the luminous objects. LO_InitForNewFrame(); } @@ -2553,10 +2731,11 @@ void Rend_RenderMap(void) // Make vissprites of all the visible decorations. Rend_ProjectDecorations(); - // Maintain luminous objects. if(doLums) { + // Spawn omnilights for mobjs. LO_AddLuminousMobjs(); + // Link the lumobjs to all contacted surfaces. LO_LinkLumobjs(); } @@ -2583,7 +2762,7 @@ void Rend_RenderMap(void) Rend_RenderShadows(); - // Wrap up with Shadow Bias. + // Wrap up with Source, Bias lights. SB_EndFrame(); } RL_RenderAllLists(); @@ -2591,7 +2770,15 @@ void Rend_RenderMap(void) // Draw the mobj bounding boxes. Rend_RenderBoundingBoxes(); - // Draw the Shadow Bias Editor's draw that identifies the current +/*#if _DEBUG +Rend_RenderNormals(); +#endif*/ + +/*#if _DEBUG +LO_DrawLumobjs(); +#endif*/ + + // Draw the Source Bias Editor's draw that identifies the current // light. SBE_DrawCursor(); diff --git a/doomsday/plugins/common/src/p_map.c b/doomsday/plugins/common/src/p_map.c index b9a1d744ff..3db12ef00a 100644 --- a/doomsday/plugins/common/src/p_map.c +++ b/doomsday/plugins/common/src/p_map.c @@ -336,8 +336,8 @@ boolean PIT_CrossLine(linedef_t *ld, void *data) tmBBox[BOXTOP] < bbox[BOXBOTTOM] || tmBBox[BOXBOTTOM] > bbox[BOXTOP])) { - if(P_PointOnLineSide(startPos[VX], startPos[VY], ld) != - P_PointOnLineSide(endPos[VX], endPos[VY], ld)) + if(P_PointOnLinedefSide(startPos[VX], startPos[VY], ld) != + P_PointOnLinedefSide(endPos[VX], endPos[VY], ld)) // Line blocks trajectory. return false; } @@ -1399,8 +1399,8 @@ static boolean P_TryMove2(mobj_t *thing, float x, float y, boolean dropoff) // See if the line was crossed. if(P_ToXLine(ld)->special) { - side = P_PointOnLineSide(thing->pos[VX], thing->pos[VY], ld); - oldside = P_PointOnLineSide(oldpos[VX], oldpos[VY], ld); + side = P_PointOnLinedefSide(thing->pos[VX], thing->pos[VY], ld); + oldside = P_PointOnLinedefSide(oldpos[VX], oldpos[VY], ld); if(side != oldside) { #if __JHEXEN__ @@ -1439,7 +1439,7 @@ static boolean P_TryMove2(mobj_t *thing, float x, float y, boolean dropoff) while((ld = P_IterListIterator(spechit)) != NULL) { // See if the line was crossed. - side = P_PointOnLineSide(thing->pos[VX], thing->pos[VY], ld); + side = P_PointOnLinedefSide(thing->pos[VX], thing->pos[VY], ld); CheckForPushSpecial(ld, side, thing); } } @@ -1464,7 +1464,7 @@ boolean P_TryMove(mobj_t *thing, float x, float y, boolean dropoff, { // Move not possible, see if the thing hit a line and send a Hit // event to it. - XL_HitLine(tmHitLine, P_PointOnLineSide(thing->pos[VX], thing->pos[VY], tmHitLine), + XL_HitLine(tmHitLine, P_PointOnLinedefSide(thing->pos[VX], thing->pos[VY], tmHitLine), thing); } @@ -2133,7 +2133,7 @@ boolean PTR_UseTraverse(intercept_t* in) } side = 0; - if(1 == P_PointOnLineSide(useThing->pos[VX], useThing->pos[VY], + if(1 == P_PointOnLinedefSide(useThing->pos[VX], useThing->pos[VY], in->d.lineDef)) side = 1; @@ -2269,7 +2269,7 @@ static void P_HitSlideLine(linedef_t *ld) return; } - side = P_PointOnLineSide(slideMo->pos[VX], slideMo->pos[VY], ld); + side = P_PointOnLinedefSide(slideMo->pos[VX], slideMo->pos[VY], ld); lineangle = R_PointToAngle2(0, 0, P_GetFloatp(ld, DMU_DX), P_GetFloatp(ld, DMU_DY)); @@ -2307,7 +2307,7 @@ boolean PTR_SlideTraverse(intercept_t *in) if(!frontSec || !backSec) { - if(P_PointOnLineSide(slideMo->pos[VX], slideMo->pos[VY], li)) + if(P_PointOnLinedefSide(slideMo->pos[VX], slideMo->pos[VY], li)) return true; // Don't hit the back side. goto isblocking; @@ -2906,7 +2906,7 @@ boolean PTR_BounceTraverse(intercept_t *in) if(!frontSec || !backSec) { - if(P_PointOnLineSide(slideMo->pos[VX], slideMo->pos[VY], li)) + if(P_PointOnLinedefSide(slideMo->pos[VX], slideMo->pos[VY], li)) return true; // Don't hit the back side. goto bounceblocking; } @@ -2962,7 +2962,7 @@ void P_BounceWall(mobj_t *mo) if(!bestSlideLine) return; // We don't want to crash. - side = P_PointOnLineSide(mo->pos[VX], mo->pos[VY], bestSlideLine); + side = P_PointOnLinedefSide(mo->pos[VX], mo->pos[VY], bestSlideLine); lineangle = R_PointToAngle2(0, 0, P_GetFloatp(bestSlideLine, DMU_DX), P_GetFloatp(bestSlideLine, DMU_DY)); @@ -3028,7 +3028,7 @@ boolean PTR_PuzzleItemTraverse(intercept_t *in) return true; // Continue searching... } - if(P_PointOnLineSide(puzzleItemUser->pos[VX], + if(P_PointOnLinedefSide(puzzleItemUser->pos[VX], puzzleItemUser->pos[VY], in->d.lineDef) == 1) return false; // Don't use back sides. diff --git a/doomsday/plugins/common/src/p_xgline.c b/doomsday/plugins/common/src/p_xgline.c index 24cf0b8fd4..4a433de249 100644 --- a/doomsday/plugins/common/src/p_xgline.c +++ b/doomsday/plugins/common/src/p_xgline.c @@ -1635,7 +1635,7 @@ int C_DECL XLTrav_LineTeleport(linedef_t *newline, boolean dummy, void *context, side = 1; // Make sure we are on correct side of exit linedef. - while(P_PointOnLineSide(newx, newy, newline) != side && --fudge >= 0) + while(P_PointOnLinedefSide(newx, newy, newline) != side && --fudge >= 0) { if(fabs(newldx) > fabs(newldy)) newy -= FIX2FLT((newldx < 0) != side ? -1 : 1);