From 5c78017a1dfb07f835100957feb30774f7dfa943 Mon Sep 17 00:00:00 2001 From: danij Date: Thu, 24 Nov 2011 10:33:20 +0000 Subject: [PATCH] Refactor: New mechanism for configuring render list texture units The previous implementation made texture unit configuration a function of primitive writing, therefore every time one wanted to write a polygon to the lists, the texture unit config had to be reconstructed. This interface mechanic was a architectural bottleneck (not helped by the fact that acquiring the config to construct the texture unit state itself had some performance issues). This commit addresses this bottleneck thus: 1) Render list primitive write interface was extended with a state based texture unit configuration mechanic. It is also now possible to configure this state once, before then writing multiple polygons to the list(s). 2) Render list interface was extended with the ability to reference directly prepared rtexmapunit_t states owned by another module. 3) World renderer was enhanced to take advantage of the new mechanics of the render list inteface, mapping the preprocessed rtexmapunit_t state (owned by MaterialSnapshot) when writing to the lists. 4) Added new logical texture units for shiny textures and their masks and moved writing of the shiny polygons into the render list module. The interface presented by the render list module now deals entirely with "logical" texture units. Users of this module should not need to be concerned with whether there are enough "physical" texture units available. The render list module will itself dynamically determine when insufficent units are available and use a new render pass as is necessary. Therefore the primitive write for shiny textures belongs in this module. Cleanup of the Material type hierarchy. --- doomsday/engine/portable/include/materials.h | 18 + .../engine/portable/include/materialvariant.h | 66 +- doomsday/engine/portable/include/p_mapdata.h | 1 - doomsday/engine/portable/include/r_data.h | 81 +- doomsday/engine/portable/include/r_draw.h | 2 + doomsday/engine/portable/include/r_things.h | 1 - doomsday/engine/portable/include/rend_list.h | 160 ++- doomsday/engine/portable/include/rend_main.h | 8 +- doomsday/engine/portable/src/gl_main.c | 10 +- doomsday/engine/portable/src/material.c | 5 +- doomsday/engine/portable/src/materials.c | 151 ++- doomsday/engine/portable/src/r_data.c | 78 +- doomsday/engine/portable/src/r_draw.c | 9 +- doomsday/engine/portable/src/r_lumobjs.c | 13 +- doomsday/engine/portable/src/r_main.c | 7 +- doomsday/engine/portable/src/r_model.c | 5 +- doomsday/engine/portable/src/r_sky.c | 17 +- doomsday/engine/portable/src/r_things.c | 26 +- doomsday/engine/portable/src/rend_console.c | 2 +- doomsday/engine/portable/src/rend_dynlight.c | 35 +- doomsday/engine/portable/src/rend_fakeradio.c | 132 ++- doomsday/engine/portable/src/rend_font.c | 2 +- doomsday/engine/portable/src/rend_list.c | 586 ++++++++--- doomsday/engine/portable/src/rend_main.c | 927 +++++++++--------- doomsday/engine/portable/src/rend_model.c | 5 +- doomsday/engine/portable/src/rend_shadow.c | 52 +- doomsday/engine/portable/src/rend_sky.c | 5 +- doomsday/engine/portable/src/rend_sprite.c | 52 +- doomsday/engine/portable/src/sys_sdl_window.c | 3 +- doomsday/engine/portable/src/ui2_main.c | 33 +- doomsday/engine/win32/src/sys_window.c | 3 +- 31 files changed, 1464 insertions(+), 1031 deletions(-) diff --git a/doomsday/engine/portable/include/materials.h b/doomsday/engine/portable/include/materials.h index cb7fa1d72e..ef3259e0a4 100644 --- a/doomsday/engine/portable/include/materials.h +++ b/doomsday/engine/portable/include/materials.h @@ -34,6 +34,24 @@ struct materialsnapshot_s; enum materialnamespaceid_t; // Defined in dd_share.h +/// Material (Usage) Context identifiers. +typedef enum { + MC_UNKNOWN = -1, + MATERIALCONTEXT_FIRST = 0, + MC_UI = MATERIALCONTEXT_FIRST, + MC_MAPSURFACE, + MC_SPRITE, + MC_MODELSKIN, + MC_PSPRITE, + MC_SKYSPHERE, + MATERIALCONTEXT_LAST = MC_SKYSPHERE +} materialcontext_t; + +#define MATERIALCONTEXT_COUNT (MATERIALCONTEXT_LAST + 1 - MATERIALCONTEXT_FIRST ) + +/// @c true= val can be interpreted as a valid material context identifier. +#define VALID_MATERIALCONTEXT(val) ((val) >= MATERIALCONTEXT_FIRST && (val) <= MATERIALCONTEXT_LAST) + /// Components within a Material path hierarchy are delimited by this character. #define MATERIALS_PATH_DELIMITER '/' diff --git a/doomsday/engine/portable/include/materialvariant.h b/doomsday/engine/portable/include/materialvariant.h index 1150a1fb52..b4eb6def27 100644 --- a/doomsday/engine/portable/include/materialvariant.h +++ b/doomsday/engine/portable/include/materialvariant.h @@ -24,27 +24,11 @@ #ifndef LIBDENG_MATERIALVARIANT_H #define LIBDENG_MATERIALVARIANT_H -#include "texture.h" +#include "r_data.h" +struct texturevariant_s; struct texturevariantspecification_s; -/// Material (Usage) Context identifiers. -typedef enum { - MC_UNKNOWN = -1, - MATERIALCONTEXT_FIRST = 0, - MC_UI = MATERIALCONTEXT_FIRST, - MC_MAPSURFACE, - MC_SPRITE, - MC_MODELSKIN, - MC_PSPRITE, - MC_SKYSPHERE, - MATERIALCONTEXT_LAST = MC_SKYSPHERE -} materialcontext_t; - -#define MATERIALCONTEXT_COUNT (MATERIALCONTEXT_LAST + 1 - MATERIALCONTEXT_FIRST ) - -#define VALID_MATERIALCONTEXT(mc) ((mc) >= MATERIALCONTEXT_FIRST && (mc) <= MATERIALCONTEXT_LAST) - typedef struct materialvariantspecification_s { materialcontext_t context; struct texturevariantspecification_s* primarySpec; @@ -61,35 +45,16 @@ enum { NUM_MATERIAL_TEXTURE_UNITS }; -typedef struct material_textureunit_s { - struct material_textureunit_texture { - texture_t* texture; - const struct texturevariantspecification_s* spec; - DGLuint glName; - float s, t; - } tex; - - int magMode; - - /// Currently used only with reflection. - blendmode_t blendMode; - - /// Material-space scale multiplier. - vec2_t scale; - - /// Material-space origin translation. - vec2_t offset; - - float alpha; -} material_textureunit_t; - typedef struct materialsnapshot_s { - /// "Virtual" texturing units. - material_textureunit_t units[NUM_MATERIAL_TEXTURE_UNITS]; + /// @c true= this material is entirely opaque. + boolean isOpaque; /// Dimensions in logical world units. int width, height; + /// Glow strength multiplier. + float glowing; + /// Average colors (for lighting). vec3_t color; vec3_t colorAmplified; @@ -100,17 +65,24 @@ typedef struct materialsnapshot_s { /// Minimum sector light color for shiny texturing. vec3_t shinyMinColor; - /// Glow strength multiplier. - float glowing; + /// Textures used on each texture unit. + const struct texturevariant_s* textures[NUM_MATERIAL_TEXTURE_UNITS]; - boolean isOpaque; + /// Texture unit configuration. + rtexmapunit_t units[NUM_MATERIAL_TEXTURE_UNITS]; } materialsnapshot_t; -#define MSU(ms, u) ((ms)->units[u]) +// Helper macros for accessing MaterialSnapshot data elements. +#define MST(ms, u) ((ms)->textures[u]) +#define MSU(ms, u) ((ms)->units[u]) + +#define MSU_texture(ms, u) (MST(ms, u)? TextureVariant_GeneralCase(MST(ms, u)) : NULL) +#define MSU_gltexture(ms, u) (MST(ms, u)? TextureVariant_GLName(MST(ms, u)) : 0) +#define MSU_texturespec(ms, u) (MST(ms, u)? TextureVariant_Spec(MST(ms, u)) : NULL) typedef struct materialvariant_layer_s { int stage; // -1 => layer not in use. - texture_t* texture; + struct texture_s* texture; float texOrigin[2]; /// Origin of the texture in material-space. float glow; short tics; diff --git a/doomsday/engine/portable/include/p_mapdata.h b/doomsday/engine/portable/include/p_mapdata.h index 72cf2f1b27..0c6a8c68c1 100644 --- a/doomsday/engine/portable/include/p_mapdata.h +++ b/doomsday/engine/portable/include/p_mapdata.h @@ -130,7 +130,6 @@ typedef struct biassurface_s { typedef void* blockmap_t; -#include "materialvariant.h" #include "p_polyob.h" #include "p_maptypes.h" diff --git a/doomsday/engine/portable/include/r_data.h b/doomsday/engine/portable/include/r_data.h index b581bba1aa..a588a45afe 100644 --- a/doomsday/engine/portable/include/r_data.h +++ b/doomsday/engine/portable/include/r_data.h @@ -29,6 +29,7 @@ #ifndef LIBDENG_REFRESH_DATA_H #define LIBDENG_REFRESH_DATA_H +#include "dd_types.h" #include "gl_main.h" #include "dd_def.h" #include "p_think.h" @@ -53,13 +54,68 @@ struct font_s; #define DTLF_PWAD 0x2 // Can use if from PWAD. #define DTLF_EXTERNAL 0x4 // Can use if from external resource. +/** + * Texture unit state. POD. + * + * A simple Record data structure for storing properties used for + * configuring a GL texture unit during render. + */ +typedef struct rtexmapuint_s { + /// Texture used on this layer (if any). + DGLuint tex; + + /// GL texture magnification filter. + int magMode; + + /// Currently used only with reflection. + blendmode_t blendMode; + + /// Opacity of this layer [0...1]. + float opacity; + + /// Texture-space scale multiplier. + vec2_t scale; + + /// Texture-space origin translation (unscaled). + vec2_t offset; +} rtexmapunit_t; + +/// Manipulators, for convenience. +void Rtu_Init(rtexmapunit_t* rtu); + +/// Change the scale property. +void Rtu_SetScale(rtexmapunit_t* rtu, float s, float t); +void Rtu_SetScalev(rtexmapunit_t* rtu, float const st[2]); + +/** + * Multiply the offset and scale properties by @a scalar. + * \note @a scalar is applied to both scale and offset properties + * however the offset remains independent from scale (i.e., it is + * still considered "unscaled"). + */ +void Rtu_Scale(rtexmapunit_t* rtu, float scalar); +void Rtu_ScaleST(rtexmapunit_t* rtu, float const scalarST[2]); + +/// Change the offset property. +void Rtu_SetOffset(rtexmapunit_t* rtu, float s, float t); +void Rtu_SetOffsetv(rtexmapunit_t* rtu, float const st[2]); + +/// Translate the offset property. +void Rtu_TranslateOffset(rtexmapunit_t* rtu, float s, float t); +void Rtu_TranslateOffsetv(rtexmapunit_t* rtu, float const st[2]); + +/** + * Logical texture unit indices. + */ typedef enum { - TU_PRIMARY = 0, - TU_PRIMARY_DETAIL, - TU_INTER, - TU_INTER_DETAIL, + RTU_PRIMARY = 0, + RTU_PRIMARY_DETAIL, + RTU_INTER, + RTU_INTER_DETAIL, + RTU_REFLECTION, + RTU_REFLECTION_MASK, NUM_TEXMAP_UNITS -} gltexunit_t; +} rtexmapunitid_t; typedef struct glcommand_vertex_s { float s, t; @@ -226,14 +282,13 @@ void R_FreeRendColors(rcolor_t* rcolors); void R_FreeRendTexCoords(rtexcoord_t* rtexcoords); void R_InfoRendVerticesPool(void); -void R_DivVerts(rvertex_t* dst, const rvertex_t* src, - const walldiv_t* divs); -void R_DivVertColors(rcolor_t* dst, const rcolor_t* src, - const walldiv_t* divs, float bL, float tL, - float bR, float tR); -void R_DivTexCoords(rtexcoord_t* dst, const rtexcoord_t* src, - const walldiv_t* divs, float bL, float tL, - float bR, float tR); +void R_DivVerts(rvertex_t* dst, const rvertex_t* src, const walldiv_t* divs); + +void R_DivVertColors(rcolor_t* dst, const rcolor_t* src, const walldiv_t* divs, + float bL, float tL, float bR, float tR); + +void R_DivTexCoords(rtexcoord_t* dst, const rtexcoord_t* src, const walldiv_t* divs, + float bL, float tL, float bR, float tR); void R_InitTranslationTables(void); void R_UpdateTranslationTables(void); diff --git a/doomsday/engine/portable/include/r_draw.h b/doomsday/engine/portable/include/r_draw.h index 46994851b7..8d7e167fbd 100644 --- a/doomsday/engine/portable/include/r_draw.h +++ b/doomsday/engine/portable/include/r_draw.h @@ -29,6 +29,8 @@ #ifndef LIBDENG_REFRESH_DRAW_H #define LIBDENG_REFRESH_DRAW_H +#include "texture.h" + void R_InitViewWindow(void); void R_ShutdownViewWindow(void); diff --git a/doomsday/engine/portable/include/r_things.h b/doomsday/engine/portable/include/r_things.h index bc66a9dc99..61e6211265 100644 --- a/doomsday/engine/portable/include/r_things.h +++ b/doomsday/engine/portable/include/r_things.h @@ -99,7 +99,6 @@ typedef struct rendspriteparams_s { // Material: material_t* mat; int tMap, tClass; - float matOffset[2]; boolean matFlip[2]; // [S, T] Flip along the specified axis. // Lighting/color: diff --git a/doomsday/engine/portable/include/rend_list.h b/doomsday/engine/portable/include/rend_list.h index 576d53d949..1b6df827ac 100644 --- a/doomsday/engine/portable/include/rend_list.h +++ b/doomsday/engine/portable/include/rend_list.h @@ -34,7 +34,9 @@ // Multiplicative blending for dynamic lights? #define IS_MUL (dynlightBlend != 1 && !usingFog) -// Types of rendering primitives. +/** + * Types of render primitive supported by this module (polygons only). + */ typedef enum primtype_e { PT_FIRST = 0, PT_TRIANGLE_STRIP = PT_FIRST, // Used for most stuff. @@ -42,24 +44,18 @@ typedef enum primtype_e { NUM_PRIM_TYPES } primtype_t; -// Special rendpoly types. -typedef enum { - RPT_NORMAL = 0, - RPT_SKY_MASK, // A sky mask polygon. - RPT_LIGHT, // A dynamic light. - RPT_SHADOW, // An object shadow or fakeradio edge shadow. - RPT_SHINY // A shiny polygon. -} rendpolytype_t; - -typedef struct rtexmapuint_s { - DGLuint tex; - int magMode; - float blend; - float scale[2], offset[2]; // For use with the texture matrix. - blendmode_t blendMode; -} rtexmapunit_t; - -#define RTU(tu, u) ((tu)[u]) +/** + * @defgroup rendpolyFlags Rendpoly Flags. + * @{ + */ +#define RPF_SKYMASK 0x1 /// This primitive is to be added to the sky mask. +#define RPF_LIGHT 0x2 /// This primitive is to be added to the special lists for lights. +#define RPF_SHADOW 0x4 /// This primitive is to be added to the special lists for shadows (either object or fakeradio edge shadow). +#define RPF_HAS_DYNLIGHTS 0x8 /// Dynamic light primitives are to be drawn on top of this. + +/// Default rendpolyFlags +#define RPF_DEFAULT 0 +/**@}*/ extern int renderTextures; extern int renderWireframe; @@ -73,22 +69,114 @@ extern float detailFactor, detailScale; extern int torchAdditive; extern float torchColor[]; -void RL_Register(void); -void RL_Init(void); -boolean RL_IsMTexLights(void); -boolean RL_IsMTexDetails(void); - -void RL_ClearLists(void); -void RL_DeleteLists(void); - -void RL_AddPoly(primtype_t type, rendpolytype_t polyType, - const rvertex_t* rvertices, - const rtexcoord_t* rtexcoords, const rtexcoord_t* rtexcoords1, - const rtexcoord_t* rtexcoords2, - const rcolor_t* rcolors, - uint numVertices, uint numLights, - DGLuint modTex, float modColor[3], - const rtexmapunit_t rTU[NUM_TEXMAP_UNITS]); -void RL_RenderAllLists(void); +/// Register the console commands, variables, etc..., of this module. +void RL_Register(void); + +/// Initialize this module. +void RL_Init(void); + +/// Shutdown this module. +void RL_Shutdown(void); + +/// @return @c true iff multitexturing is currently enabled for lights. +boolean RL_IsMTexLights(void); + +/// @return @c true iff multitexturing is currently enabled for detail textures. +boolean RL_IsMTexDetails(void); + +void RL_ClearLists(void); + +void RL_DeleteLists(void); + +/** + * Reset the texture unit write state back to the initial default values. + * Any mappings between logical units and preconfigured RTU states are + * cleared at this time. + */ +void RL_LoadDefaultRtus(void); + +/** + * Map the texture unit write state for the identified @a idx unit + * to @a rtu. This creates a reference to @a rtu which MUST contine + * to remain accessible until the mapping is subsequently cleared + * or changed (explicitly by call to RL_MapRtu/RL_LoadDefaultRtus, + * or, implicitly by customizing the unit configuration through one + * of the RL_RTU* family of functions (at which point a copy will + * be performed). + */ +void RL_MapRtu(uint idx, const rtexmapunit_t* rtu); + +/** + * Copy the configuration for the identified @idx texture unit of + * the primitive writer's internal state from @a rtu. + * + * @param idx Logical index of the texture unit being configured. + * @param rtu Configured RTU state to copy the configuration from. + */ +void RL_CopyRtu(uint idx, const rtexmapunit_t* rtu); + +/// Change the scale property of the identified @a idx texture unit. +void RL_Rtu_SetScale(uint idx, float s, float t); +void RL_Rtu_SetScalev(uint idx, float st[2]); + +/// Scale the offset and scale properties of the identified @a idx +void RL_Rtu_Scale(uint idx, float scalar); +void RL_Rtu_ScaleST(uint idx, float st[2]); + +/// Change the offset property of the identified @a idx texture unit. +void RL_Rtu_SetOffset(uint idx, float s, float t); +void RL_Rtu_SetOffsetv(uint idx, float st[2]); + +/// Translate the offset property of the identified @a idx texture unit. +void RL_Rtu_TranslateOffset(uint idx, float s, float t); +void RL_Rtu_TranslateOffsetv(uint idx, float st[2]); + +/// Change the texture assigned to the identified @idx texture unit. +void RL_Rtu_SetTexture(uint idx, DGLuint glName); + +/** + * @param primType Type of primitive being written. + * @param flags @see rendpolyFlags + */ +void RL_AddPolyWithCoordsModulationReflection(primtype_t primType, int flags, + uint numElements, const rvertex_t* vertices, const rcolor_t* colors, + const rtexcoord_t* primaryCoords, const rtexcoord_t* interCoords, + DGLuint modTex, const rcolor_t* modColor, const rtexcoord_t* modCoords, + const rcolor_t* reflectionColors, const rtexcoord_t* reflectionCoords, + const rtexcoord_t* reflectionMaskCoords); + +/** + * @param primType Type of primitive being written. + * @param flags @see rendpolyFlags + */ +void RL_AddPolyWithCoordsModulation(primtype_t primType, int flags, + uint numElements, const rvertex_t* vertices, const rcolor_t* colors, + const rtexcoord_t* primaryCoords, const rtexcoord_t* interCoords, + DGLuint modTex, const rcolor_t* modColor, const rtexcoord_t* modCoords); + +/** + * @param primType Type of primitive being written. + * @param flags @see rendpolyFlags + */ +void RL_AddPolyWithCoords(primtype_t primType, int flags, uint numElements, + const rvertex_t* vertices, const rcolor_t* colors, + const rtexcoord_t* primaryCoords, const rtexcoord_t* interCoords); + +/** + * @param primType Type of primitive being written. + * @param flags @see rendpolyFlags + */ +void RL_AddPolyWithModulation(primtype_t primType, int flags, uint numElements, + const rvertex_t* vertices, const rcolor_t* colors, + DGLuint modTex, const rcolor_t* modColor, const rtexcoord_t* modCoords); + +/** + * @param primType Type of primitive being written. + * @param flags @see rendpolyFlags + */ +void RL_AddPoly(primtype_t primType, int flags, uint numElements, + const rvertex_t* vertices, const rcolor_t* colors); + +void RL_RenderAllLists(void); #endif /* LIBDENG_REND_LIST_H */ diff --git a/doomsday/engine/portable/include/rend_main.h b/doomsday/engine/portable/include/rend_main.h index 5a4358d2ed..bce538c298 100644 --- a/doomsday/engine/portable/include/rend_main.h +++ b/doomsday/engine/portable/include/rend_main.h @@ -63,9 +63,11 @@ extern int shadowMaxDistance; extern int useShinySurfaces; -void Rend_Register(void); -void Rend_Init(void); -void Rend_Reset(void); +void Rend_Register(void); + +void Rend_Init(void); +void Rend_Shutdown(void); +void Rend_Reset(void); void Rend_RenderMap(void); void Rend_ModelViewMatrix(boolean use_angles); diff --git a/doomsday/engine/portable/src/gl_main.c b/doomsday/engine/portable/src/gl_main.c index dd9b6860bf..3a892775d2 100644 --- a/doomsday/engine/portable/src/gl_main.c +++ b/doomsday/engine/portable/src/gl_main.c @@ -49,6 +49,7 @@ #include "colorpalette.h" #include "texturecontent.h" +#include "texturevariant.h" #include "materialvariant.h" #if defined(WIN32) && defined(WIN32_GAMMA) @@ -969,7 +970,7 @@ void GL_SetMaterialUI(material_t* mat) spec = Materials_VariantSpecificationForContext(MC_UI, 0, 1, 0, 0, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0, 1, 0, false, false, false, false); ms = Materials_Prepare(mat, spec, true); - GL_BindTexture(MSU(ms, MTU_PRIMARY).tex.glName, MSU(ms, MTU_PRIMARY).magMode); + GL_BindTexture(MSU_gltexture(ms, MTU_PRIMARY), MSU(ms, MTU_PRIMARY).magMode); } void GL_SetPSprite(material_t* mat, int tClass, int tMap) @@ -982,16 +983,15 @@ void GL_SetPSprite(material_t* mat, int tClass, int tMap) spec = Materials_VariantSpecificationForContext(MC_PSPRITE, 0, 1, tClass, tMap, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0, 1, 0, false, true, true, false); ms = Materials_Prepare(mat, spec, true); - GL_BindTexture(MSU(ms, MTU_PRIMARY).tex.glName, MSU(ms, MTU_PRIMARY).magMode); + GL_BindTexture(MSU_gltexture(ms, MTU_PRIMARY), MSU(ms, MTU_PRIMARY).magMode); } void GL_SetRawImage(lumpnum_t lumpNum, int wrapS, int wrapT) { rawtex_t* rawTex = R_GetRawTex(lumpNum); - if(NULL != rawTex) + if(rawTex) { - DGLuint tex = GL_PrepareRawTexture(rawTex); - GL_BindTexture(tex, (filterUI ? GL_LINEAR : GL_NEAREST)); + GL_BindTexture(GL_PrepareRawTexture(rawTex), (filterUI ? GL_LINEAR : GL_NEAREST)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); } diff --git a/doomsday/engine/portable/src/material.c b/doomsday/engine/portable/src/material.c index d50cfdd46c..2426be9138 100644 --- a/doomsday/engine/portable/src/material.c +++ b/doomsday/engine/portable/src/material.c @@ -59,12 +59,13 @@ void Material_Initialize(material_t* mat) void Material_Ticker(material_t* mat, timespan_t time) { + material_variantlist_node_t* node; assert(mat); - {material_variantlist_node_t* node; + for(node = mat->_variants; node; node = node->next) { MaterialVariant_Ticker(node->variant, time); - }} + } } ded_material_t* Material_Definition(const material_t* mat) diff --git a/doomsday/engine/portable/src/materials.c b/doomsday/engine/portable/src/materials.c index d891b0009a..7070daebe8 100644 --- a/doomsday/engine/portable/src/materials.c +++ b/doomsday/engine/portable/src/materials.c @@ -1125,34 +1125,21 @@ static void updateMaterialTextureLinks(materialbind_t* mb) Material_SetShinyStrength(mat, (refDef? refDef->shininess : 0)); } -static void setTexUnit(materialsnapshot_t* ss, byte unit, const texturevariant_t* tex, +static void setTexUnit(materialsnapshot_t* ms, byte unit, const texturevariant_t* texture, blendmode_t blendMode, int magMode, float sScale, float tScale, float sOffset, - float tOffset, float alpha) + float tOffset, float opacity) { - material_textureunit_t* tu; - assert(ss); + rtexmapunit_t* tu; + assert(ms && unit < NUM_MATERIAL_TEXTURE_UNITS); - tu = &MSU(ss, unit); - if(tex) - { - tu->tex.texture = TextureVariant_GeneralCase(tex); - tu->tex.spec = TextureVariant_Spec(tex); - tu->tex.glName = TextureVariant_GLName(tex); - TextureVariant_Coords(tex, &tu->tex.s, &tu->tex.t); - } - else - { - tu->tex.texture = NULL; - tu->tex.spec = NULL; - tu->tex.glName = 0; - tu->tex.s = tu->tex.t = 0; - } - - tu->magMode = magMode; + ms->textures[unit] = texture; + tu = &ms->units[unit]; + tu->tex = (texture? TextureVariant_GLName(texture) : 0); tu->blendMode = blendMode; - tu->alpha = MINMAX_OF(0, alpha, 1); + tu->magMode = magMode; V2_Set(tu->scale, sScale, tScale); V2_Set(tu->offset, sOffset, tOffset); + tu->opacity = MINMAX_OF(0, opacity, 1); } void Materials_InitSnapshot(materialsnapshot_t* ms) @@ -1160,34 +1147,36 @@ void Materials_InitSnapshot(materialsnapshot_t* ms) int i; assert(ms); - memset(ms, 0, sizeof(materialsnapshot_t)); - ms->width = ms->height = 0; - - for(i = 0; i < MATERIALVARIANT_MAXLAYERS; ++i) + for(i = 0; i < NUM_MATERIAL_TEXTURE_UNITS; ++i) { - setTexUnit(ms, i, NULL, BM_NORMAL, GL_LINEAR, 1, 1, 0, 0, 0); + Rtu_Init(&ms->units[i]); + ms->textures[i] = NULL; } + ms->width = ms->height = 0; + ms->glowing = 0; + ms->isOpaque = true; + V3_Set(ms->topColor, 1, 1, 1); V3_Set(ms->color, 1, 1, 1); V3_Set(ms->colorAmplified, 1, 1, 1); V3_Set(ms->shinyMinColor, 0, 0, 0); - - ms->glowing = 0; - ms->isOpaque = true; } -const materialsnapshot_t* Materials_PrepareVariant2(materialvariant_t* variant, boolean updateSnapshot) +/// @return Same as @a snapshot for caller convenience. +const materialsnapshot_t* updateMaterialSnapshot(materialvariant_t* variant, + materialsnapshot_t* snapshot) { static struct materialtextureunit_s { const texturevariant_t* tex; } texUnits[NUM_MATERIAL_TEXTURE_UNITS]; - materialsnapshot_t* snapshot; material_t* mat = MaterialVariant_GeneralCase(variant); const materialvariantspecification_t* spec = MaterialVariant_Spec(variant); int i, layerCount; + texture_t* tex; + assert(snapshot); - memset(texUnits, 0, sizeof(texUnits)); + memset(texUnits, 0, sizeof texUnits); // Ensure all resources needed to visualize this Material's layers have been prepared. layerCount = Material_LayerCount(mat); @@ -1222,64 +1211,35 @@ const materialsnapshot_t* Materials_PrepareVariant2(materialvariant_t* variant, } // Do we need to prepare a DetailTexture? - if(r_detail) + tex = Material_DetailTexture(mat); + if(tex) { - texture_t* tex = Material_DetailTexture(mat); - if(tex) - { - const float contrast = Material_DetailStrength(mat) * detailFactor; - texturevariantspecification_t* texSpec = GL_DetailTextureVariantSpecificationForContext(contrast); - texUnits[MTU_DETAIL].tex = GL_PrepareTextureVariant(tex, texSpec); - } + const float contrast = Material_DetailStrength(mat) * detailFactor; + texturevariantspecification_t* texSpec = GL_DetailTextureVariantSpecificationForContext(contrast); + texUnits[MTU_DETAIL].tex = GL_PrepareTextureVariant(tex, texSpec); } // Do we need to prepare a shiny texture (and possibly a mask)? - if(useShinySurfaces) + tex = Material_ShinyTexture(mat); + if(tex) { - texture_t* tex = Material_ShinyTexture(mat); - if(tex) - { - texturevariantspecification_t* texSpec = - GL_TextureVariantSpecificationForContext(TC_MAPSURFACE_REFLECTION, - TSF_NO_COMPRESSION, 0, 0, 0, GL_REPEAT, GL_REPEAT, 1, 1, -1, - false, false, false, false); + texturevariantspecification_t* texSpec = + GL_TextureVariantSpecificationForContext(TC_MAPSURFACE_REFLECTION, + TSF_NO_COMPRESSION, 0, 0, 0, GL_REPEAT, GL_REPEAT, 1, 1, -1, + false, false, false, false); - texUnits[MTU_REFLECTION].tex = GL_PrepareTextureVariant(tex, texSpec); + texUnits[MTU_REFLECTION].tex = GL_PrepareTextureVariant(tex, texSpec); - // We are only interested in a mask if we have a shiny texture. - if(texUnits[MTU_REFLECTION].tex && (tex = Material_ShinyMaskTexture(mat))) - { - texSpec = GL_TextureVariantSpecificationForContext( - TC_MAPSURFACE_REFLECTIONMASK, 0, 0, 0, 0, GL_REPEAT, GL_REPEAT, - -1, -1, -1, true, false, false, false); - texUnits[MTU_REFLECTION_MASK].tex = GL_PrepareTextureVariant(tex, texSpec); - } + // We are only interested in a mask if we have a shiny texture. + if(texUnits[MTU_REFLECTION].tex && (tex = Material_ShinyMaskTexture(mat))) + { + texSpec = GL_TextureVariantSpecificationForContext( + TC_MAPSURFACE_REFLECTIONMASK, 0, 0, 0, 0, GL_REPEAT, GL_REPEAT, + -1, -1, -1, true, false, false, false); + texUnits[MTU_REFLECTION_MASK].tex = GL_PrepareTextureVariant(tex, texSpec); } } - // Acquire the snapshot we will be updating. - snapshot = MaterialVariant_Snapshot(variant); - if(!snapshot) - { - // Time to allocate the snapshot. - snapshot = (materialsnapshot_t*)malloc(sizeof *snapshot); - if(!snapshot) - Con_Error("Materials::Prepare: Failed on allocation of %lu bytes for new MaterialSnapshot.", (unsigned long) sizeof *snapshot); - snapshot = MaterialVariant_AttachSnapshot(variant, snapshot); - Materials_InitSnapshot(snapshot); - - // Update the snapshot right away. - updateSnapshot = true; - } - else if(MaterialVariant_SnapshotPrepareFrame(variant) != frameCount) - { - // Time to update the snapshot. - updateSnapshot = true; - } - - // If we aren't updating a snapshot; get out of here. - if(!updateSnapshot) return snapshot; - MaterialVariant_SetSnapshotPrepareFrame(variant, frameCount); Materials_InitSnapshot(snapshot); @@ -1390,6 +1350,35 @@ const materialsnapshot_t* Materials_PrepareVariant2(materialvariant_t* variant, return snapshot; } +const materialsnapshot_t* Materials_PrepareVariant2(materialvariant_t* variant, boolean updateSnapshot) +{ + // Acquire the snapshot we are interested in. + materialsnapshot_t* snapshot = MaterialVariant_Snapshot(variant); + if(!snapshot) + { + // Time to allocate the snapshot. + snapshot = (materialsnapshot_t*)malloc(sizeof *snapshot); + if(!snapshot) + Con_Error("Materials::Prepare: Failed on allocation of %lu bytes for new MaterialSnapshot.", (unsigned long) sizeof *snapshot); + snapshot = MaterialVariant_AttachSnapshot(variant, snapshot); + Materials_InitSnapshot(snapshot); + + // Update the snapshot right away. + updateSnapshot = true; + } + else if(MaterialVariant_SnapshotPrepareFrame(variant) != frameCount) + { + // Time to update the snapshot. + updateSnapshot = true; + } + + // If we aren't updating a snapshot; get out of here. + if(!updateSnapshot) return snapshot; + + // We have work to do... + return updateMaterialSnapshot(variant, snapshot); +} + const materialsnapshot_t* Materials_PrepareVariant(materialvariant_t* variant) { return Materials_PrepareVariant2(variant, false/*do not force a snapshot update*/); diff --git a/doomsday/engine/portable/src/r_data.c b/doomsday/engine/portable/src/r_data.c index 64187a476f..e71309e1c0 100644 --- a/doomsday/engine/portable/src/r_data.c +++ b/doomsday/engine/portable/src/r_data.c @@ -43,6 +43,7 @@ #include "colorpalette.h" #include "texture.h" +#include "materialvariant.h" #include "font.h" // MACROS ------------------------------------------------------------------ @@ -821,6 +822,74 @@ void R_FreeRendTexCoords(rtexcoord_t* rtexcoords) #endif } +void Rtu_Init(rtexmapunit_t* rtu) +{ + assert(rtu); + rtu->tex = 0; + rtu->magMode = GL_LINEAR; + rtu->blendMode = BM_NORMAL; + rtu->opacity = 1; + rtu->scale[0] = rtu->scale[1] = 1; + rtu->offset[0] = rtu->offset[1] = 0; +} + +void Rtu_SetScale(rtexmapunit_t* rtu, float s, float t) +{ + assert(rtu); + rtu->scale[0] = s; + rtu->scale[1] = t; +} + +void Rtu_SetScalev(rtexmapunit_t* rtu, float const st[2]) +{ + assert(st); + Rtu_SetScale(rtu, st[0], st[0]); +} + +void Rtu_Scale(rtexmapunit_t* rtu, float scalar) +{ + assert(rtu); + rtu->scale[0] *= scalar; + rtu->scale[1] *= scalar; + rtu->offset[0] *= scalar; + rtu->offset[1] *= scalar; +} + +void Rtu_ScaleST(rtexmapunit_t* rtu, float const scalarST[2]) +{ + assert(rtu); + rtu->scale[0] *= scalarST[0]; + rtu->scale[1] *= scalarST[1]; + rtu->offset[0] *= scalarST[0]; + rtu->offset[1] *= scalarST[1]; +} + +void Rtu_SetOffset(rtexmapunit_t* rtu, float s, float t) +{ + assert(rtu); + rtu->offset[0] = s; + rtu->offset[1] = t; +} + +void Rtu_SetOffsetv(rtexmapunit_t* rtu, float const st[2]) +{ + assert(st); + Rtu_SetOffset(rtu, st[0], st[1]); +} + +void Rtu_TranslateOffset(rtexmapunit_t* rtu, float s, float t) +{ + assert(rtu); + rtu->offset[0] += s; + rtu->offset[1] += t; +} + +void Rtu_TranslateOffsetv(rtexmapunit_t* rtu, float const st[2]) +{ + assert(st); + Rtu_TranslateOffset(rtu, st[0], st[1]); +} + void R_DivVerts(rvertex_t* dst, const rvertex_t* src, const walldiv_t* divs) { #define COPYVERT(d, s) (d)->pos[VX] = (s)->pos[VX]; \ @@ -1142,7 +1211,7 @@ boolean R_GetPatchInfo(patchid_t id, patchinfo_t* info) if(!info) Con_Error("R_GetPatchInfo: Argument 'info' cannot be NULL."); - memset(info, 0, sizeof(*info)); + memset(info, 0, sizeof *info); tex = Textures_ToTexture(Textures_TextureForUniqueId(TN_PATCHES, id)); if(tex) { @@ -1162,7 +1231,12 @@ boolean R_GetPatchInfo(patchid_t id, patchinfo_t* info) info->extraOffset[0] = info->extraOffset[1] = (pTex->flags & PF_UPSCALE_AND_SHARPEN)? -1 : 0; return true; } - VERBOSE( Con_Message("Warning:R_GetPatchInfo Invalid Patch id #%i.\n", id) ) + if(id != 0) + { +#if _DEBUG + Con_Message("Warning:R_GetPatchInfo: Invalid Patch id #%i.\n", id); +#endif + } return false; } diff --git a/doomsday/engine/portable/src/r_draw.c b/doomsday/engine/portable/src/r_draw.c index d4b7a748e8..313b2e2ac2 100644 --- a/doomsday/engine/portable/src/r_draw.c +++ b/doomsday/engine/portable/src/r_draw.c @@ -36,6 +36,7 @@ #include "sys_opengl.h" #include "texture.h" +#include "texturevariant.h" #include "materialvariant.h" // MACROS ------------------------------------------------------------------ @@ -169,10 +170,9 @@ void R_DrawPatch3(texture_t* tex, int x, int y, int w, int h, boolean useOffsets return; } - glBindTexture(GL_TEXTURE_2D, GL_PreparePatchTexture(tex)); + GL_BindTexture(GL_PreparePatchTexture(tex), (filterUI ? GL_LINEAR : GL_NEAREST)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filterUI ? GL_LINEAR : GL_NEAREST)); if(useOffsets) { @@ -200,10 +200,9 @@ void R_DrawPatchTiled(texture_t* tex, int x, int y, int w, int h, DGLint wrapS, { if(!tex) return; - glBindTexture(GL_TEXTURE_2D, GL_PreparePatchTexture(tex)); + GL_BindTexture(GL_PreparePatchTexture(tex), (filterUI ? GL_LINEAR : GL_NEAREST)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filterUI ? GL_LINEAR : GL_NEAREST)); GL_DrawRectTiled(x, y, w, h, Texture_Width(tex), Texture_Height(tex)); } @@ -251,7 +250,7 @@ void R_DrawViewBorder(void) MC_UI, 0, 0, 0, 0, GL_REPEAT, GL_REPEAT, 0, 1, 0, false, false, false, false); const materialsnapshot_t* ms = Materials_Prepare(mat, spec, true); - GL_BindTexture(MSU(ms, MTU_PRIMARY).tex.glName, (filterUI ? GL_LINEAR : GL_NEAREST)); + GL_BindTexture(MSU_gltexture(ms, MTU_PRIMARY), (filterUI ? GL_LINEAR : GL_NEAREST)); GL_DrawCutRectTiled(0, 0, port->dimensions.width, port->dimensions.height, ms->width, ms->height, 0, 0, vd->window.x - border, vd->window.y - border, vd->window.width + 2 * border, vd->window.height + 2 * border); diff --git a/doomsday/engine/portable/src/r_lumobjs.c b/doomsday/engine/portable/src/r_lumobjs.c index 12974f208d..8cd932e459 100644 --- a/doomsday/engine/portable/src/r_lumobjs.c +++ b/doomsday/engine/portable/src/r_lumobjs.c @@ -36,6 +36,7 @@ #include "sys_opengl.h" #include "texture.h" +#include "texturevariant.h" #include "materialvariant.h" BEGIN_PROF_TIMERS() @@ -353,16 +354,17 @@ static void newLightProjection(uint* listIdx, int flags, DGLuint texture, */ static void calcLightColor(float outRGB[3], const float color[3], float light) { + int i; + light = MINMAX_OF(0, light, 1) * dynlightFactor; // In fog additive blending is used; the normal fog color is way too bright. if(usingFog) light *= dynlightFogBright; // Multiply light with (ambient) color. - { int i; for(i = 0; i < 3; ++i) { outRGB[i] = light * color[i]; - }} + } } typedef struct { @@ -749,8 +751,7 @@ static void addLuminous(mobj_t* mo) GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 1, -2, -1, true, true, true, false); ms = Materials_Prepare(mat, spec, true); - pl = (const pointlight_analysis_t*) Texture_Analysis( - MSU(ms, MTU_PRIMARY).tex.texture, TA_SPRITE_AUTOLIGHT); + pl = (const pointlight_analysis_t*) Texture_Analysis(MSU_texture(ms, MTU_PRIMARY), TA_SPRITE_AUTOLIGHT); if(!pl) return; // Not good... size = pl->brightMul; @@ -769,11 +770,11 @@ static void addLuminous(mobj_t* mo) autoLightColor[CB] = pl->color[CB]; #if _DEBUG - if(Textures_Namespace(Textures_Id(MSU(ms, MTU_PRIMARY).tex.texture)) != TN_SPRITES) + if(Textures_Namespace(Textures_Id(MSU_texture(ms, MTU_PRIMARY))) != TN_SPRITES) Con_Error("LO_AddLuminous: Internal error, material snapshot's primary texture is not a SpriteTex!"); #endif - sprTex = (spritetex_t*) Texture_UserData(MSU(ms, MTU_PRIMARY).tex.texture); + sprTex = (spritetex_t*) Texture_UserData(MSU_texture(ms, MTU_PRIMARY)); assert(sprTex); center = sprTex->offY - mo->floorClip - R_GetBobOffset(mo) - yOffset; diff --git a/doomsday/engine/portable/src/r_main.c b/doomsday/engine/portable/src/r_main.c index d0b571a36c..858f3967f5 100644 --- a/doomsday/engine/portable/src/r_main.c +++ b/doomsday/engine/portable/src/r_main.c @@ -465,12 +465,10 @@ void R_Update(void) R_UpdateData(); R_InitSprites(); // Fully reinitialize sprites. - R_UpdateTranslationTables(); - Cl_InitTranslations(); - R_InitModels(); // Defs might've changed. - Rend_ParticleLoadExtraTextures(); + R_UpdateTranslationTables(); + Cl_InitTranslations(); Def_PostInit(); P_UpdateParticleGens(); // Defs might've changed. @@ -544,6 +542,7 @@ void R_Shutdown(void) R_ShutdownVectorGraphics(); R_ShutdownViewWindow(); Fonts_Shutdown(); + Rend_Shutdown(); } void R_Ticker(timespan_t time) diff --git a/doomsday/engine/portable/src/r_model.c b/doomsday/engine/portable/src/r_model.c index da1fce5ef4..dfa1079bb0 100644 --- a/doomsday/engine/portable/src/r_model.c +++ b/doomsday/engine/portable/src/r_model.c @@ -48,6 +48,7 @@ #include "def_main.h" #include "texture.h" +#include "texturevariant.h" #include "materialvariant.h" // MACROS ------------------------------------------------------------------ @@ -811,11 +812,11 @@ static void R_ScaleModelToSprite(modeldef_t* mf, int sprite, int frame) ms = Materials_Prepare(spr->spriteFrames[frame].mats[0], spec, true); #if _DEBUG - if(Textures_Namespace(Textures_Id(MSU(ms, MTU_PRIMARY).tex.texture)) != TN_SPRITES) + if(Textures_Namespace(Textures_Id(MSU_texture(ms, MTU_PRIMARY))) != TN_SPRITES) Con_Error("R_ScaleModelToSprite: Internal error, material snapshot's primary texture is not a SpriteTex!"); #endif - sprTex = (spritetex_t*) Texture_UserData(MSU(ms, MTU_PRIMARY).tex.texture); + sprTex = (spritetex_t*) Texture_UserData(MSU_texture(ms, MTU_PRIMARY)); assert(sprTex); off = sprTex->offY - ms->height; diff --git a/doomsday/engine/portable/src/r_sky.c b/doomsday/engine/portable/src/r_sky.c index 400c3aca8c..c8da598a7e 100644 --- a/doomsday/engine/portable/src/r_sky.c +++ b/doomsday/engine/portable/src/r_sky.c @@ -37,6 +37,7 @@ #include "m_vector.h" #include "rend_sky.h" #include "texture.h" +#include "texturevariant.h" #include "materialvariant.h" // MACROS ------------------------------------------------------------------ @@ -169,9 +170,8 @@ static void prepareSkySphere(void) 0, 0, 0, GL_REPEAT, GL_REPEAT, 1, 1, 0, false, true, false, false); ms = Materials_Prepare(slayer->material, spec, false); - slayer->tex = MSU(ms, MTU_PRIMARY).tex.glName; - Texture_Dimensions(MSU(ms, MTU_PRIMARY).tex.texture, - &slayer->texWidth, &slayer->texHeight); + slayer->tex = MSU_gltexture(ms, MTU_PRIMARY); + Texture_Dimensions(MSU_texture(ms, MTU_PRIMARY), &slayer->texWidth, &slayer->texHeight); slayer->texMagMode = MSU(ms, MTU_PRIMARY).magMode; slayer->fadeout.rgb[CR] = ms->topColor[CR]; @@ -392,16 +392,15 @@ void R_SkyTicker(void) void Rend_SkyReleaseTextures(void) { - if(novideo || isDedicated) - return; - { int i; + int i; + if(novideo || isDedicated) return; + for(i = 0; i < MAXSKYLAYERS; ++i) { skylayer_t* slayer = &skyLayers[i]; - if(slayer->tex) - glDeleteTextures(1, &slayer->tex); + glDeleteTextures(1, (GLuint*)&slayer->tex); slayer->tex = 0; - }} + } } const float* R_SkyAmbientColor(void) diff --git a/doomsday/engine/portable/src/r_things.c b/doomsday/engine/portable/src/r_things.c index 7a12757f7a..ca279f995a 100644 --- a/doomsday/engine/portable/src/r_things.c +++ b/doomsday/engine/portable/src/r_things.c @@ -55,6 +55,7 @@ #include "blockset.h" #include "m_stack.h" #include "texture.h" +#include "texturevariant.h" #include "materialvariant.h" // MACROS ------------------------------------------------------------------ @@ -625,13 +626,13 @@ boolean R_GetSpriteInfo(int sprite, int frame, spriteinfo_t* info) ms = Materials_Prepare(mat, spec, false); #if _DEBUG - if(Textures_Namespace(Textures_Id(MSU(ms, MTU_PRIMARY).tex.texture)) != TN_SPRITES) + if(Textures_Namespace(Textures_Id(MSU_texture(ms, MTU_PRIMARY))) != TN_SPRITES) Con_Error("R_GetSpriteInfo: Internal error, material snapshot's primary texture is not a SpriteTex!"); #endif - sprTex = (spritetex_t*) Texture_UserData(MSU(ms, MTU_PRIMARY).tex.texture); + sprTex = (spritetex_t*) Texture_UserData(MSU_texture(ms, MTU_PRIMARY)); assert(sprTex); - texSpec = TS_GENERAL(MSU(ms, MTU_PRIMARY).tex.spec); + texSpec = TS_GENERAL(MSU_texturespec(ms, MTU_PRIMARY)); assert(texSpec); info->numFrames = sprDef->numFrames; @@ -641,8 +642,7 @@ boolean R_GetSpriteInfo(int sprite, int frame, spriteinfo_t* info) info->topOffset = sprTex->offY + texSpec->border; info->width = ms->width + texSpec->border*2; info->height = ms->height + texSpec->border*2; - info->texCoord[0] = MSU(ms, MTU_PRIMARY).tex.s; - info->texCoord[1] = MSU(ms, MTU_PRIMARY).tex.t; + TextureVariant_Coords(MST(ms, MTU_PRIMARY), &info->texCoord[0], &info->texCoord[1]); return true; } @@ -959,13 +959,13 @@ static void setupSpriteParamsForVisSprite(rendspriteparams_t *params, ms = Materials_Prepare(mat, spec, true); #if _DEBUG - if(Textures_Namespace(Textures_Id(MSU(ms, MTU_PRIMARY).tex.texture)) != TN_SPRITES) + if(Textures_Namespace(Textures_Id(MSU_texture(ms, MTU_PRIMARY))) != TN_SPRITES) Con_Error("setupSpriteParamsForVisSprite: Internal error, material snapshot's primary texture is not a SpriteTex!"); #endif - sprTex = (spritetex_t*) Texture_UserData(MSU(ms, MTU_PRIMARY).tex.texture); + sprTex = (spritetex_t*) Texture_UserData(MSU_texture(ms, MTU_PRIMARY)); assert(sprTex); - texSpec = TS_GENERAL(MSU(ms, MTU_PRIMARY).tex.spec); + texSpec = TS_GENERAL(MSU_texturespec(ms, MTU_PRIMARY)); assert(texSpec); params->width = ms->width + texSpec->border*2; @@ -987,8 +987,6 @@ static void setupSpriteParamsForVisSprite(rendspriteparams_t *params, params->mat = mat; params->tMap = tMap; params->tClass = tClass; - params->matOffset[0] = MSU(ms, MTU_PRIMARY).tex.s; - params->matOffset[1] = MSU(ms, MTU_PRIMARY).tex.t; params->matFlip[0] = matFlipS; params->matFlip[1] = matFlipT; params->blendMode = (useSpriteBlend? blendMode : BM_NORMAL); @@ -1214,11 +1212,11 @@ void R_ProjectSprite(mobj_t* mo) ms = Materials_Prepare(mat, spec, true); #if _DEBUG - if(Textures_Namespace(Textures_Id(MSU(ms, MTU_PRIMARY).tex.texture)) != TN_SPRITES) + if(Textures_Namespace(Textures_Id(MSU_texture(ms, MTU_PRIMARY))) != TN_SPRITES) Con_Error("R_ProjectSprite: Internal error, material snapshot's primary texture is not a SpriteTex!"); #endif - sprTex = (spritetex_t*) Texture_UserData(MSU(ms, MTU_PRIMARY).tex.texture); + sprTex = (spritetex_t*) Texture_UserData(MSU_texture(ms, MTU_PRIMARY)); assert(sprTex); // Align to the view plane? @@ -1498,8 +1496,8 @@ void R_ProjectSprite(mobj_t* mo) GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 1,-2, -1, true, true, true, false); ms = Materials_Prepare(mat, spec, true); - pl = (const pointlight_analysis_t*) Texture_Analysis( - MSU(ms, MTU_PRIMARY).tex.texture, TA_SPRITE_AUTOLIGHT); + pl = (const pointlight_analysis_t*) + Texture_Analysis(MSU_texture(ms, MTU_PRIMARY), TA_SPRITE_AUTOLIGHT); if(!pl) return; // Not good... lum = LO_GetLuminous(mo->lumIdx); diff --git a/doomsday/engine/portable/src/rend_console.c b/doomsday/engine/portable/src/rend_console.c index 82c7feb136..ab8c05d9fe 100644 --- a/doomsday/engine/portable/src/rend_console.c +++ b/doomsday/engine/portable/src/rend_console.c @@ -533,7 +533,7 @@ static void drawConsoleBackground(int x, int y, int w, int h, float closeFade) MC_UI, 0, 0, 0, 0, GL_REPEAT, GL_REPEAT, 0, 1, 0, false, false, false, false); const materialsnapshot_t* ms = Materials_Prepare(consoleBackgroundMaterial, spec, Con_IsActive()); - GL_BindTexture(MSU(ms, MTU_PRIMARY).tex.glName, MSU(ms, MTU_PRIMARY).magMode); + GL_BindTexture(MSU_gltexture(ms, MTU_PRIMARY), MSU(ms, MTU_PRIMARY).magMode); bgX = (int) (ms->width * consoleBackgroundZoom); bgY = (int) (ms->height * consoleBackgroundZoom); diff --git a/doomsday/engine/portable/src/rend_dynlight.c b/doomsday/engine/portable/src/rend_dynlight.c index f1d2571d66..efa7f3baeb 100644 --- a/doomsday/engine/portable/src/rend_dynlight.c +++ b/doomsday/engine/portable/src/rend_dynlight.c @@ -24,6 +24,7 @@ #include "de_base.h" #include "de_console.h" +#include "de_graphics.h" #include "de_refresh.h" #include "de_render.h" @@ -37,23 +38,13 @@ int RIT_RenderLightProjectionIterator(const dynlight_t* dyn, void* paramaters) rvertex_t* rvertices; rtexcoord_t* rtexcoords; rcolor_t* rcolors; - rtexmapunit_t rTU[NUM_TEXMAP_UNITS]; uint i, c; - memset(rTU, 0, sizeof(rTU)); - // Allocate enough for the divisions too. rvertices = R_AllocRendVertices(p->realNumVertices); rtexcoords = R_AllocRendTexCoords(p->realNumVertices); rcolors = R_AllocRendColors(p->realNumVertices); - rTU[TU_PRIMARY].tex = dyn->texture; - rTU[TU_PRIMARY].magMode = GL_LINEAR; - - rTU[TU_PRIMARY_DETAIL].tex = 0; - rTU[TU_INTER].tex = 0; - rTU[TU_INTER_DETAIL].tex = 0; - for(i = 0; i < p->numVertices; ++i) { rcolor_t* col = &rcolors[i]; @@ -120,25 +111,21 @@ int RIT_RenderLightProjectionIterator(const dynlight_t* dyn, void* paramaters) memcpy(rvertices, p->rvertices, sizeof(rvertex_t) * p->numVertices); } + RL_LoadDefaultRtus(); + RL_Rtu_SetTexture(RTU_PRIMARY, dyn->texture); + if(p->isWall && p->divs) { - RL_AddPoly(PT_FAN, RPT_LIGHT, - rvertices + 3 + p->divs[0].num, - rtexcoords + 3 + p->divs[0].num, NULL, NULL, - rcolors + 3 + p->divs[0].num, - 3 + p->divs[1].num, 0, - 0, NULL, rTU); - RL_AddPoly(PT_FAN, RPT_LIGHT, - rvertices, rtexcoords, NULL, NULL, - rcolors, 3 + p->divs[0].num, 0, - 0, NULL, rTU); + RL_AddPolyWithCoords(PT_FAN, RPF_DEFAULT|RPF_LIGHT, + 3 + p->divs[1].num, rvertices + 3 + p->divs[0].num, + rcolors + 3 + p->divs[0].num, rtexcoords + 3 + p->divs[0].num, NULL); + RL_AddPolyWithCoords(PT_FAN, RPF_DEFAULT|RPF_LIGHT, + 3 + p->divs[0].num, rvertices, rcolors, rtexcoords, NULL); } else { - RL_AddPoly(p->isWall? PT_TRIANGLE_STRIP : PT_FAN, RPT_LIGHT, - rvertices, rtexcoords, NULL, NULL, - rcolors, p->numVertices, 0, - 0, NULL, rTU); + RL_AddPolyWithCoords(p->isWall? PT_TRIANGLE_STRIP : PT_FAN, RPF_DEFAULT|RPF_LIGHT, + p->numVertices, rvertices, rcolors, rtexcoords, NULL); } R_FreeRendVertices(rvertices); diff --git a/doomsday/engine/portable/src/rend_fakeradio.c b/doomsday/engine/portable/src/rend_fakeradio.c index feca78ac13..867c9e98c2 100644 --- a/doomsday/engine/portable/src/rend_fakeradio.c +++ b/doomsday/engine/portable/src/rend_fakeradio.c @@ -956,25 +956,17 @@ static void quadTexCoords(rtexcoord_t* tc, const rvertex_t* rverts, tc[0].st[1] = tc[3].st[1] + (rverts[3].pos[VZ] - rverts[2].pos[VZ]) / texHeight; } -static void renderShadowSeg(const rvertex_t* origVertices, - const walldiv_t* divs, - const rendershadowseg_params_t* p, - const float shadowRGB[3], float shadowDark) +static void renderShadowSeg(const rvertex_t* origVertices, const walldiv_t* divs, + const rendershadowseg_params_t* p, const float shadowRGB[3], float shadowDark) { float texOrigin[2][3]; rcolor_t* rcolors; rtexcoord_t* rtexcoords; - rtexmapunit_t rTU[NUM_TEXMAP_UNITS]; uint realNumVertices = 4; if(divs) realNumVertices = 3 + divs[0].num + 3 + divs[1].num; - memset(rTU, 0, sizeof(rTU)); - rTU[TU_PRIMARY].tex = GL_PrepareLSTexture(p->texture); - rTU[TU_PRIMARY].magMode = GL_LINEAR; - rTU[TU_PRIMARY].blend = 1; - // Top left. texOrigin[0][VX] = origVertices[1].pos[VX]; texOrigin[0][VY] = origVertices[1].pos[VY]; @@ -998,12 +990,15 @@ static void renderShadowSeg(const rvertex_t* origVertices, if(rendFakeRadio != 2) { // Write multiple polys depending on rend params. + RL_LoadDefaultRtus(); + RL_Rtu_SetTexture(RTU_PRIMARY, GL_PrepareLSTexture(p->texture)); + if(divs) { - float bL, tL, bR, tR; - rvertex_t* rvertices; - rtexcoord_t origTexCoords[4]; - rcolor_t origColors[4]; + float bL, tL, bR, tR; + rvertex_t* rvertices; + rtexcoord_t origTexCoords[4]; + rcolor_t origColors[4]; /** * Need to swap indices around into fans set the position @@ -1025,20 +1020,18 @@ static void renderShadowSeg(const rvertex_t* origVertices, R_DivTexCoords(rtexcoords, origTexCoords, divs, bL, tL, bR, tR); R_DivVertColors(rcolors, origColors, divs, bL, tL, bR, tR); - RL_AddPoly(PT_FAN, RPT_SHADOW, rvertices + 3 + divs[0].num, - rtexcoords + 3 + divs[0].num, NULL, NULL, - rcolors + 3 + divs[0].num, 3 + divs[1].num, - 0, 0, NULL, rTU); - RL_AddPoly(PT_FAN, RPT_SHADOW, rvertices, rtexcoords, NULL, NULL, - rcolors, 3 + divs[0].num, 0, 0, NULL, rTU); + RL_AddPolyWithCoords(PT_FAN, RPF_DEFAULT|RPF_SHADOW, + 3 + divs[1].num, rvertices + 3 + divs[0].num, rcolors + 3 + divs[0].num, + rtexcoords + 3 + divs[0].num, NULL); + RL_AddPolyWithCoords(PT_FAN, RPF_DEFAULT|RPF_SHADOW, + 3 + divs[0].num, rvertices, rcolors, rtexcoords, NULL); R_FreeRendVertices(rvertices); } else { - RL_AddPoly(PT_TRIANGLE_STRIP, RPT_SHADOW, origVertices, - rtexcoords, NULL, NULL, - rcolors, 4, 0, 0, NULL, rTU); + RL_AddPolyWithCoords(PT_TRIANGLE_STRIP, RPF_DEFAULT|RPF_SHADOW, + 4, origVertices, rcolors, rtexcoords, NULL); } } @@ -1232,9 +1225,9 @@ static uint radioEdgeHackType(const linedef_t* line, const sector_t* front, cons /** * Construct and write a new shadow polygon to the rendering lists. */ -/*static*/ void addShadowEdge(vec2_t inner[2], vec2_t outer[2], float innerLeftZ, +static void addShadowEdge(vec2_t inner[2], vec2_t outer[2], float innerLeftZ, float innerRightZ, float outerLeftZ, float outerRightZ, const float sideOpen[2], - const float edgeOpen[2], boolean isFloor, const float shadowRGB[3], float shadowDark, const rtexmapunit_t rTU[NUM_TEXMAP_UNITS]) + const float edgeOpen[2], boolean isFloor, const float shadowRGB[3], float shadowDark) { static const uint floorIndices[][4] = {{0, 1, 2, 3}, {1, 2, 3, 0}}; static const uint ceilIndices[][4] = {{0, 3, 2, 1}, {1, 0, 3, 2}}; @@ -1243,12 +1236,11 @@ static uint radioEdgeHackType(const linedef_t* line, const sector_t* front, cons rcolor_t rcolors[4]; vec2_t outerAlpha; const uint* idx; - uint winding; // Winding: 0 = left, 1 = right + uint i, winding; // Winding: 0 = left, 1 = right V2_Set(outerAlpha, MIN_OF(shadowDark * (1 - edgeOpen[0]), 1), MIN_OF(shadowDark * (1 - edgeOpen[1]), 1)); - if(!(outerAlpha[0] > .0001 && outerAlpha[1] > .0001)) - return; + if(!(outerAlpha[0] > .0001 && outerAlpha[1] > .0001)) return; // What vertex winding order? // (for best results, the cross edge should always be the shortest). @@ -1277,13 +1269,12 @@ static uint radioEdgeHackType(const linedef_t* line, const sector_t* front, cons rvertices[idx[3]].pos[VZ] = innerLeftZ; // Light this polygon. - { int i; for(i = 0; i < 4; ++i) { rcolors[idx[i]].rgba[CR] = (renderWireframe? 1 : shadowRGB[CR]); rcolors[idx[i]].rgba[CG] = (renderWireframe? 1 : shadowRGB[CG]); rcolors[idx[i]].rgba[CB] = (renderWireframe? 1 : shadowRGB[CB]); - }} + } // Right inner. rcolors[idx[2]].rgba[CA] = 0; @@ -1301,37 +1292,43 @@ static uint radioEdgeHackType(const linedef_t* line, const sector_t* front, cons if(sideOpen[1] < 1) rcolors[idx[1]].rgba[CA] *= 1 - sideOpen[1]; - if(rendFakeRadio != 2) - RL_AddPoly(PT_FAN, (renderWireframe? RPT_NORMAL : RPT_SHADOW), rvertices, NULL, NULL, NULL, rcolors, 4, 0, 0, NULL, rTU); + if(rendFakeRadio == 2) return; + + RL_LoadDefaultRtus(); + RL_AddPoly(PT_FAN, RPF_DEFAULT | (!renderWireframe? RPF_SHADOW : 0), 4, rvertices, rcolors); } -/*static*/ void drawEdgeShadow(const subsector_t* ssec, const linedef_t* lineDef, uint side, - uint planeId, float shadowDark) +static void processEdgeShadow(const subsector_t* ssec, const linedef_t* lineDef, + uint side, uint planeId, float shadowDark) { - assert(ssec && lineDef && (side == FRONT || side == BACK) && lineDef->L_side(side) && planeId <= lineDef->L_sector(side)->planeCount); - { const sidedef_t* sideDef = lineDef->L_side(side? BACK : FRONT); const plane_t* pln = sideDef->sector->SP_plane(planeId); - float plnHeight, fz, bz, bhz; vec2_t inner[2], outer[2], edgeOpen, sideOpen; - vec3_t shadowRGB; + const materialvariantspecification_t* spec; + const materialsnapshot_t* ms; + float plnHeight, fz, bz, bhz; sector_t* front, *back; const surface_t* suf; + vec3_t shadowRGB; + int i; + assert(ssec && lineDef && (side == FRONT || side == BACK) && lineDef->L_side(side) && planeId <= lineDef->L_sector(side)->planeCount); - if(!(shadowDark > .0001)) - return; - - // Determine the openness of the lineDef. If this edge is edgeOpen, - // there won't be a shadow at all. Open neighbours cause some - // changes in the polygon corner vertices (placement, colour). + if(!(shadowDark > .0001)) return; suf = &pln->surface; plnHeight = pln->visHeight; // Glowing surfaces or missing textures shouldn't have shadows. - if((suf->inFlags & SUIF_NO_RADIO) || !suf->material || R_IsSkySurface(suf)) - return; + if((suf->inFlags & SUIF_NO_RADIO) || !suf->material || R_IsSkySurface(suf)) return; + + spec = Materials_VariantSpecificationForContext(MC_MAPSURFACE, 0, 0, 0, 0, GL_REPEAT, GL_REPEAT, + -1, -1, -1, true, true, false, false); + ms = Materials_Prepare(pln->PS_material, spec, true); + if(ms->glowing > 0) return; + // Determine the openness of the lineDef. If this edge is edgeOpen, + // there won't be a shadow at all. Open neighbours cause some + // changes in the polygon corner vertices (placement, colour). if(lineDef->L_backside) { uint hackType; @@ -1352,14 +1349,14 @@ static uint radioEdgeHackType(const linedef_t* line, const sector_t* front, cons } } else + { V2_Set(edgeOpen, 0, 0); + } - if(edgeOpen[0] >= 1 && edgeOpen[1] >= 1) - return; + if(edgeOpen[0] >= 1 && edgeOpen[1] >= 1) return; // Find the neighbors of this edge and determine their 'openness'. sideOpen[0] = sideOpen[1] = 0; - { int i; for(i = 0; i < 2; ++i) { lineowner_t* vo; @@ -1417,45 +1414,33 @@ static uint radioEdgeHackType(const linedef_t* line, const sector_t* front, cons { V2_Sum(inner[i], lineDef->L_vpos(i^side), vo->shadowOffsets.extended); } - }} + } V2_Copy(outer[0], lineDef->L_vpos(side)); V2_Copy(outer[1], lineDef->L_vpos(side^1)); - - { - const materialvariantspecification_t* spec = Materials_VariantSpecificationForContext( - MC_MAPSURFACE, 0, 0, 0, 0, GL_REPEAT, GL_REPEAT, -1, -1, -1, true, true, false, false); - const materialsnapshot_t* ms = Materials_Prepare(pln->PS_material, spec, true); - rtexmapunit_t rTU[NUM_TEXMAP_UNITS]; - - if(ms->glowing > 0) return; - - memset(rTU, 0, sizeof(rTU)); - rTU[TU_PRIMARY].blend = 1; - // Shadows are black V3_Set(shadowRGB, 0, 0, 0); - addShadowEdge(inner, outer, plnHeight, plnHeight, plnHeight, plnHeight, sideOpen, edgeOpen, suf->normal[VZ] > 0, shadowRGB, shadowDark, rTU); } - } + addShadowEdge(inner, outer, plnHeight, plnHeight, plnHeight, plnHeight, sideOpen, edgeOpen, suf->normal[VZ] > 0, shadowRGB, shadowDark); } -static void drawLinkedEdgeShadows(const subsector_t* ssec, shadowlink_t* link, const byte* doPlanes, float shadowDark) +static void drawLinkedEdgeShadows(const subsector_t* ssec, shadowlink_t* link, + const byte* doPlanes, float shadowDark) { + uint pln; assert(ssec && link && doPlanes); - if(!(shadowDark > .0001)) - return; + if(!(shadowDark > .0001)) return; if(doPlanes[PLN_FLOOR]) - drawEdgeShadow(ssec, link->lineDef, link->side, PLN_FLOOR, shadowDark); + processEdgeShadow(ssec, link->lineDef, link->side, PLN_FLOOR, shadowDark); if(doPlanes[PLN_CEILING]) - drawEdgeShadow(ssec, link->lineDef, link->side, PLN_CEILING, shadowDark); - { uint pln; + processEdgeShadow(ssec, link->lineDef, link->side, PLN_CEILING, shadowDark); + for(pln = PLN_MID; pln < ssec->sector->planeCount; ++pln) { - drawEdgeShadow(ssec, link->lineDef, link->side, pln, shadowDark); - }} + processEdgeShadow(ssec, link->lineDef, link->side, pln, shadowDark); + } // Mark it rendered for this frame. link->lineDef->shadowVisFrame[link->side] = (ushort) frameCount; @@ -1531,8 +1516,7 @@ static void radioSubsectorEdges(const subsector_t* subsector) { // Already rendered during the current frame? We only want to // render each shadow once per frame. - if(link->lineDef->shadowVisFrame[link->side] == (ushort) frameCount) - continue; + if(link->lineDef->shadowVisFrame[link->side] == (ushort) frameCount) continue; drawLinkedEdgeShadows(subsector, link, doPlanes, shadowDark); }} } diff --git a/doomsday/engine/portable/src/rend_font.c b/doomsday/engine/portable/src/rend_font.c index 24605a3c91..1243722359 100644 --- a/doomsday/engine/portable/src/rend_font.c +++ b/doomsday/engine/portable/src/rend_font.c @@ -826,7 +826,7 @@ static void drawChar(unsigned char ch, int posX, int posY, font_t* font, if(patch) { - glBindTexture(GL_TEXTURE_2D, GL_PreparePatchTexture(Textures_ToTexture(Textures_TextureForUniqueId(TN_PATCHES, patch)))); + GL_BindTexture(GL_PreparePatchTexture(Textures_ToTexture(Textures_TextureForUniqueId(TN_PATCHES, patch))), filterUI? GL_LINEAR : GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 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 5a939ec5ab..d69e5e5d1f 100644 --- a/doomsday/engine/portable/src/rend_list.c +++ b/doomsday/engine/portable/src/rend_list.c @@ -24,8 +24,9 @@ */ /** - * Doomsday Rendering Lists v3.2 + * Doomsday Rendering Lists v3.3 * + * 3.3 -- Texture unit write state and revised primitive write interface. * 3.2 -- Shiny walls and floors * 3.1 -- Support for multiple shadow textures * 3.0 -- Multitexturing @@ -127,6 +128,24 @@ enum { NUM_TEXCOORD_ARRAYS }; +// Texture unit indices. These map to real GL texture units. +typedef enum { + TU_PRIMARY = 0, + TU_PRIMARY_DETAIL, + TU_INTER, + TU_INTER_DETAIL, + NUM_TEXTURE_UNITS +} texunitid_t; + +// Primitive types. +typedef enum { + PT_NORMAL = 0, + PT_SKY_MASK, // A sky mask polygon. + PT_LIGHT, // A dynamic light. + PT_SHADOW, // An object shadow or fakeradio edge shadow. + PT_SHINY +} rendpolytype_t; + /** * Primitive flags: */ @@ -177,7 +196,7 @@ typedef struct primhdr_s { typedef struct rendlist_texmapunit_s { DGLuint tex; int magMode; - float blend; // Blend amount. + float opacity; // Blend amount. blendmode_t blendMode; // Currently used only with shiny pass. } rendlist_texmapunit_t; @@ -187,7 +206,7 @@ typedef struct rendlist_texmapunit_s { */ typedef struct rendlist_s { struct rendlist_s* next; - rendlist_texmapunit_t texmapunits[NUM_TEXMAP_UNITS]; + rendlist_texmapunit_t texmapunits[NUM_TEXTURE_UNITS]; size_t size; // Number of bytes allocated for the data. byte* data; // Data for a number of polygons (The List). byte* cursor; // A pointer to data, for reading/writing. @@ -231,6 +250,16 @@ int torchAdditive = true; // PRIVATE DATA DEFINITIONS ------------------------------------------------ +static boolean initedOk = false; + +// Logical texture unit state. Used with RL_LoadDefaultRtus and RL_CopyRtu +static rtexmapunit_t rtuDefault; +static rtexmapunit_t rtuState[NUM_TEXMAP_UNITS]; +static rtexmapunit_t const* rtuMap[NUM_TEXMAP_UNITS]; + +// GL texture unit state used during write. Global for performance reasons. +static rtexmapunit_t const* texunits[NUM_TEXTURE_UNITS]; + /** * The vertex arrays. */ @@ -272,6 +301,10 @@ void RL_Register(void) static void rlBind(DGLuint tex, int magMode) { +#ifdef _DEBUG + GLenum error; +#endif + if(!renderTextures) tex = 0; @@ -279,22 +312,18 @@ static void rlBind(DGLuint tex, int magMode) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magMode); if(GL_state.features.texFilterAniso) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, - GL_GetTexAnisoMul(texAniso)); -#ifdef _DEBUG -{ -GLenum error; -if((error = glGetError()) != GL_NO_ERROR) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GL_GetTexAnisoMul(texAniso)); + +#if _DEBUG +error = glGetError(); +if(error != GL_NO_ERROR) Con_Error("OpenGL error: %i\n", error); -} #endif } static void rlBind2(const rendlist_texmapunit_t* tmu) { - if(!tmu->tex) - return; - + if(!tmu->tex) return; rlBind(tmu->tex, tmu->magMode); } @@ -312,11 +341,10 @@ static void clearHash(listhash_t* hash) memset(hash, 0, sizeof(listhash_t) * RL_HASH_SIZE); } -/** - * Called only once, from R_Init -> Rend_Init. - */ void RL_Init(void) { + if(initedOk) return; // Already been here. + clearHash(plainHash); clearHash(litHash); clearHash(dynHash); @@ -324,6 +352,17 @@ void RL_Init(void) clearHash(shinyHash); memset(&skyMaskList, 0, sizeof(skyMaskList)); + Rtu_Init(&rtuDefault); + RL_LoadDefaultRtus(); + initedOk = true; +} + +void RL_Shutdown(void) +{ + // Stub. + /// \todo Rework list memory management so we explicitly free it, rather + /// than depend on it being free'd by the Zone when it is shutdown. + initedOk = false; } boolean RL_IsMTexLights(void) @@ -469,15 +508,15 @@ static void rewindList(rendlist_t* rl) // The interpolation target must be explicitly set (in RL_AddPoly). TU(rl, TU_INTER)->tex = 0; - TU(rl, TU_INTER)->blend = 0; + TU(rl, TU_INTER)->opacity = 0; TU(rl, TU_INTER_DETAIL)->tex = 0; - TU(rl, TU_INTER_DETAIL)->blend = 0; + TU(rl, TU_INTER_DETAIL)->opacity = 0; } static void rewindHash(listhash_t* hash) { - uint i; - rendlist_t* list; + uint i; + rendlist_t* list; for(i = 0; i < RL_HASH_SIZE; ++i) { @@ -508,7 +547,7 @@ void RL_ClearLists(void) static rendlist_t* createList(listhash_t* hash) { - rendlist_t* list = Z_Calloc(sizeof(rendlist_t), PU_APPSTATIC, 0); + rendlist_t* list = Z_Calloc(sizeof(rendlist_t), PU_APPSTATIC, 0); if(hash->last) hash->last->next = list; @@ -518,34 +557,28 @@ static rendlist_t* createList(listhash_t* hash) return list; } -static __inline void copyTU(rendlist_texmapunit_t* lTU, - const rtexmapunit_t* rTU) +static __inline void copyTU(rendlist_texmapunit_t* ltu, const rtexmapunit_t* rtu) { - lTU->tex = rTU->tex; - lTU->magMode = rTU->magMode; - lTU->blendMode = rTU->blendMode; - lTU->blend = MINMAX_OF(0, rTU->blend, 1); + ltu->tex = rtu->tex; + ltu->magMode = rtu->magMode; + ltu->blendMode = rtu->blendMode; + ltu->opacity = MINMAX_OF(0, rtu->opacity, 1); } -static __inline boolean compareTU(const rendlist_texmapunit_t* lTU, - const rtexmapunit_t* rTU) +static __inline boolean compareTU(const rendlist_texmapunit_t* ltu, const rtexmapunit_t* rtu) { - if(lTU->tex == rTU->tex && lTU->magMode == rTU->magMode && - lTU->blend == rTU->blend) + if(ltu->tex == rtu->tex && ltu->magMode == rtu->magMode && ltu->opacity == rtu->opacity) return true; - return false; } -static rendlist_t* getListFor(rendpolytype_t polyType, - const rtexmapunit_t rTU[NUM_TEXMAP_UNITS], - boolean useLights) +static rendlist_t* getListFor(rendpolytype_t polyType, boolean isLit) { - listhash_t* hash, *table; - rendlist_t* dest, *convertable = NULL; + listhash_t* hash, *table; + rendlist_t* dest, *convertable = NULL; // Check for specialized rendering lists first. - if(polyType == RPT_SKY_MASK) + if(polyType == PT_SKY_MASK) { return &skyMaskList; } @@ -553,43 +586,43 @@ static rendlist_t* getListFor(rendpolytype_t polyType, // Choose the correct hash table. switch(polyType) { - case RPT_SHINY: table = shinyHash; break; - case RPT_SHADOW: table = shadowHash; break; - case RPT_LIGHT: table = dynHash; break; + case PT_SHINY: table = shinyHash; break; + case PT_SHADOW: table = shadowHash; break; + case PT_LIGHT: table = dynHash; break; default: - table = (useLights ? litHash : plainHash); + table = (isLit ? litHash : plainHash); break; } // Find/create a list in the hash. - hash = &table[rTU[TU_PRIMARY].tex % RL_HASH_SIZE]; + hash = &table[texunits[TU_PRIMARY]->tex % RL_HASH_SIZE]; for(dest = hash->first; dest; dest = dest->next) { - if((polyType == RPT_SHINY && - compareTU(TU(dest, TU_PRIMARY), &rTU[TU_PRIMARY])) || - (polyType != RPT_SHINY && - compareTU(TU(dest, TU_PRIMARY), &rTU[TU_PRIMARY]) && - compareTU(TU(dest, TU_PRIMARY_DETAIL), &rTU[TU_PRIMARY_DETAIL]))) + if((polyType == PT_SHINY && + compareTU(TU(dest, TU_PRIMARY), texunits[TU_PRIMARY])) || + (polyType != PT_SHINY && + compareTU(TU(dest, TU_PRIMARY), texunits[TU_PRIMARY]) && + compareTU(TU(dest, TU_PRIMARY_DETAIL), texunits[TU_PRIMARY_DETAIL]))) { - if(!TU(dest, TU_INTER)->tex && !rTU[TU_INTER].tex) + if(!TU(dest, TU_INTER)->tex && !texunits[TU_INTER]->tex) { // This will do great. return dest; } // Is this eligible for conversion to a blended list? - if(!dest->last && !convertable && rTU[TU_INTER].tex) + if(!dest->last && !convertable && texunits[TU_INTER]->tex) { // If necessary, this empty list will be selected. convertable = dest; } // Possibly an exact match? - if((polyType == RPT_SHINY && - compareTU(TU(dest, TU_INTER), &rTU[TU_INTER])) || - (polyType != RPT_SHINY && - compareTU(TU(dest, TU_INTER), &rTU[TU_INTER]) && - compareTU(TU(dest, TU_INTER_DETAIL), &rTU[TU_INTER_DETAIL]))) + if((polyType == PT_SHINY && + compareTU(TU(dest, TU_INTER), texunits[TU_INTER])) || + (polyType != PT_SHINY && + compareTU(TU(dest, TU_INTER), texunits[TU_INTER]) && + compareTU(TU(dest, TU_INTER_DETAIL), texunits[TU_INTER_DETAIL]))) { return dest; } @@ -599,14 +632,14 @@ static rendlist_t* getListFor(rendpolytype_t polyType, // Did we find a convertable list? if(convertable) { // This list is currently empty. - if(polyType == RPT_SHINY) + if(polyType == PT_SHINY) { - copyTU(TU(convertable, TU_INTER), &rTU[TU_INTER]); + copyTU(TU(convertable, TU_INTER), texunits[TU_INTER]); } else { - copyTU(TU(convertable, TU_INTER), &rTU[TU_INTER]); - copyTU(TU(convertable, TU_INTER_DETAIL), &rTU[TU_INTER_DETAIL]); + copyTU(TU(convertable, TU_INTER), texunits[TU_INTER]); + copyTU(TU(convertable, TU_INTER_DETAIL), texunits[TU_INTER_DETAIL]); } return convertable; @@ -616,21 +649,21 @@ static rendlist_t* getListFor(rendpolytype_t polyType, dest = createList(hash); // Init the info. - if(polyType == RPT_SHINY) + if(polyType == PT_SHINY) { - copyTU(TU(dest, TU_PRIMARY), &rTU[TU_PRIMARY]); - if(rTU[TU_INTER].tex) - copyTU(TU(dest, TU_INTER), &rTU[TU_INTER]); + copyTU(TU(dest, TU_PRIMARY), texunits[TU_PRIMARY]); + if(texunits[TU_INTER]->tex) + copyTU(TU(dest, TU_INTER), texunits[TU_INTER]); } else { - copyTU(TU(dest, TU_PRIMARY), &rTU[TU_PRIMARY]); - copyTU(TU(dest, TU_PRIMARY_DETAIL), &rTU[TU_PRIMARY_DETAIL]); + copyTU(TU(dest, TU_PRIMARY), texunits[TU_PRIMARY]); + copyTU(TU(dest, TU_PRIMARY_DETAIL), texunits[TU_PRIMARY_DETAIL]); - if(rTU[TU_INTER].tex) + if(texunits[TU_INTER]->tex) { - copyTU(TU(dest, TU_INTER), &rTU[TU_INTER]); - copyTU(TU(dest, TU_INTER_DETAIL), &rTU[TU_INTER_DETAIL]); + copyTU(TU(dest, TU_INTER), texunits[TU_INTER]); + copyTU(TU(dest, TU_INTER_DETAIL), texunits[TU_INTER_DETAIL]); } } @@ -711,7 +744,7 @@ static void* allocateData(rendlist_t* list, int bytes) static void allocateIndices(rendlist_t* list, uint numIndices) { - void* indices; + void* indices; list->last->numIndices = numIndices; indices = allocateData(list, sizeof(uint) * numIndices); @@ -723,44 +756,39 @@ static void allocateIndices(rendlist_t* list, uint numIndices) static void endWrite(rendlist_t* list) { // The primitive has been written, update the size in the header. - list->last->size = list->cursor - (byte *) list->last; + list->last->size = list->cursor - (byte*) list->last; // Write the end marker (which will be overwritten by the next // primitive). The idea is that this zero is interpreted as the // size of the following primhdr. - *(int *) list->cursor = 0; + *(int*) list->cursor = 0; } static void writePrimitive(const rendlist_t* list, uint base, - const rvertex_t* rvertices, - const rtexcoord_t* coords, - const rtexcoord_t* coords1, - const rtexcoord_t* coords2, - const rcolor_t* rcolors, uint numVertices, - rendpolytype_t type) + const rvertex_t* rvertices, const rtexcoord_t* coords, + const rtexcoord_t* coords1, const rtexcoord_t* coords2, + const rcolor_t* rcolors, uint numElements, rendpolytype_t type) { - uint i; + uint i; - for(i = 0; i < numVertices; ++i) + for(i = 0; i < numElements; ++i) { // Vertex. - { - const rvertex_t* rvtx = &rvertices[i]; - dgl_vertex_t* vtx = &vertices[base + i]; + const rvertex_t* rvtx = &rvertices[i]; + dgl_vertex_t* vtx = &vertices[base + i]; vtx->xyz[0] = rvtx->pos[VX]; vtx->xyz[1] = rvtx->pos[VZ]; vtx->xyz[2] = rvtx->pos[VY]; - } - if(type == RPT_SKY_MASK) - continue; // Sky masked polys need nothing more. + // Sky masked polys need nothing more. + if(type == PT_SKY_MASK) continue; // Primary texture coordinates. if(TU(list, TU_PRIMARY)->tex) { - const rtexcoord_t* rtc = &coords[i]; - dgl_texcoord_t* tc = &texCoords[TCA_MAIN][base + i]; + const rtexcoord_t* rtc = &coords[i]; + dgl_texcoord_t* tc = &texCoords[TCA_MAIN][base + i]; tc->st[0] = rtc->st[0]; tc->st[1] = rtc->st[1]; @@ -769,8 +797,8 @@ static void writePrimitive(const rendlist_t* list, uint base, // Secondary texture coordinates. if(TU(list, TU_INTER)->tex) { - const rtexcoord_t* rtc = &coords1[i]; - dgl_texcoord_t* tc = &texCoords[TCA_BLEND][base + i]; + const rtexcoord_t* rtc = &coords1[i]; + dgl_texcoord_t* tc = &texCoords[TCA_BLEND][base + i]; tc->st[0] = rtc->st[0]; tc->st[1] = rtc->st[1]; @@ -779,8 +807,8 @@ static void writePrimitive(const rendlist_t* list, uint base, // First light texture coordinates. if((list->last->flags & PF_IS_LIT) && IS_MTEX_LIGHTS) { - const rtexcoord_t* rtc = &coords2[i]; - dgl_texcoord_t* tc = &texCoords[TCA_LIGHT][base + i]; + const rtexcoord_t* rtc = &coords2[i]; + dgl_texcoord_t* tc = &texCoords[TCA_LIGHT][base + i]; tc->st[0] = rtc->st[0]; tc->st[1] = rtc->st[1]; @@ -788,8 +816,8 @@ static void writePrimitive(const rendlist_t* list, uint base, // Color. { - const rcolor_t* rcolor = &rcolors[i]; - dgl_color_t* color = &colors[base + i]; + const rcolor_t* rcolor = &rcolors[i]; + dgl_color_t* color = &colors[base + i]; color->rgba[CR] = (DGLubyte) (255 * MINMAX_OF(0, rcolor->rgba[CR], 1)); color->rgba[CG] = (DGLubyte) (255 * MINMAX_OF(0, rcolor->rgba[CG], 1)); @@ -801,24 +829,19 @@ static void writePrimitive(const rendlist_t* list, uint base, /** * Adds one or more polys the render lists depending on configuration. + * \assume Caller knows what they are doing. Arguments are not validity checked. */ -static void addPoly(primtype_t type, rendpolytype_t polyType, - const rvertex_t* rvertices, - const rtexcoord_t* rtexcoords, - const rtexcoord_t* rtexcoords1, - const rtexcoord_t* rtexcoords2, const rcolor_t* rcolors, - uint numVertices, blendmode_t blendMode, - uint numLights, - DGLuint modTex, float modColor[3], - const rtexmapunit_t rTU[NUM_TEXMAP_UNITS]) +static void writePoly2(primtype_t type, rendpolytype_t polyType, int flags, + uint numElements, const rvertex_t* vertices, const rcolor_t* colors, + const rtexcoord_t* primaryCoords, const rtexcoord_t* interCoords, + DGLuint modTex, const rcolor_t* modColor, const rtexcoord_t* modCoords) { - uint i, base, primSize, numIndices; - rendlist_t* li; - primhdr_t* hdr; - boolean useLights = - (polyType != RPT_LIGHT && numLights > 0); + const boolean isLit = (polyType != PT_LIGHT && (modTex || !!(flags & RPF_HAS_DYNLIGHTS))); + uint i, base, primSize, numIndices; + rendlist_t* li; + primhdr_t* hdr; - if(polyType == RPT_SKY_MASK) + if(polyType == PT_SKY_MASK) rDrawSky = true; BEGIN_PROF( PROF_RL_ADD_POLY ); @@ -826,12 +849,12 @@ BEGIN_PROF( PROF_RL_ADD_POLY ); BEGIN_PROF( PROF_RL_GET_LIST ); // Find/create a rendering list for the polygon's texture. - li = getListFor(polyType, rTU, useLights); + li = getListFor(polyType, isLit); END_PROF( PROF_RL_GET_LIST ); - primSize = numVertices; - numIndices = numVertices; + primSize = numElements; + numIndices = numElements; base = allocateVertices(primSize); hdr = allocateData(li, sizeof(primhdr_t)); @@ -839,42 +862,45 @@ END_PROF( PROF_RL_GET_LIST ); li->last = hdr; // This becomes the new last primitive. // Primitive-specific blending mode. - hdr->blendMode = blendMode; + hdr->blendMode = texunits[TU_PRIMARY]->blendMode; hdr->size = 0; hdr->indices = NULL; hdr->numIndices = 0; hdr->flags = 0; - if(numLights > 1) - hdr->flags |= PF_MANY_LIGHTS; - else if(numLights == 1) - hdr->flags |= PF_ONE_LIGHT; + if(isLit) + { + if(modTex && !(flags & RPF_HAS_DYNLIGHTS)) + hdr->flags |= PF_ONE_LIGHT; // Using modulation. + else + hdr->flags |= PF_MANY_LIGHTS; + } hdr->modTex = modTex; - hdr->modColor[CR] = modColor? modColor[CR] : 0; - hdr->modColor[CG] = modColor? modColor[CG] : 0; - hdr->modColor[CB] = modColor? modColor[CB] : 0; + hdr->modColor[CR] = modColor? modColor->red : 0; + hdr->modColor[CG] = modColor? modColor->green : 0; + hdr->modColor[CB] = modColor? modColor->blue : 0; hdr->modColor[CA] = 0; - if(polyType == RPT_SHINY && rTU[TU_INTER].tex) + if(polyType == PT_SHINY && texunits[TU_INTER]->tex) { - hdr->ptexScale[0] = rTU[TU_INTER].scale[0]; - hdr->ptexScale[1] = rTU[TU_INTER].scale[1]; - hdr->ptexOffset[0] = rTU[TU_INTER].offset[0]; - hdr->ptexOffset[1] = rTU[TU_INTER].offset[1]; + hdr->ptexScale[0] = texunits[TU_INTER]->scale[0]; + hdr->ptexScale[1] = texunits[TU_INTER]->scale[1]; + hdr->ptexOffset[0] = texunits[TU_INTER]->offset[0] * texunits[TU_INTER]->scale[0]; + hdr->ptexOffset[1] = texunits[TU_INTER]->offset[1] * texunits[TU_INTER]->scale[1]; } - else if(rTU[TU_PRIMARY].tex) + else if(texunits[TU_PRIMARY]->tex) { - hdr->ptexScale[0] = rTU[TU_PRIMARY].scale[0]; - hdr->ptexScale[1] = rTU[TU_PRIMARY].scale[1]; - hdr->ptexOffset[0] = rTU[TU_PRIMARY].offset[0]; - hdr->ptexOffset[1] = rTU[TU_PRIMARY].offset[1]; + hdr->ptexScale[0] = texunits[TU_PRIMARY]->scale[0]; + hdr->ptexScale[1] = texunits[TU_PRIMARY]->scale[1]; + hdr->ptexOffset[0] = texunits[TU_PRIMARY]->offset[0] * texunits[TU_PRIMARY]->scale[0]; + hdr->ptexOffset[1] = texunits[TU_PRIMARY]->offset[1] * texunits[TU_PRIMARY]->scale[1]; } - if(rTU[TU_PRIMARY_DETAIL].tex) + if(texunits[TU_PRIMARY_DETAIL]->tex) { - hdr->texScale[0] = rTU[TU_PRIMARY_DETAIL].scale[0]; - hdr->texScale[1] = rTU[TU_PRIMARY_DETAIL].scale[1]; - hdr->texOffset[0] = rTU[TU_PRIMARY_DETAIL].offset[0]; - hdr->texOffset[1] = rTU[TU_PRIMARY_DETAIL].offset[1]; + hdr->texScale[0] = texunits[TU_PRIMARY_DETAIL]->scale[0]; + hdr->texScale[1] = texunits[TU_PRIMARY_DETAIL]->scale[1]; + hdr->texOffset[0] = texunits[TU_PRIMARY_DETAIL]->offset[0] * texunits[TU_PRIMARY_DETAIL]->scale[0]; + hdr->texOffset[1] = texunits[TU_PRIMARY_DETAIL]->offset[1] * texunits[TU_PRIMARY_DETAIL]->scale[1]; } else { @@ -889,30 +915,278 @@ END_PROF( PROF_RL_GET_LIST ); li->last->type = (type == PT_TRIANGLE_STRIP? GL_TRIANGLE_STRIP : GL_TRIANGLE_FAN); - writePrimitive(li, base, rvertices, rtexcoords, rtexcoords1, - rtexcoords2, rcolors, numVertices, polyType); + writePrimitive(li, base, vertices, primaryCoords, interCoords, + modCoords, colors, numElements, polyType); endWrite(li); END_PROF( PROF_RL_ADD_POLY ); } -void RL_AddPoly(primtype_t type, rendpolytype_t polyType, - const rvertex_t* rvertices, - const rtexcoord_t* rtexcoords, const rtexcoord_t* rtexcoords1, - const rtexcoord_t* rtexcoords2, - const rcolor_t* rcolors, - uint numVertices, uint numLights, - DGLuint modTex, float modColor[3], - const rtexmapunit_t rTU[NUM_TEXMAP_UNITS]) +/** + * Rationalizes write arguments prior to flushing the write. + * Implemented for the purposes of cleaner/more readable code in modules which + * interface with this. + */ +static void writePoly(primtype_t type, rendpolytype_t polyType, int flags, + uint numElements, const rvertex_t* vertices, const rcolor_t* colors, + const rtexcoord_t* primaryCoords, const rtexcoord_t* interCoords, + DGLuint modTex, const rcolor_t* modColor, const rtexcoord_t* modCoords) +{ + if(numElements < 3) return; // huh? + + /// \todo Logical disconnect: modulation VS dynlight multitexture state. + if(modTex && !RL_IsMTexLights()) + Con_Error("RL_AddPoly: Attempt to write modulated primitive with multitexture disabled."); + + if(flags & RPF_SKYMASK) + { + flags &= ~(RPF_LIGHT|RPF_SHADOW|RPF_HAS_DYNLIGHTS); + colors = NULL; + primaryCoords = NULL; + interCoords = NULL; + modTex = 0; + modColor = NULL; + modCoords = NULL; + } + else if(flags & RPF_LIGHT) + { + flags &= ~(RPF_SHADOW|RPF_HAS_DYNLIGHTS); + interCoords = NULL; + modTex = 0; + modColor = NULL; + modCoords = NULL; + } + else if(flags & RPF_SHADOW) + { + flags &= ~RPF_HAS_DYNLIGHTS; + interCoords = NULL; + modTex = 0; + modColor = NULL; + modCoords = NULL; + } + + // Flush the write. + writePoly2(type, polyType, flags, numElements, vertices, + colors, primaryCoords, interCoords, modTex, modColor, modCoords); +} + +static __inline boolean validRTUIndex(uint idx) +{ + return idx < NUM_TEXMAP_UNITS; +} + +static __inline void errorIfNotValidRTUIndex(uint idx, const char* callerName) +{ + if(validRTUIndex(idx)) return; + Con_Error("%s: Invalid texture unit index %u.", callerName, idx); + exit(1); // Unreachable. +} + +static __inline boolean isWriteStateRTU(const rtexmapunit_t* ptr) +{ + // Note that the default texture unit is not considered as being + // part of the write state. + return ptr >= &rtuState[0] && ptr <= &rtuState[NUM_TEXMAP_UNITS]; +} + +/** + * If the identified @idx texture unit of the primitive writer has been + * mapped to an external address, insert a copy of it into our internal + * write state. + * + * To be called before customizing a texture unit begins to ensure we + * are modifying data we have ownership of! + */ +static void copyMappedRtuToState(uint idx) +{ + assert(validRTUIndex(idx)); + if(isWriteStateRTU(rtuMap[idx])) return; + RL_CopyRtu(idx, rtuMap[idx]); +} + +void RL_LoadDefaultRtus(void) +{ + int i; + for(i = 0; i < NUM_TEXMAP_UNITS; ++i) + { + rtuMap[i] = &rtuDefault; + } +} + +void RL_MapRtu(uint idx, const rtexmapunit_t* rtu) +{ + errorIfNotValidRTUIndex(idx, "RL_MapRtu"); + rtuMap[idx] = (rtu? rtu : &rtuDefault); +} + +void RL_CopyRtu(uint idx, const rtexmapunit_t* rtu) +{ + errorIfNotValidRTUIndex(idx, "RL_CopyRtu"); + if(!rtu) + { + // Restore defaults. + rtuMap[idx] = &rtuDefault; + return; + } + // Some _DEBUG error checking here wouldn't go amiss! + memcpy(rtuState + idx, rtu, sizeof rtuState[0]); + // Map this unit to that owned by the write state. + rtuMap[idx] = rtuState + idx; +} + +void RL_Rtu_SetScale(uint idx, float s, float t) +{ + errorIfNotValidRTUIndex(idx, "RL_Rtu_SetScale"); + copyMappedRtuToState(idx); + Rtu_SetScale(rtuState + idx, s, t); +} + +void RL_Rtu_SetScalev(uint idx, float st[2]) +{ + errorIfNotValidRTUIndex(idx, "RL_Rtu_SetScalev"); + copyMappedRtuToState(idx); + Rtu_SetScalev(rtuState + idx, st); +} + +void RL_Rtu_Scale(uint idx, float scalar) +{ + errorIfNotValidRTUIndex(idx, "RL_Rtu_Scale"); + copyMappedRtuToState(idx); + Rtu_Scale(rtuState + idx, scalar); +} + +void RL_Rtu_ScaleST(uint idx, float st[2]) +{ + errorIfNotValidRTUIndex(idx, "RL_Rtu_ScaleST"); + copyMappedRtuToState(idx); + Rtu_ScaleST(rtuState + idx, st); +} + +void RL_Rtu_SetOffset(uint idx, float x, float y) +{ + errorIfNotValidRTUIndex(idx, "RL_Rtu_SetOffset"); + copyMappedRtuToState(idx); + Rtu_SetOffset(rtuState + idx, x, y); +} + +void RL_Rtu_SetOffsetv(uint idx, float xy[2]) +{ + errorIfNotValidRTUIndex(idx, "RL_Rtu_SetOffsetv"); + copyMappedRtuToState(idx); + Rtu_SetOffsetv(rtuState + idx, xy); +} + +void RL_Rtu_TranslateOffset(uint idx, float x, float y) +{ + errorIfNotValidRTUIndex(idx, "RL_Rtu_TranslateOffset"); + copyMappedRtuToState(idx); + Rtu_TranslateOffset(rtuState + idx, x, y); +} + +void RL_Rtu_TranslateOffsetv(uint idx, float xy[2]) { - if(numVertices < 3) - return; // huh? + errorIfNotValidRTUIndex(idx, "RL_Rtu_TranslateOffsetv"); + copyMappedRtuToState(idx); + Rtu_TranslateOffsetv(rtuState + idx, xy); +} + +void RL_Rtu_SetTexture(uint idx, DGLuint glName) +{ + errorIfNotValidRTUIndex(idx, "RL_Rtu_SetTexture"); + copyMappedRtuToState(idx); + rtuState[idx].tex = glName; +} + +/** + * Choose a specialised polytype from the specified primitive configuration. + * @param flags @see rendpolyFlags + */ +static __inline rendpolytype_t choosePolyType(int flags) +{ + return ((flags & RPF_SKYMASK)? PT_SKY_MASK : + (flags & RPF_LIGHT) ? PT_LIGHT : + (flags & RPF_SHADOW) ? PT_SHADOW : PT_NORMAL); +} + +// Prepare the final texture unit map for writing "normal" polygons, filling +// any gaps using a default configured texture unit. +static void prepareTextureUnitMap(void) +{ + // Map logical texture units to "real" ones known to the GL renderer. + texunits[TU_PRIMARY] = rtuMap[RTU_PRIMARY]; + texunits[TU_PRIMARY_DETAIL] = rtuMap[RTU_PRIMARY_DETAIL]; + texunits[TU_INTER] = rtuMap[RTU_INTER]; + texunits[TU_INTER_DETAIL] = rtuMap[RTU_INTER_DETAIL]; +} + +// Prepare the final texture unit map for writing "shiny" polygons, filling +// any gaps using a default configured texture unit. +static void prepareTextureUnitMapForShinyPoly(void) +{ + // Map logical texture units to "real" ones known to the GL renderer. + texunits[TU_PRIMARY] = rtuMap[RTU_REFLECTION]; + texunits[TU_PRIMARY_DETAIL] = &rtuDefault; + texunits[TU_INTER] = rtuMap[RTU_REFLECTION_MASK]; + texunits[TU_INTER_DETAIL] = &rtuDefault; +} + +void RL_AddPolyWithCoordsModulationReflection(primtype_t primType, int flags, + uint numElements, const rvertex_t* vertices, const rcolor_t* colors, + const rtexcoord_t* primaryCoords, const rtexcoord_t* interCoords, + DGLuint modTex, const rcolor_t* modColor, const rtexcoord_t* modCoords, + const rcolor_t* reflectionColors, const rtexcoord_t* reflectionCoords, + const rtexcoord_t* reflectionMaskCoords) +{ + const rtexmapunit_t* rtuShiny; + + prepareTextureUnitMap(); + writePoly(primType, choosePolyType(flags), flags, numElements, + vertices, colors, primaryCoords, interCoords, modTex, modColor, modCoords); + + // We are currently limited to two texture units, therefore shiny effects + // must be drawn in a separate pass using a new primitive. + rtuShiny = rtuMap[RTU_REFLECTION]? rtuMap[RTU_REFLECTION] : &rtuDefault; + if(!rtuShiny->tex) return; + + prepareTextureUnitMapForShinyPoly(); + writePoly(primType, PT_SHINY, flags & ~RPF_HAS_DYNLIGHTS, numElements, + vertices, reflectionColors, reflectionCoords, reflectionMaskCoords, 0, NULL, NULL); +} + +void RL_AddPolyWithCoordsModulation(primtype_t primType, int flags, uint numElements, + const rvertex_t* vertices, const rcolor_t* colors, const rtexcoord_t* primaryCoords, + const rtexcoord_t* interCoords, + DGLuint modTex, const rcolor_t* modColor, const rtexcoord_t* modCoords) +{ + prepareTextureUnitMap(); + writePoly(primType, choosePolyType(flags), flags, numElements, + vertices, colors, primaryCoords, interCoords, modTex, modColor, modCoords); +} - if(type < PT_FIRST || type >= NUM_PRIM_TYPES) - Con_Error("RL_AddPoly: Unknown primtype %i.", type); +void RL_AddPolyWithCoords(primtype_t primType, int flags, uint numElements, + const rvertex_t* vertices, const rcolor_t* colors, + const rtexcoord_t* primaryCoords, const rtexcoord_t* interCoords) +{ + prepareTextureUnitMap(); + writePoly(primType, choosePolyType(flags), flags, numElements, + vertices, colors, primaryCoords, interCoords, 0, NULL, NULL); +} + +void RL_AddPolyWithModulation(primtype_t primType, int flags, uint numElements, + const rvertex_t* vertices, const rcolor_t* colors, + DGLuint modTex, const rcolor_t* modColor, const rtexcoord_t* modCoords) +{ + prepareTextureUnitMap(); + writePoly(primType, choosePolyType(flags), flags, numElements, + vertices, colors, NULL, NULL, modTex, modColor, modCoords); +} - addPoly(type, polyType, rvertices, rtexcoords, rtexcoords1, rtexcoords2, - rcolors, numVertices, rTU[TU_PRIMARY].blendMode, numLights, modTex, modColor, rTU); +void RL_AddPoly(primtype_t primType, int flags, uint numElements, const rvertex_t* vertices, + const rcolor_t* colors) +{ + prepareTextureUnitMap(); + writePoly(primType, choosePolyType(flags), flags, numElements, + vertices, colors, NULL, NULL, 0, NULL, NULL); } /** @@ -1115,7 +1389,7 @@ if(numTexUnits < 2) GL_ModulateTexture(2); color[0] = color[1] = color[2] = 0; - color[3] = TU(list, TU_INTER)->blend; + color[3] = TU(list, TU_INTER)->opacity; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); } else @@ -1159,7 +1433,7 @@ if(numTexUnits < 2) GL_ModulateTexture(2); - color[0] = color[1] = color[2] = 0; color[3] = TU(list, TU_INTER)->blend; + color[0] = color[1] = color[2] = 0; color[3] = TU(list, TU_INTER)->opacity; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); return DCF_SET_MATRIX_TEXTURE0 | DCF_SET_MATRIX_TEXTURE1; } @@ -1193,8 +1467,8 @@ if(numTexUnits < 2) // Mode 3 actually just disables the second texture stage, // which would modulate with primary color. #ifdef _DEBUG -if(numTexUnits < 2) - Con_Error("setupListState: Not enough texture units.\n"); + if(numTexUnits < 2) + Con_Error("setupListState: Not enough texture units.\n"); #endif GL_SelectTexUnits(2); @@ -1203,7 +1477,7 @@ if(numTexUnits < 2) GL_ModulateTexture(3); - color[0] = color[1] = color[2] = 0; color[3] = TU(list, TU_INTER)->blend; + color[0] = color[1] = color[2] = 0; color[3] = TU(list, TU_INTER)->opacity; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); // Render all primitives. return DCF_SET_MATRIX_TEXTURE0 | DCF_SET_MATRIX_TEXTURE1; @@ -1280,7 +1554,7 @@ if(numTexUnits < 2) rlBindTo(0, TU(list, TU_PRIMARY_DETAIL)); rlBindTo(1, TU(list, TU_INTER_DETAIL)); - color[0] = color[1] = color[2] = 0; color[3] = TU(list, TU_INTER_DETAIL)->blend; + color[0] = color[1] = color[2] = 0; color[3] = TU(list, TU_INTER_DETAIL)->opacity; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); return DCF_SET_MATRIX_DTEXTURE0 | DCF_SET_MATRIX_DTEXTURE1; } diff --git a/doomsday/engine/portable/src/rend_main.c b/doomsday/engine/portable/src/rend_main.c index 5342bce779..54df35a074 100644 --- a/doomsday/engine/portable/src/rend_main.c +++ b/doomsday/engine/portable/src/rend_main.c @@ -40,11 +40,12 @@ #include "de_refresh.h" #include "de_play.h" #include "de_graphics.h" - #include "de_misc.h" #include "de_ui.h" #include "de_system.h" + #include "net_main.h" +#include "texturevariant.h" #include "materialvariant.h" // MACROS ------------------------------------------------------------------ @@ -221,8 +222,13 @@ float Rend_PointDist3D(const float c[3]) void Rend_Init(void) { - C_Init(); // Clipper. - RL_Init(); // Rendering lists. + C_Init(); + RL_Init(); +} + +void Rend_Shutdown(void) +{ + RL_Shutdown(); } /// World/map renderer reset. @@ -857,10 +863,9 @@ int RIT_FirstDynlightIterator(const dynlight_t* dyn, void* paramaters) */ void Rend_AddMaskedPoly(const rvertex_t* rvertices, const rcolor_t* rcolors, float wallLength, - float texWidth, float texHeight, + DGLuint tex, int magMode, float texWidth, float texHeight, const float texOffset[2], blendmode_t blendMode, - uint lightListIdx, float glow, boolean masked, - const rtexmapunit_t rTU[NUM_TEXMAP_UNITS]) + uint lightListIdx, float glow, boolean masked) { vissprite_t* vis = R_NewVisSprite(); int i, c; @@ -875,8 +880,8 @@ void Rend_AddMaskedPoly(const rvertex_t* rvertices, vis->center[VY] = midpoint[VY]; vis->center[VZ] = midpoint[VZ]; vis->distance = Rend_PointDist2D(midpoint); - vis->data.wall.tex = rTU[TU_PRIMARY].tex; - vis->data.wall.magMode = rTU[TU_PRIMARY].magMode; + vis->data.wall.tex = tex; + vis->data.wall.magMode = magMode; vis->data.wall.masked = masked; for(i = 0; i < 4; ++i) { @@ -1092,154 +1097,9 @@ static float getSnapshots(const materialsnapshot_t** msA, const materialsnapshot } } -static void setupRTU(rtexmapunit_t main[NUM_TEXMAP_UNITS], rtexmapunit_t reflection[NUM_TEXMAP_UNITS], - const materialsnapshot_t* msA, float inter, const materialsnapshot_t* msB) -{ - RTU(main, TU_PRIMARY).tex = MSU(msA, MTU_PRIMARY).tex.glName; - RTU(main, TU_PRIMARY).magMode = MSU(msA, MTU_PRIMARY).magMode; - RTU(main, TU_PRIMARY).scale[0] = MSU(msA, MTU_PRIMARY).scale[0]; - RTU(main, TU_PRIMARY).scale[1] = MSU(msA, MTU_PRIMARY).scale[1]; - RTU(main, TU_PRIMARY).offset[0] = MSU(msA, MTU_PRIMARY).offset[0] * RTU(main, TU_PRIMARY).scale[0]; - RTU(main, TU_PRIMARY).offset[1] = MSU(msA, MTU_PRIMARY).offset[1] * RTU(main, TU_PRIMARY).scale[1]; - RTU(main, TU_PRIMARY).blendMode = MSU(msA, MTU_PRIMARY).blendMode; - RTU(main, TU_PRIMARY).blend = MSU(msA, MTU_PRIMARY).alpha; - - if(0 != MSU(msA, MTU_DETAIL).tex.glName) - { - RTU(main, TU_PRIMARY_DETAIL).tex = MSU(msA, MTU_DETAIL).tex.glName; - RTU(main, TU_PRIMARY_DETAIL).magMode = MSU(msA, MTU_DETAIL).magMode; - RTU(main, TU_PRIMARY_DETAIL).scale[0] = MSU(msA, MTU_DETAIL).scale[0]; - RTU(main, TU_PRIMARY_DETAIL).scale[1] = MSU(msA, MTU_DETAIL).scale[1]; - RTU(main, TU_PRIMARY_DETAIL).offset[0] = MSU(msA, MTU_DETAIL).offset[0] * RTU(main, TU_PRIMARY_DETAIL).scale[0]; - RTU(main, TU_PRIMARY_DETAIL).offset[1] = MSU(msA, MTU_DETAIL).offset[1] * RTU(main, TU_PRIMARY_DETAIL).scale[1]; - RTU(main, TU_PRIMARY_DETAIL).blendMode = MSU(msA, MTU_DETAIL).blendMode; - RTU(main, TU_PRIMARY_DETAIL).blend = MSU(msA, MTU_DETAIL).alpha; - } - - if(msB && 0 != MSU(msB, MTU_PRIMARY).tex.glName) - { - RTU(main, TU_INTER).tex = MSU(msB, MTU_PRIMARY).tex.glName; - RTU(main, TU_INTER).magMode = MSU(msB, MTU_PRIMARY).magMode; - RTU(main, TU_INTER).scale[0] = MSU(msB, MTU_PRIMARY).scale[0]; - RTU(main, TU_INTER).scale[1] = MSU(msB, MTU_PRIMARY).scale[1]; - RTU(main, TU_INTER).offset[0] = MSU(msB, MTU_PRIMARY).offset[0] * RTU(main, TU_INTER).scale[0]; - RTU(main, TU_INTER).offset[1] = MSU(msB, MTU_PRIMARY).offset[1] * RTU(main, TU_INTER).scale[1]; - RTU(main, TU_INTER).blendMode = MSU(msB, MTU_PRIMARY).blendMode; - RTU(main, TU_INTER).blend = MSU(msB, MTU_PRIMARY).alpha; - - // Blend between the primary and inter textures. - RTU(main, TU_INTER).blend = inter; - } - - if(msB && 0 != MSU(msB, MTU_DETAIL).tex.glName) - { - RTU(main, TU_INTER_DETAIL).tex = MSU(msB, MTU_DETAIL).tex.glName; - RTU(main, TU_INTER_DETAIL).magMode = MSU(msB, MTU_DETAIL).magMode; - RTU(main, TU_INTER_DETAIL).scale[0] = MSU(msB, MTU_DETAIL).scale[0]; - RTU(main, TU_INTER_DETAIL).scale[1] = MSU(msB, MTU_DETAIL).scale[1]; - RTU(main, TU_INTER_DETAIL).offset[0] = MSU(msB, MTU_DETAIL).offset[0] * RTU(main, TU_INTER_DETAIL).scale[0]; - RTU(main, TU_INTER_DETAIL).offset[1] = MSU(msB, MTU_DETAIL).offset[1] * RTU(main, TU_INTER_DETAIL).scale[1]; - RTU(main, TU_INTER_DETAIL).blendMode = MSU(msB, MTU_DETAIL).blendMode; - RTU(main, TU_INTER_DETAIL).blend = MSU(msB, MTU_DETAIL).alpha; - - // Blend between the primary and inter detail textures. - RTU(main, TU_INTER_DETAIL).blend = inter; - } - - if(0 != MSU(msA, MTU_REFLECTION).tex.glName) - { - RTU(reflection, TU_PRIMARY).tex = MSU(msA, MTU_REFLECTION).tex.glName; - RTU(reflection, TU_PRIMARY).magMode = MSU(msA, MTU_REFLECTION).magMode; - RTU(reflection, TU_PRIMARY).scale[0] = MSU(msA, MTU_REFLECTION).scale[0]; - RTU(reflection, TU_PRIMARY).scale[1] = MSU(msA, MTU_REFLECTION).scale[1]; - RTU(reflection, TU_PRIMARY).offset[0] = MSU(msA, MTU_REFLECTION).offset[0] * RTU(reflection, TU_PRIMARY).scale[0]; - RTU(reflection, TU_PRIMARY).offset[1] = MSU(msA, MTU_REFLECTION).offset[1] * RTU(reflection, TU_PRIMARY).scale[1]; - RTU(reflection, TU_PRIMARY).blendMode = MSU(msA, MTU_REFLECTION).blendMode; - RTU(reflection, TU_PRIMARY).blend = MSU(msA, MTU_REFLECTION).alpha; - - if(0 != MSU(msA, MTU_REFLECTION_MASK).tex.glName) - { - RTU(reflection, TU_INTER).tex = MSU(msA, MTU_REFLECTION_MASK).tex.glName; - RTU(reflection, TU_INTER).magMode = MSU(msA, MTU_REFLECTION_MASK).magMode; - RTU(reflection, TU_INTER).scale[0] = MSU(msA, MTU_REFLECTION_MASK).scale[0]; - RTU(reflection, TU_INTER).scale[1] = MSU(msA, MTU_REFLECTION_MASK).scale[1]; - RTU(reflection, TU_INTER).offset[0] = MSU(msA, MTU_REFLECTION_MASK).offset[0] * RTU(reflection, TU_INTER).scale[0]; - RTU(reflection, TU_INTER).offset[1] = MSU(msA, MTU_REFLECTION_MASK).offset[1] * RTU(reflection, TU_INTER).scale[1]; - RTU(reflection, TU_INTER).blendMode = MSU(msA, MTU_REFLECTION_MASK).blendMode; - RTU(reflection, TU_INTER).blend = MSU(msA, MTU_REFLECTION_MASK).alpha; - } - } -} - -/** - * Apply primitive-specific manipulations. - */ -static void setupRTU2(rtexmapunit_t rTU[NUM_TEXMAP_UNITS], - rtexmapunit_t rTUs[NUM_TEXMAP_UNITS], - boolean isWall, const float texOffset[2], - const float texScale[2], - const materialsnapshot_t* msA, - const materialsnapshot_t* msB) -{ - if(texScale) - { - rTU[TU_PRIMARY].scale[0] *= texScale[0]; - rTU[TU_PRIMARY].scale[1] *= texScale[1]; - } - if(texOffset) - { - rTU[TU_PRIMARY].offset[0] += texOffset[0] / msA->width; - rTU[TU_PRIMARY].offset[1] += (isWall? texOffset[1] : -texOffset[1]) / msA->height; - } - - if(0 != MSU(msA, MTU_DETAIL).tex.glName && texOffset) - { - rTU[TU_PRIMARY_DETAIL].offset[0] += texOffset[0] * rTU[TU_PRIMARY_DETAIL].scale[0]; - rTU[TU_PRIMARY_DETAIL].offset[1] += (isWall? texOffset[1] : -texOffset[1]) - * rTU[TU_PRIMARY_DETAIL].scale[1]; - } - - if(msB && 0 != MSU(msB, MTU_PRIMARY).tex.glName) - { - if(texScale) - { - rTU[TU_INTER].scale[0] *= texScale[0]; - rTU[TU_INTER].scale[1] *= texScale[1]; - } - if(texOffset) - { - rTU[TU_INTER].offset[0] += texOffset[0] / msB->width; - rTU[TU_INTER].offset[1] += (isWall? texOffset[1] : -texOffset[1]) / msB->height; - } - } - - if(msB && 0 != MSU(msB, MTU_DETAIL).tex.glName && texOffset) - { - rTU[TU_INTER_DETAIL].offset[0] += - texOffset[0] * rTU[TU_INTER_DETAIL].scale[0]; - rTU[TU_INTER_DETAIL].offset[1] += (isWall? texOffset[1] : -texOffset[1]) - * rTU[TU_INTER_DETAIL].scale[1]; - } - - if(0 != MSU(msA, MTU_REFLECTION).tex.glName) - { - if(texScale) - { - rTUs[TU_INTER].scale[0] *= texScale[0]; - rTUs[TU_INTER].scale[1] *= texScale[1]; - } - if(texOffset) - { - rTUs[TU_INTER].offset[0] += texOffset[0] / msA->width; - rTUs[TU_INTER].offset[1] += (isWall? texOffset[1] : -texOffset[1]) / - msA->height; - } - } -} - typedef struct { boolean isWall; - rendpolytype_t type; + int flags; /// @see rendpolyFlags blendmode_t blendMode; pvec3_t texTL, texBR; const float* texOffset, *texScale; @@ -1272,47 +1132,39 @@ static boolean renderWorldPoly(rvertex_t* rvertices, uint numVertices, const materialsnapshot_t* msA, float inter, const materialsnapshot_t* msB) { - rcolor_t* rcolors; - rtexcoord_t* rtexcoords = NULL, *rtexcoords2 = NULL, - *rtexcoords5 = NULL; - uint realNumVertices = - p->isWall && divs? 3 + divs[0].num + 3 + divs[1].num : numVertices; - rcolor_t* shinyColors = NULL; - rtexcoord_t* shinyTexCoords = NULL; - boolean useLights = false, useShadows = false; - uint numLights = 0; - DGLuint modTex = 0; - float modTexTC[2][2]; - float modColor[3]; - float glowing = p->glowing; - boolean drawAsVisSprite = false; - rtexmapunit_t rTU[NUM_TEXMAP_UNITS], rTUs[NUM_TEXMAP_UNITS]; - - if(!p->forceOpaque && p->type != RPT_SKY_MASK && + boolean useLights = false, useShadows = false, hasDynlights = false; + rtexcoord_t* primaryCoords = NULL, *interCoords = NULL, *modCoords = NULL; + uint realNumVertices = p->isWall && divs? 3 + divs[0].num + 3 + divs[1].num : numVertices; + rcolor_t* rcolors; + rcolor_t* shinyColors = NULL; + rtexcoord_t* shinyTexCoords = NULL; + float modTexTC[2][2] = {{ 0, 0 }, { 0, 0 }}; + rcolor_t modColor = { 0, 0, 0, 0 }; + DGLuint modTex = 0; + float glowing = p->glowing; + boolean drawAsVisSprite = false; + + // Map RTU configuration from prepared MaterialSnapshot(s). + const rtexmapunit_t* primaryRTU = (!(p->flags & RPF_SKYMASK))? &MSU(msA, MTU_PRIMARY) : NULL; + const rtexmapunit_t* primaryDetailRTU = (r_detail && !(p->flags & RPF_SKYMASK) && MSU(msA, MTU_DETAIL).tex)? &MSU(msA, MTU_DETAIL) : NULL; + const rtexmapunit_t* interRTU = (!(p->flags & RPF_SKYMASK) && msB && MSU(msB, MTU_PRIMARY).tex)? &MSU(msB, MTU_PRIMARY) : NULL; + const rtexmapunit_t* interDetailRTU = (r_detail && !(p->flags & RPF_SKYMASK) && msB && MSU(msB, MTU_DETAIL).tex)? &MSU(msB, MTU_DETAIL) : NULL; + const rtexmapunit_t* shinyRTU = (useShinySurfaces && !(p->flags & RPF_SKYMASK) && MSU(msA, MTU_REFLECTION).tex)? &MSU(msA, MTU_REFLECTION) : NULL; + const rtexmapunit_t* shinyMaskRTU = (useShinySurfaces && !(p->flags & RPF_SKYMASK) && MSU(msA, MTU_REFLECTION).tex && MSU(msA, MTU_REFLECTION_MASK).tex)? &MSU(msA, MTU_REFLECTION_MASK) : NULL; + + if(!p->forceOpaque && !(p->flags & RPF_SKYMASK) && (!msA->isOpaque || p->alpha < 1 || p->blendMode > 0)) drawAsVisSprite = true; - memset(rTU, 0, sizeof(rtexmapunit_t) * NUM_TEXMAP_UNITS); - memset(rTUs, 0, sizeof(rtexmapunit_t) * NUM_TEXMAP_UNITS); - - if(p->type != RPT_SKY_MASK) - { - setupRTU(rTU, rTUs, msA, inter, msB); - setupRTU2(rTU, rTUs, p->isWall, p->texOffset, p->texScale, msA, msB); - } - - memset(modTexTC, 0, sizeof(modTexTC)); - memset(modColor, 0, sizeof(modColor)); - rcolors = R_AllocRendColors(realNumVertices); - rtexcoords = R_AllocRendTexCoords(realNumVertices); - if(rTU[TU_INTER].tex) - rtexcoords2 = R_AllocRendTexCoords(realNumVertices); + primaryCoords = R_AllocRendTexCoords(realNumVertices); + if(interRTU) + interCoords = R_AllocRendTexCoords(realNumVertices); - if(p->type != RPT_SKY_MASK) + if(!(p->flags & RPF_SKYMASK)) { // ShinySurface? - if(useShinySurfaces && rTUs[TU_PRIMARY].tex && !drawAsVisSprite) + if(shinyRTU && !drawAsVisSprite) { // We'll reuse the same verts but we need new colors. shinyColors = R_AllocRendColors(realNumVertices); @@ -1337,18 +1189,16 @@ static boolean renderWorldPoly(rvertex_t* rvertices, uint numVertices, LO_IterateProjections2(p->lightListIdx, RIT_FirstDynlightIterator, (void*)&dyn); - rtexcoords5 = R_AllocRendTexCoords(realNumVertices); + modCoords = R_AllocRendTexCoords(realNumVertices); modTex = dyn->texture; - modColor[CR] = dyn->color.rgb[CR]; - modColor[CG] = dyn->color.rgb[CG]; - modColor[CB] = dyn->color.rgb[CB]; + modColor.red = dyn->color.red; + modColor.green = dyn->color.green; + modColor.blue = dyn->color.blue; modTexTC[0][0] = dyn->s[0]; modTexTC[0][1] = dyn->s[1]; modTexTC[1][0] = dyn->t[0]; modTexTC[1][1] = dyn->t[1]; - - numLights = 1; } } } @@ -1356,19 +1206,19 @@ static boolean renderWorldPoly(rvertex_t* rvertices, uint numVertices, if(p->isWall) { // Primary texture coordinates. - quadTexCoords(rtexcoords, rvertices, *p->segLength, p->texTL); + quadTexCoords(primaryCoords, rvertices, *p->segLength, p->texTL); // Blend texture coordinates. - if(rTU[TU_INTER].tex && !drawAsVisSprite) - quadTexCoords(rtexcoords2, rvertices, *p->segLength, p->texTL); + if(interRTU && !drawAsVisSprite) + quadTexCoords(interCoords, rvertices, *p->segLength, p->texTL); // Shiny texture coordinates. - if(useShinySurfaces && rTUs[TU_PRIMARY].tex && !drawAsVisSprite) + if(shinyRTU && !drawAsVisSprite) quadShinyTexCoords(shinyTexCoords, &rvertices[1], &rvertices[2], *p->segLength); // First light texture coordinates. - if(numLights > 0 && RL_IsMTexLights()) - quadLightCoords(rtexcoords5, modTexTC[0], modTexTC[1]); + if(modTex && RL_IsMTexLights()) + quadLightCoords(modCoords, modTexTC[0], modTexTC[1]); } else { @@ -1384,33 +1234,33 @@ static boolean renderWorldPoly(rvertex_t* rvertices, uint numVertices, xyz[VZ] = vtx->pos[VZ] - p->texTL[VZ]; // Primary texture coordinates. - if(rTU[TU_PRIMARY].tex) + if(primaryRTU) { - rtexcoord_t* tc = &rtexcoords[i]; + rtexcoord_t* tc = &primaryCoords[i]; tc->st[0] = xyz[VX]; tc->st[1] = -xyz[VY]; } // Blend primary texture coordinates. - if(rTU[TU_INTER].tex) + if(interRTU) { - rtexcoord_t* tc = &rtexcoords2[i]; + rtexcoord_t* tc = &interCoords[i]; tc->st[0] = xyz[VX]; tc->st[1] = -xyz[VY]; } // Shiny texture coordinates. - if(useShinySurfaces && rTUs[TU_PRIMARY].tex) + if(shinyRTU) { flatShinyTexCoords(&shinyTexCoords[i], vtx->pos); } // First light texture coordinates. - if(numLights > 0 && RL_IsMTexLights()) + if(modTex && RL_IsMTexLights()) { - rtexcoord_t* tc = &rtexcoords5[i]; + rtexcoord_t* tc = &modCoords[i]; float width, height; width = p->texBR[VX] - p->texTL[VX]; @@ -1423,7 +1273,7 @@ static boolean renderWorldPoly(rvertex_t* rvertices, uint numVertices, } // Light this polygon. - if(p->type != RPT_SKY_MASK) + if(!(p->flags & RPF_SKYMASK)) { if(levelFullBright || !(glowing < 1)) { // Uniform colour. Apply to all vertices. @@ -1507,7 +1357,7 @@ static boolean renderWorldPoly(rvertex_t* rvertices, uint numVertices, Rend_VertexColorsApplyTorchLight(rcolors, rvertices, numVertices); } - if(useShinySurfaces && rTUs[TU_PRIMARY].tex && !drawAsVisSprite) + if(shinyRTU && !drawAsVisSprite) { uint i; @@ -1517,7 +1367,7 @@ static boolean renderWorldPoly(rvertex_t* rvertices, uint numVertices, shinyColors[i].rgba[CR] = MAX_OF(rcolors[i].rgba[CR], msA->shinyMinColor[CR]); shinyColors[i].rgba[CG] = MAX_OF(rcolors[i].rgba[CG], msA->shinyMinColor[CG]); shinyColors[i].rgba[CB] = MAX_OF(rcolors[i].rgba[CB], msA->shinyMinColor[CB]); - shinyColors[i].rgba[CA] = rTUs[TU_PRIMARY].blend; + shinyColors[i].rgba[CA] = shinyRTU->opacity; } } @@ -1562,14 +1412,15 @@ static boolean renderWorldPoly(rvertex_t* rvertices, uint numVertices, * are masked polys). Otherwise there will be artifacts. */ Rend_AddMaskedPoly(rvertices, rcolors, *p->segLength, - msA->width, msA->height, p->texOffset, + primaryRTU->tex, primaryRTU->magMode, msA->width, msA->height, + p->texOffset, p->blendMode, p->lightListIdx, glowing, - !msA->isOpaque, rTU); - R_FreeRendTexCoords(rtexcoords); - if(rtexcoords2) - R_FreeRendTexCoords(rtexcoords2); - if(rtexcoords5) - R_FreeRendTexCoords(rtexcoords5); + !msA->isOpaque); + R_FreeRendTexCoords(primaryCoords); + if(interCoords) + R_FreeRendTexCoords(interCoords); + if(modCoords) + R_FreeRendTexCoords(modCoords); if(shinyTexCoords) R_FreeRendTexCoords(shinyTexCoords); R_FreeRendColors(rcolors); @@ -1579,7 +1430,7 @@ static boolean renderWorldPoly(rvertex_t* rvertices, uint numVertices, return false; // We HAD to use a vissprite, so it MUST not be opaque. } - if(p->type != RPT_SKY_MASK && useLights) + if(!(p->flags & RPF_SKYMASK) && useLights) { // Render all lights projected onto this surface. renderlightprojectionparams_t params; @@ -1593,10 +1444,10 @@ static boolean renderWorldPoly(rvertex_t* rvertices, uint numVertices, params.texTL = p->texTL; params.texBR = p->texBR; - numLights += Rend_RenderLightProjections(p->lightListIdx, ¶ms); + hasDynlights = (0 != Rend_RenderLightProjections(p->lightListIdx, ¶ms)); } - if(p->type != RPT_SKY_MASK && useShadows) + if(!(p->flags & RPF_SKYMASK) && useShadows) { // Render all shadows projected onto this surface. rendershadowprojectionparams_t params; @@ -1612,6 +1463,65 @@ static boolean renderWorldPoly(rvertex_t* rvertices, uint numVertices, Rend_RenderShadowProjections(p->shadowListIdx, ¶ms); } + // Map RTU state from the prepared texture units in the MaterialSnapshot(s). + RL_LoadDefaultRtus(); + RL_MapRtu(RTU_PRIMARY, primaryRTU); + RL_MapRtu(RTU_PRIMARY_DETAIL, primaryDetailRTU); + RL_MapRtu(RTU_INTER, interRTU); + RL_MapRtu(RTU_INTER_DETAIL, interDetailRTU); + RL_MapRtu(RTU_REFLECTION, shinyRTU); + RL_MapRtu(RTU_REFLECTION_MASK, shinyMaskRTU); + + if(primaryRTU) + { + rtexmapunit_t rtu; + memcpy(&rtu, primaryRTU, sizeof rtu); + if(p->texOffset) Rtu_TranslateOffsetv(&rtu, p->texOffset); + if(p->texScale) Rtu_ScaleST(&rtu, p->texScale); + RL_CopyRtu(RTU_PRIMARY, &rtu); + } + + if(primaryDetailRTU) + { + rtexmapunit_t rtu; + memcpy(&rtu, primaryDetailRTU, sizeof rtu); + if(p->texOffset) Rtu_TranslateOffsetv(&rtu, p->texOffset); + RL_CopyRtu(RTU_PRIMARY_DETAIL, &rtu); + } + + if(interRTU) + { + rtexmapunit_t rtu; + memcpy(&rtu, interRTU, sizeof rtu); + // Blend between the primary and inter textures. + rtu.opacity = inter; + if(p->texOffset) Rtu_TranslateOffsetv(&rtu, p->texOffset); + if(p->texScale) Rtu_ScaleST(&rtu, p->texScale); + RL_CopyRtu(RTU_INTER, &rtu); + + if(interDetailRTU) + { + memcpy(&rtu, interDetailRTU, sizeof rtu); + // Blend between the primary and inter textures. + rtu.opacity = inter; + if(p->texOffset) Rtu_TranslateOffsetv(&rtu, p->texOffset); + RL_CopyRtu(RTU_INTER_DETAIL, &rtu); + } + } + + if(shinyRTU) + { + RL_CopyRtu(RTU_REFLECTION, shinyRTU); + if(shinyMaskRTU) + { + rtexmapunit_t rtu; + memcpy(&rtu, shinyMaskRTU, sizeof rtu); + if(p->texOffset) Rtu_TranslateOffsetv(&rtu, p->texOffset); + if(p->texScale) Rtu_ScaleST(&rtu, p->texScale); + RL_CopyRtu(RTU_REFLECTION_MASK, &rtu); + } + } + // Write multiple polys depending on rend params. if(p->isWall && divs) { @@ -1627,7 +1537,7 @@ static boolean renderWorldPoly(rvertex_t* rvertices, uint numVertices, */ memcpy(origVerts, rvertices, sizeof(rvertex_t) * 4); - memcpy(origTexCoords, rtexcoords, sizeof(rtexcoord_t) * 4); + memcpy(origTexCoords, primaryCoords, sizeof(rtexcoord_t) * 4); memcpy(origColors, rcolors, sizeof(rcolor_t) * 4); bL = origVerts[0].pos[VZ]; @@ -1636,28 +1546,28 @@ static boolean renderWorldPoly(rvertex_t* rvertices, uint numVertices, tR = origVerts[3].pos[VZ]; R_DivVerts(rvertices, origVerts, divs); - R_DivTexCoords(rtexcoords, origTexCoords, divs, bL, tL, bR, tR); + R_DivTexCoords(primaryCoords, origTexCoords, divs, bL, tL, bR, tR); R_DivVertColors(rcolors, origColors, divs, bL, tL, bR, tR); - if(rtexcoords2) + if(interCoords) { - rtexcoord_t origTexCoords2[4]; + rtexcoord_t origTexCoords2[4]; - memcpy(origTexCoords2, rtexcoords2, sizeof(rtexcoord_t) * 4); - R_DivTexCoords(rtexcoords2, origTexCoords2, divs, bL, tL, bR, tR); + memcpy(origTexCoords2, interCoords, sizeof(rtexcoord_t) * 4); + R_DivTexCoords(interCoords, origTexCoords2, divs, bL, tL, bR, tR); } - if(rtexcoords5) + if(modCoords) { - rtexcoord_t origTexCoords5[4]; + rtexcoord_t origTexCoords5[4]; - memcpy(origTexCoords5, rtexcoords5, sizeof(rtexcoord_t) * 4); - R_DivTexCoords(rtexcoords5, origTexCoords5, divs, bL, tL, bR, tR); + memcpy(origTexCoords5, modCoords, sizeof(rtexcoord_t) * 4); + R_DivTexCoords(modCoords, origTexCoords5, divs, bL, tL, bR, tR); } if(shinyTexCoords) { - rtexcoord_t origShinyTexCoords[4]; + rtexcoord_t origShinyTexCoords[4]; memcpy(origShinyTexCoords, shinyTexCoords, sizeof(rtexcoord_t) * 4); R_DivTexCoords(shinyTexCoords, origShinyTexCoords, divs, bL, tL, bR, tR); @@ -1665,52 +1575,38 @@ static boolean renderWorldPoly(rvertex_t* rvertices, uint numVertices, if(shinyColors) { - rcolor_t origShinyColors[4]; + rcolor_t origShinyColors[4]; memcpy(origShinyColors, shinyColors, sizeof(rcolor_t) * 4); R_DivVertColors(shinyColors, origShinyColors, divs, bL, tL, bR, tR); } - RL_AddPoly(PT_FAN, p->type, rvertices + 3 + divs[0].num, - rtexcoords + 3 + divs[0].num, - rtexcoords2? rtexcoords2 + 3 + divs[0].num : NULL, - rtexcoords5? rtexcoords5 + 3 + divs[0].num : NULL, - rcolors + 3 + divs[0].num, 3 + divs[1].num, - numLights, modTex, modColor, rTU); - RL_AddPoly(PT_FAN, p->type, rvertices, rtexcoords, rtexcoords2, - - rtexcoords5, rcolors, 3 + divs[0].num, - numLights, modTex, modColor, rTU); - if(useShinySurfaces && rTUs[TU_PRIMARY].tex) - { - RL_AddPoly(PT_FAN, RPT_SHINY, rvertices + 3 + divs[0].num, - shinyTexCoords? shinyTexCoords + 3 + divs[0].num : NULL, - rTUs[TU_INTER].tex? rtexcoords + 3 + divs[0].num : NULL, - NULL, - shinyColors + 3 + divs[0].num, - 3 + divs[1].num, 0, 0, NULL, rTUs); - RL_AddPoly(PT_FAN, RPT_SHINY, rvertices, - shinyTexCoords, rTUs[TU_INTER].tex? rtexcoords : NULL, - NULL, shinyColors, 3 + divs[0].num, 0, 0, NULL, rTUs); - } + RL_AddPolyWithCoordsModulationReflection(PT_FAN, p->flags | (hasDynlights? RPF_HAS_DYNLIGHTS : 0), + 3 + divs[1].num, rvertices + 3 + divs[0].num, rcolors + 3 + divs[0].num, + primaryCoords + 3 + divs[0].num, interCoords? interCoords + 3 + divs[0].num : NULL, + modTex, &modColor, modCoords? modCoords + 3 + divs[0].num : NULL, + shinyColors + 3 + divs[0].num, shinyTexCoords? shinyTexCoords + 3 + divs[0].num : NULL, + shinyMaskRTU? primaryCoords + 3 + divs[0].num : NULL); + + RL_AddPolyWithCoordsModulationReflection(PT_FAN, p->flags | (hasDynlights? RPF_HAS_DYNLIGHTS : 0), + 3 + divs[0].num, rvertices, rcolors, + primaryCoords, interCoords, + modTex, &modColor, modCoords, + shinyColors, shinyTexCoords, shinyMaskRTU? primaryCoords : NULL); } else { - RL_AddPoly(p->isWall? PT_TRIANGLE_STRIP : PT_FAN, p->type, rvertices, - rtexcoords, rtexcoords2, rtexcoords5, rcolors, - - numVertices, numLights, modTex, modColor, rTU); - if(useShinySurfaces && rTUs[TU_PRIMARY].tex) - RL_AddPoly(p->isWall? PT_TRIANGLE_STRIP : PT_FAN, RPT_SHINY, - rvertices, shinyTexCoords, - rTUs[TU_INTER].tex? rtexcoords : NULL, - NULL, shinyColors, numVertices, 0, 0, NULL, rTUs); + RL_AddPolyWithCoordsModulationReflection(p->isWall? PT_TRIANGLE_STRIP : PT_FAN, p->flags | (hasDynlights? RPF_HAS_DYNLIGHTS : 0), + numVertices, rvertices, rcolors, + primaryCoords, interCoords, + modTex, &modColor, modCoords, + shinyColors, shinyTexCoords, shinyMaskRTU? primaryCoords : NULL); } - R_FreeRendTexCoords(rtexcoords); - if(rtexcoords2) - R_FreeRendTexCoords(rtexcoords2); - if(rtexcoords5) - R_FreeRendTexCoords(rtexcoords5); + R_FreeRendTexCoords(primaryCoords); + if(interCoords) + R_FreeRendTexCoords(interCoords); + if(modCoords) + R_FreeRendTexCoords(modCoords); if(shinyTexCoords) R_FreeRendTexCoords(shinyTexCoords); R_FreeRendColors(rcolors); @@ -1751,7 +1647,7 @@ static boolean doRenderSeg(seg_t* seg, // Init the params. memset(¶ms, 0, sizeof(params)); - params.type = (skyMask? RPT_SKY_MASK : RPT_NORMAL); + params.flags = RPF_DEFAULT | (skyMask? RPF_SKYMASK : 0); params.isWall = true; params.segLength = &seg->length; params.forceOpaque = (alpha < 0? true : false); @@ -1802,7 +1698,7 @@ static boolean doRenderSeg(seg_t* seg, if(renderWorldPoly(rvertices, 4, divs, ¶ms, msA, inter, msB)) { // Drawn poly was opaque. // Render Fakeradio polys for this seg? - if(params.type != RPT_SKY_MASK && addFakeRadio) + if(!(params.flags & RPF_SKYMASK) && addFakeRadio) { rendsegradio_params_t radioParams; float ll; @@ -1883,6 +1779,7 @@ static void renderPlane(subsector_t* ssec, planetype_t type, float height, memset(¶ms, 0, sizeof(params)); + params.flags = RPF_DEFAULT; params.isWall = false; params.mapObject = ssec; params.elmIdx = elmIdx; @@ -1903,7 +1800,6 @@ static void renderPlane(subsector_t* ssec, planetype_t type, float height, // skymask as regular world polys (with a few obvious properties). if(devRendSkyMode) { - params.type = RPT_NORMAL; params.blendMode = BM_NORMAL; params.glowing = 1; params.forceOpaque = true; @@ -1911,12 +1807,11 @@ static void renderPlane(subsector_t* ssec, planetype_t type, float height, } else { // We'll mask this. - params.type = RPT_SKY_MASK; + params.flags |= RPF_SKYMASK; } } else { - params.type = RPT_NORMAL; mat = inMat; if(type != PLN_MID) @@ -1938,7 +1833,7 @@ static void renderPlane(subsector_t* ssec, planetype_t type, float height, rvertices = R_AllocRendVertices(numVertices); Rend_PreparePlane(rvertices, numVertices, height, ssec, !(normal[VZ] > 0) ^ flipSurfaceNormal); - if(params.type != RPT_SKY_MASK) + if(!(params.flags & RPF_SKYMASK)) { // Smooth Texture Animation? if(smoothTexAnim) @@ -2124,7 +2019,7 @@ static boolean rendSegSection(subsector_t* ssec, seg_t* seg, walldiv_t divs[2]; boolean forceOpaque = false; material_t* mat = NULL; - rendpolytype_t type = RPT_NORMAL; + int rpFlags = RPF_DEFAULT; boolean isTwoSided = (seg->lineDef && seg->lineDef->L_frontside && seg->lineDef->L_backside)? true:false; blendmode_t blendMode = BM_NORMAL; @@ -2152,7 +2047,7 @@ static boolean rendSegSection(subsector_t* ssec, seg_t* seg, } else { // We'll mask this. - type = RPT_SKY_MASK; + rpFlags |= RPF_SKYMASK; } } else @@ -2204,7 +2099,7 @@ static boolean rendSegSection(subsector_t* ssec, seg_t* seg, addFakeRadio = !(surfaceInFlags & SUIF_NO_RADIO); } - if(type != RPT_SKY_MASK) + if(!(rpFlags & RPF_SKYMASK)) { // Smooth Texture Animation? if(smoothTexAnim) @@ -2758,132 +2653,136 @@ static boolean skymaskSegIsVisible(seg_t* seg, boolean clipBackFacing) return true; } -void lightGeometry(rendpolytype_t type, size_t count, rvertex_t* rvertices, rcolor_t* rcolors, - rcolor_t* rcolorsShiny, rtexmapunit_t* rTU, rtexmapunit_t* rTUs, const materialsnapshot_t* msA, +/** + * @param rpFlags @see rendpolyFlags + */ +void lightGeometry(int rpFlags, size_t count, rvertex_t* rvertices, rcolor_t* rcolors, + rcolor_t* rcolorsShiny, const rtexmapunit_t* shinyRTU, const materialsnapshot_t* msA, const float* surfaceNormal, const float* surfaceColor, float surfaceAlpha, const float* surfaceColor2, const float* ambientLightColor, float ambientLightLevel, float lightLevelDeltaLeft, float lightLevelDeltaRight, float lightLevelDeltaBottom, float lightLevelDeltaTop, biassurface_t* bsuf, void* mapObject, uint elmIdx, float glowing, boolean isWall, boolean drawAsVisSprite) { assert(rvertices && rcolors && ambientLightColor); - { + if(!rcolors || (rpFlags & RPF_SKYMASK)) return; + // Light this polygon. - if(rcolors && type != RPT_SKY_MASK) - { - if(levelFullBright || !(glowing < 1)) - { // Uniform colour. Apply to all vertices. - Rend_VertexColorsGlow(rcolors, count, ambientLightLevel + (levelFullBright? 1 : glowing)); - } - else - { // Non-uniform color. - if(useBias && bsuf) - { // Do BIAS lighting for this poly. - SB_RendPoly(rcolors, bsuf, rvertices, count, surfaceNormal, ambientLightLevel, mapObject, elmIdx, isWall); - if(glowing > 0) + if(levelFullBright || !(glowing < 1)) + { // Uniform colour. Apply to all vertices. + Rend_VertexColorsGlow(rcolors, count, ambientLightLevel + (levelFullBright? 1 : glowing)); + } + else + { // Non-uniform color. + if(useBias && bsuf) + { // Do BIAS lighting for this poly. + SB_RendPoly(rcolors, bsuf, rvertices, count, surfaceNormal, ambientLightLevel, mapObject, elmIdx, isWall); + if(glowing > 0) + { + size_t i; + for(i = 0; i < count; ++i) { - size_t i; - for(i = 0; i < count; ++i) - { - rcolors[i].rgba[CR] = MINMAX_OF(0, rcolors[i].rgba[CR] + glowing, 1); - rcolors[i].rgba[CG] = MINMAX_OF(0, rcolors[i].rgba[CG] + glowing, 1); - rcolors[i].rgba[CB] = MINMAX_OF(0, rcolors[i].rgba[CB] + glowing, 1); - } + rcolors[i].rgba[CR] = MINMAX_OF(0, rcolors[i].rgba[CR] + glowing, 1); + rcolors[i].rgba[CG] = MINMAX_OF(0, rcolors[i].rgba[CG] + glowing, 1); + rcolors[i].rgba[CB] = MINMAX_OF(0, rcolors[i].rgba[CB] + glowing, 1); } } - else - { - float llB = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaBottom + glowing, 1); - float llT = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaTop + glowing, 1); - float llL = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaLeft + glowing, 1); - float llR = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaRight + glowing, 1); + } + else + { + float llB = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaBottom + glowing, 1); + float llT = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaTop + glowing, 1); + float llL = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaLeft + glowing, 1); + float llR = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaRight + glowing, 1); - // Calculate the color for each vertex, blended with plane color? - if(surfaceColor && (surfaceColor[0] < 1 || surfaceColor[1] < 1 || surfaceColor[2] < 1)) - { - float vColor[4]; + // Calculate the color for each vertex, blended with plane color? + if(surfaceColor && (surfaceColor[0] < 1 || surfaceColor[1] < 1 || surfaceColor[2] < 1)) + { + float vColor[4]; - // Blend sector light+color+surfacecolor - vColor[CR] = surfaceColor[CR] * ambientLightColor[CR]; - vColor[CG] = surfaceColor[CG] * ambientLightColor[CG]; - vColor[CB] = surfaceColor[CB] * ambientLightColor[CB]; - vColor[CA] = 1; + // Blend sector light+color+surfacecolor + vColor[CR] = surfaceColor[CR] * ambientLightColor[CR]; + vColor[CG] = surfaceColor[CG] * ambientLightColor[CG]; + vColor[CB] = surfaceColor[CB] * ambientLightColor[CB]; + vColor[CA] = 1; - if(!(isWall && (llL != llR || llB != llT))) - { - lightVertices(count, rcolors, rvertices, llL, vColor); - } - else - { - float lightLevels[4]; - lightLevels[0] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaBottom + lightLevelDeltaLeft + glowing, 1); - lightLevels[1] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaTop + lightLevelDeltaLeft + glowing, 1); - lightLevels[2] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaBottom + lightLevelDeltaRight + glowing, 1); - lightLevels[3] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaTop + lightLevelDeltaRight + glowing, 1); - lightVertex(&rcolors[0], &rvertices[0], lightLevels[0], vColor); - lightVertex(&rcolors[1], &rvertices[1], lightLevels[1], vColor); - lightVertex(&rcolors[2], &rvertices[2], lightLevels[2], vColor); - lightVertex(&rcolors[3], &rvertices[3], lightLevels[3], vColor); - } + if(!(isWall && (llL != llR || llB != llT))) + { + lightVertices(count, rcolors, rvertices, llL, vColor); } else - { // Use sector light+color only. - if(!(isWall && (llL != llR || llB != llT))) - { - lightVertices(count, rcolors, rvertices, llL, ambientLightColor); - } - else - { - float lightLevels[4]; - lightLevels[0] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaBottom + lightLevelDeltaLeft + glowing, 1); - lightLevels[1] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaTop + lightLevelDeltaLeft + glowing, 1); - lightLevels[2] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaBottom + lightLevelDeltaRight + glowing, 1); - lightLevels[3] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaTop + lightLevelDeltaRight + glowing, 1); - lightVertex(&rcolors[0], &rvertices[0], lightLevels[0], ambientLightColor); - lightVertex(&rcolors[1], &rvertices[1], lightLevels[1], ambientLightColor); - lightVertex(&rcolors[2], &rvertices[2], lightLevels[2], ambientLightColor); - lightVertex(&rcolors[3], &rvertices[3], lightLevels[3], ambientLightColor); - } + { + float lightLevels[4]; + lightLevels[0] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaBottom + lightLevelDeltaLeft + glowing, 1); + lightLevels[1] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaTop + lightLevelDeltaLeft + glowing, 1); + lightLevels[2] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaBottom + lightLevelDeltaRight + glowing, 1); + lightLevels[3] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaTop + lightLevelDeltaRight + glowing, 1); + lightVertex(&rcolors[0], &rvertices[0], lightLevels[0], vColor); + lightVertex(&rcolors[1], &rvertices[1], lightLevels[1], vColor); + lightVertex(&rcolors[2], &rvertices[2], lightLevels[2], vColor); + lightVertex(&rcolors[3], &rvertices[3], lightLevels[3], vColor); } - - // Bottom color (if different from top)? - if(isWall && surfaceColor2) + } + else + { // Use sector light+color only. + if(!(isWall && (llL != llR || llB != llT))) { - float vColor[4]; - - // Blend sector light+color+surfacecolor - vColor[CR] = surfaceColor2[CR] * ambientLightColor[CR]; - vColor[CG] = surfaceColor2[CG] * ambientLightColor[CG]; - vColor[CB] = surfaceColor2[CB] * ambientLightColor[CB]; - vColor[CA] = 1; - - lightVertex(&rcolors[0], &rvertices[0], llL * llB, vColor); - lightVertex(&rcolors[2], &rvertices[2], llR * llB, vColor); + lightVertices(count, rcolors, rvertices, llL, ambientLightColor); + } + else + { + float lightLevels[4]; + lightLevels[0] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaBottom + lightLevelDeltaLeft + glowing, 1); + lightLevels[1] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaTop + lightLevelDeltaLeft + glowing, 1); + lightLevels[2] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaBottom + lightLevelDeltaRight + glowing, 1); + lightLevels[3] = MINMAX_OF(0, ambientLightLevel + lightLevelDeltaTop + lightLevelDeltaRight + glowing, 1); + lightVertex(&rcolors[0], &rvertices[0], lightLevels[0], ambientLightColor); + lightVertex(&rcolors[1], &rvertices[1], lightLevels[1], ambientLightColor); + lightVertex(&rcolors[2], &rvertices[2], lightLevels[2], ambientLightColor); + lightVertex(&rcolors[3], &rvertices[3], lightLevels[3], ambientLightColor); } } - Rend_VertexColorsApplyTorchLight(rcolors, rvertices, count); - } - - if(useShinySurfaces && rcolorsShiny && rTUs && rTUs[TU_PRIMARY].tex && !drawAsVisSprite) - { - // Strength of the shine. - size_t i; - for(i = 0; i < count; ++i) + // Bottom color (if different from top)? + if(isWall && surfaceColor2) { - rcolorsShiny[i].rgba[CR] = MAX_OF(rcolors[i].rgba[CR], msA->shinyMinColor[CR]); - rcolorsShiny[i].rgba[CG] = MAX_OF(rcolors[i].rgba[CG], msA->shinyMinColor[CG]); - rcolorsShiny[i].rgba[CB] = MAX_OF(rcolors[i].rgba[CB], msA->shinyMinColor[CB]); - rcolorsShiny[i].rgba[CA] = rTUs[TU_PRIMARY].blend; + float vColor[4]; + + // Blend sector light+color+surfacecolor + vColor[CR] = surfaceColor2[CR] * ambientLightColor[CR]; + vColor[CG] = surfaceColor2[CG] * ambientLightColor[CG]; + vColor[CB] = surfaceColor2[CB] * ambientLightColor[CB]; + vColor[CA] = 1; + + lightVertex(&rcolors[0], &rvertices[0], llL * llB, vColor); + lightVertex(&rcolors[2], &rvertices[2], llR * llB, vColor); } } - // Apply uniform alpha. - Rend_VertexColorsAlpha(rcolors, count, surfaceAlpha); + Rend_VertexColorsApplyTorchLight(rcolors, rvertices, count); } + + if(shinyRTU && rcolorsShiny && !drawAsVisSprite) + { + // Strength of the shine. + size_t i; + for(i = 0; i < count; ++i) + { + rcolorsShiny[i].rgba[CR] = MAX_OF(rcolors[i].rgba[CR], msA->shinyMinColor[CR]); + rcolorsShiny[i].rgba[CG] = MAX_OF(rcolors[i].rgba[CG], msA->shinyMinColor[CG]); + rcolorsShiny[i].rgba[CB] = MAX_OF(rcolors[i].rgba[CB], msA->shinyMinColor[CB]); + rcolorsShiny[i].rgba[CA] = shinyRTU->opacity; + } } + + // Apply uniform alpha. + Rend_VertexColorsAlpha(rcolors, count, surfaceAlpha); } -static void prepareSkyMaskSurface(rendpolytype_t polyType, size_t count, rvertex_t* rvertices, - rtexcoord_t* rtexcoords, rcolor_t* rcolors, rcolor_t* rcolorsShiny, rtexmapunit_t* rTU, rtexmapunit_t* rTUs, +/** + * @param rpFlags @see rendpolyFlags + */ +static void prepareSkyMaskSurface(int rpFlags, size_t count, rvertex_t* rvertices, + rtexcoord_t* rtexcoords, rcolor_t* rcolors, rcolor_t* rcolorsShiny, + const rtexmapunit_t** primaryRTU, const rtexmapunit_t** primaryDetailRTU, const float* surfaceNormal, const float* surfaceColor, float surfaceAlpha, const float* surfaceColor2, const float* ambientLightColor, float lightLevel, float lightLevelDeltaLeft, float lightLevelDeltaRight, float lightLevelDeltaBottom, float lightLevelDeltaTop, @@ -2893,18 +2792,15 @@ static void prepareSkyMaskSurface(rendpolytype_t polyType, size_t count, rvertex const materialvariantspecification_t* spec = Materials_VariantSpecificationForContext( MC_MAPSURFACE, 0, 0, 0, 0, GL_REPEAT, GL_REPEAT, -1, -1, -1, true, true, false, false); const materialsnapshot_t* ms = Materials_Prepare(mat, spec, true); + const rtexmapunit_t* shinyRTU; // In devRendSkyMode mode we render all polys destined for the skymask as // regular world polys (with a few obvious properties). - rTU[TU_PRIMARY].tex = MSU(ms, MTU_PRIMARY).tex.glName; - rTU[TU_PRIMARY].magMode = MSU(ms, MTU_PRIMARY).magMode; - rTU[TU_PRIMARY].scale[0] = MSU(ms, MTU_PRIMARY).scale[0]; - rTU[TU_PRIMARY].scale[1] = MSU(ms, MTU_PRIMARY).scale[1]; - rTU[TU_PRIMARY].offset[0] = MSU(ms, MTU_PRIMARY).offset[0] * rTU[TU_PRIMARY].scale[0]; - rTU[TU_PRIMARY].offset[1] = MSU(ms, MTU_PRIMARY).offset[1] * rTU[TU_PRIMARY].scale[1]; - rTU[TU_PRIMARY].blend = MSU(ms, MTU_PRIMARY).alpha; - rTU[TU_PRIMARY].blendMode = MSU(ms, MTU_PRIMARY).blendMode; + // Map RTU configuration from prepared MaterialSnapshot(s). + *primaryRTU = &MSU(ms, MTU_PRIMARY); + *primaryDetailRTU = (MSU(ms, MTU_DETAIL).tex)? &MSU(ms, MTU_DETAIL) : NULL; + shinyRTU = (MSU(ms, MTU_REFLECTION).tex)? &MSU(ms, MTU_REFLECTION) : NULL; if(rtexcoords) { @@ -2918,14 +2814,17 @@ static void prepareSkyMaskSurface(rendpolytype_t polyType, size_t count, rvertex if(rcolors) { - lightGeometry(polyType, count, rvertices, rcolors, rcolorsShiny, rTU, rTUs, ms, + lightGeometry(rpFlags, count, rvertices, rcolors, rcolorsShiny, shinyRTU, ms, surfaceNormal, surfaceColor, surfaceAlpha, surfaceColor2, ambientLightColor, lightLevel, lightLevelDeltaLeft, lightLevelDeltaRight, lightLevelDeltaBottom, lightLevelDeltaTop, bsuf, mapObject, elmIdx, glowing, isWall, drawAsVisSprite); } } -static int buildSkymaskQuad(rendpolytype_t polyType, rvertex_t* rvertices, rtexcoord_t* rtexcoords) +/** + * @param rpFlags @see rendpolyFlags + */ +static int buildSkymaskQuad(int rpFlags, rvertex_t* rvertices, rtexcoord_t* rtexcoords) { V3_Set(rvertices[0].pos, 0, 0, 0); V3_Set(rvertices[1].pos, 0, 0, 0); @@ -2947,128 +2846,164 @@ static int buildSkymaskQuad(rendpolytype_t polyType, rvertex_t* rvertices, rtexc return 4; } -/*static __inline*/ void translateGeometryAxis(rendpolytype_t polyType, byte axis, float delta, +/** + * @param rpFlags @see rendpolyFlags + */ +static __inline void translateGeometryAxis(int rpFlags, byte axis, float delta, rvertex_t* rvertices, rtexcoord_t* rtexcoord, rcolor_t* rcolor, rcolor_t* shinyColor) { rvertices[0].pos[axis] += delta; } -/*static __inline*/ void translateGeometryX(rendpolytype_t polyType, vec3_t* deltas, +/** + * @param rpFlags @see rendpolyFlags + */ +static __inline void translateGeometryX(int rpFlags, vec3_t* deltas, size_t count, rvertex_t* rvertices, rtexcoord_t* rtexcoords, rcolor_t* rcolors, rcolor_t* rcolorsShiny) { size_t i; for(i = 0; i < count; ++i) { - translateGeometryAxis(polyType, VX, deltas[i][VX], rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); + translateGeometryAxis(rpFlags, VX, deltas[i][VX], rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); } } -/*static __inline*/ void translateGeometryY(rendpolytype_t polyType, vec3_t* deltas, +/** + * @param rpFlags @see rendpolyFlags + */ +static __inline void translateGeometryY(int rpFlags, vec3_t* deltas, size_t count, rvertex_t* rvertices, rtexcoord_t* rtexcoords, rcolor_t* rcolors, rcolor_t* rcolorsShiny) { size_t i; for(i = 0; i < count; ++i) { - translateGeometryAxis(polyType, VY, deltas[i][VY], rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); + translateGeometryAxis(rpFlags, VY, deltas[i][VY], rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); } } -/*static __inline*/ void translateGeometryZ(rendpolytype_t polyType, vec3_t* deltas, +/** + * @param rpFlags @see rendpolyFlags + */ +static __inline void translateGeometryZ(int rpFlags, vec3_t* deltas, size_t count, rvertex_t* rvertices, rtexcoord_t* rtexcoords, rcolor_t* rcolors, rcolor_t* rcolorsShiny) { size_t i; for(i = 0; i < count; ++i) { - translateGeometryAxis(polyType, VZ, deltas[i][VZ], rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); + translateGeometryAxis(rpFlags, VZ, deltas[i][VZ], rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); } } -/*static __inline*/ void translateGeometryXY(rendpolytype_t polyType, vec3_t* deltas, +/** + * @param rpFlags @see rendpolyFlags + */ +static __inline void translateGeometryXY(int rpFlags, vec3_t* deltas, size_t count, rvertex_t* rvertices, rtexcoord_t* rtexcoords, rcolor_t* rcolors, rcolor_t* rcolorsShiny) { - translateGeometryX(polyType, deltas, count, rvertices, rtexcoords, rcolors, rcolorsShiny); - translateGeometryY(polyType, deltas, count, rvertices, rtexcoords, rcolors, rcolorsShiny); + translateGeometryX(rpFlags, deltas, count, rvertices, rtexcoords, rcolors, rcolorsShiny); + translateGeometryY(rpFlags, deltas, count, rvertices, rtexcoords, rcolors, rcolorsShiny); } -/*static __inline*/ void translateGeometryXYZ(rendpolytype_t polyType, vec3_t* deltas, +/** + * @param rpFlags @see rendpolyFlags + */ +static __inline void translateGeometryXYZ(int rpFlags, vec3_t* deltas, size_t count, rvertex_t* rvertices, rtexcoord_t* rtexcoords, rcolor_t* rcolors, rcolor_t* rcolorsShiny) { - translateGeometryXY(polyType, deltas, count, rvertices, rtexcoords, rcolors, rcolorsShiny); - translateGeometryZ (polyType, deltas, count, rvertices, rtexcoords, rcolors, rcolorsShiny); + translateGeometryXY(rpFlags, deltas, count, rvertices, rtexcoords, rcolors, rcolorsShiny); + translateGeometryZ (rpFlags, deltas, count, rvertices, rtexcoords, rcolors, rcolorsShiny); } -/*static __inline*/ void setGeometryAxis(rendpolytype_t polyType, byte axis, float delta, +/** + * @param rpFlags @see rendpolyFlags + */ +static __inline void setGeometryAxis(int rpFlags, byte axis, float delta, rvertex_t* rvertices, rtexcoord_t* rtexcoords, rcolor_t* rcolors, rcolor_t* rcolorsShiny) { rvertices[0].pos[axis] = 0; - translateGeometryAxis(polyType, axis, delta, rvertices, rtexcoords, rcolors, rcolorsShiny); + translateGeometryAxis(rpFlags, axis, delta, rvertices, rtexcoords, rcolors, rcolorsShiny); } -/*static __inline*/ void setGeometryX(rendpolytype_t polyType, vec3_t* destPoints, +/** + * @param rpFlags @see rendpolyFlags + */ +static __inline void setGeometryX(int rpFlags, vec3_t* destPoints, size_t count, rvertex_t* rvertices, rtexcoord_t* rtexcoords, rcolor_t* rcolors, rcolor_t* rcolorsShiny) { size_t i; for(i = 0; i < count; ++i) { - setGeometryAxis(polyType, VX, destPoints[i][VX], rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); + setGeometryAxis(rpFlags, VX, destPoints[i][VX], rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); } } -/*static __inline*/ void setGeometryY(rendpolytype_t polyType, vec3_t* destPoints, +/** + * @param rpFlags @see rendpolyFlags + */ +static __inline void setGeometryY(int rpFlags, vec3_t* destPoints, size_t count, rvertex_t* rvertices, rtexcoord_t* rtexcoords, rcolor_t* rcolors, rcolor_t* rcolorsShiny) { size_t i; for(i = 0; i < count; ++i) { - setGeometryAxis(polyType, VY, destPoints[i][VY], rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); + setGeometryAxis(rpFlags, VY, destPoints[i][VY], rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); } } -/*static __inline*/ void setGeometryZ(rendpolytype_t polyType, vec3_t* destPoints, +/** + * @param rpFlags @see rendpolyFlags + */ +static __inline void setGeometryZ(int rpFlags, vec3_t* destPoints, size_t count, rvertex_t* rvertices, rtexcoord_t* rtexcoords, rcolor_t* rcolors, rcolor_t* rcolorsShiny) { size_t i; for(i = 0; i < count; ++i) { - setGeometryAxis(polyType, VZ, destPoints[i][VZ], rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); + setGeometryAxis(rpFlags, VZ, destPoints[i][VZ], rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); } } -/*static __inline*/ void setGeometryXY(rendpolytype_t polyType, vec3_t* destPoints, +/** + * @param rpFlags @see rendpolyFlags + */ +static __inline void setGeometryXY(int rpFlags, vec3_t* destPoints, size_t count, rvertex_t* rvertices, rtexcoord_t* rtexcoords, rcolor_t* rcolors, rcolor_t* rcolorsShiny) { size_t i; for(i = 0; i < count; ++i) { - setGeometryX(polyType, &destPoints[i], 1, rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); - setGeometryY(polyType, &destPoints[i], 1, rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); + setGeometryX(rpFlags, &destPoints[i], 1, rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); + setGeometryY(rpFlags, &destPoints[i], 1, rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); } } -/*static __inline*/ void setGeometryXYZ(rendpolytype_t polyType, vec3_t* destPoints, +/** + * @param rpFlags @see rendpolyFlags + */ +static __inline void setGeometryXYZ(int rpFlags, vec3_t* destPoints, size_t count, rvertex_t* rvertices, rtexcoord_t* rtexcoords, rcolor_t* rcolors, rcolor_t* rcolorsShiny) { size_t i; for(i = 0; i < count; ++i) { - setGeometryX(polyType, &destPoints[i], 1, rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); - setGeometryY(polyType, &destPoints[i], 1, rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); - setGeometryZ(polyType, &destPoints[i], 1, rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); + setGeometryX(rpFlags, &destPoints[i], 1, rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); + setGeometryY(rpFlags, &destPoints[i], 1, rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); + setGeometryZ(rpFlags, &destPoints[i], 1, rvertices+i, rtexcoords? rtexcoords+i : 0, rcolors? rcolors+i : 0, rcolorsShiny? rcolorsShiny+i : 0); } } #if 0 -/*static __inline*/ float calculateZBiasInter(float factor, float _height, float _skyHeight) +static __inline float calculateZBiasInter(float factor, float _height, float _skyHeight) { // Influenced by the source bias. if(_skyHeight != 0) @@ -3081,7 +3016,7 @@ static int buildSkymaskQuad(rendpolytype_t polyType, rvertex_t* rvertices, rtexc return 0; } -/*static __inline*/ float getZBiasHeightDelta(plane_t* ffloor, plane_t* fceil, float bias, float height) +static __inline float getZBiasHeightDelta(plane_t* ffloor, plane_t* fceil, float bias, float height) { assert(ffloor && fceil); { @@ -3099,7 +3034,7 @@ static int buildSkymaskQuad(rendpolytype_t polyType, rvertex_t* rvertices, rtexc } } -/*static __inline*/ float calculateZBiasDimming(float diffZ, float bias) +static __inline float calculateZBiasDimming(float diffZ, float bias) { float dimming = 0; if(diffZ && bias) @@ -3116,7 +3051,7 @@ static int buildSkymaskQuad(rendpolytype_t polyType, rvertex_t* rvertices, rtexc } #endif -/*static __inline*/ void getSurfaceLightLevelDeltas(seg_t* seg, plane_t* ffloor, plane_t* fceil, +static __inline void getSurfaceLightLevelDeltas(seg_t* seg, plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, float bottom, float top, float skyFloor, float skyCeil, float* deltaL, float* deltaR, float* deltaB, float* deltaT) { @@ -3138,7 +3073,7 @@ static int buildSkymaskQuad(rendpolytype_t polyType, rvertex_t* rvertices, rtexc #undef ZBIAS_FACTOR } -/*static __inline*/ void setGeometryDeltasZ(size_t count, vec3_t* deltas, float height) +static __inline void setGeometryDeltasZ(size_t count, vec3_t* deltas, float height) { assert(count != 0 && deltas); { size_t i; @@ -3148,7 +3083,7 @@ static int buildSkymaskQuad(rendpolytype_t polyType, rvertex_t* rvertices, rtexc }} } -/*static __inline*/ void translateGeometryDeltasZ(size_t count, vec3_t* edgeDeltas, +static __inline void translateGeometryDeltasZ(size_t count, vec3_t* edgeDeltas, float* deltasZ, rvertex_t* rvertices) { assert(count != 0 && edgeDeltas && deltasZ && rvertices); @@ -3159,7 +3094,7 @@ static int buildSkymaskQuad(rendpolytype_t polyType, rvertex_t* rvertices, rtexc }} } -/*static __inline*/ void getSurfaceNormal(float* normal, linedef_t* lineDef, byte side) +static __inline void getSurfaceNormal(float* normal, linedef_t* lineDef, byte side) { assert(normal && lineDef && lineDef->L_side(side)); { sidedef_t* sideDef = lineDef->L_side(side); @@ -3171,7 +3106,7 @@ static int buildSkymaskQuad(rendpolytype_t polyType, rvertex_t* rvertices, rtexc } } -/*static*/ void getSkymaskBottomTop(plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, +static void getSkymaskBottomTop(plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, float skyFloor, float skyCeil, seg_t* seg, sector_t* frontsec, sector_t* backsec, float* bottom, float* top) @@ -3199,7 +3134,7 @@ static int buildSkymaskQuad(rendpolytype_t polyType, rvertex_t* rvertices, rtexc } } -/*static*/ void getSkymaskBottomTop2(plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, +static void getSkymaskBottomTop2(plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, float skyFloor, float skyCeil, seg_t* seg, sector_t* frontsec, sector_t* backsec, float* bottom, float* top) @@ -3227,7 +3162,7 @@ static int buildSkymaskQuad(rendpolytype_t polyType, rvertex_t* rvertices, rtexc } } -/*static*/ void getSkymaskBottomTop3(plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, +static void getSkymaskBottomTop3(plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, float skyFloor, float skyCeil, seg_t* seg, sector_t* frontsec , sector_t* backsec, float* bottom, float* top) @@ -3278,7 +3213,7 @@ static int buildSkymaskQuad(rendpolytype_t polyType, rvertex_t* rvertices, rtexc } } -/*static*/ void getSkymaskBottomTop4(plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, +static void getSkymaskBottomTop4(plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, float skyFloor, float skyCeil, seg_t* seg, sector_t* frontsec, sector_t* backsec, float* bottom, float* top) @@ -3329,7 +3264,7 @@ static int buildSkymaskQuad(rendpolytype_t polyType, rvertex_t* rvertices, rtexc } } -/*static*/ void getSkymaskBottomTop5(plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, +static void getSkymaskBottomTop5(plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, float skyFloor, float skyCeil, boolean bottomHasMaterialFix, seg_t* seg, sector_t* frontsec, sector_t* backsec, float* bottom, float* top, boolean* addSolidViewSeg) @@ -3353,7 +3288,7 @@ static int buildSkymaskQuad(rendpolytype_t polyType, rvertex_t* rvertices, rtexc } } -/*static*/ void getSkymaskBottomTop6(plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, +static void getSkymaskBottomTop6(plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, float skyFloor, float skyCeil, boolean topHasMaterialFix, seg_t* seg, sector_t* frontsec, sector_t* backsec, float* bottom, float* top, boolean* addSolidViewSeg) @@ -3387,7 +3322,7 @@ static __inline float getSkyCeiling(plane_t* ffloor, plane_t* fceil, plane_t* bf return ((P_IsInVoid(viewPlayer) && !(R_IsSkySurface(&fceil-> surface) && bceil && R_IsSkySurface(&bceil-> surface)))? fceil-> visHeight : (skyFix[PLN_CEILING].height > DDMINFLOAT? skyFix[PLN_CEILING].height : 0)); } -/*static*/ void getSkymaskBottomOffsets(seg_t* seg, sector_t* frontsec, sector_t* backsec, +static void getSkymaskBottomOffsets(seg_t* seg, sector_t* frontsec, sector_t* backsec, plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, float skyFloor, float skyCeil, float* offsets, float* bottom, float* top, boolean* addSolidViewSeg) { @@ -3408,16 +3343,17 @@ static __inline float getSkyCeiling(plane_t* ffloor, plane_t* fceil, plane_t* bf } } -/*static*/ void drawSSectSkyFixBottom(rendpolytype_t polyType, subsector_t* ssec, boolean clipBackFacing, boolean flipSurfaceNormals) +static void drawSSectSkyFixBottom(subsector_t* ssec, boolean clipBackFacing, boolean flipSurfaceNormals, boolean addToSkyMask) { - rtexmapunit_t rTU[NUM_TEXMAP_UNITS]; + const int rpFlags = RPF_DEFAULT | (addToSkyMask? RPF_SKYMASK : 0); + const rtexmapunit_t* primaryRTU, *primaryDetailRTU; rtexcoord_t rtexcoords[4]; rvertex_t rvertices[4]; rcolor_t rcolors[4], rcolorsShiny[4]; size_t numVerts; seg_t** segPtr; - numVerts = buildSkymaskQuad(polyType, rvertices, (polyType == RPT_NORMAL? rtexcoords : 0)); + numVerts = buildSkymaskQuad(rpFlags, rvertices, (!addToSkyMask? rtexcoords : 0)); segPtr = ssec->segs; while(*segPtr) @@ -3448,7 +3384,10 @@ static __inline float getSkyCeiling(plane_t* ffloor, plane_t* fceil, plane_t* bf V3_Set(edgeDeltasXY[2], to-> V_pos[VX], to-> V_pos[VY], 0); V3_Set(edgeDeltasXY[3], to-> V_pos[VX], to-> V_pos[VY], 0); - setGeometryXY(polyType, edgeDeltasXY, numVerts, rvertices, (polyType == RPT_NORMAL? rtexcoords : 0), (polyType == RPT_NORMAL? rcolors : 0), (polyType == RPT_NORMAL? rcolorsShiny : 0)); + setGeometryXY(rpFlags, edgeDeltasXY, numVerts, rvertices, + (!addToSkyMask? rtexcoords : NULL), + (!addToSkyMask? rcolors : NULL), + (!addToSkyMask? rcolorsShiny : NULL)); ffloor = frontsec->SP_plane(PLN_FLOOR); fceil = frontsec->SP_plane(PLN_CEILING); @@ -3471,18 +3410,33 @@ static __inline float getSkyCeiling(plane_t* ffloor, plane_t* fceil, plane_t* bf float ambientLightLevel = frontsec->lightLevel; getSurfaceLightLevelDeltas(seg, ffloor, fceil, bfloor, bceil, bottom, top, skyFloor, skyCeil, &lightLevelDeltaLeft, &lightLevelDeltaRight, &lightLevelDeltaBottom, &lightLevelDeltaTop); - translateGeometryDeltasZ(numVerts, edgeDeltasZ, offsets, rvertices); - memset(rTU, 0, sizeof(rTU)); - setGeometryZ(polyType, edgeDeltasZ, numVerts, rvertices, (polyType == RPT_NORMAL? rtexcoords : 0), (polyType == RPT_NORMAL? rcolors : 0), (polyType == RPT_NORMAL? rcolorsShiny : 0)); - prepareSkyMaskSurface(polyType, numVerts, rvertices, (polyType == RPT_NORMAL? rtexcoords : 0), (polyType == RPT_NORMAL? rcolors : 0), (polyType == RPT_NORMAL? rcolorsShiny : 0), rTU, 0, surfaceNormal, 0, 1, 0, ambientLightColor, ambientLightLevel, lightLevelDeltaLeft, lightLevelDeltaRight, lightLevelDeltaBottom, lightLevelDeltaTop, 0, 0, 0, 0, seg->length, true, renderTextures!=2?ffloor->PS_material:Materials_ToMaterial(Materials_ResolveUriCString(MN_SYSTEM_NAME":gray")), false); - RL_AddPoly(PT_TRIANGLE_STRIP, polyType, rvertices, (polyType == RPT_NORMAL? rtexcoords : 0), 0, 0, (polyType == RPT_NORMAL? rcolors : 0), numVerts, 0, 0, 0, rTU); + translateGeometryDeltasZ(numVerts, edgeDeltasZ, offsets, rvertices); + setGeometryZ(rpFlags, edgeDeltasZ, numVerts, rvertices, + (!addToSkyMask? rtexcoords : NULL), + (!addToSkyMask? rcolors : NULL), + (!addToSkyMask? rcolorsShiny : NULL)); + + prepareSkyMaskSurface(rpFlags, numVerts, rvertices, + (!addToSkyMask? rtexcoords : NULL), + (!addToSkyMask? rcolors : NULL), + (!addToSkyMask? rcolorsShiny : NULL), + &primaryRTU, &primaryDetailRTU, + surfaceNormal, 0, 1, 0, ambientLightColor, + ambientLightLevel, lightLevelDeltaLeft, lightLevelDeltaRight, lightLevelDeltaBottom, lightLevelDeltaTop, 0, 0, 0, 0, seg->length, true, renderTextures!=2?ffloor->PS_material:Materials_ToMaterial(Materials_ResolveUriCString(MN_SYSTEM_NAME":gray")), false); + + RL_LoadDefaultRtus(); + RL_CopyRtu(RTU_PRIMARY, primaryRTU); + RL_CopyRtu(RTU_PRIMARY_DETAIL, primaryDetailRTU); + + RL_AddPolyWithCoords(PT_TRIANGLE_STRIP, rpFlags, + numVerts, rvertices, rcolors, rtexcoords, NULL); } segPtr++; } } -/*static*/ void getSkymaskTopOffsets(seg_t* seg, sector_t* frontsec, sector_t* backsec, +static void getSkymaskTopOffsets(seg_t* seg, sector_t* frontsec, sector_t* backsec, plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, float skyFloor, float skyCeil, float* offsets, float* bottom, float* top, boolean* addSolidViewSeg) { @@ -3503,16 +3457,17 @@ static __inline float getSkyCeiling(plane_t* ffloor, plane_t* fceil, plane_t* bf } } -/*static*/ void drawSSectSkyFixTop(rendpolytype_t polyType, subsector_t* ssec, boolean clipBackFacing, boolean flipSurfaceNormals) +static void drawSSectSkyFixTop(subsector_t* ssec, boolean clipBackFacing, boolean flipSurfaceNormals, boolean addToSkyMask) { - rtexmapunit_t rTU[NUM_TEXMAP_UNITS]; + const int rpFlags = RPF_DEFAULT | (addToSkyMask? RPF_SKYMASK : 0); + const rtexmapunit_t* primaryRTU, *primaryDetailRTU; rtexcoord_t rtexcoords[4]; rvertex_t rvertices[4]; rcolor_t rcolors[4], rcolorsShiny[4]; size_t numVerts; seg_t** segPtr; - numVerts = buildSkymaskQuad(polyType, rvertices, (polyType == RPT_NORMAL? rtexcoords : 0)); + numVerts = buildSkymaskQuad(rpFlags, rvertices, (!addToSkyMask? rtexcoords : 0)); segPtr = ssec->segs; while(*segPtr) @@ -3543,7 +3498,10 @@ static __inline float getSkyCeiling(plane_t* ffloor, plane_t* fceil, plane_t* bf V3_Set(edgeDeltasXY[2], to-> V_pos[VX], to-> V_pos[VY], 0); V3_Set(edgeDeltasXY[3], to-> V_pos[VX], to-> V_pos[VY], 0); - setGeometryXY(polyType, edgeDeltasXY, numVerts, rvertices, (polyType == RPT_NORMAL? rtexcoords : 0), (polyType == RPT_NORMAL? rcolors : 0), (polyType == RPT_NORMAL? rcolorsShiny : 0)); + setGeometryXY(rpFlags, edgeDeltasXY, numVerts, rvertices, + (!addToSkyMask? rtexcoords : NULL), + (!addToSkyMask? rcolors : NULL), + (!addToSkyMask? rcolorsShiny : NULL)); ffloor = frontsec->SP_plane(PLN_FLOOR); fceil = frontsec->SP_plane(PLN_CEILING); @@ -3566,18 +3524,33 @@ static __inline float getSkyCeiling(plane_t* ffloor, plane_t* fceil, plane_t* bf float ambientLightLevel = frontsec->lightLevel; getSurfaceLightLevelDeltas(seg, ffloor, fceil, bfloor, bceil, bottom, top, skyFloor, skyCeil, &lightLevelDeltaLeft, &lightLevelDeltaRight, &lightLevelDeltaBottom, &lightLevelDeltaTop); - translateGeometryDeltasZ(numVerts, edgeDeltasZ, offsets, rvertices); - memset(rTU, 0, sizeof(rTU)); - setGeometryZ(polyType, edgeDeltasZ, numVerts, rvertices, (polyType == RPT_NORMAL? rtexcoords : 0), (polyType == RPT_NORMAL? rcolors : 0), (polyType == RPT_NORMAL? rcolorsShiny : 0)); - prepareSkyMaskSurface(polyType, numVerts, rvertices, (polyType == RPT_NORMAL? rtexcoords : 0), (polyType == RPT_NORMAL? rcolors : 0), (polyType == RPT_NORMAL? rcolorsShiny : 0), rTU, 0, surfaceNormal, 0, 1, 0, ambientLightColor, ambientLightLevel, lightLevelDeltaLeft, lightLevelDeltaRight, lightLevelDeltaBottom, lightLevelDeltaTop, 0, 0, 0, 0, seg->length, true, renderTextures!=2?fceil->PS_material:Materials_ToMaterial(Materials_ResolveUriCString(MN_SYSTEM_NAME":gray")), false); - RL_AddPoly(PT_TRIANGLE_STRIP, polyType, rvertices, (polyType == RPT_NORMAL? rtexcoords : 0), 0, 0, (polyType == RPT_NORMAL? rcolors : 0), numVerts, 0, 0, 0, rTU); + translateGeometryDeltasZ(numVerts, edgeDeltasZ, offsets, rvertices); + setGeometryZ(rpFlags, edgeDeltasZ, numVerts, rvertices, + (!addToSkyMask? rtexcoords : NULL), + (!addToSkyMask? rcolors : NULL), + (!addToSkyMask? rcolorsShiny : NULL)); + + prepareSkyMaskSurface(rpFlags, numVerts, rvertices, + (!addToSkyMask? rtexcoords : NULL), + (!addToSkyMask? rcolors : NULL), + (!addToSkyMask? rcolorsShiny : NULL), + &primaryRTU, &primaryDetailRTU, + surfaceNormal, 0, 1, 0, ambientLightColor, + ambientLightLevel, lightLevelDeltaLeft, lightLevelDeltaRight, lightLevelDeltaBottom, lightLevelDeltaTop, 0, 0, 0, 0, seg->length, true, renderTextures!=2?fceil->PS_material:Materials_ToMaterial(Materials_ResolveUriCString(MN_SYSTEM_NAME":gray")), false); + + RL_LoadDefaultRtus(); + RL_CopyRtu(RTU_PRIMARY, primaryRTU); + RL_CopyRtu(RTU_PRIMARY_DETAIL, primaryDetailRTU); + + RL_AddPolyWithCoords(PT_TRIANGLE_STRIP, rpFlags, + numVerts, rvertices, rcolors, rtexcoords, NULL); } segPtr++; } } -/*static*/ void getSkymaskClosedOffsets(seg_t* seg, sector_t* frontsec, sector_t* backsec, +static void getSkymaskClosedOffsets(seg_t* seg, sector_t* frontsec, sector_t* backsec, plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, float skyFloor, float skyCeil, boolean topHasMaterialFix, float* offsets, float* bottom, float* top, boolean* addSolidViewSeg) { @@ -3604,7 +3577,7 @@ static __inline float getSkyCeiling(plane_t* ffloor, plane_t* fceil, plane_t* bf /** * danij: Still needed? */ -/*static*/ void getSkymaskClosedOffsets2(seg_t* seg, sector_t* frontsec, sector_t* backsec, +static void getSkymaskClosedOffsets2(seg_t* seg, sector_t* frontsec, sector_t* backsec, plane_t* ffloor, plane_t* fceil, plane_t* bfloor, plane_t* bceil, float skyFloor, float skyCeil, boolean bottomHasMaterialFix, float* offsets, float* bottom, float* top, boolean* addSolidViewSeg) @@ -3629,16 +3602,17 @@ static __inline float getSkyCeiling(plane_t* ffloor, plane_t* fceil, plane_t* bf } } -/*static*/ void drawSSectSkyFixClosed(rendpolytype_t polyType, subsector_t* ssec, boolean clipBackFacing, boolean flipSurfaceNormals) +static void drawSSectSkyFixClosed(subsector_t* ssec, boolean clipBackFacing, boolean flipSurfaceNormals, boolean addToSkyMask) { - rtexmapunit_t rTU[NUM_TEXMAP_UNITS]; + const int rpFlags = RPF_DEFAULT | (addToSkyMask? RPF_SKYMASK : 0); + const rtexmapunit_t* primaryRTU, *primaryDetailRTU; rtexcoord_t rtexcoords[4]; rvertex_t rvertices[4]; rcolor_t rcolors[4], rcolorsShiny[4]; size_t numVerts; seg_t** segPtr; - numVerts = buildSkymaskQuad(polyType, rvertices, (polyType == RPT_NORMAL? rtexcoords : 0)); + numVerts = buildSkymaskQuad(rpFlags, rvertices, !addToSkyMask? rtexcoords : NULL); segPtr = ssec->segs; while(*segPtr) @@ -3670,7 +3644,10 @@ static __inline float getSkyCeiling(plane_t* ffloor, plane_t* fceil, plane_t* bf V3_Set(edgeDeltasXY[2], to-> V_pos[VX], to-> V_pos[VY], 0); V3_Set(edgeDeltasXY[3], to-> V_pos[VX], to-> V_pos[VY], 0); - setGeometryXY(polyType, edgeDeltasXY, numVerts, rvertices, (polyType == RPT_NORMAL? rtexcoords : 0), (polyType == RPT_NORMAL? rcolors : 0), (polyType == RPT_NORMAL? rcolorsShiny : 0)); + setGeometryXY(rpFlags, edgeDeltasXY, numVerts, rvertices, + (!addToSkyMask? rtexcoords : NULL), + (!addToSkyMask? rcolors : NULL), + (!addToSkyMask? rcolorsShiny : NULL)); ffloor = frontsec->SP_plane(PLN_FLOOR); fceil = frontsec->SP_plane(PLN_CEILING); @@ -3693,12 +3670,27 @@ static __inline float getSkyCeiling(plane_t* ffloor, plane_t* fceil, plane_t* bf float lightLevelDeltaLeft = 0, lightLevelDeltaRight = 0, lightLevelDeltaBottom = 0, lightLevelDeltaTop = 0; getSurfaceLightLevelDeltas(seg, ffloor, fceil, bfloor, bceil, bottom, top, skyFloor, skyCeil, &lightLevelDeltaLeft, &lightLevelDeltaRight, &lightLevelDeltaBottom, &lightLevelDeltaTop); - translateGeometryDeltasZ(numVerts, edgeDeltasZ, offsets, rvertices); - memset(rTU, 0, sizeof(rTU)); - setGeometryZ(polyType, edgeDeltasZ, numVerts, rvertices, (polyType == RPT_NORMAL? rtexcoords : 0), (polyType == RPT_NORMAL? rcolors : 0), (polyType == RPT_NORMAL? rcolorsShiny : 0)); - prepareSkyMaskSurface(polyType, numVerts, rvertices, (polyType == RPT_NORMAL? rtexcoords : 0), (polyType == RPT_NORMAL? rcolors : 0), (polyType == RPT_NORMAL? rcolorsShiny : 0), rTU, 0, surfaceNormal, 0, 1, 0, ambientLightColor, ambientLightLevel, lightLevelDeltaLeft, lightLevelDeltaRight, lightLevelDeltaBottom, lightLevelDeltaTop, 0, 0, 0, 0, seg->length, true, renderTextures!=2?fceil->PS_material:Materials_ToMaterial(Materials_ResolveUriCString(MN_SYSTEM_NAME":gray")), false); - RL_AddPoly(PT_TRIANGLE_STRIP, polyType, rvertices, (polyType == RPT_NORMAL? rtexcoords : 0), 0, 0, (polyType == RPT_NORMAL? rcolors : 0), numVerts, 0, 0, 0, rTU); + translateGeometryDeltasZ(numVerts, edgeDeltasZ, offsets, rvertices); + setGeometryZ(rpFlags, edgeDeltasZ, numVerts, rvertices, + (!addToSkyMask? rtexcoords : NULL), + (!addToSkyMask? rcolors : NULL), + (!addToSkyMask? rcolorsShiny : NULL)); + + prepareSkyMaskSurface(rpFlags, numVerts, rvertices, + (!addToSkyMask? rtexcoords : NULL), + (!addToSkyMask? rcolors : NULL), + (!addToSkyMask? rcolorsShiny : NULL), + &primaryRTU, &primaryDetailRTU, + surfaceNormal, 0, 1, 0, ambientLightColor, + ambientLightLevel, lightLevelDeltaLeft, lightLevelDeltaRight, lightLevelDeltaBottom, lightLevelDeltaTop, 0, 0, 0, 0, seg->length, true, renderTextures!=2?fceil->PS_material:Materials_ToMaterial(Materials_ResolveUriCString(MN_SYSTEM_NAME":gray")), false); + + RL_LoadDefaultRtus(); + RL_CopyRtu(RTU_PRIMARY, primaryRTU); + RL_CopyRtu(RTU_PRIMARY_DETAIL, primaryDetailRTU); + + RL_AddPolyWithCoords(PT_TRIANGLE_STRIP, rpFlags, + numVerts, rvertices, rcolors, rtexcoords, NULL); } if(!P_IsInVoid(viewPlayer) && backsec && !LINE_SELFREF(lineDef)) @@ -3712,11 +3704,10 @@ static __inline float getSkyCeiling(plane_t* ffloor, plane_t* fceil, plane_t* bf static void Rend_SSectSkyFixes(subsector_t* ssec) { + const boolean clipBackFacing = (devRendSkyMode == 1); + const boolean flipSurfaceNormals = false; + const boolean addToSkyMask = (devRendSkyMode == 0); assert(ssec && ssec->sector && (devRendSkyMode == 2 || R_SectorContainsSkySurfaces(ssec->sector))); - { - rendpolytype_t polyType = (devRendSkyMode? RPT_NORMAL : RPT_SKY_MASK); - boolean clipBackFacing = (devRendSkyMode == 2? false : polyType == RPT_NORMAL); - boolean flipSurfaceNormals = false; /// Setup GL state for skymask geometry construction. /** @@ -3724,15 +3715,14 @@ static void Rend_SSectSkyFixes(subsector_t* ssec) glDisable(GL_CULL_FACE); */ - drawSSectSkyFixBottom(polyType, ssec, clipBackFacing, flipSurfaceNormals); - drawSSectSkyFixTop (polyType, ssec, clipBackFacing, flipSurfaceNormals); - drawSSectSkyFixClosed(polyType, ssec, clipBackFacing, flipSurfaceNormals); + drawSSectSkyFixBottom(ssec, clipBackFacing, flipSurfaceNormals, addToSkyMask); + drawSSectSkyFixTop (ssec, clipBackFacing, flipSurfaceNormals, addToSkyMask); + drawSSectSkyFixClosed(ssec, clipBackFacing, flipSurfaceNormals, addToSkyMask); /// Restore original GL state. /* glEnable(GL_CULL_FACE); */ - } } /** @@ -3990,6 +3980,9 @@ static void Rend_RenderSubsector(uint ssecidx) texOffset[VX] += ssec->worldGridOffset[VX]; texOffset[VY] += ssec->worldGridOffset[VY]; + // Inverted. + texOffset[VY] = -texOffset[VY]; + texScale[VX] = ((suf->flags & DDSUF_MATERIAL_FLIPH)? -1 : 1); texScale[VY] = ((suf->flags & DDSUF_MATERIAL_FLIPV)? -1 : 1); @@ -4965,7 +4958,7 @@ static void Rend_RenderBoundingBoxes(void) GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 1, -2, -1, true, true, true, false); ms = Materials_Prepare(mat, spec, true); - GL_BindTexture(MSU(ms, MTU_PRIMARY).tex.glName, MSU(ms, MTU_PRIMARY).magMode); + GL_BindTexture(MSU_gltexture(ms, MTU_PRIMARY), MSU(ms, MTU_PRIMARY).magMode); GL_BlendMode(BM_ADD); if(devMobjBBox) diff --git a/doomsday/engine/portable/src/rend_model.c b/doomsday/engine/portable/src/rend_model.c index 7c221cad11..ca905cd5fe 100644 --- a/doomsday/engine/portable/src/rend_model.c +++ b/doomsday/engine/portable/src/rend_model.c @@ -45,8 +45,9 @@ #include "de_graphics.h" #include "de_misc.h" -#include "net_main.h" // for gametic +#include "net_main.h" // for gametic #include "texture.h" +#include "texturevariant.h" #include "materialvariant.h" // MACROS ------------------------------------------------------------------ @@ -762,7 +763,7 @@ static void Mod_RenderSubModel(uint number, const rendmodelparams_t* params) MC_MODELSKIN, 0, 0, 0, 0, GL_REPEAT, GL_REPEAT, 1, -2, -1, true, true, false, false); const materialsnapshot_t* ms = Materials_Prepare(mat, spec, true); - skinTexture = MSU(ms, MTU_PRIMARY).tex.glName; + skinTexture = MSU_gltexture(ms, MTU_PRIMARY); } else { diff --git a/doomsday/engine/portable/src/rend_shadow.c b/doomsday/engine/portable/src/rend_shadow.c index 451ddfcf34..65ac5dd315 100644 --- a/doomsday/engine/portable/src/rend_shadow.c +++ b/doomsday/engine/portable/src/rend_shadow.c @@ -33,7 +33,6 @@ typedef struct { rvertex_t vertices[4]; rcolor_t colors[4]; rtexcoord_t texCoords[4]; - rtexmapunit_t texUnits[NUM_TEXMAP_UNITS]; } shadowprim_t; /// \optimize This global shadow primitive is used to avoid repeated local @@ -73,7 +72,8 @@ static void drawShadowPrimitive(const vectorcomp_t pos[3], float radius, float a rs->vertices[3].pos[VZ] = pos[VZ] + SHADOW_ZOFFSET; rs->colors[3].alpha = alpha; - RL_AddPoly(PT_FAN, RPT_SHADOW, rs->vertices, rs->texCoords, NULL, NULL, rs->colors, 4, 0, 0, NULL, rs->texUnits); + RL_AddPolyWithCoords(PT_FAN, RPF_DEFAULT|RPF_SHADOW, 4, + rs->vertices, rs->colors, rs->texCoords, NULL); } static void processMobjShadow(mobj_t* mo) @@ -144,11 +144,6 @@ static void initShadowPrimitive(void) { #define SETCOLOR_BLACK(c) ((c).rgba[CR] = (c).rgba[CG] = (c).rgba[CB] = 0) - memset(rs->texUnits, 0, sizeof(rs->texUnits)); - rs->texUnits[TU_PRIMARY].tex = GL_PrepareLSTexture(LST_DYNAMIC); - rs->texUnits[TU_PRIMARY].magMode = GL_LINEAR; - rs->texUnits[TU_PRIMARY].blend = 1; - rs->texCoords[0].st[0] = 0; rs->texCoords[0].st[1] = 1; SETCOLOR_BLACK(rs->colors[0]); @@ -177,7 +172,11 @@ void Rend_RenderMobjShadows(void) // Disabled for now, awaiting a heuristic analyser to enable it on selective mobjs. return; - // Initialize the invariant parts of our global shadow primitive now. + // Configure the render list primitive writer's texture unit state now. + RL_LoadDefaultRtus(); + RL_Rtu_SetTexture(RTU_PRIMARY, GL_PrepareLSTexture(LST_DYNAMIC)); + + // Initialize the invariant parts of our shadow primitive now. initShadowPrimitive(); // Process all sectors: @@ -202,27 +201,16 @@ int RIT_RenderShadowProjectionIterator(const shadowprojection_t* sp, void* param { static const float black[3] = { 0, 0, 0 }; rendershadowprojectionparams_t* p = (rendershadowprojectionparams_t*)paramaters; - rtexmapunit_t rTU[NUM_TEXMAP_UNITS]; rvertex_t* rvertices; rtexcoord_t* rtexcoords; rcolor_t* rcolors; uint i, c; - memset(rTU, 0, sizeof(rTU)); - // Allocate enough for the divisions too. rvertices = R_AllocRendVertices(p->realNumVertices); rtexcoords = R_AllocRendTexCoords(p->realNumVertices); rcolors = R_AllocRendColors(p->realNumVertices); - rTU[TU_PRIMARY].tex = GL_PrepareLSTexture(LST_DYNAMIC); - rTU[TU_PRIMARY].magMode = GL_LINEAR; - rTU[TU_PRIMARY].blend = 1; - - rTU[TU_PRIMARY_DETAIL].tex = 0; - rTU[TU_INTER].tex = 0; - rTU[TU_INTER_DETAIL].tex = 0; - for(i = 0; i < p->numVertices; ++i) { rcolor_t* col = &rcolors[i]; @@ -293,23 +281,16 @@ int RIT_RenderShadowProjectionIterator(const shadowprojection_t* sp, void* param if(p->isWall && p->divs) { - RL_AddPoly(PT_FAN, RPT_SHADOW, - rvertices + 3 + p->divs[0].num, - rtexcoords + 3 + p->divs[0].num, NULL, NULL, - rcolors + 3 + p->divs[0].num, - 3 + p->divs[1].num, 0, - 0, NULL, rTU); - RL_AddPoly(PT_FAN, RPT_SHADOW, - rvertices, rtexcoords, NULL, NULL, - rcolors, 3 + p->divs[0].num, 0, - 0, NULL, rTU); + RL_AddPolyWithCoords(PT_FAN, RPF_DEFAULT|RPF_SHADOW, + 3 + p->divs[1].num, rvertices + 3 + p->divs[0].num, + rcolors + 3 + p->divs[0].num, rtexcoords + 3 + p->divs[0].num, NULL); + RL_AddPolyWithCoords(PT_FAN, RPF_DEFAULT|RPF_SHADOW, + 3 + p->divs[0].num, rvertices, rcolors, rtexcoords, NULL); } else { - RL_AddPoly(p->isWall? PT_TRIANGLE_STRIP : PT_FAN, RPT_SHADOW, - rvertices, rtexcoords, NULL, NULL, - rcolors, p->numVertices, 0, - 0, NULL, rTU); + RL_AddPolyWithCoords(p->isWall? PT_TRIANGLE_STRIP : PT_FAN, RPF_DEFAULT|RPF_SHADOW, + p->numVertices, rvertices, rcolors, rtexcoords, NULL); } R_FreeRendVertices(rvertices); @@ -321,5 +302,10 @@ int RIT_RenderShadowProjectionIterator(const shadowprojection_t* sp, void* param void Rend_RenderShadowProjections(uint listIdx, rendershadowprojectionparams_t* p) { + // Configure the render list primitive writer's texture unit state now. + RL_LoadDefaultRtus(); + RL_Rtu_SetTexture(RTU_PRIMARY, GL_PrepareLSTexture(LST_DYNAMIC)); + + // Write shadows to the render lists. R_IterateShadowProjections2(listIdx, RIT_RenderShadowProjectionIterator, (void*)p); } diff --git a/doomsday/engine/portable/src/rend_sky.c b/doomsday/engine/portable/src/rend_sky.c index bd4e7ef331..db08c1b948 100644 --- a/doomsday/engine/portable/src/rend_sky.c +++ b/doomsday/engine/portable/src/rend_sky.c @@ -42,6 +42,7 @@ #include "de_play.h" #include "texture.h" +#include "texturevariant.h" #include "materialvariant.h" // MACROS ------------------------------------------------------------------ @@ -278,8 +279,8 @@ void Rend_SkyRenderer(int hemi, const rendskysphereparams_t* params) 1, 1, 0, false, true, false, false); ms = Materials_Prepare(mat, spec, true); - tex = MSU(ms, MTU_PRIMARY).tex.glName; - Texture_Dimensions(MSU(ms, MTU_PRIMARY).tex.texture, &skyTexWidth, &skyTexHeight); + tex = MSU_gltexture(ms, MTU_PRIMARY); + Texture_Dimensions(MSU_texture(ms, MTU_PRIMARY), &skyTexWidth, &skyTexHeight); magMode = MSU(ms, MTU_PRIMARY).magMode; } diff --git a/doomsday/engine/portable/src/rend_sprite.c b/doomsday/engine/portable/src/rend_sprite.c index 3a2236d298..0bd5587e0c 100644 --- a/doomsday/engine/portable/src/rend_sprite.c +++ b/doomsday/engine/portable/src/rend_sprite.c @@ -40,6 +40,7 @@ #include "de_ui.h" #include "texture.h" +#include "texturevariant.h" #include "materialvariant.h" // MACROS ------------------------------------------------------------------ @@ -342,13 +343,13 @@ static void setupPSpriteParams(rendpspriteparams_t* params, vispsprite_t* spr) ms = Materials_Prepare(sprFrame->mats[0], spec, true); #if _DEBUG - if(Textures_Namespace(Textures_Id(MSU(ms, MTU_PRIMARY).tex.texture)) != TN_SPRITES) + if(Textures_Namespace(Textures_Id(MSU_texture(ms, MTU_PRIMARY))) != TN_SPRITES) Con_Error("setupPSpriteParams: Internal error, material snapshot's primary texture is not a SpriteTex!"); #endif - sprTex = (spritetex_t*)Texture_UserData(MSU(ms, MTU_PRIMARY).tex.texture); + sprTex = (spritetex_t*)Texture_UserData(MSU_texture(ms, MTU_PRIMARY)); assert(sprTex); - texSpec = TS_GENERAL(MSU(ms, MTU_PRIMARY).tex.spec); + texSpec = TS_GENERAL(MSU_texturespec(ms, MTU_PRIMARY)); assert(spec); params->pos[VX] = psp->pos[VX] - sprTex->offX + pspOffset[VX] + -texSpec->border; @@ -356,9 +357,7 @@ static void setupPSpriteParams(rendpspriteparams_t* params, vispsprite_t* spr) params->width = ms->width + texSpec->border*2; params->height = ms->height + texSpec->border*2; - // Calculate texture coordinates. - params->texOffset[0] = MSU(ms, MTU_PRIMARY).tex.s; - params->texOffset[1] = MSU(ms, MTU_PRIMARY).tex.t; + TextureVariant_Coords(MST(ms, MTU_PRIMARY), ¶ms->texOffset[0], ¶ms->texOffset[1]); params->texFlip[0] = flip; params->texFlip[1] = false; @@ -434,7 +433,7 @@ void Rend_DrawPSprite(const rendpspriteparams_t *params) MC_SPRITE, 0, 0, 0, 0, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 1, -2, 0, false, true, true, false); const materialsnapshot_t* ms = Materials_Prepare(mat, spec, true); - GL_BindTexture(MSU(ms, MTU_PRIMARY).tex.glName, MSU(ms, MTU_PRIMARY).magMode); + GL_BindTexture(MSU_gltexture(ms, MTU_PRIMARY), MSU(ms, MTU_PRIMARY).magMode); glEnable(GL_TEXTURE_2D); } @@ -583,13 +582,19 @@ void Rend_RenderMaskedWall(rendmaskedwallparams_t *params) // The dynamic light. glActiveTexture(IS_MUL ? GL_TEXTURE0 : GL_TEXTURE1); - GL_BindTexture(renderTextures ? params->modTex : 0, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, renderTextures ? params->modTex : 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if(GL_state.features.texFilterAniso) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GL_GetTexAnisoMul(texAniso)); glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, params->modColor); // The actual texture. glActiveTexture(IS_MUL ? GL_TEXTURE1 : GL_TEXTURE0); - GL_BindTexture(renderTextures ? params->tex : 0, params->magMode); + glBindTexture(GL_TEXTURE_2D, renderTextures ? params->tex : 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, params->magMode); + if(GL_state.features.texFilterAniso) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GL_GetTexAnisoMul(texAniso)); withDyn = true; } @@ -598,7 +603,10 @@ void Rend_RenderMaskedWall(rendmaskedwallparams_t *params) GL_SelectTexUnits(1); GL_ModulateTexture(1); - GL_BindTexture(renderTextures? params->tex : 0, params->magMode); + glBindTexture(GL_TEXTURE_2D, renderTextures? params->tex : 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, params->magMode); + if(GL_state.features.texFilterAniso) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GL_GetTexAnisoMul(texAniso)); normal = 0; } @@ -934,6 +942,7 @@ void Rend_RenderSprite(const rendspriteparams_t* params) float spriteCenter[3]; float surfaceNormal[3]; material_t* mat = NULL; + float s = 1, t = 1; // bottom right coords. int i; if(renderTextures == 1) @@ -951,7 +960,8 @@ void Rend_RenderSprite(const rendspriteparams_t* params) 1, -2, -1, true, true, true, false); const materialsnapshot_t* ms = Materials_Prepare(mat, spec, true); - GL_BindTexture(MSU(ms, MTU_PRIMARY).tex.glName, MSU(ms, MTU_PRIMARY).magMode); + GL_BindTexture(MSU_gltexture(ms, MTU_PRIMARY), MSU(ms, MTU_PRIMARY).magMode); + TextureVariant_Coords(MST(ms, MTU_PRIMARY), &s, &t); glEnable(GL_TEXTURE_2D); } else @@ -1071,8 +1081,8 @@ glEnd(); } { - dgl_vertex_t vs[4], *v = vs; - dgl_texcoord_t tcs[4], *tc = tcs; + dgl_vertex_t vs[4], *v = vs; + dgl_texcoord_t tcs[4], *tc = tcs; // 1---2 // | | Vertex layout. @@ -1094,14 +1104,14 @@ glEnd(); v[3].xyz[1] = v4[VZ]; v[3].xyz[2] = v4[VY]; - tc[0].st[0] = params->matOffset[0] * (params->matFlip[0]? 1:0); - tc[0].st[1] = params->matOffset[1] * (!params->matFlip[1]? 1:0); - tc[1].st[0] = params->matOffset[0] * (params->matFlip[0]? 1:0); - tc[1].st[1] = params->matOffset[1] * (params->matFlip[1]? 1:0); - tc[2].st[0] = params->matOffset[0] * (!params->matFlip[0]? 1:0); - tc[2].st[1] = params->matOffset[1] * (params->matFlip[1]? 1:0); - tc[3].st[0] = params->matOffset[0] * (!params->matFlip[0]? 1:0); - tc[3].st[1] = params->matOffset[1] * (!params->matFlip[1]? 1:0); + tc[0].st[0] = s * (params->matFlip[0]? 1:0); + tc[0].st[1] = t * (!params->matFlip[1]? 1:0); + tc[1].st[0] = s * (params->matFlip[0]? 1:0); + tc[1].st[1] = t * (params->matFlip[1]? 1:0); + tc[2].st[0] = s * (!params->matFlip[0]? 1:0); + tc[2].st[1] = t * (params->matFlip[1]? 1:0); + tc[3].st[0] = s * (!params->matFlip[0]? 1:0); + tc[3].st[1] = t * (!params->matFlip[1]? 1:0); renderQuad(v, quadColors, tc); } diff --git a/doomsday/engine/portable/src/sys_sdl_window.c b/doomsday/engine/portable/src/sys_sdl_window.c index 0f2d7e3081..c0170a9f48 100644 --- a/doomsday/engine/portable/src/sys_sdl_window.c +++ b/doomsday/engine/portable/src/sys_sdl_window.c @@ -739,8 +739,7 @@ extern boolean usingFog; gx.UpdateState(DD_RENDER_RESTART_PRE); R_UnloadVectorGraphics(); - Rend_ParticleReleaseExtraTextures(); - GL_ReleaseSystemTextures(); + GL_ReleaseTextures(); } if(createContext(window->width, window->height, window->normal.bpp, diff --git a/doomsday/engine/portable/src/ui2_main.c b/doomsday/engine/portable/src/ui2_main.c index a2273aad01..f5d0bab435 100644 --- a/doomsday/engine/portable/src/ui2_main.c +++ b/doomsday/engine/portable/src/ui2_main.c @@ -33,6 +33,7 @@ #include "de_audio.h" #include "de_misc.h" +#include "texturevariant.h" #include "materialvariant.h" // MACROS ------------------------------------------------------------------ @@ -531,17 +532,19 @@ static void drawPageBackground(fi_page_t* p, float x, float y, float width, floa MC_UI, 0, 0, 0, 0, GL_REPEAT, GL_REPEAT, 0, 1, 0, false, false, false, false); const materialsnapshot_t* ms = Materials_Prepare(p->_bg.material, spec, true); - tex = ms->units[MTU_PRIMARY].tex.glName; + tex = MSU_gltexture(ms, MTU_PRIMARY); } else { - tex = p->_bg.tex; - if(tex) - { // Make sure the current texture will be tiled. - glBindTexture(GL_TEXTURE_2D, tex); + DGLuint glName = p->_bg.tex; + if(glName) + { + // Make sure the current texture will be tiled. + glBindTexture(GL_TEXTURE_2D, glName); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } + tex = p->_bg.tex; } V3_Set(topColor, p->_bg.topColor [0].value * light, p->_bg.topColor [1].value * light, p->_bg.topColor [2].value * light); V3_Set(bottomColor, p->_bg.bottomColor[0].value * light, p->_bg.bottomColor[1].value * light, p->_bg.bottomColor[2].value * light); @@ -990,7 +993,7 @@ static void drawPicFrame(fidata_pic_t* p, uint frame, const float _origin[3], break; } case PFT_XIMAGE: - glTexName = (DGLuint)f->texRef.tex; + glTexName = f->texRef.tex; V3_Set(offset, 0, 0, 0); V3_Set(dimensions, 1, 1, 0); break; @@ -1001,31 +1004,31 @@ static void drawPicFrame(fidata_pic_t* p, uint frame, const float _origin[3], const materialvariantspecification_t* spec = Materials_VariantSpecificationForContext( MC_UI, 0, 1, 0, 0, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0, 1, 0, false, false, false, false); const materialsnapshot_t* ms = Materials_Prepare(mat, spec, true); + DGLuint tex = MSU_gltexture(ms, MTU_PRIMARY); - if(ms->units[MTU_PRIMARY].tex.glName) + if(tex) { - const texturevariantspecification_t* spec = MSU(ms, MTU_PRIMARY).tex.spec; + const texturevariantspecification_t* spec = MSU_texturespec(ms, MTU_PRIMARY); /// \todo Utilize *all* properties of the Material. - glTexName = MSU(ms, MTU_PRIMARY).tex.glName; V3_Set(offset, -MSU(ms, MTU_PRIMARY).offset[0], -MSU(ms, MTU_PRIMARY).offset[1], 0); V3_Set(dimensions, ms->width + TS_GENERAL(spec)->border*2, ms->height + TS_GENERAL(spec)->border*2, 0); - V2_Set(texScale, MSU(ms, MTU_PRIMARY).tex.s, MSU(ms, MTU_PRIMARY).tex.t); + TextureVariant_Coords(MST(ms, MTU_PRIMARY), &texScale[VX], &texScale[VY]); } } break; } case PFT_PATCH: { - texture_t* tex = Textures_ToTexture(Textures_TextureForUniqueId(TN_PATCHES, f->texRef.patch)); - if(tex) + texture_t* texture = Textures_ToTexture(Textures_TextureForUniqueId(TN_PATCHES, f->texRef.patch)); + if(texture) { - patchtex_t* pTex = (patchtex_t*)Texture_UserData(tex); + patchtex_t* pTex = (patchtex_t*)Texture_UserData(texture); assert(pTex); - glTexName = (renderTextures==1? GL_PreparePatchTexture(tex) : 0); + glTexName = (renderTextures==1? GL_PreparePatchTexture(texture) : 0); V3_Set(offset, pTex->offX, pTex->offY, 0); - V3_Set(dimensions, Texture_Width(tex), Texture_Height(tex), 0); + V3_Set(dimensions, Texture_Width(texture), Texture_Height(texture), 0); } break; } diff --git a/doomsday/engine/win32/src/sys_window.c b/doomsday/engine/win32/src/sys_window.c index 6bb2aeed1e..39f621e0f7 100644 --- a/doomsday/engine/win32/src/sys_window.c +++ b/doomsday/engine/win32/src/sys_window.c @@ -1215,8 +1215,7 @@ extern boolean usingFog; gx.UpdateState(DD_RENDER_RESTART_PRE); R_UnloadVectorGraphics(); - Rend_ParticleReleaseExtraTextures(); - GL_ReleaseSystemTextures(); + GL_ReleaseTextures(); wglMakeCurrent(NULL, NULL); wglDeleteContext(window->normal.glContext);