/// @todo fixme: Should use the visual plane heights of subsectors. static bool middleMaterialCoversOpening(LineSide const &side) { if (!side.hasSector()) return false; // Never. if (!side.hasSections()) return false; //if (!side.middle().hasMaterial()) return false; MaterialAnimator *matAnimator = side.middle().materialAnimator(); /* material().as<ClientMaterial>() .getAnimator(Rend_MapSurfaceMaterialSpec());*/ if (!matAnimator) return false; // Ensure we have up to date info about the material. matAnimator->prepare(); // Might the material cover the opening? if (matAnimator->isOpaque() && !side.middle().blendMode() && side.middle().opacity() >= 1) { // Stretched middles always cover the opening. if (side.isFlagged(SDF_MIDDLE_STRETCH)) return true; Sector const &frontSec = side.sector(); Sector const *backSec = side.back().sectorPtr(); // Determine the opening between the visual sector planes at this edge. coord_t openBottom; if (backSec && backSec->floor().heightSmoothed() > frontSec.floor().heightSmoothed()) { openBottom = backSec->floor().heightSmoothed(); } else { openBottom = frontSec.floor().heightSmoothed(); } coord_t openTop; if (backSec && backSec->ceiling().heightSmoothed() < frontSec.ceiling().heightSmoothed()) { openTop = backSec->ceiling().heightSmoothed(); } else { openTop = frontSec.ceiling().heightSmoothed(); } if (matAnimator->dimensions().y >= openTop - openBottom) { // Possibly; check the placement. if(side.leftHEdge()) // possibility of degenerate BSP leaf { WallEdge edge(WallSpec::fromMapSide(side, LineSide::Middle), *side.leftHEdge(), Line::From); return (edge.isValid() && edge.top().z() > edge.bottom().z() && edge.top().z() >= openTop && edge.bottom().z() <= openBottom); } } } return false; }
void updateDecorations(Surface &suf, MaterialAnimator &matAnimator, Vector2f const &materialOrigin, Vector3d const &topLeft, Vector3d const &bottomRight, Sector *containingSector = nullptr) { Vector3d delta = bottomRight - topLeft; if(de::fequal(delta.length(), 0)) return; Material &material = matAnimator.material(); int const axis = suf.normal().maxAxis(); Vector2d sufDimensions; if(axis == 0 || axis == 1) { sufDimensions.x = std::sqrt(de::squared(delta.x) + de::squared(delta.y)); sufDimensions.y = delta.z; } else { sufDimensions.x = std::sqrt(de::squared(delta.x)); sufDimensions.y = delta.y; } if(sufDimensions.x < 0) sufDimensions.x = -sufDimensions.x; if(sufDimensions.y < 0) sufDimensions.y = -sufDimensions.y; // Generate a number of decorations. int decorIndex = 0; material.forAllDecorations([&suf, &matAnimator, &materialOrigin , &topLeft, &bottomRight, &containingSector , &delta, &axis, &sufDimensions, &decorIndex] (MaterialDecoration &decor) { Vector2i const &matDimensions = matAnimator.material().dimensions(); MaterialAnimator::Decoration const &decorSS = matAnimator.decoration(decorIndex); // Skip values must be at least one. Vector2i skip = Vector2i(decor.patternSkip().x + 1, decor.patternSkip().y + 1) .max(Vector2i(1, 1)); Vector2f repeat = matDimensions * skip; if(repeat == Vector2f(0, 0)) return LoopAbort; Vector3d origin = topLeft + suf.normal() * decorSS.elevation(); float s = de::wrap(decorSS.origin().x - matDimensions.x * decor.patternOffset().x + materialOrigin.x, 0.f, repeat.x); // Plot decorations. for(; s < sufDimensions.x; s += repeat.x) { // Determine the topmost point for this row. float t = de::wrap(decorSS.origin().y - matDimensions.y * decor.patternOffset().y + materialOrigin.y, 0.f, repeat.y); for(; t < sufDimensions.y; t += repeat.y) { float const offS = s / sufDimensions.x; float const offT = t / sufDimensions.y; Vector3d patternOffset(offS, axis == VZ? offT : offS, axis == VZ? offS : offT); Vector3d decorOrigin = origin + delta * patternOffset; ConvexSubspace *subspace = suf.map().bspLeafAt(decorOrigin).subspacePtr(); if(!subspace) continue; if(!subspace->contains(decorOrigin)) continue; if(containingSector) { // The point must be in the correct sector. if(containingSector != &subspace->sector()) continue; } suf.addDecoration(new LightDecoration(decorSS, decorOrigin)); } } decorIndex += 1; return LoopContinue; }); }
void Rend_DrawMaskedWall(drawmaskedwallparams_t const &parms) { DENG_ASSERT_IN_MAIN_THREAD(); DENG_ASSERT_GL_CONTEXT_ACTIVE(); TextureVariant *tex = nullptr; if(::renderTextures) { MaterialAnimator *matAnimator = parms.animator; DENG2_ASSERT(matAnimator); // Ensure we have up to date info about the material. matAnimator->prepare(); tex = matAnimator->texUnit(MaterialAnimator::TU_LAYER0).texture; } // Do we have a dynamic light to blend with? // This only happens when multitexturing is enabled. bool withDyn = false; dint normal = 0, dyn = 1; if(parms.modTex && ::numTexUnits > 1) { if(IS_MUL) { normal = 1; dyn = 0; } else { normal = 0; dyn = 1; } GL_SelectTexUnits(2); GL_ModulateTexture(IS_MUL ? 4 : 5); // The dynamic light. glActiveTexture(IS_MUL ? GL_TEXTURE0 : GL_TEXTURE1); /// @todo modTex may be the name of a "managed" texture. GL_BindTextureUnmanaged(renderTextures ? parms.modTex : 0, gl::ClampToEdge, gl::ClampToEdge); glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, parms.modColor); // The actual texture. glActiveTexture(IS_MUL ? GL_TEXTURE1 : GL_TEXTURE0); GL_BindTexture(tex); withDyn = true; } else { GL_ModulateTexture(1); glEnable(GL_TEXTURE_2D); GL_BindTexture(tex); normal = 0; } GL_BlendMode(parms.blendMode); GLenum normalTarget = normal? GL_TEXTURE1 : GL_TEXTURE0; GLenum dynTarget = dyn? GL_TEXTURE1 : GL_TEXTURE0; // Draw one quad. This is obviously not a very efficient way to render // lots of masked walls, but since 3D models and sprites must be // rendered interleaved with masked walls, there's not much that can be // done about this. if(withDyn) { glBegin(GL_QUADS); glColor4fv(parms.vertices[0].color); glMultiTexCoord2f(normalTarget, parms.texCoord[0][0], parms.texCoord[1][1]); glMultiTexCoord2f(dynTarget, parms.modTexCoord[0][0], parms.modTexCoord[1][1]); glVertex3f(parms.vertices[0].pos[0], parms.vertices[0].pos[2], parms.vertices[0].pos[1]); glColor4fv(parms.vertices[1].color); glMultiTexCoord2f(normalTarget, parms.texCoord[0][0], parms.texCoord[0][1]); glMultiTexCoord2f(dynTarget, parms.modTexCoord[0][0], parms.modTexCoord[0][1]); glVertex3f(parms.vertices[1].pos[0], parms.vertices[1].pos[2], parms.vertices[1].pos[1]); glColor4fv(parms.vertices[3].color); glMultiTexCoord2f(normalTarget, parms.texCoord[1][0], parms.texCoord[0][1]); glMultiTexCoord2f(dynTarget, parms.modTexCoord[1][0], parms.modTexCoord[0][1]); glVertex3f(parms.vertices[3].pos[0], parms.vertices[3].pos[2], parms.vertices[3].pos[1]); glColor4fv(parms.vertices[2].color); glMultiTexCoord2f(normalTarget, parms.texCoord[1][0], parms.texCoord[1][1]); glMultiTexCoord2f(dynTarget, parms.modTexCoord[1][0], parms.modTexCoord[1][1]); glVertex3f(parms.vertices[2].pos[0], parms.vertices[2].pos[2], parms.vertices[2].pos[1]); glEnd(); // Restore normal GL state. GL_SelectTexUnits(1); GL_ModulateTexture(1); } else { glBegin(GL_QUADS); glColor4fv(parms.vertices[0].color); glTexCoord2f(parms.texCoord[0][0], parms.texCoord[1][1]); glVertex3f(parms.vertices[0].pos[0], parms.vertices[0].pos[2], parms.vertices[0].pos[1]); glColor4fv(parms.vertices[1].color); glTexCoord2f(parms.texCoord[0][0], parms.texCoord[0][1]); glVertex3f(parms.vertices[1].pos[0], parms.vertices[1].pos[2], parms.vertices[1].pos[1]); glColor4fv(parms.vertices[3].color); glTexCoord2f(parms.texCoord[1][0], parms.texCoord[0][1]); glVertex3f(parms.vertices[3].pos[0], parms.vertices[3].pos[2], parms.vertices[3].pos[1]); glColor4fv(parms.vertices[2].color); glTexCoord2f(parms.texCoord[1][0], parms.texCoord[1][1]); glVertex3f(parms.vertices[2].pos[0], parms.vertices[2].pos[2], parms.vertices[2].pos[1]); glEnd(); } glDisable(GL_TEXTURE_2D); GL_BlendMode(BM_NORMAL); }
void materialAnimatorDecorationStageChanged(MaterialAnimator &animator) { markSurfacesForRedecoration(animator.material()); }