3DCamera.cpp
Upload User: kairuinn
Upload Date: 2009-02-07
Package Size: 2922k
Code Size: 37k
Category:

Graph program

Development Platform:

Visual C++

  1. #include "stdafx.h"
  2. #include "3DCamera.h"
  3. #ifdef _DEBUG
  4. #define new DEBUG_NEW
  5. #undef THIS_FILE
  6. static char THIS_FILE[] = __FILE__;
  7. #endif
  8. static  SG_VECTOR   x_axe = {1.0, 0.0, 0.0};
  9. static  SG_VECTOR   y_axe = {0.0, 1.0, 0.0};
  10. static  SG_VECTOR   z_axe = {0.0, 0.0, 1.0};
  11. static  SG_POINT    zero_p = {0.0, 0.0, 0.0};
  12. #define Pi        3.14159265
  13. #define PiOver180   1.74532925199433E-002
  14. #define PiUnder180    5.72957795130823E+001
  15. #define SMALL_NUMBER  0.00001
  16. #define LARGE_NUMBER  1E20
  17. static GLdouble Radiansf(GLdouble Angle)
  18. {
  19. GLdouble r = (GLdouble)Angle*PiOver180; 
  20. return r;
  21. }
  22. GLdouble Degreesf(GLdouble Angle)
  23. {
  24. GLdouble d = (GLdouble)Angle*PiUnder180;
  25. return d;
  26. }
  27. GLdouble Diff(GLdouble a, GLdouble b)
  28. {
  29. if(a >= 0 && b >= 0)
  30. {
  31. if(a > b)
  32. return a-b;
  33. else
  34. return b-a;
  35. }
  36. if(a < 0 && b < 0)
  37. {
  38. if( a > b)
  39. return b-a;
  40. else
  41. return a-b;
  42. }
  43. if(a >= 0 && b < 0)
  44. return a-b;
  45. else
  46. return b-a;
  47. }
  48. void PrepareMatrix(double Ox,  double Oy,  double Oz,
  49.    double Rx,  double Ry,  double Rz,
  50.    double Tx,  double Ty,  double Tz,
  51.    sgCMatrix& XForm)
  52. {
  53. XForm.Identity(); 
  54. SG_VECTOR TransV = {Tx, Ty, Tz};
  55. XForm.Translate(TransV);
  56. XForm.Rotate(zero_p, x_axe, Rx);
  57. XForm.Rotate(zero_p, y_axe, Ry);
  58. XForm.Rotate(zero_p, z_axe, Rz);
  59. SG_VECTOR oV = {Ox, Oy, Oz};
  60. XForm.Translate(oV);
  61. }
  62. void PrepareInvMatrix(double Ox,  double Oy,  double Oz,
  63.   double Rx,  double Ry,  double Rz,
  64.   double Tx,  double Ty,  double Tz,
  65.   sgCMatrix& XForm)
  66. {
  67. XForm.Identity(); 
  68. SG_VECTOR oV = {Ox, Oy, Oz};
  69. XForm.Translate(oV);
  70. XForm.Rotate(zero_p, z_axe, Rz);
  71. XForm.Rotate(zero_p, y_axe, Ry);
  72. XForm.Rotate(zero_p, x_axe, Rx);
  73. SG_VECTOR TransV = {Tx, Ty, Tz};
  74. XForm.Translate(TransV);
  75. }
  76. /////////////////////////////////////////////////////////////////////////////
  77. // C3dCamera construction
  78. C3dCamera::C3dCamera()
  79. {
  80. ReInit();
  81. }
  82. C3dCamera& C3dCamera::operator = (const C3dCamera& oldCam) 
  83. {
  84. m_bBuildLists = oldCam.m_bBuildLists;
  85. m_bResetClippingPlanes = oldCam.m_bResetClippingPlanes;
  86. m_iDisplayLists = oldCam.m_iDisplayLists;
  87. m_bPerspective = oldCam.m_bPerspective;
  88. m_enumCameraPosition = oldCam.m_enumCameraPosition;
  89. m_iScreenWidth = oldCam.m_iScreenWidth;
  90. m_iScreenHeight = oldCam.m_iScreenHeight;
  91. m_fFovY = oldCam.m_fFovY; // Y-Axis field of view
  92. m_fAspect = oldCam.m_fAspect; // width(x) to height(y) aspect
  93. m_fLeft = oldCam.m_fLeft;
  94. m_fRight = oldCam.m_fRight;
  95. m_fBottom = oldCam.m_fBottom;
  96. m_fTop = oldCam.m_fTop;
  97. m_fNear = oldCam.m_fNear;
  98. m_fFar = oldCam.m_fFar;
  99. memcpy(&m_iViewport[0],&(oldCam.m_iViewport[0]),4*sizeof(GLint));
  100. memcpy(&m_fEyePos,&(oldCam.m_fEyePos),sizeof(SG_POINT));
  101. memcpy(&m_fLookAtPos,&(oldCam.m_fLookAtPos),sizeof(SG_POINT));
  102. memcpy(&m_fUpVector,&(oldCam.m_fUpVector),sizeof(SG_VECTOR));
  103. m_fFocalLength = oldCam.m_fFocalLength;
  104. m_fPitch = oldCam.m_fPitch; // Rotation about the X-Axis
  105. m_fRoll = oldCam.m_fRoll; // Rotation about the Y-Axis
  106. m_fYaw = oldCam.m_fYaw; // Rotation about the Z-Axis
  107. memcpy(&m_dModelViewMatrix[0],&(oldCam.m_dModelViewMatrix[0]),16*sizeof(GLdouble));
  108. memcpy(&m_dProjectionMatrix[0],&(oldCam.m_dProjectionMatrix[0]),16*sizeof(GLdouble));
  109. memcpy(&m_fFrustum[0][0],&(oldCam.m_fFrustum[0][0]),6*4*sizeof(GLdouble));
  110. m_cur_animation_position_index = -1;
  111. m_timer_ID = NULL;
  112. return *this;
  113. }
  114. void C3dCamera::ReInit()
  115. {
  116. SetLookAtPos(0.0f, 0.0f, 0.0f);
  117. SetEyePos(9.0f, 9.0f, 9.0f);
  118. SetFocalLength(9.0f);
  119. SetRotationAboutLookAt(-30.0f, 0.0f, -30.0f);
  120. SetUpVector(0.0f, 0.0f, 1.0f); // Z-Axis is up
  121. m_fPitch = 0.0f;
  122. m_fYaw   = 0.0f;
  123. m_fRoll  = 0.0f;
  124. m_fFovY = 45.0f;
  125. m_fNear = 1.0f;
  126. m_fFar  = 10000.0f;
  127. m_bPerspective = TRUE;
  128. m_enumCameraPosition = CP_USER_POSITION;
  129. m_bBuildLists = TRUE;
  130. m_iDisplayLists = 0;
  131. m_bResetClippingPlanes = TRUE;
  132. m_cur_animation_position_index = -1;
  133. m_timer_ID = NULL;
  134. // Clear our modelview and projection matrix
  135. memset(&m_dModelViewMatrix, 0, sizeof(GLdouble)*16);
  136. memset(&m_dProjectionMatrix, 0, sizeof(GLdouble)*16);
  137. }
  138. /////////////////////////////////////////////////////////////////////////////
  139. // C3dCamera Destructor
  140. C3dCamera::~C3dCamera()
  141. {
  142. // Delete the DisplayLists
  143. if(m_iDisplayLists)
  144. {
  145. glDeleteLists(m_iDisplayLists, 1);
  146. m_iDisplayLists = 0;
  147. }
  148. }
  149. void C3dCamera::PositionCamera()
  150. {
  151. if(m_bResetClippingPlanes)
  152. {
  153. // Reset our cameras clipping plane
  154. ResetView();
  155. m_bResetClippingPlanes = FALSE;
  156. }
  157. if(m_fRoll)
  158. {
  159. sgCMatrix matx;
  160. SG_VECTOR UpVector;
  161. matx.Rotate(zero_p, x_axe, m_fPitch/180.0*Pi);
  162. matx.Rotate(zero_p, y_axe, m_fRoll/180.0*Pi);
  163. matx.Rotate(zero_p, z_axe, -m_fYaw/180.0*Pi);
  164. UpVector = z_axe;
  165. matx.ApplyMatrixToVector(zero_p,UpVector);
  166. // Position the camera using the newly calculated 'Up' vector
  167. gluLookAt(m_fEyePos.x,    m_fEyePos.y,    m_fEyePos.z,
  168. m_fLookAtPos.x, m_fLookAtPos.y, m_fLookAtPos.z,
  169. UpVector.x,     UpVector.y,     UpVector.z);
  170. }
  171. else
  172. {
  173. // Since our 'Up' vector has already been calculated, all we need to do is
  174. // position the camera..
  175. gluLookAt(m_fEyePos.x,    m_fEyePos.y,    m_fEyePos.z,
  176. m_fLookAtPos.x, m_fLookAtPos.y, m_fLookAtPos.z,
  177. m_fUpVector.x,  m_fUpVector.y,  m_fUpVector.z);
  178. }
  179. // Save the Model view matrix.  This is used later for
  180. // conversion of mouse coordinates to world coordinates.
  181. glGetDoublev(GL_MODELVIEW_MATRIX, m_dModelViewMatrix);
  182. }
  183. void C3dCamera::ResetView(int w, int h)
  184. {
  185. // Save the screen width and height
  186. if(w || h) {
  187. m_iScreenWidth  = (GLsizei)w;
  188. m_iScreenHeight = (GLsizei)h;
  189. }
  190. // calculate the aspect ratio of the screen
  191. if (m_iScreenHeight==0)
  192. m_fAspect = (GLdouble)m_iScreenWidth;
  193. else
  194. m_fAspect = (GLdouble)m_iScreenWidth/(GLdouble)m_iScreenHeight;
  195. // Calculate the clipping volume along the y-axis, then set our
  196. // right, left, top and bottom clipping volumn
  197. GLdouble viewDepth = (GLdouble)GetFocalLength();
  198. GLdouble clipY = (GLdouble)tan(Radiansf(m_fFovY/2))*viewDepth;
  199. if(m_iScreenWidth <= m_iScreenHeight) {
  200. m_fLeft   = -clipY;
  201. m_fRight  =  clipY;
  202. m_fBottom = -clipY*m_iScreenHeight/m_iScreenWidth;
  203. m_fTop    =  clipY*m_iScreenHeight/m_iScreenWidth;
  204. }
  205. else {
  206. m_fLeft   = -clipY*m_iScreenWidth/m_iScreenHeight;
  207. m_fRight  =  clipY*m_iScreenWidth/m_iScreenHeight;
  208. m_fBottom = -clipY;
  209. m_fTop    =  clipY;
  210. }
  211. // Set Viewport to window dimensions
  212. glViewport(0, 0, m_iScreenWidth, m_iScreenHeight);
  213. // Reset the projection matrix (coordinate system)
  214. glMatrixMode(GL_PROJECTION);
  215. glLoadIdentity();
  216. if(m_bPerspective) {
  217. // Perspective transformations.
  218. gluPerspective(m_fFovY, m_fAspect, m_fNear, m_fFar);
  219. }
  220. else {
  221. // Orthographic transformations.
  222. glOrtho(m_fLeft, m_fRight, m_fBottom, m_fTop, m_fNear, m_fFar); 
  223. }
  224. // Save the Projection matrix.  This is used later for
  225. // conversion of mouse coordinates to world coordinates.
  226. glGetDoublev(GL_PROJECTION_MATRIX, m_dProjectionMatrix);
  227. // Save the Projection matrix.  This is used later for
  228. // conversion of mouse coordinates to world coordinates.
  229. glGetIntegerv(GL_VIEWPORT, m_iViewport);
  230. // Reset the ModelView matrix
  231. glMatrixMode(GL_MODELVIEW);
  232. glLoadIdentity();
  233. }
  234. void C3dCamera::GetWorldCoord(int ix, int iy, GLdouble fz, SG_VECTOR& coord)
  235. {
  236. GLdouble x, y, z, winX, winY, winZ;
  237. // Fix the yPos value.  MS Windows origin 0,0 is upper left
  238. // while OpenGL windows origin 0,0 is lower left...
  239. winX = (GLdouble)ix;
  240. winY = (GLdouble)m_iViewport[3]-iy;
  241. // Add the camera's focal length, or distance from 'LookAt' to 'Eye' position
  242. // to the given 'z' coordinate.
  243. fz += GetFocalLength();
  244. // Calculate the winZ coordinate:
  245. if(m_bPerspective)
  246. // Compensate for perspective view
  247. winZ = 0.5 + (((m_fFar+m_fNear)-(2*m_fFar*m_fNear)/fz))/(2*(m_fFar-m_fNear));
  248. else
  249. // winZ is linearly interpolated between the Near_Far clipping plane
  250. winZ = (fz-m_fNear)/(m_fFar-m_fNear);
  251. // Unproject the point
  252. gluUnProject(winX, winY, winZ,
  253. m_dModelViewMatrix,
  254. m_dProjectionMatrix,
  255. m_iViewport,
  256. &x, &y, &z);
  257. // Copmensate for rounding errors
  258. if(fabs(x) < SMALL_NUMBER)
  259. x = 0;
  260. if(fabs(y) < SMALL_NUMBER)
  261. y = 0;
  262. if(fabs(z) < SMALL_NUMBER)
  263. z = 0;
  264. coord.x = x;
  265. coord.y = y;
  266. coord.z = z;
  267. }
  268. void C3dCamera::GetScreenCoord(GLdouble wX, GLdouble wY, GLdouble wZ,
  269.    double& scrX, double& scrY, double& scrZ)
  270. {
  271. gluProject(wX, wY, wZ,
  272. m_dModelViewMatrix,m_dProjectionMatrix,m_iViewport,
  273. &scrX,&scrY,&scrZ);
  274. scrY = (GLdouble)m_iViewport[3]-scrY;
  275. scrZ += GetFocalLength();
  276. }
  277. void C3dCamera::GetEyePos(GLdouble *x, GLdouble *y, GLdouble *z)
  278. {
  279. *x = m_fEyePos.x;
  280. *y = m_fEyePos.y;
  281. *z = m_fEyePos.z;
  282. }
  283. void C3dCamera::SetEyePos(GLdouble x, GLdouble y, GLdouble z)
  284. {
  285. m_fEyePos.x = x;
  286. m_fEyePos.y = y;
  287. m_fEyePos.z = z;
  288. CalculateYawPitchRoll();
  289. CalculateUpVector();
  290. }
  291. void C3dCamera::GetLookAtPos(GLdouble *x, GLdouble *y, GLdouble *z)
  292. {
  293. *x = m_fLookAtPos.x;
  294. *y = m_fLookAtPos.y;
  295. *z = m_fLookAtPos.z;
  296. }
  297. void C3dCamera::SetLookAtPos(GLdouble x, GLdouble y, GLdouble z)
  298. {
  299. m_fLookAtPos.x = x;
  300. m_fLookAtPos.y = y;
  301. m_fLookAtPos.z = z;
  302. }
  303. void C3dCamera::GetUpVector(GLdouble *x, GLdouble *y, GLdouble *z)
  304. {
  305. *x = m_fUpVector.x;
  306. *y = m_fUpVector.y;
  307. *z = m_fUpVector.z;
  308. }
  309. void C3dCamera::SetUpVector(GLdouble x, GLdouble y, GLdouble z)
  310. {
  311. m_fUpVector.x = x;
  312. m_fUpVector.y = y;
  313. m_fUpVector.z = z;
  314. }
  315. void C3dCamera::SetNearClipPlane(GLdouble fNear)
  316. {
  317. m_fNear = fNear;
  318. // Reset the projection matrix (coordinate system)
  319. glMatrixMode(GL_PROJECTION);
  320. glLoadIdentity();
  321. if(m_bPerspective)
  322. // Perspective transformations.
  323. gluPerspective(m_fFovY, m_fAspect, m_fNear, m_fFar);
  324. else
  325. // Orthographic transformations.
  326. glOrtho(m_fLeft, m_fRight, m_fBottom, m_fTop, m_fNear, m_fFar); 
  327. // Save the Projection matrix.  This is used later for
  328. // conversion of mouse coordinates to world coordinates.
  329. glGetDoublev(GL_PROJECTION_MATRIX, m_dProjectionMatrix);
  330. // Reset the ModelView matrix
  331. glMatrixMode(GL_MODELVIEW);
  332. }
  333. void C3dCamera::SetFarClipPlane(GLdouble fFar)
  334. {
  335. m_fFar = fFar;
  336. // Reset the projection matrix (coordinate system)
  337. glMatrixMode(GL_PROJECTION);
  338. glLoadIdentity();
  339. if(m_bPerspective)
  340. // Perspective transformations.
  341. gluPerspective(m_fFovY, m_fAspect, m_fNear, m_fFar);
  342. else
  343. // Orthographic transformations.
  344. glOrtho(m_fLeft, m_fRight, m_fBottom, m_fTop, m_fNear, m_fFar); 
  345. // Save the Projection matrix.  This is used later for
  346. // conversion of mouse coordinates to world coordinates.
  347. glGetDoublev(GL_PROJECTION_MATRIX, m_dProjectionMatrix);
  348. // Reset the ModelView matrix
  349. glMatrixMode(GL_MODELVIEW);
  350. }
  351. void C3dCamera::CalculateYawPitchRoll()
  352. {
  353. CalculateFocalLength();
  354. GLdouble ax, ay, az;
  355. ax = m_fEyePos.x - m_fLookAtPos.x;
  356. ay = m_fEyePos.y - m_fLookAtPos.y;
  357. az = m_fEyePos.z - m_fLookAtPos.z;
  358. // Compensate for rounding errors
  359. if(fabs(ax) < SMALL_NUMBER)
  360. ax = 0.0f;
  361. if(fabs(ay) < SMALL_NUMBER)
  362. ay = 0.0f;
  363. if(fabs(az) < SMALL_NUMBER)
  364. az = 0.0f;
  365. // Calculate the Camera Pitch angle
  366. if(m_fUpVector.z >= 0)
  367. m_fPitch = Degreesf(asin(-az/m_fFocalLength));
  368. else
  369. m_fPitch = 180-Degreesf(asin(-az/m_fFocalLength));
  370. // Calculate the Camera 'Yaw' angle
  371. if(m_fPitch == 90.0f)
  372. m_fYaw = Degreesf(atan2(-m_fUpVector.x, -m_fUpVector.y));
  373. else if(m_fPitch == -90.0f)
  374. m_fYaw = Degreesf(atan2(m_fUpVector.x, m_fUpVector.y));
  375. else if(m_fPitch < 90.0f)
  376. m_fYaw = Degreesf(atan2(-ax, -ay));
  377. else
  378. m_fYaw = Degreesf(atan2(ax, ay));
  379. }
  380. void C3dCamera::CalculateUpVector()
  381. {
  382. sgCMatrix matx;
  383. matx.Rotate(zero_p, x_axe, m_fPitch/180.0*Pi);
  384. matx.Rotate(zero_p, z_axe, -m_fYaw/180.0*Pi);
  385. m_fUpVector = z_axe;
  386. matx.ApplyMatrixToVector(zero_p,m_fUpVector);
  387. // Compensate for rounding errors
  388. if(fabs(m_fUpVector.x) < SMALL_NUMBER)
  389. m_fUpVector.x = 0.0f;
  390. if(fabs(m_fUpVector.y) < SMALL_NUMBER)
  391. m_fUpVector.y = 0.0f;
  392. if(fabs(m_fUpVector.z) < SMALL_NUMBER)
  393. m_fUpVector.z = 0.0f;
  394. }
  395. GLdouble C3dCamera::GetFocalLength()
  396. {
  397. return(m_fFocalLength);
  398. }
  399. void C3dCamera::SetFocalLength(GLdouble length, BOOL bLookAtPos)
  400. {
  401. GLdouble rx, ry, rz;
  402. if(bLookAtPos)
  403. {
  404. // Calculate the 'Eye' position by first getting the rotation about
  405. // the 'LookAt' position, set the new focal length, then set the 
  406. // rotation about the 'LookAt' position.
  407. GetRotationAboutLookAt(&rx, &ry, &rz);
  408. // Set the member variable
  409. m_fFocalLength = length;
  410. SetRotationAboutLookAt(rx, ry, rz);
  411. }
  412. else
  413. {
  414. // Calculate the 'LookAt' position
  415. // Calculate the 'LookAt' position by first getting the rotation about
  416. // the 'Eye' position, set the new focal length, then set the rotation
  417. // about the 'Eye' position.
  418. GetRotationAboutEye(&rx, &ry, &rz);
  419. // Set the member variable
  420. m_fFocalLength = length;
  421. SetRotationAboutEye(rx, ry, rz);
  422. }
  423. }
  424. void C3dCamera::CalculateFocalLength()
  425. {
  426. // Calculate a new focal length based on the position of the
  427. // 'LookAt' and 'Eye' position, where:
  428. //    length = sqrt(a*a + b*b +c*c);
  429. GLdouble a, b, c, temp;
  430. a = m_fEyePos.x-m_fLookAtPos.x;
  431. b = m_fEyePos.y-m_fLookAtPos.y;
  432. c = m_fEyePos.z-m_fLookAtPos.z;
  433. temp = sqrt(a*a + b*b + c*c);
  434. if(temp == 0.0f)
  435. m_fFocalLength = 1.0f;
  436. else
  437. m_fFocalLength = temp;
  438. }
  439. void C3dCamera::GetRotationAboutEye(GLdouble *x, GLdouble *y, GLdouble *z)
  440. {
  441. CalculateFocalLength();
  442. GLdouble ax, ay, az;
  443. ax = m_fEyePos.x - m_fLookAtPos.x;
  444. ay = m_fEyePos.y - m_fLookAtPos.y;
  445. az = m_fEyePos.z - m_fLookAtPos.z;
  446. // Compensate for rounding errors
  447. if(fabs(ax) < SMALL_NUMBER)
  448. ax = 0.0f;
  449. if(fabs(ay) < SMALL_NUMBER)
  450. ay = 0.0f;
  451. if(fabs(az) < SMALL_NUMBER)
  452. az = 0.0f;
  453. // Calculate the Camera Pitch angle
  454. if(m_fUpVector.z >= 0)
  455. m_fPitch = Degreesf(asin(-az/m_fFocalLength));
  456. else
  457. m_fPitch = 180-Degreesf(asin(-az/m_fFocalLength));
  458. // Calculate the Camera 'Yaw' angle
  459. if(m_fPitch == 90.0f)
  460. m_fYaw = Degreesf(atan2(-m_fUpVector.x, -m_fUpVector.y));
  461. else if(m_fPitch == -90.0f)
  462. m_fYaw = Degreesf(atan2(m_fUpVector.x, m_fUpVector.y));
  463. else if(m_fPitch < 90.0f)
  464. m_fYaw = Degreesf(atan2(-ax, -ay));
  465. else
  466. m_fYaw = Degreesf(atan2(ax, ay));
  467. // Pass the values back to the caller
  468. *x = m_fPitch;
  469. *y = m_fRoll;
  470. *z = m_fYaw;
  471. }
  472. void C3dCamera::SetRotationAboutEye(GLdouble x, GLdouble y, GLdouble z)
  473. {
  474. sgCMatrix matx;
  475. SG_VECTOR LookAtPos;
  476. matx.Rotate(zero_p, x_axe, x/180.0*Pi);
  477. matx.Rotate(zero_p, z_axe, -z/180.0*Pi);
  478. LookAtPos.x = 0.0;
  479. LookAtPos.y = m_fFocalLength;
  480. LookAtPos.z = 0.0;
  481. matx.ApplyMatrixToVector(zero_p,LookAtPos);
  482. m_fLookAtPos.x = m_fEyePos.x + LookAtPos.x;
  483. m_fLookAtPos.y = m_fEyePos.y + LookAtPos.y;
  484. m_fLookAtPos.z = m_fEyePos.z + LookAtPos.z;
  485. // Compensate for rounding errors
  486. if(fabs(m_fLookAtPos.x) < SMALL_NUMBER)
  487. m_fLookAtPos.x = 0.0f;
  488. if(fabs(m_fLookAtPos.y) < SMALL_NUMBER)
  489. m_fLookAtPos.y = 0.0f;
  490. if(fabs(m_fLookAtPos.z) < SMALL_NUMBER)
  491. m_fLookAtPos.z = 0.0f;
  492. // Calculate our camera's UpVector using ONLY the 'X' (Pitch) and 'Z' (Yaw)
  493. // parameters
  494. m_fUpVector = z_axe;
  495. matx.ApplyMatrixToVector(zero_p,m_fUpVector);
  496. // Compensate for rounding errors
  497. if(fabs(m_fUpVector.x) < SMALL_NUMBER)
  498. m_fUpVector.x = 0.0f;
  499. if(fabs(m_fUpVector.y) < SMALL_NUMBER)
  500. m_fUpVector.y = 0.0f;
  501. if(fabs(m_fUpVector.z) < SMALL_NUMBER)
  502. m_fUpVector.z = 0.0f;
  503. // Just save the 'y' value for later use when calculating the camera's 'Up' vector
  504. // prior to calling gluLookAt()
  505. m_fRoll = y;
  506. }
  507. void C3dCamera::GetRotationAboutLookAt(GLdouble *x, GLdouble *y, GLdouble *z)
  508. {
  509. CalculateFocalLength();
  510. GLdouble ax, ay, az;
  511. ax = m_fEyePos.x - m_fLookAtPos.x;
  512. ay = m_fEyePos.y - m_fLookAtPos.y;
  513. az = m_fEyePos.z - m_fLookAtPos.z;
  514. // Compensate for rounding errors
  515. if(fabs(ax) < SMALL_NUMBER)
  516. ax = 0.0f;
  517. if(fabs(ay) < SMALL_NUMBER)
  518. ay = 0.0f;
  519. if(fabs(az) < SMALL_NUMBER)
  520. az = 0.0f;
  521. // Calculate the Camera Pitch angle
  522. if(m_fUpVector.z >= 0)
  523. m_fPitch = Degreesf(asin(-az/m_fFocalLength));
  524. else
  525. m_fPitch = 180-Degreesf(asin(-az/m_fFocalLength));
  526. // Calculate the Camera 'Yaw' angle
  527. if(m_fPitch == 90.0f)
  528. m_fYaw = Degreesf(atan2(-m_fUpVector.x, -m_fUpVector.y));
  529. else if(m_fPitch == -90.0f)
  530. m_fYaw = Degreesf(atan2(m_fUpVector.x, m_fUpVector.y));
  531. else if(m_fPitch < 90.0f)
  532. m_fYaw = Degreesf(atan2(-ax, -ay));
  533. else
  534. m_fYaw = Degreesf(atan2(ax, ay));
  535. // Pass the values back to the caller
  536. *x = m_fPitch;
  537. *y = m_fRoll;
  538. *z = m_fYaw;
  539. }
  540. void C3dCamera::SetRotationAboutLookAt(GLdouble x, GLdouble y, GLdouble z)
  541. {
  542. sgCMatrix matx;
  543. SG_VECTOR EyePos;
  544. matx.Rotate(zero_p, x_axe, x/180.0*Pi);
  545. matx.Rotate(zero_p, z_axe, -z/180.0*Pi);
  546. EyePos.x = 0.0;
  547. EyePos.y = -m_fFocalLength;
  548. EyePos.z = 0.0;
  549. matx.ApplyMatrixToVector(zero_p,EyePos);
  550. m_fEyePos.x = EyePos.x + m_fLookAtPos.x;
  551. m_fEyePos.y = EyePos.y + m_fLookAtPos.y;
  552. m_fEyePos.z = EyePos.z + m_fLookAtPos.z;
  553. // Compensate for rounding errors
  554. if(fabs(m_fEyePos.x) < SMALL_NUMBER)
  555. m_fEyePos.x = 0.0f;
  556. if(fabs(m_fEyePos.y) < SMALL_NUMBER)
  557. m_fEyePos.y = 0.0f;
  558. if(fabs(m_fEyePos.z) < SMALL_NUMBER)
  559. m_fEyePos.z = 0.0f;
  560. // Calculate our camera's UpVector using ONLY the 'X' (Pitch) and 'Z' (Yaw)
  561. // parameters
  562. m_fUpVector = z_axe;
  563. matx.ApplyMatrixToVector(zero_p,m_fUpVector);
  564. // Compensate for rounding errors
  565. if(fabs(m_fUpVector.x) < SMALL_NUMBER)
  566. m_fUpVector.x = 0.0f;
  567. if(fabs(m_fUpVector.y) < SMALL_NUMBER)
  568. m_fUpVector.y = 0.0f;
  569. if(fabs(m_fUpVector.z) < SMALL_NUMBER)
  570. m_fUpVector.z = 0.0f;
  571. // Just save the 'y' value for later use when calculating the camera's 'Up' vector
  572. // prior to calling gluLookAt()
  573. m_fRoll = y;
  574. }
  575. void C3dCamera::GetRotationMatrix(sgCMatrix& XformMatrix)
  576. {
  577. // Calculate the cameras' rotation matrix
  578. PrepareMatrix(0.0f, 0.0f, 0.0f,       // Origin
  579. -m_fPitch,  m_fRoll,  m_fYaw, // Rotation
  580. 0.0f, 0.0f, 0.0f,       // Translation
  581. XformMatrix);
  582. }
  583. void C3dCamera::GetInvRotationMatrix(sgCMatrix& XformMatrix)
  584. {
  585. // Calculate the cameras' inverse rotation matrix
  586. PrepareInvMatrix(0.0f, 0.0f, 0.0f,        // Origin
  587. -m_fPitch,  m_fRoll,  m_fYaw,  // Rotation
  588. 0.0f, 0.0f, 0.0f,        // Translation
  589. XformMatrix);
  590. }
  591. void C3dCamera::GetVectorsForRayTracingCamera(SG_VECTOR& eye_loc,
  592.   SG_VECTOR& eye_look_at,
  593.   SG_VECTOR& eye_y,
  594.   SG_VECTOR& eye_x)
  595. {
  596. GetEyePos(&eye_loc.x, &eye_loc.y, &eye_loc.z);
  597. GetLookAtPos(&eye_look_at.x, &eye_look_at.y, &eye_look_at.z);
  598. SG_VECTOR p1, p2;
  599. GetWorldCoord(m_iScreenWidth/2,m_iScreenHeight/2,0.0,p1);
  600. GetWorldCoord(m_iScreenWidth/2,0,0.0, p2);
  601. eye_y = sgSpaceMath::VectorsSub(p2,p1);
  602. sgSpaceMath::NormalVector(eye_y);
  603. GetWorldCoord(m_iScreenWidth, m_iScreenHeight/2,0.0,p2);
  604. eye_x = sgSpaceMath::VectorsSub(p2,p1);
  605. sgSpaceMath::NormalVector(eye_x);
  606. }
  607. typedef struct 
  608. {
  609. SG_VECTOR       vec;
  610. GLdouble    fDepth;
  611. } boundingPlane;
  612. void C3dCamera::FitBounds(double minX, double minY, double minZ, 
  613.   double maxX, double maxY,double maxZ)
  614. {
  615. boundingPlane boundsRight;
  616. boundingPlane boundsLeft;
  617. boundingPlane boundsTop;
  618. boundingPlane boundsBottom;
  619. boundingPlane boundsNear;
  620. boundingPlane boundsFar;
  621. SG_VECTOR boundsMax;
  622. SG_VECTOR boundsMin;
  623. SG_VECTOR vecCenter;
  624. SG_VECTOR vertices[8];
  625. SG_VECTOR vecOffset;
  626. sgCMatrix matrix;
  627. GLdouble focalLength;
  628. GLdouble fDepthWidth, fDepthHeight;
  629. GLdouble rx, ry, rz;
  630. GLdouble fTan;
  631. GLdouble fx, fz;
  632. // Initialize our function variables
  633. boundsRight.fDepth  = 0.0;
  634. boundsLeft.fDepth = 0.0;
  635. boundsTop.fDepth  = 0.0;
  636. boundsBottom.fDepth = 0.0;
  637. boundsNear.fDepth = 0.0;
  638. boundsFar.fDepth  = 0.0;
  639. memset(&(boundsRight.vec),0,sizeof(SG_VECTOR));
  640. memset(&(boundsLeft.vec),0,sizeof(SG_VECTOR));
  641. memset(&(boundsTop.vec),0,sizeof(SG_VECTOR));
  642. memset(&(boundsBottom.vec),0,sizeof(SG_VECTOR));
  643. memset(&(boundsNear.vec),0,sizeof(SG_VECTOR));
  644. memset(&(boundsFar.vec),0,sizeof(SG_VECTOR));
  645. memset(&(vecOffset),0,sizeof(SG_VECTOR));
  646. memset(&(boundsMin),0,sizeof(SG_VECTOR));
  647. memset(&(boundsMax),0,sizeof(SG_VECTOR));
  648. memset(&(vecCenter),0,sizeof(SG_VECTOR));
  649. fTan = (double)tanf((float)Radiansf(m_fFovY/2));
  650. // Get the cameras rotatiom about the LookAt position, as we 
  651. // will use this to restore the rotation values after we move
  652. // the camera and it's focal length.
  653. GetRotationAboutLookAt(&rx, &ry, &rz);
  654. // Copy the bounds to our local variable
  655. boundsMin.x = minX; boundsMin.y = minY; boundsMin.z = minZ;
  656. boundsMax.x = maxX; boundsMax.y = maxY; boundsMax.z = maxZ;
  657. double spanX, spanY, spanZ;
  658. spanX = Diff(boundsMax.x, boundsMin.x);
  659. spanY = Diff(boundsMax.y, boundsMin.y);
  660. spanZ = Diff(boundsMax.z, boundsMin.z);
  661. vecCenter.x = boundsMax.x - fabs(spanX)/2;
  662. vecCenter.y = boundsMax.y - fabs(spanY)/2;
  663. vecCenter.z = boundsMax.z - fabs(spanZ)/2;
  664. boundsMax.x = spanX/2;
  665. boundsMax.y = spanY/2;
  666. boundsMax.z = spanZ/2;
  667. boundsMin.x = -spanX/2;
  668. boundsMin.y = -spanY/2;
  669. boundsMin.z = -spanZ/2;
  670. // Given the bounding box, fill in the missing vertices to complete our
  671. // cube
  672. vertices[0] = boundsMax;  // Left
  673. vertices[1].x = boundsMax.x; vertices[1].y = boundsMax.y; vertices[1].z = boundsMin.x;
  674. vertices[2].x = boundsMax.x; vertices[2].y = boundsMin.y; vertices[2].z = boundsMin.x;
  675. vertices[3].x = boundsMax.x; vertices[3].y = boundsMin.y; vertices[3].z = boundsMax.x;
  676. vertices[4] = boundsMin;
  677. vertices[5].x = boundsMin.x; vertices[5].y = boundsMin.y; vertices[5].z = boundsMax.x;
  678. vertices[6].x = boundsMin.x; vertices[6].y = boundsMax.y; vertices[6].z = boundsMax.x;
  679. vertices[7].x = boundsMin.x; vertices[7].y = boundsMax.y; vertices[7].z = boundsMin.x;
  680. // Get the cameras rotation matrix
  681. GetRotationMatrix(matrix);
  682. for(int i=0; i<8; i++)
  683. {
  684. // Transform the vertice by the camera rotation matrix.  Since we define the 
  685. // default 'Up' camera position as Z-axis Up, the coordinates map as follows:
  686. //    X maps to Width,
  687. //    Y maps to Depth
  688. //    Z mpas to Height
  689. zero_p.x  = zero_p.y  =zero_p.z  =0.0;
  690. matrix.ApplyMatrixToVector(zero_p, vertices[i]);
  691. // Calculate the focal length needed to fit the near bounding plane
  692. fDepthWidth  = (fabs(vertices[i].x)/fTan/m_fAspect)-vertices[i].y;
  693. fDepthHeight = (fabs(vertices[i].z)/fTan)-vertices[i].y;
  694. // Calculate the Near clipping bounds.  This will be used to fit Isometric views and
  695. // for calculating the Near/Far clipping m_fFrustum.
  696. if(vertices[i].y<0)
  697. {
  698. if( fabs(vertices[i].x) > fabs(boundsNear.vec.x) ||
  699. (fabs(vertices[i].x) == boundsNear.vec.x && fabs(vertices[i].y) > fabs(boundsNear.vec.z)) )
  700. {
  701. boundsNear.vec.x = fabs(vertices[i].x);
  702. boundsNear.vec.z = fabs(vertices[i].y);
  703. }
  704. if( fabs(vertices[i].z) > fabs(boundsNear.vec.y) ||
  705. (fabs(vertices[i].z) == boundsNear.vec.y) )
  706. {
  707. boundsNear.vec.y = fabs(vertices[i].z);
  708. //boundsNear.vec[W] = fabs(vertices[i].y);
  709. }
  710. // Get the bounding depth closest to the viewer
  711. if(fDepthWidth < boundsNear.fDepth || boundsNear.fDepth == 0)
  712. boundsNear.fDepth = fDepthWidth;
  713. if(fDepthHeight < boundsNear.fDepth || boundsNear.fDepth == 0)
  714. boundsNear.fDepth = fDepthHeight;
  715. }
  716. else
  717. {
  718. if( fabs(vertices[i].x) > fabs(boundsFar.vec.x) ||
  719. (fabs(vertices[i].x) == boundsFar.vec.x && fabs(vertices[i].y) < fabs(boundsFar.vec.z)) )
  720. {
  721. boundsFar.vec.x = vertices[i].x;
  722. boundsFar.vec.z = vertices[i].y;
  723. }
  724. if( fabs(vertices[i].z) > fabs(boundsFar.vec.y) ||
  725. (fabs(vertices[i].z) == fabs(boundsFar.vec.y)) )
  726. {
  727. boundsFar.vec.y = vertices[i].z;
  728. //boundsFar.vec[W] = vertices[i].y;
  729. }
  730. // Get the bounding depth furtherest from the viewer
  731. if(fDepthWidth > boundsFar.fDepth)
  732. boundsFar.fDepth = fDepthWidth;
  733. if(fDepthHeight > boundsFar.fDepth)
  734. boundsFar.fDepth = fDepthHeight;
  735. }
  736. // Calculate the Right, Left, Top and Bottom clipping bounds.  This will be used to fit
  737. // Perspective views.
  738. if(vertices[i].x > 0)
  739. {
  740. if(fDepthWidth > boundsRight.fDepth)
  741. {
  742. boundsRight.fDepth = fDepthWidth;
  743. boundsRight.vec.x = vertices[i].x;
  744. //boundsRight.vec[W] = vertices[i].y;
  745. }
  746. }
  747. if(vertices[i].x <= 0)
  748. {
  749. if(fDepthWidth > boundsLeft.fDepth)
  750. {
  751. boundsLeft.fDepth = fDepthWidth;
  752. boundsLeft.vec.x = vertices[i].x;
  753. //boundsLeft.vec[W] = vertices[i].y;
  754. }
  755. }
  756. if(vertices[i].z > 0)
  757. {
  758. if(fDepthHeight > boundsTop.fDepth)
  759. {
  760. boundsTop.fDepth = fDepthHeight;
  761. boundsTop.vec.x = vertices[i].x;
  762. //boundsTop.vec[W] = vertices[i].y;
  763. }
  764. }
  765. if(vertices[i].z <= 0)
  766. {
  767. if(fDepthHeight > boundsBottom.fDepth)
  768. {
  769. boundsBottom.fDepth = fDepthHeight;
  770. boundsBottom.vec.x = vertices[i].x;
  771. //boundsBottom.vec[W] = vertices[i].y;
  772. }
  773. }
  774. }
  775. // Now that we have the view clipping bounds, we can calculate the focal depth
  776. // required to fit the volumn and the offset necessary to center the volumn.
  777. if(m_bPerspective)
  778. {
  779. sgCMatrix invMatrix;
  780. if(boundsRight.fDepth == boundsLeft.fDepth &&
  781. boundsTop.fDepth == boundsBottom.fDepth )
  782. {
  783. // Front, Side or Top view
  784. //  Since the bounds are symetric, just use the Right and Top focal depth.
  785. fx = boundsRight.fDepth;
  786. fz = boundsTop.fDepth;
  787. // No offset necessary
  788. vecOffset.x = vecOffset.y = vecOffset.z = 0.0;
  789. }
  790. else
  791. {
  792. // Calculate the average focal length needed to fit the bounding box
  793. fx = (boundsRight.fDepth + boundsLeft.fDepth)/2;
  794. fz = (boundsTop.fDepth + boundsBottom.fDepth)/2;
  795. // Calculate the offset necessary to center the bounding box.  Note that we
  796. // use a scaling factor for centering the non-limiting bounds to achieve a
  797. // more visually appealing center.
  798. if(fx > fz)
  799. {
  800. GLdouble fScale = sqrt(boundsTop.fDepth/boundsBottom.fDepth);
  801. GLdouble fTop = fTan*fx - fTan*boundsTop.fDepth;
  802. GLdouble fBottom = fTan*fx - fTan*boundsBottom.fDepth;
  803. vecOffset.x = (fTan*m_fAspect*boundsRight.fDepth - fTan*m_fAspect*fx);
  804. vecOffset.z = (fBottom-fTop*fScale)/2;
  805. }
  806. else
  807. {
  808. GLdouble fScale = sqrt(boundsLeft.fDepth/boundsRight.fDepth);
  809. GLdouble fRight = fTan*m_fAspect*fz - fTan*m_fAspect*boundsRight.fDepth;
  810. GLdouble fLeft  = fTan*m_fAspect*fz - fTan*m_fAspect*boundsLeft.fDepth;
  811. vecOffset.z = (fTan*boundsTop.fDepth - fTan*fz);
  812. vecOffset.x = (fLeft - fRight*fScale)/2; 
  813. }
  814. }
  815. // Now that we have the offsets necessary to center the bounds, we must rotate
  816. // the vertices (camera coordinates) by the cameras inverse rotation matrix to
  817. // convert the offsets to world coordinates.
  818. GetInvRotationMatrix(invMatrix);
  819. zero_p.x  = zero_p.y  =zero_p.z  =0.0;
  820. invMatrix.ApplyMatrixToVector(zero_p,vecOffset);
  821. }
  822. else
  823. {
  824. // Isometric View
  825. // Calculate the focal length needed to fit the near bounding plane
  826. if(m_iScreenWidth <= m_iScreenHeight)
  827. {
  828. fx = boundsNear.vec.x/tanf((float)Radiansf(m_fFovY/2));
  829. fz = boundsNear.vec.y/tanf((float)Radiansf(m_fFovY/2))/((GLdouble)m_iScreenHeight/(GLdouble)m_iScreenWidth);
  830. }
  831. else
  832. {
  833. fx = boundsNear.vec.x/tanf((float)Radiansf(m_fFovY/2))/m_fAspect;
  834. fz = boundsNear.vec.y/tanf((float)Radiansf(m_fFovY/2));
  835. }
  836. }
  837. // Set the focal length equal to the largest length required to fit either the 
  838. // Width (Horizontal) or Height (Vertical)
  839. focalLength = (fx > fz? fx : fz);
  840. // Set the camera's new LookAt position to focus on the center
  841. // of the bounding box.
  842. SetLookAtPos(vecCenter.x+vecOffset.x, vecCenter.y+vecOffset.y, vecCenter.z+vecOffset.z);
  843. // Set the camera focal Length
  844. if(focalLength > m_fNear)
  845. SetFocalLength(focalLength, TRUE);
  846. // Adjust the Near clipping plane if necessary
  847. //  if((boundsNear.fDepth/2) > 0.5f)
  848. //    m_fNear = boundsNear.fDepth/2;
  849. // Adjust the Far clipping plane if necessary
  850. if(focalLength+boundsFar.fDepth > m_fFar)
  851. m_fFar = focalLength+boundsFar.fDepth;
  852. // Recalculate the camera view m_fFrustum;
  853. ResetView();
  854. // Restore the cameras rotation about the LookAt position
  855. SetRotationAboutLookAt(rx, ry, rz);
  856. }
  857. void C3dCamera::ExtractFrustum()
  858. {
  859. // Extracts The Current View m_fFrustum Plane Equations
  860. float proj[16]; // For Grabbing The PROJECTION Matrix
  861. float modl[16]; // For Grabbing The MODELVIEW Matrix
  862. double  clip[16]; // Result Of Concatenating PROJECTION and MODELVIEW
  863. double  t;      // Temporary Work Variable
  864. glGetFloatv( GL_PROJECTION_MATRIX, proj );      // Grab The Current PROJECTION Matrix
  865. glGetFloatv( GL_MODELVIEW_MATRIX, modl );     // Grab The Current MODELVIEW Matrix
  866. // Concatenate (Multiply) The Two Matricies
  867. clip[ 0] = modl[ 0] * proj[ 0] + modl[ 1] * proj[ 4] + modl[ 2] * proj[ 8] + modl[ 3] * proj[12];
  868. clip[ 1] = modl[ 0] * proj[ 1] + modl[ 1] * proj[ 5] + modl[ 2] * proj[ 9] + modl[ 3] * proj[13];
  869. clip[ 2] = modl[ 0] * proj[ 2] + modl[ 1] * proj[ 6] + modl[ 2] * proj[10] + modl[ 3] * proj[14];
  870. clip[ 3] = modl[ 0] * proj[ 3] + modl[ 1] * proj[ 7] + modl[ 2] * proj[11] + modl[ 3] * proj[15];
  871. clip[ 4] = modl[ 4] * proj[ 0] + modl[ 5] * proj[ 4] + modl[ 6] * proj[ 8] + modl[ 7] * proj[12];
  872. clip[ 5] = modl[ 4] * proj[ 1] + modl[ 5] * proj[ 5] + modl[ 6] * proj[ 9] + modl[ 7] * proj[13];
  873. clip[ 6] = modl[ 4] * proj[ 2] + modl[ 5] * proj[ 6] + modl[ 6] * proj[10] + modl[ 7] * proj[14];
  874. clip[ 7] = modl[ 4] * proj[ 3] + modl[ 5] * proj[ 7] + modl[ 6] * proj[11] + modl[ 7] * proj[15];
  875. clip[ 8] = modl[ 8] * proj[ 0] + modl[ 9] * proj[ 4] + modl[10] * proj[ 8] + modl[11] * proj[12];
  876. clip[ 9] = modl[ 8] * proj[ 1] + modl[ 9] * proj[ 5] + modl[10] * proj[ 9] + modl[11] * proj[13];
  877. clip[10] = modl[ 8] * proj[ 2] + modl[ 9] * proj[ 6] + modl[10] * proj[10] + modl[11] * proj[14];
  878. clip[11] = modl[ 8] * proj[ 3] + modl[ 9] * proj[ 7] + modl[10] * proj[11] + modl[11] * proj[15];
  879. clip[12] = modl[12] * proj[ 0] + modl[13] * proj[ 4] + modl[14] * proj[ 8] + modl[15] * proj[12];
  880. clip[13] = modl[12] * proj[ 1] + modl[13] * proj[ 5] + modl[14] * proj[ 9] + modl[15] * proj[13];
  881. clip[14] = modl[12] * proj[ 2] + modl[13] * proj[ 6] + modl[14] * proj[10] + modl[15] * proj[14];
  882. clip[15] = modl[12] * proj[ 3] + modl[13] * proj[ 7] + modl[14] * proj[11] + modl[15] * proj[15];
  883. // Extract the RIGHT clipping plane
  884. m_fFrustum[0][0] = clip[ 3] - clip[ 0];
  885. m_fFrustum[0][1] = clip[ 7] - clip[ 4];
  886. m_fFrustum[0][2] = clip[11] - clip[ 8];
  887. m_fFrustum[0][3] = clip[15] - clip[12];
  888. // Normalize it
  889. t = (double) sqrt( m_fFrustum[0][0] * m_fFrustum[0][0] + m_fFrustum[0][1] * m_fFrustum[0][1] + m_fFrustum[0][2] * m_fFrustum[0][2] );
  890. m_fFrustum[0][0] /= t;
  891. m_fFrustum[0][1] /= t;
  892. m_fFrustum[0][2] /= t;
  893. m_fFrustum[0][3] /= t;
  894. // Extract the LEFT clipping plane
  895. m_fFrustum[1][0] = clip[ 3] + clip[ 0];
  896. m_fFrustum[1][1] = clip[ 7] + clip[ 4];
  897. m_fFrustum[1][2] = clip[11] + clip[ 8];
  898. m_fFrustum[1][3] = clip[15] + clip[12];
  899. // Normalize it
  900. t = (double) sqrt( m_fFrustum[1][0] * m_fFrustum[1][0] + m_fFrustum[1][1] * m_fFrustum[1][1] + m_fFrustum[1][2] * m_fFrustum[1][2] );
  901. m_fFrustum[1][0] /= t;
  902. m_fFrustum[1][1] /= t;
  903. m_fFrustum[1][2] /= t;
  904. m_fFrustum[1][3] /= t;
  905. // Extract the BOTTOM clipping plane
  906. m_fFrustum[2][0] = clip[ 3] + clip[ 1];
  907. m_fFrustum[2][1] = clip[ 7] + clip[ 5];
  908. m_fFrustum[2][2] = clip[11] + clip[ 9];
  909. m_fFrustum[2][3] = clip[15] + clip[13];
  910. // Normalize it
  911. t = (double) sqrt( m_fFrustum[2][0] * m_fFrustum[2][0] + m_fFrustum[2][1] * m_fFrustum[2][1] + m_fFrustum[2][2] * m_fFrustum[2][2] );
  912. m_fFrustum[2][0] /= t;
  913. m_fFrustum[2][1] /= t;
  914. m_fFrustum[2][2] /= t;
  915. m_fFrustum[2][3] /= t;
  916. // Extract the TOP clipping plane
  917. m_fFrustum[3][0] = clip[ 3] - clip[ 1];
  918. m_fFrustum[3][1] = clip[ 7] - clip[ 5];
  919. m_fFrustum[3][2] = clip[11] - clip[ 9];
  920. m_fFrustum[3][3] = clip[15] - clip[13];
  921. // Normalize it
  922. t = sqrt( m_fFrustum[3][0] * m_fFrustum[3][0] + m_fFrustum[3][1] * m_fFrustum[3][1] + m_fFrustum[3][2] * m_fFrustum[3][2] );
  923. m_fFrustum[3][0] /= t;
  924. m_fFrustum[3][1] /= t;
  925. m_fFrustum[3][2] /= t;
  926. m_fFrustum[3][3] /= t;
  927. // Extract the FAR clipping plane
  928. m_fFrustum[4][0] = clip[ 3] - clip[ 2];
  929. m_fFrustum[4][1] = clip[ 7] - clip[ 6];
  930. m_fFrustum[4][2] = clip[11] - clip[10];
  931. m_fFrustum[4][3] = clip[15] - clip[14];
  932. // Normalize it
  933. t = sqrt( m_fFrustum[4][0] * m_fFrustum[4][0] + m_fFrustum[4][1] * m_fFrustum[4][1] + m_fFrustum[4][2] * m_fFrustum[4][2] );
  934. m_fFrustum[4][0] /= t;
  935. m_fFrustum[4][1] /= t;
  936. m_fFrustum[4][2] /= t;
  937. m_fFrustum[4][3] /= t;
  938. // Extract the NEAR clipping plane. 
  939. m_fFrustum[5][0] = clip[ 3] + clip[ 2];
  940. m_fFrustum[5][1] = clip[ 7] + clip[ 6];
  941. m_fFrustum[5][2] = clip[11] + clip[10];
  942. m_fFrustum[5][3] = clip[15] + clip[14];
  943. // Normalize it
  944. t = (double) sqrt( m_fFrustum[5][0] * m_fFrustum[5][0] + m_fFrustum[5][1] * m_fFrustum[5][1] + m_fFrustum[5][2] * m_fFrustum[5][2] );
  945. m_fFrustum[5][0] /= t;
  946. m_fFrustum[5][1] /= t;
  947. m_fFrustum[5][2] /= t;
  948. m_fFrustum[5][3] /= t;
  949. }
  950. bool C3dCamera::ProjectCenterOfScreenOnPlane(double plD, SG_VECTOR& plN, SG_POINT& resP)
  951. {
  952. SG_POINT wP;
  953. SG_VECTOR tmpVec;
  954. GetWorldCoord(m_iScreenWidth/2, m_iScreenHeight/2, 0.0 , tmpVec);
  955. wP.x = tmpVec.x; wP.y = tmpVec.y;  wP.z = tmpVec.z;
  956. SG_VECTOR viewNorm;
  957. viewNorm.x = (double)(m_fLookAtPos.x-m_fEyePos.x);
  958. viewNorm.y = (double)(m_fLookAtPos.y-m_fEyePos.y);
  959. viewNorm.z = (double)(m_fLookAtPos.z-m_fEyePos.z);
  960. sgSpaceMath::NormalVector(viewNorm);
  961. if (sgSpaceMath::IntersectPlaneAndLine(plN,plD,wP,viewNorm,resP)!=1)
  962. return false;
  963. return true;
  964. }
  965. void  C3dCamera::StartAnimatePosition(CWnd* wnd,CAMERA_POSITION newPos)
  966. {
  967. if (m_timer_ID)
  968. return; 
  969. ASSERT(wnd);
  970. SG_POINT oldPosPnt;
  971. oldPosPnt.x = m_fEyePos.x;
  972. oldPosPnt.y = m_fEyePos.y;
  973. oldPosPnt.z = m_fEyePos.z;
  974. SG_POINT targPosPnt;
  975. targPosPnt.x = m_fLookAtPos.x;
  976. targPosPnt.y = m_fLookAtPos.y;
  977. targPosPnt.z = m_fLookAtPos.z;
  978. double  dist = sgSpaceMath::PointsDistance(oldPosPnt,targPosPnt);
  979. SG_POINT newPosPnt = targPosPnt;
  980. switch(newPos) 
  981. {
  982. case CP_USER_POSITION:
  983. return;
  984. case CP_FRONT:
  985. newPosPnt.x+=dist;
  986. break;
  987. case CP_BACK:
  988. newPosPnt.x-=dist;
  989. break;
  990. case CP_TOP:
  991. newPosPnt.z+=dist;
  992. break;
  993. case CP_BOTTOM:
  994. newPosPnt.z-=dist;
  995. break;
  996. case CP_LEFT:
  997. newPosPnt.y+=dist;
  998. break;
  999. case CP_RIGHT:
  1000. newPosPnt.y-=dist;
  1001. break;
  1002. case CP_ISO_FRONT:
  1003. newPosPnt.x+=dist*0.5773502691f;
  1004. newPosPnt.y+=dist*0.5773502691f;
  1005. newPosPnt.z+=dist*0.5773502691f;
  1006. break;
  1007. case CP_ISO_BACK:
  1008. newPosPnt.x-=dist*0.5773502691f;
  1009. newPosPnt.y-=dist*0.5773502691f;
  1010. newPosPnt.z+=dist*0.5773502691f;
  1011. break;
  1012. default:
  1013. ASSERT(0);
  1014. break;
  1015. }
  1016. SG_VECTOR begV;
  1017. begV.x = oldPosPnt.x-targPosPnt.x;
  1018. begV.y = oldPosPnt.y-targPosPnt.y;
  1019. begV.z = oldPosPnt.z-targPosPnt.z;
  1020. SG_VECTOR endV;
  1021. endV.x = newPosPnt.x-targPosPnt.x;
  1022. endV.y = newPosPnt.y-targPosPnt.y;
  1023. endV.z = newPosPnt.z-targPosPnt.z;
  1024. sgSpaceMath::NormalVector(begV);
  1025. sgSpaceMath::NormalVector(endV);
  1026. double  alfa = acos(begV.x*endV.x+begV.y*endV.y+begV.z*endV.z);
  1027. size_t stepsCount;
  1028. if (alfa>1.57)
  1029. stepsCount = 10;
  1030. else
  1031.     stepsCount = 6;
  1032. double  alfa_step = alfa/(double)stepsCount;
  1033. SG_VECTOR normal; double Pld;
  1034. normal.x=normal.y=normal.z=0.0;
  1035. if (!sgSpaceMath::PlaneFromPoints(targPosPnt,oldPosPnt,newPosPnt,normal,Pld))
  1036. {
  1037. switch(newPos) 
  1038. {
  1039. case CP_FRONT:
  1040. case CP_BACK:
  1041. case CP_TOP:
  1042. case CP_BOTTOM:
  1043. normal.y = 1.0;
  1044. break;
  1045. case CP_LEFT:
  1046. case CP_RIGHT:
  1047. normal.z = 1.0;
  1048. break;
  1049. case CP_ISO_FRONT:
  1050. case CP_ISO_BACK:
  1051. case CP_USER_POSITION:
  1052. default:
  1053. ASSERT(0);
  1054. break;
  1055. }
  1056. }
  1057. m_animation_positions.clear();
  1058. m_animation_positions.reserve(stepsCount);
  1059. sgCMatrix matr;
  1060. matr.Rotate(targPosPnt,normal,alfa_step);
  1061. for (size_t i=0;i<stepsCount;i++)
  1062. {
  1063. matr.ApplyMatrixToVector(targPosPnt,begV);
  1064. oldPosPnt.x=targPosPnt.x+begV.x*dist;
  1065. oldPosPnt.y=targPosPnt.y+begV.y*dist;
  1066. oldPosPnt.z=targPosPnt.z+begV.z*dist;
  1067. m_animation_positions.push_back(oldPosPnt);
  1068. }
  1069. m_cur_animation_position_index = 0;
  1070. m_timer_ID = wnd->SetTimer(1, 50, 0);
  1071. m_enumCameraPosition = newPos;
  1072. }
  1073. void  C3dCamera::AnimatePosition(CWnd* wnd)
  1074. {
  1075. SetEyePos(m_animation_positions[m_cur_animation_position_index].x,
  1076. m_animation_positions[m_cur_animation_position_index].y,
  1077. m_animation_positions[m_cur_animation_position_index].z);
  1078. //ResetView();
  1079. wnd->Invalidate();
  1080. m_cur_animation_position_index++;
  1081. if (m_cur_animation_position_index==m_animation_positions.size())
  1082. {
  1083. wnd->KillTimer(m_timer_ID);
  1084. m_timer_ID = NULL;
  1085. m_cur_animation_position_index = 0;
  1086. m_animation_positions.clear();
  1087. }
  1088. }
  1089. double  RoundGrid(double oldVal, float gridSz)
  1090. {
  1091. int  celoeColichestvoGrids = (int)(oldVal/gridSz);
  1092. if (oldVal>0)
  1093. {
  1094. if (fabs(oldVal-celoeColichestvoGrids*gridSz)<
  1095. fabs(oldVal-(celoeColichestvoGrids+1)*gridSz))
  1096. return (celoeColichestvoGrids*gridSz);
  1097. else
  1098. return ((celoeColichestvoGrids+1)*gridSz);
  1099. }
  1100. else
  1101. {
  1102. if (fabs(oldVal-celoeColichestvoGrids*gridSz)<
  1103. fabs(oldVal-(celoeColichestvoGrids-1)*gridSz))
  1104. return (celoeColichestvoGrids*gridSz);
  1105. else
  1106. return ((celoeColichestvoGrids-1)*gridSz);
  1107. }
  1108. }
  1109. double  FloorGrid(double oldVal, float gridSz)
  1110. {
  1111. int  celoeColichestvoGrids = (int)(oldVal/gridSz);
  1112. if (oldVal>0)
  1113. return (double)(celoeColichestvoGrids*gridSz);
  1114. else
  1115. return (double)((celoeColichestvoGrids-1)*gridSz);
  1116. }