llviewercamera.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. /**
  2. * @file llviewercamera.cpp
  3. * @brief LLViewerCamera class implementation
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewergpl$
  6. *
  7. * Copyright (c) 2002-2009, 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. #include "llviewercamera.h"
  34. #include "llgl.h"
  35. #include "llmatrix4a.h"
  36. #include "llagent.h"
  37. #include "lldrawable.h"
  38. #include "llface.h"
  39. #include "llpipeline.h"
  40. //MK
  41. #include "mkrlinterface.h"
  42. //mk
  43. #include "lltoolmgr.h"
  44. #include "llviewercontrol.h"
  45. #include "llviewerdisplay.h" // For gCubeSnapshot
  46. #include "llviewerjoystick.h"
  47. #include "llviewerobjectlist.h"
  48. #include "llviewerregion.h"
  49. #include "llviewerwindow.h"
  50. #include "llvovolume.h"
  51. #include "llworld.h"
  52. LLViewerCamera gViewerCamera;
  53. // Static members
  54. LLStat LLViewerCamera::sVelocityStat;
  55. LLStat LLViewerCamera::sAngularVelocityStat;
  56. S32 LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
  57. LLViewerCamera::LLViewerCamera()
  58. : LLCamera()
  59. {
  60. calcProjection(getFar());
  61. mCameraFOVDefault = DEFAULT_FIELD_OF_VIEW;
  62. mPrevCameraFOVDefault = DEFAULT_FIELD_OF_VIEW;
  63. mCosHalfCameraFOV = cosf(mCameraFOVDefault * 0.5f);
  64. mPixelMeterRatio = 0.f;
  65. mScreenPixelArea = 0;
  66. mZoomFactor = 1.f;
  67. mZoomSubregion = 1;
  68. mAverageSpeed = 0.f;
  69. mAverageAngularSpeed = 0.f;
  70. }
  71. //static
  72. void LLViewerCamera::initClass()
  73. {
  74. LLControlVariable* ctrlp = gSavedSettings.getControl("CameraAngle");
  75. if (!ctrlp)
  76. {
  77. llwarns << "Missing CameraAngle debug setting." << llendl;
  78. return;
  79. }
  80. ctrlp->getSignal()->connect(boost::bind(&LLViewerCamera::updateCameraAngle,
  81. _2));
  82. llinfos << "Viewer camera initialized." << llendl;
  83. }
  84. //static
  85. void LLViewerCamera::updateCameraAngle(const LLSD& value)
  86. {
  87. gViewerCamera.setDefaultFOV(value.asReal());
  88. }
  89. void LLViewerCamera::updateCameraLocation(const LLVector3& center,
  90. const LLVector3& up_direction,
  91. const LLVector3& point_of_interest)
  92. {
  93. // Do not update if we are in build mode AND avatar did not move
  94. if (gToolMgr.inBuildMode() &&
  95. !LLViewerJoystick::getInstance()->getCameraNeedsUpdate())
  96. {
  97. return;
  98. }
  99. LLVector3 last_position;
  100. LLVector3 last_axis;
  101. last_position = getOrigin();
  102. last_axis = getAtAxis();
  103. mLastPointOfInterest = point_of_interest;
  104. // Constrain to max distance from avatar
  105. LLViewerRegion* regionp = gWorld.getRegionFromPosAgent(getOrigin());
  106. if (!regionp)
  107. {
  108. regionp = gAgent.getRegion();
  109. }
  110. F32 water_height = regionp ? regionp->getWaterHeight() : 0.f;
  111. LLVector3 origin = center;
  112. if (origin.mV[2] > water_height)
  113. {
  114. origin.mV[2] = llmax(origin.mV[2], water_height + 0.20f);
  115. }
  116. else
  117. {
  118. origin.mV[2] = llmin(origin.mV[2], water_height - 0.20f);
  119. }
  120. setOriginAndLookAt(origin, up_direction, point_of_interest);
  121. mVelocityDir = center - last_position;
  122. F32 dpos = mVelocityDir.normalize();
  123. LLQuaternion rotation;
  124. rotation.shortestArc(last_axis, getAtAxis());
  125. F32 x, y, z;
  126. F32 drot;
  127. rotation.getAngleAxis(&drot, &x, &y, &z);
  128. sVelocityStat.addValue(dpos);
  129. sAngularVelocityStat.addValue(drot);
  130. mAverageSpeed = sVelocityStat.getMeanPerSec();
  131. mAverageAngularSpeed = sAngularVelocityStat.getMeanPerSec();
  132. mCosHalfCameraFOV = cosf(0.5f * getView() * llmax(1.0f, getAspect()));
  133. // update pixel meter ratio using default fov, not modified one
  134. mPixelMeterRatio = getViewHeightInPixels() / (2.f * tanf(mCameraFOVDefault * 0.5));
  135. // update screen pixel area
  136. mScreenPixelArea = (S32)((F32)getViewHeightInPixels() *
  137. ((F32)getViewHeightInPixels() * getAspect()));
  138. }
  139. const LLMatrix4& LLViewerCamera::getProjection() const
  140. {
  141. calcProjection(getFar());
  142. return mProjectionMatrix;
  143. }
  144. const LLMatrix4& LLViewerCamera::getModelview() const
  145. {
  146. LLMatrix4 cfr(OGL_TO_CFR_ROTATION);
  147. getMatrixToLocal(mModelviewMatrix);
  148. mModelviewMatrix *= cfr;
  149. return mModelviewMatrix;
  150. }
  151. void LLViewerCamera::calcProjection(F32 far_distance) const
  152. {
  153. F32 fov_y = getView();
  154. F32 z_far = far_distance;
  155. F32 z_near = getNear();
  156. F32 aspect = getAspect();
  157. F32 f = 1.f / tanf(fov_y * 0.5f);
  158. mProjectionMatrix.setZero();
  159. mProjectionMatrix.mMatrix[0][0] = f / aspect;
  160. mProjectionMatrix.mMatrix[1][1] = f;
  161. mProjectionMatrix.mMatrix[2][2] = (z_far + z_near) / (z_near - z_far);
  162. mProjectionMatrix.mMatrix[3][2] = 2 * z_far * z_near / (z_near - z_far);
  163. mProjectionMatrix.mMatrix[2][3] = -1;
  164. }
  165. //static
  166. void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, bool ortho,
  167. bool zflip, bool no_hacks)
  168. {
  169. LLVector3 frust[8];
  170. LLRect view_port(gGLViewport[0], gGLViewport[1] + gGLViewport[3],
  171. gGLViewport[0] + gGLViewport[2], gGLViewport[1]);
  172. if (no_hacks)
  173. {
  174. gGL.unprojectf(LLVector3(view_port.mLeft, view_port.mBottom, 0.f),
  175. gGLModelView, gGLProjection, view_port, frust[0]);
  176. gGL.unprojectf(LLVector3(view_port.mRight, view_port.mBottom, 0.f),
  177. gGLModelView, gGLProjection, view_port, frust[1]);
  178. gGL.unprojectf(LLVector3(view_port.mRight, view_port.mTop, 0.f),
  179. gGLModelView, gGLProjection, view_port, frust[2]);
  180. gGL.unprojectf(LLVector3(view_port.mLeft, view_port.mTop, 0.f),
  181. gGLModelView, gGLProjection, view_port, frust[3]);
  182. gGL.unprojectf(LLVector3(view_port.mLeft, view_port.mBottom, 1.f),
  183. gGLModelView, gGLProjection, view_port, frust[4]);
  184. gGL.unprojectf(LLVector3(view_port.mRight, view_port.mBottom, 1.f),
  185. gGLModelView, gGLProjection, view_port, frust[5]);
  186. gGL.unprojectf(LLVector3(view_port.mRight, view_port.mTop, 1.f),
  187. gGLModelView, gGLProjection, view_port, frust[6]);
  188. gGL.unprojectf(LLVector3(view_port.mLeft, view_port.mTop, 1.f),
  189. gGLModelView, gGLProjection, view_port, frust[7]);
  190. }
  191. else if (zflip)
  192. {
  193. gGL.unprojectf(LLVector3(view_port.mLeft, view_port.mTop, 0.f),
  194. gGLModelView, gGLProjection, view_port, frust[0]);
  195. gGL.unprojectf(LLVector3(view_port.mRight, view_port.mTop, 0.f),
  196. gGLModelView, gGLProjection, view_port, frust[1]);
  197. gGL.unprojectf(LLVector3(view_port.mRight, view_port.mBottom, 0.f),
  198. gGLModelView, gGLProjection, view_port, frust[2]);
  199. gGL.unprojectf(LLVector3(view_port.mLeft, view_port.mBottom, 0.f),
  200. gGLModelView, gGLProjection, view_port, frust[3]);
  201. gGL.unprojectf(LLVector3(view_port.mLeft, view_port.mTop, 1.f),
  202. gGLModelView, gGLProjection, view_port, frust[4]);
  203. gGL.unprojectf(LLVector3(view_port.mRight, view_port.mTop, 1.f),
  204. gGLModelView, gGLProjection, view_port, frust[5]);
  205. gGL.unprojectf(LLVector3(view_port.mRight, view_port.mBottom, 1.f),
  206. gGLModelView, gGLProjection, view_port, frust[6]);
  207. gGL.unprojectf(LLVector3(view_port.mLeft, view_port.mBottom, 1.f),
  208. gGLModelView, gGLProjection, view_port, frust[7]);
  209. for (U32 i = 0; i < 4; ++i)
  210. {
  211. frust[i + 4] = frust[i + 4] - frust[i];
  212. frust[i + 4].normalize();
  213. frust[i + 4] = frust[i] + frust[i + 4] * camera.getFar();
  214. }
  215. }
  216. else
  217. {
  218. gGL.unprojectf(LLVector3(view_port.mLeft, view_port.mBottom, 0.f),
  219. gGLModelView, gGLProjection, view_port, frust[0]);
  220. gGL.unprojectf(LLVector3(view_port.mRight, view_port.mBottom, 0.f),
  221. gGLModelView, gGLProjection, view_port, frust[1]);
  222. gGL.unprojectf(LLVector3(view_port.mRight, view_port.mTop, 0.f),
  223. gGLModelView, gGLProjection, view_port, frust[2]);
  224. gGL.unprojectf(LLVector3(view_port.mLeft, view_port.mTop, 0.f),
  225. gGLModelView, gGLProjection, view_port, frust[3]);
  226. if (ortho)
  227. {
  228. LLVector3 far_shift = camera.getAtAxis() * camera.getFar() * 2.f;
  229. for (U32 i = 0; i < 4; ++i)
  230. {
  231. frust[i + 4] = frust[i] + far_shift;
  232. }
  233. }
  234. else
  235. {
  236. for (U32 i = 0; i < 4; ++i)
  237. {
  238. LLVector3 vec = frust[i] - camera.getOrigin();
  239. vec.normalize();
  240. frust[i + 4] = camera.getOrigin() + vec * camera.getFar();
  241. }
  242. }
  243. }
  244. camera.calcAgentFrustumPlanes(frust);
  245. }
  246. void LLViewerCamera::setPerspective(bool for_selection, S32 x, S32 y_from_bot,
  247. S32 width, S32 height, bool limit_sel_dist,
  248. F32 z_near, F32 z_far)
  249. {
  250. F32 fov_y = RAD_TO_DEG * getView();
  251. bool z_default_far = false;
  252. if (z_far <= 0)
  253. {
  254. z_default_far = true;
  255. z_far = getFar();
  256. }
  257. if (z_near <= 0)
  258. {
  259. z_near = getNear();
  260. }
  261. F32 aspect = getAspect();
  262. // Load camera view matrix
  263. gGL.matrixMode(LLRender::MM_PROJECTION);
  264. gGL.loadIdentity();
  265. LLMatrix4a proj_mat;
  266. proj_mat.setIdentity();
  267. if (for_selection)
  268. {
  269. // Make a tiny little viewport; anything drawn into this viewport will
  270. // be "selected"
  271. const LLRect& rect = gViewerWindowp->getWindowRect();
  272. F32 scale_x = rect.getWidth() / F32(width);
  273. F32 scale_y = rect.getHeight() / F32(height);
  274. F32 trans_x = scale_x + 2.f * (rect.mLeft - x) / (F32)width - 1.f;
  275. F32 trans_y = scale_y + 2.f * (rect.mBottom - y_from_bot) /
  276. (F32)height - 1.f;
  277. // Generate a pick matrix
  278. proj_mat.applyScaleAffine(scale_x, scale_y, 1.f);
  279. proj_mat.setTranslateAffine(LLVector3(trans_x, trans_y, 0.f));
  280. if (limit_sel_dist)
  281. {
  282. // Select distance from control
  283. static LLCachedControl<F32> max_select_distance(gSavedSettings,
  284. "MaxSelectDistance");
  285. z_far = llclamp((F32)max_select_distance, 32.f, 512.f);
  286. }
  287. else
  288. {
  289. z_far = gAgent.mDrawDistance;
  290. }
  291. }
  292. else
  293. {
  294. // Only override the far clip if it's not passed in explicitly.
  295. if (z_default_far)
  296. {
  297. z_far = MAX_FAR_CLIP;
  298. }
  299. glViewport(x, y_from_bot, width, height);
  300. gGLViewport[0] = x;
  301. gGLViewport[1] = y_from_bot;
  302. gGLViewport[2] = width;
  303. gGLViewport[3] = height;
  304. }
  305. if (mZoomFactor > 1.f)
  306. {
  307. F32 offset = mZoomFactor - 1.f;
  308. S32 pos_y = mZoomSubregion / llceil(mZoomFactor);
  309. S32 pos_x = mZoomSubregion - pos_y * llceil(mZoomFactor);
  310. proj_mat.applyTranslationAffine(offset - (F32)pos_x * 2.f,
  311. offset - (F32)pos_y * 2.f, 0.f);
  312. proj_mat.applyScaleAffine(mZoomFactor, mZoomFactor, 1.f);
  313. }
  314. calcProjection(z_far); // Update the projection matrix cache
  315. proj_mat.mul(gl_perspective(fov_y, aspect, z_near, z_far));
  316. gGL.loadMatrix(proj_mat);
  317. gGLProjection = proj_mat;
  318. gGL.matrixMode(LLRender::MM_MODELVIEW);
  319. LLMatrix4a ogl_matrix;
  320. getOpenGLTransform(ogl_matrix.getF32ptr());
  321. LLMatrix4a modelview;
  322. modelview.setMul(OGL_TO_CFR_ROT4A, ogl_matrix);
  323. gGL.loadMatrix(modelview);
  324. if (for_selection && (width > 1 || height > 1))
  325. {
  326. F32 wwidth = (F32)gViewerWindowp->getWindowWidth();
  327. F32 wheight = (F32)gViewerWindowp->getWindowHeight();
  328. calculateFrustumPlanesFromWindow((F32)(x - width / 2) / wwidth - 0.5f,
  329. (F32)(y_from_bot - height / 2) / wheight - 0.5f,
  330. (F32)(x + width / 2) / wwidth - 0.5f,
  331. (F32)(y_from_bot + height / 2) / wheight - 0.5f);
  332. }
  333. // if not picking and not doing a snapshot, cache various GL matrices
  334. if (!for_selection && mZoomFactor == 1.f)
  335. {
  336. // Save GL matrices for access elsewhere in code, especially
  337. // project_world_to_screen
  338. gGLModelView = modelview;
  339. }
  340. updateFrustumPlanes(*this);
  341. }
  342. // Uses the last GL matrices set in set_perspective to project a point from
  343. // screen coordinates to the agent's region.
  344. void LLViewerCamera::projectScreenToPosAgent(S32 screen_x, S32 screen_y,
  345. LLVector3* pos_agent) const
  346. {
  347. gGL.unprojectf(LLVector3(screen_x, screen_y, 0.f),
  348. gGLModelView, gGLProjection,
  349. LLRect(gGLViewport[0], gGLViewport[1] + gGLViewport[3],
  350. gGLViewport[0] + gGLViewport[2], gGLViewport[1]),
  351. *pos_agent);
  352. }
  353. // Uses the last GL matrices set in set_perspective to project a point from the
  354. // agent's region space to screen coordinates. Returns true if point in within
  355. // the current window.
  356. bool LLViewerCamera::projectPosAgentToScreen(const LLVector3& pos_agent,
  357. LLCoordGL& out_point,
  358. bool clamp) const
  359. {
  360. bool in_front = true;
  361. LLVector3 dir_to_point = pos_agent - getOrigin();
  362. dir_to_point /= dir_to_point.length();
  363. if (dir_to_point * getAtAxis() < 0.f)
  364. {
  365. if (clamp)
  366. {
  367. return false;
  368. }
  369. else
  370. {
  371. in_front = false;
  372. }
  373. }
  374. LLVector3 window_coordinates;
  375. if (gGL.projectf(pos_agent, gGLModelView, gGLProjection,
  376. LLRect(gGLViewport[0], gGLViewport[1] + gGLViewport[3],
  377. gGLViewport[0] + gGLViewport[2], gGLViewport[1]),
  378. window_coordinates))
  379. {
  380. F32& x = window_coordinates.mV[VX];
  381. F32& y = window_coordinates.mV[VY];
  382. // convert screen coordinates to virtual UI coordinates
  383. x /= gViewerWindowp->getDisplayScale().mV[VX];
  384. y /= gViewerWindowp->getDisplayScale().mV[VY];
  385. // should now have the x,y coords of grab_point in screen space
  386. const LLRect& window_rect = gViewerWindowp->getWindowRect();
  387. // ...sanity check
  388. S32 int_x = lltrunc(x);
  389. S32 int_y = lltrunc(y);
  390. bool valid = true;
  391. if (clamp)
  392. {
  393. if (int_x < window_rect.mLeft)
  394. {
  395. out_point.mX = window_rect.mLeft;
  396. valid = false;
  397. }
  398. else if (int_x > window_rect.mRight)
  399. {
  400. out_point.mX = window_rect.mRight;
  401. valid = false;
  402. }
  403. else
  404. {
  405. out_point.mX = int_x;
  406. }
  407. if (int_y < window_rect.mBottom)
  408. {
  409. out_point.mY = window_rect.mBottom;
  410. valid = false;
  411. }
  412. else if (int_y > window_rect.mTop)
  413. {
  414. out_point.mY = window_rect.mTop;
  415. valid = false;
  416. }
  417. else
  418. {
  419. out_point.mY = int_y;
  420. }
  421. return valid;
  422. }
  423. else
  424. {
  425. out_point.mX = int_x;
  426. out_point.mY = int_y;
  427. if (int_x < window_rect.mLeft)
  428. {
  429. valid = false;
  430. }
  431. else if (int_x > window_rect.mRight)
  432. {
  433. valid = false;
  434. }
  435. if (int_y < window_rect.mBottom)
  436. {
  437. valid = false;
  438. }
  439. else if (int_y > window_rect.mTop)
  440. {
  441. valid = false;
  442. }
  443. return in_front && valid;
  444. }
  445. }
  446. else
  447. {
  448. return false;
  449. }
  450. }
  451. // Uses the last GL matrices set in set_perspective to project a point from the
  452. // agent's region space to the nearest edge in screen coordinates. Returns true
  453. // if the projection succeeded.
  454. bool LLViewerCamera::projectPosAgentToScreenEdge(const LLVector3& pos_agent,
  455. LLCoordGL& out_point) const
  456. {
  457. LLVector3 dir_to_point = pos_agent - getOrigin();
  458. dir_to_point /= dir_to_point.length();
  459. bool in_front = true;
  460. if (dir_to_point * getAtAxis() < 0.f)
  461. {
  462. in_front = false;
  463. }
  464. LLVector3 window_coordinates;
  465. if (gGL.projectf(pos_agent, gGLModelView, gGLProjection,
  466. LLRect(gGLViewport[0], gGLViewport[1] + gGLViewport[3],
  467. gGLViewport[0] + gGLViewport[2], gGLViewport[1]),
  468. window_coordinates))
  469. {
  470. F32& x = window_coordinates.mV[VX];
  471. F32& y = window_coordinates.mV[VY];
  472. x /= gViewerWindowp->getDisplayScale().mV[VX];
  473. y /= gViewerWindowp->getDisplayScale().mV[VY];
  474. // should now have the x,y coords of grab_point in screen space
  475. const LLRect& window_rect = gViewerWindowp->getVirtualWindowRect();
  476. // ...sanity check
  477. S32 int_x = lltrunc(x);
  478. S32 int_y = lltrunc(y);
  479. // find the center
  480. GLdouble center_x = (GLdouble)(0.5f * (window_rect.mLeft + window_rect.mRight));
  481. GLdouble center_y = (GLdouble)(0.5f * (window_rect.mBottom + window_rect.mTop));
  482. if (x == center_x && y == center_y)
  483. {
  484. // can't project to edge from exact center
  485. return false;
  486. }
  487. // find the line from center to local
  488. GLdouble line_x = x - center_x;
  489. GLdouble line_y = y - center_y;
  490. int_x = lltrunc(center_x);
  491. int_y = lltrunc(center_y);
  492. if (0.f == line_x)
  493. {
  494. // the slope of the line is undefined
  495. if (line_y > 0.f)
  496. {
  497. int_y = window_rect.mTop;
  498. }
  499. else
  500. {
  501. int_y = window_rect.mBottom;
  502. }
  503. }
  504. else if (0 == window_rect.getWidth())
  505. {
  506. // the diagonal slope of the view is undefined
  507. if (y < window_rect.mBottom)
  508. {
  509. int_y = window_rect.mBottom;
  510. }
  511. else if (y > window_rect.mTop)
  512. {
  513. int_y = window_rect.mTop;
  514. }
  515. }
  516. else
  517. {
  518. F32 line_slope = (F32)(line_y / line_x);
  519. F32 rect_slope = (F32)window_rect.getHeight() / (F32)window_rect.getWidth();
  520. if (fabs(line_slope) > rect_slope)
  521. {
  522. if (line_y < 0.f)
  523. {
  524. // bottom
  525. int_y = window_rect.mBottom;
  526. }
  527. else
  528. {
  529. // top
  530. int_y = window_rect.mTop;
  531. }
  532. int_x = lltrunc(((GLdouble)int_y - center_y) / line_slope + center_x);
  533. }
  534. else if (fabs(line_slope) < rect_slope)
  535. {
  536. if (line_x < 0.f)
  537. {
  538. // left
  539. int_x = window_rect.mLeft;
  540. }
  541. else
  542. {
  543. // right
  544. int_x = window_rect.mRight;
  545. }
  546. int_y = lltrunc(((GLdouble)int_x - center_x) * line_slope + center_y);
  547. }
  548. else
  549. {
  550. // exactly parallel ==> push to the corners
  551. if (line_x > 0.f)
  552. {
  553. int_x = window_rect.mRight;
  554. }
  555. else
  556. {
  557. int_x = window_rect.mLeft;
  558. }
  559. if (line_y > 0.0f)
  560. {
  561. int_y = window_rect.mTop;
  562. }
  563. else
  564. {
  565. int_y = window_rect.mBottom;
  566. }
  567. }
  568. }
  569. if (!in_front)
  570. {
  571. int_x = window_rect.mLeft + window_rect.mRight - int_x;
  572. int_y = window_rect.mBottom + window_rect.mTop - int_y;
  573. }
  574. out_point.mX = int_x;
  575. out_point.mY = int_y;
  576. return true;
  577. }
  578. return false;
  579. }
  580. void LLViewerCamera::getPixelVectors(const LLVector3& pos_agent, LLVector3& up,
  581. LLVector3& right)
  582. {
  583. LLVector3 to_vec = pos_agent - getOrigin();
  584. F32 at_dist = to_vec * getAtAxis();
  585. F32 height_meters = at_dist * tanf(getView() * 0.5f);
  586. F32 height_pixels = getViewHeightInPixels() * 0.5f;
  587. F32 pixel_aspect = gWindowp->getPixelAspectRatio();
  588. F32 meters_per_pixel = height_meters / height_pixels;
  589. up = getUpAxis() * meters_per_pixel * gViewerWindowp->getDisplayScale().mV[VY];
  590. right = -1.f * pixel_aspect * meters_per_pixel * getLeftAxis() *
  591. gViewerWindowp->getDisplayScale().mV[VX];
  592. }
  593. LLVector3 LLViewerCamera::roundToPixel(const LLVector3& pos_agent)
  594. {
  595. F32 dist = (pos_agent - getOrigin()).length();
  596. // Convert to screen space and back, preserving the depth.
  597. LLCoordGL screen_point;
  598. if (!projectPosAgentToScreen(pos_agent, screen_point, false))
  599. {
  600. // Off the screen, just return the original position.
  601. return pos_agent;
  602. }
  603. LLVector3 ray_dir;
  604. projectScreenToPosAgent(screen_point.mX, screen_point.mY, &ray_dir);
  605. ray_dir -= getOrigin();
  606. ray_dir.normalize();
  607. LLVector3 pos_agent_rounded = getOrigin() + ray_dir*dist;
  608. #if 0
  609. LLVector3 pixel_x, pixel_y;
  610. getPixelVectors(pos_agent_rounded, pixel_y, pixel_x);
  611. pos_agent_rounded += 0.5f*pixel_x, 0.5f*pixel_y;
  612. #endif
  613. return pos_agent_rounded;
  614. }
  615. bool LLViewerCamera::cameraUnderWater() const
  616. {
  617. // *TODO: figure out how to handle this case.
  618. if (gPipeline.mHeroProbeManager.isMirrorPass())
  619. {
  620. return false;
  621. }
  622. LLViewerRegion* regionp = gWorld.getRegionFromPosAgent(getOrigin());
  623. if (!regionp)
  624. {
  625. regionp = gAgent.getRegion();
  626. }
  627. return regionp && getOrigin().mV[VZ] < regionp->getWaterHeight();
  628. }
  629. bool LLViewerCamera::areVertsVisible(LLViewerObject* volumep, bool all_verts)
  630. {
  631. LLDrawable* drawablep = volumep->mDrawable;
  632. if (!drawablep)
  633. {
  634. return false;
  635. }
  636. LLVolume* volume = volumep->getVolume();
  637. if (!volume)
  638. {
  639. return false;
  640. }
  641. LLVOVolume* vo_volume = (LLVOVolume*)volumep;
  642. vo_volume->updateRelativeXform();
  643. LLMatrix4 render_mat(vo_volume->getRenderRotation(),
  644. LLVector4(vo_volume->getRenderPosition()));
  645. LLMatrix4a render_mata;
  646. render_mata.loadu(render_mat);
  647. LLMatrix4a mata;
  648. mata.loadu(vo_volume->getRelativeXform());
  649. S32 num_faces = volume->getNumVolumeFaces();
  650. for (S32 i = 0; i < num_faces; ++i)
  651. {
  652. const LLVolumeFace& face = volume->getVolumeFace(i);
  653. for (U32 v = 0, count = face.mNumVertices; v < count; ++v)
  654. {
  655. const LLVector4a& src_vec = face.mPositions[v];
  656. LLVector4a vec;
  657. mata.affineTransform(src_vec, vec);
  658. if (drawablep->isActive())
  659. {
  660. LLVector4a t = vec;
  661. render_mata.affineTransform(t, vec);
  662. }
  663. bool in_frustum = pointInFrustum(LLVector3(vec.getF32ptr())) > 0;
  664. if ((!in_frustum && all_verts) || (in_frustum && !all_verts))
  665. {
  666. return !all_verts;
  667. }
  668. }
  669. }
  670. return all_verts;
  671. }
  672. // Changes local camera and broadcasts change
  673. //virtual
  674. void LLViewerCamera::setView(F32 vertical_fov_rads)
  675. {
  676. if (gCubeSnapshot) // Should not happen
  677. {
  678. llassert(false);
  679. return;
  680. }
  681. F32 old_fov = getView();
  682. // Cap the FoV
  683. vertical_fov_rads = llclamp(vertical_fov_rads, getMinView(), getMaxView());
  684. if (vertical_fov_rads == old_fov) return;
  685. // Send the new value to the simulator
  686. LLMessageSystem* msg = gMessageSystemp;
  687. msg->newMessageFast(_PREHASH_AgentFOV);
  688. msg->nextBlockFast(_PREHASH_AgentData);
  689. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  690. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  691. msg->addU32Fast(_PREHASH_CircuitCode, msg->mOurCircuitCode);
  692. msg->nextBlockFast(_PREHASH_FOVBlock);
  693. msg->addU32Fast(_PREHASH_GenCounter, 0);
  694. msg->addF32Fast(_PREHASH_VerticalAngle, vertical_fov_rads);
  695. gAgent.sendReliableMessage();
  696. // Sync the camera with the new value
  697. LLCamera::setView(vertical_fov_rads); // Call base implementation
  698. }
  699. void LLViewerCamera::setDefaultFOV(F32 vertical_fov_rads)
  700. {
  701. vertical_fov_rads = llclamp(vertical_fov_rads, getMinView(), getMaxView());
  702. //MK
  703. if (gRLenabled)
  704. {
  705. if (gRLInterface.mCamZoomMax < EXTREMUM &&
  706. DEFAULT_FIELD_OF_VIEW / vertical_fov_rads > gRLInterface.mCamZoomMax)
  707. {
  708. vertical_fov_rads = DEFAULT_FIELD_OF_VIEW / gRLInterface.mCamZoomMax;
  709. }
  710. if (gRLInterface.mCamZoomMin > -EXTREMUM &&
  711. DEFAULT_FIELD_OF_VIEW / vertical_fov_rads < gRLInterface.mCamZoomMin)
  712. {
  713. vertical_fov_rads = DEFAULT_FIELD_OF_VIEW / gRLInterface.mCamZoomMin;
  714. }
  715. }
  716. //mk
  717. setView(vertical_fov_rads);
  718. mCameraFOVDefault = vertical_fov_rads;
  719. mCosHalfCameraFOV = cosf(mCameraFOVDefault * 0.5f);
  720. }
  721. bool LLViewerCamera::isDefaultFOVChanged()
  722. {
  723. static LLCachedControl<bool> ignore_fov_zoom(gSavedSettings,
  724. "IgnoreFOVZoomForLODs");
  725. if (mCameraFOVDefault != mPrevCameraFOVDefault)
  726. {
  727. mPrevCameraFOVDefault = mCameraFOVDefault;
  728. return !ignore_fov_zoom;
  729. }
  730. return false;
  731. }