// // Look at the sloped edges to see if they meet at a particular point; // if so, set that as the Level's story height. Return true on success. // bool vtLevel::DetermineHeightFromSlopes() { // In order to find a roof point, we need 3 adjacent edges whose // edges intersect. int i, edges = NumEdges(); bool bFoundASolution = false; FPlane *planes = new FPlane[edges]; float fMinHeight = 1E10; for (i = 0; i < edges; i++) { GetEdgePlane(i, planes[i]); } for (i = 0; i < edges; i++) { int i0 = i; int i1 = (i+1)%edges; int i2 = (i+2)%edges; vtEdge *edge0 = m_Edges[i0]; vtEdge *edge1 = m_Edges[i1]; vtEdge *edge2 = m_Edges[i2]; if (edge0->m_iSlope == 90 && edge1->m_iSlope == 90 && edge2->m_iSlope == 90) { // skip this one; 3 vertical edges aren't useful continue; } FPoint3 point; bool valid = PlaneIntersection(planes[i0], planes[i1], planes[i2], point); if (valid) { // take this point as the height of the roof float fHeight = (point.y - m_LocalFootprint[0][0].y); if (fHeight < 0) // shouldn't happen, but just a safety check continue; if (fHeight < fMinHeight) fMinHeight = fHeight; bFoundASolution = true; } } if (bFoundASolution) m_fStoryHeight = fMinHeight; delete [] planes; return bFoundASolution; }
Frustum::Frustum( const SMatrix4x4& matrix ) { // build a view frustum based on the current view & projection matrices... SVector4 column4( matrix._14, matrix._24, matrix._34, matrix._44 ); SVector4 column1( matrix._11, matrix._21, matrix._31, matrix._41 ); SVector4 column2( matrix._12, matrix._22, matrix._32, matrix._42 ); SVector4 column3( matrix._13, matrix._23, matrix._33, matrix._43 ); SVector4 planes[6]; planes[0] = column4 - column1; // left planes[1] = column4 + column1; // right planes[2] = column4 - column2; // bottom planes[3] = column4 + column2; // top planes[4] = column4 - column3; // near planes[5] = column4 + column3; // far int p; for (p=0; p<6; p++) // normalize the planes { float dot = planes[p].x*planes[p].x + planes[p].y*planes[p].y + planes[p].z*planes[p].z; dot = 1.0f / sqrtf(dot); planes[p] = planes[p] * dot; } for (p=0; p<6; p++) camPlanes[p] = SPlane( planes[p].x, planes[p].y, planes[p].z, planes[p].w ); // build a bit-field that will tell us the indices for the nearest and farthest vertices from each plane... for (int i=0; i<6; i++) nVertexLUT[i] = ((planes[i].x<0.f)?1:0) | ((planes[i].y<0.f)?2:0) | ((planes[i].z<0.f)?4:0); for( int i=0; i<8; ++i ) // compute extrema { const SPlane& p0 = (i&1)?camPlanes[4] : camPlanes[5]; const SPlane& p1 = (i&2)?camPlanes[3] : camPlanes[2]; const SPlane& p2 = (i&4)?camPlanes[0] : camPlanes[1]; PlaneIntersection( &pntList[i], p0, p1, p2 ); } }
//----------------------------------------------------------------------------- // Copies the texture coordinate system from pFrom into pTo. Then it rotates // the texture around the edge until it's as close to pTo's normal as possible. //----------------------------------------------------------------------------- void CFaceEditMaterialPage::CopyTCoordSystem( const CMapFace *pFrom, CMapFace *pTo ) { Vector axis[2], vEdge, vEdgePt, vOrigin; Vector vFromPt, vNextFromPt; Vector vToPt, vPrevToPt; Vector vTestTextureNormal, vTextureNormal; VMatrix mEdgeRotation, mOriginRotation, mTranslation; float fAngle, fDot; bool bRotate; float fShift[2]; Vector vProjTexNormal; Vector vProjPolyNormal; // The edge vector lies on both planes. vEdge = pFrom->plane.normal.Cross(pTo->plane.normal); VectorNormalize( vEdge ); // To find a point on the plane, we make a plane from the edge vector and find the intersection // between the three planes (without the third plane, there are an infinite number of solutions). if( PlaneIntersection( VPlane(pFrom->plane.normal, pFrom->plane.dist), VPlane(pTo->plane.normal, pTo->plane.dist), VPlane(vEdge, 0.0f), vEdgePt ) ) { bRotate = true; } else { // Ok, in this case, the planes are parallel so we don't need to rotate around the edge anyway! bRotate = false; } // Copy the texture coordinate system. axis[0] = pFrom->texture.UAxis.AsVector3D(); axis[1] = pFrom->texture.VAxis.AsVector3D(); fShift[0] = pFrom->texture.UAxis[3]; fShift[1] = pFrom->texture.VAxis[3]; vOrigin = axis[0]*fShift[0]*pFrom->texture.scale[0] + axis[1]*fShift[1]*pFrom->texture.scale[1]; vTextureNormal = axis[0].Cross(axis[1]); VectorNormalize(vTextureNormal); if(bRotate) { // Project texture normal and poly normal into the plane of rotation // to get the angle between them. vProjTexNormal = vTextureNormal - vEdge * vEdge.Dot(vTextureNormal); vProjPolyNormal = pTo->plane.normal - vEdge * vEdge.Dot(pTo->plane.normal); VectorNormalize( vProjTexNormal ); VectorNormalize( vProjPolyNormal ); fDot = vProjTexNormal.Dot(vProjPolyNormal); fAngle = (float)(acos(fDot) * (180.0f / M_PI)); if(fDot < 0.0f) fAngle = 180.0f - fAngle; // Ok, rotate them for the final values. mEdgeRotation = SetupMatrixAxisRot(vEdge, fAngle); axis[0] = mEdgeRotation.ApplyRotation(axis[0]); axis[1] = mEdgeRotation.ApplyRotation(axis[1]); // Origin needs translation and rotation to rotate around the edge. mTranslation = SetupMatrixTranslation(vEdgePt); mOriginRotation = ~mTranslation * mEdgeRotation * mTranslation; vOrigin = mOriginRotation * vOrigin; } pTo->texture.UAxis.AsVector3D() = axis[0]; pTo->texture.VAxis.AsVector3D() = axis[1]; pTo->texture.UAxis[3] = axis[0].Dot(vOrigin) / pFrom->texture.scale[0]; pTo->texture.VAxis[3] = axis[1].Dot(vOrigin) / pFrom->texture.scale[1]; pTo->NormalizeTextureShifts(); pTo->texture.scale[0] = pFrom->texture.scale[0]; pTo->texture.scale[1] = pFrom->texture.scale[1]; // rotate is only for UI purposes, it doesn't actually do anything. pTo->texture.rotate = 0.0f; pTo->CalcTextureCoords(); }