aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llviewerwindow.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llviewerwindow.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llviewerwindow.cpp')
-rw-r--r--linden/indra/newview/llviewerwindow.cpp4883
1 files changed, 4883 insertions, 0 deletions
diff --git a/linden/indra/newview/llviewerwindow.cpp b/linden/indra/newview/llviewerwindow.cpp
new file mode 100644
index 0000000..dc2db19
--- /dev/null
+++ b/linden/indra/newview/llviewerwindow.cpp
@@ -0,0 +1,4883 @@
1/**
2 * @file llviewerwindow.cpp
3 * @brief Implementation of the LLViewerWindow class.
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30// system library includes
31#include <stdio.h>
32#include <iostream>
33#include <fstream>
34
35#include "llviewerwindow.h"
36#include "llviewquery.h"
37#include "llxmltree.h"
38#include "llviewercamera.h"
39//#include "imdebug.h"
40
41#ifdef SABINRIG
42#include "cbw.h"
43#endif //SABINRIG
44
45//
46// TODO: Many of these includes are unnecessary. Remove them.
47//
48
49// linden library includes
50#include "audioengine.h" // mute on minimize
51#include "indra_constants.h"
52#include "linked_lists.h"
53#include "llassetstorage.h"
54#include "llfontgl.h"
55#include "llmediaengine.h" // mute on minimize
56#include "llrect.h"
57#include "llsky.h"
58#include "llstring.h"
59#include "llui.h"
60#include "lluuid.h"
61#include "llview.h"
62#include "llxfermanager.h"
63#include "message.h"
64#include "object_flags.h"
65#include "text_out.h"
66#include "lltimer.h"
67#include "timing.h"
68#include "llviewermenu.h"
69
70// newview includes
71#include "llagent.h"
72#include "llalertdialog.h"
73#include "llbox.h"
74#include "llcameraview.h"
75#include "llchatbar.h"
76#include "llconsole.h"
77#include "llviewercontrol.h"
78#include "llcylinder.h"
79#include "lldebugview.h"
80#include "lldir.h"
81#include "lldrawable.h"
82#include "lldrawpoolalpha.h"
83#include "lldrawpoolbump.h"
84#include "lldrawpoolwater.h"
85#include "llmaniptranslate.h"
86#include "llface.h"
87#include "llfeaturemanager.h"
88#include "llfilepicker.h"
89#include "llfloater.h"
90#include "llfloaterbuildoptions.h"
91#include "llfloaterbuyland.h"
92#include "llfloaterchat.h"
93#include "llfloatercustomize.h"
94#include "llfloatereditui.h" // HACK JAMESDEBUG for ui editor
95#include "llfloaterland.h"
96#include "llfloaterinspect.h"
97#include "llfloatermap.h"
98#include "llfloatermute.h"
99#include "llfloaternamedesc.h"
100#include "llfloatersnapshot.h"
101#include "llfloatertools.h"
102#include "llfloaterworldmap.h"
103#include "llfocusmgr.h"
104#include "llframestatview.h"
105#include "llgesturemgr.h"
106#include "llglheaders.h"
107#include "llhippo.h"
108#include "llhoverview.h"
109#include "llhudmanager.h"
110#include "llhudview.h"
111#include "llimagebmp.h"
112#include "llimagej2c.h"
113#include "llinventoryview.h"
114#include "llkeyboard.h"
115#include "lllineeditor.h"
116#include "llmenugl.h"
117#include "llmodaldialog.h"
118#include "llmorphview.h"
119#include "llmoveview.h"
120#include "llnotify.h"
121#include "lloverlaybar.h"
122#include "llpreviewtexture.h"
123#include "llprogressview.h"
124#include "llresmgr.h"
125#include "llrootview.h"
126#include "llselectmgr.h"
127#include "llsphere.h"
128#include "llstartup.h"
129#include "llstatusbar.h"
130#include "llstatview.h"
131#include "llsurface.h"
132#include "llsurfacepatch.h"
133#include "llimview.h"
134#include "lltexlayer.h"
135#include "lltextbox.h"
136#include "lltextureview.h"
137#include "lltool.h"
138#include "lltoolbar.h"
139#include "lltoolcomp.h"
140#include "lltooldraganddrop.h"
141#include "lltoolface.h"
142#include "lltoolfocus.h"
143#include "lltoolgrab.h"
144#include "lltoolmgr.h"
145#include "lltoolmorph.h"
146#include "lltoolpie.h"
147#include "lltoolplacer.h"
148#include "lltoolselect.h"
149#include "lltoolselectland.h"
150#include "lltoolview.h"
151#include "llvieweruictrlfactory.h"
152#include "lluploaddialog.h"
153#include "llviewercamera.h"
154#include "llviewergesture.h"
155#include "llviewerimagelist.h"
156#include "llviewerinventory.h"
157#include "llviewerkeyboard.h"
158#include "llviewermenu.h"
159#include "llviewermessage.h"
160#include "llviewerobjectlist.h"
161#include "llviewerparcelmgr.h"
162#include "llviewerregion.h"
163#include "llviewerstats.h"
164#include "llvoavatar.h"
165#include "llvovolume.h"
166#include "llworld.h"
167#include "llworldmapview.h"
168#include "moviemaker.h"
169#include "pipeline.h"
170#include "viewer.h"
171
172#if LL_WINDOWS
173#include "llwindebug.h"
174#include <tchar.h> // For Unicode conversion methods
175#endif
176
177//
178// Globals
179//
180
181LLBottomPanel* gBottomPanel = NULL;
182
183extern BOOL gDebugClicks;
184extern BOOL gDisplaySwapBuffers;
185extern S32 gJamesInt;
186
187LLViewerWindow *gViewerWindow = NULL;
188LLVelocityBar *gVelocityBar = NULL;
189
190LLVector3d gLastHitPosGlobal;
191LLVector3d gLastHitObjectOffset;
192LLUUID gLastHitObjectID;
193S32 gLastHitObjectFace = -1;
194BOOL gLastHitLand = FALSE;
195F32 gLastHitUCoord;
196F32 gLastHitVCoord;
197
198
199LLVector3d gLastHitNonFloraPosGlobal;
200LLVector3d gLastHitNonFloraObjectOffset;
201LLUUID gLastHitNonFloraObjectID;
202S32 gLastHitNonFloraObjectFace = -1;
203BOOL gLastHitParcelWall = FALSE;
204
205S32 gLastHitUIElement = 0;
206LLHUDIcon* gLastHitHUDIcon = NULL;
207
208BOOL gDebugSelect = FALSE;
209U8 gLastPickAlpha = 255;
210BOOL gUseGLPick = FALSE;
211
212// On the next pick pass (whenever that happens)
213// should we try to pick individual faces?
214// Cleared to FALSE every time a pick happens.
215BOOL gPickFaces = FALSE;
216
217LLFrameTimer gMouseIdleTimer;
218LLFrameTimer gAwayTimer;
219LLFrameTimer gAwayTriggerTimer;
220LLFrameTimer gAlphaFadeTimer;
221
222BOOL gShowOverlayTitle = FALSE;
223BOOL gPickTransparent = TRUE;
224
225BOOL gDebugFastUIRender = FALSE;
226
227BOOL gbCapturing = FALSE;
228MovieMaker gMovieMaker;
229
230S32 CHAT_BAR_HEIGHT = 28;
231S32 OVERLAY_BAR_HEIGHT = 20;
232
233const U8 NO_FACE = 255;
234BOOL gQuietSnapshot = FALSE;
235
236const F32 MIN_AFK_TIME = 2.f; // minimum time after setting away state before coming back
237const F32 MAX_FAST_FRAME_TIME = 0.5f;
238const F32 FAST_FRAME_INCREMENT = 0.1f;
239
240const S32 PICK_HALF_WIDTH = 5;
241const S32 PICK_DIAMETER = 2 * PICK_HALF_WIDTH+1;
242
243const F32 MIN_DISPLAY_SCALE = 0.85f;
244
245#ifdef SABINRIG
246/// ALL RIG STUFF
247bool rigControl = false;
248bool voltDisplay = true;
249bool nominalX = false;
250bool nominalY = false;
251static F32 nomerX = 0.0f;
252static F32 nomerY = 0.0f;
253const BOARD_NUM = 0; // rig stuff!
254const ADRANGE = BIP10VOLTS; // rig stuff!
255static unsigned short DataVal; // rig stuff!
256static F32 oldValueX = 0;
257static F32 newValueX = 50;
258static F32 oldValueY = 0;
259static F32 newValueY = 50;
260static S32 mouseX = 50;
261static S32 mouseY = 50;
262static float VoltageX = 50; // rig stuff!
263static float VoltageY = 50; // rig stuff!
264static float nVoltX = 0;
265static float nVoltY = 0;
266static F32 temp1 = 50.f;
267static F32 temp2 = 20.f;
268LLCoordGL new_gl;
269#endif //SABINRIG
270
271char LLViewerWindow::sSnapshotBaseName[LL_MAX_PATH];
272char LLViewerWindow::sSnapshotDir[LL_MAX_PATH];
273
274char LLViewerWindow::sMovieBaseName[LL_MAX_PATH];
275
276extern void toggle_debug_menus(void*);
277
278#ifdef SABINRIG
279// static
280void LLViewerWindow::printFeedback()
281{
282 if(rigControl == true)
283 {
284 cbAIn (BOARD_NUM, 0, ADRANGE, &DataVal);
285 cbToEngUnits (BOARD_NUM,ADRANGE,DataVal,&VoltageX); //Convert raw to voltage for X-axis
286 cbAIn (BOARD_NUM, 1, ADRANGE, &DataVal);
287 cbToEngUnits (BOARD_NUM,ADRANGE,DataVal,&VoltageY); //Convert raw to voltage for Y-axis
288 if(voltDisplay == true)
289 {
290 llinfos << "Current Voltages - X:" << VoltageX << " Y:" << VoltageY << llendl; //Display voltage
291 }
292
293 if(nVoltX == 0)
294 {
295 nVoltX = VoltageX;
296 nVoltY = VoltageY; //First time setup of nominal values.
297 }
298
299 newValueX = VoltageX;
300 newValueY = VoltageY; //Take in current voltage and set to a separate value for adjustment.
301
302 mouseX = mCurrentMousePoint.mX;
303 mouseY = mCurrentMousePoint.mY; //Take in current cursor position and set to separate value for adjustment.
304
305 if( abs(newValueX - nVoltX) > nomerX )
306 {
307 if( (newValueX - oldValueX) < 0)
308 {
309 mouseX += (S32)( ((newValueX - oldValueX)*.5)) * -temp;
310 }
311 else
312 {
313 mouseX += (S32)( ((newValueX - oldValueX)*.5) * temp1);
314 }
315 }
316 else
317 {
318 mouseX = getWindowWidth() / 2;
319 }
320 if( abs(newValueY - nVoltY) > nomerY )
321 {
322 if( (newValueY - oldValueY) < 0)
323 {
324 mouseY += (S32)( ((newValueY - oldValueY)*(newValueY - oldValueY)) * -temp2);
325 }
326 else
327 {
328 mouseY += (S32)( ((newValueY - oldValueY)*(newValueY - oldValueY)) * temp2);
329 }
330 }
331 else
332 {
333 mouseY = getWindowHeight() / 2;
334 }
335 //mouseX += (S32)( (newValueX - nVoltX) * temp1 + 0.5 );
336 // (newValueX - oldValueX) = difference between current position and nominal position
337 // * temp1 = the amplification of the number that sets sensitivity
338 // + 0.5 = fixes rounding errors
339
340
341 //mouseY += (S32)( (newValueY - nVoltY) * temp2 + 0.5 ); //Algorithm to adjust voltage for mouse adjustment.
342
343 oldValueX = newValueX;
344 oldValueY = newValueY;
345
346 new_gl.mX = mouseX;
347 new_gl.mY = mouseY; //Setup final coordinate to move mouse to.
348
349 setCursorPosition(new_gl); //Set final cursor position
350 }
351}
352#endif //SABINRIG
353
354
355//
356// LLViewerWindow
357//
358
359BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
360{
361 S32 x = pos.mX;
362 S32 y = pos.mY;
363 x = llround((F32)x / mDisplayScale.mV[VX]);
364 y = llround((F32)y / mDisplayScale.mV[VY]);
365
366 if (gDebugClicks)
367 {
368 llinfos << "ViewerWindow left mouse down at " << x << "," << y << llendl;
369 }
370
371 if (gMenuBarView)
372 {
373 // stop ALT-key access to menu
374 gMenuBarView->resetMenuTrigger();
375 }
376
377 mLeftMouseDown = TRUE;
378
379 // Make sure we get a coresponding mouseup event, even if the mouse leaves the window
380 mWindow->captureMouse();
381
382 // Indicate mouse was active
383 gMouseIdleTimer.reset();
384
385 // Hide tooltips on mousedown
386 if( mToolTip )
387 {
388 mToolTip->setVisible( FALSE );
389 }
390
391 // Also hide hover info on mousedown
392 if (gHoverView)
393 {
394 gHoverView->cancelHover();
395 }
396
397 if (gToolMgr)
398 {
399 // Don't let the user move the mouse out of the window until mouse up.
400 if( gToolMgr->getCurrentTool(mask)->clipMouseWhenDown() )
401 {
402 mWindow->setMouseClipping(TRUE);
403 }
404 }
405
406 LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
407 if( mouse_captor )
408 {
409 S32 local_x;
410 S32 local_y;
411 mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
412 if (LLView::sDebugMouseHandling)
413 {
414 llinfos << "Left Mouse Down handled by captor " << mouse_captor->getName() << llendl;
415 }
416
417 return mouse_captor->handleMouseDown(local_x, local_y, mask);
418 }
419
420 // Topmost view gets a chance before the hierarchy
421 LLView* top_view = gFocusMgr.getTopView();
422 if (top_view)
423 {
424 S32 local_x, local_y;
425 top_view->screenPointToLocal( x, y, &local_x, &local_y );
426 if (top_view->pointInView(local_x, local_y) && top_view->handleMouseDown(local_x, local_y, mask)) return TRUE;
427 }
428
429 // Give the UI views a chance to process the click
430 if( mRootView->handleMouseDown(x, y, mask) )
431 {
432 if (LLView::sDebugMouseHandling)
433 {
434 llinfos << "Left Mouse Down" << LLView::sMouseHandlerMessage << llendl;
435 LLView::sMouseHandlerMessage = "";
436 }
437 return TRUE;
438 }
439 else if (LLView::sDebugMouseHandling)
440 {
441 llinfos << "Left Mouse Down not handled by view" << llendl;
442 }
443
444 if (gDisconnected)
445 {
446 return FALSE;
447 }
448
449 if (gToolMgr)
450 {
451 if(gToolMgr->getCurrentTool(mask)->handleMouseDown( x, y, mask ) )
452 {
453 // This is necessary to force clicks in the world to cause edit
454 // boxes that might have keyboard focus to relinquish it, and hence
455 // cause a commit to update their value. JC
456 gFocusMgr.setKeyboardFocus(NULL, NULL);
457 return TRUE;
458 }
459 }
460
461 return FALSE;
462}
463
464BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask)
465{
466 S32 x = pos.mX;
467 S32 y = pos.mY;
468 x = llround((F32)x / mDisplayScale.mV[VX]);
469 y = llround((F32)y / mDisplayScale.mV[VY]);
470
471 if (gDebugClicks)
472 {
473 llinfos << "ViewerWindow left mouse double-click at " << x << "," << y << llendl;
474 }
475
476 mLeftMouseDown = TRUE;
477
478 // Hide tooltips
479 if( mToolTip )
480 {
481 mToolTip->setVisible( FALSE );
482 }
483
484 LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
485 if( mouse_captor )
486 {
487 S32 local_x;
488 S32 local_y;
489 mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
490 if (LLView::sDebugMouseHandling)
491 {
492 llinfos << "Left Mouse Down handled by captor " << mouse_captor->getName() << llendl;
493 }
494
495 return mouse_captor->handleDoubleClick(local_x, local_y, mask);
496 }
497
498 // Check for hit on UI.
499 LLView* top_view = gFocusMgr.getTopView();
500 if (top_view)
501 {
502 S32 local_x, local_y;
503 top_view->screenPointToLocal( x, y, &local_x, &local_y );
504 if (top_view->pointInView(local_x, local_y) && top_view->handleDoubleClick(local_x, local_y, mask)) return TRUE;
505 }
506
507 if (mRootView->handleDoubleClick(x, y, mask))
508 {
509 if (LLView::sDebugMouseHandling)
510 {
511 llinfos << "Left Mouse Down" << LLView::sMouseHandlerMessage << llendl;
512 LLView::sMouseHandlerMessage = "";
513 }
514 return TRUE;
515 }
516 else if (LLView::sDebugMouseHandling)
517 {
518 llinfos << "Left Mouse Down not handled by view" << llendl;
519 }
520
521 // Why is this here? JC 9/3/2002
522 if (gNoRender)
523 {
524 return TRUE;
525 }
526
527 if (gToolMgr)
528 {
529 if(gToolMgr->getCurrentTool(mask)->handleDoubleClick( x, y, mask ) )
530 {
531 return TRUE;
532 }
533 }
534
535 // if we got this far and nothing handled a double click, pass a normal mouse down
536 return handleMouseDown(window, pos, mask);
537}
538
539BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
540{
541 S32 x = pos.mX;
542 S32 y = pos.mY;
543 x = llround((F32)x / mDisplayScale.mV[VX]);
544 y = llround((F32)y / mDisplayScale.mV[VY]);
545
546 if (gDebugClicks)
547 {
548 llinfos << "ViewerWindow left mouse up" << llendl;
549 }
550
551 mLeftMouseDown = FALSE;
552
553 // Indicate mouse was active
554 gMouseIdleTimer.reset();
555
556 // Hide tooltips on mouseup
557 if( mToolTip )
558 {
559 mToolTip->setVisible( FALSE );
560 }
561
562 // Also hide hover info on mouseup
563 if (gHoverView) gHoverView->cancelHover();
564
565 BOOL handled = FALSE;
566
567 mWindow->releaseMouse();
568
569 LLTool *tool = NULL;
570 if (gToolMgr)
571 {
572 tool = gToolMgr->getCurrentTool(mask);
573
574 if( tool->clipMouseWhenDown() )
575 {
576 mWindow->setMouseClipping(FALSE);
577 }
578 }
579
580 LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
581 if( mouse_captor )
582 {
583 S32 local_x;
584 S32 local_y;
585 mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
586 if (LLView::sDebugMouseHandling)
587 {
588 llinfos << "Left Mouse Up handled by captor " << mouse_captor->getName() << llendl;
589 }
590
591 return mouse_captor->handleMouseUp(local_x, local_y, mask);
592 }
593
594 LLView* top_view = gFocusMgr.getTopView();
595 if (top_view)
596 {
597 S32 local_x, local_y;
598 top_view->screenPointToLocal( x, y, &local_x, &local_y );
599 handled = top_view->pointInView(local_x, local_y) && top_view->handleMouseUp(local_x, local_y, mask);
600 }
601
602 if( !handled )
603 {
604 handled = mRootView->handleMouseUp(x, y, mask);
605 }
606
607 if (LLView::sDebugMouseHandling)
608 {
609 if (handled)
610 {
611 llinfos << "Left Mouse Up" << LLView::sMouseHandlerMessage << llendl;
612 LLView::sMouseHandlerMessage = "";
613 }
614 else
615 {
616 llinfos << "Left Mouse Up not handled by view" << llendl;
617 }
618 }
619
620 if( !handled )
621 {
622 if (tool)
623 {
624 handled = tool->handleMouseUp(x, y, mask);
625 }
626 }
627
628 // Always handled as far as the OS is concerned.
629 return TRUE;
630}
631
632
633BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
634{
635 S32 x = pos.mX;
636 S32 y = pos.mY;
637 x = llround((F32)x / mDisplayScale.mV[VX]);
638 y = llround((F32)y / mDisplayScale.mV[VY]);
639
640 if (gDebugClicks)
641 {
642 llinfos << "ViewerWindow right mouse down at " << x << "," << y << llendl;
643 }
644
645 if (gMenuBarView)
646 {
647 // stop ALT-key access to menu
648 gMenuBarView->resetMenuTrigger();
649 }
650
651 mRightMouseDown = TRUE;
652
653 // Make sure we get a coresponding mouseup event, even if the mouse leaves the window
654 mWindow->captureMouse();
655
656 // Hide tooltips
657 if( mToolTip )
658 {
659 mToolTip->setVisible( FALSE );
660 }
661
662 // Also hide hover info on mousedown
663 if (gHoverView)
664 {
665 gHoverView->cancelHover();
666 }
667
668 if (gToolMgr)
669 {
670 // Don't let the user move the mouse out of the window until mouse up.
671 if( gToolMgr->getCurrentTool(mask)->clipMouseWhenDown() )
672 {
673 mWindow->setMouseClipping(TRUE);
674 }
675 }
676
677 LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
678 if( mouse_captor )
679 {
680 S32 local_x;
681 S32 local_y;
682 mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
683 if (LLView::sDebugMouseHandling)
684 {
685 llinfos << "Right Mouse Down handled by captor " << mouse_captor->getName() << llendl;
686 }
687 return mouse_captor->handleRightMouseDown(local_x, local_y, mask);
688 }
689
690 LLView* top_view = gFocusMgr.getTopView();
691 if (top_view)
692 {
693 S32 local_x, local_y;
694 top_view->screenPointToLocal( x, y, &local_x, &local_y );
695 if (top_view->pointInView(local_x, local_y) && top_view->handleRightMouseDown(local_x, local_y, mask)) return TRUE;
696 }
697
698 if( mRootView->handleRightMouseDown(x, y, mask) )
699 {
700 if (LLView::sDebugMouseHandling)
701 {
702 llinfos << "Right Mouse Down" << LLView::sMouseHandlerMessage << llendl;
703 LLView::sMouseHandlerMessage = "";
704 }
705 return TRUE;
706 }
707 else if (LLView::sDebugMouseHandling)
708 {
709 llinfos << "Right Mouse Down not handled by view" << llendl;
710 }
711
712 if (gToolMgr)
713 {
714 if(gToolMgr->getCurrentTool(mask)->handleRightMouseDown( x, y, mask ) )
715 {
716 // This is necessary to force clicks in the world to cause edit
717 // boxes that might have keyboard focus to relinquish it, and hence
718 // cause a commit to update their value. JC
719 gFocusMgr.setKeyboardFocus(NULL, NULL);
720 return TRUE;
721 }
722 }
723
724 // *HACK: this should be rolled into the composite tool logic, not
725 // hardcoded at the top level.
726 if (gToolPie && (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgent.getCameraMode()) )
727 {
728 // If the current tool didn't process the click, we should show
729 // the pie menu. This can be done by passing the event to the pie
730 // menu tool.
731 gToolPie->handleRightMouseDown(x, y, mask);
732 // show_context_menu( x, y, mask );
733 }
734
735 return TRUE;
736}
737
738BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
739{
740 S32 x = pos.mX;
741 S32 y = pos.mY;
742 x = llround((F32)x / mDisplayScale.mV[VX]);
743 y = llround((F32)y / mDisplayScale.mV[VY]);
744
745 // Don't care about caps lock for mouse events.
746 if (gDebugClicks)
747 {
748 llinfos << "ViewerWindow right mouse up" << llendl;
749 }
750
751 mRightMouseDown = FALSE;
752
753 // Indicate mouse was active
754 gMouseIdleTimer.reset();
755
756 // Hide tooltips on mouseup
757 if( mToolTip )
758 {
759 mToolTip->setVisible( FALSE );
760 }
761
762 // Also hide hover info on mouseup
763 if (gHoverView) gHoverView->cancelHover();
764
765 BOOL handled = FALSE;
766
767 mWindow->releaseMouse();
768
769 LLTool *tool = NULL;
770 if (gToolMgr)
771 {
772 tool = gToolMgr->getCurrentTool(mask);
773
774 if( tool->clipMouseWhenDown() )
775 {
776 mWindow->setMouseClipping(FALSE);
777 }
778 }
779
780 LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
781 if( mouse_captor )
782 {
783 S32 local_x;
784 S32 local_y;
785 mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
786 if (LLView::sDebugMouseHandling)
787 {
788 llinfos << "Right Mouse Up handled by captor " << mouse_captor->getName() << llendl;
789 }
790 return mouse_captor->handleRightMouseUp(local_x, local_y, mask);
791 }
792
793 LLView* top_view = gFocusMgr.getTopView();
794 if (top_view)
795 {
796 S32 local_x, local_y;
797 top_view->screenPointToLocal( x, y, &local_x, &local_y );
798 handled = top_view->pointInView(local_x, local_y) && top_view->handleRightMouseUp(local_x, local_y, mask);
799 }
800
801 if( !handled )
802 {
803 handled = mRootView->handleRightMouseUp(x, y, mask);
804 }
805
806 if (LLView::sDebugMouseHandling)
807 {
808 if (handled)
809 {
810 llinfos << "Right Mouse Up" << LLView::sMouseHandlerMessage << llendl;
811 LLView::sMouseHandlerMessage = "";
812 }
813 else
814 {
815 llinfos << "Right Mouse Up not handled by view" << llendl;
816 }
817 }
818
819 if( !handled )
820 {
821 if (tool)
822 {
823 handled = tool->handleRightMouseUp(x, y, mask);
824 }
825 }
826
827 // Always handled as far as the OS is concerned.
828 return TRUE;
829}
830
831
832void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask)
833{
834 S32 x = pos.mX;
835 S32 y = pos.mY;
836
837 x = llround((F32)x / mDisplayScale.mV[VX]);
838 y = llround((F32)y / mDisplayScale.mV[VY]);
839
840 mMouseInWindow = TRUE;
841
842 // Save mouse point for access during idle() and display()
843
844 LLCoordGL prev_saved_mouse_point = mCurrentMousePoint;
845 LLCoordGL mouse_point(x, y);
846 saveLastMouse(mouse_point);
847 BOOL mouse_actually_moved = (prev_saved_mouse_point.mX != mCurrentMousePoint.mX) || (prev_saved_mouse_point.mY != mCurrentMousePoint.mY);
848
849 gMouseIdleTimer.reset();
850
851 mWindow->showCursorFromMouseMove();
852
853 if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
854 {
855 gAgent.clearAFK();
856 }
857
858 if(mToolTip && mouse_actually_moved)
859 {
860 mToolTipBlocked = FALSE; // Blocking starts on keyboard events and (only) ends here.
861 if( mToolTip->getVisible() && !mToolTipStickyRect.pointInRect( x, y ) )
862 {
863 mToolTip->setVisible( FALSE );
864 }
865 }
866
867 // Activate the hover picker on mouse move.
868 if (gHoverView)
869 {
870 gHoverView->setTyping(FALSE);
871 }
872}
873
874void LLViewerWindow::handleMouseLeave(LLWindow *window)
875{
876 // Note: we won't get this if we have captured the mouse.
877 llassert( gFocusMgr.getMouseCapture() == NULL );
878 mMouseInWindow = FALSE;
879 if (mToolTip)
880 {
881 mToolTip->setVisible( FALSE );
882 }
883}
884
885BOOL LLViewerWindow::handleCloseRequest(LLWindow *window)
886{
887 // User has indicated they want to close, but we may need to ask
888 // about modified documents.
889 app_request_quit();
890 // Don't quit immediately
891 return FALSE;
892}
893
894void LLViewerWindow::handleQuit(LLWindow *window)
895{
896 app_force_quit(NULL);
897}
898
899void LLViewerWindow::handleResize(LLWindow *window, S32 width, S32 height)
900{
901 reshape(width, height);
902}
903
904// The top-level window has gained focus (e.g. via ALT-TAB)
905void LLViewerWindow::handleFocus(LLWindow *window)
906{
907 gFocusMgr.setAppHasFocus(TRUE);
908 LLModalDialog::onAppFocusGained();
909 if (gToolMgr)
910 {
911 gToolMgr->onAppFocusGained();
912 }
913
914 gShowTextEditCursor = TRUE;
915
916 // See if we're coming in with modifier keys held down
917 if (gKeyboard)
918 {
919 gKeyboard->resetMaskKeys();
920 }
921}
922
923// The top-level window has lost focus (e.g. via ALT-TAB)
924void LLViewerWindow::handleFocusLost(LLWindow *window)
925{
926 gFocusMgr.setAppHasFocus(FALSE);
927 //LLModalDialog::onAppFocusLost();
928 if( gToolMgr )
929 {
930 gToolMgr->onAppFocusLost();
931 }
932 gFocusMgr.setMouseCapture( NULL, NULL );
933
934 if (gMenuBarView)
935 {
936 // stop ALT-key access to menu
937 gMenuBarView->resetMenuTrigger();
938 }
939
940 // restore mouse cursor
941 gViewerWindow->showCursor();
942 gViewerWindow->getWindow()->setMouseClipping(FALSE);
943
944 // JC - Leave keyboard focus, so if you're popping in and out editing
945 // a script, you don't have to click in the editor again and again.
946 // gFocusMgr.setKeyboardFocus( NULL, NULL );
947 gShowTextEditCursor = FALSE;
948
949 // If losing focus while keys are down, reset them.
950 if (gKeyboard)
951 {
952 gKeyboard->resetKeys();
953 }
954}
955
956
957BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated)
958{
959 if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
960 {
961 gAgent.clearAFK();
962 }
963
964 // *NOTE: We want to interpret KEY_RETURN later when it arrives as
965 // a Unicode char, not as a keydown. Otherwise when client frame
966 // rate is really low, hitting return sends your chat text before
967 // it's all entered/processed.
968 if (key == KEY_RETURN && mask == MASK_NONE)
969 {
970 return FALSE;
971 }
972
973 return gViewerKeyboard.handleKey(key, mask, repeated);
974}
975
976BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask)
977{
978 return FALSE;
979}
980
981
982void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
983{
984 return gViewerKeyboard.scanKey(key, key_down, key_up, key_level);
985}
986
987
988
989
990BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated)
991{
992 if (activated)
993 {
994 mActive = TRUE;
995 send_agent_resume();
996 gAgent.clearAFK();
997 if (mWindow->getFullscreen() && !mIgnoreActivate)
998 {
999 if (!gQuit)
1000 {
1001 if (gStartupState >= STATE_STARTED)
1002 {
1003 // if we're in world, show a progress bar to hide reloading of textures
1004 llinfos << "Restoring GL during activate" << llendl;
1005 restoreGL("Restoring...");
1006 }
1007 else
1008 {
1009 // otherwise restore immediately
1010 restoreGL();
1011 }
1012 }
1013 else
1014 {
1015 llwarns << "Activating while quitting" << llendl;
1016 }
1017 }
1018
1019 // Unmute audio
1020 if (!gSavedSettings.getBOOL("MuteAudio"))
1021 {
1022 if (gAudiop) gAudiop->setMuted(FALSE);
1023 F32 volume = gSavedSettings.getF32("MediaAudioVolume");
1024 if(LLMediaEngine::getInstance())
1025 {
1026 LLMediaEngine::getInstance()->setVolume(volume);
1027 LLMediaEngine::updateClass(volume);
1028 }
1029 }
1030 }
1031 else
1032 {
1033 mActive = FALSE;
1034 gAgent.setAFK();
1035 send_agent_pause();
1036 if (mWindow->getFullscreen() && !mIgnoreActivate)
1037 {
1038 llinfos << "Stopping GL during deactivation" << llendl;
1039 stopGL();
1040 }
1041 // Mute audio
1042 if (gSavedSettings.getBOOL("MuteWhenMinimized"))
1043 {
1044 llinfos << "Muting audio on minimize" << llendl;
1045 if (gAudiop) gAudiop->setMuted(TRUE);
1046 F32 volume = 0.f;
1047 LLMediaEngine::getInstance()->setVolume(volume);
1048 LLMediaEngine::updateClass(volume);
1049 }
1050 }
1051 return TRUE;
1052}
1053
1054
1055void LLViewerWindow::handleMenuSelect(LLWindow *window, S32 menu_item)
1056{
1057}
1058
1059
1060BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height)
1061{
1062#if LL_WINDOWS
1063 if (gNoRender)
1064 {
1065 HWND window_handle = (HWND)window->getPlatformWindow();
1066 PAINTSTRUCT ps;
1067 HDC hdc;
1068
1069 RECT wnd_rect;
1070 wnd_rect.left = 0;
1071 wnd_rect.top = 0;
1072 wnd_rect.bottom = 200;
1073 wnd_rect.right = 500;
1074
1075 hdc = BeginPaint(window_handle, &ps);
1076 //SetBKColor(hdc, RGB(255, 255, 255));
1077 FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255)));
1078
1079 LLString name_str;
1080 gAgent.getName(name_str);
1081
1082 S32 len;
1083 char temp_str[255];
1084 sprintf(temp_str, "%s FPS %3.1f Phy FPS %2.1f Time Dil %1.3f",
1085 name_str.c_str(),
1086 gViewerStats->mFPSStat.getMeanPerSec(),
1087 gViewerStats->mSimPhysicsFPS.getPrev(0),
1088 gViewerStats->mSimTimeDilation.getPrev(0));
1089 len = strlen(temp_str);
1090 TextOutA(hdc, 0, 0, temp_str, len);
1091
1092
1093 LLVector3d pos_global = gAgent.getPositionGlobal();
1094 sprintf(temp_str, "Avatar pos %6.1lf %6.1lf %6.1lf", pos_global.mdV[0], pos_global.mdV[1], pos_global.mdV[2]);
1095 len = strlen(temp_str);
1096 TextOutA(hdc, 0, 25, temp_str, len);
1097
1098 TextOutA(hdc, 0, 50, "Set \"DisableRendering FALSE\" in settings.ini file to reenable", 61);
1099 EndPaint(window_handle, &ps);
1100 return TRUE;
1101 }
1102#endif
1103 return FALSE;
1104}
1105
1106
1107void LLViewerWindow::handleScrollWheel(LLWindow *window, S32 clicks)
1108{
1109 gViewerWindow->handleScrollWheel( clicks );
1110}
1111
1112void LLViewerWindow::handleWindowBlock(LLWindow *window)
1113{
1114 send_agent_pause();
1115}
1116
1117void LLViewerWindow::handleWindowUnblock(LLWindow *window)
1118{
1119 send_agent_resume();
1120}
1121
1122void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data)
1123{
1124 switch (data_type)
1125 {
1126 case 0:
1127 // received URL
1128 if (LLURLSimString::unpack_data(data))
1129 {
1130 if(gFloaterWorldMap)
1131 {
1132 gFloaterWorldMap->trackURL(LLURLSimString::sInstance.mSimName,
1133 LLURLSimString::sInstance.mX,
1134 LLURLSimString::sInstance.mY,
1135 LLURLSimString::sInstance.mZ);
1136
1137 LLFloaterWorldMap::show(NULL, TRUE);
1138 }
1139
1140 // bring window to foreground, as it has just been "launched" from a URL
1141 mWindow->bringToFront();
1142 }
1143 break;
1144 }
1145}
1146
1147
1148//
1149// Classes
1150//
1151LLViewerWindow::LLViewerWindow(
1152 char* title, char* name,
1153 S32 x, S32 y,
1154 S32 width, S32 height,
1155 BOOL fullscreen, BOOL ignore_pixel_depth)
1156 :
1157 mActive(TRUE),
1158 mWantFullscreen(fullscreen),
1159 mShowFullscreenProgress(FALSE),
1160 mWindowRect(0, height, width, 0),
1161 mVirtualWindowRect(0, height, width, 0),
1162 mLeftMouseDown(FALSE),
1163 mRightMouseDown(FALSE),
1164 mToolTip(NULL),
1165 mToolTipBlocked(FALSE),
1166 mMouseInWindow( FALSE ),
1167 mLastMask( MASK_NONE ),
1168 mToolStored( NULL ),
1169 mSuppressToolbox( FALSE ),
1170 mHideCursorPermanent( FALSE ),
1171 mPickPending(FALSE),
1172 mIgnoreActivate( FALSE ),
1173 mRenderFullFrame(FALSE)
1174{
1175 // Default to application directory.
1176 strcpy(LLViewerWindow::sSnapshotBaseName, "Snapshot");
1177 strcpy(LLViewerWindow::sMovieBaseName, "SLmovie");
1178 LLViewerWindow::sSnapshotDir[0] = '\0';
1179
1180 mFastFrameTimer.stop();
1181
1182 // create window
1183 mWindow = LLWindowManager::createWindow(
1184 title, name, x, y, width, height, 0,
1185 fullscreen,
1186 gNoRender,
1187 gSavedSettings.getBOOL("DisableVerticalSync"),
1188 !gNoRender,
1189 ignore_pixel_depth);
1190#if LL_WINDOWS
1191 if (!LLWinDebug::setupExceptionHandler())
1192 {
1193 llwarns << " Someone took over my exception handler (post createWindow)!" << llendl;
1194 }
1195#endif
1196
1197 if (NULL == mWindow)
1198 {
1199 LLSplashScreen::update("Shutting down...");
1200#if LL_LINUX
1201 llwarns << "Unable to create window, be sure screen is set at 32-bit color and your graphics driver is configured correctly. See README-linux.txt for further information."
1202 << llendl;
1203#else
1204 llwarns << "Unable to create window, be sure screen is set at 32-bit color in Control Panels->Display->Settings"
1205 << llendl;
1206#endif
1207 app_force_exit(1);
1208 }
1209
1210 // Get the real window rect the window was created with (since there are various OS-dependent reasons why
1211 // the size of a window or fullscreen context may have been adjusted slightly...)
1212 F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor");
1213
1214 mDisplayScale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
1215 mDisplayScale *= ui_scale_factor;
1216 LLUI::setScaleFactor(mDisplayScale);
1217
1218 {
1219 LLCoordWindow size;
1220 mWindow->getSize(&size);
1221 mWindowRect.set(0, size.mY, size.mX, 0);
1222 mVirtualWindowRect.set(0, llround((F32)size.mY / mDisplayScale.mV[VY]), llround((F32)size.mX / mDisplayScale.mV[VX]), 0);
1223 }
1224
1225 LLFontManager::initClass();
1226
1227 //
1228 // We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off
1229 // stuff like AGP if we think that it'll crash the viewer.
1230 //
1231 gFeatureManagerp->initGraphicsFeatureMasks();
1232 if (gFeatureManagerp->isSafe()
1233 || (gSavedSettings.getS32("LastFeatureVersion") != gFeatureManagerp->getVersion()))
1234 {
1235 gFeatureManagerp->applyRecommendedFeatures();
1236 }
1237
1238 S32 idx = gSavedSettings.getS32("GraphicsCardMemorySetting");
1239 // -1 indicates use default (max)
1240 if (idx == -1)
1241 {
1242 idx = LLViewerImageList::getMaxVideoRamSetting(-2); // get max recommended setting
1243 gSavedSettings.setS32("GraphicsCardMemorySetting", idx);
1244 }
1245
1246 if (!gNoRender)
1247 {
1248 //
1249 // Initialize GL stuff
1250 //
1251
1252 gPipeline.init();
1253 stop_glerror();
1254 initGLDefaults();
1255 LLViewerImage::initClass();
1256 }
1257
1258 //
1259 // Done initing GL stuff.
1260 //
1261
1262 // set callbacks
1263 mWindow->setCallbacks(this);
1264
1265 // Init the image list. Must happen after GL is initialized and before the images that
1266 // LLViewerWindow needs are requested.
1267 gImageList.init();
1268 gBumpImageList.init();
1269
1270 // Create container for all sub-views
1271 mRootView = new LLRootView("root", mVirtualWindowRect, FALSE);
1272 mRootView->setRenderInFastFrame(FALSE);
1273
1274 if (!gNoRender)
1275 {
1276 // Init default fonts
1277 initFonts();
1278 }
1279
1280 // Init Resource Manager
1281 gResMgr = new LLResMgr();
1282
1283 // Make avatar head look forward at start
1284 mCurrentMousePoint.mX = getWindowWidth() / 2;
1285 mCurrentMousePoint.mY = getWindowHeight() / 2;
1286
1287 mPickBuffer = new U8[PICK_DIAMETER * PICK_DIAMETER * 4];
1288
1289 gShowOverlayTitle = gSavedSettings.getBOOL("ShowOverlayTitle");
1290 mOverlayTitle = gSavedSettings.getString("OverlayTitle");
1291 // Can't have spaces in settings.ini strings, so use underscores instead and convert them.
1292 LLString::replaceChar(mOverlayTitle, '_', ' ');
1293
1294 gAwayTimer.stop();
1295
1296 LLAlertDialog::setDisplayCallback(alertCallback); // call this before calling any modal dialogs
1297
1298 // sync the keyboard's setting with the saved setting
1299 gSavedSettings.getControl("NumpadControl")->firePropertyChanged();
1300}
1301
1302void LLViewerWindow::initGLDefaults()
1303{
1304 //LLGLState::reset();
1305 //gGLSDefault.set();
1306 //LLGLState::verify(TRUE);
1307
1308 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1309 glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
1310
1311 F32 ambient[4] = {0.f,0.f,0.f,0.f };
1312 F32 diffuse[4] = {1.f,1.f,1.f,1.f };
1313 glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,ambient);
1314 glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,diffuse);
1315
1316 glPixelStorei(GL_PACK_ALIGNMENT,1);
1317 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
1318
1319 // lights for objects
1320 glShadeModel( GL_SMOOTH );
1321
1322 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
1323
1324 glCullFace(GL_BACK);
1325
1326 // RN: Need this for translation and stretch manip.
1327 gCone.prerender();
1328 gBox.prerender();
1329 gSphere.prerender();
1330 gCylinder.prerender();
1331
1332 LLVOAvatar::initVertexPrograms();
1333}
1334
1335void LLViewerWindow::initBase()
1336{
1337 S32 height = getWindowHeight();
1338 S32 width = getWindowWidth();
1339
1340 LLRect full_window(0, height, width, 0);
1341
1342 adjustRectanglesForFirstUse(full_window);
1343
1344 ////////////////////
1345 //
1346 // Set the gamma
1347 //
1348
1349 F32 gamma = gSavedSettings.getF32("RenderGamma");
1350 if (gamma != 0.0f)
1351 {
1352 gViewerWindow->getWindow()->setGamma(gamma);
1353 }
1354
1355 // Create global views
1356
1357 // Create the floater view at the start so that other views can add children to it.
1358 // (But wait to add it as a child of the root view so that it will be in front of the
1359 // other views.)
1360
1361 // Constrain floaters to inside the menu and status bar regions.
1362 LLRect floater_view_rect = full_window;
1363 // make space for menu bar if we have one
1364 floater_view_rect.mTop -= MENU_BAR_HEIGHT;
1365 floater_view_rect.mBottom += STATUS_BAR_HEIGHT + 12 + 16 + 2;
1366
1367 // Check for non-first startup
1368 S32 floater_view_bottom = gSavedSettings.getS32("FloaterViewBottom");
1369 if (floater_view_bottom >= 0)
1370 {
1371 floater_view_rect.mBottom = floater_view_bottom;
1372 }
1373 gFloaterView = new LLFloaterView("Floater View", floater_view_rect );
1374 gFloaterView->setVisible(TRUE);
1375
1376 gSnapshotFloaterView = new LLSnapshotFloaterView("Snapshot Floater View", full_window);
1377 gSnapshotFloaterView->setVisible(TRUE);
1378
1379 // Console
1380 llassert( !gConsole );
1381 LLRect console_rect = full_window;
1382 console_rect.mTop -= 24;
1383 console_rect.mBottom += STATUS_BAR_HEIGHT + 12 + 16 + 12;
1384 console_rect.mLeft += 24; //gSavedSettings.getS32("StatusBarButtonWidth") + gSavedSettings.getS32("StatusBarPad");
1385
1386 if (gSavedSettings.getBOOL("ChatFullWidth"))
1387 {
1388 console_rect.mRight -= 10;
1389 }
1390 else
1391 {
1392 // Make console rect somewhat narrow so having inventory open is
1393 // less of a problem.
1394 console_rect.mRight = console_rect.mLeft + 2 * width / 3;
1395 }
1396
1397 gConsole = new LLConsole(
1398 "console",
1399 gSavedSettings.getS32("ConsoleBufferSize"),
1400 console_rect,
1401 gSavedSettings.getS32("ChatFontSize"),
1402 gSavedSettings.getF32("ChatPersistTime") );
1403 gConsole->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
1404 mRootView->addChild(gConsole);
1405
1406 // Debug view over the console
1407 gDebugView = new LLDebugView("gDebugView", full_window);
1408 gDebugView->setFollowsAll();
1409 gDebugView->setVisible(TRUE);
1410 mRootView->addChild(gDebugView);
1411
1412 // HUD elements just below floaters
1413 LLRect hud_rect = full_window;
1414 hud_rect.mTop -= 24;
1415 hud_rect.mBottom += STATUS_BAR_HEIGHT;
1416 gHUDView = new LLHUDView("hud_view", hud_rect);
1417 gHUDView->setFollowsAll();
1418 mRootView->addChild(gHUDView);
1419
1420 // Add floater view at the end so it will be on top, and give it tab priority over others
1421 mRootView->addChild(gFloaterView, -1);
1422 mRootView->addChild(gSnapshotFloaterView);
1423
1424 // notify above floaters!
1425 LLRect notify_rect = full_window;
1426 //notify_rect.mTop -= 24;
1427 notify_rect.mBottom += STATUS_BAR_HEIGHT;
1428 gNotifyBoxView = new LLNotifyBoxView("notify", notify_rect, FALSE, FOLLOWS_ALL);
1429 mRootView->addChild(gNotifyBoxView, -2);
1430
1431 // Tooltips go above floaters
1432 mToolTip = new LLTextBox( "tool tip", LLRect(0, 1, 1, 0 ) );
1433 mToolTip->setHPad( 4 );
1434 mToolTip->setVPad( 2 );
1435 mToolTip->setColor( gColors.getColor( "ToolTipTextColor" ) );
1436 mToolTip->setBorderColor( gColors.getColor( "ToolTipBorderColor" ) );
1437 mToolTip->setBorderVisible( FALSE );
1438 mToolTip->setBackgroundColor( gColors.getColor( "ToolTipBgColor" ) );
1439 mToolTip->setBackgroundVisible( TRUE );
1440 mToolTip->setDropshadowVisible( FALSE );
1441 mToolTip->setBorderDropshadowVisible( TRUE );
1442 mToolTip->setVisible( FALSE );
1443
1444 // Add the progress bar view (startup view), which overrides everything
1445 mProgressView = new LLProgressView("ProgressView", full_window);
1446 mRootView->addChild(mProgressView);
1447 setShowProgress(FALSE);
1448 setProgressCancelButtonVisible(FALSE, "");
1449}
1450
1451
1452void adjust_rect_top_left(const LLString& control, const LLRect& window)
1453{
1454 LLRect r = gSavedSettings.getRect(control);
1455 if (r.mLeft == 0 && r.mBottom == 0)
1456 {
1457 r.setLeftTopAndSize(0, window.getHeight(), r.getWidth(), r.getHeight());
1458 gSavedSettings.setRect(control, r);
1459 }
1460}
1461
1462void adjust_rect_top_right(const LLString& control, const LLRect& window)
1463{
1464 LLRect r = gSavedSettings.getRect(control);
1465 if (r.mLeft == 0 && r.mBottom == 0)
1466 {
1467 r.setLeftTopAndSize(window.getWidth() - r.getWidth(),
1468 window.getHeight(),
1469 r.getWidth(),
1470 r.getHeight());
1471 gSavedSettings.setRect(control, r);
1472 }
1473}
1474
1475void adjust_rect_bottom_center(const LLString& control, const LLRect& window)
1476{
1477 LLRect r = gSavedSettings.getRect(control);
1478 if (r.mLeft == 0 && r.mBottom == 0)
1479 {
1480 r.setOriginAndSize(
1481 window.getWidth()/2 - r.getWidth()/2,
1482 0,
1483 r.getWidth(),
1484 r.getHeight());
1485 gSavedSettings.setRect(control, r);
1486 }
1487}
1488
1489// Many rectangles can't be placed until we know the screen size.
1490// These rectangles have their bottom-left corner as 0,0
1491void LLViewerWindow::adjustRectanglesForFirstUse(const LLRect& window)
1492{
1493 LLRect r;
1494
1495 adjust_rect_bottom_center("FloaterMoveRect", window);
1496
1497 adjust_rect_bottom_center("FloaterCameraRect", window);
1498
1499 adjust_rect_top_left("FloaterCustomizeAppearanceRect", window);
1500
1501 adjust_rect_top_left("FloaterLandRect5", window);
1502
1503 adjust_rect_top_left("FloaterFindRect2", window);
1504
1505 adjust_rect_top_left("FloaterGestureRect", window);
1506
1507 adjust_rect_top_right("FloaterMapRect", window);
1508
1509 adjust_rect_top_left("FloaterBuildOptionsRect", window);
1510
1511 // bottom-right
1512 r = gSavedSettings.getRect("FloaterInventoryRect");
1513 if (r.mLeft == 0 && r.mBottom == 0)
1514 {
1515 r.setOriginAndSize(
1516 window.getWidth() - r.getWidth(),
1517 0,
1518 r.getWidth(),
1519 r.getHeight());
1520 gSavedSettings.setRect("FloaterInventoryRect", r);
1521 }
1522}
1523
1524
1525void LLViewerWindow::initWorldUI()
1526{
1527 pre_init_menus();
1528
1529 S32 height = mRootView->getRect().getHeight();
1530 S32 width = mRootView->getRect().getWidth();
1531 LLRect full_window(0, height, width, 0);
1532
1533 LLRect bar_rect(-1, STATUS_BAR_HEIGHT, width+1, -1);
1534 gToolBar = new LLToolBar("toolbar", bar_rect);
1535
1536 LLRect chat_bar_rect(-1,CHAT_BAR_HEIGHT, width+1, -1);
1537 chat_bar_rect.translate(0, STATUS_BAR_HEIGHT-1);
1538 gChatBar = new LLChatBar("chat", chat_bar_rect);
1539
1540 bar_rect.translate(0, STATUS_BAR_HEIGHT-1);
1541 bar_rect.translate(0, CHAT_BAR_HEIGHT-1);
1542 gOverlayBar = new LLOverlayBar("overlay", bar_rect);
1543
1544 // panel containing chatbar, toolbar, and overlay, over floaters
1545 LLRect bottom_rect(-1, 2*STATUS_BAR_HEIGHT + CHAT_BAR_HEIGHT, width+1, -1);
1546 gBottomPanel = new LLBottomPanel("bottom panel", bottom_rect);
1547
1548 // the order here is important
1549 gBottomPanel->addChild(gChatBar);
1550 gBottomPanel->addChild(gToolBar);
1551 gBottomPanel->addChild(gOverlayBar);
1552 mRootView->addChild(gBottomPanel);
1553
1554 // View for hover information
1555 gHoverView = new LLHoverView("gHoverView", full_window);
1556 gHoverView->setVisible(TRUE);
1557 mRootView->addChild(gHoverView);
1558
1559 //
1560 // Map
1561 //
1562 // TODO: Move instance management into class
1563 gFloaterMap = new LLFloaterMap("Map");
1564 gFloaterMap->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT);
1565 gFloaterMap->setVisible( gSavedSettings.getBOOL("ShowMiniMap") );
1566
1567 // keep onscreen
1568 gFloaterView->adjustToFitScreen(gFloaterMap, FALSE);
1569
1570 if (gSavedSettings.getBOOL("ShowCameraControls"))
1571 {
1572 LLFloaterCamera::show(NULL);
1573 }
1574
1575 if (gSavedSettings.getBOOL("ShowMovementControls"))
1576 {
1577 LLFloaterMove::show(NULL);
1578 }
1579
1580 // Must have one global chat floater so it can actually store
1581 // the history. JC
1582 gFloaterChat = new LLFloaterChat();
1583 gFloaterChat->setVisible( FALSE );
1584
1585 if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) gFloaterChat->loadHistory();
1586
1587 gIMView = new LLIMView("gIMView", LLRect() );
1588 gIMView->setFollowsAll();
1589
1590 LLRect morph_view_rect = full_window;
1591 morph_view_rect.stretch( -STATUS_BAR_HEIGHT );
1592 morph_view_rect.mTop = full_window.mTop - 32;
1593 gMorphView = new LLMorphView("gMorphView", morph_view_rect );
1594 mRootView->addChild(gMorphView);
1595 gMorphView->setVisible(FALSE);
1596
1597 gFloaterMute = new LLFloaterMute();
1598 gFloaterMute->setVisible(FALSE);
1599
1600 LLWorldMapView::initClass();
1601
1602 LLRect world_map_rect = gSavedSettings.getRect("FloaterWorldMapRect");
1603 // if 0,0,0,0 then use fullscreen
1604 if (world_map_rect.mTop == 0
1605 && world_map_rect.mLeft == 0
1606 && world_map_rect.mRight == 0
1607 && world_map_rect.mBottom == 0)
1608 {
1609 world_map_rect.set(0, height-TOOL_BAR_HEIGHT, width, STATUS_BAR_HEIGHT);
1610 world_map_rect.stretch(-4);
1611 gSavedSettings.setRect("FloaterWorldMapRect", world_map_rect);
1612 }
1613 gFloaterWorldMap = new LLFloaterWorldMap();
1614 gFloaterWorldMap->setVisible(FALSE);
1615
1616 //
1617 // Tools for building
1618 //
1619
1620 // Toolbox floater
1621 init_menus();
1622
1623 gFloaterTools = new LLFloaterTools();
1624 gFloaterTools->setVisible(FALSE);
1625
1626 // Status bar
1627 S32 menu_bar_height = gMenuBarView->getRect().getHeight();
1628 LLRect root_rect = gViewerWindow->getRootView()->getRect();
1629 LLRect status_rect(0, root_rect.getHeight(), root_rect.getWidth(), root_rect.getHeight() - menu_bar_height);
1630 gStatusBar = new LLStatusBar("status", status_rect);
1631 gStatusBar->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP);
1632
1633 gStatusBar->reshape(root_rect.getWidth(), gStatusBar->getRect().getHeight(), TRUE);
1634 gStatusBar->translate(0, root_rect.getHeight() - gStatusBar->getRect().getHeight());
1635
1636 gViewerWindow->getRootView()->addChild(gStatusBar);
1637}
1638
1639
1640LLViewerWindow::~LLViewerWindow()
1641{
1642 gSavedSettings.setS32("FloaterViewBottom", gFloaterView->getRect().mBottom);
1643
1644 // Cleanup global views
1645 if (gMorphView)
1646 {
1647 gMorphView->setVisible(FALSE);
1648 }
1649
1650 // Delete all child views.
1651 delete mRootView;
1652 mRootView = NULL;
1653
1654 // Automatically deleted as children of mRootView. Fix the globals.
1655 gFloaterTools = NULL;
1656 gStatusBar = NULL;
1657 gFloaterCamera = NULL;
1658 gIMView = NULL;
1659 gHoverView = NULL;
1660
1661 gFloaterView = NULL;
1662 gMorphView = NULL;
1663
1664 gFloaterChat = NULL;
1665 gFloaterMute = NULL;
1666
1667 gFloaterMap = NULL;
1668 gHUDView = NULL;
1669
1670 gNotifyBoxView = NULL;
1671
1672 delete mToolTip;
1673 mToolTip = NULL;
1674
1675 delete gResMgr;
1676 gResMgr = NULL;
1677
1678 //--------------------------------------------------------
1679 // Shutdown GL cleanly. Order is very important here.
1680 //--------------------------------------------------------
1681 LLFontGL::destroyDefaultFonts();
1682 LLFontManager::cleanupClass();
1683 stop_glerror();
1684
1685 gSky.cleanup();
1686 stop_glerror();
1687
1688 gImageList.shutdown();
1689 stop_glerror();
1690
1691 gBumpImageList.shutdown();
1692 stop_glerror();
1693
1694 LLWorldMapView::cleanupTextures();
1695
1696 LLViewerImage::cleanupClass();
1697
1698 delete[] mPickBuffer;
1699 mPickBuffer = NULL;
1700
1701 llinfos << "Stopping GL during shutdown" << llendl;
1702 if (!gNoRender)
1703 {
1704 stopGL(FALSE);
1705 stop_glerror();
1706 }
1707
1708 if (gSelectMgr)
1709 {
1710 llinfos << "Cleaning up select manager" << llendl;
1711 gSelectMgr->cleanup();
1712 }
1713
1714 llinfos << "Cleaning up pipeline" << llendl;
1715 gPipeline.cleanup();
1716 stop_glerror();
1717 llinfos << "Destroying Window" << llendl;
1718 destroyWindow();
1719}
1720
1721
1722void LLViewerWindow::setCursor( ECursorType c )
1723{
1724 mWindow->setCursor( c );
1725}
1726
1727void LLViewerWindow::showCursor()
1728{
1729 mWindow->showCursor();
1730}
1731
1732void LLViewerWindow::hideCursor()
1733{
1734 // Hide tooltips
1735 if(mToolTip ) mToolTip->setVisible( FALSE );
1736
1737 // Also hide hover info
1738 if (gHoverView) gHoverView->cancelHover();
1739
1740 // And hide the cursor
1741 mWindow->hideCursor();
1742}
1743
1744void LLViewerWindow::sendShapeToSim()
1745{
1746 LLMessageSystem* msg = gMessageSystem;
1747 if(!msg) return;
1748 msg->newMessageFast(_PREHASH_AgentHeightWidth);
1749 msg->nextBlockFast(_PREHASH_AgentData);
1750 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
1751 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
1752 msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode);
1753 msg->nextBlockFast(_PREHASH_HeightWidthBlock);
1754 msg->addU32Fast(_PREHASH_GenCounter, 0);
1755 U16 height16 = (U16) mWindowRect.getHeight();
1756 U16 width16 = (U16) mWindowRect.getWidth();
1757 msg->addU16Fast(_PREHASH_Height, height16);
1758 msg->addU16Fast(_PREHASH_Width, width16);
1759 gAgent.sendReliableMessage();
1760}
1761
1762// Must be called after window is created to set up agent
1763// camera variables and UI variables.
1764void LLViewerWindow::reshape(S32 width, S32 height)
1765{
1766 // Destroying the window at quit time generates spurious
1767 // reshape messages. We don't care about these, and we
1768 // don't want to send messages because the message system
1769 // may have been destructed.
1770 if (!gQuit)
1771 {
1772 if (gNoRender)
1773 {
1774 return;
1775 }
1776
1777 glViewport(0, 0, width, height );
1778
1779 if (height > 0 && gCamera)
1780 {
1781 gCamera->setViewHeightInPixels( height );
1782 if (mWindow->getFullscreen())
1783 {
1784 // force to 4:3 aspect for odd resolutions
1785 gCamera->setAspect( getDisplayAspectRatio() );
1786 }
1787 else
1788 {
1789 gCamera->setAspect( width / (F32) height);
1790 }
1791 }
1792
1793 // update our window rectangle
1794 mWindowRect.mRight = mWindowRect.mLeft + width;
1795 mWindowRect.mTop = mWindowRect.mBottom + height;
1796 calcDisplayScale();
1797
1798 BOOL display_scale_changed = mDisplayScale != LLUI::sGLScaleFactor;
1799 LLUI::setScaleFactor(mDisplayScale);
1800
1801 // update our window rectangle
1802 mVirtualWindowRect.mRight = mVirtualWindowRect.mLeft + llround((F32)width / mDisplayScale.mV[VX]);
1803 mVirtualWindowRect.mTop = mVirtualWindowRect.mBottom + llround((F32)height / mDisplayScale.mV[VY]);
1804
1805 setupViewport();
1806
1807 // Inform lower views of the change
1808 // round up when converting coordinates to make sure there are no gaps at edge of window
1809 LLView::sForceReshape = display_scale_changed;
1810 mRootView->reshape(llceil((F32)width / mDisplayScale.mV[VX]), llceil((F32)height / mDisplayScale.mV[VY]));
1811 LLView::sForceReshape = FALSE;
1812
1813 // clear font width caches
1814 if (display_scale_changed)
1815 {
1816 LLHUDText::reshape();
1817 }
1818
1819 sendShapeToSim();
1820
1821
1822 // store the mode the user wants (even if not there yet)
1823 gSavedSettings.setBOOL("FullScreen", mWantFullscreen);
1824
1825 // store new settings for the mode we are in, regardless
1826 if (mWindow->getFullscreen())
1827 {
1828 gSavedSettings.setS32("FullScreenWidth", width);
1829 gSavedSettings.setS32("FullScreenHeight", height);
1830 }
1831 else
1832 {
1833 // Only save size if not maximized
1834 BOOL maximized = mWindow->getMaximized();
1835 gSavedSettings.setBOOL("WindowMaximized", maximized);
1836
1837 LLCoordScreen window_size;
1838 if (!maximized
1839 && mWindow->getSize(&window_size))
1840 {
1841 gSavedSettings.setS32("WindowWidth", window_size.mX);
1842 gSavedSettings.setS32("WindowHeight", window_size.mY);
1843 }
1844 }
1845
1846 gViewerStats->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width);
1847 gViewerStats->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height);
1848 }
1849}
1850
1851
1852void LLViewerWindow::draw()
1853{
1854#if LL_DEBUG
1855 LLView::sIsDrawing = TRUE;
1856#endif
1857 stop_glerror();
1858
1859 LLUI::setLineWidth(1.f);
1860 //popup alerts from the UI
1861 LLAlertInfo alert;
1862 while (LLPanel::nextAlert(alert))
1863 {
1864 alertXml(alert.mLabel, alert.mArgs);
1865 }
1866
1867 LLUI::setLineWidth(1.f);
1868 // Reset any left-over transforms
1869 glMatrixMode(GL_MODELVIEW);
1870
1871 glLoadIdentity();
1872
1873 //S32 screen_x, screen_y;
1874
1875 // HACK for timecode debugging
1876 if (gSavedSettings.getBOOL("DisplayTimecode"))
1877 {
1878 // draw timecode block
1879 char text[256];
1880
1881 glLoadIdentity();
1882
1883 microsecondsToTimecodeString(gFrameTime,text);
1884 const LLFontGL* font = gResMgr->getRes( LLFONT_SANSSERIF );
1885 font->renderUTF8(text, 0,
1886 llround((getWindowWidth()/2)-100.f),
1887 llround((getWindowHeight()-60.f)),
1888 LLColor4( 1.f, 1.f, 1.f, 1.f ),
1889 LLFontGL::LEFT, LLFontGL::TOP);
1890 }
1891
1892 // Draw all nested UI views.
1893 // No translation needed, this view is glued to 0,0
1894
1895 glPushMatrix();
1896 {
1897 // scale view by UI global scale factor and aspect ratio correction factor
1898 glScalef(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
1899
1900 LLVector2 old_scale_factor = LLUI::sGLScaleFactor;
1901 if (gCamera)
1902 {
1903 // apply camera zoom transform (for high res screenshots)
1904 F32 zoom_factor = gCamera->getZoomFactor();
1905 S16 sub_region = gCamera->getZoomSubRegion();
1906 if (zoom_factor > 1.f)
1907 {
1908 //decompose subregion number to x and y values
1909 int pos_y = sub_region / llceil(zoom_factor);
1910 int pos_x = sub_region - (pos_y*llceil(zoom_factor));
1911 // offset for this tile
1912 glTranslatef((F32)gViewerWindow->getWindowWidth() * -(F32)pos_x,
1913 (F32)gViewerWindow->getWindowHeight() * -(F32)pos_y,
1914 0.f);
1915 glScalef(zoom_factor, zoom_factor, 1.f);
1916 LLUI::sGLScaleFactor *= zoom_factor;
1917 }
1918 }
1919
1920 {
1921 LLGLSTexture gls_texture;
1922 show_text_gl();
1923 }
1924
1925 if (gToolMgr)
1926 {
1927 // Draw tool specific overlay on world
1928 gToolMgr->getCurrentTool( gKeyboard->currentMask(TRUE) )->draw();
1929 }
1930
1931 if( gAgent.cameraMouselook() )
1932 {
1933 drawMouselookInstructions();
1934 stop_glerror();
1935 }
1936
1937 // Draw all nested UI views.
1938 // No translation needed, this view is glued to 0,0
1939 mRootView->draw();
1940
1941 // Draw optional on-top-of-everyone view
1942 LLView* top_view = gFocusMgr.getTopView();
1943 if (top_view && top_view->getVisible())
1944 {
1945 S32 screen_x, screen_y;
1946 top_view->localPointToScreen(0, 0, &screen_x, &screen_y);
1947
1948 glMatrixMode(GL_MODELVIEW);
1949 LLUI::pushMatrix();
1950 LLUI::translate( (F32) screen_x, (F32) screen_y, 0.f);
1951 top_view->draw();
1952 LLUI::popMatrix();
1953 }
1954
1955 // Draw tooltips
1956 // Adjust their rectangle so they don't go off the top or bottom
1957 // of the screen.
1958 if( mToolTip && mToolTip->getVisible() )
1959 {
1960 glMatrixMode(GL_MODELVIEW);
1961 LLUI::pushMatrix();
1962 {
1963 S32 tip_height = mToolTip->getRect().getHeight();
1964
1965 S32 screen_x, screen_y;
1966 mToolTip->localPointToScreen(0, -24 - tip_height,
1967 &screen_x, &screen_y);
1968
1969 // If tooltip would draw off the bottom of the screen,
1970 // show it from the cursor tip position.
1971 if (screen_y < tip_height)
1972 {
1973 mToolTip->localPointToScreen(0, 0, &screen_x, &screen_y);
1974 }
1975 LLUI::translate( (F32) screen_x, (F32) screen_y, 0);
1976 mToolTip->draw();
1977 }
1978 LLUI::popMatrix();
1979 }
1980
1981 if( gShowOverlayTitle && !mOverlayTitle.empty() )
1982 {
1983 // Used for special titles such as "Second Life - Special E3 2003 Beta"
1984 const S32 DIST_FROM_TOP = 20;
1985 LLGLSTexture gls_texture;
1986 LLFontGL::sSansSerifBig->renderUTF8(
1987 mOverlayTitle, 0,
1988 llround( gViewerWindow->getWindowWidth() * 0.5f),
1989 gViewerWindow->getWindowHeight() - DIST_FROM_TOP,
1990 LLColor4(1, 1, 1, 0.4f),
1991 LLFontGL::HCENTER, LLFontGL::TOP);
1992 }
1993
1994 LLUI::sGLScaleFactor = old_scale_factor;
1995 }
1996 glPopMatrix();
1997
1998
1999#if LL_DEBUG
2000 LLView::sIsDrawing = FALSE;
2001#endif
2002}
2003
2004// Takes a single keydown event, usually when UI is visible
2005BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
2006{
2007 if (gFocusMgr.getKeyboardFocus() && !(mask & (MASK_CONTROL | MASK_ALT)))
2008 {
2009 // We have keyboard focus, and it's not an accelerator
2010
2011 if (key < 0x80)
2012 {
2013 // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first.
2014 return gFocusMgr.childHasKeyboardFocus(mRootView);
2015 }
2016 }
2017
2018 // HACK look for UI editing keys
2019 if (LLView::sEditingUI)
2020 {
2021 if (LLFloaterEditUI::handleKey(key, mask))
2022 {
2023 return TRUE;
2024 }
2025 }
2026
2027 // Hide tooltips on keypress
2028 if(mToolTip )
2029 {
2030 mToolTipBlocked = TRUE; // block until next time mouse is moved
2031 mToolTip->setVisible( FALSE );
2032 }
2033
2034 // Also hide hover info on keypress
2035 if (gHoverView)
2036 {
2037 gHoverView->cancelHover();
2038
2039 gHoverView->setTyping(TRUE);
2040 }
2041
2042 // Explicit hack for debug menu.
2043 if ((MASK_ALT & mask) &&
2044 (MASK_CONTROL & mask) &&
2045 ('D' == key || 'd' == key))
2046 {
2047 toggle_debug_menus(NULL);
2048 }
2049
2050 // Example "bug" for bug reporter web page
2051 if ((MASK_SHIFT & mask)
2052 && (MASK_ALT & mask)
2053 && (MASK_CONTROL & mask)
2054 && ('H' == key || 'h' == key))
2055 {
2056 trigger_hippo_bug(NULL);
2057 }
2058
2059 // handle escape key
2060 if (key == KEY_ESCAPE && mask == MASK_NONE)
2061 {
2062 if (gMenuHolder && gMenuHolder->hideMenus())
2063 {
2064 return TRUE;
2065 }
2066
2067 // *TODO: get this to play well with mouselook and hidden
2068 // cursor modes, etc, and re-enable.
2069 //if (gFocusMgr.getMouseCapture())
2070 //{
2071 // gFocusMgr.setMouseCapture(NULL, NULL);
2072 // return TRUE;
2073 //}
2074 }
2075
2076 // let menus handle navigation keys
2077 if (gMenuBarView && gMenuBarView->handleKey(key, mask, TRUE))
2078 {
2079 return TRUE;
2080 }
2081
2082 // Traverses up the hierarchy
2083 LLUICtrl* keyboard_focus = gFocusMgr.getKeyboardFocus();
2084 if( keyboard_focus )
2085 {
2086 // arrow keys move avatar while chatting hack
2087 if (gChatBar && gChatBar->inputEditorHasFocus())
2088 {
2089 if (gChatBar->getCurrentChat().empty() || gSavedSettings.getBOOL("ArrowKeysMoveAvatar"))
2090 {
2091 switch(key)
2092 {
2093 case KEY_LEFT:
2094 case KEY_RIGHT:
2095 case KEY_UP:
2096 case KEY_DOWN:
2097 case KEY_PAGE_UP:
2098 case KEY_PAGE_DOWN:
2099 case KEY_HOME:
2100 // when chatbar is empty or ArrowKeysMoveAvatar set, pass arrow keys on to avatar...
2101 return FALSE;
2102 default:
2103 break;
2104 }
2105 }
2106 }
2107
2108 if (keyboard_focus->handleKey(key, mask, FALSE))
2109 {
2110 return TRUE;
2111 }
2112 }
2113
2114 if (gToolMgr)
2115 {
2116 if( gToolMgr->getCurrentTool(mask)->handleKey(key, mask) )
2117 {
2118 return TRUE;
2119 }
2120 }
2121
2122 // Try for a new-format gesture
2123 if (gGestureManager.triggerGesture(key, mask))
2124 {
2125 return TRUE;
2126 }
2127
2128 // See if this is a gesture trigger. If so, eat the key and
2129 // don't pass it down to the menus.
2130 if (gGestureList.trigger(key, mask))
2131 {
2132 return TRUE;
2133 }
2134
2135 // Topmost view gets a chance before the hierarchy
2136 // *FIX: get rid of this?
2137 LLView* top_view = gFocusMgr.getTopView();
2138 if (top_view)
2139 {
2140 if( top_view->handleKey( key, mask, TRUE ) )
2141 {
2142 return TRUE;
2143 }
2144 }
2145
2146 // give floaters first chance to handle TAB key
2147 // so frontmost floater gets focus
2148 if (key == KEY_TAB)
2149 {
2150 // if nothing has focus, go to first or last UI element as appropriate
2151 if (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL)
2152 {
2153 if (gMenuHolder) gMenuHolder->hideMenus();
2154
2155 // if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode
2156 gFloaterView->setCycleMode((mask & MASK_CONTROL) != 0);
2157
2158 // do CTRL-TAB and CTRL-SHIFT-TAB logic
2159 if (mask & MASK_SHIFT)
2160 {
2161 mRootView->focusPrevRoot();
2162 }
2163 else
2164 {
2165 mRootView->focusNextRoot();
2166 }
2167 return TRUE;
2168 }
2169 }
2170
2171 // give menus a chance to handle keys
2172 if (gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
2173 {
2174 return TRUE;
2175 }
2176
2177 // don't pass keys on to world when something in ui has focus
2178 return gFocusMgr.childHasKeyboardFocus(mRootView) || (gMenuBarView && gMenuBarView->getHighlightedItem());
2179}
2180
2181
2182BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
2183{
2184 // HACK: We delay processing of return keys until they arrive as a Unicode char,
2185 // so that if you're typing chat text at low frame rate, we don't send the chat
2186 // until all keystrokes have been entered. JC
2187 // HACK: Numeric keypad <enter> on Mac is Unicode 3
2188 // HACK: Control-M on Windows is Unicode 13
2189 if ((uni_char == 13 && mask != MASK_CONTROL)
2190 || (uni_char == 3 && mask == MASK_NONE))
2191 {
2192 return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
2193 }
2194
2195 // let menus handle navigation (jump) keys
2196 if (gMenuBarView && gMenuBarView->handleUnicodeChar(uni_char, TRUE))
2197 {
2198 return TRUE;
2199 }
2200
2201 // Traverses up the hierarchy
2202 LLView* keyboard_focus = gFocusMgr.getKeyboardFocus();
2203 if( keyboard_focus )
2204 {
2205 if (keyboard_focus->handleUnicodeChar(uni_char, FALSE))
2206 {
2207 return TRUE;
2208 }
2209
2210 // Topmost view gets a chance before the hierarchy
2211 LLView* top_view = gFocusMgr.getTopView();
2212 if (top_view && top_view->handleUnicodeChar( uni_char, FALSE ) )
2213 {
2214 return TRUE;
2215 }
2216
2217 return TRUE;
2218 }
2219
2220 return FALSE;
2221}
2222
2223
2224void LLViewerWindow::handleScrollWheel(S32 clicks)
2225{
2226 gMouseIdleTimer.reset();
2227
2228 // Hide tooltips
2229 if( mToolTip )
2230 {
2231 mToolTip->setVisible( FALSE );
2232 }
2233
2234 LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
2235 if( mouse_captor )
2236 {
2237 S32 local_x;
2238 S32 local_y;
2239 mouse_captor->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
2240 mouse_captor->handleScrollWheel(local_x, local_y, clicks);
2241 if (LLView::sDebugMouseHandling)
2242 {
2243 llinfos << "Scroll Wheel handled by captor " << mouse_captor->getName() << llendl;
2244 }
2245 return;
2246 }
2247
2248 LLView* top_view = gFocusMgr.getTopView();
2249 if (top_view)
2250 {
2251 S32 local_x;
2252 S32 local_y;
2253 top_view->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
2254 if (top_view->handleScrollWheel(local_x, local_y, clicks)) return;
2255 }
2256
2257 if (mRootView->handleScrollWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks) )
2258 {
2259 if (LLView::sDebugMouseHandling)
2260 {
2261 llinfos << "Scroll Wheel" << LLView::sMouseHandlerMessage << llendl;
2262 LLView::sMouseHandlerMessage = "";
2263 }
2264 return;
2265 }
2266 else if (LLView::sDebugMouseHandling)
2267 {
2268 llinfos << "Scroll Wheel not handled by view" << llendl;
2269 }
2270
2271 if (gWorldPointer)
2272 {
2273 // Zoom the camera in and out behavior
2274 gAgent.handleScrollWheel(clicks);
2275 }
2276
2277 return;
2278}
2279
2280void LLViewerWindow::moveCursorToCenter()
2281{
2282#if 1 // old version
2283
2284#if 0 // Dave's changes - this reportedly is making the drift worse on some systems?
2285 S32 x = llround((F32) mVirtualWindowRect.getWidth() / 2);
2286 S32 y = llround((F32) mVirtualWindowRect.getHeight() / 2);
2287#else
2288 S32 x = mVirtualWindowRect.getWidth() / 2;
2289 S32 y = mVirtualWindowRect.getHeight() / 2;
2290#endif
2291
2292 //on a forced move, all deltas get zeroed out to prevent jumping
2293 mCurrentMousePoint.set(x,y);
2294 mLastMousePoint.set(x,y);
2295 mCurrentMouseDelta.set(0,0);
2296
2297 LLUI::setCursorPositionScreen(x, y);
2298
2299#else // Richard's version - fails on intel macs
2300
2301 S32 x = llround((F32) mWindowRect.getWidth() / 2);
2302 S32 y = llround((F32) mWindowRect.getHeight() / 2);
2303
2304 LLCoordWindow window_point;
2305 mWindow->convertCoords(LLCoordGL(x, y), &window_point);
2306 mWindow->setCursorPosition(window_point);
2307
2308 // read back cursor position
2309 mWindow->getCursorPosition(&window_point);
2310 LLCoordGL new_mouse_pos;
2311 mWindow->convertCoords(window_point, &new_mouse_pos);
2312 new_mouse_pos.mX = llround((F32)new_mouse_pos.mX / mDisplayScale.mV[VX]);
2313 new_mouse_pos.mY = llround((F32)new_mouse_pos.mY / mDisplayScale.mV[VY]);
2314
2315 //on a forced move, all deltas get zeroed out to prevent jumping
2316 mCurrentMousePoint = new_mouse_pos;
2317 mLastMousePoint = new_mouse_pos;
2318 mCurrentMouseDelta.set(0,0);
2319#endif
2320}
2321
2322//////////////////////////////////////////////////////////////////////
2323//
2324// Hover handlers
2325//
2326
2327// Update UI based on stored mouse position from mouse-move
2328// event processing.
2329BOOL LLViewerWindow::handlePerFrameHover()
2330{
2331 static std::string last_handle_msg;
2332
2333 //RN: fix for asynchronous notification of mouse leaving window not working
2334 LLCoordWindow mouse_pos;
2335 mWindow->getCursorPosition(&mouse_pos);
2336 if (mouse_pos.mX < 0 ||
2337 mouse_pos.mY < 0 ||
2338 mouse_pos.mX > mWindowRect.getWidth() ||
2339 mouse_pos.mY > mWindowRect.getHeight())
2340 {
2341 mMouseInWindow = FALSE;
2342 }
2343 else
2344 {
2345 mMouseInWindow = TRUE;
2346 }
2347
2348 S32 dx = mCurrentMousePoint.mX - mLastMousePoint.mX;
2349 S32 dy = mCurrentMousePoint.mY - mLastMousePoint.mY;
2350 mCurrentMouseDelta.set(dx,dy);
2351 LLVector2 mouse_vel((F32)dx, (F32)dy);
2352 mMouseVelocityStat.addValue(mouse_vel.magVec());
2353
2354 if (gNoRender)
2355 {
2356 return TRUE;
2357 }
2358
2359 S32 x = mCurrentMousePoint.mX;
2360 S32 y = mCurrentMousePoint.mY;
2361 MASK mask = gKeyboard->currentMask(TRUE);
2362
2363 // clean up current focus
2364 LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus();
2365 if (cur_focus)
2366 {
2367 if (!cur_focus->isInVisibleChain() || !cur_focus->isInEnabledChain())
2368 {
2369 gFocusMgr.releaseFocusIfNeeded(cur_focus);
2370
2371 LLView* parent = cur_focus->getParent();
2372 LLView* focus_root = cur_focus->findRootMostFocusRoot();
2373 while(parent)
2374 {
2375 if (parent->isCtrl() &&
2376 (((LLUICtrl*)parent)->hasTabStop() || parent == focus_root) &&
2377 !((LLUICtrl*)parent)->getIsChrome() &&
2378 parent->isInVisibleChain() &&
2379 parent->isInEnabledChain())
2380 {
2381 if (!parent->focusFirstItem())
2382 {
2383 ((LLUICtrl*)parent)->setFocus(TRUE);
2384 }
2385 break;
2386 }
2387 parent = parent->getParent();
2388 }
2389 }
2390 else if (cur_focus->isFocusRoot())
2391 {
2392 // focus roots keep trying to delegate focus to their first valid descendant
2393 // this assumes that focus roots are not valid focus holders on their own
2394 cur_focus->focusFirstItem();
2395 }
2396 }
2397
2398 // Show joints while in edit mode and hold down alt key.
2399 if (gHUDManager)
2400 {
2401 if (gSavedSettings.getBOOL("AltShowsPhysical")
2402 || (gFloaterTools && gFloaterTools->getVisible()))
2403 {
2404 gHUDManager->toggleShowPhysical( mask & MASK_ALT );
2405 }
2406 }
2407
2408 BOOL handled = FALSE;
2409
2410 BOOL handled_by_top_view = FALSE;
2411 LLView* top_view = gFocusMgr.getTopView();
2412
2413 LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
2414 if( mouse_captor )
2415 {
2416 // Pass hover events to object capturing mouse events.
2417 S32 local_x;
2418 S32 local_y;
2419 mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
2420 handled = mouse_captor->handleHover(local_x, local_y, mask);
2421 if (LLView::sDebugMouseHandling)
2422 {
2423 llinfos << "Hover handled by captor " << mouse_captor->getName() << llendl;
2424 }
2425
2426 if( !handled )
2427 {
2428 lldebugst(LLERR_USER_INPUT) << "hover not handled by mouse captor" << llendl;
2429 }
2430 }
2431 else
2432 {
2433 if (top_view)
2434 {
2435 S32 local_x, local_y;
2436 top_view->screenPointToLocal( x, y, &local_x, &local_y );
2437 handled = top_view->pointInView(local_x, local_y) && top_view->handleHover(local_x, local_y, mask);
2438 handled_by_top_view = TRUE;
2439 }
2440
2441 if ( !handled )
2442 {
2443 // x and y are from last time mouse was in window
2444 // mMouseInWindow tracks *actual* mouse location
2445 if (mMouseInWindow && mRootView->handleHover(x, y, mask) )
2446 {
2447 if (LLView::sDebugMouseHandling && LLView::sMouseHandlerMessage != last_handle_msg)
2448 {
2449 last_handle_msg = LLView::sMouseHandlerMessage;
2450 llinfos << "Hover" << LLView::sMouseHandlerMessage << llendl;
2451 }
2452 LLView::sMouseHandlerMessage = "";
2453 handled = TRUE;
2454 }
2455 else if (LLView::sDebugMouseHandling)
2456 {
2457 if (last_handle_msg != "")
2458 {
2459 last_handle_msg = "";
2460 llinfos << "Hover not handled by view" << llendl;
2461 }
2462 }
2463 }
2464
2465 if( !handled )
2466 {
2467 lldebugst(LLERR_USER_INPUT) << "hover not handled by top view or root" << llendl;
2468 }
2469 }
2470
2471 // *NOTE: sometimes tools handle the mouse as a captor, so this
2472 // logic is a little confusing
2473 LLTool *tool = NULL;
2474 if (gToolMgr && gHoverView)
2475 {
2476 tool = gToolMgr->getCurrentTool(mask);
2477
2478 if(!handled && tool)
2479 {
2480 handled = tool->handleHover(x, y, mask);
2481
2482 if (!mWindow->isCursorHidden())
2483 {
2484 gHoverView->updateHover(tool);
2485 }
2486 }
2487 else
2488 {
2489 // Cancel hovering if any UI element handled the event.
2490 gHoverView->cancelHover();
2491 }
2492
2493 // Suppress the toolbox view if our source tool was the pie tool,
2494 // and we've overridden to something else.
2495 mSuppressToolbox =
2496 (gToolMgr->getCurrentTool(MASK_NONE) == gToolPie) &&
2497 (gToolMgr->getCurrentTool(mask) != gToolPie);
2498
2499 }
2500
2501 //llinfos << (mToolTipBlocked ? "BLOCKED" : "NOT BLOCKED") << llendl;
2502 // Show a new tool tip (or update one that is alrady shown)
2503 BOOL tool_tip_handled = FALSE;
2504 LLString tool_tip_msg;
2505 F32 tooltip_delay = gSavedSettings.getF32( "ToolTipDelay" );
2506 //HACK: hack for tool-based tooltips which need to pop up more quickly
2507 //Also for show xui names as tooltips debug mode
2508 if ((mouse_captor && !mouse_captor->isView()) || LLUI::sShowXUINames)
2509 {
2510 tooltip_delay = gSavedSettings.getF32( "DragAndDropToolTipDelay" );
2511 }
2512 if( handled &&
2513 !mToolTipBlocked &&
2514 (gMouseIdleTimer.getElapsedTimeF32() > tooltip_delay) &&
2515 !mWindow->isCursorHidden() )
2516 {
2517 LLRect screen_sticky_rect;
2518
2519 if (mouse_captor)
2520 {
2521 S32 local_x, local_y;
2522 mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
2523 tool_tip_handled = mouse_captor->handleToolTip( local_x, local_y, tool_tip_msg, &screen_sticky_rect );
2524 }
2525 else if (handled_by_top_view)
2526 {
2527 S32 local_x, local_y;
2528 top_view->screenPointToLocal( x, y, &local_x, &local_y );
2529 tool_tip_handled = top_view->handleToolTip( local_x, local_y, tool_tip_msg, &screen_sticky_rect );
2530 }
2531 else
2532 {
2533 tool_tip_handled = mRootView->handleToolTip(x, y, tool_tip_msg, &screen_sticky_rect );
2534 }
2535
2536 if( tool_tip_handled && !tool_tip_msg.empty() )
2537 {
2538 mToolTipStickyRect = screen_sticky_rect;
2539 mToolTip->setWrappedText( tool_tip_msg, 200 );
2540 mToolTip->reshapeToFitText();
2541 mToolTip->setOrigin( x, y );
2542 LLRect virtual_window_rect(0, getWindowHeight(), getWindowWidth(), 0);
2543 mToolTip->translateIntoRect( virtual_window_rect, FALSE );
2544 mToolTip->setVisible( TRUE );
2545 }
2546 }
2547
2548 if (tool != gToolNull && tool != gToolInspect && tool != gToolDragAndDrop && !gSavedSettings.getBOOL("FreezeTime"))
2549 {
2550 LLMouseHandler *captor = gFocusMgr.getMouseCapture();
2551 // With the null, inspect, or drag and drop tool, don't muck
2552 // with visibility.
2553
2554 if (gFloaterTools->isMinimized() ||
2555 (tool != gToolPie // not default tool
2556 && tool != gToolGun // not coming out of mouselook
2557 && !mSuppressToolbox // not override in third person
2558 && gCurrentToolset != gFaceEditToolset // not special mode
2559 && gCurrentToolset != gMouselookToolset
2560 && (!captor || captor->isView())) // not dragging
2561 )
2562 {
2563 // Force floater tools to be visible (unless minimized)
2564 if (!gFloaterTools->getVisible())
2565 {
2566 gFloaterTools->open();
2567 }
2568 // Update the location of the blue box tool popup
2569 LLCoordGL select_center_screen;
2570 gFloaterTools->updatePopup( select_center_screen, mask );
2571 }
2572 else
2573 {
2574 gFloaterTools->setVisible(FALSE);
2575 }
2576 }
2577 if (gToolBar)
2578 {
2579 gToolBar->refresh();
2580 }
2581
2582 if (gChatBar)
2583 {
2584 gChatBar->refresh();
2585 }
2586
2587 if (gOverlayBar)
2588 {
2589 gOverlayBar->refresh();
2590 }
2591
2592 // Update rectangles for the various toolbars
2593 if (gToolBar && gChatBar && gOverlayBar && gNotifyBoxView && gConsole)
2594 {
2595 LLRect bar_rect(-1, STATUS_BAR_HEIGHT, getWindowWidth()+1, -1);
2596 if (gToolBar->getVisible())
2597 {
2598 gToolBar->setRect(bar_rect);
2599 bar_rect.translate(0, STATUS_BAR_HEIGHT-1);
2600 }
2601
2602 if (gChatBar->getVisible())
2603 {
2604 // fix up the height
2605 LLRect chat_bar_rect = bar_rect;
2606 chat_bar_rect.mTop = chat_bar_rect.mBottom + CHAT_BAR_HEIGHT + 1;
2607 gChatBar->setRect(chat_bar_rect);
2608 bar_rect.translate(0, CHAT_BAR_HEIGHT-1);
2609 }
2610
2611 LLRect notify_box_rect = gNotifyBoxView->getRect();
2612 notify_box_rect.mBottom = bar_rect.mBottom;
2613 gNotifyBoxView->reshape(notify_box_rect.getWidth(), notify_box_rect.getHeight());
2614 gNotifyBoxView->setRect(notify_box_rect);
2615
2616 // make sure floaters snap to visible rect by adjusting floater view rect
2617 LLRect floater_rect = gFloaterView->getRect();
2618 if (floater_rect.mBottom != bar_rect.mBottom+1)
2619 {
2620 floater_rect.mBottom = bar_rect.mBottom+1;
2621 // Don't bounce the floaters up and down.
2622 gFloaterView->reshape(floater_rect.getWidth(), floater_rect.getHeight(),
2623 TRUE, ADJUST_VERTICAL_NO);
2624 gFloaterView->setRect(floater_rect);
2625 }
2626
2627 if (gOverlayBar->getVisible())
2628 {
2629 LLRect overlay_rect = bar_rect;
2630 overlay_rect.mTop = overlay_rect.mBottom + OVERLAY_BAR_HEIGHT;
2631
2632 // Fitt's Law: Push buttons flush with bottom of screen if
2633 // nothing else visible.
2634 if (!gToolBar->getVisible()
2635 && !gChatBar->getVisible())
2636 {
2637 // *NOTE: this is highly depenent on the XML
2638 // describing the position of the buttons
2639 overlay_rect.translate(0, 0);
2640 }
2641
2642 gOverlayBar->setRect(overlay_rect);
2643 gOverlayBar->updateRect();
2644 bar_rect.translate(0, gOverlayBar->getRect().getHeight());
2645
2646 gFloaterView->setSnapOffsetBottom(OVERLAY_BAR_HEIGHT);
2647 }
2648 else
2649 {
2650 gFloaterView->setSnapOffsetBottom(0);
2651 }
2652
2653 // fix rectangle of bottom panel focus indicator
2654 if(gBottomPanel && gBottomPanel->getFocusIndicator())
2655 {
2656 LLRect focus_rect = gBottomPanel->getFocusIndicator()->getRect();
2657 focus_rect.mTop = (gToolBar->getVisible() ? STATUS_BAR_HEIGHT : 0) +
2658 (gChatBar->getVisible() ? CHAT_BAR_HEIGHT : 0) - 2;
2659 gBottomPanel->getFocusIndicator()->setRect(focus_rect);
2660 }
2661
2662 // Always update console
2663 LLRect console_rect = gConsole->getRect();
2664 console_rect.mBottom = bar_rect.mBottom + 8;
2665 gConsole->reshape(console_rect.getWidth(), console_rect.getHeight());
2666 gConsole->setRect(console_rect);
2667 }
2668
2669 mLastMousePoint = mCurrentMousePoint;
2670
2671 // last ditch force of edit menu to selection manager
2672 if (gEditMenuHandler == NULL && gSelectMgr && gSelectMgr->getObjectCount())
2673 {
2674 gEditMenuHandler = gSelectMgr;
2675 }
2676
2677 if (gFloaterView->getCycleMode())
2678 {
2679 // sync all floaters with their focus state
2680 gFloaterView->highlightFocusedFloater();
2681 gSnapshotFloaterView->highlightFocusedFloater();
2682 if ((gKeyboard->currentMask(TRUE) & MASK_CONTROL) == 0)
2683 {
2684 // control key no longer held down, finish cycle mode
2685 gFloaterView->setCycleMode(FALSE);
2686
2687 gFloaterView->syncFloaterTabOrder();
2688 }
2689 else
2690 {
2691 // user holding down CTRL, don't update tab order of floaters
2692 }
2693 }
2694 else
2695 {
2696 // update focused floater
2697 gFloaterView->highlightFocusedFloater();
2698 gSnapshotFloaterView->highlightFocusedFloater();
2699 // make sure floater visible order is in sync with tab order
2700 gFloaterView->syncFloaterTabOrder();
2701 }
2702
2703 if (gSavedSettings.getBOOL("ChatBarStealsFocus") && gChatBar && gFocusMgr.getKeyboardFocus() == NULL && gChatBar->getVisible())
2704 {
2705 gChatBar->startChat(NULL);
2706 }
2707
2708 // sync land selection with edit and about land dialogs
2709 if (gParcelMgr
2710 && !gMenuHolder->hasVisibleMenu()
2711 && !LLFloaterLand::floaterVisible()
2712 && !LLFloaterBuyLand::isOpen()
2713 && !LLPanelLandGeneral::buyPassDialogVisible()
2714 && (!gFloaterTools || !gFloaterTools->getVisible()))
2715 {
2716 gParcelMgr->deselectLand();
2717 }
2718
2719 return handled;
2720}
2721
2722
2723void LLViewerWindow::saveLastMouse(const LLCoordGL &point)
2724{
2725 // Store last mouse location.
2726 // If mouse leaves window, pretend last point was on edge of window
2727 if (point.mX < 0)
2728 {
2729 mCurrentMousePoint.mX = 0;
2730 }
2731 else if (point.mX > getWindowWidth())
2732 {
2733 mCurrentMousePoint.mX = getWindowWidth();
2734 }
2735 else
2736 {
2737 mCurrentMousePoint.mX = point.mX;
2738 }
2739
2740 if (point.mY < 0)
2741 {
2742 mCurrentMousePoint.mY = 0;
2743 }
2744 else if (point.mY > getWindowHeight() )
2745 {
2746 mCurrentMousePoint.mY = getWindowHeight();
2747 }
2748 else
2749 {
2750 mCurrentMousePoint.mY = point.mY;
2751 }
2752}
2753
2754
2755// Draws the selection outlines for the currently selected objects
2756// Must be called after displayObjects is called, which sets the mGLName parameter
2757// NOTE: This function gets called 3 times:
2758// render_ui_3d: FALSE, FALSE, TRUE
2759// renderObjectsForSelect: TRUE, pick_parcel_wall, FALSE
2760// render_hud_elements: FALSE, FALSE, FALSE
2761void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, BOOL for_hud )
2762{
2763 LLViewerObject* object;
2764
2765 if (!for_hud && !for_gl_pick)
2766 {
2767 // Call this once and only once
2768 gSelectMgr->updateSilhouettes();
2769 }
2770
2771 // Draw fence around land selections
2772 if (for_gl_pick)
2773 {
2774 if (pick_parcel_walls)
2775 {
2776 gParcelMgr->renderParcelCollision();
2777 }
2778 }
2779 else if (( for_hud && gSelectMgr->getSelectType() == SELECT_TYPE_HUD) ||
2780 (!for_hud && gSelectMgr->getSelectType() != SELECT_TYPE_HUD))
2781 {
2782 gSelectMgr->renderSilhouettes(for_hud);
2783
2784 stop_glerror();
2785
2786 // setup HUD render
2787 if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD && gSelectMgr->getObjectCount())
2788 {
2789 LLBBox hud_bbox = gAgent.getAvatarObject()->getHUDBBox();
2790
2791 // set up transform to encompass bounding box of HUD
2792 glMatrixMode(GL_PROJECTION);
2793 glPushMatrix();
2794 glLoadIdentity();
2795 F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
2796 glOrtho(-0.5f * gCamera->getAspect(), 0.5f * gCamera->getAspect(), -0.5f, 0.5f, 0.f, depth);
2797
2798 glMatrixMode(GL_MODELVIEW);
2799 glPushMatrix();
2800 glLoadIdentity();
2801 glLoadMatrixf(OGL_TO_CFR_ROTATION); // Load Cory's favorite reference frame
2802 glTranslatef(-hud_bbox.getCenterLocal().mV[VX] + (depth *0.5f), 0.f, 0.f);
2803 }
2804
2805 // Render light for editing
2806 if (LLSelectMgr::sRenderLightRadius)
2807 {
2808 LLGLEnable gls_blend(GL_BLEND);
2809 LLGLEnable gls_cull(GL_CULL_FACE);
2810 LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
2811 glMatrixMode(GL_MODELVIEW);
2812 glPushMatrix();
2813 if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD)
2814 {
2815 F32 zoom = gAgent.getAvatarObject()->mHUDCurZoom;
2816 glScalef(zoom, zoom, zoom);
2817 }
2818 for( object = gSelectMgr->getFirstObject(); object; object = gSelectMgr->getNextObject() )
2819 {
2820 LLDrawable* drawable = object->mDrawable;
2821 if (drawable && drawable->isLight())
2822 {
2823 LLVOVolume* vovolume = drawable->getVOVolume();
2824 glPushMatrix();
2825
2826 LLVector3 center = drawable->getPositionAgent();
2827 glTranslatef(center[0], center[1], center[2]);
2828 F32 scale = vovolume->getLightRadius();
2829 glScalef(scale, scale, scale);
2830
2831 LLColor4 color(vovolume->getLightColor(), .5f);
2832 glColor4fv(color.mV);
2833
2834 F32 pixel_area = 100000.f;
2835 // Render Outside
2836 gSphere.render(pixel_area);
2837
2838 // Render Inside
2839 glCullFace(GL_FRONT);
2840 gSphere.render(pixel_area);
2841 glCullFace(GL_BACK);
2842
2843 glPopMatrix();
2844 }
2845 }
2846 glPopMatrix();
2847 }
2848
2849 // NOTE: The average position for the axis arrows of the selected objects should
2850 // not be recalculated at this time. If they are, then group rotations will break.
2851
2852 // Draw arrows at average center of all selected objects
2853 LLTool* tool = gToolMgr->getCurrentTool( gKeyboard->currentMask(TRUE) );
2854 if (tool)
2855 {
2856 if(tool->isAlwaysRendered())
2857 {
2858 tool->render();
2859 }
2860 else
2861 {
2862 if( !gSelectMgr->isEmpty() )
2863 {
2864 BOOL moveable_object_selected = FALSE;
2865 BOOL all_selected_objects_move = TRUE;
2866 BOOL all_selected_objects_modify = TRUE;
2867 BOOL selecting_linked_set = gSavedSettings.getBOOL("SelectLinkedSet");
2868 for( object = gSelectMgr->getFirstObject(); object; object = gSelectMgr->getNextObject() )
2869 {
2870 BOOL this_object_movable = FALSE;
2871 if (object->permMove() && (object->permModify() || selecting_linked_set))
2872 {
2873 moveable_object_selected = TRUE;
2874 this_object_movable = TRUE;
2875 }
2876 all_selected_objects_move = all_selected_objects_move && this_object_movable;
2877 all_selected_objects_modify = all_selected_objects_modify && object->permModify();
2878 }
2879
2880 BOOL draw_handles = TRUE;
2881
2882 if (tool == gToolTranslate && (!moveable_object_selected || !all_selected_objects_move))
2883 {
2884 draw_handles = FALSE;
2885 }
2886
2887 if (tool == gToolRotate && (!moveable_object_selected || !all_selected_objects_move))
2888 {
2889 draw_handles = FALSE;
2890 }
2891
2892 if ( !all_selected_objects_modify && tool == gToolStretch )
2893 {
2894 draw_handles = FALSE;
2895 }
2896
2897 if( draw_handles )
2898 {
2899 tool->render();
2900 }
2901 }
2902 }
2903 if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD && gSelectMgr->getObjectCount())
2904 {
2905 glMatrixMode(GL_PROJECTION);
2906 glPopMatrix();
2907
2908 glMatrixMode(GL_MODELVIEW);
2909 glPopMatrix();
2910 stop_glerror();
2911 }
2912 }
2913 }
2914}
2915
2916// Return a point near the clicked object representative of the place the object was clicked.
2917LLVector3d LLViewerWindow::clickPointInWorldGlobal(S32 x, S32 y_from_bot, LLViewerObject* clicked_object) const
2918{
2919 // create a normalized vector pointing from the camera center into the
2920 // world at the location of the mouse click
2921 LLVector3 mouse_direction_global = mouseDirectionGlobal( x, y_from_bot );
2922
2923 LLVector3d relative_object = clicked_object->getPositionGlobal() - gAgent.getCameraPositionGlobal();
2924
2925 // make mouse vector as long as object vector, so it touchs a point near
2926 // where the user clicked on the object
2927 mouse_direction_global *= (F32) relative_object.magVec();
2928
2929 LLVector3d new_pos;
2930 new_pos.setVec(mouse_direction_global);
2931 // transform mouse vector back to world coords
2932 new_pos += gAgent.getCameraPositionGlobal();
2933
2934 return new_pos;
2935}
2936
2937
2938BOOL LLViewerWindow::clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewerObject *objectp, LLVector3d &point_global) const
2939{
2940 BOOL intersect = FALSE;
2941
2942// U8 shape = objectp->mPrimitiveCode & LL_PCODE_BASE_MASK;
2943 if (!intersect)
2944 {
2945 point_global = clickPointInWorldGlobal(x, y, objectp);
2946 llinfos << "approx intersection at " << (objectp->getPositionGlobal() - point_global) << llendl;
2947 }
2948 else
2949 {
2950 llinfos << "good intersection at " << (objectp->getPositionGlobal() - point_global) << llendl;
2951 }
2952
2953 return intersect;
2954}
2955
2956void LLViewerWindow::hitObjectOrLandGlobalAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(S32 x, S32 y, MASK mask), BOOL pick_transparent, BOOL pick_parcel_walls)
2957{
2958 if (gNoRender)
2959 {
2960 return;
2961 }
2962
2963 S32 scaled_x = llround((F32)x * mDisplayScale.mV[VX]);
2964 S32 scaled_y = llround((F32)y_from_bot * mDisplayScale.mV[VY]);
2965
2966 F32 delta_time = gAlphaFadeTimer.getElapsedTimeAndResetF32();
2967
2968 BOOL in_build_mode = gFloaterTools && gFloaterTools->getVisible();
2969 if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha)
2970 {
2971 // build mode allows interaction with all transparent objects
2972 // "Show Debug Alpha" means no object actually transparent
2973 pick_transparent = TRUE;
2974 }
2975 gPickTransparent = pick_transparent;
2976
2977 if (gPickTransparent)
2978 {
2979 gPickAlphaTargetThreshold = 0.f;
2980 gPickAlphaThreshold = llmax(gPickAlphaTargetThreshold, gPickAlphaThreshold - (delta_time * 0.7f));
2981 }
2982 else
2983 {
2984 gPickAlphaTargetThreshold = 1.f;
2985 gPickAlphaThreshold = llmin(gPickAlphaTargetThreshold, gPickAlphaThreshold + (delta_time * 0.7f));
2986 }
2987
2988 gUseGLPick = FALSE;
2989 mPickCallback = callback;
2990
2991 // Default to not hitting anything
2992 gLastHitPosGlobal.zeroVec();
2993 gLastHitObjectOffset.zeroVec();
2994 gLastHitObjectID.setNull();
2995 gLastHitObjectFace = -1;
2996
2997 gLastHitNonFloraPosGlobal.zeroVec();
2998 gLastHitNonFloraObjectOffset.zeroVec();
2999 gLastHitNonFloraObjectID.setNull();
3000 gLastHitNonFloraObjectFace = -1;
3001
3002 gLastHitParcelWall = FALSE;
3003
3004 LLCamera pick_camera;
3005 pick_camera.setOrigin(gCamera->getOrigin());
3006 pick_camera.setOriginAndLookAt(gCamera->getOrigin(),
3007 gCamera->getUpAxis(),
3008 gCamera->getOrigin() + mouseDirectionGlobal(x, y_from_bot));
3009 pick_camera.setView(0.5f*DEG_TO_RAD);
3010 pick_camera.setNear(gCamera->getNear());
3011 pick_camera.setFar(gCamera->getFar());
3012 pick_camera.setAspect(1.f);
3013
3014 // save our drawing state
3015 glMatrixMode(GL_MODELVIEW);
3016 glPushMatrix();
3017 glLoadIdentity();
3018
3019 glMatrixMode(GL_PROJECTION);
3020 glPushMatrix();
3021 glLoadIdentity();
3022
3023 // build perspective transform and picking viewport
3024 // Perform pick on a PICK_DIAMETER x PICK_DIAMETER pixel region around cursor point.
3025 // Don't limit the select distance for this pick.
3026 // make viewport big enough to handle antialiased frame buffers
3027 gCamera->setPerspective(FOR_SELECTION, scaled_x - (PICK_HALF_WIDTH + 2), scaled_y - (PICK_HALF_WIDTH + 2), PICK_DIAMETER + 4, PICK_DIAMETER + 4, FALSE);
3028 pick_camera.calcAgentFrustumPlanes(gCamera->mAgentFrustum);
3029 // make viewport big enough to handle antialiased frame buffers
3030 glViewport(scaled_x - (PICK_HALF_WIDTH + 2), scaled_y - (PICK_HALF_WIDTH + 2), PICK_DIAMETER + 4, PICK_DIAMETER + 4);
3031 stop_glerror();
3032
3033 glClearColor(0.f, 0.f, 0.f, 1.f);
3034 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
3035
3036 // Draw the objects so the user can select them.
3037 // The starting ID is 1, since land is zero.
3038 gObjectList.renderObjectsForSelect(pick_camera, pick_parcel_walls);
3039
3040 stop_glerror();
3041
3042 // restore drawing state
3043 glMatrixMode(GL_PROJECTION);
3044 glPopMatrix();
3045 glMatrixMode(GL_MODELVIEW);
3046 glPopMatrix();
3047
3048 setupViewport();
3049
3050 mPickPoint.set(x, y_from_bot);
3051 mPickOffset.set(0, 0);
3052 mPickMask = mask;
3053 mPickPending = TRUE;
3054
3055 // delay further event processing until we receive results of pick
3056 mWindow->delayInputProcessing();
3057}
3058
3059void LLViewerWindow::hitUIElementImmediate(S32 x, S32 y, void (*callback)(S32 x, S32 y, MASK mask))
3060{
3061 // Performs the GL UI pick.
3062 // Stores its results in global, gLastHitUIElement
3063 if (gNoRender)
3064 {
3065 return;
3066 }
3067
3068 hitUIElementAsync(x, y, gKeyboard->currentMask(TRUE), NULL);
3069 performPick();
3070 if (callback)
3071 {
3072 callback(x, y, gKeyboard->currentMask(TRUE));
3073 }
3074}
3075
3076//RN: this currently doesn't do anything
3077void LLViewerWindow::hitUIElementAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(S32 x, S32 y, MASK mask))
3078{
3079 if (gNoRender)
3080 {
3081 return;
3082 }
3083
3084// F32 delta_time = gAlphaFadeTimer.getElapsedTimeAndResetF32();
3085
3086 gUseGLPick = FALSE;
3087 mPickCallback = callback;
3088
3089 // Default to not hitting anything
3090 gLastHitUIElement = 0;
3091
3092 LLCamera pick_camera;
3093 pick_camera.setOrigin(gCamera->getOrigin());
3094 pick_camera.setOriginAndLookAt(gCamera->getOrigin(),
3095 gCamera->getUpAxis(),
3096 gCamera->getOrigin() + mouseDirectionGlobal(x, y_from_bot));
3097 pick_camera.setView(0.5f*DEG_TO_RAD);
3098 pick_camera.setNear(gCamera->getNear());
3099 pick_camera.setFar(gCamera->getFar());
3100 pick_camera.setAspect(1.f);
3101
3102 // save our drawing state
3103 glMatrixMode(GL_MODELVIEW);
3104 glPushMatrix();
3105 glLoadIdentity();
3106
3107 glMatrixMode(GL_PROJECTION);
3108 glPushMatrix();
3109 glLoadIdentity();
3110
3111 // build orthogonal transform and picking viewport
3112 // Perform pick on a PICK_DIAMETER x PICK_DIAMETER pixel region around cursor point.
3113 // Don't limit the select distance for this pick.
3114 gViewerWindow->setup2DRender();
3115 const LLVector2& display_scale = gViewerWindow->getDisplayScale();
3116 glScalef(display_scale.mV[VX], display_scale.mV[VY], 1.f);
3117
3118 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
3119
3120 // make viewport big enough to handle antialiased frame buffers
3121 glViewport(x - (PICK_HALF_WIDTH + 2), y_from_bot - (PICK_HALF_WIDTH + 2), PICK_DIAMETER + 4, PICK_DIAMETER + 4);
3122 stop_glerror();
3123
3124 glClearColor(0.f, 0.f, 0.f, 1.f);
3125 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
3126
3127 // Draw the objects so the user can select them.
3128 // The starting ID is 1, since land is zero.
3129 //gViewerWindow->drawForSelect();
3130
3131 stop_glerror();
3132
3133 // restore drawing state
3134 glMatrixMode(GL_PROJECTION);
3135 glPopMatrix();
3136 glMatrixMode(GL_MODELVIEW);
3137 glPopMatrix();
3138
3139 setupViewport();
3140
3141 mPickPoint.set(x, y_from_bot);
3142 mPickOffset.set(0, 0);
3143 mPickMask = mask;
3144 mPickPending = TRUE;
3145}
3146
3147void LLViewerWindow::performPick()
3148{
3149 if (gNoRender || !mPickPending)
3150 {
3151 return;
3152 }
3153
3154 finishFastFrame();
3155
3156 mPickPending = FALSE;
3157 U32 te_offset = NO_FACE;
3158
3159 // find pick region that is fully onscreen
3160 LLCoordGL scaled_pick_point = mPickPoint;
3161 scaled_pick_point.mX = llclamp(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX]), PICK_HALF_WIDTH, gViewerWindow->getWindowDisplayWidth() - PICK_HALF_WIDTH);
3162 scaled_pick_point.mY = llclamp(llround((F32)mPickPoint.mY * mDisplayScale.mV[VY]), PICK_HALF_WIDTH, gViewerWindow->getWindowDisplayHeight() - PICK_HALF_WIDTH);
3163
3164 glReadPixels(scaled_pick_point.mX - PICK_HALF_WIDTH, scaled_pick_point.mY - PICK_HALF_WIDTH, PICK_DIAMETER, PICK_DIAMETER, GL_RGBA, GL_UNSIGNED_BYTE, mPickBuffer);
3165
3166 S32 pixel_index = PICK_HALF_WIDTH * PICK_DIAMETER + PICK_HALF_WIDTH;
3167 S32 name = (U32)mPickBuffer[(pixel_index * 4) + 0] << 16 | (U32)mPickBuffer[(pixel_index * 4) + 1] << 8 | (U32)mPickBuffer[(pixel_index * 4) + 2];
3168 gLastPickAlpha = mPickBuffer[(pixel_index * 4) + 3];
3169
3170 if (name >= (S32)GL_NAME_UI_RESERVED && name < (S32)GL_NAME_INDEX_OFFSET)
3171 {
3172 // hit a UI element
3173 gLastHitUIElement = name;
3174 if (mPickCallback)
3175 {
3176 mPickCallback(mPickPoint.mX, mPickPoint.mY, mPickMask);
3177 }
3178 }
3179
3180 //imdebug("rgba rbga=bbba b=8 w=%d h=%d %p", PICK_DIAMETER, PICK_DIAMETER, mPickBuffer);
3181
3182 S32 x_offset = mPickPoint.mX - llround((F32)scaled_pick_point.mX / mDisplayScale.mV[VX]);
3183 S32 y_offset = mPickPoint.mY - llround((F32)scaled_pick_point.mY / mDisplayScale.mV[VY]);
3184
3185
3186 // we hit nothing, scan surrounding pixels for something useful
3187 if (!name)
3188 {
3189 S32 closest_distance = 10000;
3190 //S32 closest_pick_name = 0;
3191 for (S32 col = 0; col < PICK_DIAMETER; col++)
3192 {
3193 for (S32 row = 0; row < PICK_DIAMETER; row++)
3194 {
3195 S32 distance_squared = (llabs(col - x_offset - PICK_HALF_WIDTH) * llabs(col - x_offset - PICK_HALF_WIDTH)) + (llabs(row - y_offset - PICK_HALF_WIDTH) * llabs(row - y_offset - PICK_HALF_WIDTH));
3196 pixel_index = row * PICK_DIAMETER + col;
3197 S32 test_name = (U32)mPickBuffer[(pixel_index * 4) + 0] << 16 | (U32)mPickBuffer[(pixel_index * 4) + 1] << 8 | (U32)mPickBuffer[(pixel_index * 4) + 2];
3198 gLastPickAlpha = mPickBuffer[(pixel_index * 4) + 3];
3199 if (test_name && distance_squared < closest_distance)
3200 {
3201 closest_distance = distance_squared;
3202 name = test_name;
3203 gLastPickAlpha = mPickBuffer[(pixel_index * 4) + 3];
3204 mPickOffset.mX = col - PICK_HALF_WIDTH;
3205 mPickOffset.mY = row - PICK_HALF_WIDTH;
3206 }
3207 }
3208 }
3209 }
3210
3211 if (name)
3212 {
3213 mPickPoint.mX += llround((F32)mPickOffset.mX * mDisplayScale.mV[VX]);
3214 mPickPoint.mY += llround((F32)mPickOffset.mY * mDisplayScale.mV[VY]);
3215 }
3216
3217 if (gPickFaces)
3218 {
3219 te_offset = ((U32)name >> 20);
3220 name &= 0x000fffff;
3221 // don't clear gPickFaces, as we still need to check for UV coordinates
3222 }
3223
3224 LLViewerObject *objectp = NULL;
3225
3226 // Frontmost non-foreground object that isn't trees or grass
3227 LLViewerObject* nonflora_objectp = NULL;
3228 S32 nonflora_name = -1;
3229 S32 nonflora_te_offset = NO_FACE;
3230
3231 if (name == (S32)GL_NAME_PARCEL_WALL)
3232 {
3233 gLastHitParcelWall = TRUE;
3234 }
3235
3236 gLastHitHUDIcon = NULL;
3237
3238 objectp = gObjectList.getSelectedObject(name);
3239 if (objectp)
3240 {
3241 if (objectp->mbCanSelect)
3242 {
3243 te_offset = (te_offset == 16) ? NO_FACE : te_offset;
3244
3245 // If the hit object isn't a plant, store it as the frontmost non-flora object.
3246 LLPCode pcode = objectp->getPCode();
3247 if( (LL_PCODE_LEGACY_GRASS != pcode) &&
3248 (LL_PCODE_LEGACY_TREE != pcode) &&
3249 (LL_PCODE_TREE_NEW != pcode))
3250 {
3251 nonflora_objectp = objectp;
3252 nonflora_name = name;
3253 nonflora_te_offset = te_offset;
3254 }
3255 }
3256 else
3257 {
3258 //llinfos << "Hit object you can't select" << llendl;
3259 }
3260 }
3261 else
3262 {
3263 // was this name referring to a hud icon?
3264 gLastHitHUDIcon = LLHUDIcon::handlePick(name);
3265 }
3266
3267 analyzeHit(
3268 mPickPoint.mX, mPickPoint.mY, objectp, te_offset,
3269 &gLastHitObjectID, &gLastHitObjectFace, &gLastHitPosGlobal, &gLastHitLand, &gLastHitUCoord, &gLastHitVCoord );
3270
3271 if (objectp && !gLastHitObjectID.isNull())
3272 {
3273 gLastHitObjectOffset = gAgent.calcFocusOffset(objectp, mPickPoint.mX, mPickPoint.mY);
3274 }
3275
3276 if( objectp == nonflora_objectp )
3277 {
3278 gLastHitNonFloraObjectID = gLastHitObjectID;
3279 gLastHitNonFloraObjectFace = gLastHitObjectFace;
3280 gLastHitNonFloraPosGlobal = gLastHitPosGlobal;
3281 gLastHitNonFloraObjectOffset= gLastHitObjectOffset;
3282 }
3283 else
3284 {
3285 analyzeHit( mPickPoint.mX, mPickPoint.mY, nonflora_objectp, nonflora_te_offset,
3286 &gLastHitNonFloraObjectID, &gLastHitNonFloraObjectFace, &gLastHitNonFloraPosGlobal,
3287 &gLastHitLand, &gLastHitUCoord, &gLastHitVCoord);
3288
3289 if( nonflora_objectp )
3290 {
3291 gLastHitNonFloraObjectOffset = gAgent.calcFocusOffset(nonflora_objectp, mPickPoint.mX, mPickPoint.mY);
3292 }
3293 }
3294
3295 if (mPickCallback)
3296 {
3297 mPickCallback(mPickPoint.mX, mPickPoint.mY, mPickMask);
3298 }
3299
3300 gPickFaces = FALSE;
3301}
3302
3303// Performs the GL object/land pick.
3304// Stores its results in globals, gHit*
3305void LLViewerWindow::hitObjectOrLandGlobalImmediate(S32 x, S32 y_from_bot, void (*callback)(S32 x, S32 y, MASK mask), BOOL pick_transparent)
3306{
3307 if (gNoRender)
3308 {
3309 return;
3310 }
3311
3312 hitObjectOrLandGlobalAsync(x, y_from_bot, gKeyboard->currentMask(TRUE), NULL, pick_transparent);
3313 performPick();
3314 if (callback)
3315 {
3316 callback(x, y_from_bot, gKeyboard->currentMask(TRUE));
3317 }
3318}
3319
3320LLViewerObject* LLViewerWindow::getObjectUnderCursor(const F32 depth)
3321{
3322 S32 x = getCurrentMouseX();
3323 S32 y = getCurrentMouseY();
3324
3325 LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
3326 LLVector3 camera_pos_global = gCamera->getOrigin();
3327 LLVector3 pick_end = camera_pos_global + mouse_direction_global * depth;
3328 LLVector3 collision_point;
3329 return gPipeline.pickObject(camera_pos_global, pick_end, collision_point);
3330}
3331
3332void LLViewerWindow::analyzeHit(
3333 S32 x, // input
3334 S32 y_from_bot, // input
3335 LLViewerObject* objectp, // input
3336 U32 te_offset, // input
3337 LLUUID* hit_object_id_p,// output
3338 S32* hit_face_p, // output
3339 LLVector3d* hit_pos_p, // output
3340 BOOL* hit_land, // output
3341 F32* hit_u_coord, // output
3342 F32* hit_v_coord) // output
3343{
3344 // Clean up inputs
3345 S32 face = -1;
3346
3347 if (te_offset != NO_FACE )
3348 {
3349 face = te_offset;
3350 }
3351
3352 *hit_land = FALSE;
3353
3354 if (objectp)
3355 {
3356 if( objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH )
3357 {
3358 // Hit land
3359 *hit_land = TRUE;
3360
3361 // put global position into land_pos
3362 LLVector3d land_pos;
3363 if (mousePointOnLandGlobal(x, y_from_bot, &land_pos))
3364 {
3365 *hit_object_id_p = LLUUID::null;
3366 *hit_face_p = -1;
3367
3368 // Fudge the land focus a little bit above ground.
3369 *hit_pos_p = land_pos + LLVector3d(0.f, 0.f, 0.1f);
3370 //llinfos << "DEBUG Hit Land " << *hit_pos_p << llendl;
3371 return;
3372 }
3373 else
3374 {
3375 //llinfos << "Hit land but couldn't find position" << llendl;
3376 // Fall through to "Didn't hit anything"
3377 }
3378 }
3379 else
3380 {
3381 *hit_object_id_p = objectp->mID;
3382 *hit_face_p = face;
3383
3384 // Hit an object
3385 if (objectp->isAvatar())
3386 {
3387 *hit_pos_p = gAgent.getPosGlobalFromAgent(((LLVOAvatar*)objectp)->mPelvisp->getWorldPosition());
3388 }
3389 else if (objectp->mDrawable.notNull())
3390 {
3391 *hit_pos_p = gAgent.getPosGlobalFromAgent(objectp->getRenderPosition());
3392 }
3393 else
3394 {
3395 // regular object
3396 *hit_pos_p = objectp->getPositionGlobal();
3397 }
3398
3399 if (gPickFaces && face > -1 &&
3400 objectp->mDrawable.notNull() && objectp->getPCode() == LL_PCODE_VOLUME &&
3401 face < objectp->mDrawable->getNumFaces())
3402 {
3403 // render red-blue gradient to get 1/256 precision
3404 // then render green grid to get final 1/4096 precision
3405 S32 scaled_x = llround((F32)x * mDisplayScale.mV[VX]);
3406 S32 scaled_y = llround((F32)y_from_bot * mDisplayScale.mV[VY]);
3407 const S32 UV_PICK_WIDTH = 41;
3408 const S32 UV_PICK_HALF_WIDTH = (UV_PICK_WIDTH - 1) / 2;
3409 U8 uv_pick_buffer[UV_PICK_WIDTH * UV_PICK_WIDTH * 4];
3410 S32 pick_face = ((LLVOVolume*)objectp)->getAllTEsSame() ? 0 : face;
3411 LLFace* facep = objectp->mDrawable->getFace(objectp->getFaceIndexOffset() + pick_face);
3412 gCamera->setPerspective(FOR_SELECTION, scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, FALSE);
3413 glViewport(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH);
3414 gPipeline.renderFaceForUVSelect(facep);
3415
3416 glReadPixels(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, GL_RGBA, GL_UNSIGNED_BYTE, uv_pick_buffer);
3417 U8* center_pixel = &uv_pick_buffer[4 * ((UV_PICK_WIDTH * UV_PICK_HALF_WIDTH) + UV_PICK_HALF_WIDTH + 1)];
3418 *hit_u_coord = (F32)((center_pixel[VGREEN] & 0xf) + (16.f * center_pixel[VRED])) / 4095.f;
3419 *hit_v_coord = (F32)((center_pixel[VGREEN] >> 4) + (16.f * center_pixel[VBLUE])) / 4095.f;
3420 }
3421 else
3422 {
3423 *hit_u_coord = 0.f;
3424 *hit_v_coord = 0.f;
3425 }
3426
3427 //llinfos << "DEBUG Hit Object " << *hit_pos_p << llendl;
3428 return;
3429 }
3430 }
3431
3432 // Didn't hit anything.
3433 *hit_object_id_p = LLUUID::null;
3434 *hit_face_p = -1;
3435 *hit_pos_p = LLVector3d::zero;
3436 *hit_u_coord = 0.f;
3437 *hit_v_coord = 0.f;
3438 //llinfos << "DEBUG Hit Nothing " << llendl;
3439}
3440
3441
3442void LLViewerWindow::requestFastFrame(LLView *view)
3443{
3444 if (!mPickPending &&
3445 mWindow->getSwapMethod() != LLWindow::SWAP_METHOD_UNDEFINED &&
3446 gStartupState >= STATE_STARTED &&
3447 gSavedSettings.getBOOL("RenderFastUI") &&
3448 !gbCapturing)
3449 {
3450 if (!mFastFrameTimer.getStarted())
3451 {
3452 // we're double buffered, so when first requesting a fast ui update
3453 // we need to render the scene again so that the front and back buffers
3454 // are synced
3455 mRenderFullFrame = TRUE;
3456 }
3457 // calculation new expiration time and reset timer
3458 F32 expiration;
3459 if (mFastFrameTimer.hasExpired())
3460 {
3461 expiration = FAST_FRAME_INCREMENT;
3462 }
3463 else
3464 {
3465 expiration = llmin(MAX_FAST_FRAME_TIME, mFastFrameTimer.getTimeToExpireF32() + FAST_FRAME_INCREMENT);
3466 }
3467
3468 mFastFrameTimer.start();
3469 mFastFrameTimer.setTimerExpirySec(expiration);
3470
3471 LLView::sFastFrameView = view->getRootMostFastFrameView();
3472 if (!LLView::sFastFrameView)
3473 {
3474 LLView::sFastFrameView = view;
3475 }
3476 }
3477}
3478
3479
3480// Returns unit vector relative to camera
3481// indicating direction of point on screen x,y
3482LLVector3 LLViewerWindow::mouseDirectionGlobal(const S32 x, const S32 y) const
3483{
3484 // find vertical field of view
3485 F32 fov = gCamera->getView();
3486
3487 // find screen resolution
3488 S32 height = getWindowHeight();
3489 S32 width = getWindowWidth();
3490
3491 // calculate pixel distance to screen
3492 F32 distance = (height / 2.f) / (tan(fov / 2.f));
3493
3494 // calculate click point relative to middle of screen
3495 F32 click_x = x - width / 2.f;
3496 F32 click_y = y - height / 2.f;
3497
3498 // compute mouse vector
3499 LLVector3 mouse_vector = distance * gCamera->getAtAxis()
3500 - click_x * gCamera->getLeftAxis()
3501 + click_y * gCamera->getUpAxis();
3502
3503 mouse_vector.normVec();
3504
3505 return mouse_vector;
3506}
3507
3508
3509// Returns unit vector relative to camera in camera space
3510// indicating direction of point on screen x,y
3511LLVector3 LLViewerWindow::mouseDirectionCamera(const S32 x, const S32 y) const
3512{
3513 // find vertical field of view
3514 F32 fov_height = gCamera->getView();
3515 F32 fov_width = fov_height * gCamera->getAspect();
3516
3517 // find screen resolution
3518 S32 height = getWindowHeight();
3519 S32 width = getWindowWidth();
3520
3521 // calculate click point relative to middle of screen
3522 F32 click_x = (((F32)x / (F32)width) - 0.5f) * fov_width * -1.f;
3523 F32 click_y = (((F32)y / (F32)height) - 0.5f) * fov_height;
3524
3525 // compute mouse vector
3526 LLVector3 mouse_vector = LLVector3(0.f, 0.f, -1.f);
3527 LLQuaternion mouse_rotate;
3528 mouse_rotate.setQuat(click_y, click_x, 0.f);
3529
3530 mouse_vector = mouse_vector * mouse_rotate;
3531 // project to z = -1 plane;
3532 mouse_vector = mouse_vector * (-1.f / mouse_vector.mV[VZ]);
3533
3534 return mouse_vector;
3535}
3536
3537
3538
3539BOOL LLViewerWindow::mousePointOnPlaneGlobal(LLVector3d& point, const S32 x, const S32 y,
3540 const LLVector3d &plane_point_global,
3541 const LLVector3 &plane_normal_global)
3542{
3543 LLVector3d mouse_direction_global_d;
3544
3545 mouse_direction_global_d.setVec(mouseDirectionGlobal(x,y));
3546 LLVector3d plane_normal_global_d;
3547 plane_normal_global_d.setVec(plane_normal_global);
3548 F64 plane_mouse_dot = (plane_normal_global_d * mouse_direction_global_d);
3549 LLVector3d plane_origin_camera_rel = plane_point_global - gAgent.getCameraPositionGlobal();
3550 F64 mouse_look_at_scale = (plane_normal_global_d * plane_origin_camera_rel)
3551 / plane_mouse_dot;
3552 if (llabs(plane_mouse_dot) < 0.00001)
3553 {
3554 // if mouse is parallel to plane, return closest point on line through plane origin
3555 // that is parallel to camera plane by scaling mouse direction vector
3556 // by distance to plane origin, modulated by deviation of mouse direction from plane origin
3557 LLVector3d plane_origin_dir = plane_origin_camera_rel;
3558 plane_origin_dir.normVec();
3559
3560 mouse_look_at_scale = plane_origin_camera_rel.magVec() / (plane_origin_dir * mouse_direction_global_d);
3561 }
3562
3563 point = gAgent.getCameraPositionGlobal() + mouse_look_at_scale * mouse_direction_global_d;
3564
3565 return mouse_look_at_scale > 0.0;
3566}
3567
3568
3569// Returns global position
3570BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d *land_position_global)
3571{
3572 LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
3573 F32 mouse_dir_scale;
3574 BOOL hit_land = FALSE;
3575 LLViewerRegion *regionp;
3576 F32 land_z;
3577 const F32 FIRST_PASS_STEP = 1.0f; // meters
3578 const F32 SECOND_PASS_STEP = 0.1f; // meters
3579 LLVector3d camera_pos_global;
3580
3581 camera_pos_global = gAgent.getCameraPositionGlobal();
3582 LLVector3d probe_point_global;
3583 LLVector3 probe_point_region;
3584
3585 // walk forwards to find the point
3586 for (mouse_dir_scale = FIRST_PASS_STEP; mouse_dir_scale < gAgent.mDrawDistance; mouse_dir_scale += FIRST_PASS_STEP)
3587 {
3588 LLVector3d mouse_direction_global_d;
3589 mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale);
3590 probe_point_global = camera_pos_global + mouse_direction_global_d;
3591
3592 regionp = gWorldPointer->resolveRegionGlobal(probe_point_region, probe_point_global);
3593
3594 if (!regionp)
3595 {
3596 // ...we're outside the world somehow
3597 continue;
3598 }
3599
3600 S32 i = (S32) (probe_point_region.mV[VX]/regionp->getLand().getMetersPerGrid());
3601 S32 j = (S32) (probe_point_region.mV[VY]/regionp->getLand().getMetersPerGrid());
3602 S32 grids_per_edge = (S32) regionp->getLand().mGridsPerEdge;
3603 if ((i >= grids_per_edge) || (j >= grids_per_edge))
3604 {
3605 //llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl;
3606 continue;
3607 }
3608
3609 land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
3610
3611 //llinfos << "mousePointOnLand initial z " << land_z << llendl;
3612
3613 if (probe_point_region.mV[VZ] < land_z)
3614 {
3615 // ...just went under land
3616
3617 // cout << "under land at " << probe_point << " scale " << mouse_vec_scale << endl;
3618
3619 hit_land = TRUE;
3620 break;
3621 }
3622 }
3623
3624
3625 if (hit_land)
3626 {
3627 // Don't go more than one step beyond where we stopped above.
3628 // This can't just be "mouse_vec_scale" because floating point error
3629 // will stop the loop before the last increment.... X - 1.0 + 0.1 + 0.1 + ... + 0.1 != X
3630 F32 stop_mouse_dir_scale = mouse_dir_scale + FIRST_PASS_STEP;
3631
3632 // take a step backwards, then walk forwards again to refine position
3633 for ( mouse_dir_scale -= FIRST_PASS_STEP; mouse_dir_scale <= stop_mouse_dir_scale; mouse_dir_scale += SECOND_PASS_STEP)
3634 {
3635 LLVector3d mouse_direction_global_d;
3636 mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale);
3637 probe_point_global = camera_pos_global + mouse_direction_global_d;
3638
3639 regionp = gWorldPointer->resolveRegionGlobal(probe_point_region, probe_point_global);
3640
3641 if (!regionp)
3642 {
3643 // ...we're outside the world somehow
3644 continue;
3645 }
3646
3647 /*
3648 i = (S32) (local_probe_point.mV[VX]/regionp->getLand().getMetersPerGrid());
3649 j = (S32) (local_probe_point.mV[VY]/regionp->getLand().getMetersPerGrid());
3650 if ((i >= regionp->getLand().mGridsPerEdge) || (j >= regionp->getLand().mGridsPerEdge))
3651 {
3652 // llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl;
3653 continue;
3654 }
3655 land_z = regionp->getLand().mSurfaceZ[ i + j * (regionp->getLand().mGridsPerEdge) ];
3656 */
3657
3658 land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
3659
3660 //llinfos << "mousePointOnLand refine z " << land_z << llendl;
3661
3662 if (probe_point_region.mV[VZ] < land_z)
3663 {
3664 // ...just went under land again
3665
3666 *land_position_global = probe_point_global;
3667 return TRUE;
3668 }
3669 }
3670 }
3671
3672 return FALSE;
3673}
3674
3675// Saves an image to the harddrive as "SnapshotX" where X >= 1.
3676BOOL LLViewerWindow::saveImageNumbered(LLImageRaw *raw)
3677{
3678 if (! raw)
3679 {
3680 return FALSE;
3681 }
3682
3683 // Get a directory if this is the first time.
3684 if (strlen(sSnapshotDir) == 0)
3685 {
3686 LLString proposed_name( sSnapshotBaseName );
3687 proposed_name.append( ".bmp" );
3688
3689 // pick a directory in which to save
3690 LLFilePicker& picker = LLFilePicker::instance();
3691 if (!picker.getSaveFile(LLFilePicker::FFSAVE_BMP, proposed_name.c_str()))
3692 {
3693 // Clicked cancel
3694 return FALSE;
3695 }
3696
3697 // Copy the directory + file name
3698 char directory[LL_MAX_PATH];
3699 strcpy(directory, picker.getFirstFile());
3700
3701 // Smash the file extension
3702 S32 length = strlen(directory);
3703 S32 index = length;
3704
3705 // Back up over ".bmp"
3706 index -= 4;
3707 if (index >= 0 && directory[index] == '.')
3708 {
3709 directory[index] = '\0';
3710 }
3711 else
3712 {
3713 index = length;
3714 }
3715
3716 // Find trailing backslash
3717 while (index >= 0 && directory[index] != gDirUtilp->getDirDelimiter()[0])
3718 {
3719 index--;
3720 }
3721
3722 // If we found one, truncate the string there
3723 if (index >= 0)
3724 {
3725 if (index + 1 <= length)
3726 {
3727 strcpy(LLViewerWindow::sSnapshotBaseName, directory + index + 1);
3728 }
3729
3730 index++;
3731 directory[index] = '\0';
3732 strcpy(LLViewerWindow::sSnapshotDir, directory);
3733 }
3734 }
3735
3736 // Look for an unused file name
3737 LLString filepath;
3738 S32 i = 1;
3739 S32 err = 0;
3740
3741 do
3742 {
3743 char extension[100];
3744 sprintf( extension, "_%.3d.bmp", i );
3745 filepath = sSnapshotDir;
3746 filepath += sSnapshotBaseName;
3747 filepath += extension;
3748
3749 struct stat stat_info;
3750 err = gViewerWindow->mWindow->stat( filepath.c_str(), &stat_info );
3751 i++;
3752 }
3753 while( -1 != err ); // search until the file is not found (i.e., stat() gives an error).
3754
3755 LLPointer<LLImageBMP> bmp_image = new LLImageBMP;
3756 LLImageBase::setSizeOverride(TRUE);
3757 BOOL success = bmp_image->encode(raw);
3758 if( success )
3759 {
3760 success = bmp_image->save(filepath);
3761 }
3762 else
3763 {
3764 llwarns << "Unable to encode bmp snapshot" << llendl;
3765 }
3766 LLImageBase::setSizeOverride(FALSE);
3767
3768 return success;
3769}
3770
3771void LLViewerWindow::saveMovieNumbered(void*)
3772{
3773 if (!gbCapturing)
3774 {
3775 // Get a directory if this is the first time.
3776 if (strlen(sSnapshotDir) == 0)
3777 {
3778 LLString proposed_name( sMovieBaseName );
3779#if LL_DARWIN
3780 proposed_name.append( ".mov" );
3781#else
3782 proposed_name.append( ".avi" );
3783#endif
3784
3785 // pick a directory in which to save
3786 LLFilePicker &picker = LLFilePicker::instance();
3787 if (!picker.getSaveFile(LLFilePicker::FFSAVE_AVI, proposed_name.c_str()))
3788 {
3789 // Clicked cancel
3790 return;
3791 }
3792
3793 // Copy the directory + file name
3794 char directory[LL_MAX_PATH];
3795 strcpy(directory, picker.getFirstFile());
3796
3797 // Smash the file extension
3798 S32 length = strlen(directory);
3799 S32 index = length;
3800
3801 // Back up over ".bmp"
3802 index -= 4;
3803 if (index >= 0 && directory[index] == '.')
3804 {
3805 directory[index] = '\0';
3806 }
3807 else
3808 {
3809 index = length;
3810 }
3811
3812 // Find trailing backslash
3813 while (index >= 0 && directory[index] != gDirUtilp->getDirDelimiter()[0])
3814 {
3815 index--;
3816 }
3817
3818 // If we found one, truncate the string there
3819 if (index >= 0)
3820 {
3821 if (index + 1 <= length)
3822 {
3823 strcpy(LLViewerWindow::sMovieBaseName, directory + index + 1);
3824 }
3825
3826 index++;
3827 directory[index] = '\0';
3828 strcpy(LLViewerWindow::sSnapshotDir, directory);
3829 }
3830 }
3831
3832 // Look for an unused file name
3833 LLString filepath;
3834 S32 i = 1;
3835 S32 err = 0;
3836
3837 do
3838 {
3839 char extension[100];
3840#if LL_DARWIN
3841 sprintf( extension, "_%.3d.mov", i );
3842#else
3843 sprintf( extension, "_%.3d.avi", i );
3844#endif
3845 filepath.assign( sSnapshotDir );
3846 filepath.append( sMovieBaseName );
3847 filepath.append( extension );
3848
3849 struct stat stat_info;
3850 err = gViewerWindow->mWindow->stat( filepath.c_str(), &stat_info );
3851 i++;
3852 }
3853 while( -1 != err ); // search until the file is not found (i.e., stat() gives an error).
3854 S32 x = gViewerWindow->getWindowWidth();
3855 S32 y = gViewerWindow->getWindowHeight();
3856
3857 gbCapturing = TRUE;
3858 gMovieMaker.StartCapture((char *)filepath.c_str(), x, y);
3859 }
3860 else
3861 {
3862 gMovieMaker.EndCapture();
3863 gbCapturing = FALSE;
3864 }
3865}
3866
3867static S32 BORDERHEIGHT = 0;
3868static S32 BORDERWIDTH = 0;
3869
3870void LLViewerWindow::movieSize(S32 new_width, S32 new_height)
3871{
3872 LLCoordScreen size;
3873 gViewerWindow->mWindow->getSize(&size);
3874 if ( (size.mX != new_width + BORDERWIDTH)
3875 ||(size.mY != new_height + BORDERHEIGHT))
3876 {
3877 S32 x = gViewerWindow->getWindowWidth();
3878 S32 y = gViewerWindow->getWindowHeight();
3879 BORDERWIDTH = size.mX - x;
3880 BORDERHEIGHT = size.mY- y;
3881 LLCoordScreen new_size(new_width + BORDERWIDTH,
3882 new_height + BORDERHEIGHT);
3883 BOOL disable_sync = gSavedSettings.getBOOL("DisableVerticalSync");
3884 if (gViewerWindow->mWindow->getFullscreen())
3885 {
3886 gViewerWindow->changeDisplaySettings(FALSE,
3887 new_size,
3888 disable_sync,
3889 TRUE);
3890 }
3891 else
3892 {
3893 gViewerWindow->mWindow->setSize(new_size);
3894 }
3895 }
3896}
3897
3898BOOL LLViewerWindow::saveSnapshot( const LLString& filepath, S32 image_width, S32 image_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type)
3899{
3900 llinfos << "Saving snapshot to: " << filepath << llendl;
3901
3902 LLPointer<LLImageRaw> raw = new LLImageRaw;
3903 BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, show_ui, do_rebuild);
3904
3905 if (success)
3906 {
3907 LLPointer<LLImageBMP> bmp_image = new LLImageBMP;
3908 success = bmp_image->encode(raw);
3909 if( success )
3910 {
3911 success = bmp_image->save(filepath);
3912 }
3913 else
3914 {
3915 llwarns << "Unable to encode bmp snapshot" << llendl;
3916 }
3917 }
3918 else
3919 {
3920 llwarns << "Unable to capture raw snapshot" << llendl;
3921 }
3922
3923 return success;
3924}
3925
3926
3927void LLViewerWindow::playSnapshotAnimAndSound()
3928{
3929 gAgent.sendAnimationRequest(ANIM_AGENT_SNAPSHOT, ANIM_REQUEST_START);
3930 send_sound_trigger(LLUUID(gSavedSettings.getString("UISndSnapshot")), 1.0f);
3931}
3932
3933
3934// Saves the image from the screen to the specified filename and path.
3935BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height,
3936 BOOL keep_window_aspect, BOOL show_ui, BOOL do_rebuild, ESnapshotType type)
3937{
3938 F32 image_aspect_ratio = ((F32)image_width) / ((F32)image_height);
3939 F32 window_aspect_ratio = ((F32)getWindowWidth()) / ((F32)getWindowHeight());
3940
3941 if ((!gWorldPointer) ||
3942 (!raw))
3943 {
3944 return FALSE;
3945 }
3946
3947 // IW 3/5/04 We don'a wan' nunna yer fest frumes har!
3948 finishFastFrame();
3949
3950 // PRE SNAPSHOT
3951
3952 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
3953 setCursor(UI_CURSOR_WAIT);
3954
3955 // Hide all the UI widgets first and draw a frame
3956 BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
3957
3958 if ( prev_draw_ui != show_ui)
3959 {
3960 LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
3961 }
3962
3963 BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD);
3964 if (hide_hud)
3965 {
3966 LLPipeline::toggleRenderType((void*)LLPipeline::RENDER_TYPE_HUD);
3967 }
3968
3969 // Copy screen to a buffer
3970 // crop sides or top and bottom, if taking a snapshot of different aspect ratio
3971 // from window
3972 S32 snapshot_width = mWindowRect.getWidth();
3973 S32 snapshot_height = mWindowRect.getHeight();
3974 if (!keep_window_aspect)
3975 {
3976 if (image_aspect_ratio > window_aspect_ratio)
3977 {
3978 snapshot_height = llround((F32)snapshot_width / image_aspect_ratio);
3979 }
3980 else if (image_aspect_ratio < window_aspect_ratio)
3981 {
3982 snapshot_width = llround((F32)snapshot_height * image_aspect_ratio);
3983 }
3984 }
3985
3986 F32 scale_factor = llmax(1.f, (F32)image_width / snapshot_width, (F32)image_height / snapshot_height);
3987 raw->resize(llfloor(snapshot_width*scale_factor), llfloor(snapshot_height *scale_factor), type == SNAPSHOT_TYPE_DEPTH ? 4 : 3);
3988
3989 BOOL high_res = scale_factor > 1.f;
3990 if (high_res)
3991 {
3992 send_agent_pause();
3993 //rescale fonts
3994 initFonts(scale_factor);
3995 LLHUDText::reshape();
3996 }
3997
3998 // SNAPSHOT
3999 S32 window_width = mWindowRect.getWidth();
4000 S32 window_height = mWindowRect.getHeight();
4001 S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f);
4002 S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f);
4003
4004 S32 output_buffer_offset_y = 0;
4005
4006 F32 depth_conversion_factor_1 = (gCamera->getFar() + gCamera->getNear()) / (2.f * gCamera->getFar() * gCamera->getNear());
4007 F32 depth_conversion_factor_2 = (gCamera->getFar() - gCamera->getNear()) / (2.f * gCamera->getFar() * gCamera->getNear());
4008
4009 for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y)
4010 {
4011 S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height);;
4012 // handle fractional columns
4013 U32 read_height = llmax(0, (window_height - subimage_y_offset) -
4014 llmax(0, (window_height * (subimage_y + 1)) - (buffer_y_offset + raw->getHeight())));
4015
4016 S32 output_buffer_offset_x = 0;
4017 for (int subimage_x = 0; subimage_x < scale_factor; ++subimage_x)
4018 {
4019 gDisplaySwapBuffers = FALSE;
4020 if (type == SNAPSHOT_TYPE_OBJECT_ID)
4021 {
4022 glClearColor(0.f, 0.f, 0.f, 1.f);
4023 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
4024
4025 gCamera->setZoomParameters(scale_factor, subimage_x+(subimage_y*llceil(scale_factor)));
4026 setup3DRender();
4027 setupViewport();
4028 BOOL first_time_through = (subimage_x + subimage_y == 0);
4029 gPickTransparent = FALSE;
4030 gPickAlphaThreshold = 0.1f;
4031 gObjectList.renderObjectsForSelect(*gCamera, FALSE, !first_time_through);
4032 }
4033 else
4034 {
4035 display(do_rebuild, scale_factor, subimage_x+(subimage_y*llceil(scale_factor)));
4036 }
4037 glFlush();
4038 S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width);
4039 // handle fractional rows
4040 U32 read_width = llmax(0, (window_width - subimage_x_offset) -
4041 llmax(0, (window_width * (subimage_x + 1)) - (buffer_x_offset + raw->getWidth())));
4042 for(U32 out_y = 0; out_y < read_height ; out_y++)
4043 {
4044 if (type == SNAPSHOT_TYPE_OBJECT_ID || type == SNAPSHOT_TYPE_COLOR)
4045 {
4046 glReadPixels(
4047 subimage_x_offset, out_y + subimage_y_offset,
4048 read_width, 1,
4049 GL_RGB, GL_UNSIGNED_BYTE,
4050 raw->getData() + // current output pixel is beginning of buffer...
4051 (
4052 (out_y * (raw->getWidth())) // ...plus iterated y...
4053 + (window_width * subimage_x) // ...plus subimage start in x...
4054 + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y...
4055 - output_buffer_offset_x // ...minus buffer padding x...
4056 - (output_buffer_offset_y * (raw->getWidth())) // ...minus buffer padding y...
4057 ) * 3 // times 3 bytes per pixel
4058 );
4059 }
4060 else // SNAPSHOT_TYPE_DEPTH
4061 {
4062 S32 output_buffer_offset = (
4063 (out_y * (raw->getWidth())) // ...plus iterated y...
4064 + (window_width * subimage_x) // ...plus subimage start in x...
4065 + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y...
4066 - output_buffer_offset_x // ...minus buffer padding x...
4067 - (output_buffer_offset_y * (raw->getWidth())) // ...minus buffer padding y...
4068 ) * 4; // times 4 bytes per pixel
4069
4070 glReadPixels(
4071 subimage_x_offset, out_y + subimage_y_offset,
4072 read_width, 1,
4073 GL_DEPTH_COMPONENT, GL_FLOAT,
4074 raw->getData() + output_buffer_offset// current output pixel is beginning of buffer...
4075 );
4076
4077 for (S32 i = output_buffer_offset; i < output_buffer_offset + (S32)read_width * 4; i += 4)
4078 {
4079 F32 depth_float = *(F32*)(raw->getData() + i);
4080
4081 F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float * depth_conversion_factor_2));
4082 U8 depth_byte = F32_to_U8(linear_depth_float, gCamera->getNear(), gCamera->getFar());
4083 *(raw->getData() + i + 0) = depth_byte;
4084 *(raw->getData() + i + 1) = depth_byte;
4085 *(raw->getData() + i + 2) = depth_byte;
4086 *(raw->getData() + i + 3) = 255;
4087 }
4088 }
4089 }
4090 output_buffer_offset_x += subimage_x_offset;
4091 stop_glerror();
4092 }
4093 output_buffer_offset_y += subimage_y_offset;
4094 }
4095
4096 // POST SNAPSHOT
4097 if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
4098 {
4099 LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
4100 }
4101
4102 if (hide_hud)
4103 {
4104 LLPipeline::toggleRenderType((void*)LLPipeline::RENDER_TYPE_HUD);
4105 }
4106
4107 if (high_res)
4108 {
4109 initFonts(1.f);
4110 LLHUDText::reshape();
4111 }
4112
4113 gDisplaySwapBuffers = TRUE;
4114
4115 // Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding)
4116 // Note: this formula depends on the number of components being 3. Not obvious, but it's correct.
4117 image_width += (image_width * (type == SNAPSHOT_TYPE_DEPTH ? 4 : 3)) % 4;
4118
4119 // Resize image
4120 raw->scale( image_width, image_height );
4121
4122 setCursor(UI_CURSOR_ARROW);
4123
4124 if (do_rebuild)
4125 {
4126 // If we had to do a rebuild, that means that the lists of drawables to be rendered
4127 // was empty before we started.
4128 // Need to reset these, otherwise we call state sort on it again when render gets called the next time
4129 // and we stand a good chance of crashing on rebuild because the render drawable arrays have multiple copies of
4130 // objects on them.
4131 gPipeline.resetDrawOrders();
4132 }
4133
4134 if (high_res)
4135 {
4136 send_agent_resume();
4137 }
4138
4139 return TRUE;
4140}
4141
4142void LLViewerWindow::destroyWindow()
4143{
4144 if (mWindow)
4145 {
4146 LLWindowManager::destroyWindow(mWindow);
4147 }
4148 mWindow = NULL;
4149}
4150
4151
4152void LLViewerWindow::drawMouselookInstructions()
4153{
4154 // Draw instructions for mouselook ("Press ESC to leave Mouselook" in a box at the top of the screen.)
4155 const char* instructions = "Press ESC to leave Mouselook.";
4156 const LLFontGL* font = gResMgr->getRes( LLFONT_SANSSERIF );
4157
4158 const S32 INSTRUCTIONS_PAD = 5;
4159 LLRect instructions_rect;
4160 instructions_rect.setLeftTopAndSize(
4161 INSTRUCTIONS_PAD,
4162 gViewerWindow->getWindowHeight() - INSTRUCTIONS_PAD,
4163 font->getWidth( instructions ) + 2 * INSTRUCTIONS_PAD,
4164 llround(font->getLineHeight() + 2 * INSTRUCTIONS_PAD));
4165
4166 {
4167 LLGLSNoTexture gls_no_texture;
4168 glColor4f( 0.9f, 0.9f, 0.9f, 1.0f );
4169 gl_rect_2d( instructions_rect );
4170 }
4171
4172 font->renderUTF8(
4173 instructions, 0,
4174 instructions_rect.mLeft + INSTRUCTIONS_PAD,
4175 instructions_rect.mTop - INSTRUCTIONS_PAD,
4176 LLColor4( 0.0f, 0.0f, 0.0f, 1.f ),
4177 LLFontGL::LEFT, LLFontGL::TOP);
4178}
4179
4180
4181// These functions are here only because LLViewerWindow used to do the work that gFocusMgr does now.
4182// They let other objects continue to work without change.
4183
4184void LLViewerWindow::setKeyboardFocus(LLUICtrl* new_focus,void (*on_focus_lost)(LLUICtrl* old_focus))
4185{
4186 gFocusMgr.setKeyboardFocus( new_focus, on_focus_lost );
4187}
4188
4189LLUICtrl* LLViewerWindow::getKeyboardFocus()
4190{
4191 return gFocusMgr.getKeyboardFocus();
4192}
4193
4194BOOL LLViewerWindow::hasKeyboardFocus(const LLUICtrl* possible_focus) const
4195{
4196 return possible_focus == gFocusMgr.getKeyboardFocus();
4197}
4198
4199BOOL LLViewerWindow::childHasKeyboardFocus(const LLView* parent) const
4200{
4201 return gFocusMgr.childHasKeyboardFocus( parent );
4202}
4203
4204void LLViewerWindow::setMouseCapture(LLMouseHandler* new_captor,void (*on_capture_lost)(LLMouseHandler* old_captor))
4205{
4206 gFocusMgr.setMouseCapture( new_captor, on_capture_lost );
4207}
4208
4209LLMouseHandler* LLViewerWindow::getMouseCaptor() const
4210{
4211 return gFocusMgr.getMouseCapture();
4212}
4213
4214BOOL LLViewerWindow::hasMouseCapture(const LLMouseHandler* possible_captor) const
4215{
4216 return possible_captor == gFocusMgr.getMouseCapture();
4217}
4218
4219S32 LLViewerWindow::getWindowHeight() const
4220{
4221 return mVirtualWindowRect.getHeight();
4222}
4223
4224S32 LLViewerWindow::getWindowWidth() const
4225{
4226 return mVirtualWindowRect.getWidth();
4227}
4228
4229S32 LLViewerWindow::getWindowDisplayHeight() const
4230{
4231 return mWindowRect.getHeight();
4232}
4233
4234S32 LLViewerWindow::getWindowDisplayWidth() const
4235{
4236 return mWindowRect.getWidth();
4237}
4238
4239LLView* LLViewerWindow::getTopView() const
4240{
4241 return gFocusMgr.getTopView();
4242}
4243
4244BOOL LLViewerWindow::hasTopView(LLView* view) const
4245{
4246 return view == gFocusMgr.getTopView();
4247}
4248
4249void LLViewerWindow::setTopView(LLView* new_top,void (*on_top_lost)(LLView* old_top))
4250{
4251 gFocusMgr.setTopView( new_top, on_top_lost );
4252}
4253
4254void LLViewerWindow::setupViewport(S32 x_offset, S32 y_offset)
4255{
4256 glViewport(x_offset, y_offset, mWindowRect.getWidth(), mWindowRect.getHeight());
4257}
4258
4259void LLViewerWindow::setup3DRender()
4260{
4261 gCamera->setPerspective(NOT_FOR_SELECTION, 0, 0, mWindowRect.getWidth(), mWindowRect.getHeight(), FALSE, gCamera->getNear(), MAX_FAR_PLANE);
4262}
4263
4264void LLViewerWindow::setup2DRender()
4265{
4266 gl_state_for_2d(mWindowRect.getWidth(), mWindowRect.getHeight());
4267}
4268
4269// Could cache the pointer from the last hitObjectOrLand here.
4270LLViewerObject *LLViewerWindow::lastObjectHit()
4271{
4272 return gObjectList.findObject( gLastHitObjectID );
4273}
4274
4275const LLVector3d& LLViewerWindow::lastObjectHitOffset()
4276{
4277 return gLastHitObjectOffset;
4278}
4279
4280// Could cache the pointer from the last hitObjectOrLand here.
4281LLViewerObject *LLViewerWindow::lastNonFloraObjectHit()
4282{
4283 return gObjectList.findObject( gLastHitNonFloraObjectID );
4284}
4285
4286const LLVector3d& LLViewerWindow::lastNonFloraObjectHitOffset()
4287{
4288 return gLastHitNonFloraObjectOffset;
4289}
4290
4291
4292void LLViewerWindow::setShowProgress(const BOOL show)
4293{
4294 if (mProgressView)
4295 {
4296 mProgressView->setVisible(show);
4297 }
4298}
4299
4300BOOL LLViewerWindow::getShowProgress() const
4301{
4302 return (mProgressView && mProgressView->getVisible());
4303}
4304
4305
4306void LLViewerWindow::moveProgressViewToFront()
4307{
4308 if( mProgressView && mRootView )
4309 {
4310 mRootView->removeChild( mProgressView );
4311 mRootView->addChild( mProgressView );
4312 }
4313}
4314
4315void LLViewerWindow::setProgressString(const LLString& string)
4316{
4317 if (mProgressView)
4318 {
4319 mProgressView->setText(string);
4320 }
4321}
4322
4323void LLViewerWindow::setProgressMessage(const LLString& msg)
4324{
4325 if(mProgressView)
4326 {
4327 mProgressView->setMessage(msg);
4328 }
4329}
4330
4331void LLViewerWindow::setProgressPercent(const F32 percent)
4332{
4333 if (mProgressView)
4334 {
4335 mProgressView->setPercent(percent);
4336 }
4337}
4338
4339void LLViewerWindow::setProgressCancelButtonVisible( BOOL b, const LLString& label )
4340{
4341 if (mProgressView)
4342 {
4343 mProgressView->setCancelButtonVisible( b, label );
4344 }
4345}
4346
4347
4348LLProgressView *LLViewerWindow::getProgressView() const
4349{
4350 return mProgressView;
4351}
4352
4353void LLViewerWindow::dumpState()
4354{
4355 llinfos << "LLViewerWindow Active " << S32(mActive) << llendl;
4356 llinfos << "mWindow visible " << S32(mWindow->getVisible())
4357 << " minimized " << S32(mWindow->getMinimized())
4358 << llendl;
4359}
4360
4361void LLViewerWindow::stopGL(BOOL save_state)
4362{
4363 if (!gGLManager.mIsDisabled)
4364 {
4365 llinfos << "Shutting down GL..." << llendl;
4366 gSky.destroyGL();
4367 stop_glerror();
4368
4369 gImageList.destroyGL(save_state);
4370 stop_glerror();
4371
4372 gBumpImageList.destroyGL();
4373 stop_glerror();
4374
4375 LLFontGL::destroyGL();
4376 stop_glerror();
4377
4378 LLVOAvatar::destroyGL();
4379 stop_glerror();
4380
4381 LLDynamicTexture::destroyGL();
4382 stop_glerror();
4383
4384 if(gParcelMgr) gParcelMgr->destroyGL();
4385
4386 gPipeline.destroyGL();
4387
4388 gCone.cleanupGL();
4389 gBox.cleanupGL();
4390 gSphere.cleanupGL();
4391 gCylinder.cleanupGL();
4392
4393 gGLManager.mIsDisabled = TRUE;
4394 stop_glerror();
4395
4396 llinfos << "Remaining allocated texture memory: " << LLImageGL::sGlobalTextureMemory << " bytes" << llendl;
4397 }
4398}
4399
4400void LLViewerWindow::restoreGL(const LLString& progress_message)
4401{
4402 if (gGLManager.mIsDisabled)
4403 {
4404 llinfos << "Restoring GL..." << llendl;
4405 gGLManager.mIsDisabled = FALSE;
4406
4407 // for future support of non-square pixels, and fonts that are properly stretched
4408 //LLFontGL::destroyDefaultFonts();
4409 initFonts();
4410 initGLDefaults();
4411 LLGLState::restoreGL();
4412 gSky.restoreGL();
4413 gPipeline.restoreGL();
4414 LLDrawPoolWater::restoreGL();
4415 LLManipTranslate::restoreGL();
4416 gImageList.restoreGL();
4417 gBumpImageList.restoreGL();
4418 gPipeline.setUseAGP(gSavedSettings.getBOOL("RenderUseAGP"));
4419 LLDynamicTexture::restoreGL();
4420 LLVOAvatar::restoreGL();
4421 if (gParcelMgr) gParcelMgr->restoreGL();
4422
4423 if (gFloaterCustomize && gFloaterCustomize->getVisible())
4424 {
4425 LLVisualParamHint::requestHintUpdates();
4426 }
4427
4428 if (!progress_message.empty())
4429 {
4430 gRestoreGLTimer.reset();
4431 gRestoreGL = TRUE;
4432 setShowProgress(TRUE);
4433 setProgressString(progress_message);
4434 }
4435 llinfos << "...Restoring GL done" << llendl;
4436#if LL_WINDOWS
4437 if (SetUnhandledExceptionFilter(LLWinDebug::handleException) != LLWinDebug::handleException)
4438 {
4439 llwarns << " Someone took over my exception handler (post restoreGL)!" << llendl;
4440 }
4441#endif
4442
4443 }
4444}
4445
4446void LLViewerWindow::initFonts(F32 zoom_factor)
4447{
4448 LLFontGL::destroyGL();
4449 LLFontGL::initDefaultFonts( gSavedSettings.getF32("FontScreenDPI"),
4450 mDisplayScale.mV[VX] * zoom_factor,
4451 mDisplayScale.mV[VY] * zoom_factor,
4452 gSavedSettings.getString("FontMonospace"),
4453 gSavedSettings.getF32("FontSizeMonospace"),
4454 gSavedSettings.getString("FontSansSerif"),
4455 gSavedSettings.getString("FontSansSerifFallback"),
4456 gSavedSettings.getF32("FontSansSerifFallbackScale"),
4457 gSavedSettings.getF32("FontSizeSmall"),
4458 gSavedSettings.getF32("FontSizeMedium"),
4459 gSavedSettings.getF32("FontSizeLarge"),
4460 gSavedSettings.getF32("FontSizeHuge"),
4461 gSavedSettings.getString("FontSansSerifBold"),
4462 gSavedSettings.getF32("FontSizeMedium"),
4463 gDirUtilp->getAppRODataDir()
4464 );
4465}
4466void LLViewerWindow::toggleFullscreen(BOOL show_progress)
4467{
4468 if (mWindow)
4469 {
4470 mWantFullscreen = mWindow->getFullscreen() ? FALSE : TRUE;
4471 mShowFullscreenProgress = show_progress;
4472 }
4473}
4474
4475void LLViewerWindow::getTargetWindow(BOOL& fullscreen, S32& width, S32& height) const
4476{
4477 fullscreen = mWantFullscreen;
4478
4479 if (gViewerWindow->mWindow
4480 && gViewerWindow->mWindow->getFullscreen() == mWantFullscreen)
4481 {
4482 width = gViewerWindow->getWindowDisplayWidth();
4483 height = gViewerWindow->getWindowDisplayHeight();
4484 }
4485 else if (mWantFullscreen)
4486 {
4487 width = gSavedSettings.getS32("FullScreenWidth");
4488 height = gSavedSettings.getS32("FullScreenHeight");
4489 }
4490 else
4491 {
4492 width = gSavedSettings.getS32("WindowWidth");
4493 height = gSavedSettings.getS32("WindowHeight");
4494 }
4495}
4496
4497
4498BOOL LLViewerWindow::checkSettings()
4499{
4500 BOOL is_fullscreen = gViewerWindow->mWindow->getFullscreen();
4501 if (is_fullscreen && !mWantFullscreen)
4502 {
4503 gViewerWindow->changeDisplaySettings(FALSE,
4504 LLCoordScreen(gSavedSettings.getS32("WindowWidth"),
4505 gSavedSettings.getS32("WindowHeight")),
4506 TRUE,
4507 mShowFullscreenProgress);
4508 return TRUE;
4509 }
4510 else if (!is_fullscreen && mWantFullscreen)
4511 {
4512 if (!LLStartUp::canGoFullscreen())
4513 {
4514 return FALSE;
4515 }
4516
4517 gViewerWindow->changeDisplaySettings(TRUE,
4518 LLCoordScreen(gSavedSettings.getS32("FullScreenWidth"),
4519 gSavedSettings.getS32("FullScreenHeight")),
4520 gSavedSettings.getBOOL("DisableVerticalSync"),
4521 mShowFullscreenProgress);
4522 return TRUE;
4523 }
4524 return FALSE;
4525}
4526
4527void LLViewerWindow::restartDisplay(BOOL show_progress_bar)
4528{
4529 llinfos << "Restaring GL" << llendl;
4530 stopGL();
4531 if (show_progress_bar)
4532 {
4533 restoreGL("Changing Resolution...");
4534 }
4535 else
4536 {
4537 restoreGL();
4538 }
4539}
4540
4541BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar)
4542{
4543 BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized");
4544 mWantFullscreen = fullscreen;
4545 mShowFullscreenProgress = show_progress_bar;
4546 gSavedSettings.setBOOL("FullScreen", mWantFullscreen);
4547
4548 BOOL old_fullscreen = mWindow->getFullscreen();
4549 if (!old_fullscreen && fullscreen && !LLStartUp::canGoFullscreen())
4550 {
4551 // we can't do this now, so do it later
4552
4553 gSavedSettings.setS32("FullScreenWidth", size.mX);
4554 gSavedSettings.setS32("FullScreenHeight", size.mY);
4555 //gSavedSettings.setBOOL("DisableVerticalSync", disable_vsync);
4556
4557 return TRUE; // a lie..., because we'll get to it later
4558 }
4559
4560 // going from windowed to windowed
4561 if (!old_fullscreen && !fullscreen)
4562 {
4563 // if not maximized, use the request size
4564 if (!mWindow->getMaximized())
4565 {
4566 mWindow->setSize(size);
4567 }
4568 return TRUE;
4569 }
4570
4571 // Close floaters that don't handle settings change
4572 LLFloaterSnapshot::hide(0);
4573
4574 BOOL result_first_try = FALSE;
4575 BOOL result_second_try = FALSE;
4576
4577 LLUICtrl* keyboard_focus = gFocusMgr.getKeyboardFocus();
4578 send_agent_pause();
4579 llinfos << "Stopping GL during changeDisplaySettings" << llendl;
4580 stopGL();
4581 mIgnoreActivate = TRUE;
4582 LLCoordScreen old_size;
4583 LLCoordScreen old_pos;
4584 mWindow->getSize(&old_size);
4585 BOOL got_position = mWindow->getPosition(&old_pos);
4586
4587 if (!old_fullscreen && fullscreen && got_position)
4588 {
4589 // switching from windowed to fullscreen, so save window position
4590 gSavedSettings.setS32("WindowX", old_pos.mX);
4591 gSavedSettings.setS32("WindowY", old_pos.mY);
4592 }
4593
4594 result_first_try = mWindow->switchContext(fullscreen, size, disable_vsync);
4595 if (!result_first_try)
4596 {
4597 // try to switch back
4598 result_second_try = mWindow->switchContext(old_fullscreen, old_size, disable_vsync);
4599
4600 if (!result_second_try)
4601 {
4602 // we are stuck...try once again with a minimal resolution?
4603 send_agent_resume();
4604 mIgnoreActivate = FALSE;
4605 return FALSE;
4606 }
4607 }
4608 send_agent_resume();
4609
4610 llinfos << "Restoring GL during resolution change" << llendl;
4611 if (show_progress_bar)
4612 {
4613 restoreGL("Changing Resolution...");
4614 }
4615 else
4616 {
4617 restoreGL();
4618 }
4619
4620 if (!result_first_try)
4621 {
4622 LLStringBase<char>::format_map_t args;
4623 args["[RESX]"] = llformat("%d",size.mX);
4624 args["[RESY]"] = llformat("%d",size.mY);
4625 alertXml("ResolutionSwitchFail", args);
4626 size = old_size; // for reshape below
4627 }
4628
4629 BOOL success = result_first_try || result_second_try;
4630 if (success)
4631 {
4632#if LL_WINDOWS
4633 // Only trigger a reshape after switching to fullscreen; otherwise rely on the windows callback
4634 // (otherwise size is wrong; this is the entire window size, reshape wants the visible window size)
4635 if (fullscreen)
4636#endif
4637 {
4638 reshape(size.mX, size.mY);
4639 }
4640 }
4641
4642 if (!mWindow->getFullscreen() && success)
4643 {
4644 // maximize window if was maximized, else reposition
4645 if (was_maximized)
4646 {
4647 mWindow->maximize();
4648 }
4649 else
4650 {
4651 S32 windowX = gSavedSettings.getS32("WindowX");
4652 S32 windowY = gSavedSettings.getS32("WindowY");
4653
4654 mWindow->setPosition(LLCoordScreen ( windowX, windowY ) );
4655 }
4656 }
4657
4658 mIgnoreActivate = FALSE;
4659 gFocusMgr.setKeyboardFocus(keyboard_focus, NULL);
4660 mWantFullscreen = mWindow->getFullscreen();
4661 mShowFullscreenProgress = FALSE;
4662
4663 return success;
4664}
4665
4666
4667F32 LLViewerWindow::getDisplayAspectRatio() const
4668{
4669 if (mWindow->getFullscreen())
4670 {
4671 if (gSavedSettings.getBOOL("FullScreenAutoDetectAspectRatio"))
4672 {
4673 return mWindow->getNativeAspectRatio();
4674 }
4675 else
4676 {
4677 return gSavedSettings.getF32("FullScreenAspectRatio");
4678 }
4679 }
4680 else
4681 {
4682 return mWindow->getNativeAspectRatio();
4683 }
4684}
4685
4686
4687void LLViewerWindow::drawPickBuffer() const
4688{
4689 if (mPickBuffer)
4690 {
4691 LLGLDisable no_blend(GL_BLEND);
4692 LLGLDisable no_alpha_test(GL_ALPHA_TEST);
4693 LLGLSNoTexture no_texture;
4694 glPixelZoom(10.f, 10.f);
4695 glRasterPos2f(((F32)mPickPoint.mX * mDisplayScale.mV[VX] + 10.f),
4696 ((F32)mPickPoint.mY * mDisplayScale.mV[VY] + 10.f));
4697 glDrawPixels(PICK_DIAMETER, PICK_DIAMETER, GL_RGBA, GL_UNSIGNED_BYTE, mPickBuffer);
4698 glPixelZoom(1.f, 1.f);
4699 glColor4fv(LLColor4::white.mV);
4700 gl_rect_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] - (F32)(PICK_HALF_WIDTH)),
4701 llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH)),
4702 llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH)),
4703 llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] - (F32)(PICK_HALF_WIDTH)),
4704 FALSE);
4705 gl_line_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] - (F32)(PICK_HALF_WIDTH)),
4706 llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH)),
4707 llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + 10.f),
4708 llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_DIAMETER) * 10.f + 10.f));
4709 gl_line_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH)),
4710 llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] - (F32)(PICK_HALF_WIDTH)),
4711 llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_DIAMETER) * 10.f + 10.f),
4712 llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + 10.f));
4713 glTranslatef(10.f, 10.f, 0.f);
4714 gl_rect_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX]),
4715 llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_DIAMETER) * 10.f),
4716 llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_DIAMETER) * 10.f),
4717 llround((F32)mPickPoint.mY * mDisplayScale.mV[VY]),
4718 FALSE);
4719 gl_rect_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH + mPickOffset.mX)* 10.f),
4720 llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH + mPickOffset.mY + 1) * 10.f),
4721 llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH + mPickOffset.mX + 1) * 10.f),
4722 llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH + mPickOffset.mY) * 10.f),
4723 FALSE);
4724 glPopMatrix();
4725 }
4726}
4727
4728void LLViewerWindow::calcDisplayScale()
4729{
4730 F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor");
4731 LLVector2 display_scale;
4732 display_scale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
4733 F32 height_normalization = gSavedSettings.getBOOL("UIAutoScale") ? ((F32)mWindowRect.getHeight() / display_scale.mV[VY]) / 768.f : 1.f;
4734 if(mWindow->getFullscreen())
4735 {
4736 display_scale *= (ui_scale_factor * height_normalization);
4737 }
4738 else
4739 {
4740 display_scale *= ui_scale_factor;
4741 }
4742
4743 // limit minimum display scale
4744 if (display_scale.mV[VX] < MIN_DISPLAY_SCALE || display_scale.mV[VY] < MIN_DISPLAY_SCALE)
4745 {
4746 display_scale *= MIN_DISPLAY_SCALE / llmin(display_scale.mV[VX], display_scale.mV[VY]);
4747 }
4748
4749 if (mWindow->getFullscreen())
4750 {
4751 display_scale.mV[0] = llround(display_scale.mV[0], 2.0f/(F32) mWindowRect.getWidth());
4752 display_scale.mV[1] = llround(display_scale.mV[1], 2.0f/(F32) mWindowRect.getHeight());
4753 }
4754
4755 if (display_scale != mDisplayScale)
4756 {
4757 llinfos << "Setting display scale to " << display_scale << llendl;
4758
4759 mDisplayScale = display_scale;
4760 // Init default fonts
4761 initFonts();
4762 }
4763}
4764
4765//----------------------------------------------------------------------------
4766
4767// static
4768bool LLViewerWindow::alertCallback(S32 modal)
4769{
4770 if (gNoRender)
4771 {
4772 return false;
4773 }
4774 else
4775 {
4776// if (modal) // we really always want to take you out of mouselook
4777 {
4778 // If we're in mouselook, the mouse is hidden and so the user can't click
4779 // the dialog buttons. In that case, change to First Person instead.
4780 if( gAgent.cameraMouselook() )
4781 {
4782 gAgent.changeCameraToDefault();
4783 }
4784 }
4785 return true;
4786 }
4787}
4788
4789LLAlertDialog* LLViewerWindow::alertXml(const std::string& xml_filename,
4790 LLAlertDialog::alert_callback_t callback, void* user_data)
4791{
4792 LLString::format_map_t args;
4793 return alertXml( xml_filename, args, callback, user_data );
4794}
4795
4796LLAlertDialog* LLViewerWindow::alertXml(const std::string& xml_filename, const LLString::format_map_t& args,
4797 LLAlertDialog::alert_callback_t callback, void* user_data)
4798{
4799 if (gNoRender)
4800 {
4801 llinfos << "Alert: " << xml_filename << llendl;
4802 if (callback)
4803 {
4804 callback(-1, user_data);
4805 }
4806 return NULL;
4807 }
4808
4809 // If we're in mouselook, the mouse is hidden and so the user can't click
4810 // the dialog buttons. In that case, change to First Person instead.
4811 if( gAgent.cameraMouselook() )
4812 {
4813 gAgent.changeCameraToDefault();
4814 }
4815
4816 // Note: object adds, removes, and destroys itself.
4817 return LLAlertDialog::showXml( xml_filename, args, callback, user_data );
4818}
4819
4820LLAlertDialog* LLViewerWindow::alertXmlEditText(const std::string& xml_filename, const LLString::format_map_t& args,
4821 LLAlertDialog::alert_callback_t callback, void* user_data,
4822 LLAlertDialog::alert_text_callback_t text_callback, void *text_data,
4823 const LLString::format_map_t& edit_args, BOOL draw_asterixes)
4824{
4825 if (gNoRender)
4826 {
4827 llinfos << "Alert: " << xml_filename << llendl;
4828 if (callback)
4829 {
4830 callback(-1, user_data);
4831 }
4832 return NULL;
4833 }
4834
4835 // If we're in mouselook, the mouse is hidden and so the user can't click
4836 // the dialog buttons. In that case, change to First Person instead.
4837 if( gAgent.cameraMouselook() )
4838 {
4839 gAgent.changeCameraToDefault();
4840 }
4841
4842 // Note: object adds, removes, and destroys itself.
4843 LLAlertDialog* alert = LLAlertDialog::createXml( xml_filename, args, callback, user_data );
4844 if (alert)
4845 {
4846 if (text_callback)
4847 {
4848 alert->setEditTextCallback(text_callback, text_data);
4849 }
4850 alert->setEditTextArgs(edit_args);
4851 alert->setDrawAsterixes(draw_asterixes);
4852 alert->show();
4853 }
4854 return alert;
4855}
4856
4857LLBottomPanel::LLBottomPanel(const LLString &name, const LLRect &rect) :
4858 LLPanel(name, rect, FALSE),
4859 mIndicator(NULL)
4860{
4861 // bottom panel is focus root, so Tab moves through the toolbar and button bar, and overlay
4862 setFocusRoot(TRUE);
4863 // don't capture mouse clicks that don't hit a child
4864 setMouseOpaque(FALSE);
4865 setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
4866 setIsChrome(TRUE);
4867}
4868
4869void LLBottomPanel::setFocusIndicator(LLView * indicator)
4870{
4871 mIndicator = indicator;
4872}
4873
4874void LLBottomPanel::draw()
4875{
4876 if(mIndicator)
4877 {
4878 BOOL hasFocus = gFocusMgr.childHasKeyboardFocus(this);
4879 mIndicator->setVisible(hasFocus);
4880 mIndicator->setEnabled(hasFocus);
4881 }
4882 LLPanel::draw();
4883}