PageRenderTime 39ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llviewercamera.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 892 lines | 670 code | 138 blank | 84 comment | 82 complexity | b82f18bd8a342b1700cd0ba4b2385adb MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llviewercamera.cpp
  3. * @brief LLViewerCamera class implementation
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #define LLVIEWERCAMERA_CPP
  28. #include "llviewercamera.h"
  29. // Viewer includes
  30. #include "llagent.h"
  31. #include "llagentcamera.h"
  32. #include "llmatrix4a.h"
  33. #include "llviewercontrol.h"
  34. #include "llviewerobjectlist.h"
  35. #include "llviewerregion.h"
  36. #include "llviewerwindow.h"
  37. #include "llvovolume.h"
  38. #include "llworld.h"
  39. #include "lltoolmgr.h"
  40. #include "llviewerjoystick.h"
  41. // Linden library includes
  42. #include "lldrawable.h"
  43. #include "llface.h"
  44. #include "llgl.h"
  45. #include "llglheaders.h"
  46. #include "llquaternion.h"
  47. #include "llwindow.h" // getPixelAspectRatio()
  48. // System includes
  49. #include <iomanip> // for setprecision
  50. U32 LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
  51. //glu pick matrix implementation borrowed from Mesa3D
  52. glh::matrix4f gl_pick_matrix(GLfloat x, GLfloat y, GLfloat width, GLfloat height, GLint* viewport)
  53. {
  54. GLfloat m[16];
  55. GLfloat sx, sy;
  56. GLfloat tx, ty;
  57. sx = viewport[2] / width;
  58. sy = viewport[3] / height;
  59. tx = (viewport[2] + 2.f * (viewport[0] - x)) / width;
  60. ty = (viewport[3] + 2.f * (viewport[1] - y)) / height;
  61. #define M(row,col) m[col*4+row]
  62. M(0,0) = sx; M(0,1) = 0.f; M(0,2) = 0.f; M(0,3) = tx;
  63. M(1,0) = 0.f; M(1,1) = sy; M(1,2) = 0.f; M(1,3) = ty;
  64. M(2,0) = 0.f; M(2,1) = 0.f; M(2,2) = 1.f; M(2,3) = 0.f;
  65. M(3,0) = 0.f; M(3,1) = 0.f; M(3,2) = 0.f; M(3,3) = 1.f;
  66. #undef M
  67. return glh::matrix4f(m);
  68. }
  69. glh::matrix4f gl_perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar)
  70. {
  71. GLfloat f = 1.f/tanf(DEG_TO_RAD*fovy/2.f);
  72. return glh::matrix4f(f/aspect, 0, 0, 0,
  73. 0, f, 0, 0,
  74. 0, 0, (zFar+zNear)/(zNear-zFar), (2.f*zFar*zNear)/(zNear-zFar),
  75. 0, 0, -1.f, 0);
  76. }
  77. glh::matrix4f gl_lookat(LLVector3 eye, LLVector3 center, LLVector3 up)
  78. {
  79. LLVector3 f = center-eye;
  80. f.normVec();
  81. up.normVec();
  82. LLVector3 s = f % up;
  83. LLVector3 u = s % f;
  84. return glh::matrix4f(s[0], s[1], s[2], 0,
  85. u[0], u[1], u[2], 0,
  86. -f[0], -f[1], -f[2], 0,
  87. 0, 0, 0, 1);
  88. }
  89. // Build time optimization, generate this once in .cpp file
  90. template class LLViewerCamera* LLSingleton<class LLViewerCamera>::getInstance();
  91. LLViewerCamera::LLViewerCamera() : LLCamera()
  92. {
  93. calcProjection(getFar());
  94. mCameraFOVDefault = DEFAULT_FIELD_OF_VIEW;
  95. mCosHalfCameraFOV = cosf(mCameraFOVDefault * 0.5f);
  96. mPixelMeterRatio = 0.f;
  97. mScreenPixelArea = 0;
  98. mZoomFactor = 1.f;
  99. mZoomSubregion = 1;
  100. mAverageSpeed = 0.f;
  101. mAverageAngularSpeed = 0.f;
  102. gSavedSettings.getControl("CameraAngle")->getCommitSignal()->connect(boost::bind(&LLViewerCamera::updateCameraAngle, this, _2));
  103. }
  104. void LLViewerCamera::updateCameraLocation(const LLVector3 &center,
  105. const LLVector3 &up_direction,
  106. const LLVector3 &point_of_interest)
  107. {
  108. // do not update if avatar didn't move
  109. if (!LLViewerJoystick::getInstance()->getCameraNeedsUpdate())
  110. {
  111. return;
  112. }
  113. LLVector3 last_position;
  114. LLVector3 last_axis;
  115. last_position = getOrigin();
  116. last_axis = getAtAxis();
  117. mLastPointOfInterest = point_of_interest;
  118. // constrain to max distance from avatar
  119. LLVector3 camera_offset = center - gAgent.getPositionAgent();
  120. LLViewerRegion * regp = gAgent.getRegion();
  121. F32 water_height = (NULL != regp) ? regp->getWaterHeight() : 0.f;
  122. LLVector3 origin = center;
  123. if (origin.mV[2] > water_height)
  124. {
  125. origin.mV[2] = llmax(origin.mV[2], water_height+0.20f);
  126. }
  127. else
  128. {
  129. origin.mV[2] = llmin(origin.mV[2], water_height-0.20f);
  130. }
  131. setOriginAndLookAt(origin, up_direction, point_of_interest);
  132. mVelocityDir = center - last_position ;
  133. F32 dpos = mVelocityDir.normVec() ;
  134. LLQuaternion rotation;
  135. rotation.shortestArc(last_axis, getAtAxis());
  136. F32 x, y, z;
  137. F32 drot;
  138. rotation.getAngleAxis(&drot, &x, &y, &z);
  139. mVelocityStat.addValue(dpos);
  140. mAngularVelocityStat.addValue(drot);
  141. mAverageSpeed = mVelocityStat.getMeanPerSec() ;
  142. mAverageAngularSpeed = mAngularVelocityStat.getMeanPerSec() ;
  143. mCosHalfCameraFOV = cosf(0.5f * getView() * llmax(1.0f, getAspect()));
  144. // update pixel meter ratio using default fov, not modified one
  145. mPixelMeterRatio = getViewHeightInPixels()/ (2.f*tanf(mCameraFOVDefault*0.5));
  146. // update screen pixel area
  147. mScreenPixelArea =(S32)((F32)getViewHeightInPixels() * ((F32)getViewHeightInPixels() * getAspect()));
  148. }
  149. const LLMatrix4 &LLViewerCamera::getProjection() const
  150. {
  151. calcProjection(getFar());
  152. return mProjectionMatrix;
  153. }
  154. const LLMatrix4 &LLViewerCamera::getModelview() const
  155. {
  156. LLMatrix4 cfr(OGL_TO_CFR_ROTATION);
  157. getMatrixToLocal(mModelviewMatrix);
  158. mModelviewMatrix *= cfr;
  159. return mModelviewMatrix;
  160. }
  161. void LLViewerCamera::calcProjection(const F32 far_distance) const
  162. {
  163. F32 fov_y, z_far, z_near, aspect, f;
  164. fov_y = getView();
  165. z_far = far_distance;
  166. z_near = getNear();
  167. aspect = getAspect();
  168. f = 1/tan(fov_y*0.5f);
  169. mProjectionMatrix.setZero();
  170. mProjectionMatrix.mMatrix[0][0] = f/aspect;
  171. mProjectionMatrix.mMatrix[1][1] = f;
  172. mProjectionMatrix.mMatrix[2][2] = (z_far + z_near)/(z_near - z_far);
  173. mProjectionMatrix.mMatrix[3][2] = (2*z_far*z_near)/(z_near - z_far);
  174. mProjectionMatrix.mMatrix[2][3] = -1;
  175. }
  176. // Sets up opengl state for 3D drawing. If for selection, also
  177. // sets up a pick matrix. x and y are ignored if for_selection is false.
  178. // The picking region is centered on x,y and has the specified width and
  179. // height.
  180. //static
  181. void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, BOOL ortho, BOOL zflip, BOOL no_hacks)
  182. {
  183. GLint* viewport = (GLint*) gGLViewport;
  184. F64 model[16];
  185. F64 proj[16];
  186. for (U32 i = 0; i < 16; i++)
  187. {
  188. model[i] = (F64) gGLModelView[i];
  189. proj[i] = (F64) gGLProjection[i];
  190. }
  191. GLdouble objX,objY,objZ;
  192. LLVector3 frust[8];
  193. if (no_hacks)
  194. {
  195. gluUnProject(viewport[0],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
  196. frust[0].setVec((F32)objX,(F32)objY,(F32)objZ);
  197. gluUnProject(viewport[0]+viewport[2],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
  198. frust[1].setVec((F32)objX,(F32)objY,(F32)objZ);
  199. gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
  200. frust[2].setVec((F32)objX,(F32)objY,(F32)objZ);
  201. gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
  202. frust[3].setVec((F32)objX,(F32)objY,(F32)objZ);
  203. gluUnProject(viewport[0],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ);
  204. frust[4].setVec((F32)objX,(F32)objY,(F32)objZ);
  205. gluUnProject(viewport[0]+viewport[2],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ);
  206. frust[5].setVec((F32)objX,(F32)objY,(F32)objZ);
  207. gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ);
  208. frust[6].setVec((F32)objX,(F32)objY,(F32)objZ);
  209. gluUnProject(viewport[0],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ);
  210. frust[7].setVec((F32)objX,(F32)objY,(F32)objZ);
  211. }
  212. else if (zflip)
  213. {
  214. gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
  215. frust[0].setVec((F32)objX,(F32)objY,(F32)objZ);
  216. gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
  217. frust[1].setVec((F32)objX,(F32)objY,(F32)objZ);
  218. gluUnProject(viewport[0]+viewport[2],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
  219. frust[2].setVec((F32)objX,(F32)objY,(F32)objZ);
  220. gluUnProject(viewport[0],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
  221. frust[3].setVec((F32)objX,(F32)objY,(F32)objZ);
  222. gluUnProject(viewport[0],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ);
  223. frust[4].setVec((F32)objX,(F32)objY,(F32)objZ);
  224. gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ);
  225. frust[5].setVec((F32)objX,(F32)objY,(F32)objZ);
  226. gluUnProject(viewport[0]+viewport[2],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ);
  227. frust[6].setVec((F32)objX,(F32)objY,(F32)objZ);
  228. gluUnProject(viewport[0],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ);
  229. frust[7].setVec((F32)objX,(F32)objY,(F32)objZ);
  230. for (U32 i = 0; i < 4; i++)
  231. {
  232. frust[i+4] = frust[i+4]-frust[i];
  233. frust[i+4].normVec();
  234. frust[i+4] = frust[i] + frust[i+4]*camera.getFar();
  235. }
  236. }
  237. else
  238. {
  239. gluUnProject(viewport[0],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
  240. frust[0].setVec((F32)objX,(F32)objY,(F32)objZ);
  241. gluUnProject(viewport[0]+viewport[2],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
  242. frust[1].setVec((F32)objX,(F32)objY,(F32)objZ);
  243. gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
  244. frust[2].setVec((F32)objX,(F32)objY,(F32)objZ);
  245. gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
  246. frust[3].setVec((F32)objX,(F32)objY,(F32)objZ);
  247. if (ortho)
  248. {
  249. LLVector3 far_shift = camera.getAtAxis()*camera.getFar()*2.f;
  250. for (U32 i = 0; i < 4; i++)
  251. {
  252. frust[i+4] = frust[i] + far_shift;
  253. }
  254. }
  255. else
  256. {
  257. for (U32 i = 0; i < 4; i++)
  258. {
  259. LLVector3 vec = frust[i] - camera.getOrigin();
  260. vec.normVec();
  261. frust[i+4] = camera.getOrigin() + vec*camera.getFar();
  262. }
  263. }
  264. }
  265. camera.calcAgentFrustumPlanes(frust);
  266. }
  267. void LLViewerCamera::setPerspective(BOOL for_selection,
  268. S32 x, S32 y_from_bot, S32 width, S32 height,
  269. BOOL limit_select_distance,
  270. F32 z_near, F32 z_far)
  271. {
  272. F32 fov_y, aspect;
  273. fov_y = RAD_TO_DEG * getView();
  274. BOOL z_default_near, z_default_far = FALSE;
  275. if (z_far <= 0)
  276. {
  277. z_default_far = TRUE;
  278. z_far = getFar();
  279. }
  280. if (z_near <= 0)
  281. {
  282. z_default_near = TRUE;
  283. z_near = getNear();
  284. }
  285. aspect = getAspect();
  286. // Load camera view matrix
  287. gGL.matrixMode(LLRender::MM_PROJECTION);
  288. gGL.loadIdentity();
  289. glh::matrix4f proj_mat;
  290. if (for_selection)
  291. {
  292. // make a tiny little viewport
  293. // anything drawn into this viewport will be "selected"
  294. GLint viewport[4];
  295. viewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
  296. viewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
  297. viewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
  298. viewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
  299. proj_mat = gl_pick_matrix(x+width/2.f, y_from_bot+height/2.f, (GLfloat) width, (GLfloat) height, viewport);
  300. if (limit_select_distance)
  301. {
  302. // ...select distance from control
  303. z_far = gSavedSettings.getF32("MaxSelectDistance");
  304. }
  305. else
  306. {
  307. z_far = gAgentCamera.mDrawDistance;
  308. }
  309. }
  310. else
  311. {
  312. // Only override the far clip if it's not passed in explicitly.
  313. if (z_default_far)
  314. {
  315. z_far = MAX_FAR_CLIP;
  316. }
  317. glViewport(x, y_from_bot, width, height);
  318. gGLViewport[0] = x;
  319. gGLViewport[1] = y_from_bot;
  320. gGLViewport[2] = width;
  321. gGLViewport[3] = height;
  322. }
  323. if (mZoomFactor > 1.f)
  324. {
  325. float offset = mZoomFactor - 1.f;
  326. int pos_y = mZoomSubregion / llceil(mZoomFactor);
  327. int pos_x = mZoomSubregion - (pos_y*llceil(mZoomFactor));
  328. glh::matrix4f translate;
  329. translate.set_translate(glh::vec3f(offset - (F32)pos_x * 2.f, offset - (F32)pos_y * 2.f, 0.f));
  330. glh::matrix4f scale;
  331. scale.set_scale(glh::vec3f(mZoomFactor, mZoomFactor, 1.f));
  332. proj_mat = scale*proj_mat;
  333. proj_mat = translate*proj_mat;
  334. }
  335. calcProjection(z_far); // Update the projection matrix cache
  336. proj_mat *= gl_perspective(fov_y,aspect,z_near,z_far);
  337. gGL.loadMatrix(proj_mat.m);
  338. for (U32 i = 0; i < 16; i++)
  339. {
  340. gGLProjection[i] = proj_mat.m[i];
  341. }
  342. gGL.matrixMode(LLRender::MM_MODELVIEW);
  343. glh::matrix4f modelview((GLfloat*) OGL_TO_CFR_ROTATION);
  344. GLfloat ogl_matrix[16];
  345. getOpenGLTransform(ogl_matrix);
  346. modelview *= glh::matrix4f(ogl_matrix);
  347. gGL.loadMatrix(modelview.m);
  348. if (for_selection && (width > 1 || height > 1))
  349. {
  350. // NB: as of this writing, i believe the code below is broken (doesn't take into account the world view, assumes entire window)
  351. // however, it is also unused (the GL matricies are used for selection, (see LLCamera::sphereInFrustum())) and so i'm not
  352. // comfortable hacking on it.
  353. calculateFrustumPlanesFromWindow((F32)(x - width / 2) / (F32)gViewerWindow->getWindowWidthScaled() - 0.5f,
  354. (F32)(y_from_bot - height / 2) / (F32)gViewerWindow->getWindowHeightScaled() - 0.5f,
  355. (F32)(x + width / 2) / (F32)gViewerWindow->getWindowWidthScaled() - 0.5f,
  356. (F32)(y_from_bot + height / 2) / (F32)gViewerWindow->getWindowHeightScaled() - 0.5f);
  357. }
  358. // if not picking and not doing a snapshot, cache various GL matrices
  359. if (!for_selection && mZoomFactor == 1.f)
  360. {
  361. // Save GL matrices for access elsewhere in code, especially project_world_to_screen
  362. for (U32 i = 0; i < 16; i++)
  363. {
  364. gGLModelView[i] = modelview.m[i];
  365. }
  366. }
  367. updateFrustumPlanes(*this);
  368. }
  369. // Uses the last GL matrices set in set_perspective to project a point from
  370. // screen coordinates to the agent's region.
  371. void LLViewerCamera::projectScreenToPosAgent(const S32 screen_x, const S32 screen_y, LLVector3* pos_agent) const
  372. {
  373. GLdouble x, y, z;
  374. F64 mdlv[16];
  375. F64 proj[16];
  376. for (U32 i = 0; i < 16; i++)
  377. {
  378. mdlv[i] = (F64) gGLModelView[i];
  379. proj[i] = (F64) gGLProjection[i];
  380. }
  381. gluUnProject(
  382. GLdouble(screen_x), GLdouble(screen_y), 0.0,
  383. mdlv, proj, (GLint*)gGLViewport,
  384. &x,
  385. &y,
  386. &z );
  387. pos_agent->setVec( (F32)x, (F32)y, (F32)z );
  388. }
  389. // Uses the last GL matrices set in set_perspective to project a point from
  390. // the agent's region space to screen coordinates. Returns TRUE if point in within
  391. // the current window.
  392. BOOL LLViewerCamera::projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoordGL &out_point, const BOOL clamp) const
  393. {
  394. BOOL in_front = TRUE;
  395. GLdouble x, y, z; // object's window coords, GL-style
  396. LLVector3 dir_to_point = pos_agent - getOrigin();
  397. dir_to_point /= dir_to_point.magVec();
  398. if (dir_to_point * getAtAxis() < 0.f)
  399. {
  400. if (clamp)
  401. {
  402. return FALSE;
  403. }
  404. else
  405. {
  406. in_front = FALSE;
  407. }
  408. }
  409. LLRect world_view_rect = gViewerWindow->getWorldViewRectRaw();
  410. S32 viewport[4];
  411. viewport[0] = world_view_rect.mLeft;
  412. viewport[1] = world_view_rect.mBottom;
  413. viewport[2] = world_view_rect.getWidth();
  414. viewport[3] = world_view_rect.getHeight();
  415. F64 mdlv[16];
  416. F64 proj[16];
  417. for (U32 i = 0; i < 16; i++)
  418. {
  419. mdlv[i] = (F64) gGLModelView[i];
  420. proj[i] = (F64) gGLProjection[i];
  421. }
  422. if (GL_TRUE == gluProject(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ],
  423. mdlv, proj, (GLint*)viewport,
  424. &x, &y, &z))
  425. {
  426. // convert screen coordinates to virtual UI coordinates
  427. x /= gViewerWindow->getDisplayScale().mV[VX];
  428. y /= gViewerWindow->getDisplayScale().mV[VY];
  429. // should now have the x,y coords of grab_point in screen space
  430. LLRect world_rect = gViewerWindow->getWorldViewRectScaled();
  431. // convert to pixel coordinates
  432. S32 int_x = lltrunc(x);
  433. S32 int_y = lltrunc(y);
  434. BOOL valid = TRUE;
  435. if (clamp)
  436. {
  437. if (int_x < world_rect.mLeft)
  438. {
  439. out_point.mX = world_rect.mLeft;
  440. valid = FALSE;
  441. }
  442. else if (int_x > world_rect.mRight)
  443. {
  444. out_point.mX = world_rect.mRight;
  445. valid = FALSE;
  446. }
  447. else
  448. {
  449. out_point.mX = int_x;
  450. }
  451. if (int_y < world_rect.mBottom)
  452. {
  453. out_point.mY = world_rect.mBottom;
  454. valid = FALSE;
  455. }
  456. else if (int_y > world_rect.mTop)
  457. {
  458. out_point.mY = world_rect.mTop;
  459. valid = FALSE;
  460. }
  461. else
  462. {
  463. out_point.mY = int_y;
  464. }
  465. return valid;
  466. }
  467. else
  468. {
  469. out_point.mX = int_x;
  470. out_point.mY = int_y;
  471. if (int_x < world_rect.mLeft)
  472. {
  473. valid = FALSE;
  474. }
  475. else if (int_x > world_rect.mRight)
  476. {
  477. valid = FALSE;
  478. }
  479. if (int_y < world_rect.mBottom)
  480. {
  481. valid = FALSE;
  482. }
  483. else if (int_y > world_rect.mTop)
  484. {
  485. valid = FALSE;
  486. }
  487. return in_front && valid;
  488. }
  489. }
  490. else
  491. {
  492. return FALSE;
  493. }
  494. }
  495. // Uses the last GL matrices set in set_perspective to project a point from
  496. // the agent's region space to the nearest edge in screen coordinates.
  497. // Returns TRUE if projection succeeds.
  498. BOOL LLViewerCamera::projectPosAgentToScreenEdge(const LLVector3 &pos_agent,
  499. LLCoordGL &out_point) const
  500. {
  501. LLVector3 dir_to_point = pos_agent - getOrigin();
  502. dir_to_point /= dir_to_point.magVec();
  503. BOOL in_front = TRUE;
  504. if (dir_to_point * getAtAxis() < 0.f)
  505. {
  506. in_front = FALSE;
  507. }
  508. LLRect world_view_rect = gViewerWindow->getWorldViewRectRaw();
  509. S32 viewport[4];
  510. viewport[0] = world_view_rect.mLeft;
  511. viewport[1] = world_view_rect.mBottom;
  512. viewport[2] = world_view_rect.getWidth();
  513. viewport[3] = world_view_rect.getHeight();
  514. GLdouble x, y, z; // object's window coords, GL-style
  515. F64 mdlv[16];
  516. F64 proj[16];
  517. for (U32 i = 0; i < 16; i++)
  518. {
  519. mdlv[i] = (F64) gGLModelView[i];
  520. proj[i] = (F64) gGLProjection[i];
  521. }
  522. if (GL_TRUE == gluProject(pos_agent.mV[VX], pos_agent.mV[VY],
  523. pos_agent.mV[VZ], mdlv,
  524. proj, (GLint*)viewport,
  525. &x, &y, &z))
  526. {
  527. x /= gViewerWindow->getDisplayScale().mV[VX];
  528. y /= gViewerWindow->getDisplayScale().mV[VY];
  529. // should now have the x,y coords of grab_point in screen space
  530. const LLRect& world_rect = gViewerWindow->getWorldViewRectScaled();
  531. // ...sanity check
  532. S32 int_x = lltrunc(x);
  533. S32 int_y = lltrunc(y);
  534. // find the center
  535. GLdouble center_x = (GLdouble)world_rect.getCenterX();
  536. GLdouble center_y = (GLdouble)world_rect.getCenterY();
  537. if (x == center_x && y == center_y)
  538. {
  539. // can't project to edge from exact center
  540. return FALSE;
  541. }
  542. // find the line from center to local
  543. GLdouble line_x = x - center_x;
  544. GLdouble line_y = y - center_y;
  545. int_x = lltrunc(center_x);
  546. int_y = lltrunc(center_y);
  547. if (0.f == line_x)
  548. {
  549. // the slope of the line is undefined
  550. if (line_y > 0.f)
  551. {
  552. int_y = world_rect.mTop;
  553. }
  554. else
  555. {
  556. int_y = world_rect.mBottom;
  557. }
  558. }
  559. else if (0 == world_rect.getWidth())
  560. {
  561. // the diagonal slope of the view is undefined
  562. if (y < world_rect.mBottom)
  563. {
  564. int_y = world_rect.mBottom;
  565. }
  566. else if ( y > world_rect.mTop)
  567. {
  568. int_y = world_rect.mTop;
  569. }
  570. }
  571. else
  572. {
  573. F32 line_slope = (F32)(line_y / line_x);
  574. F32 rect_slope = ((F32)world_rect.getHeight()) / ((F32)world_rect.getWidth());
  575. if (fabs(line_slope) > rect_slope)
  576. {
  577. if (line_y < 0.f)
  578. {
  579. // bottom
  580. int_y = world_rect.mBottom;
  581. }
  582. else
  583. {
  584. // top
  585. int_y = world_rect.mTop;
  586. }
  587. int_x = lltrunc(((GLdouble)int_y - center_y) / line_slope + center_x);
  588. }
  589. else if (fabs(line_slope) < rect_slope)
  590. {
  591. if (line_x < 0.f)
  592. {
  593. // left
  594. int_x = world_rect.mLeft;
  595. }
  596. else
  597. {
  598. // right
  599. int_x = world_rect.mRight;
  600. }
  601. int_y = lltrunc(((GLdouble)int_x - center_x) * line_slope + center_y);
  602. }
  603. else
  604. {
  605. // exactly parallel ==> push to the corners
  606. if (line_x > 0.f)
  607. {
  608. int_x = world_rect.mRight;
  609. }
  610. else
  611. {
  612. int_x = world_rect.mLeft;
  613. }
  614. if (line_y > 0.0f)
  615. {
  616. int_y = world_rect.mTop;
  617. }
  618. else
  619. {
  620. int_y = world_rect.mBottom;
  621. }
  622. }
  623. }
  624. if (!in_front)
  625. {
  626. int_x = world_rect.mLeft + world_rect.mRight - int_x;
  627. int_y = world_rect.mBottom + world_rect.mTop - int_y;
  628. }
  629. out_point.mX = int_x + world_rect.mLeft;
  630. out_point.mY = int_y + world_rect.mBottom;
  631. return TRUE;
  632. }
  633. return FALSE;
  634. }
  635. void LLViewerCamera::getPixelVectors(const LLVector3 &pos_agent, LLVector3 &up, LLVector3 &right)
  636. {
  637. LLVector3 to_vec = pos_agent - getOrigin();
  638. F32 at_dist = to_vec * getAtAxis();
  639. F32 height_meters = at_dist* (F32)tan(getView()/2.f);
  640. F32 height_pixels = getViewHeightInPixels()/2.f;
  641. F32 pixel_aspect = gViewerWindow->getWindow()->getPixelAspectRatio();
  642. F32 meters_per_pixel = height_meters / height_pixels;
  643. up = getUpAxis() * meters_per_pixel * gViewerWindow->getDisplayScale().mV[VY];
  644. right = -1.f * pixel_aspect * meters_per_pixel * getLeftAxis() * gViewerWindow->getDisplayScale().mV[VX];
  645. }
  646. LLVector3 LLViewerCamera::roundToPixel(const LLVector3 &pos_agent)
  647. {
  648. F32 dist = (pos_agent - getOrigin()).magVec();
  649. // Convert to screen space and back, preserving the depth.
  650. LLCoordGL screen_point;
  651. if (!projectPosAgentToScreen(pos_agent, screen_point, FALSE))
  652. {
  653. // Off the screen, just return the original position.
  654. return pos_agent;
  655. }
  656. LLVector3 ray_dir;
  657. projectScreenToPosAgent(screen_point.mX, screen_point.mY, &ray_dir);
  658. ray_dir -= getOrigin();
  659. ray_dir.normVec();
  660. LLVector3 pos_agent_rounded = getOrigin() + ray_dir*dist;
  661. /*
  662. LLVector3 pixel_x, pixel_y;
  663. getPixelVectors(pos_agent_rounded, pixel_y, pixel_x);
  664. pos_agent_rounded += 0.5f*pixel_x, 0.5f*pixel_y;
  665. */
  666. return pos_agent_rounded;
  667. }
  668. BOOL LLViewerCamera::cameraUnderWater() const
  669. {
  670. if(!gAgent.getRegion())
  671. {
  672. return FALSE ;
  673. }
  674. return getOrigin().mV[VZ] < gAgent.getRegion()->getWaterHeight();
  675. }
  676. BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts)
  677. {
  678. S32 i, num_faces;
  679. LLDrawable* drawablep = volumep->mDrawable;
  680. if (!drawablep)
  681. {
  682. return FALSE;
  683. }
  684. LLVolume* volume = volumep->getVolume();
  685. if (!volume)
  686. {
  687. return FALSE;
  688. }
  689. LLVOVolume* vo_volume = (LLVOVolume*) volumep;
  690. vo_volume->updateRelativeXform();
  691. LLMatrix4 mat = vo_volume->getRelativeXform();
  692. LLMatrix4 render_mat(vo_volume->getRenderRotation(), LLVector4(vo_volume->getRenderPosition()));
  693. LLMatrix4a render_mata;
  694. render_mata.loadu(render_mat);
  695. LLMatrix4a mata;
  696. mata.loadu(mat);
  697. num_faces = volume->getNumVolumeFaces();
  698. for (i = 0; i < num_faces; i++)
  699. {
  700. const LLVolumeFace& face = volume->getVolumeFace(i);
  701. for (U32 v = 0; v < face.mNumVertices; v++)
  702. {
  703. const LLVector4a& src_vec = face.mPositions[v];
  704. LLVector4a vec;
  705. mata.affineTransform(src_vec, vec);
  706. if (drawablep->isActive())
  707. {
  708. LLVector4a t = vec;
  709. render_mata.affineTransform(t, vec);
  710. }
  711. BOOL in_frustum = pointInFrustum(LLVector3(vec.getF32ptr())) > 0;
  712. if (( !in_frustum && all_verts) ||
  713. (in_frustum && !all_verts))
  714. {
  715. return !all_verts;
  716. }
  717. }
  718. }
  719. return all_verts;
  720. }
  721. // changes local camera and broadcasts change
  722. /* virtual */ void LLViewerCamera::setView(F32 vertical_fov_rads)
  723. {
  724. F32 old_fov = LLViewerCamera::getInstance()->getView();
  725. // cap the FoV
  726. vertical_fov_rads = llclamp(vertical_fov_rads, getMinView(), getMaxView());
  727. if (vertical_fov_rads == old_fov) return;
  728. // send the new value to the simulator
  729. LLMessageSystem* msg = gMessageSystem;
  730. msg->newMessageFast(_PREHASH_AgentFOV);
  731. msg->nextBlockFast(_PREHASH_AgentData);
  732. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  733. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  734. msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode);
  735. msg->nextBlockFast(_PREHASH_FOVBlock);
  736. msg->addU32Fast(_PREHASH_GenCounter, 0);
  737. msg->addF32Fast(_PREHASH_VerticalAngle, vertical_fov_rads);
  738. gAgent.sendReliableMessage();
  739. // sync the camera with the new value
  740. LLCamera::setView(vertical_fov_rads); // call base implementation
  741. }
  742. void LLViewerCamera::setDefaultFOV(F32 vertical_fov_rads)
  743. {
  744. vertical_fov_rads = llclamp(vertical_fov_rads, getMinView(), getMaxView());
  745. setView(vertical_fov_rads);
  746. mCameraFOVDefault = vertical_fov_rads;
  747. mCosHalfCameraFOV = cosf(mCameraFOVDefault * 0.5f);
  748. }
  749. // static
  750. void LLViewerCamera::updateCameraAngle( void* user_data, const LLSD& value)
  751. {
  752. LLViewerCamera* self=(LLViewerCamera*)user_data;
  753. self->setDefaultFOV(value.asReal());
  754. }