Viewers.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "StdAfx.h"
  13. #include "WorldEditor.h"
  14. /////////////////////////////////////////////////////////////////////
  15. // CSlaveViewer
  16. #define MIN_TARGET_DISTANCE 0.1f
  17. #define MAX_TARGET_DISTANCE 640000.0f
  18. extern FLOAT wed_fFrontClipDistance;
  19. /*
  20. * Default constructor
  21. */
  22. CMasterViewer::CMasterViewer(void)
  23. {
  24. // set initial viewer variables, viewing tovards origin from ten meters distance
  25. mv_plViewer.pl_PositionVector = FLOAT3D(3.0f, 4.0f, 10.0f);
  26. mv_plViewer.pl_OrientationAngle = ANGLE3D(AngleDeg( 20.0f), AngleDeg( -20.0f), 0);
  27. mv_fTargetDistance = 10.0f; // this must never be very small!
  28. }
  29. // get placement of the virtual target
  30. CPlacement3D CMasterViewer::GetTargetPlacement(void) const
  31. {
  32. CPlacement3D plTarget;
  33. // copy viewer to target
  34. plTarget = mv_plViewer;
  35. // get the direction vector of viewer's sight
  36. FLOAT3D vDirection;
  37. AnglesToDirectionVector(mv_plViewer.pl_OrientationAngle, vDirection);
  38. // offset the target placement by target distance along the vector
  39. plTarget.pl_PositionVector += vDirection*mv_fTargetDistance;
  40. // return the target placement
  41. return plTarget;
  42. }
  43. // set placement of the virtual target
  44. void CMasterViewer::SetTargetPlacement(FLOAT3D f3dTarget)
  45. {
  46. CPlacement3D plViewer;
  47. // copy the viewer's orientation, it will stay the same
  48. plViewer.pl_OrientationAngle = mv_plViewer.pl_OrientationAngle;
  49. // set position vector of new target
  50. plViewer.pl_PositionVector = f3dTarget;
  51. // translate viewer back from target for their distance
  52. plViewer.Translate_OwnSystem( FLOAT3D( 0.0f, 0.0f, mv_fTargetDistance) );
  53. // set new viewer's pacement
  54. mv_plViewer = plViewer;
  55. }
  56. /*
  57. * Convert from slave.
  58. */
  59. void CMasterViewer::operator=(const CSlaveViewer &svSlave)
  60. {
  61. // copy target distance
  62. mv_fTargetDistance = svSlave.sv_fTargetDistance;
  63. // if is perspective
  64. if( svSlave.IsPerspective())
  65. {
  66. // copy viewer placement
  67. mv_plViewer = svSlave.sv_plViewer;
  68. }
  69. // if is isometric
  70. else
  71. {
  72. // copy slave viewer position to master viewer position
  73. mv_plViewer.pl_PositionVector = svSlave.sv_plViewer.pl_PositionVector;
  74. // get the ray of the slave viewing direction
  75. FLOAT3D vSlaveDirection;
  76. AnglesToDirectionVector(svSlave.sv_plViewer.pl_OrientationAngle, vSlaveDirection);
  77. // offset the viewer forward by target distance along the slave direction vector
  78. mv_plViewer.pl_PositionVector += vSlaveDirection*mv_fTargetDistance;
  79. // get the ray of the master viewing direction
  80. FLOAT3D vMasterDirection;
  81. AnglesToDirectionVector(mv_plViewer.pl_OrientationAngle, vMasterDirection);
  82. // offset the viewer backward by target distance along the slave direction vector
  83. mv_plViewer.pl_PositionVector -= vMasterDirection*mv_fTargetDistance;
  84. }
  85. }
  86. /////////////////////////////////////////////////////////////////////
  87. // CSlaveViewer
  88. // get orientation angles for type of isometric viewer
  89. ANGLE3D CSlaveViewer::GetAngleForIsometricType(void) const
  90. {
  91. // depending on the projection type, return angles
  92. switch (sv_ProjectionType) {
  93. case PT_ISOMETRIC_FRONT:
  94. return ANGLE3D((ANGLE)ANGLE_0 ,(ANGLE)ANGLE_0 ,(ANGLE)ANGLE_0 );
  95. case PT_ISOMETRIC_RIGHT:
  96. return ANGLE3D((ANGLE)ANGLE_90 ,(ANGLE)ANGLE_0 ,(ANGLE)ANGLE_0 );
  97. case PT_ISOMETRIC_TOP:
  98. return ANGLE3D((ANGLE)ANGLE_0 ,(ANGLE)ANGLE_270,(ANGLE)ANGLE_0 );
  99. case PT_ISOMETRIC_BACK:
  100. return ANGLE3D((ANGLE)ANGLE_180,(ANGLE)ANGLE_0 ,(ANGLE)ANGLE_0 );
  101. case PT_ISOMETRIC_LEFT:
  102. return ANGLE3D((ANGLE)ANGLE_270,(ANGLE)ANGLE_0 ,(ANGLE)ANGLE_0 );
  103. case PT_ISOMETRIC_BOTTOM:
  104. return ANGLE3D((ANGLE)ANGLE_0 ,(ANGLE)ANGLE_90 ,(ANGLE)ANGLE_0 );
  105. default:
  106. ASSERT(FALSE);
  107. return ANGLE3D((ANGLE)ANGLE_0 ,(ANGLE)ANGLE_0 ,(ANGLE)ANGLE_0 );
  108. }
  109. }
  110. /*
  111. * Get zoom factor for the viewer.
  112. */
  113. FLOAT CSlaveViewer::GetZoomFactor(void)
  114. {
  115. // calculate the zoom factor that as ratio of size in pixels and size in meters
  116. // for target object
  117. FLOAT fScreenX = (float)sv_pdpDrawPort->GetWidth();
  118. ANGLE aHalfI = AngleDeg(90.0f)/2; // assume FOV of 90 degrees for perspective
  119. FLOAT fPerspectiveRatio = fScreenX/(2.0f*Tan(aHalfI));
  120. FLOAT fZoomFactor = fPerspectiveRatio/sv_fTargetDistance;
  121. ASSERT( fZoomFactor > 0);
  122. return fZoomFactor;
  123. }
  124. /*
  125. * Get distance for wanted zoom factor for the viewer.
  126. */
  127. FLOAT CSlaveViewer::GetDistanceForZoom(FLOAT fZoom)
  128. {
  129. // calculate the zoom factor that as ratio of size in pixels and size in meters
  130. // for target object
  131. FLOAT fScreenX = (float)sv_pdpDrawPort->GetWidth();
  132. ANGLE aHalfI = AngleDeg(90.0f)/2; // assume FOV of 90 degrees for perspective
  133. FLOAT fPerspectiveRatio = fScreenX/(2.0f*Tan(aHalfI));
  134. FLOAT fDistance = fPerspectiveRatio / fZoom;
  135. ASSERT( fDistance > 0);
  136. return fDistance;
  137. }
  138. // get placement of the virtual target
  139. CPlacement3D CSlaveViewer::GetTargetPlacement(void) const
  140. {
  141. CPlacement3D plTarget;
  142. // copy viewer to target
  143. plTarget = sv_plViewer;
  144. // get the direction vector of viewer's sight
  145. FLOAT3D vDirection;
  146. AnglesToDirectionVector(sv_plViewer.pl_OrientationAngle, vDirection);
  147. // offset the target placement by target distance along the vector
  148. plTarget.pl_PositionVector += vDirection*sv_fTargetDistance;
  149. // return the target placement
  150. return plTarget;
  151. }
  152. /*
  153. * Default constructor
  154. */
  155. CSlaveViewer::CSlaveViewer(const CMasterViewer &mvMaster,
  156. enum ProjectionType ptProjectionType,
  157. const CPlacement3D &plGrid,
  158. CDrawPort *pdpDrawPort)
  159. {
  160. // remember the drawport
  161. sv_pdpDrawPort = pdpDrawPort;
  162. // set projection type
  163. sv_ProjectionType = ptProjectionType;
  164. // set grid placement
  165. sv_plGrid = plGrid;
  166. // copy target distance
  167. sv_fTargetDistance = mvMaster.mv_fTargetDistance;
  168. // if is perspective
  169. if( IsPerspective())
  170. {
  171. // copy viewer placement
  172. sv_plViewer = mvMaster.mv_plViewer;
  173. }
  174. // if is isometric
  175. else
  176. {
  177. // copy target position to slave viewer position
  178. sv_plViewer.pl_PositionVector = mvMaster.GetTargetPlacement().pl_PositionVector;
  179. // get the orientation depending on the isometry type
  180. sv_plViewer.pl_OrientationAngle = GetAngleForIsometricType();
  181. // transform to grid system
  182. sv_plViewer.AbsoluteToRelative(sv_plGrid);
  183. // get the ray of the viewing direction
  184. FLOAT3D vDirection;
  185. AnglesToDirectionVector(sv_plViewer.pl_OrientationAngle, vDirection);
  186. // offset the viewer backward by target distance along the vector
  187. sv_plViewer.pl_PositionVector -= vDirection*sv_fTargetDistance;
  188. // transform back from grid system
  189. sv_plViewer.RelativeToAbsolute(sv_plGrid);
  190. }
  191. }
  192. /*
  193. * create a perspective projection for this viewer
  194. */
  195. void CSlaveViewer::MakePerspectiveProjection(CPerspectiveProjection3D &prPerspectiveProjection)
  196. {
  197. // if is perspective
  198. ASSERT( IsPerspective());
  199. // init projection parameters
  200. prPerspectiveProjection.FOVL() = AngleDeg(90.0f);
  201. prPerspectiveProjection.ScreenBBoxL() = FLOATaabbox2D(
  202. FLOAT2D(0.0f, 0.0f),
  203. FLOAT2D((float)sv_pdpDrawPort->GetWidth(), (float)sv_pdpDrawPort->GetHeight())
  204. );
  205. wed_fFrontClipDistance = Clamp( wed_fFrontClipDistance, 0.02f, 2.00f);
  206. prPerspectiveProjection.FrontClipDistanceL() = wed_fFrontClipDistance;
  207. prPerspectiveProjection.AspectRatioL() = 1.0f;
  208. prPerspectiveProjection.ObjectStretchL() = FLOAT3D(1.0f, 1.0f, 1.0f);
  209. // set up viewer position and placement
  210. prPerspectiveProjection.ViewerPlacementL() = sv_plViewer;
  211. prPerspectiveProjection.ObjectPlacementL().pl_PositionVector = FLOAT3D(0.0f, 0.0f, 0.0f);
  212. prPerspectiveProjection.ObjectPlacementL().pl_OrientationAngle = ANGLE3D(0, 0, 0);
  213. }
  214. /*
  215. * create a projection for this viewer
  216. */
  217. void CSlaveViewer::MakeProjection(CAnyProjection3D &prProjection)
  218. {
  219. // if is perspective
  220. if( IsPerspective()) {
  221. // use perspective projection
  222. CPerspectiveProjection3D prPerspectiveProjection;
  223. // make perspective projection
  224. MakePerspectiveProjection( prPerspectiveProjection);
  225. // return the result
  226. prProjection = prPerspectiveProjection;
  227. // if is isometric
  228. } else {
  229. // use isometric projection
  230. CIsometricProjection3D prIsometricProjection;
  231. // init projection parameters
  232. prIsometricProjection.ZoomFactorL() = GetZoomFactor();
  233. prIsometricProjection.ScreenBBoxL() = FLOATaabbox2D(
  234. FLOAT2D(0.0f, 0.0f),
  235. FLOAT2D((float)sv_pdpDrawPort->GetWidth(), (float)sv_pdpDrawPort->GetHeight())
  236. );
  237. wed_fFrontClipDistance = Clamp( wed_fFrontClipDistance, 0.02f, 2.00f);
  238. prIsometricProjection.AspectRatioL() = 1.0f;
  239. prIsometricProjection.FrontClipDistanceL() = wed_fFrontClipDistance;
  240. prIsometricProjection.ObjectStretchL() = FLOAT3D(1.0f, 1.0f, 1.0f);
  241. // set up viewer position and placement
  242. prIsometricProjection.ViewerPlacementL() = sv_plViewer;
  243. prIsometricProjection.ObjectPlacementL().pl_PositionVector = FLOAT3D(0.0f, 0.0f, 0.0f);
  244. prIsometricProjection.ObjectPlacementL().pl_OrientationAngle = ANGLE3D(0, 0, 0);
  245. // return the result
  246. prProjection = prIsometricProjection;
  247. }
  248. }
  249. /*
  250. * Translate slave viewer in his own system
  251. */
  252. void CSlaveViewer::Translate_OwnSystem( PIX pixDI, PIX pixDJ, PIX pixDK)
  253. {
  254. FLOAT fZoom = GetZoomFactor();
  255. sv_fTargetDistance += pixDK/fZoom;
  256. if( sv_fTargetDistance < MIN_TARGET_DISTANCE)
  257. {
  258. sv_fTargetDistance = MIN_TARGET_DISTANCE;
  259. return;
  260. }
  261. if( sv_fTargetDistance > MAX_TARGET_DISTANCE)
  262. {
  263. sv_fTargetDistance = MAX_TARGET_DISTANCE;
  264. return;
  265. }
  266. ASSERT( sv_fTargetDistance > 0);
  267. sv_plViewer.Translate_OwnSystem( FLOAT3D(-pixDI/fZoom, pixDJ/fZoom, pixDK/fZoom));
  268. }
  269. /*
  270. * Translate slave viewer without stretching zoom factor
  271. */
  272. void CSlaveViewer::Translate_Local_OwnSystem(FLOAT fdX, FLOAT fdY, FLOAT fdZ)
  273. {
  274. sv_plViewer.Translate_OwnSystem( FLOAT3D(fdX, fdY, fdZ));
  275. }
  276. /*
  277. * Scales target distance using given factor
  278. */
  279. void CSlaveViewer::ScaleTargetDistance( FLOAT fFactor)
  280. {
  281. // if very close to the target, and trying to go even closer or
  282. // if very far away and trying to move further away
  283. if( (sv_fTargetDistance <MIN_TARGET_DISTANCE && fFactor<1.0f) ||
  284. (sv_fTargetDistance >MAX_TARGET_DISTANCE && fFactor>1.0f) )
  285. {
  286. // don't do anything
  287. return;
  288. }
  289. // change along z axis
  290. FLOAT dz = sv_fTargetDistance * fFactor;
  291. sv_plViewer.Translate_OwnSystem( FLOAT3D( 0.0f, 0.0f, dz));
  292. sv_fTargetDistance += dz;
  293. }
  294. /*
  295. * Rotate slave viewer arround target using HPB method
  296. */
  297. void CSlaveViewer::Rotate_HPB( PIX pixDI, PIX pixDJ, PIX pixDK)
  298. {
  299. // if is perspective
  300. if( IsPerspective())
  301. {
  302. // get target placement
  303. CPlacement3D plTarget = GetTargetPlacement();
  304. // project viewer placement to the target placement
  305. sv_plViewer.AbsoluteToRelative(plTarget);
  306. // rotate the target
  307. plTarget.Rotate_HPB( ANGLE3D( AngleDeg((FLOAT)-pixDI),
  308. AngleDeg((FLOAT)-pixDJ),
  309. AngleDeg((FLOAT)-pixDK)));
  310. // project viewer placement back from the target placement
  311. sv_plViewer.RelativeToAbsolute(plTarget);
  312. }
  313. // if is isometric
  314. else
  315. {
  316. // can't rotate isometric projections
  317. }
  318. }
  319. /*
  320. * Rotate slave viewer in his own system using HPB method
  321. */
  322. void CSlaveViewer::Rotate_Local_HPB( FLOAT fdX, FLOAT fdY, FLOAT fdZ)
  323. {
  324. // if is perspective
  325. if( IsPerspective())
  326. {
  327. // rotate the viewer
  328. sv_plViewer.Rotate_HPB( ANGLE3D( AngleDeg(-fdX), AngleDeg(-fdY), AngleDeg(-fdZ)));
  329. }
  330. // if is isometric
  331. else
  332. {
  333. // can't rotate isometric projections
  334. }
  335. }
  336. // translate a placement in given system
  337. void CSlaveViewer::TranslatePlacement_OtherSystem(CPlacement3D &plToTranslate,
  338. CPlacement3D &plOtherSystem,
  339. PIX pixDI, PIX pixDJ, PIX pixDK)
  340. {
  341. FLOAT fZoom = GetZoomFactor();
  342. // project the placement to the viewer's system
  343. plToTranslate.AbsoluteToRelative(sv_plViewer);
  344. // project the placement to the given system
  345. plToTranslate.AbsoluteToRelative(plOtherSystem);
  346. // translate it
  347. plToTranslate.Translate_AbsoluteSystem( FLOAT3D(pixDI/fZoom, -pixDJ/fZoom, pixDK/fZoom));
  348. // project the placement back from given system
  349. plToTranslate.RelativeToAbsolute(plOtherSystem);
  350. // project the placement back from viewer's system
  351. plToTranslate.RelativeToAbsolute(sv_plViewer);
  352. }
  353. // translate a placement in viewer's system
  354. void CSlaveViewer::TranslatePlacement_OwnSystem(CPlacement3D &plToTranslate,
  355. PIX pixDI, PIX pixDJ, PIX pixDK)
  356. {
  357. FLOAT fZoom = GetZoomFactor();
  358. // project the placement to the viewer's system
  359. plToTranslate.AbsoluteToRelative(sv_plViewer);
  360. // translate it
  361. plToTranslate.Translate_AbsoluteSystem( FLOAT3D(pixDI/fZoom, -pixDJ/fZoom, pixDK/fZoom));
  362. // project the placement back from viewer's system
  363. plToTranslate.RelativeToAbsolute(sv_plViewer);
  364. }
  365. // convert offset from pixels to meters
  366. FLOAT CSlaveViewer::PixelsToMeters(PIX pix)
  367. {
  368. FLOAT fZoom = GetZoomFactor();
  369. return pix/fZoom;
  370. }
  371. // translate a placement in viewer's system
  372. void CSlaveViewer::RotatePlacement_HPB(CPlacement3D &plToRotate,
  373. PIX pixDI, PIX pixDJ, PIX pixDK)
  374. {
  375. // project the placement to the viewer's system
  376. plToRotate.AbsoluteToRelative(sv_plViewer);
  377. // rotate it
  378. plToRotate.Rotate_HPB( ANGLE3D( AngleDeg((FLOAT)-pixDI),
  379. AngleDeg((FLOAT)-pixDJ),
  380. AngleDeg((FLOAT)-pixDK)));
  381. // project the placement back from viewer's system
  382. plToRotate.RelativeToAbsolute(sv_plViewer);
  383. }
  384. // translate a placement in viewer's system
  385. void CSlaveViewer::RotatePlacement_TrackBall(CPlacement3D &plToRotate,
  386. PIX pixDI, PIX pixDJ, PIX pixDK)
  387. {
  388. // if viewer is perspective
  389. if( IsPerspective()) {
  390. // project the placement to the viewer's system
  391. plToRotate.AbsoluteToRelative(sv_plViewer);
  392. // rotate it
  393. plToRotate.Rotate_TrackBall( ANGLE3D( AngleDeg((FLOAT)-pixDI),
  394. AngleDeg((FLOAT)-pixDJ),
  395. AngleDeg((FLOAT)-pixDK)));
  396. // project the placement back from viewer's system
  397. plToRotate.RelativeToAbsolute(sv_plViewer);
  398. // if viewer is isometric
  399. } else {
  400. // project the placement to the viewer's system
  401. plToRotate.AbsoluteToRelative(sv_plViewer);
  402. // rotate it only around banking axis
  403. plToRotate.Rotate_TrackBall( ANGLE3D( 0,0, AngleDeg((FLOAT)-pixDI)));
  404. // project the placement back from viewer's system
  405. plToRotate.RelativeToAbsolute(sv_plViewer);
  406. }
  407. }