// Draw one quad tree node ( draws terrain tile in wireframe mode if leaf node ) static void DrawWireQuadTreeNode(INDEX iqtn) { ASSERT(_ptrTerrain!=NULL); CEntity *pen = _ptrTerrain->tr_penEntity; QuadTreeNode &qtn = _ptrTerrain->tr_aqtnQuadTreeNodes[iqtn]; FLOATmatrix3D &mAbsToView = _aprProjection->pr_ViewerRotationMatrix; FLOATobbox3D obbox = FLOATobbox3D( qtn.qtn_aabbox, (pen->en_plPlacement.pl_PositionVector-_aprProjection->pr_vViewerPosition)*mAbsToView, mAbsToView*pen->en_mRotation); INDEX iFrustumTest = _aprProjection->TestBoxToFrustum(obbox); if(iFrustumTest!=(-1)) { // is this leaf node if(qtn.qtn_iTileIndex != -1) { _ctNodesVis++; // draw terrain tile for this node RenderWireTile(qtn.qtn_iTileIndex); // this node has some children } else { for(INDEX iqc=0;iqc<4;iqc++) { INDEX iChildNode = qtn.qtn_iChild[iqc]; // if child node exists if(iChildNode != -1) { // draw child node DrawWireQuadTreeNode(qtn.qtn_iChild[iqc]); } } } } }
// Create render model structure for rendering an attached model BOOL CModelObject::CreateAttachment( CRenderModel &rmMain, CAttachmentModelObject &amo) { _pfModelProfile.StartTimer( CModelProfile::PTI_CREATEATTACHMENT); _pfModelProfile.IncrementTimerAveragingCounter( CModelProfile::PTI_CREATEATTACHMENT); CRenderModel &rmAttached = *amo.amo_prm; rmAttached.rm_ulFlags = rmMain.rm_ulFlags&(RMF_FOG|RMF_HAZE|RMF_WEAPON) | RMF_ATTACHMENT; // get the position rmMain.rm_pmdModelData->md_aampAttachedPosition.Lock(); const CAttachedModelPosition & = rmMain.rm_pmdModelData->md_aampAttachedPosition[amo.amo_iAttachedPosition]; rmMain.rm_pmdModelData->md_aampAttachedPosition.Unlock(); // copy common values rmAttached.rm_vLightDirection = rmMain.rm_vLightDirection; rmAttached.rm_fDistanceFactor = rmMain.rm_fDistanceFactor; rmAttached.rm_colLight = rmMain.rm_colLight; rmAttached.rm_colAmbient = rmMain.rm_colAmbient; rmAttached.rm_colBlend = rmMain.rm_colBlend; // unpack the reference vertices FLOAT3D vCenter, vFront, vUp; const INDEX iCenter = amp.amp_iCenterVertex; const INDEX iFront = amp.amp_iFrontVertex; const INDEX iUp = amp.amp_iUpVertex; UnpackVertex( rmMain, iCenter, vCenter); UnpackVertex( rmMain, iFront, vFront); UnpackVertex( rmMain, iUp, vUp); // create front and up direction vectors FLOAT3D vY = vUp - vCenter; FLOAT3D vZ = vCenter - vFront; // project center and directions from object to absolute space const FLOATmatrix3D &mO2A = rmMain.rm_mObjectRotation; const FLOAT3D &vO2A = rmMain.rm_vObjectPosition; vCenter = vCenter*mO2A +vO2A; vY = vY *mO2A; vZ = vZ *mO2A; // make a rotation matrix from the direction vectors FLOAT3D vX = vY*vZ; vY = vZ*vX; vX.Normalize(); vY.Normalize(); vZ.Normalize(); FLOATmatrix3D mOrientation; mOrientation(1,1) = vX(1); mOrientation(1,2) = vY(1); mOrientation(1,3) = vZ(1); mOrientation(2,1) = vX(2); mOrientation(2,2) = vY(2); mOrientation(2,3) = vZ(2); mOrientation(3,1) = vX(3); mOrientation(3,2) = vY(3); mOrientation(3,3) = vZ(3); // adjust for relative placement of the attachment FLOAT3D vOffset; FLOATmatrix3D mRelative; MakeRotationMatrixFast( mRelative, amo.amo_plRelative.pl_OrientationAngle); vOffset(1) = amo.amo_plRelative.pl_PositionVector(1) * mo_Stretch(1); vOffset(2) = amo.amo_plRelative.pl_PositionVector(2) * mo_Stretch(2); vOffset(3) = amo.amo_plRelative.pl_PositionVector(3) * mo_Stretch(3); FLOAT3D vO = vCenter + vOffset * mOrientation; mOrientation *= mRelative; // convert absolute to relative orientation rmAttached.SetObjectPlacement( vO, mOrientation); // done here if clipping optimizations are not allowed extern INDEX gap_iOptimizeClipping; if( gap_iOptimizeClipping<1) { gap_iOptimizeClipping = 0; _pfModelProfile.StopTimer( CModelProfile::PTI_CREATEATTACHMENT); return TRUE; } // test attachment to frustum and/or mirror FLOAT3D vHandle; _aprProjection->PreClip( vO, vHandle); CalculateBoundingBox( &amo.amo_moModelObject, rmAttached); // compose view-space bounding box and sphere of an attacment const FLOAT fR = Max( rmAttached.rm_vObjectMinBB.Length(), rmAttached.rm_vObjectMaxBB.Length()); const FLOATobbox3D boxEntity( FLOATaabbox3D(rmAttached.rm_vObjectMinBB, rmAttached.rm_vObjectMaxBB), vHandle, _aprProjection->pr_ViewerRotationMatrix*mOrientation); // frustum test? if( gap_iOptimizeClipping>1) { // test sphere against frustrum INDEX iFrustumTest = _aprProjection->TestSphereToFrustum(vHandle,fR); if( iFrustumTest==0) { // test box if sphere cut one of frustum planes iFrustumTest = _aprProjection->TestBoxToFrustum(boxEntity); } // mark if attachment is fully inside frustum if( iFrustumTest>0) rmAttached.rm_ulFlags |= RMF_INSIDE; else if( iFrustumTest<0) { // if completely outside of frustum // signal skip rendering only if doesn't have any attachments _pfModelProfile.StopTimer( CModelProfile::PTI_CREATEATTACHMENT); return !amo.amo_moModelObject.mo_lhAttachments.IsEmpty(); } } // test sphere against mirror/warp plane (if any) if( _aprProjection->pr_bMirror || _aprProjection->pr_bWarp) { INDEX iMirrorPlaneTest; const FLOAT fPlaneDistance = _aprProjection->pr_plMirrorView.PointDistance(vHandle); if( fPlaneDistance < -fR) iMirrorPlaneTest = -1; else if( fPlaneDistance > +fR) iMirrorPlaneTest = +1; else { // test box if sphere cut mirror plane iMirrorPlaneTest = boxEntity.TestAgainstPlane(_aprProjection->pr_plMirrorView); } // mark if attachment is fully inside mirror if( iMirrorPlaneTest>0) rmAttached.rm_ulFlags |= RMF_INMIRROR; else if( iMirrorPlaneTest<0) { // if completely outside mirror // signal skip rendering only if doesn't have any attachments _pfModelProfile.StopTimer( CModelProfile::PTI_CREATEATTACHMENT); return !amo.amo_moModelObject.mo_lhAttachments.IsEmpty(); } } // all done _pfModelProfile.StopTimer( CModelProfile::PTI_CREATEATTACHMENT); return TRUE; }