STDMETHODIMP CVectorObject::get_Rotation(float *pfTheta) { D3DVECTOR rlvPreDef, rlvDir; D3DVALUE valCosTheta; // The pre-defined angle. rlvPreDef.x = 0.0F; rlvPreDef.y = 0.0F; rlvPreDef.z = 1.0F; // Make a D3DVECTOR from this vector. rlvDir.x = m_x; rlvDir.y = m_y; rlvDir.z = m_z; D3DRMVectorNormalize(&rlvDir); // First need angle between the pre-defined angle and rlvDir. valCosTheta = D3DRMVectorDotProduct(&rlvPreDef, &rlvDir); *pfTheta = (D3DVALUE)acos(valCosTheta); // This will always be the acute angle. Since rotation will always be in positive direction we must // give correct angle (possibly obtuse) for that direction. if (rlvDir.x < 0.0F) { // Acute angle will not work, need obtuse angle. *pfTheta = (2*PI) - *pfTheta; } return S_OK; }
/* Returns a random unit vector */ LPD3DVECTOR WINAPI D3DRMVectorRandom(LPD3DVECTOR d) { d->u1.x = rand(); d->u2.y = rand(); d->u3.z = rand(); D3DRMVectorNormalize(d); return d; }
/* Rotation of a vector */ LPD3DVECTOR WINAPI D3DRMVectorRotate(LPD3DVECTOR r, LPD3DVECTOR v, LPD3DVECTOR axis, D3DVALUE theta) { D3DRMQUATERNION quaternion1, quaternion2, quaternion3; D3DVECTOR norm; quaternion1.s = cos(theta * 0.5f); quaternion2.s = cos(theta * 0.5f); norm = *D3DRMVectorNormalize(axis); D3DRMVectorScale(&quaternion1.v, &norm, sin(theta * 0.5f)); D3DRMVectorScale(&quaternion2.v, &norm, -sin(theta * 0.5f)); quaternion3.s = 0.0; quaternion3.v = *v; D3DRMQuaternionMultiply(&quaternion1, &quaternion1, &quaternion3); D3DRMQuaternionMultiply(&quaternion1, &quaternion1, &quaternion2); *r = *D3DRMVectorNormalize(&quaternion1.v); return r; }
HRESULT CVWScale3DTool::SetupEnvironment() { HRESULT hr = S_OK; IThing* pGlobal = NULL; VARIANT_BOOL vbLock; D3DVECTOR tmpVec, upVec; hr = m_pWorld->get_Global(&pGlobal); if(FAILED(hr)) goto EXIT_FAIL; m_nAxisLock = 0; pGlobal->get_BOOL(bstrXAxisLocked, &vbLock); if(FAILED(hr)) goto EXIT_FAIL; if (vbLock) m_nAxisLock |= X_LOCK; pGlobal->get_BOOL(bstrYAxisLocked, &vbLock); if(FAILED(hr)) goto EXIT_FAIL; if (vbLock) m_nAxisLock |= Y_LOCK; pGlobal->get_BOOL(bstrZAxisLocked, &vbLock); if(FAILED(hr)) goto EXIT_FAIL; if (vbLock) m_nAxisLock |= Z_LOCK; pGlobal->get_BOOL(bstrGravity, &m_bGravity); if(FAILED(hr)) goto EXIT_FAIL; hr = m_pRMCameraFrame->GetOrientation(NULL, &tmpVec, &upVec); if(FAILED(hr)) goto EXIT_FAIL; D3DRMVectorNormalize(&upVec); //Figure out which editing mode we're in. if (upVec.y == 0.0f) m_nCameraMode = TOP; else m_nCameraMode = PERSPECTIVE; EXIT_FAIL: SAFERELEASE(pGlobal); return hr; }
// Calculate the normals for all the vertices of the patches of land. void BoidsLand::gouraudShading( ) { // Local buffer for storing the current patches details. D3DRMVERTEX patchVertices[ 6 ]; D3DVECTOR averageNormal; int faces; // Iterate through the patches of land on the landscape. for ( int row = 0; row < LAND_Z_SIZE; row++ ) { for ( int col = 0; col < LAND_X_SIZE; col++ ) { // Get the current state of the current vertex. landMesh -> GetVertices( patchGroups[ 0 ][ row ][ col ], 0, 6, patchVertices ); // Recalculate the normals from vertices 0 & 3. // Find the average of the face normals surrounding the vertex. averageNormal.x = 0; averageNormal.y = 0; averageNormal.z = 0; faces = 0; // Working round in a clockwise direction - // - starting from the current face. D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col ][ 1 ] ); D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col ][ 0 ] ); faces += 2; if ( row > 0 ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row - 1 ][ col ][ 0 ] ); faces++; } if ( row > 0 && col > 0 ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row - 1 ][ col - 1 ][ 1 ] ); D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row - 1 ][ col - 1 ][ 0 ] ); faces += 2; } if ( col > 0 ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col - 1 ][ 1 ] ); faces++; } averageNormal.x /= faces; averageNormal.y /= faces; averageNormal.z /= faces; // Normalise the resultant vector. D3DRMVectorNormalize( &averageNormal ); // Update the normal of vertex 0. patchVertices[ 0 ].normal = averageNormal; // Update the normal of vertex 3. patchVertices[ 3 ].normal = averageNormal; // Recalculate the normal from vertex 1. // Find the average of the face normals surrounding the vertex. averageNormal.x = 0; averageNormal.y = 0; averageNormal.z = 0; faces = 0; // Working round in a clockwise direction - // - starting from the current face. D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col ][ 0 ] ); faces++; if ( col > 0 ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col - 1 ][ 1 ] ); D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col - 1 ][ 0 ] ); faces += 2; } if ( col > 0 && ( ( row + 1 ) < LAND_Z_SIZE ) ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row + 1 ][ col - 1 ][ 1 ] ); faces++; } if ( ( row + 1 ) < LAND_Z_SIZE ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row + 1 ][ col ][ 0 ] ); D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row + 1 ][ col ][ 1 ] ); faces += 2; } averageNormal.x /= faces; averageNormal.y /= faces; averageNormal.z /= faces; // Normalise the resultant vector. D3DRMVectorNormalize( &averageNormal ); // Update the normal of vertex 1. patchVertices[ 1 ].normal = averageNormal; // Recalculate the normals from vertices 2 & 4. // Find the average of the face normals surrounding the vertex. averageNormal.x = 0; averageNormal.y = 0; averageNormal.z = 0; faces = 0; // Working round in a clockwise direction - // - starting from the current face. D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col ][ 1 ] ); D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col ][ 0 ] ); faces += 2; if ( ( row + 1 ) < LAND_Z_SIZE ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row + 1 ][ col ][ 1 ] ); faces++; } if ( ( row + 1 ) < LAND_Z_SIZE && ( col + 1 ) < LAND_X_SIZE ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row + 1 ][ col + 1 ][ 0 ] ); D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row + 1 ][ col + 1 ][ 1 ] ); faces += 2; } if ( ( col + 1 ) < LAND_X_SIZE ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col + 1 ][ 0 ] ); faces++; } averageNormal.x /= faces; averageNormal.y /= faces; averageNormal.z /= faces; // Normalise the resultant vector. D3DRMVectorNormalize( &averageNormal ); // Update the normal of vertex 2. patchVertices[ 2 ].normal = averageNormal; // Update the normal of vertex 4. patchVertices[ 4 ].normal = averageNormal; // Recalculate the normal from vertex 5. // Find the average of the face normals surrounding the vertex. averageNormal.x = 0; averageNormal.y = 0; averageNormal.z = 0; faces = 0; // Working round in a clockwise direction - //- starting from the current face. D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col ][ 1 ] ); faces++; if ( ( col + 1 ) < LAND_X_SIZE ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col + 1 ][ 0 ] ); D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row ][ col + 1 ][ 1 ] ); faces += 2; } if ( row > 0 && ( ( col + 1 ) < LAND_X_SIZE ) ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row - 1 ][ col + 1 ][ 0 ] ); faces++; } if ( row > 0 ) { D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row - 1 ][ col ][ 1 ] ); D3DRMVectorAdd( &averageNormal, &averageNormal, &patchFaceNormals[ row - 1 ][ col ][ 0 ] ); faces += 2; } averageNormal.x /= faces; averageNormal.y /= faces; averageNormal.z /= faces; // Normalise the resultant vector. D3DRMVectorNormalize( &averageNormal ); // Update the normal of vertex 5. patchVertices[ 5 ].normal = averageNormal; // Store the state of the current vertex. landMesh -> SetVertices( patchGroups[ 0 ][ row ][ col ], 0, 6, patchVertices ); } } }
// Calculate the normals for all the face of the patches of land. void BoidsLand::towerFlatShading( int side, D3DRMVERTEX towerVertices[ ] ) { // Calculate the normals for the triangular faces. // First make references to the values to simpify the code. D3DVALUE &x1 = towerVertices[ 0 ].position.x; D3DVALUE &x2 = towerVertices[ 1 ].position.x; D3DVALUE &x3 = towerVertices[ 2 ].position.x; D3DVALUE &y1 = towerVertices[ 0 ].position.y; D3DVALUE &y2 = towerVertices[ 1 ].position.y; D3DVALUE &y3 = towerVertices[ 2 ].position.y; D3DVALUE &z1 = towerVertices[ 0 ].position.z; D3DVALUE &z2 = towerVertices[ 1 ].position.z; D3DVALUE &z3 = towerVertices[ 2 ].position.z; D3DVALUE &x4 = towerVertices[ 3 ].position.x; D3DVALUE &x5 = towerVertices[ 4 ].position.x; D3DVALUE &x6 = towerVertices[ 5 ].position.x; D3DVALUE &y4 = towerVertices[ 3 ].position.y; D3DVALUE &y5 = towerVertices[ 4 ].position.y; D3DVALUE &y6 = towerVertices[ 5 ].position.y; D3DVALUE &z4 = towerVertices[ 3 ].position.z; D3DVALUE &z5 = towerVertices[ 4 ].position.z; D3DVALUE &z6 = towerVertices[ 5 ].position.z; // Produce two vectors from the first triangle. D3DVECTOR v1, v2, v3; v1.x = x3 - x2; v1.y = y3 - y2; v1.z = z3 - z2; v2.x = x1 - x3; v2.y = y1 - y3; v2.z = z1 - z3; // Find the cross product of the two vectors. D3DRMVectorCrossProduct( &v3, &v1, &v2 ); // Normalise the resultant vector. D3DRMVectorNormalize( &v3 ); // Set the normals of the first triangular face. towerFaceNormals[ side ][ 0 ] = v3; // Produce two vectors from the second triangle. v1.x = x6 - x5; v1.y = y6 - y5; v1.z = z6 - z5; v2.x = x4 - x6; v2.y = y4 - y6; v2.z = z4 - z6; // Find the cross product of the two vectors. D3DRMVectorCrossProduct( &v3, &v1, &v2 ); // Normalise the resultant vector. D3DRMVectorNormalize( &v3 ); // Set the normals of the second triangular face. towerFaceNormals[ side ][ 1 ] = v3; // Set the normals for the trianglar faces for flat shading. // First triangle. towerVertices[ 0 ].normal = towerFaceNormals[ side ][ 0 ]; towerVertices[ 1 ].normal = towerFaceNormals[ side ][ 0 ]; towerVertices[ 2 ].normal = towerFaceNormals[ side ][ 0 ]; // Second triangle. towerVertices[ 3 ].normal = towerFaceNormals[ side ][ 1 ]; towerVertices[ 4 ].normal = towerFaceNormals[ side ][ 1 ]; towerVertices[ 5 ].normal = towerFaceNormals[ side ][ 1 ]; }
/* Return a unit quaternion that represents a rotation of an angle around an axis */ LPD3DRMQUATERNION WINAPI D3DRMQuaternionFromRotation(LPD3DRMQUATERNION q, LPD3DVECTOR v, D3DVALUE theta) { q->s = cos(theta/2.0); D3DRMVectorScale(&q->v, D3DRMVectorNormalize(v), sin(theta/2.0)); return q; }
HRESULT CVWScale3DTool::ScaleSelectedObjects( float flDeltaX, float flDeltaY ) { CTranslate3DObject * pCTrans = NULL; IDirect3DRMFrame *pRMObjFrame = NULL; IDirect3DRMFrame *pRMParentFrame = NULL; IDirect3DRMFrame *pRMTmpFrame = NULL; D3DVECTOR axis; IVWFrame * pScene = NULL; BOOL bXAxisLocked, bYAxisLocked, bZAxisLocked; DWORD dwTimeNow; CComBSTR bstr1, bstr2, bstr3; CString tmpStr; static DWORD dwTime = - 1; HRESULT hr = S_OK; POSITION pos; CString szTmp; D3DVECTOR vecDelta, initialPos; IVector* vecPtr = NULL, *vecDestPtr = NULL; float fRot; float fX, fY, fZ, fTmp; D3DVECTOR vecCameraPos, vecObjToCam; if (IsPressed('S')) { flDeltaX *= SLOWKEY_SLOWFACTOR; flDeltaY *= SLOWKEY_SLOWFACTOR; } bXAxisLocked = m_nAxisLock & X_LOCK; bYAxisLocked = m_nAxisLock & Y_LOCK; bZAxisLocked = m_nAxisLock & Z_LOCK; if (m_nCameraMode == TOP) { flDeltaX /= 64.0f; flDeltaY /= 64.0f; } if (IsPressed('X')) { if (m_nCameraMode == TOP) { vecDelta.x = -flDeltaX / 4.0f; vecDelta.y = 0.0f; vecDelta.z = 0.0f; } else { vecDelta.x = -flDeltaX / 32.0f; vecDelta.y = 0.0f; vecDelta.z = 0.0f; } } else if (IsPressed('Y')) { if (m_nCameraMode == TOP) { vecDelta.x = 0.0; vecDelta.y = 0.0f; vecDelta.z = flDeltaY / 4.0f; } else { vecDelta.x = 0.0; vecDelta.y = flDeltaY / 32.0f; vecDelta.z = 0.0f; } } else if (IsPressed('Z')) { if (m_nCameraMode == TOP) { vecDelta.x = 0.0; vecDelta.y = flDeltaY / 4.0f; vecDelta.z = 0.0f; } else { vecDelta.x = 0.0; vecDelta.y = 0.0f; vecDelta.z = flDeltaY / 32.0f; } } else { if (m_nCameraMode == TOP) { vecDelta.x = (bXAxisLocked ? 0.0f : -flDeltaX / 4.0f); vecDelta.y = 0.0f; vecDelta.z = (bZAxisLocked ? 0.0f : flDeltaY / 4.0f); } else { vecDelta.x = (bXAxisLocked ? 0.0f : flDeltaX / 32.0f); vecDelta.y = 0.0f; vecDelta.z = (bZAxisLocked ? 0.0f : flDeltaY / 32.0f); //0.0f; //(bZAxisLocked ? 0.0f : flDeltaX / 32.0f); } } hr = m_pRMCameraFrame->GetPosition(NULL, &vecCameraPos); if (FAILED(hr)) goto EXIT_FAIL; hr = CoCreateInstance(CLSID_Vector, NULL, CLSCTX_INPROC_SERVER, IID_IVector, (LPVOID*)&vecPtr); if (FAILED(hr)) goto EXIT_FAIL; hr = CoCreateInstance(CLSID_Vector, NULL, CLSCTX_INPROC_SERVER, IID_IVector, (LPVOID*)&vecDestPtr); if (FAILED(hr)) goto EXIT_FAIL; for( pos = m_TransformList.GetHeadPosition(); pos != NULL; ) { pCTrans = m_TransformList.GetNext( pos ); if(pCTrans != NULL && pCTrans->m_pTrans != NULL) { hr = pCTrans->m_pVWFrame->get_Frame3D(&pRMObjFrame); if (FAILED(hr) || (!pRMObjFrame)) goto EXIT_FAIL; hr = pRMObjFrame->GetParent(&pRMParentFrame); if (FAILED(hr) || (!pRMParentFrame)) goto EXIT_FAIL; pRMObjFrame->GetPosition(NULL, &initialPos); if (FAILED(hr)) goto EXIT_FAIL; if (!IsPressed(VK_SHIFT)) { vecObjToCam.x = initialPos.x - vecCameraPos.x; vecObjToCam.y = 0.0f; //initialPos.y - vecCameraPos.y; vecObjToCam.z = initialPos.z - vecCameraPos.z; D3DRMVectorNormalize(&vecObjToCam); vecPtr->set(vecObjToCam.x, vecObjToCam.y, vecObjToCam.z); vecPtr->get_Rotation(&fRot); if (fRot >= 0.785 && fRot <= 2.355) { //Camera is behind the object } else if (fRot >= 2.355 && fRot <= 3.925) { //Camera is left of the object float fTmp; fTmp = vecDelta.x; vecDelta.x = vecDelta.z; vecDelta.z = fTmp; } else if (fRot >= 3.925 && fRot <= 5.495) { //Camera is in front of the object } else { //Camera is right of the object float fTmp; fTmp = vecDelta.x; vecDelta.x = vecDelta.z; vecDelta.z = fTmp; } ComputeEulerAngles(pCTrans->m_pVWFrame, vecDestPtr); vecDestPtr->get(&fX, &fY, &fZ); if (fX >= 0.785 && fX <= 2.355) { //Camera is behind the object fTmp = vecDelta.z; vecDelta.z = vecDelta.y; vecDelta.y = fTmp; } else if (fX >= 2.355 && fX <= 3.925) { //Camera is left of the object } else if (fX >= 3.925 && fX <= 5.495) { //Camera is in front of the object fTmp = vecDelta.z; vecDelta.z = vecDelta.y; vecDelta.y = fTmp; } else { //Camera is right of the object } if (fY >= 0.785 && fY <= 2.355) // && !(fX >= 2.355 && fX <= 3.925)) { //Camera is behind the object fTmp = vecDelta.x; vecDelta.x = vecDelta.z; vecDelta.z = fTmp; } else if (fY >= 2.355 && fY <= 3.925) { //Camera is left of the object } else if (fY >= 3.925 && fY <= 5.495) // && !(fX >= 2.355 && fX <= 3.925) ) { //Camera is in front of the object fTmp = vecDelta.x; vecDelta.x = vecDelta.z; vecDelta.z = fTmp; } else { //Camera is right of the object } } else { //Shift it pressed vecDelta.y = vecDelta.x; } pRMObjFrame->SetPosition(NULL, 0.0f, 0.0f, 0.0f); if (FAILED(hr)) goto EXIT_FAIL; //Do a uniform (all axis) scaling // axis.x = 1.0f + (vecDelta.x > 0 ? vecDelta.x : vecDelta.z); // axis.y = 1.0f + (vecDelta.x > 0 ? vecDelta.x : vecDelta.z); // axis.z = 1.0f + (vecDelta.x > 0 ? vecDelta.x : vecDelta.z); // } // else //Normal perspective viewing // { axis.x = 1.0f + vecDelta.x; axis.y = 1.0f + vecDelta.y; axis.z = 1.0f + vecDelta.z; // } //Fix up current scale and fire UI event if (SIGN(pCTrans->currentLocation.x) == SIGN(axis.x) && axis.x != 0.0f) { fTmp = pCTrans->currentLocation.x; pCTrans->currentLocation.x *= axis.x; if (pCTrans->currentLocation.x < MIN_SCALE || pCTrans->currentLocation.x > MAX_SCALE) { pCTrans->currentLocation.x = fTmp; axis.x = 1.0f; } } else axis.x = 1.0f; if (SIGN(pCTrans->currentLocation.y) == SIGN(axis.y) && axis.y != 0.0f) { fTmp = pCTrans->currentLocation.y; pCTrans->currentLocation.y *= axis.y; if (pCTrans->currentLocation.y < MIN_SCALE || pCTrans->currentLocation.y > MAX_SCALE) { pCTrans->currentLocation.y = fTmp; axis.y = 1.0f; } } else axis.y = 1.0f; if (SIGN(pCTrans->currentLocation.z) == SIGN(axis.z) && axis.z != 0.0f) { fTmp = pCTrans->currentLocation.z; pCTrans->currentLocation.z *= axis.z; if (pCTrans->currentLocation.z < MIN_SCALE || pCTrans->currentLocation.z > MAX_SCALE) { pCTrans->currentLocation.z = fTmp; axis.z = 1.0f; } } else axis.z = 1.0f; hr = pRMObjFrame->AddScale(D3DRMCOMBINE_BEFORE, axis.x, axis.y, axis.z); if (FAILED(hr)) goto EXIT_FAIL; pRMObjFrame->SetPosition(NULL, initialPos.x, initialPos.y, initialPos.z); if (FAILED(hr)) goto EXIT_FAIL; dwTimeNow = GetTickCount(); if (dwTimeNow - dwTime > 200) { tmpStr.Format("%0.3f", pCTrans->currentLocation.x); bstr1 = tmpStr; tmpStr.Format("%0.3f", pCTrans->currentLocation.y); bstr2 = tmpStr; tmpStr.Format("%0.3f", pCTrans->currentLocation.z); bstr3 = tmpStr; hr = InvokeToolEvent(TOOLEVENT_3DOBJECTSCALED, pCTrans->m_pThing, bstr1.m_str, bstr2.m_str, bstr3.m_str, VARIANT_TRUE); if(FAILED( hr )) goto EXIT_FAIL; dwTime = dwTimeNow; } SAFERELEASE(pRMObjFrame); SAFERELEASE(pRMParentFrame); } } EXIT_FAIL: SAFERELEASE(pRMParentFrame); SAFERELEASE(pRMObjFrame); SAFERELEASE(pScene); SAFERELEASE(vecDestPtr); SAFERELEASE(vecPtr); return hr; }