/******************************* * For the binder construction * *******************************/ void binder_geo_nappe (GEO *Generic, INDEX *Index, VECTOR *Min, VECTOR *Max, void **Info) { GEO_NAPPE *Geo; FCT *Fct; PNT *Pnt; Geo = (GEO_NAPPE *) Generic; if (*Index == 0) *Index = Geo->NbrFct; *Index -= 1; Fct = Geo->TabFct + *Index; *Info = Fct; Min->x = Min->y = Min->z = INFINITY; Max->x = Max->y = Max->z = -INFINITY; Pnt = Geo->TabPnt + Fct->i; VEC_MIN (*Min, Pnt->Point); VEC_MAX (*Max, Pnt->Point); Pnt = Geo->TabPnt + Fct->j; VEC_MIN (*Min, Pnt->Point); VEC_MAX (*Max, Pnt->Point); Pnt = Geo->TabPnt + Fct->k; VEC_MIN (*Min, Pnt->Point); VEC_MAX (*Max, Pnt->Point); Pnt = Geo->TabPnt + Fct->l; VEC_MIN (*Min, Pnt->Point); VEC_MAX (*Max, Pnt->Point); }
/***************************************** * Read nappe characterization in a file * *****************************************/ GEO * file_geo_nappe (BYTE Type, FILE *File) { GEO_NAPPE *Geo; PNT *Pnt, *PntA, *PntB, *PntC, *PntD; FCT *Fct; VECTOR U, V; REAL Real; INDEX Index; INIT_MEM (Geo, 1, GEO_NAPPE); Geo->Type = Type; GET_INDEX (Geo->NbrPnt); INIT_MEM (Geo->TabPnt, Geo->NbrPnt, PNT); GET_INDEX (Geo->NbrFct); INIT_MEM (Geo->TabFct, Geo->NbrFct, FCT); Geo->Min.x = Geo->Min.y = Geo->Min.z = INFINITY; Geo->Max.x = Geo->Max.y = Geo->Max.z = -INFINITY; for (Index = 0, Pnt = Geo->TabPnt; Index < Geo->NbrPnt; Index++, Pnt++) { GET_VECTOR (Pnt->Point); VEC_MIN (Geo->Min, Pnt->Point); VEC_MAX (Geo->Max, Pnt->Point); } for (Index = 0, Fct = Geo->TabFct; Index < Geo->NbrFct; Index++, Fct++) { if (fscanf (File, " ( %d %d %d %d )", &Fct->i, &Fct->j, &Fct->k, &Fct->l) < 4) return (FALSE); Fct->NumFct = Index; PntA = Geo->TabPnt + Fct->i; PntB = Geo->TabPnt + Fct->j; PntC = Geo->TabPnt + Fct->k; PntD = Geo->TabPnt + Fct->l; VEC_SUB (U, PntC->Point, PntA->Point); VEC_SUB (V, PntD->Point, PntB->Point); VEC_CROSS (Fct->Normal, U, V); VEC_UNIT (Fct->Normal, Real); VEC_INC (PntA->Normal, Fct->Normal); VEC_INC (PntB->Normal, Fct->Normal); VEC_INC (PntC->Normal, Fct->Normal); VEC_INC (PntD->Normal, Fct->Normal); } for (Index = 0, Pnt = Geo->TabPnt; Index < Geo->NbrPnt; Index++, Pnt++) VEC_UNIT (Pnt->Normal, Real); return ((GEO *) Geo); }
inline void linesystem_ExtendBounds(LineSystem *pSystem, LTVector *pPt) { VEC_MIN(pSystem->m_MinPos, pSystem->m_MinPos, *pPt); VEC_MAX(pSystem->m_MaxPos, pSystem->m_MaxPos, *pPt); }
// Sets up pParams. // pPos and pRotation are the view position and orientation. // pRect is the rectangle on the screen that the viewing window maps into. // pScale is an extra scale that scales all the coordinates up. bool d3d_InitFrustum2(ViewParams *pParams, ViewBoxDef *pViewBox, float screenMinX, float screenMinY, float screenMaxX, float screenMaxY, const LTMatrix *pMat, const LTVector& vScale, ViewParams::ERenderMode eMode) { LTMatrix mTempWorld, mRotation, mScale; LTMatrix mFOVScale, mBackTransform; LTMatrix mDevice, mBackTranslate; float leftX, rightX, topY, bottomY, normalZ; uint32 i; LTVector forwardVec, zPlanePos, vTrans; LTMatrix mProjectionTransform; //mUnit, mPerspective; pParams->m_mIdentity.Identity(); pParams->m_mInvView = *pMat; // Here's how the viewing works: // The world to camera transformation rotates and translates // the world into camera space. // The camera to clip transformation just scales the sides so the // field of view is 90 degrees (faster to clip in). // Clipping takes place on NEARZ and g_ViewParams.m_FarZ. // In terms of Z buffer calculations, the maximum Z is MAX_FARZ (that way, // when the farZ clipping plane is changed, sz and rhw stay the same). /////// Copy stuff in and setup view limits. memcpy(&pParams->m_ViewBox, pViewBox, sizeof(pParams->m_ViewBox)); pMat->GetTranslation(pParams->m_Pos); pParams->m_FarZ = pViewBox->m_FarZ; if(pParams->m_FarZ < 3.0f) pParams->m_FarZ = 3.0f; if(pParams->m_FarZ > MAX_FARZ) pParams->m_FarZ = MAX_FARZ; pParams->m_NearZ = pViewBox->m_NearZ; pParams->m_Rect.left = (int)RoundFloatToInt(screenMinX); pParams->m_Rect.top = (int)RoundFloatToInt(screenMinY); pParams->m_Rect.right = (int)RoundFloatToInt(screenMaxX); pParams->m_Rect.bottom = (int)RoundFloatToInt(screenMaxY); /////// Setup all the matrices. // Setup the rotation and translation transforms. mRotation = *pMat; mRotation.SetTranslation(0.0f, 0.0f, 0.0f); Mat_GetBasisVectors(&mRotation, &pParams->m_Right, &pParams->m_Up, &pParams->m_Forward); // We want to transpose (ie: when we're looking left, rotate the world to the right..) MatTranspose3x3(&mRotation); mBackTranslate.Init( 1, 0, 0, -pParams->m_Pos.x, 0, 1, 0, -pParams->m_Pos.y, 0, 0, 1, -pParams->m_Pos.z, 0, 0, 0, 1); MatMul(&mTempWorld, &mRotation, &mBackTranslate); // Scale it to get the full world transform. mScale.Init( vScale.x, 0, 0, 0, 0, vScale.y, 0, 0, 0, 0, vScale.z, 0, 0, 0, 0, 1); MatMul(&pParams->m_mView, &mScale, &mTempWorld); // Shear so the center of projection is (0,0,COP.z) LTMatrix mShear; mShear.Init( 1.0f, 0.0f, -pViewBox->m_COP.x/pViewBox->m_COP.z, 0.0f, 0.0f, 1.0f, -pViewBox->m_COP.y/pViewBox->m_COP.z, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); // Figure out X and Y scale to get frustum into unit slopes. float fFovXScale = pViewBox->m_COP.z / pViewBox->m_WindowSize[0]; float fFovYScale = pViewBox->m_COP.z / pViewBox->m_WindowSize[1]; // Squash the sides to 45 degree angles. mFOVScale.Init( fFovXScale, 0.0f, 0.0f, 0.0f, 0.0f, fFovYScale, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); // Setup the projection transform. d3d_SetupPerspectiveMatrix(&mProjectionTransform, pViewBox->m_NearZ, pParams->m_FarZ); // Setup the projection space (-1<x<1) to device space transformation. pParams->m_fScreenWidth = (screenMaxX - screenMinX); pParams->m_fScreenHeight = (screenMaxY - screenMinY); // Setup the device transform. It subtracts 0.4 to account for the FP's tendency // to slip above and below 0.5. Mat_Identity(&mDevice); mDevice.m[0][0] = pParams->m_fScreenWidth * 0.5f - 0.0001f; mDevice.m[0][3] = screenMinX + pParams->m_fScreenWidth * 0.5f; mDevice.m[1][1] = -(pParams->m_fScreenHeight * 0.5f - 0.0001f); mDevice.m[1][3] = screenMinY + pParams->m_fScreenHeight * 0.5f; // Precalculate useful matrices. pParams->m_DeviceTimesProjection = mDevice * mProjectionTransform; pParams->m_FullTransform = pParams->m_DeviceTimesProjection * mFOVScale * mShear * pParams->m_mView; pParams->m_mProjection = mProjectionTransform * mFOVScale * mShear; /////// Setup the view frustum points in camera space. float xNearZ, yNearZ, xFarZ, yFarZ; xNearZ = (pParams->m_NearZ * pViewBox->m_WindowSize[0]) / pViewBox->m_COP.z; yNearZ = (pParams->m_NearZ * pViewBox->m_WindowSize[1]) / pViewBox->m_COP.z; xFarZ = (pParams->m_FarZ * pViewBox->m_WindowSize[0]) / pViewBox->m_COP.z; yFarZ = (pParams->m_FarZ * pViewBox->m_WindowSize[1]) / pViewBox->m_COP.z; pParams->m_ViewPoints[0].Init(-xNearZ, yNearZ, pParams->m_NearZ); // Near Top Left pParams->m_ViewPoints[1].Init(xNearZ, yNearZ, pParams->m_NearZ); // Near Top Right pParams->m_ViewPoints[2].Init(-xNearZ, -yNearZ, pParams->m_NearZ); // Near Bottom Left pParams->m_ViewPoints[3].Init(xNearZ, -yNearZ, pParams->m_NearZ); // Near Bottom Right pParams->m_ViewPoints[4].Init(-xFarZ, yFarZ, pParams->m_FarZ); // Far Top Left pParams->m_ViewPoints[5].Init(xFarZ, yFarZ, pParams->m_FarZ); // Far Top Right pParams->m_ViewPoints[6].Init(-xFarZ, -yFarZ, pParams->m_FarZ); // Far Bottom Left pParams->m_ViewPoints[7].Init(xFarZ, -yFarZ, pParams->m_FarZ); // Far Bottom Right // Transform them into world space. for(i=0; i < 8; i++) { MatVMul_InPlace_Transposed3x3(&pParams->m_mView, &pParams->m_ViewPoints[i]); pParams->m_ViewPoints[i] += pParams->m_Pos; } // Get the AABB of the view frustum pParams->m_ViewAABBMin = pParams->m_ViewPoints[0]; pParams->m_ViewAABBMax = pParams->m_ViewPoints[0]; for(i=1; i < 8; i++) { VEC_MIN(pParams->m_ViewAABBMin, pParams->m_ViewAABBMin, pParams->m_ViewPoints[i]); VEC_MAX(pParams->m_ViewAABBMax, pParams->m_ViewAABBMax, pParams->m_ViewPoints[i]); } /////// Setup the camera-space clipping planes. leftX = pViewBox->m_COP.x - pViewBox->m_WindowSize[0]; rightX = pViewBox->m_COP.x + pViewBox->m_WindowSize[0]; topY = pViewBox->m_COP.y + pViewBox->m_WindowSize[1]; bottomY = pViewBox->m_COP.y - pViewBox->m_WindowSize[1]; normalZ = pViewBox->m_COP.z; LTPlane CSClipPlanes[NUM_CLIPPLANES]; CSClipPlanes[CPLANE_NEAR_INDEX].m_Normal.Init(0.0f, 0.0f, 1.0f); // Near Z CSClipPlanes[CPLANE_NEAR_INDEX].m_Dist = 1.0f; CSClipPlanes[CPLANE_FAR_INDEX].m_Normal.Init(0.0f, 0.0f, -1.0f); // Far Z CSClipPlanes[CPLANE_FAR_INDEX].m_Dist = -pParams->m_FarZ; CSClipPlanes[CPLANE_LEFT_INDEX].m_Normal.Init(normalZ, 0.0f, -leftX); // Left CSClipPlanes[CPLANE_RIGHT_INDEX].m_Normal.Init(-normalZ, 0.0f, rightX); // Right CSClipPlanes[CPLANE_TOP_INDEX].m_Normal.Init(0.0f, -normalZ, topY); // Top CSClipPlanes[CPLANE_BOTTOM_INDEX].m_Normal.Init(0.0f, normalZ, -bottomY); // Bottom CSClipPlanes[CPLANE_LEFT_INDEX].m_Normal.Norm(); CSClipPlanes[CPLANE_TOP_INDEX].m_Normal.Norm(); CSClipPlanes[CPLANE_RIGHT_INDEX].m_Normal.Norm(); CSClipPlanes[CPLANE_BOTTOM_INDEX].m_Normal.Norm(); CSClipPlanes[CPLANE_LEFT_INDEX].m_Dist = CSClipPlanes[CPLANE_RIGHT_INDEX].m_Dist = 0.0f; CSClipPlanes[CPLANE_TOP_INDEX].m_Dist = CSClipPlanes[CPLANE_BOTTOM_INDEX].m_Dist = 0.0f; // Now setup the world space clipping planes. mBackTransform = pParams->m_mView; MatTranspose3x3(&mBackTransform); for(i=0; i < NUM_CLIPPLANES; i++) { if(i != CPLANE_NEAR_INDEX && i != CPLANE_FAR_INDEX) { MatVMul_3x3(&pParams->m_ClipPlanes[i].m_Normal, &mBackTransform, &CSClipPlanes[i].m_Normal); pParams->m_ClipPlanes[i].m_Dist = pParams->m_ClipPlanes[i].m_Normal.Dot(pParams->m_Pos); } } // The Z planes need to be handled a little differently. forwardVec.Init(mRotation.m[2][0], mRotation.m[2][1], mRotation.m[2][2]); zPlanePos = forwardVec * pViewBox->m_NearZ; zPlanePos += pParams->m_Pos; MatVMul_3x3(&pParams->m_ClipPlanes[CPLANE_NEAR_INDEX].m_Normal, &mBackTransform, &CSClipPlanes[CPLANE_NEAR_INDEX].m_Normal); pParams->m_ClipPlanes[CPLANE_NEAR_INDEX].m_Dist = pParams->m_ClipPlanes[CPLANE_NEAR_INDEX].m_Normal.Dot(zPlanePos); zPlanePos = forwardVec * pParams->m_FarZ; zPlanePos += pParams->m_Pos; MatVMul_3x3(&pParams->m_ClipPlanes[CPLANE_FAR_INDEX].m_Normal, &mBackTransform, &CSClipPlanes[CPLANE_FAR_INDEX].m_Normal); pParams->m_ClipPlanes[CPLANE_FAR_INDEX].m_Dist = pParams->m_ClipPlanes[CPLANE_FAR_INDEX].m_Normal.Dot(zPlanePos); // Remember AABB Corners the planes are pointing at for (uint32 nPlaneLoop = 0; nPlaneLoop < NUM_CLIPPLANES; ++nPlaneLoop) { pParams->m_AABBPlaneCorner[nPlaneLoop] = GetAABBPlaneCorner(pParams->m_ClipPlanes[nPlaneLoop].m_Normal); } // Default the world transform to identity pParams->m_mInvWorld.Identity(); //setup the environment mapping info pParams->m_mWorldEnvMap.SetBasisVectors(&pParams->m_Right, &pParams->m_Up, &pParams->m_Forward); //turn off glowing by default pParams->m_eRenderMode = eMode; d3d_SetupSkyStuff(g_pSceneDesc->m_SkyDef, pParams); return true; }
static bool RecursivelyBuildBSP(CLightBSPNode** ppNode, PrePolyArray& PolyList, CLightBSPPoly** ppBSPPolyList) { //sanity check ASSERT(ppNode); ASSERT(PolyList.GetSize() > 0); //number of polies that lie on the plane uint32 nNumLieOn, nFront, nBack; //first off, find the best splitting plane uint32 nSplitPlane = FindBestSplitPlane(PolyList, nNumLieOn, nFront, nBack); //allocate the new node *ppNode = AllocateBSPNode(nNumLieOn); //check for memory failure if(*ppNode == NULL) return false; //setup the node (*ppNode)->m_vPlaneNorm = PolyList[nSplitPlane]->Normal(); (*ppNode)->m_fPlaneDist = PolyList[nSplitPlane]->Dist(); //create the front, back, and on arrays PrePolyArray Front, Back, On; Front.SetSize(nFront); Back.SetSize(nBack); On.SetSize(nNumLieOn); //now fill up all the lists PVector vNormal = PolyList[nSplitPlane]->Normal(); float fDist = PolyList[nSplitPlane]->Dist(); //index to the coplanar poly offset uint32 nPolyIndex = 0; //indices for the lists uint32 nFrontIndex = 0; uint32 nBackIndex = 0; uint32 nOnIndex = 0; uint32 nType; //now need to count up the split information for(uint32 nTestPoly = 0; nTestPoly < PolyList.GetSize(); nTestPoly++) { if(nTestPoly == nSplitPlane) { On[nOnIndex++] = PolyList[nTestPoly]; (*ppNode)->m_pPolyList[nPolyIndex++] = ppBSPPolyList[PolyList[nTestPoly]->m_Index]; continue; } nType = ClassifyPoly(vNormal, fDist, PolyList[nTestPoly]); if(nType & PLANE_FRONT) Front[nFrontIndex++] = PolyList[nTestPoly]; if(nType & PLANE_BACK) Back[nBackIndex++] = PolyList[nTestPoly]; if(nType == PLANE_ON) { On[nOnIndex++] = PolyList[nTestPoly]; (*ppNode)->m_pPolyList[nPolyIndex++] = ppBSPPolyList[PolyList[nTestPoly]->m_Index]; } } //sanity check ASSERT(nPolyIndex == (*ppNode)->m_nNumPolies); ASSERT(nFrontIndex == nFront); ASSERT(nBackIndex == nBack); ASSERT(nOnIndex == nNumLieOn); //build up the child lists bool bSuccess = true; if(Front.GetSize() > 0) { bSuccess = RecursivelyBuildBSP(&(*ppNode)->m_pFront, Front, ppBSPPolyList); } if(bSuccess && (Back.GetSize() > 0)) { bSuccess = RecursivelyBuildBSP(&(*ppNode)->m_pBack, Back, ppBSPPolyList); } //see if we need to clean up if(!bSuccess) { FreeBSPNode(*ppNode); *ppNode = NULL; return false; } //we need to update the node's bounding sphere. This is done by running through all //the polygons on the plane and generating a bounding box, finding its center, and then //the maximum distance to the points PVector vMin((PReal)MAX_CREAL, (PReal)MAX_CREAL, (PReal)MAX_CREAL); PVector vMax(-vMin); uint32 nCurrPoly; for(nCurrPoly = 0; nCurrPoly < nNumLieOn; nCurrPoly++) { CPrePoly* pPoly = On[nCurrPoly]; for(uint32 nCurrVert = 0; nCurrVert < pPoly->NumVerts(); nCurrVert++) { VEC_MIN(vMin, vMin, pPoly->Pt(nCurrVert)); VEC_MAX(vMax, vMax, pPoly->Pt(nCurrVert)); } } //found the center (*ppNode)->m_vBSphereCenter = ((vMin + vMax) / 2); //now update the radius (*ppNode)->m_fBSphereRadSqr = 0; PReal fDistSqr; for(nCurrPoly = 0; nCurrPoly < nNumLieOn; nCurrPoly++) { CPrePoly* pPoly = On[nCurrPoly]; for(uint32 nCurrVert = 0; nCurrVert < pPoly->NumVerts(); nCurrVert++) { fDistSqr = (pPoly->Pt(nCurrVert) - (*ppNode)->m_vBSphereCenter).MagSqr(); if(fDistSqr > (*ppNode)->m_fBSphereRadSqr) { (*ppNode)->m_fBSphereRadSqr = fDistSqr; } } } //add some padding to the radius to compensate for inaccuracy (*ppNode)->m_fBSphereRadSqr += NODE_RADIUS_PADDING; return bSuccess; }
static void RecurseAndGrowDims(CWorldNode *pNode, LTVector &vMin, LTVector &vMax, LTMatrix& mTransMat) { //sanity check if(pNode == NULL) { return; } // Grow the dims for this node switch (pNode->GetType()) { case Node_Object : { CBaseEditObj *pObject = pNode->AsObject(); LTVector vCenter; mTransMat.Apply(pObject->GetPos(), vCenter); //always include at least the object center VEC_MIN(vMin, vMin, vCenter); VEC_MAX(vMax, vMax, vCenter); #ifdef DIRECTEDITOR_BUILD //see if there are other dims we need for (uint32 nCurDim = pObject->GetNumDims(); nCurDim > 0; --nCurDim) { LTVector vDims = *pObject->GetDim(nCurDim - 1); LTVector vObjMin = vCenter - vDims; LTVector vObjMax = vCenter + vDims; VEC_MIN(vMin, vMin, vObjMin); VEC_MAX(vMax, vMax, vObjMax); } #endif } break; case Node_Brush: { CEditBrush *pBrush = pNode->AsBrush(); CBoundingBox BBox = pBrush->CalcBoundingBox(); //transform the bounding box LTVector vBoxMin, vBoxMax; mTransMat.Apply(BBox.m_Min, vBoxMin); mTransMat.Apply(BBox.m_Max, vBoxMax); VEC_MIN(vMin, vMin, vBoxMin); VEC_MAX(vMax, vMax, vBoxMax); } break; case Node_PrefabRef: { //create the new transformation matrix LTMatrix mRot; ::gr_SetupMatrixEuler(pNode->GetOr(), mRot.m); LTMatrix mTranslate; mTranslate.Identity(); mTranslate.SetTranslation(pNode->GetPos()); LTMatrix mNewTransMat = mTransMat * mTranslate * mRot; RecurseAndGrowDims((CWorldNode*)((CPrefabRef*)pNode)->GetPrefabTree(), vMin, vMax, mNewTransMat); } break; } // Go through the children GPOS iFinger = pNode->m_Children.GetHeadPosition(); while (iFinger) { CWorldNode *pChild = pNode->m_Children.GetNext(iFinger); RecurseAndGrowDims(pChild, vMin, vMax, mTransMat); } }