Skip to content

Commit

Permalink
Fixed: Mismanagement of GL texture state
Browse files Browse the repository at this point in the history
Middle wall sections on two-sided linedefs use different wrap states
depending on whether the texture coordinates are within the expected
[0..1] range.

Previously this was handled by changing the current wrap state for a
GL texture directly in Rend_RenderMaskedWall(). Also, this routine
assumed tthe previous state was GL_REPEAT on both u and v axes.

Now we have the texture variant and variant specification abstractions
the GL texture state for textures handled by the GL texture manager
should only be updated by it, not by users of this subsystem.

Todo: This presently results in the preparation of additional copies
of some textures, due to the fact a variant material has already been
chosen prior to calling Rend_AddMaskedPoly(). The logic flow of
rendSegSection() should be refactored so that either a) preparation
of the variant is deferred or, b) final variant is chosen earlier.
  • Loading branch information
danij-deng committed Jan 26, 2012
1 parent c783f85 commit 3e30e2d
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 133 deletions.
24 changes: 15 additions & 9 deletions doomsday/engine/portable/include/r_things.h
Expand Up @@ -69,18 +69,19 @@ typedef enum {

typedef struct rendmaskedwallparams_s {
struct materialvariant_s* material;
blendmode_t blendMode; // Blendmode to be used when drawing
// (two sided mid textures only)
blendmode_t blendMode; ///< Blendmode to be used when drawing
/// (two sided mid textures only)
struct wall_vertex_s {
float pos[3]; // x y and z coordinates.
float color[4];
float pos[3]; ///< x y and z coordinates.
float color[4];
} vertices[4];
float texOffset[2];
float length; // Precalculated 2D distance from v1 > v2

DGLuint modTex; // Texture to modulate with.
float modTexCoord[2][2]; // u and v coordinates.
float modColor[4];
Point2Rawf texOffset;
float texCoord[2][2]; ///< u and v coordinates.

DGLuint modTex; ///< Texture to modulate with.
float modTexCoord[2][2]; ///< u and v coordinates.
float modColor[4];
} rendmaskedwallparams_t;

typedef struct rendspriteparams_s {
Expand Down Expand Up @@ -146,6 +147,11 @@ typedef struct vissprite_s {
} data;
} vissprite_t;

#define VS_SPRITE(v) (&((v)->data.sprite))
#define VS_WALL(v) (&((v)->data.wall))
#define VS_MODEL(v) (&((v)->data.model))
#define VS_FLARE(v) (&((v)->data.flare))

typedef enum {
VPSPR_SPRITE,
VPSPR_MODEL
Expand Down
103 changes: 75 additions & 28 deletions doomsday/engine/portable/src/rend_main.c
Expand Up @@ -666,6 +666,14 @@ int RIT_FirstDynlightIterator(const dynlight_t* dyn, void* paramaters)
return 1; // Stop iteration.
}

static __inline const materialvariantspecification_t*
mapSurfaceMaterialSpec(int wrapS, int wrapT)
{
return Materials_VariantSpecificationForContext(MC_MAPSURFACE, 0, 0, 0, 0,
wrapS, wrapT, -1, -1, -1,
true, true, false, false);
}

/**
* This doesn't create a rendering primitive but a vissprite! The vissprite
* represents the masked poly and will be rendered during the rendering
Expand All @@ -677,34 +685,74 @@ void Rend_AddMaskedPoly(const rvertex_t* rvertices, const ColorRawf* rcolors,
blendmode_t blendMode, uint lightListIdx, float glow)
{
vissprite_t* vis = R_NewVisSprite();
float midpoint[3];
int i, c;

midpoint[VX] = (rvertices[0].pos[VX] + rvertices[3].pos[VX]) / 2;
midpoint[VY] = (rvertices[0].pos[VY] + rvertices[3].pos[VY]) / 2;
midpoint[VZ] = (rvertices[0].pos[VZ] + rvertices[3].pos[VZ]) / 2;

vis->type = VSPR_MASKED_WALL;
vis->center[VX] = midpoint[VX];
vis->center[VY] = midpoint[VY];
vis->center[VZ] = midpoint[VZ];
vis->distance = Rend_PointDist2D(midpoint);
vis->data.wall.material = material;
vis->data.wall.texOffset[VX] = texOffset? texOffset[VX] : 0;
vis->data.wall.texOffset[VY] = texOffset? texOffset[VY] : 0;
vis->data.wall.length = wallLength;
vis->data.wall.blendMode = blendMode;
vis->center[VX] = (rvertices[0].pos[VX] + rvertices[3].pos[VX]) / 2;
vis->center[VY] = (rvertices[0].pos[VY] + rvertices[3].pos[VY]) / 2;
vis->center[VZ] = (rvertices[0].pos[VZ] + rvertices[3].pos[VZ]) / 2;
vis->distance = Rend_PointDist2D(vis->center);

if(texOffset)
{
VS_WALL(vis)->texOffset.x = texOffset[VX];
VS_WALL(vis)->texOffset.y = texOffset[VY];
}

// Masked walls are sometimes used for special effects like arcs,
// cobwebs and bottoms of sails. In order for them to look right,
// we need to disable texture wrapping on the horizontal axis (S).
// Most masked walls need wrapping, though. What we need to do is
// look at the texture coordinates and see if they require texture
// wrapping.
if(renderTextures)
{
const materialsnapshot_t* ms = Materials_PrepareVariant(material);
int wrapS = GL_REPEAT, wrapT = GL_REPEAT;

VS_WALL(vis)->texCoord[0][VX] = VS_WALL(vis)->texOffset.x / ms->size.width;
VS_WALL(vis)->texCoord[1][VX] = VS_WALL(vis)->texCoord[0][VX] + wallLength / ms->size.width;
VS_WALL(vis)->texCoord[0][VY] = VS_WALL(vis)->texOffset.y / ms->size.height;
VS_WALL(vis)->texCoord[1][VY] = VS_WALL(vis)->texCoord[0][VY] +
(rvertices[3].pos[VZ] - rvertices[0].pos[VZ]) / ms->size.height;

if(ms && !ms->isOpaque)
{
if(!(VS_WALL(vis)->texCoord[0][VX] < 0 || VS_WALL(vis)->texCoord[0][VX] > 1 ||
VS_WALL(vis)->texCoord[1][VX] < 0 || VS_WALL(vis)->texCoord[1][VX] > 1))
{
// Visible portion is within the actual [0..1] range.
wrapS = GL_CLAMP_TO_EDGE;
}

// Clamp on the vertical axis if the coords are in the normal [0..1] range.
if(!(VS_WALL(vis)->texCoord[0][VY] < 0 || VS_WALL(vis)->texCoord[0][VY] > 1 ||
VS_WALL(vis)->texCoord[1][VY] < 0 || VS_WALL(vis)->texCoord[1][VY] > 1))
{
wrapT = GL_CLAMP_TO_EDGE;
}
}

// Choose an appropriate variant.
/// @fixme Can result in multiple variants being prepared.
/// This decision should be made earlier (in rendSegSection()).
material = Materials_ChooseVariant(MaterialVariant_GeneralCase(material),
mapSurfaceMaterialSpec(wrapS, wrapT), true, true);
}

VS_WALL(vis)->material = material;
VS_WALL(vis)->blendMode = blendMode;

for(i = 0; i < 4; ++i)
{
vis->data.wall.vertices[i].pos[VX] = rvertices[i].pos[VX];
vis->data.wall.vertices[i].pos[VY] = rvertices[i].pos[VY];
vis->data.wall.vertices[i].pos[VZ] = rvertices[i].pos[VZ];
VS_WALL(vis)->vertices[i].pos[VX] = rvertices[i].pos[VX];
VS_WALL(vis)->vertices[i].pos[VY] = rvertices[i].pos[VY];
VS_WALL(vis)->vertices[i].pos[VZ] = rvertices[i].pos[VZ];

for(c = 0; c < 4; ++c)
{
vis->data.wall.vertices[i].color[c] =
MINMAX_OF(0, rcolors[i].rgba[c], 1);
/// @todo Do not clamp here.
VS_WALL(vis)->vertices[i].color[c] = MINMAX_OF(0, rcolors[i].rgba[c], 1);
}
}

Expand All @@ -720,17 +768,17 @@ void Rend_AddMaskedPoly(const rvertex_t* rvertices, const ColorRawf* rcolors,
*/
LO_IterateProjections2(lightListIdx, RIT_FirstDynlightIterator, (void*)&dyn);

vis->data.wall.modTex = dyn->texture;
vis->data.wall.modTexCoord[0][0] = dyn->s[0];
vis->data.wall.modTexCoord[0][1] = dyn->s[1];
vis->data.wall.modTexCoord[1][0] = dyn->t[0];
vis->data.wall.modTexCoord[1][1] = dyn->t[1];
VS_WALL(vis)->modTex = dyn->texture;
VS_WALL(vis)->modTexCoord[0][0] = dyn->s[0];
VS_WALL(vis)->modTexCoord[0][1] = dyn->s[1];
VS_WALL(vis)->modTexCoord[1][0] = dyn->t[0];
VS_WALL(vis)->modTexCoord[1][1] = dyn->t[1];
for(c = 0; c < 4; ++c)
vis->data.wall.modColor[c] = dyn->color.rgba[c];
VS_WALL(vis)->modColor[c] = dyn->color.rgba[c];
}
else
{
vis->data.wall.modTex = 0;
VS_WALL(vis)->modTex = 0;
}
}

Expand Down Expand Up @@ -844,8 +892,7 @@ static void flatShinyTexCoords(rtexcoord_t* tc, const float xyz[3])
static float getSnapshots(const materialsnapshot_t** msA,
const materialsnapshot_t** msB, material_t* mat)
{
const materialvariantspecification_t* spec = Materials_VariantSpecificationForContext(
MC_MAPSURFACE, 0, 0, 0, 0, GL_REPEAT, GL_REPEAT, -1, -1, -1, true, true, false, false);
const materialvariantspecification_t* spec = mapSurfaceMaterialSpec(GL_REPEAT, GL_REPEAT);
float interPos = 0;
assert(msA);

Expand Down

0 comments on commit 3e30e2d

Please sign in to comment.