diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/newview/llviewercamera.cpp | 195 |
1 files changed, 142 insertions, 53 deletions
diff --git a/linden/indra/newview/llviewercamera.cpp b/linden/indra/newview/llviewercamera.cpp index 0a8e8c2..7c4271a 100644 --- a/linden/indra/newview/llviewercamera.cpp +++ b/linden/indra/newview/llviewercamera.cpp | |||
@@ -48,16 +48,46 @@ | |||
48 | #include "llvovolume.h" | 48 | #include "llvovolume.h" |
49 | #include "llworld.h" | 49 | #include "llworld.h" |
50 | 50 | ||
51 | GLfloat gGLZFar; | ||
52 | GLfloat gGLZNear; | ||
53 | |||
51 | LLViewerCamera *gCamera = NULL; | 54 | LLViewerCamera *gCamera = NULL; |
52 | 55 | ||
56 | //glu pick matrix implementation borrowed from Mesa3D | ||
57 | glh::matrix4f gl_pick_matrix(GLfloat x, GLfloat y, GLfloat width, GLfloat height, GLint* viewport) | ||
58 | { | ||
59 | GLfloat m[16]; | ||
60 | GLfloat sx, sy; | ||
61 | GLfloat tx, ty; | ||
62 | |||
63 | sx = viewport[2] / width; | ||
64 | sy = viewport[3] / height; | ||
65 | tx = (viewport[2] + 2.f * (viewport[0] - x)) / width; | ||
66 | ty = (viewport[3] + 2.f * (viewport[1] - y)) / height; | ||
67 | |||
68 | #define M(row,col) m[col*4+row] | ||
69 | M(0,0) = sx; M(0,1) = 0.f; M(0,2) = 0.f; M(0,3) = tx; | ||
70 | M(1,0) = 0.f; M(1,1) = sy; M(1,2) = 0.f; M(1,3) = ty; | ||
71 | M(2,0) = 0.f; M(2,1) = 0.f; M(2,2) = 1.f; M(2,3) = 0.f; | ||
72 | M(3,0) = 0.f; M(3,1) = 0.f; M(3,2) = 0.f; M(3,3) = 1.f; | ||
73 | #undef M | ||
74 | |||
75 | return glh::matrix4f(m); | ||
76 | } | ||
77 | |||
78 | glh::matrix4f gl_perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar) | ||
79 | { | ||
80 | GLfloat f = 1.f/tanf(DEG_TO_RAD*fovy/2.f); | ||
81 | |||
82 | return glh::matrix4f(f/aspect, 0, 0, 0, | ||
83 | 0, f, 0, 0, | ||
84 | 0, 0, (zFar+zNear)/(zNear-zFar), (2.f*zFar*zNear)/(zNear-zFar), | ||
85 | 0, 0, -1.f, 0); | ||
86 | } | ||
87 | |||
53 | LLViewerCamera::LLViewerCamera() : LLCamera() | 88 | LLViewerCamera::LLViewerCamera() : LLCamera() |
54 | { | 89 | { |
55 | calcProjection(getFar()); | 90 | calcProjection(getFar()); |
56 | S32 i; | ||
57 | for (i = 0; i < 16; i++) | ||
58 | { | ||
59 | mGLProjectionMatrix[i] = 0.f; | ||
60 | } | ||
61 | mCameraFOVDefault = DEFAULT_FIELD_OF_VIEW; | 91 | mCameraFOVDefault = DEFAULT_FIELD_OF_VIEW; |
62 | mPixelMeterRatio = 0.f; | 92 | mPixelMeterRatio = 0.f; |
63 | mScreenPixelArea = 0; | 93 | mScreenPixelArea = 0; |
@@ -79,7 +109,20 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 ¢er, | |||
79 | // constrain to max distance from avatar | 109 | // constrain to max distance from avatar |
80 | LLVector3 camera_offset = center - gAgent.getPositionAgent(); | 110 | LLVector3 camera_offset = center - gAgent.getPositionAgent(); |
81 | 111 | ||
82 | setOriginAndLookAt(center, up_direction, point_of_interest); | 112 | LLViewerRegion * regp = gAgent.getRegion(); |
113 | F32 water_height = (NULL != regp) ? regp->getWaterHeight() : 0.f; | ||
114 | |||
115 | LLVector3 origin = center; | ||
116 | if (origin.mV[2] > water_height) | ||
117 | { | ||
118 | origin.mV[2] = llmax(origin.mV[2], water_height+0.20f); | ||
119 | } | ||
120 | else | ||
121 | { | ||
122 | origin.mV[2] = llmin(origin.mV[2], water_height-0.20f); | ||
123 | } | ||
124 | |||
125 | setOriginAndLookAt(origin, up_direction, point_of_interest); | ||
83 | 126 | ||
84 | F32 dpos = (center - last_position).magVec(); | 127 | F32 dpos = (center - last_position).magVec(); |
85 | LLQuaternion rotation; | 128 | LLQuaternion rotation; |
@@ -98,6 +141,7 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 ¢er, | |||
98 | 141 | ||
99 | // Handy copies of last good GL matrices | 142 | // Handy copies of last good GL matrices |
100 | F64 gGLModelView[16]; | 143 | F64 gGLModelView[16]; |
144 | F64 gGLLastModelView[16]; | ||
101 | F64 gGLProjection[16]; | 145 | F64 gGLProjection[16]; |
102 | S32 gGLViewport[4]; | 146 | S32 gGLViewport[4]; |
103 | 147 | ||
@@ -139,46 +183,70 @@ void LLViewerCamera::calcProjection(const F32 far_distance) const | |||
139 | // The picking region is centered on x,y and has the specified width and | 183 | // The picking region is centered on x,y and has the specified width and |
140 | // height. | 184 | // height. |
141 | 185 | ||
142 | LLMatrix4 gProjectionMat; | ||
143 | |||
144 | //static | 186 | //static |
145 | void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, BOOL ortho) | 187 | void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, BOOL ortho, BOOL zflip) |
146 | { | 188 | { |
147 | GLint viewport[4]; | 189 | GLint* viewport = (GLint*) gGLViewport; |
148 | GLdouble model[16]; | 190 | GLdouble* model = gGLModelView; |
149 | GLdouble proj[16]; | 191 | GLdouble* proj = gGLProjection; |
150 | GLdouble objX,objY,objZ; | 192 | GLdouble objX,objY,objZ; |
151 | 193 | ||
152 | LLVector3 frust[8]; | 194 | LLVector3 frust[8]; |
153 | 195 | ||
154 | glGetIntegerv(GL_VIEWPORT, viewport); | 196 | if (zflip) |
155 | glGetDoublev(GL_MODELVIEW_MATRIX, model); | ||
156 | glGetDoublev(GL_PROJECTION_MATRIX,proj); | ||
157 | |||
158 | gluUnProject(viewport[0],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ); | ||
159 | frust[0].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
160 | gluUnProject(viewport[0]+viewport[2],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ); | ||
161 | frust[1].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
162 | gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ); | ||
163 | frust[2].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
164 | gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ); | ||
165 | frust[3].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
166 | |||
167 | if (ortho) | ||
168 | { | 197 | { |
169 | LLVector3 far_shift = LLVector3(camera.getFar()*2.0f,0,0); | 198 | gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ); |
199 | frust[0].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
200 | gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ); | ||
201 | frust[1].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
202 | gluUnProject(viewport[0]+viewport[2],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ); | ||
203 | frust[2].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
204 | gluUnProject(viewport[0],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ); | ||
205 | frust[3].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
206 | |||
207 | gluUnProject(viewport[0],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ); | ||
208 | frust[4].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
209 | gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ); | ||
210 | frust[5].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
211 | gluUnProject(viewport[0]+viewport[2],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ); | ||
212 | frust[6].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
213 | gluUnProject(viewport[0],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ); | ||
214 | frust[7].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
215 | |||
170 | for (U32 i = 0; i < 4; i++) | 216 | for (U32 i = 0; i < 4; i++) |
171 | { | 217 | { |
172 | frust[i+4] = frust[i] + far_shift; | 218 | frust[i+4] = frust[i+4]-frust[i]; |
219 | frust[i+4].normVec(); | ||
220 | frust[i+4] = frust[i] + frust[i+4]*camera.getFar(); | ||
173 | } | 221 | } |
174 | } | 222 | } |
175 | else | 223 | else |
176 | { | 224 | { |
177 | for (U32 i = 0; i < 4; i++) | 225 | gluUnProject(viewport[0],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ); |
226 | frust[0].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
227 | gluUnProject(viewport[0]+viewport[2],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ); | ||
228 | frust[1].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
229 | gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ); | ||
230 | frust[2].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
231 | gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ); | ||
232 | frust[3].setVec((F32)objX,(F32)objY,(F32)objZ); | ||
233 | |||
234 | if (ortho) | ||
178 | { | 235 | { |
179 | LLVector3 vec = frust[i] - camera.getOrigin(); | 236 | LLVector3 far_shift = LLVector3(camera.getFar()*2.0f,0,0); |
180 | vec.normVec(); | 237 | for (U32 i = 0; i < 4; i++) |
181 | frust[i+4] = camera.getOrigin() + vec*camera.getFar()*2.0f; | 238 | { |
239 | frust[i+4] = frust[i] + far_shift; | ||
240 | } | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | for (U32 i = 0; i < 4; i++) | ||
245 | { | ||
246 | LLVector3 vec = frust[i] - camera.getOrigin(); | ||
247 | vec.normVec(); | ||
248 | frust[i+4] = camera.getOrigin() + vec*camera.getFar(); | ||
249 | } | ||
182 | } | 250 | } |
183 | } | 251 | } |
184 | 252 | ||
@@ -209,14 +277,15 @@ void LLViewerCamera::setPerspective(BOOL for_selection, | |||
209 | glMatrixMode( GL_PROJECTION ); | 277 | glMatrixMode( GL_PROJECTION ); |
210 | glLoadIdentity(); | 278 | glLoadIdentity(); |
211 | 279 | ||
280 | glh::matrix4f proj_mat; | ||
281 | |||
212 | if (for_selection) | 282 | if (for_selection) |
213 | { | 283 | { |
214 | // make a tiny little viewport | 284 | // make a tiny little viewport |
215 | // anything drawn into this viewport will be "selected" | 285 | // anything drawn into this viewport will be "selected" |
216 | const U8 VIEWPORT_VECTOR_LEN = 4; | 286 | GLint* viewport = (GLint*) gGLViewport; |
217 | GLint viewport[VIEWPORT_VECTOR_LEN]; | 287 | |
218 | glGetIntegerv(GL_VIEWPORT, viewport); | 288 | proj_mat = gl_pick_matrix(x+width/2.f, y_from_bot+height/2.f, (GLfloat) width, (GLfloat) height, viewport); |
219 | gluPickMatrix(x + width / 2, y_from_bot + height / 2, width, height, viewport); | ||
220 | 289 | ||
221 | if (limit_select_distance) | 290 | if (limit_select_distance) |
222 | { | 291 | { |
@@ -236,6 +305,10 @@ void LLViewerCamera::setPerspective(BOOL for_selection, | |||
236 | z_far = MAX_FAR_CLIP; | 305 | z_far = MAX_FAR_CLIP; |
237 | } | 306 | } |
238 | glViewport(x, y_from_bot, width, height); | 307 | glViewport(x, y_from_bot, width, height); |
308 | gGLViewport[0] = x; | ||
309 | gGLViewport[1] = y_from_bot; | ||
310 | gGLViewport[2] = width; | ||
311 | gGLViewport[3] = height; | ||
239 | } | 312 | } |
240 | 313 | ||
241 | if (mZoomFactor > 1.f) | 314 | if (mZoomFactor > 1.f) |
@@ -243,27 +316,41 @@ void LLViewerCamera::setPerspective(BOOL for_selection, | |||
243 | float offset = mZoomFactor - 1.f; | 316 | float offset = mZoomFactor - 1.f; |
244 | int pos_y = mZoomSubregion / llceil(mZoomFactor); | 317 | int pos_y = mZoomSubregion / llceil(mZoomFactor); |
245 | int pos_x = mZoomSubregion - (pos_y*llceil(mZoomFactor)); | 318 | int pos_x = mZoomSubregion - (pos_y*llceil(mZoomFactor)); |
246 | glTranslatef(offset - (F32)pos_x * 2.f, offset - (F32)pos_y * 2.f, 0.f); | 319 | glh::matrix4f translate; |
247 | glScalef(mZoomFactor, mZoomFactor, 1.f); | 320 | translate.set_translate(glh::vec3f(offset - (F32)pos_x * 2.f, offset - (F32)pos_y * 2.f, 0.f)); |
321 | glh::matrix4f scale; | ||
322 | scale.set_scale(glh::vec3f(mZoomFactor, mZoomFactor, 1.f)); | ||
323 | |||
324 | proj_mat = scale*proj_mat; | ||
325 | proj_mat = translate*proj_mat; | ||
248 | } | 326 | } |
249 | 327 | ||
250 | calcProjection(z_far); // Update the projection matrix cache | 328 | calcProjection(z_far); // Update the projection matrix cache |
251 | 329 | ||
252 | gluPerspective(fov_y, | 330 | proj_mat *= gl_perspective(fov_y,aspect,z_near,z_far); |
253 | aspect, | 331 | |
254 | z_near, | 332 | glLoadMatrixf(proj_mat.m); |
255 | z_far); | 333 | |
256 | glGetDoublev(GL_PROJECTION_MATRIX, gGLProjection); | 334 | for (U32 i = 0; i < 16; i++) |
257 | glGetFloatv(GL_PROJECTION_MATRIX, (float*)&gProjectionMat); | 335 | { |
258 | 336 | gGLProjection[i] = proj_mat.m[i]; | |
337 | } | ||
338 | |||
339 | gGLZNear = z_near; | ||
340 | gGLZFar = z_far; | ||
341 | |||
259 | glMatrixMode( GL_MODELVIEW ); | 342 | glMatrixMode( GL_MODELVIEW ); |
260 | 343 | ||
261 | glLoadMatrixf(OGL_TO_CFR_ROTATION); // Load Cory's favorite reference frame | 344 | glh::matrix4f modelview((GLfloat*) OGL_TO_CFR_ROTATION); |
262 | 345 | ||
263 | GLfloat ogl_matrix[16]; | 346 | GLfloat ogl_matrix[16]; |
347 | |||
264 | getOpenGLTransform(ogl_matrix); | 348 | getOpenGLTransform(ogl_matrix); |
265 | glMultMatrixf(ogl_matrix); | ||
266 | 349 | ||
350 | modelview *= glh::matrix4f(ogl_matrix); | ||
351 | |||
352 | glLoadMatrixf(modelview.m); | ||
353 | |||
267 | if (for_selection && (width > 1 || height > 1)) | 354 | if (for_selection && (width > 1 || height > 1)) |
268 | { | 355 | { |
269 | calculateFrustumPlanesFromWindow((F32)(x - width / 2) / (F32)gViewerWindow->getWindowWidth() - 0.5f, | 356 | calculateFrustumPlanesFromWindow((F32)(x - width / 2) / (F32)gViewerWindow->getWindowWidth() - 0.5f, |
@@ -277,9 +364,11 @@ void LLViewerCamera::setPerspective(BOOL for_selection, | |||
277 | if (!for_selection && mZoomFactor == 1.f) | 364 | if (!for_selection && mZoomFactor == 1.f) |
278 | { | 365 | { |
279 | // Save GL matrices for access elsewhere in code, especially project_world_to_screen | 366 | // Save GL matrices for access elsewhere in code, especially project_world_to_screen |
280 | glGetDoublev(GL_PROJECTION_MATRIX, mGLProjectionMatrix); | 367 | //glGetDoublev(GL_MODELVIEW_MATRIX, gGLModelView); |
281 | glGetDoublev(GL_MODELVIEW_MATRIX, gGLModelView); | 368 | for (U32 i = 0; i < 16; i++) |
282 | glGetIntegerv(GL_VIEWPORT, (GLint*)gGLViewport); | 369 | { |
370 | gGLModelView[i] = modelview.m[i]; | ||
371 | } | ||
283 | } | 372 | } |
284 | 373 | ||
285 | updateFrustumPlanes(*this); | 374 | updateFrustumPlanes(*this); |
@@ -302,7 +391,7 @@ void LLViewerCamera::projectScreenToPosAgent(const S32 screen_x, const S32 scree | |||
302 | GLdouble x, y, z; | 391 | GLdouble x, y, z; |
303 | gluUnProject( | 392 | gluUnProject( |
304 | GLdouble(screen_x), GLdouble(screen_y), 0.0, | 393 | GLdouble(screen_x), GLdouble(screen_y), 0.0, |
305 | gGLModelView, mGLProjectionMatrix, (GLint*)gGLViewport, | 394 | gGLModelView, gGLProjection, (GLint*)gGLViewport, |
306 | &x, | 395 | &x, |
307 | &y, | 396 | &y, |
308 | &z ); | 397 | &z ); |
@@ -333,7 +422,7 @@ BOOL LLViewerCamera::projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoord | |||
333 | } | 422 | } |
334 | 423 | ||
335 | if (GL_TRUE == gluProject(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ], | 424 | if (GL_TRUE == gluProject(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ], |
336 | gGLModelView, mGLProjectionMatrix, (GLint*)gGLViewport, | 425 | gGLModelView, gGLProjection, (GLint*)gGLViewport, |
337 | &x, &y, &z)) | 426 | &x, &y, &z)) |
338 | { | 427 | { |
339 | // convert screen coordinates to virtual UI coordinates | 428 | // convert screen coordinates to virtual UI coordinates |
@@ -431,7 +520,7 @@ BOOL LLViewerCamera::projectPosAgentToScreenEdge(const LLVector3 &pos_agent, | |||
431 | GLdouble x, y, z; // object's window coords, GL-style | 520 | GLdouble x, y, z; // object's window coords, GL-style |
432 | if (GL_TRUE == gluProject(pos_agent.mV[VX], pos_agent.mV[VY], | 521 | if (GL_TRUE == gluProject(pos_agent.mV[VX], pos_agent.mV[VY], |
433 | pos_agent.mV[VZ], gGLModelView, | 522 | pos_agent.mV[VZ], gGLModelView, |
434 | mGLProjectionMatrix, (GLint*)gGLViewport, | 523 | gGLProjection, (GLint*)gGLViewport, |
435 | &x, &y, &z)) | 524 | &x, &y, &z)) |
436 | { | 525 | { |
437 | x /= gViewerWindow->getDisplayScale().mV[VX]; | 526 | x /= gViewerWindow->getDisplayScale().mV[VX]; |