MF3DHelper.cpp
上传用户:qzpk666
上传日期:2022-08-04
资源大小:59k
文件大小:16k
- // MF3DHelper.cpp: implementation of the CMF3DHelper class.
- //
- //////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- #include <LIMITS.H>
- #include <FLOAT.H>
- #include "MF3DHelper.h"
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[]=__FILE__;
- #define new DEBUG_NEW
- #endif
- //using namespace NeHe;
- #ifndef PI
- const float PI = 3.1415927f;
- #define RAD(x) (x*PI/180.0f)
- #define DEG(x) (x*180.0f/PI)
- #define RAD2DEG(x) (x*180.f/PI);
- #define DEG2RAD(x) (x*PI / 180.0f);
- #endif
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
- CMF3DHelper::CMF3DHelper()
- {
- m_mProjection.Id();
- m_fViewport_x = 0.0f;
- m_fViewport_y = 0.0f;
- m_fViewport_widht = 640.0f;
- m_fViewport_height = 480.0f;
- m_bShadowUpdateRequired = TRUE;
- }
- CMF3DHelper::~CMF3DHelper()
- {
- }
- float CMF3DHelper::cotangens(float x) {
- float s = (float)sin(RAD(x));
- float c = (float)cos(RAD(x));
- if(s!=0.0f) {
- return c/s;
- }
- return 0.0f;
- }
- void CMF3DHelper::emul_glLoadIdentity()
- {
- m_mProjection.Id();
- m_mModel.Id();
- }
- void CMF3DHelper::emul_glViewport(int x, int y, int widht, int height)
- {
- m_fViewport_x = (float)x;
- m_fViewport_y = (float)y;
- m_fViewport_widht = (float)widht;
- m_fViewport_height = (float)height;
- }
- void CMF3DHelper::Scale(float xFactor,float yFactor,float zFactor)
- {
- m_bShadowUpdateRequired = TRUE;
- emul_glScalef(xFactor, yFactor, zFactor);
- }
- void CMF3DHelper::emul_glScalef(float x, float y, float z)
- {
- #define M(x,y) m_mProjection.m[Idx(x,y)]
- M(0,0) *= x; M(0,1) *= y; M(0,2) *= z;
- M(1,0) *= x; M(1,1) *= y; M(1,2) *= z;
- M(2,0) *= x; M(2,1) *= y; M(2,2) *= z;
- M(3,0) *= x; M(3,1) *= y; M(3,2) *= z;
- #undef M
- }
- void CMF3DHelper::Translate(float x,float y,float z)
- {
- emul_glTranslatef(x,y,z);
- }
- void CMF3DHelper::emul_glTranslatef(float x, float y, float z)
- {
- #define M(x,y) m_mModel.m[Idx(x,y)]
- M(0,3) = M(0,0) * x + M(0,1) * y + M(0,2) * z + M(0,3);
- M(1,3) = M(1,0) * x + M(1,1) * y + M(1,2) * z + M(1,3);
- M(2,3) = M(2,0) * x + M(2,1) * y + M(2,2) * z + M(2,3);
- M(3,3) = M(3,0) * x + M(3,1) * y + M(3,2) * z + M(3,3);
- #undef M
- }
- void CMF3DHelper::emul_glRotatef(float angle, float x, float y, float z)
- {
- NeHe::Matrix mR;
- float s, c;
- float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c;
- s = (float)sin(RAD(angle));
- c = (float)cos(RAD(angle));
- mR.Id();
-
- float mag = sqrtf(x*x + y*y + z*z);
- if (mag <= 1.0e-4) {
- /* no rotation, leave mat as-is */
- return;
- }
-
- x /= mag;
- y /= mag;
- z /= mag;
- xx = x * x;
- yy = y * y;
- zz = z * z;
- xy = x * y;
- yz = y * z;
- zx = z * x;
- xs = x * s;
- ys = y * s;
- zs = z * s;
- one_c = 1.0F - c;
- #define M(x,y) mR.m[Idx(x,y)]
- M(0,0) = (one_c * xx) + c;
- M(0,1) = (one_c * xy) - zs;
- M(0,2) = (one_c * zx) + ys;
- M(0,3) = 0.0f;
-
- M(1,0) = (one_c * xy) + zs;
- M(1,1) = (one_c * yy) + c;
- M(1,2) = (one_c * yz) - xs;
- M(1,3) = 0.0f;
-
- M(2,0) = (one_c * zx) - ys;
- M(2,1) = (one_c * yz) + xs;
- M(2,2) = (one_c * zz) + c;
- M(2,3) = 0.0F;
-
- M(3,0) = 0.0F;
- M(3,1) = 0.0F;
- M(3,2) = 0.0F;
- M(3,3) = 1.0F;
- #undef M
- // IMPORTANT!!!
- // We need to perform multiplication in form R(otation)xP(erspective)(and not otherwise!!!)
- m_mRotation = mR;
- NeHe::Matrix mRotTemp = m_mModel;
- m_mModel = mR * mRotTemp;
- }
- void CMF3DHelper::RotateVector(float fAngle,float fVectorX,float fVectorY, float fVectorZ, BOOL bAbsolute)
- {
- m_bShadowUpdateRequired = TRUE;
- if(bAbsolute==TRUE) {
- m_mModel.Id();
- }
-
- emul_glRotatef(fAngle, fVectorX, fVectorY, fVectorZ);
- return;
- }
- void CMF3DHelper::Rotate(float angleX,float angleY,float angleZ, BOOL bAbsolute)
- {
- m_bShadowUpdateRequired = TRUE;
- if(bAbsolute==TRUE) {
- m_mModel.Id();
- }
- emul_glRotatef(angleX, 1.0f,0.0f,0.0f);
- emul_glRotatef(angleY, 0.0f,1.0f,0.0f);
- emul_glRotatef(angleZ, 0.0f,0.0f,1.0f);
- m_cTrackBall.SetRotation(angleX, angleY, angleZ);
- return;
- }
- double calculateFov(double size, double distance)
- {
- const double PI = 3.1415926535;
-
- double radtheta, degtheta;
-
- radtheta = 2.0 * atan2 (size/2.0, distance);
- degtheta = (180.0 * radtheta) / PI;
- return (degtheta);
- }
- double calculateZNear(double fov, double top, double bottom)
- {
- double zNear = (top - bottom) /(2.0f*tan(RAD(fov) / 2.0f));
- return zNear;
- }
- BOOL CMF3DHelper::emul_gluPerspective(float fovy, float aspect, float zNear, float zFar)
- {
- const float PI = 3.1415f;
- if(aspect == 0.0f) {
- return FALSE;
- }
- if((zFar-zNear)==0.0f) {
- return FALSE;
- }
-
- NeHe::Matrix mT1, mT2;
- mT1.Zero();
-
- float f = cotangens(fovy / 2.0f);
-
- #define M(x,y) mT1.m[Idx(x,y)]
- M(0,0) = f / aspect;
- M(1,1) = f;
- M(2,2)= (zFar+zNear) / (zNear-zFar);
- M(2,3)= (2*zFar*zNear) / (zNear-zFar);
- M(3,2)= -1.0f;
- #undef M
-
- m_mProjection =mT1;
- return TRUE;
- }
- BOOL CMF3DHelper::setupPerspective(float fovy, float aspect, float zNear, float zFar)
- {
- // New should always be less than zFar
- if(zNear > zFar) {
- float t = zNear;
- zNear = zFar;
- zFar = zNear;
- }
- // Calculate bounding sphere
- float fDX, fDY, fDZ;
- fDX = m_vCubeMax.x - m_vCubeMin.x;
- fDY = m_vCubeMax.y - m_vCubeMin.y;
- fDZ = m_vCubeMax.z - m_vCubeMin.z;
- // Calculate maximal bounding sphere diameter
- float fDM = max(fDX, max(fDY, fDZ)) / 2.0f;
- float fOffset = 1.0f-zNear; // How much do we have to offset the position of zNear to start at position +1.0
- float zNearMod= 1.0f;
- float zFarMod = 0.0f;
- float zNearX= (float)calculateZNear((double)fovy, (double)m_vCubeMax.x, (double)m_vCubeMin.x);// Optimal zNear for cube (0,0,0/1,1,,1);
- float zNearY= (float)calculateZNear((double)fovy, (double)m_vCubeMax.y, (double)m_vCubeMin.y);
- zNearMod = max(zNearX, zNearY);
- zFarMod = zNearMod + fDM;
- m_mModel.Id();
- if(FALSE == emul_gluPerspective(fovy, aspect, zNearMod, zFarMod)) {
- return FALSE;
- }
- // Force visibility of cube (e.g. -1,-1,-1/+1,+1,+1);
- float xCenter = (m_vCubeMin.x + m_vCubeMax.x) / 2.0f;
- float yCenter = (m_vCubeMin.y + m_vCubeMax.y) / 2.0f;
- float zCenter = (m_vCubeMin.z + m_vCubeMax.z) / 2.0f;
- float fTranslate = (float)zNearMod + fDM;//+ 1.0f; // cube is -1..1 so shift by e.g 1 unit
- NeHe::Matrix mTmp = m_mModel;
- m_mModel = m_mProjection;
- emul_glTranslatef(-xCenter, -yCenter, fTranslate);; // m_mProjection now holds translation also
- m_mProjection = m_mModel;
- m_mModel = mTmp;
- return TRUE;
- }
- BOOL CMF3DHelper::Initialize(CDC *pTargetDC, NeHe::Vector vMin, NeHe::Vector vMax, BOOL bSupportTrackBall)
- {
- try {
- if(pTargetDC==NULL) {
- return FALSE;
- }
- CRect rcDraw;
- pTargetDC->GetWindow()->GetClientRect(&rcDraw);
- if(rcDraw.IsRectEmpty() == TRUE) {
- return FALSE;
- }
- // Mark shadow matrix as "dirty"
- m_bShadowUpdateRequired = TRUE;
- m_fViewport_x = 0.0f;
- m_fViewport_y = 0.0f;
- m_fViewport_widht = (float)rcDraw.Width();
- m_fViewport_height = (float)rcDraw.Height();
- // Set up arc ball also!
- m_cTrackBall.Initialize(rcDraw.Width(), rcDraw.Height());
- emul_glViewport((int)m_fViewport_x, (int)m_fViewport_y, (int)m_fViewport_widht, (int)m_fViewport_height);
- NeHe::Vector vDelta = vMax - vMin;
- m_vCubeMin = vMin;
- m_vCubeMax = vMax;
- float fovy, aspect, zNear, zFar;
- fovy = 45.0f;
- aspect = (float)rcDraw.Width() / (float)rcDraw.Height();
- zNear = vMin.z;
- zFar = vMax.z;
- setupPerspective(fovy, aspect, zNear, zFar);
- return TRUE;
- } catch(...) {
- return FALSE;
- }
- }
- BOOL CMF3DHelper::Reset(CDC *pTargetDC, NeHe::Vector vMin, NeHe::Vector vMax, BOOL bSupportTrackBall)
- {
- m_bShadowUpdateRequired = TRUE; // Matrix needs recalculation!
- return Initialize(pTargetDC, vMin, vMax, bSupportTrackBall);
- }
- void CMF3DHelper::UpdateTrackBall(CDC *pDC) {
- NeHe::Vector cRotDelta, cRot;
- if(TRUE == m_cTrackBall.Update(pDC, cRotDelta, cRot)) {
- Rotate(cRot.x, cRot.y, cRot.z, TRUE);
- }
- }
- NeHe::Vector CMF3DHelper::RenderPoint(NeHe::Vector v3DPoint)
- {
- NeHe::Vector vR;
- v3DPoint.w = 1.0f; // Need to be homogeneous
-
- NeHe::Vector vR5;
- if(m_bShadowUpdateRequired == TRUE) {
- m_mShadow = m_mModel*m_mProjection;
- m_bShadowUpdateRequired = FALSE;
- }
- vR = m_mShadow*v3DPoint;
- float xk,yk;
- xk = (vR.x*0.5f / vR.w + 0.5f)*(float)m_fViewport_widht;
- yk = (vR.y*0.5f / vR.w + 0.5f)*(float)m_fViewport_height;
- vR.x = xk;
- vR.y = yk;
- return vR;
- }
- CString v3DString(float x, float y, float z) {
- CString szV;
- szV.Format(_T("(%.1f, %.1f, %.1f)"), x,y,z);
- return szV;
- }
- // Draw the cube given as min/max pair of data-range
- void CMF3DHelper::DrawVisibilityCube(CDC* pDC, BOOL bDrawAxes, BOOL bDrawBoundingCoordinates)
- {
- CPen cPen(PS_SOLID, 1, RGB(255,255,255));
- CPen cPenR(PS_DASH, 1, RGB(255,64,64));
- CPen cPenG(PS_DASH, 1, RGB(64,255,64));
- CPen cPenB(PS_DASH, 1, RGB(64,64,255));
- CPen *pOld = pDC->SelectObject(&cPen);
-
- float lx,ly,lz,rx,ry,rz,cx,cy,cz;
- #define L m_vCubeMin
- #define R m_vCubeMax
- lx = L.x;
- ly = L.y;
- lz = L.z;
- rx = R.x;
- ry = R.y;
- rz = R.z;
- cx = (lx+rx)/2.0f;
- cy = (ly+ry)/2.0f;
- cz = (lz+rz)/2.0f;
- NeHe::Vector v1(lx,ly,lz);//n,n,n);
- NeHe::Vector v2(rx,ly,lz);//p,n,n);
- NeHe::Vector v3(rx,ry,lz);//p,p,n);
- NeHe::Vector v4(lx,ry,lz);//n,p,n);
- NeHe::Vector v5(lx,ly,rz);//n,n,p);
- NeHe::Vector v6(rx,ly,rz);//p,n,p);
- NeHe::Vector v7(rx,ry,rz);//p,p,p);
- NeHe::Vector v8(lx,ry,rz);//n,p,p);
-
- NeHe::Vector vc1(cx,cy,cz);//c,c,c);
- NeHe::Vector vc2(rx,cy,cz);//p,c,c);
- NeHe::Vector vc3(cx,ry,cz);//c,p,c);
- NeHe::Vector vc4(cx,cy,rz);//c,c,p);
- CString szV1= v3DString(lx,ly,lz);
- CString szV2= v3DString(rx,ly,lz);
- CString szV3= v3DString(rx,ry,lz);
- CString szV4= v3DString(lx,ry,lz);
- CString szV5= v3DString(lx,ly,rz);
- CString szV6= v3DString(rx,ly,rz);
- CString szV7= v3DString(rx,ry,rz);
- CString szV8= v3DString(lx,ry,rz);
-
-
-
- NeHe::Vector o1, o2, o3, o4, o5, o6, o7, o8, c1,c2,c3, c4;
- o1 = RenderPoint(v1);
- o2 = RenderPoint(v2);
- o3 = RenderPoint(v3);
- o4 = RenderPoint(v4);
- o5 = RenderPoint(v5);
- o6 = RenderPoint(v6);
- o7 = RenderPoint(v7);
- o8 = RenderPoint(v8);
- c1 =RenderPoint(vc1);
- c2 =RenderPoint(vc2);
- c3 =RenderPoint(vc3);
- c4 =RenderPoint(vc4);
-
- // Draw front rectangle
- pDC->MoveTo((int)o1.x, (int)o1.y);
- pDC->LineTo((int)o2.x, (int)o2.y);
- pDC->LineTo((int)o3.x, (int)o3.y);
- pDC->LineTo((int)o4.x, (int)o4.y);
- pDC->LineTo((int)o1.x, (int)o1.y);
-
- // Draw connecing lines
- pDC->MoveTo((int)o1.x, (int)o1.y);
- pDC->LineTo((int)o5.x, (int)o5.y);
- pDC->MoveTo((int)o2.x, (int)o2.y);
- pDC->LineTo((int)o6.x, (int)o6.y);
- pDC->MoveTo((int)o3.x, (int)o3.y);
- pDC->LineTo((int)o7.x, (int)o7.y);
- pDC->MoveTo((int)o4.x, (int)o4.y);
- pDC->LineTo((int)o8.x, (int)o8.y);
-
- // Draw rear rectangle
- pDC->MoveTo((int)o5.x, (int)o5.y);
- pDC->LineTo((int)o6.x, (int)o6.y);
- pDC->LineTo((int)o7.x, (int)o7.y);
- pDC->LineTo((int)o8.x, (int)o8.y);
- pDC->LineTo((int)o5.x, (int)o5.y);
-
- int iBKModeOld = pDC->GetBkMode();
- COLORREF rgbTextOld = pDC->GetTextColor();
- pDC->SetBkMode(TRANSPARENT);
-
- // Draw the coordinate axes
- // x-axis
- if(bDrawAxes==TRUE) {
- pDC->SetTextColor(RGB(255,25,255));
- pDC->MoveTo((int)c1.x, (int)c1.y);
- pDC->SelectObject(&cPenR);
- pDC->LineTo((int)c2.x, (int)c2.y);
- pDC->TextOut((int)c2.x, (int)c2.y, _T("+X"));
-
- // y-Axis
- pDC->MoveTo((int)c1.x, (int)c1.y);
- pDC->SelectObject(&cPenG);
- pDC->LineTo((int)c3.x, (int)c3.y);
- pDC->TextOut((int)c3.x, (int)c3.y, _T("+Y"));
-
- // z-Axis
- pDC->MoveTo((int)c1.x, (int)c1.y);
- pDC->SelectObject(&cPenB);
- pDC->LineTo((int)c4.x, (int)c4.y);
- pDC->TextOut((int)c4.x, (int)c4.y, _T("+Z"));
- }
- if(bDrawBoundingCoordinates==TRUE) {
- pDC->SetTextColor(RGB(255,25,255));
- pDC->TextOut((int)o1.x, (int)o1.y, szV1);
- pDC->TextOut((int)o2.x, (int)o2.y, szV2);
- pDC->TextOut((int)o3.x, (int)o3.y, szV3);
- pDC->TextOut((int)o4.x, (int)o4.y, szV4);
- pDC->TextOut((int)o5.x, (int)o5.y, szV5);
- pDC->TextOut((int)o6.x, (int)o6.y, szV6);
- pDC->TextOut((int)o7.x, (int)o7.y, szV7);
- pDC->TextOut((int)o8.x, (int)o8.y, szV8);
- }
- pDC->SetBkMode(iBKModeOld);
- pDC->SetTextColor(rgbTextOld);
- // Finish!
-
- pDC->SelectObject(pOld);
-
- }
- NeHe::CMFArcBall::CMFArcBall()
- {
- m_cMousePoint = CPoint(0,0);
- m_bLButtonDown = FALSE;
- m_fXRotation = 0.0f;
- m_fYRotation = 0.0f;
- m_fZRotation = 0.0f;
- m_iWidth = 0;
- m_iHeight = 0;
- }
- NeHe::CMFArcBall::~CMFArcBall()
- {
- }
- BOOL NeHe::CMFArcBall::getMousePosition(BOOL &bLDown, BOOL &bLToggled, BOOL &bRDown, BOOL &bRToggled, int &xPos, int &yPos, CDC* pDC)
- {
- if(pDC==NULL) {
- return FALSE;
- }
-
- bLDown = bRDown = FALSE;
- xPos = yPos = 0;
-
- CPoint ptMouse;
- GetCursorPos(&ptMouse);
-
- pDC->GetWindow()->ScreenToClient(&ptMouse);
-
- xPos = ptMouse.x;
- yPos = ptMouse.y;
-
- SHORT lButton ,rButton;
- lButton = GetAsyncKeyState(VK_LBUTTON);
- rButton = GetAsyncKeyState(VK_RBUTTON);
-
- // BOOL bLToggled, bRToggled, bLDown, bRDown;
- bLDown = ((lButton & 0x8000) != 0);
- bLToggled = ((lButton & 0x0001) != 0);
- bRDown = ((rButton & 0x8000) != 0);
- bRToggled = ((rButton & 0x0001) != 0);
-
- return TRUE;
- }
- void NeHe::CMFArcBall::mouseToArc(CPoint cPt, float &fx, float &fy)
- {
- #ifndef EPSILON
- #define EPSILON (1.0e-9)
- #endif
-
- int xPos = (cPt.x-m_iWidth/2); // Position from center
- int yPos = (cPt.y-m_iHeight/2);
-
- float xb = (float)xPos / (float)(m_iWidth/2);
- float yh = (float)yPos / (float)(m_iHeight/2);
-
- if(xb<(-1.0f-EPSILON)) {
- fx = -180;
- } else {
- if(xb > (1.0f-EPSILON)) {
- fx = 0;
- }else {
- fy = -DEG(acosf(xb));
- }
- }
-
- if(yh<(-1.0f-EPSILON)) {
- fy = 90.0f;
- } else {
- if(yh > (1.0f-EPSILON)) {
- fy = -90.0f;
- }else {
- fx = -DEG(asinf(yh));
- }
- }
-
- }
- // Returns TRUE only if a rotation is needed
- BOOL NeHe::CMFArcBall::Update(CDC* pDC, NeHe::Vector &cRotationDelta, NeHe::Vector &cRotationCumulative)
- {
- if(pDC == NULL) {
- return FALSE;
- }
- int x, y;
- BOOL bLToggled, bRToggled, bLDown, bRDown;
- getMousePosition(bLDown, bLToggled, bRDown, bRToggled, x, y, pDC);
- CRect rcScreen(0,0,m_iWidth, m_iHeight);
- CPoint point(x,y);
- // Mouse is outside the *usable* window
- if(FALSE == rcScreen.PtInRect(point)) {
- return FALSE;
- }
- if(bRDown==TRUE) {
- m_fXRotation = m_fYRotation = m_fZRotation = 0.0f;
- m_bLButtonDown = FALSE;
- m_cMousePoint = CPoint(0,0);
- cRotationDelta.Null();
- cRotationCumulative = NeHe::Vector(m_fXRotation, m_fYRotation, m_fZRotation, 0.0f);
- return TRUE;
- }
- if(bLDown==FALSE) { // Button up..
- m_bLButtonDown = FALSE;
- cRotationDelta.Null();
- // Remember global rotation
- cRotationCumulative = NeHe::Vector(m_fXRotation, m_fYRotation, m_fZRotation, 0.0f);
- m_cMousePoint = CPoint(0,0);
- return FALSE;
- } else { // Button down
- if(m_bLButtonDown==FALSE) { // Click
- // Button state has toggled
- // *Fresh* mouse down, start trackball
- m_bLButtonDown = TRUE;
- m_cMousePoint = point;
- // Stay at current rotation
- cRotationDelta.Null();
- cRotationCumulative = NeHe::Vector(m_fXRotation, m_fYRotation, m_fZRotation, 0.0f);
- return FALSE;
- } else {
- // Perform actions below
- // ** dragging **
- }
- }
- // Drag
- if(m_cMousePoint == point) {
- return FALSE;
- }
- SHORT sCTRL = ::GetAsyncKeyState(VK_CONTROL);
- BOOL bCTRLDown = ((sCTRL & 0x8000) != 0);
- bCTRLDown = FALSE;
- // Dragging state
- cRotationDelta.Null();
- float xRot, yRot, zRot;
- xRot = yRot = zRot = 0.0f;
- xRot = (float)(point.y-m_cMousePoint.y)/m_fYDiv;
- if(bCTRLDown==FALSE) {
- yRot = (float)(point.x-m_cMousePoint.x)/m_fXDiv;
- } else {
- zRot = (float)(point.x-m_cMousePoint.x)/m_fXDiv;
- }
- m_fXRotation -= xRot;
- m_fYRotation += yRot;
- m_fZRotation -= zRot;
- // Limit result to 360 degree
- m_fXRotation = fmodf(m_fXRotation, 360.0f);
- m_fYRotation = fmodf(m_fYRotation, 360.0f);
- m_fZRotation = fmodf(m_fZRotation, 360.0f);
- cRotationCumulative = NeHe::Vector(m_fXRotation, m_fYRotation, m_fZRotation, 0.0f);
- cRotationDelta = NeHe::Vector(xRot, yRot, zRot, 0.0f);
- m_cMousePoint = point;
- return TRUE;
- }