bool ExtrudeGeometryFilter::buildWallGeometry(const Structure& structure, osg::Geometry* walls, const osg::Vec4& wallColor, const osg::Vec4& wallBaseColor, const SkinResource* wallSkin) { bool madeGeom = true; // 6 verts per face total (3 triangles) unsigned numWallVerts = 6 * structure.getNumPoints(); double texWidthM = wallSkin ? *wallSkin->imageWidth() : 1.0; double texHeightM = wallSkin ? *wallSkin->imageHeight() : 1.0; bool useColor = (!wallSkin || wallSkin->texEnvMode() != osg::TexEnv::DECAL) && !_makeStencilVolume; // Scale and bias: osg::Vec2f scale, bias; float layer; if ( wallSkin ) { bias.set (wallSkin->imageBiasS().get(), wallSkin->imageBiasT().get()); scale.set(wallSkin->imageScaleS().get(), wallSkin->imageScaleT().get()); layer = (float)wallSkin->imageLayer().get(); } // create all the OSG geometry components osg::Vec3Array* verts = new osg::Vec3Array( numWallVerts ); walls->setVertexArray( verts ); osg::Vec3Array* tex = 0L; if ( wallSkin ) { tex = new osg::Vec3Array( numWallVerts ); walls->setTexCoordArray( 0, tex ); } osg::Vec4Array* colors = 0L; if ( useColor ) { // per-vertex colors are necessary if we are going to use the MeshConsolidator -gw colors = new osg::Vec4Array( numWallVerts ); walls->setColorArray( colors ); walls->setColorBinding( osg::Geometry::BIND_PER_VERTEX ); } unsigned vertptr = 0; bool tex_repeats_y = wallSkin && wallSkin->isTiled() == true; for(Elevations::const_iterator elev = structure.elevations.begin(); elev != structure.elevations.end(); ++elev) { osg::DrawElements* de = numWallVerts > 0xFFFF ? (osg::DrawElements*) new osg::DrawElementsUInt ( GL_TRIANGLES ) : numWallVerts > 0xFF ? (osg::DrawElements*) new osg::DrawElementsUShort( GL_TRIANGLES ) : (osg::DrawElements*) new osg::DrawElementsUByte ( GL_TRIANGLES ); // pre-allocate for speed de->reserveElements( numWallVerts ); walls->addPrimitiveSet( de ); for(Faces::const_iterator f = elev->faces.begin(); f != elev->faces.end(); ++f, vertptr+=6) { // set the 6 wall verts. (*verts)[vertptr+0] = f->left.roof; (*verts)[vertptr+1] = f->left.base; (*verts)[vertptr+2] = f->right.base; (*verts)[vertptr+3] = f->right.base; (*verts)[vertptr+4] = f->right.roof; (*verts)[vertptr+5] = f->left.roof; // Assign wall polygon colors. if (useColor) { #if 0 // experimental: apply some ambient occlusion to tight inside corners float bL = f->left.cosAngle > 0.0 ? 1.0 : (1.0+f->left.cosAngle); float bR = f->right.cosAngle > 0.0 ? 1.0 : (1.0+f->right.cosAngle); osg::Vec4f leftColor = Color(wallColor).brightness(bL); osg::Vec4f leftBaseColor = Color(wallBaseColor).brightness(bL); osg::Vec4f rightColor = Color(wallColor).brightness(bR); osg::Vec4f rightBaseColor = Color(wallBaseColor).brightness(bR); (*colors)[vertptr+0] = leftColor; (*colors)[vertptr+1] = leftBaseColor; (*colors)[vertptr+2] = rightBaseColor; (*colors)[vertptr+3] = rightBaseColor; (*colors)[vertptr+4] = rightColor; (*colors)[vertptr+5] = leftColor; #else (*colors)[vertptr+0] = wallColor; (*colors)[vertptr+1] = wallBaseColor; (*colors)[vertptr+2] = wallBaseColor; (*colors)[vertptr+3] = wallBaseColor; (*colors)[vertptr+4] = wallColor; (*colors)[vertptr+5] = wallColor; #endif } // Calculate texture coordinates: if (wallSkin) { // Calculate left and right corner V coordinates: double hL = tex_repeats_y ? (f->left.roof - f->left.base).length() : elev->texHeightAdjustedM; double hR = tex_repeats_y ? (f->right.roof - f->right.base).length() : elev->texHeightAdjustedM; // Calculate the texture coordinates at each corner. The structure builder // will have spaced the verts correctly for this to work. float uL = fmod( f->left.offsetX, texWidthM ) / texWidthM; float uR = fmod( f->right.offsetX, texWidthM ) / texWidthM; // Correct for the case in which the rightmost corner is exactly on a // texture boundary. if ( uR < uL || (uL == 0.0 && uR == 0.0)) uR = 1.0f; osg::Vec2f texBaseL( uL, 0.0f ); osg::Vec2f texBaseR( uR, 0.0f ); osg::Vec2f texRoofL( uL, hL/elev->texHeightAdjustedM ); osg::Vec2f texRoofR( uR, hR/elev->texHeightAdjustedM ); texRoofL = bias + osg::componentMultiply(texRoofL, scale); texRoofR = bias + osg::componentMultiply(texRoofR, scale); texBaseL = bias + osg::componentMultiply(texBaseL, scale); texBaseR = bias + osg::componentMultiply(texBaseR, scale); (*tex)[vertptr+0].set( texRoofL.x(), texRoofL.y(), layer ); (*tex)[vertptr+1].set( texBaseL.x(), texBaseL.y(), layer ); (*tex)[vertptr+2].set( texBaseR.x(), texBaseR.y(), layer ); (*tex)[vertptr+3].set( texBaseR.x(), texBaseR.y(), layer ); (*tex)[vertptr+4].set( texRoofR.x(), texRoofR.y(), layer ); (*tex)[vertptr+5].set( texRoofL.x(), texRoofL.y(), layer ); } for(int i=0; i<6; ++i) de->addElement( vertptr+i ); } } // generate per-vertex normals, altering the geometry as necessary to avoid // smoothing around sharp corners // TODO: reconsider this, given the new Structure setup // it won't actual smooth corners since we don't have shared edges. osgUtil::SmoothingVisitor::smooth( *walls, osg::DegreesToRadians(_wallAngleThresh_deg) ); return madeGeom; }
bool ExtrudeGeometryFilter::buildWallGeometry(const Structure& structure, osg::Geometry* walls, const osg::Vec4& wallColor, const osg::Vec4& wallBaseColor, const SkinResource* wallSkin) { bool madeGeom = true; // 6 verts per face total (3 triangles) unsigned numWallVerts = 6 * structure.getNumPoints(); double texWidthM = wallSkin ? *wallSkin->imageWidth() : 1.0; double texHeightM = wallSkin ? *wallSkin->imageHeight() : 1.0; bool useColor = (!wallSkin || wallSkin->texEnvMode() != osg::TexEnv::DECAL) && !_makeStencilVolume; // Scale and bias: osg::Vec2f scale, bias; float layer; if ( wallSkin ) { bias.set (wallSkin->imageBiasS().get(), wallSkin->imageBiasT().get()); scale.set(wallSkin->imageScaleS().get(), wallSkin->imageScaleT().get()); layer = (float)wallSkin->imageLayer().get(); } // create all the OSG geometry components osg::Vec3Array* verts = new osg::Vec3Array( numWallVerts ); walls->setVertexArray( verts ); osg::Vec3Array* tex = 0L; if ( wallSkin ) { tex = new osg::Vec3Array( numWallVerts ); walls->setTexCoordArray( 0, tex ); } osg::Vec4Array* colors = 0L; if ( useColor ) { colors = new osg::Vec4Array( osg::Array::BIND_PER_VERTEX, numWallVerts ); walls->setColorArray( colors ); } osg::Vec4Array* anchors = 0L; // If GPU clamping is in effect, create clamping attributes. if ( _gpuClamping ) { anchors = new osg::Vec4Array( osg::Array::BIND_PER_VERTEX, numWallVerts ); anchors->setNormalize(false); walls->setVertexAttribArray ( Clamping::AnchorAttrLocation, anchors ); } unsigned vertptr = 0; bool tex_repeats_y = wallSkin && wallSkin->isTiled() == true; bool flatten = _style.has<ExtrusionSymbol>() && _style.get<ExtrusionSymbol>()->flatten() == true; for(Elevations::const_iterator elev = structure.elevations.begin(); elev != structure.elevations.end(); ++elev) { osg::DrawElements* de = numWallVerts > 0xFFFF ? (osg::DrawElements*) new osg::DrawElementsUInt ( GL_TRIANGLES ) : numWallVerts > 0xFF ? (osg::DrawElements*) new osg::DrawElementsUShort( GL_TRIANGLES ) : (osg::DrawElements*) new osg::DrawElementsUByte ( GL_TRIANGLES ); // pre-allocate for speed de->reserveElements( numWallVerts ); walls->addPrimitiveSet( de ); for(Faces::const_iterator f = elev->faces.begin(); f != elev->faces.end(); ++f, vertptr+=6) { // set the 6 wall verts. (*verts)[vertptr+0] = f->left.roof; (*verts)[vertptr+1] = f->left.base; (*verts)[vertptr+2] = f->right.base; (*verts)[vertptr+3] = f->right.base; (*verts)[vertptr+4] = f->right.roof; (*verts)[vertptr+5] = f->left.roof; if ( anchors ) { float x = structure.baseCentroid.x(), y = structure.baseCentroid.y(), vo = structure.verticalOffset; (*anchors)[vertptr+1].set( x, y, vo, Clamping::ClampToGround ); (*anchors)[vertptr+2].set( x, y, vo, Clamping::ClampToGround ); (*anchors)[vertptr+3].set( x, y, vo, Clamping::ClampToGround ); if ( flatten ) { (*anchors)[vertptr+0].set( x, y, vo, Clamping::ClampToAnchor ); (*anchors)[vertptr+4].set( x, y, vo, Clamping::ClampToAnchor ); (*anchors)[vertptr+5].set( x, y, vo, Clamping::ClampToAnchor ); } else { (*anchors)[vertptr+0].set( x, y, vo + f->left.height, Clamping::ClampToGround ); (*anchors)[vertptr+4].set( x, y, vo + f->right.height, Clamping::ClampToGround ); (*anchors)[vertptr+5].set( x, y, vo + f->left.height, Clamping::ClampToGround ); } } // Assign wall polygon colors. if (useColor) { (*colors)[vertptr+0] = wallColor; (*colors)[vertptr+1] = wallBaseColor; (*colors)[vertptr+2] = wallBaseColor; (*colors)[vertptr+3] = wallBaseColor; (*colors)[vertptr+4] = wallColor; (*colors)[vertptr+5] = wallColor; } // Calculate texture coordinates: if (wallSkin) { // Calculate left and right corner V coordinates: double hL = tex_repeats_y ? (f->left.roof - f->left.base).length() : elev->texHeightAdjustedM; double hR = tex_repeats_y ? (f->right.roof - f->right.base).length() : elev->texHeightAdjustedM; // Calculate the texture coordinates at each corner. The structure builder // will have spaced the verts correctly for this to work. float uL = fmod( f->left.offsetX, texWidthM ) / texWidthM; float uR = fmod( f->right.offsetX, texWidthM ) / texWidthM; // Correct for the case in which the rightmost corner is exactly on a // texture boundary. if ( uR < uL || (uL == 0.0 && uR == 0.0)) uR = 1.0f; osg::Vec2f texBaseL( uL, 0.0f ); osg::Vec2f texBaseR( uR, 0.0f ); osg::Vec2f texRoofL( uL, hL/elev->texHeightAdjustedM ); osg::Vec2f texRoofR( uR, hR/elev->texHeightAdjustedM ); texRoofL = bias + osg::componentMultiply(texRoofL, scale); texRoofR = bias + osg::componentMultiply(texRoofR, scale); texBaseL = bias + osg::componentMultiply(texBaseL, scale); texBaseR = bias + osg::componentMultiply(texBaseR, scale); (*tex)[vertptr+0].set( texRoofL.x(), texRoofL.y(), layer ); (*tex)[vertptr+1].set( texBaseL.x(), texBaseL.y(), layer ); (*tex)[vertptr+2].set( texBaseR.x(), texBaseR.y(), layer ); (*tex)[vertptr+3].set( texBaseR.x(), texBaseR.y(), layer ); (*tex)[vertptr+4].set( texRoofR.x(), texRoofR.y(), layer ); (*tex)[vertptr+5].set( texRoofL.x(), texRoofL.y(), layer ); } for(int i=0; i<6; ++i) { de->addElement( vertptr+i ); } } } // generate per-vertex normals, altering the geometry as necessary to avoid // smoothing around sharp corners // TODO: reconsider this, given the new Structure setup // it won't actual smooth corners since we don't have shared edges. osgUtil::SmoothingVisitor::smooth( *walls, osg::DegreesToRadians(_wallAngleThresh_deg) ); return madeGeom; }