llviewercamera.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:23k
源码类别:

游戏引擎

开发平台:

C++ Builder

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