llviewerwindow.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llviewerwindow.h"
00035 
00036 // system library includes
00037 #include <stdio.h>
00038 #include <iostream>
00039 #include <fstream>
00040 
00041 #include "llviewquery.h"
00042 #include "llxmltree.h"
00043 //#include "llviewercamera.h"
00044 //#include "imdebug.h"
00045 
00046 #include "llvoiceclient.h"      // for push-to-talk button handling
00047 
00048 #ifdef SABINRIG
00049 #include "cbw.h"
00050 #endif //SABINRIG
00051 
00052 //
00053 // TODO: Many of these includes are unnecessary.  Remove them.
00054 //
00055 
00056 // linden library includes
00057 #include "audioengine.h"                // mute on minimize
00058 #include "indra_constants.h"
00059 #include "linked_lists.h"
00060 #include "llassetstorage.h"
00061 #include "llfontgl.h"
00062 #include "llmediaengine.h"              // mute on minimize
00063 #include "llrect.h"
00064 #include "llsky.h"
00065 #include "llstring.h"
00066 #include "llui.h"
00067 #include "lluuid.h"
00068 #include "llview.h"
00069 #include "llxfermanager.h"
00070 #include "message.h"
00071 #include "object_flags.h"
00072 #include "lltimer.h"
00073 #include "timing.h"
00074 #include "llviewermenu.h"
00075 
00076 // newview includes
00077 #include "llagent.h"
00078 #include "llalertdialog.h"
00079 #include "llbox.h"
00080 #include "llcameraview.h"
00081 #include "llchatbar.h"
00082 #include "llconsole.h"
00083 #include "llviewercontrol.h"
00084 #include "llcylinder.h"
00085 #include "lldebugview.h"
00086 #include "lldir.h"
00087 #include "lldrawable.h"
00088 #include "lldrawpoolalpha.h"
00089 #include "lldrawpoolbump.h"
00090 #include "lldrawpoolwater.h"
00091 #include "llmaniptranslate.h"
00092 #include "llface.h"
00093 #include "llfeaturemanager.h"
00094 #include "llfilepicker.h"
00095 #include "llfloater.h"
00096 #include "llfloateractivespeakers.h"
00097 #include "llfloaterbuildoptions.h"
00098 #include "llfloaterbuyland.h"
00099 #include "llfloaterchat.h"
00100 #include "llfloaterchatterbox.h"
00101 #include "llfloatercustomize.h"
00102 #include "llfloatereditui.h" // HACK JAMESDEBUG for ui editor
00103 #include "llfloatereventlog.h"
00104 #include "llfloaterland.h"
00105 #include "llfloaterinspect.h"
00106 #include "llfloatermap.h"
00107 #include "llfloatermute.h"
00108 #include "llfloaternamedesc.h"
00109 #include "llfloaterproject.h"
00110 #include "llfloatersnapshot.h"
00111 #include "llfloatertools.h"
00112 #include "llfloaterworldmap.h"
00113 #include "llfloateravatarlist.h"
00114 #include "llfocusmgr.h"
00115 #include "llframestatview.h"
00116 #include "llgesturemgr.h"
00117 #include "llglheaders.h"
00118 #include "llhippo.h"
00119 #include "llhoverview.h"
00120 #include "llhudmanager.h"
00121 #include "llhudview.h"
00122 #include "llimagebmp.h"
00123 #include "llimagej2c.h"
00124 #include "llinventoryview.h"
00125 #include "llkeyboard.h"
00126 #include "lllineeditor.h"
00127 #include "llmenugl.h"
00128 #include "llmodaldialog.h"
00129 #include "llmorphview.h"
00130 #include "llmoveview.h"
00131 #include "llnotify.h"
00132 #include "lloverlaybar.h"
00133 #include "llpreviewtexture.h"
00134 #include "llprogressview.h"
00135 #include "llresmgr.h"
00136 #include "llrootview.h"
00137 #include "llselectmgr.h"
00138 #include "llsphere.h"
00139 #include "llstartup.h"
00140 #include "llstatusbar.h"
00141 #include "llstatview.h"
00142 #include "llsurface.h"
00143 #include "llsurfacepatch.h"
00144 #include "llimview.h"
00145 #include "lltexlayer.h"
00146 #include "lltextbox.h"
00147 #include "lltexturecache.h"
00148 #include "lltexturefetch.h"
00149 #include "lltextureview.h"
00150 #include "lltool.h"
00151 #include "lltoolbar.h"
00152 #include "lltoolcomp.h"
00153 #include "lltooldraganddrop.h"
00154 #include "lltoolface.h"
00155 #include "lltoolfocus.h"
00156 #include "lltoolgrab.h"
00157 #include "lltoolmgr.h"
00158 #include "lltoolmorph.h"
00159 #include "lltoolpie.h"
00160 #include "lltoolplacer.h"
00161 #include "lltoolselect.h"
00162 #include "lltoolselectland.h"
00163 #include "lltoolview.h"
00164 #include "llvieweruictrlfactory.h"
00165 #include "lluploaddialog.h"
00166 #include "llurldispatcher.h"            // SLURL from other app instance
00167 #include "llviewercamera.h"
00168 #include "llviewergesture.h"
00169 #include "llviewerimagelist.h"
00170 #include "llviewerinventory.h"
00171 #include "llviewerkeyboard.h"
00172 #include "llviewermenu.h"
00173 #include "llviewermessage.h"
00174 #include "llviewerobjectlist.h"
00175 #include "llviewerparcelmgr.h"
00176 #include "llviewerregion.h"
00177 #include "llviewerstats.h"
00178 #include "llvoavatar.h"
00179 #include "llvovolume.h"
00180 #include "llworld.h"
00181 #include "llworldmapview.h"
00182 #include "moviemaker.h"
00183 #include "pipeline.h"
00184 #include "viewer.h"
00185 
00186 #if LL_WINDOWS
00187 #include "llwindebug.h"
00188 #include <tchar.h> // For Unicode conversion methods
00189 #endif
00190 
00191 //
00192 // Globals
00193 //
00194 
00195 LLBottomPanel* gBottomPanel = NULL;
00196 
00197 extern BOOL gDebugClicks;
00198 extern BOOL gDisplaySwapBuffers;
00199 extern S32 gJamesInt;
00200 
00201 LLViewerWindow  *gViewerWindow = NULL;
00202 LLVelocityBar   *gVelocityBar = NULL;
00203 
00204 LLVector3d              gLastHitPosGlobal;
00205 LLVector3d              gLastHitObjectOffset;
00206 LLUUID                  gLastHitObjectID;
00207 S32                             gLastHitObjectFace = -1;
00208 BOOL                    gLastHitLand = FALSE;
00209 F32                             gLastHitUCoord;
00210 F32                             gLastHitVCoord;
00211 
00212 
00213 LLVector3d              gLastHitNonFloraPosGlobal;
00214 LLVector3d              gLastHitNonFloraObjectOffset;
00215 LLUUID                  gLastHitNonFloraObjectID;
00216 S32                             gLastHitNonFloraObjectFace = -1;
00217 BOOL                    gLastHitParcelWall = FALSE;
00218 
00219 S32                             gLastHitUIElement = 0;
00220 LLHUDIcon*              gLastHitHUDIcon = NULL;
00221 
00222 BOOL                    gDebugSelect = FALSE;
00223 U8                              gLastPickAlpha = 255;
00224 BOOL                    gUseGLPick = FALSE;
00225 
00226 // On the next pick pass (whenever that happens)
00227 // should we try to pick individual faces?
00228 // Cleared to FALSE every time a pick happens.
00229 BOOL                    gPickFaces = FALSE;
00230 
00231 LLFrameTimer    gMouseIdleTimer;
00232 LLFrameTimer    gAwayTimer;
00233 LLFrameTimer    gAwayTriggerTimer;
00234 LLFrameTimer    gAlphaFadeTimer;
00235 
00236 BOOL                    gShowOverlayTitle = FALSE;
00237 BOOL                    gPickTransparent = TRUE;
00238 
00239 BOOL                    gDebugFastUIRender = FALSE;
00240 
00241 BOOL                    gbCapturing = FALSE;
00242 #if !LL_SOLARIS
00243 MovieMaker              gMovieMaker;
00244 #endif
00245 
00246 S32 CHAT_BAR_HEIGHT = 28; 
00247 S32 OVERLAY_BAR_HEIGHT = 20;
00248 
00249 const U8 NO_FACE = 255;
00250 BOOL gQuietSnapshot = FALSE;
00251 
00252 const F32 MIN_AFK_TIME = 2.f; // minimum time after setting away state before coming back
00253 const F32 MAX_FAST_FRAME_TIME = 0.5f;
00254 const F32 FAST_FRAME_INCREMENT = 0.1f;
00255 
00256 const S32 PICK_HALF_WIDTH = 5;
00257 const S32 PICK_DIAMETER = 2 * PICK_HALF_WIDTH+1;
00258 
00259 const F32 MIN_DISPLAY_SCALE = 0.85f;
00260 
00261 #ifdef SABINRIG
00263 bool rigControl = false;
00264 bool voltDisplay = true;
00265 bool nominalX = false;
00266 bool nominalY = false;
00267 static F32 nomerX = 0.0f;
00268 static F32 nomerY = 0.0f;
00269 const BOARD_NUM = 0; // rig stuff!
00270 const ADRANGE = BIP10VOLTS; // rig stuff!
00271 static unsigned short DataVal; // rig stuff!
00272 static F32 oldValueX = 0;
00273 static F32 newValueX = 50;
00274 static F32 oldValueY = 0;
00275 static F32 newValueY = 50;
00276 static S32 mouseX = 50;
00277 static S32 mouseY = 50;
00278 static float VoltageX = 50; // rig stuff!
00279 static float VoltageY = 50; // rig stuff!
00280 static float nVoltX = 0;
00281 static float nVoltY = 0;
00282 static F32 temp1 = 50.f;
00283 static F32 temp2 = 20.f;
00284 LLCoordGL new_gl;
00285 #endif //SABINRIG
00286 
00287 char    LLViewerWindow::sSnapshotBaseName[LL_MAX_PATH];
00288 char    LLViewerWindow::sSnapshotDir[LL_MAX_PATH];
00289 
00290 char    LLViewerWindow::sMovieBaseName[LL_MAX_PATH];
00291 
00292 extern void toggle_debug_menus(void*);
00293 
00294 #ifdef SABINRIG
00295 // static
00296 void LLViewerWindow::printFeedback()
00297 {
00298         if(rigControl == true)
00299         {
00300                 cbAIn (BOARD_NUM, 0, ADRANGE, &DataVal);
00301                 cbToEngUnits (BOARD_NUM,ADRANGE,DataVal,&VoltageX); //Convert raw to voltage for X-axis
00302                 cbAIn (BOARD_NUM, 1, ADRANGE, &DataVal);
00303                 cbToEngUnits (BOARD_NUM,ADRANGE,DataVal,&VoltageY); //Convert raw to voltage for Y-axis
00304                 if(voltDisplay == true)
00305                 {
00306                         llinfos <<  "Current Voltages - X:" << VoltageX << " Y:" << VoltageY << llendl; //Display voltage
00307                 }
00308 
00309                 if(nVoltX == 0)
00310                 {
00311                         nVoltX = VoltageX;
00312                         nVoltY = VoltageY; //First time setup of nominal values.
00313                 }
00314 
00315                 newValueX = VoltageX;
00316                 newValueY = VoltageY; //Take in current voltage and set to a separate value for adjustment.
00317 
00318                 mouseX = mCurrentMousePoint.mX;
00319                 mouseY = mCurrentMousePoint.mY; //Take in current cursor position and set to separate value for adjustment.
00320 
00321                 if( abs(newValueX - nVoltX) > nomerX )
00322                 {
00323                         if( (newValueX - oldValueX) < 0)
00324                         {
00325                                 mouseX += (S32)( ((newValueX - oldValueX)*.5)) * -temp;
00326                         }
00327                         else
00328                         {
00329                                 mouseX += (S32)( ((newValueX - oldValueX)*.5) * temp1);
00330                         }
00331                 }
00332                 else
00333                 {
00334                         mouseX = getWindowWidth() / 2;
00335                 }
00336                 if( abs(newValueY - nVoltY) > nomerY )
00337                 {
00338                         if( (newValueY - oldValueY) < 0)
00339                         {
00340                                 mouseY += (S32)( ((newValueY - oldValueY)*(newValueY - oldValueY)) * -temp2);
00341                         }
00342                         else
00343                         {
00344                                 mouseY += (S32)( ((newValueY - oldValueY)*(newValueY - oldValueY)) * temp2);
00345                         }
00346                 }
00347                 else
00348                 {
00349                         mouseY = getWindowHeight() / 2;
00350                 }
00351                 //mouseX += (S32)( (newValueX - nVoltX) * temp1 + 0.5 );
00352                 // (newValueX - oldValueX) = difference between current position and nominal position
00353                 // * temp1 = the amplification of the number that sets sensitivity
00354                 // + 0.5 = fixes rounding errors
00355                 
00356 
00357                 //mouseY += (S32)( (newValueY - nVoltY) * temp2 + 0.5 ); //Algorithm to adjust voltage for mouse adjustment.
00358 
00359                 oldValueX = newValueX;
00360                 oldValueY = newValueY;
00361 
00362                 new_gl.mX = mouseX;
00363                 new_gl.mY = mouseY; //Setup final coordinate to move mouse to.
00364 
00365                 setCursorPosition(new_gl); //Set final cursor position
00366         }
00367 }
00368 #endif //SABINRIG
00369 
00371 //
00372 // LLDebugText
00373 //
00374 
00375 class LLDebugText
00376 {
00377 private:
00378         struct Line
00379         {
00380                 Line(const std::string& in_text, S32 in_x, S32 in_y) : text(in_text), x(in_x), y(in_y) {}
00381                 std::string text;
00382                 S32 x,y;
00383         };
00384 
00385         LLViewerWindow *mWindow;
00386         
00387         typedef std::vector<Line> line_list_t;
00388         line_list_t mLineList;
00389         LLColor4 mTextColor;
00390         
00391 public:
00392         LLDebugText(LLViewerWindow* window) : mWindow(window) {}
00393         
00394         void addText(S32 x, S32 y, const std::string &text) 
00395         {
00396                 mLineList.push_back(Line(text, x, y));
00397         }
00398 
00399         void update()
00400         {
00401                 std::string wind_vel_text;
00402                 std::string wind_vector_text;
00403                 std::string rwind_vel_text;
00404                 std::string rwind_vector_text;
00405                 std::string audio_text;
00406 
00407                 // Draw the statistics in a light gray
00408                 // and in a thin font
00409                 mTextColor = LLColor4( 0.86f, 0.86f, 0.86f, 1.f );
00410 
00411                 // Draw stuff growing up from right lower corner of screen
00412                 U32 xpos = mWindow->getWindowWidth() - 350;
00413                 U32 ypos = 64;
00414                 const U32 y_inc = 20;
00415 
00416                 if (gSavedSettings.getBOOL("DebugShowTime"))
00417                 {
00418                         const U32 y_inc2 = 15;
00419                         for (std::map<S32,LLFrameTimer>::reverse_iterator iter = gDebugTimers.rbegin();
00420                                  iter != gDebugTimers.rend(); ++iter)
00421                         {
00422                                 S32 idx = iter->first;
00423                                 LLFrameTimer& timer = iter->second;
00424                                 F32 time = timer.getElapsedTimeF32();
00425                                 S32 hours = (S32)(time / (60*60));
00426                                 S32 mins = (S32)((time - hours*(60*60)) / 60);
00427                                 S32 secs = (S32)((time - hours*(60*60) - mins*60));
00428                                 addText(xpos, ypos, llformat(" Debug %d: %d:%02d:%02d", idx, hours,mins,secs)); ypos += y_inc2;
00429                         }
00430                         
00431                         F32 time = gFrameTimeSeconds;
00432                         S32 hours = (S32)(time / (60*60));
00433                         S32 mins = (S32)((time - hours*(60*60)) / 60);
00434                         S32 secs = (S32)((time - hours*(60*60) - mins*60));
00435                         addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc;
00436                 }
00437                 
00438                 if (gDisplayCameraPos)
00439                 {
00440                         std::string camera_view_text;
00441                         std::string camera_center_text;
00442                         std::string agent_view_text;
00443                         std::string agent_left_text;
00444                         std::string agent_center_text;
00445                         std::string agent_root_center_text;
00446 
00447                         LLVector3d tvector; // Temporary vector to hold data for printing.
00448 
00449                         // Update camera center, camera view, wind info every other frame
00450                         tvector = gAgent.getPositionGlobal();
00451                         agent_center_text = llformat("AgentCenter  %f %f %f",
00452                                                                                  (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
00453 
00454                         if (gAgent.getAvatarObject())
00455                         {
00456                                 tvector = gAgent.getPosGlobalFromAgent(gAgent.getAvatarObject()->mRoot.getWorldPosition());
00457                                 agent_root_center_text = llformat("AgentRootCenter %f %f %f",
00458                                                                                                   (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
00459                         }
00460                         else
00461                         {
00462                                 agent_root_center_text = "---";
00463                         }
00464 
00465 
00466                         tvector = LLVector4(gAgent.getFrameAgent().getAtAxis());
00467                         agent_view_text = llformat("AgentAtAxis  %f %f %f",
00468                                                                            (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
00469 
00470                         tvector = LLVector4(gAgent.getFrameAgent().getLeftAxis());
00471                         agent_left_text = llformat("AgentLeftAxis  %f %f %f",
00472                                                                            (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
00473 
00474                         tvector = gAgent.getCameraPositionGlobal();
00475                         camera_center_text = llformat("CameraCenter %f %f %f",
00476                                                                                   (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
00477 
00478                         tvector = LLVector4(gCamera->getAtAxis());
00479                         camera_view_text = llformat("CameraAtAxis    %f %f %f",
00480                                                                                 (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
00481                 
00482                         addText(xpos, ypos, agent_center_text);  ypos += y_inc;
00483                         addText(xpos, ypos, agent_root_center_text);  ypos += y_inc;
00484                         addText(xpos, ypos, agent_view_text);  ypos += y_inc;
00485                         addText(xpos, ypos, agent_left_text);  ypos += y_inc;
00486                         addText(xpos, ypos, camera_center_text);  ypos += y_inc;
00487                         addText(xpos, ypos, camera_view_text);  ypos += y_inc;
00488                 }
00489 
00490                 if (gDisplayWindInfo)
00491                 {
00492                         wind_vel_text = llformat("Wind velocity %.2f m/s", gWindVec.magVec());
00493                         wind_vector_text = llformat("Wind vector   %.2f %.2f %.2f", gWindVec.mV[0], gWindVec.mV[1], gWindVec.mV[2]);
00494                         rwind_vel_text = llformat("RWind vel %.2f m/s", gRelativeWindVec.magVec());
00495                         rwind_vector_text = llformat("RWind vec   %.2f %.2f %.2f", gRelativeWindVec.mV[0], gRelativeWindVec.mV[1], gRelativeWindVec.mV[2]);
00496 
00497                         addText(xpos, ypos, wind_vel_text);  ypos += y_inc;
00498                         addText(xpos, ypos, wind_vector_text);  ypos += y_inc;
00499                         addText(xpos, ypos, rwind_vel_text);  ypos += y_inc;
00500                         addText(xpos, ypos, rwind_vector_text);  ypos += y_inc;
00501                 }
00502                 if (gDisplayWindInfo)
00503                 {
00504                         if (gAudiop)
00505                         {
00506                                 audio_text= llformat("Audio for wind: %d", gAudiop->isWindEnabled());
00507                         }
00508                         addText(xpos, ypos, audio_text);  ypos += y_inc;
00509                 }
00510                 if (gDisplayFOV)
00511                 {
00512                         addText(xpos, ypos, llformat("FOV: %2.1f deg", RAD_TO_DEG * gCamera->getView()));
00513                         ypos += y_inc;
00514                 }
00515                 if (gSavedSettings.getBOOL("DebugShowRenderInfo"))
00516                 {
00517                         if (gPipeline.getUseVertexShaders() == 0)
00518                         {
00519                                 addText(xpos, ypos, "Shaders Disabled");
00520                                 ypos += y_inc;
00521                         }
00522                         addText(xpos, ypos, llformat("%d MB Vertex Data", LLVertexBuffer::sAllocatedBytes/(1024*1024)));
00523                         ypos += y_inc;
00524 
00525                         addText(xpos, ypos, llformat("%d Pending Lock", LLVertexBuffer::sLockedList.size()));
00526                         ypos += y_inc;
00527 
00528                         addText(xpos, ypos, llformat("%d Vertex Buffers", LLVertexBuffer::sGLCount));
00529                         ypos += y_inc;
00530                 }
00531 
00532                 // only display these messages if we are actually rendering beacons at this moment
00533                 if (LLPipeline::getRenderBeacons(NULL) && LLPipeline::getProcessBeacons(NULL))
00534                 {
00535                         if (LLPipeline::getRenderParticleBeacons(NULL))
00536                         {
00537                                 addText(xpos, ypos, "Viewing particle beacons (blue)");
00538                                 ypos += y_inc;
00539                         }
00540                         if (LLPipeline::toggleRenderTypeControlNegated((void*)LLPipeline::RENDER_TYPE_PARTICLES))
00541                         {
00542                                 addText(xpos, ypos, "Hiding particles");
00543                                 ypos += y_inc;
00544                         }
00545                         if (LLPipeline::getRenderPhysicalBeacons(NULL))
00546                         {
00547                                 addText(xpos, ypos, "Viewing physical object beacons (green)");
00548                                 ypos += y_inc;
00549                         }
00550                         if (LLPipeline::getRenderScriptedBeacons(NULL))
00551                         {
00552                                 addText(xpos, ypos, "Viewing scripted object beacons (red)");
00553                                 ypos += y_inc;
00554                         }
00555                         else
00556                                 if (LLPipeline::getRenderScriptedTouchBeacons(NULL))
00557                                 {
00558                                         addText(xpos, ypos, "Viewing scripted object with touch function beacons (red)");
00559                                         ypos += y_inc;
00560                                 }
00561                         if (LLPipeline::getRenderSoundBeacons(NULL))
00562                         {
00563                                 addText(xpos, ypos, "Viewing sound beacons (yellow)");
00564                                 ypos += y_inc;
00565                         }
00566                 }
00567         }
00568 
00569         void draw()
00570         {
00571                 for (line_list_t::iterator iter = mLineList.begin();
00572                          iter != mLineList.end(); ++iter)
00573                 {
00574                         const Line& line = *iter;
00575                         LLFontGL::sMonospace->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y, mTextColor,
00576                                                                                          LLFontGL::LEFT, LLFontGL::TOP,
00577                                                                                          LLFontGL::NORMAL, S32_MAX, S32_MAX, NULL, FALSE);
00578                 }
00579                 mLineList.clear();
00580         }
00581 
00582 };
00583 
00584 void LLViewerWindow::updateDebugText()
00585 {
00586         mDebugText->update();
00587 }
00588 
00590 //
00591 // LLViewerWindow
00592 //
00593 
00594 BOOL LLViewerWindow::handleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask)
00595 {
00596         S32 x = pos.mX;
00597         S32 y = pos.mY;
00598         x = llround((F32)x / mDisplayScale.mV[VX]);
00599         y = llround((F32)y / mDisplayScale.mV[VY]);
00600 
00601         if (gDebugClicks)
00602         {
00603                 llinfos << "ViewerWindow left mouse down at " << x << "," << y << llendl;
00604         }
00605 
00606         if (gMenuBarView)
00607         {
00608                 // stop ALT-key access to menu
00609                 gMenuBarView->resetMenuTrigger();
00610         }
00611 
00612         mLeftMouseDown = TRUE;
00613 
00614         // Make sure we get a coresponding mouseup event, even if the mouse leaves the window
00615         mWindow->captureMouse();
00616 
00617         // Indicate mouse was active
00618         gMouseIdleTimer.reset();
00619 
00620         // Hide tooltips on mousedown
00621         if( mToolTip )
00622         {
00623                 mToolTipBlocked = TRUE;
00624                 mToolTip->setVisible( FALSE );
00625         }
00626 
00627         // Also hide hover info on mousedown
00628         if (gHoverView)
00629         {
00630                 gHoverView->cancelHover();
00631         }
00632 
00633         if (gToolMgr)
00634         {
00635                 // Don't let the user move the mouse out of the window until mouse up.
00636                 if( gToolMgr->getCurrentTool()->clipMouseWhenDown() )
00637                 {
00638                         mWindow->setMouseClipping(TRUE);
00639                 }
00640         }
00641 
00642         LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
00643         if( mouse_captor )
00644         {
00645                 S32 local_x;
00646                 S32 local_y;
00647                 mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
00648                 if (LLView::sDebugMouseHandling)
00649                 {
00650                         llinfos << "Left Mouse Down handled by captor " << mouse_captor->getName() << llendl;
00651                 }
00652 
00653                 return mouse_captor->handleMouseDown(local_x, local_y, mask);
00654         }
00655 
00656         // Topmost view gets a chance before the hierarchy
00657         LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
00658         BOOL mouse_over_top_ctrl = FALSE;
00659         if (top_ctrl)
00660         {
00661                 S32 local_x, local_y;
00662                 top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
00663                 if (top_ctrl->pointInView(local_x, local_y))
00664                 {
00665                         mouse_over_top_ctrl = TRUE;
00666                         if(top_ctrl->handleMouseDown(local_x, local_y, mask)) 
00667                         {
00668                                 return TRUE;
00669                         }
00670                 }
00671         }
00672 
00673         // Give the UI views a chance to process the click
00674         if( mRootView->handleMouseDown(x, y, mask) )
00675         {
00676                 if (LLView::sDebugMouseHandling)
00677                 {
00678                         llinfos << "Left Mouse Down" << LLView::sMouseHandlerMessage << llendl;
00679                         LLView::sMouseHandlerMessage = "";
00680                 }
00681                 if (top_ctrl && top_ctrl->hasFocus() && !mouse_over_top_ctrl)
00682                 {
00683                         // always defocus top view if we click off of it
00684                         top_ctrl->setFocus(FALSE);
00685                 }
00686                 return TRUE;
00687         }
00688         else if (LLView::sDebugMouseHandling)
00689         {
00690                 llinfos << "Left Mouse Down not handled by view" << llendl;
00691         }
00692 
00693         if (top_ctrl && top_ctrl->hasFocus() && !mouse_over_top_ctrl)
00694         {
00695                 // always defocus top view if we click off of it
00696                 top_ctrl->setFocus(FALSE);
00697         }
00698 
00699         if (gDisconnected)
00700         {
00701                 return FALSE;
00702         }
00703 
00704         if (gToolMgr)
00705         {
00706                 if(gToolMgr->getCurrentTool()->handleMouseDown( x, y, mask ) )
00707                 {
00708                         // This is necessary to force clicks in the world to cause edit
00709                         // boxes that might have keyboard focus to relinquish it, and hence
00710                         // cause a commit to update their value.  JC
00711                         gFocusMgr.setKeyboardFocus(NULL, NULL);
00712                         return TRUE;
00713                 }
00714         }
00715 
00716         return FALSE;
00717 }
00718 
00719 BOOL LLViewerWindow::handleDoubleClick(LLWindow *window,  LLCoordGL pos, MASK mask)
00720 {
00721         S32 x = pos.mX;
00722         S32 y = pos.mY;
00723         x = llround((F32)x / mDisplayScale.mV[VX]);
00724         y = llround((F32)y / mDisplayScale.mV[VY]);
00725 
00726         if (gDebugClicks)
00727         {
00728                 llinfos << "ViewerWindow left mouse double-click at " << x << "," << y << llendl;
00729         }
00730 
00731         mLeftMouseDown = TRUE;
00732 
00733         // Hide tooltips
00734         if( mToolTip )
00735         {
00736                 mToolTip->setVisible( FALSE );
00737         }
00738 
00739         LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
00740         if( mouse_captor )
00741         {
00742                 S32 local_x;
00743                 S32 local_y;
00744                 mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
00745                 if (LLView::sDebugMouseHandling)
00746                 {
00747                         llinfos << "Left Mouse Down handled by captor " << mouse_captor->getName() << llendl;
00748                 }
00749 
00750                 return mouse_captor->handleDoubleClick(local_x, local_y, mask);
00751         }
00752 
00753         // Check for hit on UI.
00754         LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
00755         BOOL mouse_over_top_ctrl = FALSE;
00756         if (top_ctrl)
00757         {
00758                 S32 local_x, local_y;
00759                 top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
00760                 if (top_ctrl->pointInView(local_x, local_y))
00761                 {
00762                         mouse_over_top_ctrl = TRUE;
00763                         if(top_ctrl->handleDoubleClick(local_x, local_y, mask))
00764                         {
00765                                 return TRUE;
00766                         }
00767                 }
00768         }
00769 
00770         if (mRootView->handleDoubleClick(x, y, mask)) 
00771         {
00772                 if (LLView::sDebugMouseHandling)
00773                 {
00774                         llinfos << "Left Mouse Down" << LLView::sMouseHandlerMessage << llendl;
00775                         LLView::sMouseHandlerMessage = "";
00776                 }
00777                 if (top_ctrl && top_ctrl->hasFocus() && !mouse_over_top_ctrl)
00778                 {
00779                         // always defocus top view if we click off of it
00780                         top_ctrl->setFocus(FALSE);
00781                 }
00782                 return TRUE;
00783         }
00784         else if (LLView::sDebugMouseHandling)
00785         {
00786                 llinfos << "Left Mouse Down not handled by view" << llendl;
00787         }
00788 
00789         if (top_ctrl && top_ctrl->hasFocus() && !mouse_over_top_ctrl)
00790         {
00791                 // always defocus top view if we click off of it
00792                 top_ctrl->setFocus(FALSE);
00793         }
00794 
00795                 // Why is this here?  JC 9/3/2002
00796         if (gNoRender) 
00797         {
00798                 return TRUE;
00799         }
00800 
00801         if (gToolMgr)
00802         {
00803                 if(gToolMgr->getCurrentTool()->handleDoubleClick( x, y, mask ) )
00804                 {
00805                         return TRUE;
00806                 }
00807         }
00808 
00809         // if we got this far and nothing handled a double click, pass a normal mouse down
00810         return handleMouseDown(window, pos, mask);
00811 }
00812 
00813 BOOL LLViewerWindow::handleMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)
00814 {
00815         S32 x = pos.mX;
00816         S32 y = pos.mY;
00817         x = llround((F32)x / mDisplayScale.mV[VX]);
00818         y = llround((F32)y / mDisplayScale.mV[VY]);
00819 
00820         if (gDebugClicks)
00821         {
00822                 llinfos << "ViewerWindow left mouse up" << llendl;
00823         }
00824 
00825         mLeftMouseDown = FALSE;
00826 
00827         // Indicate mouse was active
00828         gMouseIdleTimer.reset();
00829 
00830         // Hide tooltips on mouseup
00831         if( mToolTip )
00832         {
00833                 mToolTip->setVisible( FALSE );
00834         }
00835 
00836         // Also hide hover info on mouseup
00837         if (gHoverView) gHoverView->cancelHover();
00838 
00839         BOOL handled = FALSE;
00840 
00841         mWindow->releaseMouse();
00842 
00843         LLTool *tool = NULL;
00844         if (gToolMgr)
00845         {
00846                 tool = gToolMgr->getCurrentTool();
00847 
00848                 if( tool->clipMouseWhenDown() )
00849                 {
00850                         mWindow->setMouseClipping(FALSE);
00851                 }
00852         }
00853 
00854         LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
00855         if( mouse_captor )
00856         {
00857                 S32 local_x;
00858                 S32 local_y;
00859                 mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
00860                 if (LLView::sDebugMouseHandling)
00861                 {
00862                         llinfos << "Left Mouse Up handled by captor " << mouse_captor->getName() << llendl;
00863                 }
00864 
00865                 return mouse_captor->handleMouseUp(local_x, local_y, mask);
00866         }
00867 
00868         LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
00869         if (top_ctrl)
00870         {
00871                 S32 local_x, local_y;
00872                 top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
00873                 handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleMouseUp(local_x, local_y, mask);
00874         }
00875 
00876         if( !handled )
00877         {
00878                 handled = mRootView->handleMouseUp(x, y, mask);
00879         }
00880 
00881         if (LLView::sDebugMouseHandling)
00882         {
00883                 if (handled)
00884                 {
00885                         llinfos << "Left Mouse Up" << LLView::sMouseHandlerMessage << llendl;
00886                         LLView::sMouseHandlerMessage = "";
00887                 }
00888                 else 
00889                 {
00890                         llinfos << "Left Mouse Up not handled by view" << llendl;
00891                 }
00892         }
00893 
00894         if( !handled )
00895         {
00896                 if (tool)
00897                 {
00898                         handled = tool->handleMouseUp(x, y, mask);
00899                 }
00900         }
00901 
00902         // Always handled as far as the OS is concerned.
00903         return TRUE;
00904 }
00905 
00906 
00907 BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask)
00908 {
00909         S32 x = pos.mX;
00910         S32 y = pos.mY;
00911         x = llround((F32)x / mDisplayScale.mV[VX]);
00912         y = llround((F32)y / mDisplayScale.mV[VY]);
00913 
00914         if (gDebugClicks)
00915         {
00916                 llinfos << "ViewerWindow right mouse down at " << x << "," << y << llendl;
00917         }
00918 
00919         if (gMenuBarView)
00920         {
00921                 // stop ALT-key access to menu
00922                 gMenuBarView->resetMenuTrigger();
00923         }
00924 
00925         mRightMouseDown = TRUE;
00926 
00927         // Make sure we get a coresponding mouseup event, even if the mouse leaves the window
00928         mWindow->captureMouse();
00929 
00930         // Hide tooltips
00931         if( mToolTip )
00932         {
00933                 mToolTip->setVisible( FALSE );
00934         }
00935 
00936         // Also hide hover info on mousedown
00937         if (gHoverView)
00938         {
00939                 gHoverView->cancelHover();
00940         }
00941 
00942         if (gToolMgr)
00943         {
00944                 // Don't let the user move the mouse out of the window until mouse up.
00945                 if( gToolMgr->getCurrentTool()->clipMouseWhenDown() )
00946                 {
00947                         mWindow->setMouseClipping(TRUE);
00948                 }
00949         }
00950 
00951         LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
00952         if( mouse_captor )
00953         {
00954                 S32 local_x;
00955                 S32 local_y;
00956                 mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
00957                 if (LLView::sDebugMouseHandling)
00958                 {
00959                         llinfos << "Right Mouse Down handled by captor " << mouse_captor->getName() << llendl;
00960                 }
00961                 return mouse_captor->handleRightMouseDown(local_x, local_y, mask);
00962         }
00963 
00964         LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
00965         BOOL mouse_over_top_ctrl = FALSE;
00966         if (top_ctrl)
00967         {
00968                 S32 local_x, local_y;
00969                 top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
00970                 if (top_ctrl->pointInView(local_x, local_y))
00971                 {
00972                         mouse_over_top_ctrl = TRUE;
00973                         if(top_ctrl->handleRightMouseDown(local_x, local_y, mask)) 
00974                         {
00975                                 return TRUE;
00976                         }
00977                 }
00978         }
00979 
00980         if( mRootView->handleRightMouseDown(x, y, mask) )
00981         {
00982                 if (LLView::sDebugMouseHandling)
00983                 {
00984                         llinfos << "Right Mouse Down" << LLView::sMouseHandlerMessage << llendl;
00985                         LLView::sMouseHandlerMessage = "";
00986                 }
00987                 if (top_ctrl && top_ctrl->hasFocus() && !mouse_over_top_ctrl)
00988                 {
00989                         // always defocus top view if we click off of it
00990                         top_ctrl->setFocus(FALSE);
00991                 }
00992                 return TRUE;
00993         }
00994         else if (LLView::sDebugMouseHandling)
00995         {
00996                 llinfos << "Right Mouse Down not handled by view" << llendl;
00997         }
00998 
00999         if (top_ctrl && top_ctrl->hasFocus() && !mouse_over_top_ctrl)
01000         {
01001                 // always defocus top view if we click off of it
01002                 top_ctrl->setFocus(FALSE);
01003         }
01004 
01005         if (gToolMgr)
01006         {
01007                 if(gToolMgr->getCurrentTool()->handleRightMouseDown( x, y, mask ) )
01008                 {
01009                         // This is necessary to force clicks in the world to cause edit
01010                         // boxes that might have keyboard focus to relinquish it, and hence
01011                         // cause a commit to update their value.  JC
01012                         gFocusMgr.setKeyboardFocus(NULL, NULL);
01013                         return TRUE;
01014                 }
01015         }
01016 
01017         // *HACK: this should be rolled into the composite tool logic, not
01018         // hardcoded at the top level.
01019         if (gToolPie && (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgent.getCameraMode()) )
01020         {
01021                 // If the current tool didn't process the click, we should show
01022                 // the pie menu.  This can be done by passing the event to the pie
01023                 // menu tool.
01024                 gToolPie->handleRightMouseDown(x, y, mask);
01025                 // show_context_menu( x, y, mask );
01026         }
01027 
01028         return TRUE;
01029 }
01030 
01031 BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)
01032 {
01033         S32 x = pos.mX;
01034         S32 y = pos.mY;
01035         x = llround((F32)x / mDisplayScale.mV[VX]);
01036         y = llround((F32)y / mDisplayScale.mV[VY]);
01037 
01038         // Don't care about caps lock for mouse events.
01039         if (gDebugClicks)
01040         {
01041                 llinfos << "ViewerWindow right mouse up" << llendl;
01042         }
01043 
01044         mRightMouseDown = FALSE;
01045 
01046         // Indicate mouse was active
01047         gMouseIdleTimer.reset();
01048 
01049         // Hide tooltips on mouseup
01050         if( mToolTip )
01051         {
01052                 mToolTip->setVisible( FALSE );
01053         }
01054 
01055         // Also hide hover info on mouseup
01056         if (gHoverView) gHoverView->cancelHover();
01057 
01058         BOOL handled = FALSE;
01059 
01060         mWindow->releaseMouse();
01061 
01062         LLTool *tool = NULL;
01063         if (gToolMgr)
01064         {
01065                 tool = gToolMgr->getCurrentTool();
01066 
01067                 if( tool->clipMouseWhenDown() )
01068                 {
01069                         mWindow->setMouseClipping(FALSE);
01070                 }
01071         }
01072 
01073         LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
01074         if( mouse_captor )
01075         {
01076                 S32 local_x;
01077                 S32 local_y;
01078                 mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
01079                 if (LLView::sDebugMouseHandling)
01080                 {
01081                         llinfos << "Right Mouse Up handled by captor " << mouse_captor->getName() << llendl;
01082                 }
01083                 return mouse_captor->handleRightMouseUp(local_x, local_y, mask);
01084         }
01085 
01086         LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
01087         if (top_ctrl)
01088         {
01089                 S32 local_x, local_y;
01090                 top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
01091                 handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleRightMouseUp(local_x, local_y, mask);
01092         }
01093 
01094         if( !handled )
01095         {
01096                 handled = mRootView->handleRightMouseUp(x, y, mask);
01097         }
01098 
01099         if (LLView::sDebugMouseHandling)
01100         {
01101                 if (handled)
01102                 {
01103                         llinfos << "Right Mouse Up" << LLView::sMouseHandlerMessage << llendl;
01104                         LLView::sMouseHandlerMessage = "";
01105                 }
01106                 else 
01107                 {
01108                         llinfos << "Right Mouse Up not handled by view" << llendl;
01109                 }
01110         }
01111 
01112         if( !handled )
01113         {
01114                 if (tool)
01115                 {
01116                         handled = tool->handleRightMouseUp(x, y, mask);
01117                 }
01118         }
01119 
01120         // Always handled as far as the OS is concerned.
01121         return TRUE;
01122 }
01123 
01124 BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask)
01125 {
01126         gVoiceClient->middleMouseState(true);
01127 
01128         // Always handled as far as the OS is concerned.
01129         return TRUE;
01130 }
01131 
01132 BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)
01133 {
01134         gVoiceClient->middleMouseState(false);
01135 
01136         // Always handled as far as the OS is concerned.
01137         return TRUE;
01138 }
01139 
01140 void LLViewerWindow::handleMouseMove(LLWindow *window,  LLCoordGL pos, MASK mask)
01141 {
01142         S32 x = pos.mX;
01143         S32 y = pos.mY;
01144 
01145         x = llround((F32)x / mDisplayScale.mV[VX]);
01146         y = llround((F32)y / mDisplayScale.mV[VY]);
01147 
01148         mMouseInWindow = TRUE;
01149 
01150         // Save mouse point for access during idle() and display()
01151 
01152         LLCoordGL prev_saved_mouse_point = mCurrentMousePoint;
01153         LLCoordGL mouse_point(x, y);
01154         saveLastMouse(mouse_point);
01155         BOOL mouse_actually_moved = !gFocusMgr.getMouseCapture() &&  // mouse is not currenty captured
01156                         ((prev_saved_mouse_point.mX != mCurrentMousePoint.mX) || (prev_saved_mouse_point.mY != mCurrentMousePoint.mY)); // mouse moved from last recorded position
01157 
01158         gMouseIdleTimer.reset();
01159 
01160         mWindow->showCursorFromMouseMove();
01161 
01162         if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
01163         {
01164                 gAgent.clearAFK();
01165         }
01166 
01167         if(mToolTip && mouse_actually_moved)
01168         {
01169                 mToolTipBlocked = FALSE;  // Blocking starts on keyboard events and (only) ends here.
01170                 if( mToolTip->getVisible() && !mToolTipStickyRect.pointInRect( x, y ) )
01171                 {
01172                         mToolTip->setVisible( FALSE );
01173                 }
01174         }
01175 
01176         // Activate the hover picker on mouse move.
01177         if (gHoverView)
01178         {
01179                 gHoverView->setTyping(FALSE);
01180         }
01181 }
01182 
01183 void LLViewerWindow::handleMouseLeave(LLWindow *window)
01184 {
01185         // Note: we won't get this if we have captured the mouse.
01186         llassert( gFocusMgr.getMouseCapture() == NULL );
01187         mMouseInWindow = FALSE;
01188         if (mToolTip)
01189         {
01190                 mToolTip->setVisible( FALSE );
01191         }
01192 }
01193 
01194 BOOL LLViewerWindow::handleCloseRequest(LLWindow *window)
01195 {
01196         // User has indicated they want to close, but we may need to ask
01197         // about modified documents.
01198         app_user_quit();
01199         // Don't quit immediately
01200         return FALSE;
01201 }
01202 
01203 void LLViewerWindow::handleQuit(LLWindow *window)
01204 {
01205         app_force_quit(NULL);
01206 }
01207 
01208 void LLViewerWindow::handleResize(LLWindow *window,  S32 width,  S32 height)
01209 {
01210         reshape(width, height);
01211 }
01212 
01213 // The top-level window has gained focus (e.g. via ALT-TAB)
01214 void LLViewerWindow::handleFocus(LLWindow *window)
01215 {
01216         gFocusMgr.setAppHasFocus(TRUE);
01217         LLModalDialog::onAppFocusGained();
01218         if (gToolMgr)
01219         {
01220                 gToolMgr->onAppFocusGained();
01221         }
01222 
01223         gShowTextEditCursor = TRUE;
01224 
01225         // See if we're coming in with modifier keys held down
01226         if (gKeyboard)
01227         {
01228                 gKeyboard->resetMaskKeys();
01229         }
01230 
01231         // resume foreground running timer
01232         // since we artifically limit framerate when not frontmost
01233         gForegroundTime.unpause();
01234 }
01235 
01236 // The top-level window has lost focus (e.g. via ALT-TAB)
01237 void LLViewerWindow::handleFocusLost(LLWindow *window)
01238 {
01239         gFocusMgr.setAppHasFocus(FALSE);
01240         //LLModalDialog::onAppFocusLost();
01241         if( gToolMgr )
01242         {
01243                 gToolMgr->onAppFocusLost();
01244         }
01245         gFocusMgr.setMouseCapture( NULL );
01246 
01247         if (gMenuBarView)
01248         {
01249                 // stop ALT-key access to menu
01250                 gMenuBarView->resetMenuTrigger();
01251         }
01252 
01253         // restore mouse cursor
01254         gViewerWindow->showCursor();
01255         gViewerWindow->getWindow()->setMouseClipping(FALSE);
01256 
01257         // JC - Leave keyboard focus, so if you're popping in and out editing
01258         // a script, you don't have to click in the editor again and again.
01259         // gFocusMgr.setKeyboardFocus( NULL, NULL );
01260         gShowTextEditCursor = FALSE;
01261 
01262         // If losing focus while keys are down, reset them.
01263         if (gKeyboard)
01264         {
01265                 gKeyboard->resetKeys();
01266         }
01267 
01268         // pause timer that tracks total foreground running time
01269         gForegroundTime.pause();
01270 }
01271 
01272 
01273 BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)
01274 {
01275         // Let the voice chat code check for its PTT key.  Note that this never affects event processing.
01276         gVoiceClient->keyDown(key, mask);
01277         
01278         if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
01279         {
01280                 gAgent.clearAFK();
01281         }
01282 
01283         // *NOTE: We want to interpret KEY_RETURN later when it arrives as
01284         // a Unicode char, not as a keydown.  Otherwise when client frame
01285         // rate is really low, hitting return sends your chat text before
01286         // it's all entered/processed.
01287         if (key == KEY_RETURN && mask == MASK_NONE)
01288         {
01289                 return FALSE;
01290         }
01291 
01292         return gViewerKeyboard.handleKey(key, mask, repeated);
01293 }
01294 
01295 BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key,  MASK mask)
01296 {
01297         // Let the voice chat code check for its PTT key.  Note that this never affects event processing.
01298         gVoiceClient->keyUp(key, mask);
01299 
01300         return FALSE;
01301 }
01302 
01303 
01304 void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
01305 {
01306         return gViewerKeyboard.scanKey(key, key_down, key_up, key_level);
01307 }
01308 
01309 
01310 
01311 
01312 BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated)
01313 {
01314         if (activated)
01315         {
01316                 mActive = TRUE;
01317                 send_agent_resume();
01318                 gAgent.clearAFK();
01319                 if (mWindow->getFullscreen() && !mIgnoreActivate)
01320                 {
01321                         if (!gQuit)
01322                         {
01323                                 if (LLStartUp::getStartupState() >= STATE_STARTED)
01324                                 {
01325                                         // if we're in world, show a progress bar to hide reloading of textures
01326                                         llinfos << "Restoring GL during activate" << llendl;
01327                                         restoreGL("Restoring...");
01328                                 }
01329                                 else
01330                                 {
01331                                         // otherwise restore immediately
01332                                         restoreGL();
01333                                 }
01334                         }
01335                         else
01336                         {
01337                                 llwarns << "Activating while quitting" << llendl;
01338                         }
01339                 }
01340 
01341                 // Unmute audio
01342                 audio_update_volume();
01343         }
01344         else
01345         {
01346                 mActive = FALSE;
01347                 if (gAllowIdleAFK)
01348                 {
01349                         gAgent.setAFK();
01350                 }
01351                 
01352                 // SL-53351: Make sure we're not in mouselook when minimised, to prevent control issues
01353                 gAgent.changeCameraToDefault();
01354                 
01355                 send_agent_pause();
01356                 
01357                 if (mWindow->getFullscreen() && !mIgnoreActivate)
01358                 {
01359                         llinfos << "Stopping GL during deactivation" << llendl;
01360                         stopGL();
01361                 }
01362                 // Mute audio
01363                 audio_update_volume();
01364         }
01365         return TRUE;
01366 }
01367 
01368 
01369 void LLViewerWindow::handleMenuSelect(LLWindow *window,  S32 menu_item)
01370 {
01371 }
01372 
01373 
01374 BOOL LLViewerWindow::handlePaint(LLWindow *window,  S32 x,  S32 y, S32 width,  S32 height)
01375 {
01376 #if LL_WINDOWS
01377         if (gNoRender)
01378         {
01379                 HWND window_handle = (HWND)window->getPlatformWindow();
01380                 PAINTSTRUCT ps; 
01381                 HDC hdc; 
01382  
01383                 RECT wnd_rect;
01384                 wnd_rect.left = 0;
01385                 wnd_rect.top = 0;
01386                 wnd_rect.bottom = 200;
01387                 wnd_rect.right = 500;
01388 
01389                 hdc = BeginPaint(window_handle, &ps); 
01390                 //SetBKColor(hdc, RGB(255, 255, 255));
01391                 FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255)));
01392 
01393                 LLString name_str;
01394                 gAgent.getName(name_str);
01395 
01396                 S32 len;
01397                 char temp_str[255];             /* Flawfinder: ignore */
01398                 snprintf(temp_str, sizeof(temp_str), "%s FPS %3.1f Phy FPS %2.1f Time Dil %1.3f",               /* Flawfinder: ignore */
01399                                 name_str.c_str(),
01400                                 gViewerStats->mFPSStat.getMeanPerSec(),
01401                                 gViewerStats->mSimPhysicsFPS.getPrev(0),
01402                                 gViewerStats->mSimTimeDilation.getPrev(0));
01403                 len = strlen(temp_str);         /* Flawfinder: ignore */
01404                 TextOutA(hdc, 0, 0, temp_str, len); 
01405 
01406 
01407                 LLVector3d pos_global = gAgent.getPositionGlobal();
01408                 snprintf(temp_str, sizeof(temp_str), "Avatar pos %6.1lf %6.1lf %6.1lf", pos_global.mdV[0], pos_global.mdV[1], pos_global.mdV[2]);               /* Flawfinder: ignore */
01409                 len = strlen(temp_str);         /* Flawfinder: ignore */
01410                 TextOutA(hdc, 0, 25, temp_str, len); 
01411 
01412                 TextOutA(hdc, 0, 50, "Set \"DisableRendering FALSE\" in settings.ini file to reenable", 61);
01413                 EndPaint(window_handle, &ps); 
01414                 return TRUE;
01415         }
01416 #endif
01417         return FALSE;
01418 }
01419 
01420 
01421 void LLViewerWindow::handleScrollWheel(LLWindow *window,  S32 clicks)
01422 {
01423         gViewerWindow->handleScrollWheel( clicks );
01424 }
01425 
01426 void LLViewerWindow::handleWindowBlock(LLWindow *window)
01427 {
01428         send_agent_pause();
01429 }
01430 
01431 void LLViewerWindow::handleWindowUnblock(LLWindow *window)
01432 {
01433         send_agent_resume();
01434 }
01435 
01436 void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data)
01437 {
01438         const S32 SLURL_MESSAGE_TYPE = 0;
01439         switch (data_type)
01440         {
01441         case SLURL_MESSAGE_TYPE:
01442                 // received URL
01443                 std::string url = (const char*)data;
01444                 if (LLURLDispatcher::dispatch(url))
01445                 {
01446                         // bring window to foreground, as it has just been "launched" from a URL
01447                         mWindow->bringToFront();
01448                 }
01449                 break;
01450         }
01451 }
01452 
01453 
01454 //
01455 // Classes
01456 //
01457 LLViewerWindow::LLViewerWindow(
01458         char* title, char* name,
01459         S32 x, S32 y,
01460         S32 width, S32 height,
01461         BOOL fullscreen, BOOL ignore_pixel_depth, S32 stereo_mode)
01462         :
01463         mActive(TRUE),
01464         mWantFullscreen(fullscreen),
01465         mShowFullscreenProgress(FALSE),
01466         mWindowRect(0, height, width, 0),
01467         mVirtualWindowRect(0, height, width, 0),
01468         mLeftMouseDown(FALSE),
01469         mRightMouseDown(FALSE),
01470         mToolTip(NULL),
01471         mToolTipBlocked(FALSE),
01472         mMouseInWindow( FALSE ),
01473         mLastMask( MASK_NONE ),
01474         mToolStored( NULL ),
01475         mSuppressToolbox( FALSE ),
01476         mHideCursorPermanent( FALSE ),
01477         mPickPending(FALSE),
01478         mIgnoreActivate( FALSE )
01479 {
01480         // Default to application directory.
01481         strcpy(LLViewerWindow::sSnapshotBaseName, "Snapshot");  /* Flawfinder: ignore */
01482         strcpy(LLViewerWindow::sMovieBaseName, "SLmovie");      /* Flawfinder: ignore */
01483         LLViewerWindow::sSnapshotDir[0] = '\0';
01484 
01485 
01486         // create window
01487         mWindow = LLWindowManager::createWindow(
01488                 title, name, x, y, width, height, 0,
01489                 fullscreen, 
01490                 gNoRender,
01491                 gSavedSettings.getBOOL("DisableVerticalSync"),
01492                 !gNoRender,
01493                 ignore_pixel_depth,
01494                 stereo_mode);
01495 #if LL_WINDOWS
01496         if (!LLWinDebug::setupExceptionHandler())
01497         {
01498                 llwarns << " Someone took over my exception handler (post createWindow)!" << llendl;
01499         }
01500 #endif
01501 
01502         if (NULL == mWindow)
01503         {
01504                 LLSplashScreen::update("Shutting down...");
01505 #if LL_LINUX || LL_SOLARIS
01506                 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 or README-solaris.txt for further information."
01507                                 << llendl;
01508 #else
01509                 llwarns << "Unable to create window, be sure screen is set at 32-bit color in Control Panels->Display->Settings"
01510                                 << llendl;
01511 #endif
01512                 app_force_exit(1);
01513         }
01514         
01515         // Get the real window rect the window was created with (since there are various OS-dependent reasons why
01516         // the size of a window or fullscreen context may have been adjusted slightly...)
01517         F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor");
01518         
01519         mDisplayScale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
01520         mDisplayScale *= ui_scale_factor;
01521         LLUI::setScaleFactor(mDisplayScale);
01522 
01523         {
01524                 LLCoordWindow size;
01525                 mWindow->getSize(&size);
01526                 mWindowRect.set(0, size.mY, size.mX, 0);
01527                 mVirtualWindowRect.set(0, llround((F32)size.mY / mDisplayScale.mV[VY]), llround((F32)size.mX / mDisplayScale.mV[VX]), 0);
01528         }
01529         
01530         LLFontManager::initClass();
01531 
01532         // Initialize OpenGL Renderer
01533 
01534         if (!gFeatureManagerp->isFeatureAvailable("RenderVBO") ||
01535                 !gGLManager.mHasVertexBufferObject)
01536         {
01537                 gSavedSettings.setBOOL("RenderVBOEnable", FALSE);
01538         }
01539         LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"));
01540 
01541         //
01542         // We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off
01543         // stuff like AGP if we think that it'll crash the viewer.
01544         //
01545         gFeatureManagerp->initGraphicsFeatureMasks();
01546         if (gFeatureManagerp->isSafe()
01547                 || (gSavedSettings.getS32("LastFeatureVersion") != gFeatureManagerp->getVersion()))
01548         {
01549                 gFeatureManagerp->applyRecommendedFeatures();
01550         }
01551 
01552         S32 idx = gSavedSettings.getS32("GraphicsCardMemorySetting");
01553         // -1 indicates use default (max)
01554         if (idx == -1)
01555         {
01556                 idx = LLViewerImageList::getMaxVideoRamSetting(-2); // get max recommended setting
01557                 gSavedSettings.setS32("GraphicsCardMemorySetting", idx);
01558         }
01559 
01560         // If we crashed while initializng GL stuff last time, disable certain features
01561         if (gSavedSettings.getBOOL("RenderInitError"))
01562         {
01563                 mInitAlert = "DisplaySettingsNoShaders";
01564                 gSavedSettings.setBOOL("VertexShaderEnable", FALSE);
01565         }
01566                 
01567         if (!gNoRender)
01568         {
01569                 //
01570                 // Initialize GL stuff
01571                 //
01572 
01573                 // Set this flag in case we crash while initializing GL
01574                 gSavedSettings.setBOOL("RenderInitError", TRUE);
01575                 gSavedSettings.saveToFile( gSettingsFileName, TRUE );
01576         
01577                 gPipeline.init();
01578                 stop_glerror();
01579                 initGLDefaults();
01580 
01581                 gSavedSettings.setBOOL("RenderInitError", FALSE);
01582                 gSavedSettings.saveToFile( gSettingsFileName, TRUE );
01583         }
01584 
01585         //
01586         // Done initing GL stuff.
01587         //
01588 
01589         // set callbacks
01590         mWindow->setCallbacks(this);
01591 
01592         // Init the image list.  Must happen after GL is initialized and before the images that
01593         // LLViewerWindow needs are requested.
01594         gImageList.init();
01595         LLViewerImage::initClass();
01596         gBumpImageList.init();
01597 
01598         // Create container for all sub-views
01599         mRootView = new LLRootView("root", mVirtualWindowRect, FALSE);
01600 
01601         if (!gNoRender)
01602         {
01603                 // Init default fonts
01604                 initFonts();
01605         }
01606 
01607         // Init Resource Manager
01608         gResMgr = new LLResMgr();
01609 
01610         // Make avatar head look forward at start
01611         mCurrentMousePoint.mX = getWindowWidth() / 2;
01612         mCurrentMousePoint.mY = getWindowHeight() / 2;
01613 
01614         mPickBuffer = new U8[PICK_DIAMETER * PICK_DIAMETER * 4];
01615 
01616         gShowOverlayTitle = gSavedSettings.getBOOL("ShowOverlayTitle");
01617         mOverlayTitle = gSavedSettings.getString("OverlayTitle");
01618         // Can't have spaces in settings.ini strings, so use underscores instead and convert them.
01619         LLString::replaceChar(mOverlayTitle, '_', ' ');
01620 
01621         LLAlertDialog::setDisplayCallback(alertCallback); // call this before calling any modal dialogs
01622 
01623         // sync the keyboard's setting with the saved setting
01624         gSavedSettings.getControl("NumpadControl")->firePropertyChanged();
01625 
01626         mDebugText = new LLDebugText(this);
01627 
01628 }
01629 
01630 void LLViewerWindow::initGLDefaults()
01631 {
01632         //LLGLState::reset();
01633         //gGLSDefault.set();
01634         //LLGLState::verify(TRUE);
01635 
01636         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01637         glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
01638 
01639         F32 ambient[4] = {0.f,0.f,0.f,0.f };
01640         F32 diffuse[4] = {1.f,1.f,1.f,1.f };
01641         glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,ambient);
01642         glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,diffuse);
01643         
01644         glPixelStorei(GL_PACK_ALIGNMENT,1);
01645         glPixelStorei(GL_UNPACK_ALIGNMENT,1);
01646 
01647         // lights for objects
01648         glShadeModel( GL_SMOOTH );
01649 
01650         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
01651 
01652         glCullFace(GL_BACK);
01653 
01654         // RN: Need this for translation and stretch manip.
01655         gCone.prerender();
01656         gBox.prerender();
01657         gSphere.prerender();
01658         gCylinder.prerender();
01659 
01660         LLVOAvatar::initVertexPrograms();
01661 }
01662 
01663 void LLViewerWindow::initBase()
01664 {
01665         S32 height = getWindowHeight();
01666         S32 width = getWindowWidth();
01667 
01668         LLRect full_window(0, height, width, 0);
01669 
01670         adjustRectanglesForFirstUse(full_window);
01671 
01673         //
01674         // Set the gamma
01675         //
01676 
01677         F32 gamma = gSavedSettings.getF32("RenderGamma");
01678         if (gamma != 0.0f)
01679         {
01680                 gViewerWindow->getWindow()->setGamma(gamma);
01681         }
01682 
01683         // Create global views
01684 
01685         // Create the floater view at the start so that other views can add children to it. 
01686         // (But wait to add it as a child of the root view so that it will be in front of the 
01687         // other views.)
01688 
01689         // Constrain floaters to inside the menu and status bar regions.
01690         LLRect floater_view_rect = full_window;
01691         // make space for menu bar if we have one
01692         floater_view_rect.mTop -= MENU_BAR_HEIGHT;
01693         floater_view_rect.mBottom += STATUS_BAR_HEIGHT + 12 + 16 + 2;
01694 
01695         // Check for non-first startup
01696         S32 floater_view_bottom = gSavedSettings.getS32("FloaterViewBottom");
01697         if (floater_view_bottom >= 0)
01698         {
01699                 floater_view_rect.mBottom = floater_view_bottom;
01700         }
01701         gFloaterView = new LLFloaterView("Floater View", floater_view_rect );
01702         gFloaterView->setVisible(TRUE);
01703 
01704         gSnapshotFloaterView = new LLSnapshotFloaterView("Snapshot Floater View", full_window);
01705         gSnapshotFloaterView->setVisible(TRUE);
01706 
01707         // Console
01708         llassert( !gConsole );
01709         LLRect console_rect = full_window;
01710         console_rect.mTop    -= 24;
01711         console_rect.mBottom += STATUS_BAR_HEIGHT + 12 + 16 + 12;
01712         console_rect.mLeft   += 24; //gSavedSettings.getS32("StatusBarButtonWidth") + gSavedSettings.getS32("StatusBarPad");
01713 
01714         if (gSavedSettings.getBOOL("ChatFullWidth"))
01715         {
01716                 console_rect.mRight -= 10;
01717         }
01718         else
01719         {
01720                 // Make console rect somewhat narrow so having inventory open is
01721                 // less of a problem.
01722                 console_rect.mRight  = console_rect.mLeft + 2 * width / 3;
01723         }
01724 
01725         gConsole = new LLConsole(
01726                 "console",
01727                 gSavedSettings.getS32("ConsoleBufferSize"),
01728                 console_rect,
01729                 gSavedSettings.getS32("ChatFontSize"),
01730                 gSavedSettings.getF32("ChatPersistTime") );
01731         gConsole->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
01732         mRootView->addChild(gConsole);
01733 
01734         // Debug view over the console
01735         gDebugView = new LLDebugView("gDebugView", full_window);
01736         gDebugView->setFollowsAll();
01737         gDebugView->setVisible(TRUE);
01738         mRootView->addChild(gDebugView);
01739 
01740         // HUD elements just below floaters
01741         LLRect hud_rect = full_window;
01742         hud_rect.mTop -= 24;
01743         hud_rect.mBottom += STATUS_BAR_HEIGHT;
01744         gHUDView = new LLHUDView("hud_view", hud_rect);
01745         gHUDView->setFollowsAll();
01746         mRootView->addChild(gHUDView);
01747 
01748         // Add floater view at the end so it will be on top, and give it tab priority over others
01749         mRootView->addChild(gFloaterView, -1);
01750         mRootView->addChild(gSnapshotFloaterView);
01751 
01752         // notify above floaters!
01753         LLRect notify_rect = full_window;
01754         //notify_rect.mTop -= 24;
01755         notify_rect.mBottom += STATUS_BAR_HEIGHT;
01756         gNotifyBoxView = new LLNotifyBoxView("notify_container", notify_rect, FALSE, FOLLOWS_ALL);
01757         mRootView->addChild(gNotifyBoxView, -2);
01758 
01759         // Tooltips go above floaters
01760         mToolTip = new LLTextBox( "tool tip", LLRect(0, 1, 1, 0 ) );
01761         mToolTip->setHPad( 4 );
01762         mToolTip->setVPad( 2 );
01763         mToolTip->setColor( gColors.getColor( "ToolTipTextColor" ) );
01764         mToolTip->setBorderColor( gColors.getColor( "ToolTipBorderColor" ) );
01765         mToolTip->setBorderVisible( FALSE );
01766         mToolTip->setBackgroundColor( gColors.getColor( "ToolTipBgColor" ) );
01767         mToolTip->setBackgroundVisible( TRUE );
01768         mToolTip->setFontStyle(LLFontGL::NORMAL);
01769         mToolTip->setBorderDropshadowVisible( TRUE );
01770         mToolTip->setVisible( FALSE );
01771 
01772         // Add the progress bar view (startup view), which overrides everything
01773         mProgressView = new LLProgressView("ProgressView", full_window);
01774         mRootView->addChild(mProgressView);
01775         setShowProgress(FALSE);
01776         setProgressCancelButtonVisible(FALSE, "");
01777 }
01778 
01779 
01780 void adjust_rect_top_left(const LLString& control, const LLRect& window)
01781 {
01782         LLRect r = gSavedSettings.getRect(control);
01783         if (r.mLeft == 0 && r.mBottom == 0)
01784         {
01785                 r.setLeftTopAndSize(0, window.getHeight(), r.getWidth(), r.getHeight());
01786                 gSavedSettings.setRect(control, r);
01787         }
01788 }
01789 
01790 void adjust_rect_top_right(const LLString& control, const LLRect& window)
01791 {
01792         LLRect r = gSavedSettings.getRect(control);
01793         if (r.mLeft == 0 && r.mBottom == 0)
01794         {
01795                 r.setLeftTopAndSize(window.getWidth() - r.getWidth(),
01796                         window.getHeight(),
01797                         r.getWidth(), 
01798                         r.getHeight());
01799                 gSavedSettings.setRect(control, r);
01800         }
01801 }
01802 
01803 void adjust_rect_bottom_center(const LLString& control, const LLRect& window)
01804 {
01805         LLRect r = gSavedSettings.getRect(control);
01806         if (r.mLeft == 0 && r.mBottom == 0)
01807         {
01808                 r.setOriginAndSize(
01809                         window.getWidth()/2 - r.getWidth()/2,
01810                         0,
01811                         r.getWidth(),
01812                         r.getHeight());
01813                 gSavedSettings.setRect(control, r);
01814         }
01815 }
01816 
01817 // Many rectangles can't be placed until we know the screen size.
01818 // These rectangles have their bottom-left corner as 0,0
01819 void LLViewerWindow::adjustRectanglesForFirstUse(const LLRect& window)
01820 {
01821         LLRect r;
01822 
01823         adjust_rect_bottom_center("FloaterMoveRect", window);
01824 
01825         adjust_rect_bottom_center("FloaterCameraRect", window);
01826 
01827         adjust_rect_top_left("FloaterCustomizeAppearanceRect", window);
01828 
01829         adjust_rect_top_left("FloaterLandRect5", window);
01830 
01831         adjust_rect_top_left("FloaterFindRect2", window);
01832 
01833         adjust_rect_top_left("FloaterGestureRect", window);
01834 
01835         adjust_rect_top_right("FloaterMapRect", window);
01836         
01837         adjust_rect_top_right("FloaterLagMeter", window);
01838 
01839         adjust_rect_top_right("FloaterLagMeter", window);
01840 
01841         adjust_rect_top_left("FloaterBuildOptionsRect", window);
01842 
01843         // bottom-right
01844         r = gSavedSettings.getRect("FloaterInventoryRect");
01845         if (r.mLeft == 0 && r.mBottom == 0)
01846         {
01847                 r.setOriginAndSize(
01848                         window.getWidth() - r.getWidth(),
01849                         0,
01850                         r.getWidth(),
01851                         r.getHeight());
01852                 gSavedSettings.setRect("FloaterInventoryRect", r);
01853         }
01854 }
01855 
01856 
01857 void LLViewerWindow::initWorldUI()
01858 {
01859         pre_init_menus();
01860 
01861         S32 height = mRootView->getRect().getHeight();
01862         S32 width = mRootView->getRect().getWidth();
01863         LLRect full_window(0, height, width, 0);
01864 
01865         if ( gToolBar == NULL )                 // Don't re-enter if objects are alreay created
01866         {
01867                 LLRect bar_rect(-1, STATUS_BAR_HEIGHT, width+1, -1);
01868                 gToolBar = new LLToolBar("toolbar", bar_rect);
01869 
01870                 LLRect chat_bar_rect(-1,CHAT_BAR_HEIGHT, width+1, -1);
01871                 chat_bar_rect.translate(0, STATUS_BAR_HEIGHT-1);
01872                 gChatBar = new LLChatBar("chat", chat_bar_rect);
01873 
01874                 bar_rect.translate(0, STATUS_BAR_HEIGHT-1);
01875                 bar_rect.translate(0, CHAT_BAR_HEIGHT-1);
01876                 gOverlayBar = new LLOverlayBar("overlay", bar_rect);
01877 
01878                 // panel containing chatbar, toolbar, and overlay, over floaters
01879                 LLRect bottom_rect(-1, 2*STATUS_BAR_HEIGHT + CHAT_BAR_HEIGHT, width+1, -1);
01880                 gBottomPanel = new LLBottomPanel("bottom panel", bottom_rect);
01881 
01882                 // the order here is important
01883                 gBottomPanel->addChild(gChatBar);
01884                 gBottomPanel->addChild(gToolBar);
01885                 gBottomPanel->addChild(gOverlayBar);
01886                 mRootView->addChild(gBottomPanel);
01887 
01888                 // View for hover information
01889                 gHoverView = new LLHoverView("gHoverView", full_window);
01890                 gHoverView->setVisible(TRUE);
01891                 mRootView->addChild(gHoverView);
01892 
01893                 //
01894                 // Map
01895                 //
01896                 // TODO: Move instance management into class
01897                 gFloaterMap = new LLFloaterMap("Map");
01898                 gFloaterMap->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT);
01899                 gFloaterMap->setVisible( gSavedSettings.getBOOL("ShowMiniMap") );
01900 
01901                 // keep onscreen
01902                 gFloaterView->adjustToFitScreen(gFloaterMap, FALSE);
01903 
01904                 if (gSavedSettings.getBOOL("ShowCameraControls"))
01905                 {
01906                         LLFloaterCamera::show(NULL);
01907                 }
01908                 
01909                 if (gSavedSettings.getBOOL("ShowMovementControls"))
01910                 {
01911                         LLFloaterMove::show(NULL);
01912                 }
01913                 
01914                 gIMMgr = LLIMMgr::getInstance();
01915 
01916                 if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") )
01917                 {
01918                         LLFloaterChat::getInstance(LLSD())->loadHistory();
01919                 }
01920 
01921                 LLRect morph_view_rect = full_window;
01922                 morph_view_rect.stretch( -STATUS_BAR_HEIGHT );
01923                 morph_view_rect.mTop = full_window.mTop - 32;
01924                 gMorphView = new LLMorphView("gMorphView", morph_view_rect );
01925                 mRootView->addChild(gMorphView);
01926                 gMorphView->setVisible(FALSE);
01927 
01928                 gFloaterMute = new LLFloaterMute();
01929                 gFloaterMute->setVisible(FALSE);
01930 
01931                 gFloaterAvatarList = new LLFloaterAvatarList();
01932                 gFloaterAvatarList->setVisible(FALSE);
01933 
01934                 gFloaterEventLog = new LLFloaterEventLog();
01935                 gFloaterEventLog->setVisible(FALSE);
01936 
01937                 gFloaterProject = new LLFloaterNetwork2080();
01938                 gFloaterProject->setVisible(FALSE);
01939 
01940                 LLWorldMapView::initClass();
01941                 
01942                 LLRect world_map_rect = gSavedSettings.getRect("FloaterWorldMapRect");
01943                 // if 0,0,0,0 then use fullscreen
01944                 if (world_map_rect.mTop == 0 
01945                         && world_map_rect.mLeft == 0
01946                         && world_map_rect.mRight == 0
01947                         && world_map_rect.mBottom == 0)
01948                 {
01949                         world_map_rect.set(0, height-TOOL_BAR_HEIGHT, width, STATUS_BAR_HEIGHT);
01950                         world_map_rect.stretch(-4);
01951                         gSavedSettings.setRect("FloaterWorldMapRect", world_map_rect);
01952                 }
01953                 gFloaterWorldMap = new LLFloaterWorldMap();
01954                 gFloaterWorldMap->setVisible(FALSE);
01955 
01956                 //
01957                 // Tools for building
01958                 //
01959 
01960                 // Toolbox floater
01961                 init_menus();
01962 
01963                 gFloaterTools = new LLFloaterTools();
01964                 gFloaterTools->setVisible(FALSE);
01965 
01966                 // Status bar
01967                 S32 menu_bar_height = gMenuBarView->getRect().getHeight();
01968                 LLRect root_rect = gViewerWindow->getRootView()->getRect();
01969                 LLRect status_rect(0, root_rect.getHeight(), root_rect.getWidth(), root_rect.getHeight() - menu_bar_height);
01970                 gStatusBar = new LLStatusBar("status", status_rect);
01971                 gStatusBar->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP);
01972 
01973                 gStatusBar->reshape(root_rect.getWidth(), gStatusBar->getRect().getHeight(), TRUE);
01974                 gStatusBar->translate(0, root_rect.getHeight() - gStatusBar->getRect().getHeight());
01975                 // sync bg color with menu bar
01976                 gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor() );
01977 
01978                 LLFloaterChatterBox::createInstance(LLSD());
01979 
01980                 gViewerWindow->getRootView()->addChild(gStatusBar);
01981 
01982                 // menu holder appears on top to get first pass at all mouse events
01983                 gViewerWindow->getRootView()->sendChildToFront(gMenuHolder);
01984         }
01985 }
01986 
01987 
01988 LLViewerWindow::~LLViewerWindow()
01989 {
01990         delete mDebugText;
01991         
01992         gSavedSettings.setS32("FloaterViewBottom", gFloaterView->getRect().mBottom);
01993 
01994         // Cleanup global views
01995         if (gMorphView)
01996         {
01997                 gMorphView->setVisible(FALSE);
01998         }
01999         
02000         // Delete all child views.
02001         delete mRootView;
02002         mRootView = NULL;
02003 
02004         // Automatically deleted as children of mRootView.  Fix the globals.
02005         gFloaterTools = NULL;
02006         gStatusBar = NULL;
02007         gFloaterCamera = NULL;
02008         gIMMgr = NULL;
02009         gHoverView = NULL;
02010         gFloaterEventLog = NULL;
02011 
02012         gFloaterView            = NULL;
02013         gMorphView                      = NULL;
02014 
02015         gFloaterMute = NULL;
02016         gFloaterAvatarList = NULL;
02017 
02018         gFloaterMap     = NULL;
02019         gHUDView = NULL;
02020 
02021         gNotifyBoxView = NULL;
02022 
02023         delete mToolTip;
02024         mToolTip = NULL;
02025 
02026         delete gResMgr;
02027         gResMgr = NULL;
02028         
02029         //--------------------------------------------------------
02030         // Shutdown GL cleanly.  Order is very important here.
02031         //--------------------------------------------------------
02032         LLFontGL::destroyDefaultFonts();
02033         LLFontManager::cleanupClass();
02034         stop_glerror();
02035 
02036         gSky.cleanup();
02037         stop_glerror();
02038 
02039         gImageList.shutdown();
02040         stop_glerror();
02041 
02042         gBumpImageList.shutdown();
02043         stop_glerror();
02044 
02045         LLWorldMapView::cleanupTextures();
02046 
02047         llinfos << "Cleaning up pipeline" << llendl;
02048         gPipeline.cleanup();
02049         stop_glerror();
02050 
02051         LLViewerImage::cleanupClass();
02052         
02053         delete[] mPickBuffer;
02054         mPickBuffer = NULL;
02055 
02056         if (gSelectMgr)
02057         {
02058                 llinfos << "Cleaning up select manager" << llendl;
02059                 gSelectMgr->cleanup();
02060         }
02061 
02062         LLVertexBuffer::cleanupClass();
02063 
02064         llinfos << "Stopping GL during shutdown" << llendl;
02065         if (!gNoRender)
02066         {
02067                 stopGL(FALSE);
02068                 stop_glerror();
02069         }
02070 
02071 
02072         llinfos << "Destroying Window" << llendl;
02073         destroyWindow();
02074 }
02075 
02076 
02077 void LLViewerWindow::setCursor( ECursorType c )
02078 {
02079         mWindow->setCursor( c );
02080 }
02081 
02082 void LLViewerWindow::showCursor()
02083 {
02084         mWindow->showCursor();
02085 }
02086 
02087 void LLViewerWindow::hideCursor()
02088 {
02089         // Hide tooltips
02090         if(mToolTip ) mToolTip->setVisible( FALSE );
02091 
02092         // Also hide hover info
02093         if (gHoverView) gHoverView->cancelHover();
02094 
02095         // And hide the cursor
02096         mWindow->hideCursor();
02097 }
02098 
02099 void LLViewerWindow::sendShapeToSim()
02100 {
02101         LLMessageSystem* msg = gMessageSystem;
02102         if(!msg) return;
02103         msg->newMessageFast(_PREHASH_AgentHeightWidth);
02104         msg->nextBlockFast(_PREHASH_AgentData);
02105         msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
02106         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
02107         msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode);
02108         msg->nextBlockFast(_PREHASH_HeightWidthBlock);
02109         msg->addU32Fast(_PREHASH_GenCounter, 0);
02110         U16 height16 = (U16) mWindowRect.getHeight();
02111         U16 width16 = (U16) mWindowRect.getWidth();
02112         msg->addU16Fast(_PREHASH_Height, height16);
02113         msg->addU16Fast(_PREHASH_Width, width16);
02114         gAgent.sendReliableMessage();
02115 }
02116 
02117 // Must be called after window is created to set up agent
02118 // camera variables and UI variables.
02119 void LLViewerWindow::reshape(S32 width, S32 height)
02120 {
02121         // Destroying the window at quit time generates spurious
02122         // reshape messages.  We don't care about these, and we
02123         // don't want to send messages because the message system
02124         // may have been destructed.
02125         if (!gQuit)
02126         {
02127                 if (gNoRender)
02128                 {
02129                         return;
02130                 }
02131 
02132                 glViewport(0, 0, width, height );
02133 
02134                 if (height > 0 && gCamera)
02135                 {
02136                         gCamera->setViewHeightInPixels( height );
02137                         if (mWindow->getFullscreen())
02138                         {
02139                                 // force to 4:3 aspect for odd resolutions
02140                                 gCamera->setAspect( getDisplayAspectRatio() );
02141                         }
02142                         else
02143                         {
02144                                 gCamera->setAspect( width / (F32) height);
02145                         }
02146                 }
02147 
02148                 // update our window rectangle
02149                 mWindowRect.mRight = mWindowRect.mLeft + width;
02150                 mWindowRect.mTop = mWindowRect.mBottom + height;
02151                 calcDisplayScale();
02152         
02153                 BOOL display_scale_changed = mDisplayScale != LLUI::sGLScaleFactor;
02154                 LLUI::setScaleFactor(mDisplayScale);
02155 
02156                 // update our window rectangle
02157                 mVirtualWindowRect.mRight = mVirtualWindowRect.mLeft + llround((F32)width / mDisplayScale.mV[VX]);
02158                 mVirtualWindowRect.mTop = mVirtualWindowRect.mBottom + llround((F32)height / mDisplayScale.mV[VY]);
02159 
02160                 setupViewport();
02161 
02162                 // Inform lower views of the change
02163                 // round up when converting coordinates to make sure there are no gaps at edge of window
02164                 LLView::sForceReshape = display_scale_changed;
02165                 mRootView->reshape(llceil((F32)width / mDisplayScale.mV[VX]), llceil((F32)height / mDisplayScale.mV[VY]));
02166                 LLView::sForceReshape = FALSE;
02167 
02168                 // clear font width caches
02169                 if (display_scale_changed)
02170                 {
02171                         LLHUDText::reshape();
02172                 }
02173 
02174                 sendShapeToSim();
02175 
02176 
02177                 // store the mode the user wants (even if not there yet)
02178                 gSavedSettings.setBOOL("FullScreen", mWantFullscreen);
02179 
02180                 // store new settings for the mode we are in, regardless
02181                 if (mWindow->getFullscreen())
02182                 {
02183                         gSavedSettings.setS32("FullScreenWidth", width);
02184                         gSavedSettings.setS32("FullScreenHeight", height);
02185                 }
02186                 else
02187                 {
02188                         // Only save size if not maximized
02189                         BOOL maximized = mWindow->getMaximized();
02190                         gSavedSettings.setBOOL("WindowMaximized", maximized);
02191 
02192                         LLCoordScreen window_size;
02193                         if (!maximized
02194                                 && mWindow->getSize(&window_size))
02195                         {
02196                                 gSavedSettings.setS32("WindowWidth", window_size.mX);
02197                                 gSavedSettings.setS32("WindowHeight", window_size.mY);
02198                         }
02199                 }
02200 
02201                 gViewerStats->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width);
02202                 gViewerStats->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height);
02203         }
02204 }
02205 
02206 
02207 // Hide normal UI when a logon fails
02208 void LLViewerWindow::setNormalControlsVisible( BOOL visible )
02209 {
02210         if ( gBottomPanel )
02211                 gBottomPanel->setVisible( visible );
02212 
02213         if ( gMenuBarView )
02214                 gMenuBarView->setVisible( visible );
02215 
02216         if ( gStatusBar )
02217                 gStatusBar->setVisible( visible );              
02218 }
02219 
02220 
02221 
02222 
02223 void LLViewerWindow::drawDebugText()
02224 {
02225         mDebugText->draw();
02226 }
02227 
02228 void LLViewerWindow::draw()
02229 {
02230 #if LL_DEBUG
02231         LLView::sIsDrawing = TRUE;
02232 #endif
02233         stop_glerror();
02234         
02235         LLUI::setLineWidth(1.f);
02236         //popup alerts from the UI
02237         LLAlertInfo alert;
02238         while (LLPanel::nextAlert(alert))
02239         {
02240                 alertXml(alert.mLabel, alert.mArgs);
02241         }
02242 
02243         LLUI::setLineWidth(1.f);
02244         // Reset any left-over transforms
02245         glMatrixMode(GL_MODELVIEW);
02246         
02247         glLoadIdentity();
02248 
02249         //S32 screen_x, screen_y;
02250 
02251         // HACK for timecode debugging
02252         if (gSavedSettings.getBOOL("DisplayTimecode"))
02253         {
02254                 // draw timecode block
02255                 char text[256];         /* Flawfinder: ignore */
02256 
02257                 glLoadIdentity();
02258 
02259                 microsecondsToTimecodeString(gFrameTime,text);
02260                 const LLFontGL* font = gResMgr->getRes( LLFONT_SANSSERIF );
02261                 font->renderUTF8(text, 0,
02262                                                 llround((getWindowWidth()/2)-100.f),
02263                                                 llround((getWindowHeight()-60.f)),
02264                         LLColor4( 1.f, 1.f, 1.f, 1.f ),
02265                         LLFontGL::LEFT, LLFontGL::TOP);
02266         }
02267 
02268         // Draw all nested UI views.
02269         // No translation needed, this view is glued to 0,0
02270 
02271         glPushMatrix();
02272         {
02273                 // scale view by UI global scale factor and aspect ratio correction factor
02274                 glScalef(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
02275 
02276                 LLVector2 old_scale_factor = LLUI::sGLScaleFactor;
02277                 if (gCamera)
02278                 {
02279                         // apply camera zoom transform (for high res screenshots)
02280                         F32 zoom_factor = gCamera->getZoomFactor();
02281                         S16 sub_region = gCamera->getZoomSubRegion();
02282                         if (zoom_factor > 1.f)
02283                         {
02284                                 //decompose subregion number to x and y values
02285                                 int pos_y = sub_region / llceil(zoom_factor);
02286                                 int pos_x = sub_region - (pos_y*llceil(zoom_factor));
02287                                 // offset for this tile
02288                                 glTranslatef((F32)gViewerWindow->getWindowWidth() * -(F32)pos_x, 
02289                                                         (F32)gViewerWindow->getWindowHeight() * -(F32)pos_y, 
02290                                                         0.f);
02291                                 glScalef(zoom_factor, zoom_factor, 1.f);
02292                                 LLUI::sGLScaleFactor *= zoom_factor;
02293                         }
02294                 }
02295 
02296                 {
02297                         LLGLSTexture gls_texture;
02298                         drawDebugText();
02299                 }
02300                 
02301                 if (gToolMgr)
02302                 {
02303                         // Draw tool specific overlay on world
02304                         gToolMgr->getCurrentTool()->draw();
02305                 }
02306 
02307                 if( gAgent.cameraMouselook() )
02308                 {
02309                         drawMouselookInstructions();
02310                         stop_glerror();
02311                 }
02312 
02313                 // Draw all nested UI views.
02314                 // No translation needed, this view is glued to 0,0
02315                 mRootView->draw();
02316 
02317                 // Draw optional on-top-of-everyone view
02318                 LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
02319                 if (top_ctrl && top_ctrl->getVisible())
02320                 {
02321                         S32 screen_x, screen_y;
02322                         top_ctrl->localPointToScreen(0, 0, &screen_x, &screen_y);
02323 
02324                         glMatrixMode(GL_MODELVIEW);
02325                         LLUI::pushMatrix();
02326                         LLUI::translate( (F32) screen_x, (F32) screen_y, 0.f);
02327                         top_ctrl->draw();       
02328                         LLUI::popMatrix();
02329                 }
02330 
02331                 // Draw tooltips
02332                 // Adjust their rectangle so they don't go off the top or bottom
02333                 // of the screen.
02334                 if( mToolTip && mToolTip->getVisible() )
02335                 {
02336                         glMatrixMode(GL_MODELVIEW);
02337                         LLUI::pushMatrix();
02338                         {
02339                                 S32 tip_height = mToolTip->getRect().getHeight();
02340 
02341                                 S32 screen_x, screen_y;
02342                                 mToolTip->localPointToScreen(0, -24 - tip_height, 
02343                                                                                          &screen_x, &screen_y);
02344 
02345                                 // If tooltip would draw off the bottom of the screen,
02346                                 // show it from the cursor tip position.
02347                                 if (screen_y < tip_height) 
02348                                 {
02349                                         mToolTip->localPointToScreen(0, 0, &screen_x, &screen_y);
02350                                 }
02351                                 LLUI::translate( (F32) screen_x, (F32) screen_y, 0);
02352                                 mToolTip->draw();
02353                         }
02354                         LLUI::popMatrix();
02355                 }
02356 
02357                 if( gShowOverlayTitle && !mOverlayTitle.empty() )
02358                 {
02359                         // Used for special titles such as "Second Life - Special E3 2003 Beta"
02360                         const S32 DIST_FROM_TOP = 20;
02361                         LLGLSTexture gls_texture;
02362                         LLFontGL::sSansSerifBig->renderUTF8(
02363                                 mOverlayTitle, 0,
02364                                 llround( gViewerWindow->getWindowWidth() * 0.5f),
02365                                 gViewerWindow->getWindowHeight() - DIST_FROM_TOP,
02366                                 LLColor4(1, 1, 1, 0.4f),
02367                                 LLFontGL::HCENTER, LLFontGL::TOP);
02368                 }
02369 
02370                 LLUI::sGLScaleFactor = old_scale_factor;
02371         }
02372         glPopMatrix();
02373 
02374 
02375 #if LL_DEBUG
02376         LLView::sIsDrawing = FALSE;
02377 #endif
02378 }
02379 
02380 // Takes a single keydown event, usually when UI is visible
02381 BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
02382 {
02383         if (gFocusMgr.getKeyboardFocus() && !(mask &     (MASK_CONTROL | MASK_ALT)))
02384         {
02385                 // We have keyboard focus, and it's not an accelerator
02386 
02387                 if (key < 0x80)
02388                 {
02389                         // Not a special key, so likely (we hope) to generate a character.  Let it fall through to character handler first.
02390                         return gFocusMgr.childHasKeyboardFocus(mRootView);
02391                 }
02392         }
02393 
02394         // HACK look for UI editing keys
02395         if (LLView::sEditingUI)
02396         {
02397                 if (LLFloaterEditUI::handleKey(key, mask))
02398                 {
02399                         return TRUE;
02400                 }
02401         }
02402 
02403         // Hide tooltips on keypress
02404         if(mToolTip )
02405         {
02406                 mToolTipBlocked = TRUE; // block until next time mouse is moved
02407                 mToolTip->setVisible( FALSE );
02408         }
02409 
02410         // Also hide hover info on keypress
02411         if (gHoverView)
02412         {
02413                 gHoverView->cancelHover();
02414 
02415                 gHoverView->setTyping(TRUE);
02416         }
02417 
02418         // Explicit hack for debug menu.
02419         if ((MASK_ALT & mask) &&
02420                 (MASK_CONTROL & mask) &&
02421                 ('D' == key || 'd' == key))
02422         {
02423                 toggle_debug_menus(NULL);
02424         }
02425 
02426         // Example "bug" for bug reporter web page
02427         if ((MASK_SHIFT & mask) 
02428                 && (MASK_ALT & mask)
02429                 && (MASK_CONTROL & mask)
02430                 && ('H' == key || 'h' == key))
02431         {
02432                 trigger_hippo_bug(NULL);
02433         }
02434 
02435         // handle escape key
02436         if (key == KEY_ESCAPE && mask == MASK_NONE)
02437         {
02438                 if (gMenuHolder && gMenuHolder->hideMenus())
02439                 {
02440                         return TRUE;
02441                 }
02442 
02443                 // *TODO: get this to play well with mouselook and hidden
02444                 // cursor modes, etc, and re-enable.
02445                 //if (gFocusMgr.getMouseCapture())
02446                 //{
02447                 //      gFocusMgr.setMouseCapture(NULL);
02448                 //      return TRUE;
02449                 //}
02450         }
02451 
02452         // let menus handle navigation keys
02453         if (gMenuBarView && gMenuBarView->handleKey(key, mask, TRUE))
02454         {
02455                 return TRUE;
02456         }
02457 
02458         // Traverses up the hierarchy
02459         LLUICtrl* keyboard_focus = gFocusMgr.getKeyboardFocus();
02460         if( keyboard_focus )
02461         {
02462                 // arrow keys move avatar while chatting hack
02463                 if (gChatBar && gChatBar->inputEditorHasFocus())
02464                 {
02465                         if (gChatBar->getCurrentChat().empty() || gSavedSettings.getBOOL("ArrowKeysMoveAvatar"))
02466                         {
02467                                 switch(key)
02468                                 {
02469                                 case KEY_LEFT:
02470                                 case KEY_RIGHT:
02471                                 case KEY_UP:
02472                                         // let CTRL UP through for chat line history
02473                                         if( MASK_CONTROL == mask )
02474                                         {
02475                                                 break;
02476                                         }
02477                                 case KEY_DOWN:
02478                                         // let CTRL DOWN through for chat line history
02479                                         if( MASK_CONTROL == mask )
02480                                         {
02481                                                 break;
02482                                         }
02483                                 case KEY_PAGE_UP:
02484                                 case KEY_PAGE_DOWN:
02485                                 case KEY_HOME:
02486                                         // when chatbar is empty or ArrowKeysMoveAvatar set, pass arrow keys on to avatar...
02487                                         return FALSE;
02488                                 default:
02489                                         break;
02490                                 }
02491                         }
02492                 }
02493 
02494                 if (keyboard_focus->handleKey(key, mask, FALSE))
02495                 {
02496                         return TRUE;
02497                 }
02498         }
02499 
02500         if (gToolMgr)
02501         {
02502                 if( gToolMgr->getCurrentTool()->handleKey(key, mask) )
02503                 {
02504                         return TRUE;
02505                 }
02506         }
02507 
02508         // Try for a new-format gesture
02509         if (gGestureManager.triggerGesture(key, mask))
02510         {
02511                 return TRUE;
02512         }
02513 
02514         // See if this is a gesture trigger.  If so, eat the key and
02515         // don't pass it down to the menus.
02516         if (gGestureList.trigger(key, mask))
02517         {
02518                 return TRUE;
02519         }
02520 
02521         // Topmost view gets a chance before the hierarchy
02522         // *FIX: get rid of this?
02523         LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
02524         if (top_ctrl)
02525         {
02526                 if( top_ctrl->handleKey( key, mask, TRUE ) )
02527                 {
02528                         return TRUE;
02529                 }
02530         }
02531 
02532         // give floaters first chance to handle TAB key
02533         // so frontmost floater gets focus
02534         if (key == KEY_TAB)
02535         {
02536                 // if nothing has focus, go to first or last UI element as appropriate
02537                 if (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL)
02538                 {
02539                         if (gMenuHolder) gMenuHolder->hideMenus();
02540 
02541                         // if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode
02542                         gFloaterView->setCycleMode((mask & MASK_CONTROL) != 0);
02543 
02544                         // do CTRL-TAB and CTRL-SHIFT-TAB logic
02545                         if (mask & MASK_SHIFT)
02546                         {
02547                                 mRootView->focusPrevRoot();
02548                         }
02549                         else
02550                         {
02551                                 mRootView->focusNextRoot();
02552                         }
02553                         return TRUE;
02554                 }
02555         }
02556         
02557         // give menus a chance to handle keys
02558         if (gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
02559         {
02560                 return TRUE;
02561         }
02562 
02563         // don't pass keys on to world when something in ui has focus
02564         return gFocusMgr.childHasKeyboardFocus(mRootView) 
02565                 || LLMenuGL::getKeyboardMode() 
02566                 || (gMenuBarView && gMenuBarView->getHighlightedItem() && gMenuBarView->getHighlightedItem()->isActive());
02567 }
02568 
02569 
02570 BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
02571 {
02572         // HACK:  We delay processing of return keys until they arrive as a Unicode char,
02573         // so that if you're typing chat text at low frame rate, we don't send the chat
02574         // until all keystrokes have been entered. JC
02575         // HACK: Numeric keypad <enter> on Mac is Unicode 3
02576         // HACK: Control-M on Windows is Unicode 13
02577         if ((uni_char == 13 && mask != MASK_CONTROL)
02578                 || (uni_char == 3 && mask == MASK_NONE))
02579         {
02580                 return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
02581         }
02582 
02583         // let menus handle navigation (jump) keys
02584         if (gMenuBarView && gMenuBarView->handleUnicodeChar(uni_char, TRUE))
02585         {
02586                 return TRUE;
02587         }
02588 
02589         // Traverses up the hierarchy
02590         LLView* keyboard_focus = gFocusMgr.getKeyboardFocus();
02591         if( keyboard_focus )
02592         {
02593                 if (keyboard_focus->handleUnicodeChar(uni_char, FALSE))
02594                 {
02595                         return TRUE;
02596                 }
02597 
02598                 // Topmost view gets a chance before the hierarchy
02599                 LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
02600                 if (top_ctrl && top_ctrl->handleUnicodeChar( uni_char, FALSE ) )
02601                 {
02602                         return TRUE;
02603                 }
02604 
02605                 return TRUE;
02606         }
02607 
02608         return FALSE;
02609 }
02610 
02611 
02612 void LLViewerWindow::handleScrollWheel(S32 clicks)
02613 {
02614         gMouseIdleTimer.reset();
02615 
02616         // Hide tooltips
02617         if( mToolTip )
02618         {
02619                 mToolTip->setVisible( FALSE );
02620         }
02621 
02622         LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
02623         if( mouse_captor )
02624         {
02625                 S32 local_x;
02626                 S32 local_y;
02627                 mouse_captor->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
02628                 mouse_captor->handleScrollWheel(local_x, local_y, clicks);
02629                 if (LLView::sDebugMouseHandling)
02630                 {
02631                         llinfos << "Scroll Wheel handled by captor " << mouse_captor->getName() << llendl;
02632                 }
02633                 return;
02634         }
02635 
02636         LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
02637         if (top_ctrl)
02638         {
02639                 S32 local_x;
02640                 S32 local_y;
02641                 top_ctrl->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
02642                 if (top_ctrl->handleScrollWheel(local_x, local_y, clicks)) return;
02643         }
02644 
02645         if (mRootView->handleScrollWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks) )
02646         {
02647                 if (LLView::sDebugMouseHandling)
02648                 {
02649                         llinfos << "Scroll Wheel" << LLView::sMouseHandlerMessage << llendl;
02650                         LLView::sMouseHandlerMessage = "";
02651                 }
02652                 return;
02653         }
02654         else if (LLView::sDebugMouseHandling)
02655         {
02656                 llinfos << "Scroll Wheel not handled by view" << llendl;
02657         }
02658 
02659         if (gWorldPointer)
02660         {
02661                 // Zoom the camera in and out behavior
02662                 gAgent.handleScrollWheel(clicks);
02663         }
02664 
02665         return;
02666 }
02667 
02668 void LLViewerWindow::moveCursorToCenter()
02669 {
02670         S32 x = mVirtualWindowRect.getWidth() / 2;
02671         S32 y = mVirtualWindowRect.getHeight() / 2;
02672         
02673         //on a forced move, all deltas get zeroed out to prevent jumping
02674         mCurrentMousePoint.set(x,y);
02675         mLastMousePoint.set(x,y);
02676         mCurrentMouseDelta.set(0,0);    
02677 
02678         LLUI::setCursorPositionScreen(x, y);    
02679 }
02680 
02682 //
02683 // Hover handlers
02684 //
02685 
02686 // Update UI based on stored mouse position from mouse-move
02687 // event processing.
02688 BOOL LLViewerWindow::handlePerFrameHover()
02689 {
02690         static std::string last_handle_msg;
02691 
02692         //RN: fix for asynchronous notification of mouse leaving window not working
02693         LLCoordWindow mouse_pos;
02694         mWindow->getCursorPosition(&mouse_pos);
02695         if (mouse_pos.mX < 0 || 
02696                 mouse_pos.mY < 0 ||
02697                 mouse_pos.mX > mWindowRect.getWidth() ||
02698                 mouse_pos.mY > mWindowRect.getHeight())
02699         {
02700                 mMouseInWindow = FALSE;
02701         }
02702         else
02703         {
02704                 mMouseInWindow = TRUE;
02705         }
02706 
02707         S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::sGLScaleFactor.mV[VX]);
02708         S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::sGLScaleFactor.mV[VY]);
02709 
02710         LLVector2 mouse_vel; 
02711 
02712         if (gSavedSettings.getBOOL("MouseSmooth"))
02713         {
02714                 static F32 fdx = 0.f;
02715                 static F32 fdy = 0.f;
02716 
02717                 F32 amount = 16.f;
02718                 fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f);
02719                 fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f);
02720 
02721                 mCurrentMouseDelta.set(llround(fdx), llround(fdy));
02722                 mouse_vel.setVec(fdx,fdy);
02723         }
02724         else
02725         {
02726                 mCurrentMouseDelta.set(dx, dy);
02727                 mouse_vel.setVec((F32) dx, (F32) dy);
02728         }
02729     
02730         mMouseVelocityStat.addValue(mouse_vel.magVec());
02731 
02732         if (gNoRender)
02733         {
02734                 return TRUE;
02735         }
02736 
02737         S32 x = mCurrentMousePoint.mX;
02738         S32 y = mCurrentMousePoint.mY;
02739         MASK mask = gKeyboard->currentMask(TRUE);
02740 
02741         // clean up current focus
02742         LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus();
02743         if (cur_focus)
02744         {
02745                 if (!cur_focus->isInVisibleChain() || !cur_focus->isInEnabledChain())
02746                 {
02747                         gFocusMgr.releaseFocusIfNeeded(cur_focus);
02748 
02749                         LLView* parent = cur_focus->getParent();
02750                         LLView* focus_root = cur_focus->findRootMostFocusRoot();
02751                         while(parent)
02752                         {
02753                                 if (parent->isCtrl() && 
02754                                         (((LLUICtrl*)parent)->hasTabStop() || parent == focus_root) && 
02755                                         !((LLUICtrl*)parent)->getIsChrome() && 
02756                                         parent->isInVisibleChain() && 
02757                                         parent->isInEnabledChain())
02758                                 {
02759                                         if (!parent->focusFirstItem())
02760                                         {
02761                                                 ((LLUICtrl*)parent)->setFocus(TRUE);
02762                                         }
02763                                         break;
02764                                 }
02765                                 parent = parent->getParent();
02766                         }
02767                 }
02768                 else if (cur_focus->isFocusRoot())
02769                 {
02770                         // focus roots keep trying to delegate focus to their first valid descendant
02771                         // this assumes that focus roots are not valid focus holders on their own
02772                         cur_focus->focusFirstItem();
02773                 }
02774         }
02775 
02776         gPipeline.sRenderProcessBeacons = FALSE;
02777         KEY key = gKeyboard->currentKey();
02778         if (((mask & MASK_CONTROL) && ('N' == key || 'n' == key)) || gSavedSettings.getBOOL("BeaconAlwaysOn"))
02779         {
02780                 gPipeline.sRenderProcessBeacons = TRUE;
02781         }
02782 
02783         BOOL handled = FALSE;
02784 
02785         BOOL handled_by_top_ctrl = FALSE;
02786         LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
02787 
02788         LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
02789         if( mouse_captor )
02790         {
02791                 // Pass hover events to object capturing mouse events.
02792                 S32 local_x;
02793                 S32 local_y; 
02794                 mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
02795                 handled = mouse_captor->handleHover(local_x, local_y, mask);
02796                 if (LLView::sDebugMouseHandling)
02797                 {
02798                         llinfos << "Hover handled by captor " << mouse_captor->getName() << llendl;
02799                 }
02800 
02801                 if( !handled )
02802                 {
02803                         lldebugst(LLERR_USER_INPUT) << "hover not handled by mouse captor" << llendl;
02804                 }
02805         }
02806         else
02807         {
02808                 if (top_ctrl)
02809                 {
02810                         S32 local_x, local_y;
02811                         top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
02812                         handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleHover(local_x, local_y, mask);
02813                         handled_by_top_ctrl = TRUE;
02814                 }
02815 
02816                 if ( !handled )
02817                 {
02818                         // x and y are from last time mouse was in window
02819                         // mMouseInWindow tracks *actual* mouse location
02820                         if (mMouseInWindow && mRootView->handleHover(x, y, mask) )
02821                         {
02822                                 if (LLView::sDebugMouseHandling && LLView::sMouseHandlerMessage != last_handle_msg)
02823                                 {
02824                                         last_handle_msg = LLView::sMouseHandlerMessage;
02825                                         llinfos << "Hover" << LLView::sMouseHandlerMessage << llendl;
02826                                 }
02827                                 LLView::sMouseHandlerMessage = "";
02828                                 handled = TRUE;
02829                         }
02830                         else if (LLView::sDebugMouseHandling)
02831                         {
02832                                 if (last_handle_msg != "")
02833                                 {
02834                                         last_handle_msg = "";
02835                                         llinfos << "Hover not handled by view" << llendl;
02836                                 }
02837                         }
02838                 }
02839 
02840                 if( !handled )
02841                 {
02842                         lldebugst(LLERR_USER_INPUT) << "hover not handled by top view or root" << llendl;               
02843                 }
02844         }
02845 
02846         // *NOTE: sometimes tools handle the mouse as a captor, so this
02847         // logic is a little confusing
02848         LLTool *tool = NULL;
02849         if (gToolMgr && gHoverView)
02850         {
02851                 tool = gToolMgr->getCurrentTool();
02852 
02853                 if(!handled && tool)
02854                 {
02855                         handled = tool->handleHover(x, y, mask);
02856 
02857                         if (!mWindow->isCursorHidden())
02858                         {
02859                                 gHoverView->updateHover(tool);
02860                         }
02861                 }
02862                 else
02863                 {
02864                         // Cancel hovering if any UI element handled the event.
02865                         gHoverView->cancelHover();
02866                 }
02867 
02868                 // Suppress the toolbox view if our source tool was the pie tool,
02869                 // and we've overridden to something else.
02870                 mSuppressToolbox = 
02871                         (gToolMgr->getBaseTool() == gToolPie) &&
02872                         (gToolMgr->getCurrentTool() != gToolPie);
02873 
02874         }
02875 
02876         //llinfos << (mToolTipBlocked ? "BLOCKED" : "NOT BLOCKED") << llendl;
02877         // Show a new tool tip (or update one that is alrady shown)
02878         BOOL tool_tip_handled = FALSE;
02879         LLString tool_tip_msg;
02880         F32 tooltip_delay = gSavedSettings.getF32( "ToolTipDelay" );
02881         //HACK: hack for tool-based tooltips which need to pop up more quickly
02882         //Also for show xui names as tooltips debug mode
02883         if ((mouse_captor && !mouse_captor->isView()) || LLUI::sShowXUINames)
02884         {
02885                 tooltip_delay = gSavedSettings.getF32( "DragAndDropToolTipDelay" );
02886         }
02887         if( handled && 
02888                 !mToolTipBlocked &&
02889                 (gMouseIdleTimer.getElapsedTimeF32() > tooltip_delay) &&
02890                 !mWindow->isCursorHidden() )
02891         {
02892                 LLRect screen_sticky_rect;
02893 
02894                 if (mouse_captor)
02895                 {
02896                         S32 local_x, local_y;
02897                         mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
02898                         tool_tip_handled = mouse_captor->handleToolTip( local_x, local_y, tool_tip_msg, &screen_sticky_rect );
02899                 }
02900                 else if (handled_by_top_ctrl)
02901                 {
02902                         S32 local_x, local_y;
02903                         top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
02904                         tool_tip_handled = top_ctrl->handleToolTip( local_x, local_y, tool_tip_msg, &screen_sticky_rect );
02905                 }
02906                 else
02907                 {
02908                         tool_tip_handled = mRootView->handleToolTip(x, y, tool_tip_msg, &screen_sticky_rect );
02909                 }
02910 
02911                 if( tool_tip_handled && !tool_tip_msg.empty() )
02912                 {
02913                         mToolTipStickyRect = screen_sticky_rect;
02914                         mToolTip->setWrappedText( tool_tip_msg, 200 );
02915                         mToolTip->reshapeToFitText();
02916                         mToolTip->setOrigin( x, y );
02917                         LLRect virtual_window_rect(0, getWindowHeight(), getWindowWidth(), 0);
02918                         mToolTip->translateIntoRect( virtual_window_rect, FALSE );
02919                         mToolTip->setVisible( TRUE );
02920                 }
02921         }               
02922 
02923         if (tool != gToolNull  && tool != gToolInspect && tool != gToolDragAndDrop && !gSavedSettings.getBOOL("FreezeTime"))
02924         { 
02925                 LLMouseHandler *captor = gFocusMgr.getMouseCapture();
02926                 // With the null, inspect, or drag and drop tool, don't muck
02927                 // with visibility.
02928 
02929                 if (gFloaterTools->isMinimized() ||
02930                         (tool != gToolPie                                               // not default tool
02931                         && tool != gToolGun                                             // not coming out of mouselook
02932                         && !mSuppressToolbox                                    // not override in third person
02933                         && gToolMgr->getCurrentToolset() != gFaceEditToolset    // not special mode
02934                         && gToolMgr->getCurrentToolset() != gMouselookToolset
02935                         && (!captor || captor->isView())) // not dragging
02936                         )
02937                 {
02938                         // Force floater tools to be visible (unless minimized)
02939                         if (!gFloaterTools->getVisible())
02940                         {
02941                                 gFloaterTools->open();          /* Flawfinder: ignore */
02942                         }
02943                         // Update the location of the blue box tool popup
02944                         LLCoordGL select_center_screen;
02945                         gFloaterTools->updatePopup( select_center_screen, mask );
02946                 }
02947                 else
02948                 {
02949                         gFloaterTools->setVisible(FALSE);
02950                 }
02951                 // In the future we may wish to hide the tools menu unless you
02952                 // are building. JC
02953                 //gMenuBarView->setItemVisible("Tools", gFloaterTools->getVisible());
02954                 //gMenuBarView->arrange();
02955         }
02956         if (gToolBar)
02957         {
02958                 gToolBar->refresh();
02959         }
02960 
02961         if (gChatBar)
02962         {
02963                 gChatBar->refresh();
02964         }
02965 
02966         if (gOverlayBar)
02967         {
02968                 gOverlayBar->refresh();
02969         }
02970 
02971         // Update rectangles for the various toolbars
02972         if (gToolBar && gChatBar && gOverlayBar && gNotifyBoxView && gConsole)
02973         {
02974                 LLRect bar_rect(-1, STATUS_BAR_HEIGHT, getWindowWidth()+1, -1);
02975                 if (gToolBar->getVisible())
02976                 {
02977                         gToolBar->setRect(bar_rect);
02978                         bar_rect.translate(0, STATUS_BAR_HEIGHT-1);
02979                 }
02980 
02981                 if (gChatBar->getVisible())
02982                 {
02983                         // fix up the height
02984                         LLRect chat_bar_rect = bar_rect;
02985                         chat_bar_rect.mTop = chat_bar_rect.mBottom + CHAT_BAR_HEIGHT + 1;
02986                         gChatBar->setRect(chat_bar_rect);
02987                         bar_rect.translate(0, CHAT_BAR_HEIGHT-1);
02988                 }
02989 
02990                 LLRect notify_box_rect = gNotifyBoxView->getRect();
02991                 notify_box_rect.mBottom = bar_rect.mBottom;
02992                 gNotifyBoxView->reshape(notify_box_rect.getWidth(), notify_box_rect.getHeight());
02993                 gNotifyBoxView->setRect(notify_box_rect);
02994 
02995                 // make sure floaters snap to visible rect by adjusting floater view rect
02996                 LLRect floater_rect = gFloaterView->getRect();
02997                 if (floater_rect.mBottom != bar_rect.mBottom+1)
02998                 {
02999                         floater_rect.mBottom = bar_rect.mBottom+1;
03000                         // Don't bounce the floaters up and down.
03001                         gFloaterView->reshape(floater_rect.getWidth(), floater_rect.getHeight(), 
03002                                                                         TRUE, ADJUST_VERTICAL_NO);
03003                         gFloaterView->setRect(floater_rect);
03004                 }
03005 
03006                 if (gOverlayBar->getVisible())
03007                 {
03008                         LLRect overlay_rect = bar_rect;
03009                         overlay_rect.mTop = overlay_rect.mBottom + OVERLAY_BAR_HEIGHT;
03010 
03011                         // Fitt's Law: Push buttons flush with bottom of screen if
03012                         // nothing else visible.
03013                         if (!gToolBar->getVisible()
03014                                 && !gChatBar->getVisible())
03015                         {
03016                                 // *NOTE: this is highly depenent on the XML
03017                                 // describing the position of the buttons
03018                                 overlay_rect.translate(0, 0);
03019                         }
03020 
03021                         gOverlayBar->setRect(overlay_rect);
03022                         gOverlayBar->updateRect();
03023                         bar_rect.translate(0, gOverlayBar->getRect().getHeight());
03024 
03025                         gFloaterView->setSnapOffsetBottom(OVERLAY_BAR_HEIGHT);
03026                 }
03027                 else
03028                 {
03029                         gFloaterView->setSnapOffsetBottom(0);
03030                 }
03031 
03032                 // fix rectangle of bottom panel focus indicator
03033                 if(gBottomPanel && gBottomPanel->getFocusIndicator())
03034                 {
03035                         LLRect focus_rect = gBottomPanel->getFocusIndicator()->getRect();
03036                         focus_rect.mTop = (gToolBar->getVisible() ? STATUS_BAR_HEIGHT : 0) + 
03037                                 (gChatBar->getVisible() ? CHAT_BAR_HEIGHT : 0) - 2;
03038                         gBottomPanel->getFocusIndicator()->setRect(focus_rect);
03039                 }
03040 
03041                 // Always update console
03042                 LLRect console_rect = gConsole->getRect();
03043                 console_rect.mBottom = bar_rect.mBottom + 8;
03044                 gConsole->reshape(console_rect.getWidth(), console_rect.getHeight());
03045                 gConsole->setRect(console_rect);
03046         }
03047 
03048         mLastMousePoint = mCurrentMousePoint;
03049 
03050         // last ditch force of edit menu to selection manager
03051         if (gEditMenuHandler == NULL && gSelectMgr && gSelectMgr->getSelection()->getObjectCount())
03052         {
03053                 gEditMenuHandler = gSelectMgr;
03054         }
03055 
03056         if (gFloaterView->getCycleMode())
03057         {
03058                 // sync all floaters with their focus state
03059                 gFloaterView->highlightFocusedFloater();
03060                 gSnapshotFloaterView->highlightFocusedFloater();
03061                 if ((gKeyboard->currentMask(TRUE) & MASK_CONTROL) == 0)
03062                 {
03063                         // control key no longer held down, finish cycle mode
03064                         gFloaterView->setCycleMode(FALSE);
03065 
03066                         gFloaterView->syncFloaterTabOrder();
03067                 }
03068                 else
03069                 {
03070                         // user holding down CTRL, don't update tab order of floaters
03071                 }
03072         }
03073         else
03074         {
03075                 // update focused floater
03076                 gFloaterView->highlightFocusedFloater();
03077                 gSnapshotFloaterView->highlightFocusedFloater();
03078                 // make sure floater visible order is in sync with tab order
03079                 gFloaterView->syncFloaterTabOrder();
03080         }
03081 
03082         if (gSavedSettings.getBOOL("ChatBarStealsFocus") && gChatBar && gFocusMgr.getKeyboardFocus() == NULL && gChatBar->getVisible())
03083         {
03084                 gChatBar->startChat(NULL);
03085         }
03086 
03087         // cleanup unused selections when no modal dialogs are open
03088         if (gParcelMgr && LLModalDialog::activeCount() == 0)
03089         {
03090                 gParcelMgr->deselectUnused();
03091         }
03092 
03093         if (gSelectMgr && LLModalDialog::activeCount() == 0)
03094         {
03095                 gSelectMgr->deselectUnused();
03096         }
03097 
03098         return handled;
03099 }
03100 
03101 
03102 void LLViewerWindow::saveLastMouse(const LLCoordGL &point)
03103 {
03104         // Store last mouse location.
03105         // If mouse leaves window, pretend last point was on edge of window
03106         if (point.mX < 0)
03107         {
03108                 mCurrentMousePoint.mX = 0;
03109         }
03110         else if (point.mX > getWindowWidth())
03111         {
03112                 mCurrentMousePoint.mX = getWindowWidth();
03113         }
03114         else
03115         {
03116                 mCurrentMousePoint.mX = point.mX;
03117         }
03118 
03119         if (point.mY < 0)
03120         {
03121                 mCurrentMousePoint.mY = 0;
03122         }
03123         else if (point.mY > getWindowHeight() )
03124         {
03125                 mCurrentMousePoint.mY = getWindowHeight();
03126         }
03127         else
03128         {
03129                 mCurrentMousePoint.mY = point.mY;
03130         }
03131 }
03132 
03133 
03134 // Draws the selection outlines for the currently selected objects
03135 // Must be called after displayObjects is called, which sets the mGLName parameter
03136 // NOTE: This function gets called 3 times:
03137 //  render_ui_3d:                       FALSE, FALSE, TRUE
03138 //  renderObjectsForSelect:     TRUE, pick_parcel_wall, FALSE
03139 //  render_hud_elements:        FALSE, FALSE, FALSE
03140 void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, BOOL for_hud )
03141 {
03142         LLObjectSelectionHandle selection = gSelectMgr->getSelection();
03143 
03144         if (!for_hud && !for_gl_pick)
03145         {
03146                 // Call this once and only once
03147                 gSelectMgr->updateSilhouettes();
03148         }
03149         
03150         // Draw fence around land selections
03151         if (for_gl_pick)
03152         {
03153                 if (pick_parcel_walls)
03154                 {
03155                         gParcelMgr->renderParcelCollision();
03156                 }
03157         }
03158         else if (( for_hud && selection->getSelectType() == SELECT_TYPE_HUD) ||
03159                          (!for_hud && selection->getSelectType() != SELECT_TYPE_HUD))
03160         {               
03161                 gSelectMgr->renderSilhouettes(for_hud);
03162                 
03163                 stop_glerror();
03164 
03165                 // setup HUD render
03166                 if (selection->getSelectType() == SELECT_TYPE_HUD && gSelectMgr->getSelection()->getObjectCount())
03167                 {
03168                         LLBBox hud_bbox = gAgent.getAvatarObject()->getHUDBBox();
03169 
03170                         // set up transform to encompass bounding box of HUD
03171                         glMatrixMode(GL_PROJECTION);
03172                         glPushMatrix();
03173                         glLoadIdentity();
03174                         F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
03175                         glOrtho(-0.5f * gCamera->getAspect(), 0.5f * gCamera->getAspect(), -0.5f, 0.5f, 0.f, depth);
03176                         
03177                         glMatrixMode(GL_MODELVIEW);
03178                         glPushMatrix();
03179                         glLoadIdentity();
03180                         glLoadMatrixf(OGL_TO_CFR_ROTATION);             // Load Cory's favorite reference frame
03181                         glTranslatef(-hud_bbox.getCenterLocal().mV[VX] + (depth *0.5f), 0.f, 0.f);
03182                 }
03183 
03184                 // Render light for editing
03185                 if (LLSelectMgr::sRenderLightRadius)
03186                 {
03187                         LLGLEnable gls_blend(GL_BLEND);
03188                         LLGLEnable gls_cull(GL_CULL_FACE);
03189                         LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
03190                         glMatrixMode(GL_MODELVIEW);
03191                         glPushMatrix();
03192                         if (selection->getSelectType() == SELECT_TYPE_HUD)
03193                         {
03194                                 F32 zoom = gAgent.getAvatarObject()->mHUDCurZoom;
03195                                 glScalef(zoom, zoom, zoom);
03196                         }
03197 
03198                         struct f : public LLSelectedObjectFunctor
03199                         {
03200                                 virtual bool apply(LLViewerObject* object)
03201                                 {
03202                                         LLDrawable* drawable = object->mDrawable;
03203                                         if (drawable && drawable->isLight())
03204                                         {
03205                                                 LLVOVolume* vovolume = drawable->getVOVolume();
03206                                                 glPushMatrix();
03207 
03208                                                 LLVector3 center = drawable->getPositionAgent();
03209                                                 glTranslatef(center[0], center[1], center[2]);
03210                                                 F32 scale = vovolume->getLightRadius();
03211                                                 glScalef(scale, scale, scale);
03212 
03213                                                 LLColor4 color(vovolume->getLightColor(), .5f);
03214                                                 glColor4fv(color.mV);
03215                                         
03216                                                 F32 pixel_area = 100000.f;
03217                                                 // Render Outside
03218                                                 gSphere.render(pixel_area);
03219 
03220                                                 // Render Inside
03221                                                 glCullFace(GL_FRONT);
03222                                                 gSphere.render(pixel_area);
03223                                                 glCullFace(GL_BACK);
03224                                         
03225                                                 glPopMatrix();
03226                                         }
03227                                         return true;
03228                                 }
03229                         } func;
03230                         gSelectMgr->getSelection()->applyToObjects(&func);
03231                         
03232                         glPopMatrix();
03233                 }                               
03234                 
03235                 // NOTE: The average position for the axis arrows of the selected objects should
03236                 // not be recalculated at this time.  If they are, then group rotations will break.
03237 
03238                 // Draw arrows at average center of all selected objects
03239                 LLTool* tool = gToolMgr->getCurrentTool();
03240                 if (tool)
03241                 {
03242                         if(tool->isAlwaysRendered())
03243                         {
03244                                 tool->render();
03245                         }
03246                         else
03247                         {
03248                                 if( !gSelectMgr->getSelection()->isEmpty() )
03249                                 {
03250                                         BOOL moveable_object_selected = FALSE;
03251                                         BOOL all_selected_objects_move = TRUE;
03252                                         BOOL all_selected_objects_modify = TRUE;
03253                                         BOOL selecting_linked_set = !gSavedSettings.getBOOL("EditLinkedParts");
03254 
03255                                         for (LLObjectSelection::iterator iter = gSelectMgr->getSelection()->begin();
03256                                                  iter != gSelectMgr->getSelection()->end(); iter++)
03257                                         {
03258                                                 LLSelectNode* nodep = *iter;
03259                                                 LLViewerObject* object = nodep->getObject();
03260                                                 BOOL this_object_movable = FALSE;
03261                                                 if (object->permMove() && (object->permModify() || selecting_linked_set))
03262                                                 {
03263                                                         moveable_object_selected = TRUE;
03264                                                         this_object_movable = TRUE;
03265                                                 }
03266                                                 all_selected_objects_move = all_selected_objects_move && this_object_movable;
03267                                                 all_selected_objects_modify = all_selected_objects_modify && object->permModify();
03268                                         }
03269 
03270                                         BOOL draw_handles = TRUE;
03271 
03272                                         if (tool == gToolTranslate && (!moveable_object_selected || !all_selected_objects_move))
03273                                         {
03274                                                 draw_handles = FALSE;
03275                                         }
03276 
03277                                         if (tool == gToolRotate && (!moveable_object_selected || !all_selected_objects_move))
03278                                         {
03279                                                 draw_handles = FALSE;
03280                                         }
03281 
03282                                         if ( !all_selected_objects_modify && tool == gToolStretch )
03283                                         {
03284                                                 draw_handles = FALSE;
03285                                         }
03286                                 
03287                                         if( draw_handles )
03288                                         {
03289                                                 tool->render();
03290                                         }
03291                                 }
03292                         }
03293                         if (selection->getSelectType() == SELECT_TYPE_HUD && selection->getObjectCount())
03294                         {
03295                                 glMatrixMode(GL_PROJECTION);
03296                                 glPopMatrix();
03297 
03298                                 glMatrixMode(GL_MODELVIEW);
03299                                 glPopMatrix();
03300                                 stop_glerror();
03301                         }
03302                 }
03303         }
03304 }
03305 
03306 // Return a point near the clicked object representative of the place the object was clicked.
03307 LLVector3d LLViewerWindow::clickPointInWorldGlobal(S32 x, S32 y_from_bot, LLViewerObject* clicked_object) const
03308 {
03309         // create a normalized vector pointing from the camera center into the 
03310         // world at the location of the mouse click
03311         LLVector3 mouse_direction_global = mouseDirectionGlobal( x, y_from_bot );
03312 
03313         LLVector3d relative_object = clicked_object->getPositionGlobal() - gAgent.getCameraPositionGlobal();
03314 
03315         // make mouse vector as long as object vector, so it touchs a point near
03316         // where the user clicked on the object
03317         mouse_direction_global *= (F32) relative_object.magVec();
03318 
03319         LLVector3d new_pos;
03320         new_pos.setVec(mouse_direction_global);
03321         // transform mouse vector back to world coords
03322         new_pos += gAgent.getCameraPositionGlobal();
03323 
03324         return new_pos;
03325 }
03326 
03327 
03328 BOOL LLViewerWindow::clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewerObject *objectp, LLVector3d &point_global) const
03329 {
03330         BOOL intersect = FALSE;
03331 
03332 //      U8 shape = objectp->mPrimitiveCode & LL_PCODE_BASE_MASK;
03333         if (!intersect)
03334         {
03335                 point_global = clickPointInWorldGlobal(x, y, objectp);
03336                 llinfos << "approx intersection at " <<  (objectp->getPositionGlobal() - point_global) << llendl;
03337         }
03338         else
03339         {
03340                 llinfos << "good intersection at " <<  (objectp->getPositionGlobal() - point_global) << llendl;
03341         }
03342 
03343         return intersect;
03344 }
03345 
03346 void 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)
03347 {
03348         if (gNoRender)
03349         {
03350                 return;
03351         }
03352 
03353         S32 scaled_x = llround((F32)x * mDisplayScale.mV[VX]);
03354         S32 scaled_y = llround((F32)y_from_bot * mDisplayScale.mV[VY]);
03355 
03356         BOOL in_build_mode = gFloaterTools && gFloaterTools->getVisible();
03357         if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha)
03358         {
03359                 // build mode allows interaction with all transparent objects
03360                 // "Show Debug Alpha" means no object actually transparent
03361                 pick_transparent = TRUE;
03362         }
03363         gPickTransparent = pick_transparent;
03364 
03365         gUseGLPick = FALSE;
03366         mPickCallback = callback;
03367 
03368         // Default to not hitting anything
03369         gLastHitPosGlobal.zeroVec();
03370         gLastHitObjectOffset.zeroVec();
03371         gLastHitObjectID.setNull();
03372         gLastHitObjectFace = -1;
03373 
03374         gLastHitNonFloraPosGlobal.zeroVec();
03375         gLastHitNonFloraObjectOffset.zeroVec();
03376         gLastHitNonFloraObjectID.setNull();
03377         gLastHitNonFloraObjectFace = -1;
03378 
03379         gLastHitParcelWall = FALSE;
03380 
03381         LLCamera pick_camera;
03382         pick_camera.setOrigin(gCamera->getOrigin());
03383         pick_camera.setOriginAndLookAt(gCamera->getOrigin(),
03384                                                                    gCamera->getUpAxis(),
03385                                                                    gCamera->getOrigin() + mouseDirectionGlobal(x, y_from_bot));
03386         pick_camera.setView(0.5f*DEG_TO_RAD);
03387         pick_camera.setNear(gCamera->getNear());
03388         pick_camera.setFar(gCamera->getFar());
03389         pick_camera.setAspect(1.f);
03390 
03391         // save our drawing state
03392         glMatrixMode(GL_MODELVIEW);
03393         glPushMatrix();
03394         glLoadIdentity();
03395         
03396         glMatrixMode(GL_PROJECTION);
03397         glPushMatrix();
03398         glLoadIdentity();
03399 
03400         // build perspective transform and picking viewport
03401         // Perform pick on a PICK_DIAMETER x PICK_DIAMETER pixel region around cursor point.
03402         // Don't limit the select distance for this pick.
03403         // make viewport big enough to handle antialiased frame buffers
03404         gCamera->setPerspective(FOR_SELECTION, scaled_x - (PICK_HALF_WIDTH + 2), scaled_y - (PICK_HALF_WIDTH + 2), PICK_DIAMETER + 4, PICK_DIAMETER + 4, FALSE);
03405         pick_camera.calcAgentFrustumPlanes(gCamera->mAgentFrustum);
03406         // make viewport big enough to handle antialiased frame buffers
03407         glViewport(scaled_x - (PICK_HALF_WIDTH + 2), scaled_y - (PICK_HALF_WIDTH + 2), PICK_DIAMETER + 4, PICK_DIAMETER + 4);
03408         stop_glerror();
03409 
03410         glClearColor(0.f, 0.f, 0.f, 0.f);
03411         glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
03412 
03413         // Draw the objects so the user can select them.
03414         // The starting ID is 1, since land is zero.
03415         gObjectList.renderObjectsForSelect(pick_camera, pick_parcel_walls);
03416 
03417         stop_glerror();
03418 
03419         // restore drawing state
03420         glMatrixMode(GL_PROJECTION);
03421         glPopMatrix();
03422         glMatrixMode(GL_MODELVIEW);
03423         glPopMatrix();
03424 
03425         setupViewport();
03426 
03427         mPickPoint.set(x, y_from_bot);
03428         mPickOffset.set(0, 0);
03429         mPickMask = mask;
03430         mPickPending = TRUE;
03431 
03432         // delay further event processing until we receive results of pick
03433         mWindow->delayInputProcessing();
03434 }
03435 
03436 void LLViewerWindow::hitUIElementImmediate(S32 x, S32 y, void (*callback)(S32 x, S32 y, MASK mask))
03437 {
03438         // Performs the GL UI pick.
03439         // Stores its results in global, gLastHitUIElement
03440         if (gNoRender)
03441         {
03442                 return;
03443         }
03444         
03445         hitUIElementAsync(x, y, gKeyboard->currentMask(TRUE), NULL);
03446         performPick();
03447         if (callback)
03448         {
03449                 callback(x, y, gKeyboard->currentMask(TRUE));
03450         }
03451 }
03452 
03453 //RN: this currently doesn't do anything
03454 void LLViewerWindow::hitUIElementAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(S32 x, S32 y, MASK mask))
03455 {
03456         if (gNoRender)
03457         {
03458                 return;
03459         }
03460 
03461 //      F32 delta_time = gAlphaFadeTimer.getElapsedTimeAndResetF32();
03462 
03463         gUseGLPick = FALSE;
03464         mPickCallback = callback;
03465 
03466         // Default to not hitting anything
03467         gLastHitUIElement = 0;
03468 
03469         LLCamera pick_camera;
03470         pick_camera.setOrigin(gCamera->getOrigin());
03471         pick_camera.setOriginAndLookAt(gCamera->getOrigin(),
03472                                                                    gCamera->getUpAxis(),
03473                                                                    gCamera->getOrigin() + mouseDirectionGlobal(x, y_from_bot));
03474         pick_camera.setView(0.5f*DEG_TO_RAD);
03475         pick_camera.setNear(gCamera->getNear());
03476         pick_camera.setFar(gCamera->getFar());
03477         pick_camera.setAspect(1.f);
03478 
03479         // save our drawing state
03480         glMatrixMode(GL_MODELVIEW);
03481         glPushMatrix();
03482         glLoadIdentity();
03483         
03484         glMatrixMode(GL_PROJECTION);
03485         glPushMatrix();
03486         glLoadIdentity();
03487 
03488         // build orthogonal transform and picking viewport
03489         // Perform pick on a PICK_DIAMETER x PICK_DIAMETER pixel region around cursor point.
03490         // Don't limit the select distance for this pick.
03491         gViewerWindow->setup2DRender();
03492         const LLVector2& display_scale = gViewerWindow->getDisplayScale();
03493         glScalef(display_scale.mV[VX], display_scale.mV[VY], 1.f);
03494 
03495         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03496 
03497         // make viewport big enough to handle antialiased frame buffers
03498         glViewport(x - (PICK_HALF_WIDTH + 2), y_from_bot - (PICK_HALF_WIDTH + 2), PICK_DIAMETER + 4, PICK_DIAMETER + 4);
03499         stop_glerror();
03500 
03501         glClearColor(0.f, 0.f, 0.f, 0.f);
03502         glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
03503 
03504         // Draw the objects so the user can select them.
03505         // The starting ID is 1, since land is zero.
03506         //gViewerWindow->drawForSelect();
03507 
03508         stop_glerror();
03509 
03510         // restore drawing state
03511         glMatrixMode(GL_PROJECTION);
03512         glPopMatrix();
03513         glMatrixMode(GL_MODELVIEW);
03514         glPopMatrix();
03515 
03516         setupViewport();
03517 
03518         mPickPoint.set(x, y_from_bot);
03519         mPickOffset.set(0, 0);
03520         mPickMask = mask;
03521         mPickPending = TRUE;
03522 }
03523 
03524 void LLViewerWindow::performPick()
03525 {
03526         if (gNoRender || !mPickPending)
03527         {
03528                 return;
03529         }
03530 
03531         mPickPending = FALSE;
03532         U32     te_offset = NO_FACE;
03533         
03534         // find pick region that is fully onscreen
03535         LLCoordGL scaled_pick_point = mPickPoint;
03536         scaled_pick_point.mX = llclamp(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX]), PICK_HALF_WIDTH, gViewerWindow->getWindowDisplayWidth() - PICK_HALF_WIDTH);
03537         scaled_pick_point.mY = llclamp(llround((F32)mPickPoint.mY * mDisplayScale.mV[VY]), PICK_HALF_WIDTH, gViewerWindow->getWindowDisplayHeight() - PICK_HALF_WIDTH);
03538 
03539         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);
03540 
03541         S32 pixel_index = PICK_HALF_WIDTH * PICK_DIAMETER + PICK_HALF_WIDTH;
03542         S32 name = (U32)mPickBuffer[(pixel_index * 4) + 0] << 16 | (U32)mPickBuffer[(pixel_index * 4) + 1] << 8 | (U32)mPickBuffer[(pixel_index * 4) + 2];
03543         gLastPickAlpha = mPickBuffer[(pixel_index * 4) + 3];
03544 
03545         if (name >= (S32)GL_NAME_UI_RESERVED && name < (S32)GL_NAME_INDEX_OFFSET)
03546         {
03547                 // hit a UI element
03548                 gLastHitUIElement = name;
03549                 if (mPickCallback)
03550                 {
03551                         mPickCallback(mPickPoint.mX, mPickPoint.mY, mPickMask);
03552                 }
03553         }
03554 
03555         //imdebug("rgba rbga=bbba b=8 w=%d h=%d %p", PICK_DIAMETER, PICK_DIAMETER, mPickBuffer);
03556 
03557         S32 x_offset = mPickPoint.mX - llround((F32)scaled_pick_point.mX / mDisplayScale.mV[VX]);
03558         S32 y_offset = mPickPoint.mY - llround((F32)scaled_pick_point.mY / mDisplayScale.mV[VY]);
03559 
03560         
03561         // we hit nothing, scan surrounding pixels for something useful
03562         if (!name)
03563         {
03564                 S32 closest_distance = 10000;
03565                 //S32 closest_pick_name = 0;
03566                 for (S32 col = 0; col < PICK_DIAMETER; col++)
03567                 {
03568                         for (S32 row = 0; row < PICK_DIAMETER; row++)
03569                         {
03570                                 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));
03571                                 pixel_index = row * PICK_DIAMETER + col;
03572                                 S32 test_name = (U32)mPickBuffer[(pixel_index * 4) + 0] << 16 | (U32)mPickBuffer[(pixel_index * 4) + 1] << 8 | (U32)mPickBuffer[(pixel_index * 4) + 2];
03573                                 gLastPickAlpha = mPickBuffer[(pixel_index * 4) + 3];
03574                                 if (test_name && distance_squared < closest_distance)
03575                                 {
03576                                         closest_distance = distance_squared;
03577                                         name = test_name;
03578                                         gLastPickAlpha = mPickBuffer[(pixel_index * 4) + 3];
03579                                         mPickOffset.mX = col - PICK_HALF_WIDTH;
03580                                         mPickOffset.mY = row - PICK_HALF_WIDTH;
03581                                 }
03582                         }
03583                 }
03584         }
03585 
03586         if (name)
03587         {
03588                 mPickPoint.mX += llround((F32)mPickOffset.mX * mDisplayScale.mV[VX]);
03589                 mPickPoint.mY += llround((F32)mPickOffset.mY * mDisplayScale.mV[VY]);
03590         }
03591 
03592         if (gPickFaces)
03593         {
03594                 te_offset = ((U32)name >> 20);
03595                 name &= 0x000fffff;
03596                 // don't clear gPickFaces, as we still need to check for UV coordinates
03597         }
03598 
03599         LLViewerObject  *objectp = NULL;
03600 
03601         // Frontmost non-foreground object that isn't trees or grass
03602         LLViewerObject* nonflora_objectp = NULL;
03603         S32 nonflora_name = -1;
03604         S32 nonflora_te_offset = NO_FACE;
03605 
03606         if (name == (S32)GL_NAME_PARCEL_WALL)
03607         {
03608                 gLastHitParcelWall = TRUE;
03609         }
03610 
03611         gLastHitHUDIcon = NULL;
03612 
03613         objectp = gObjectList.getSelectedObject(name);
03614         if (objectp)
03615         {
03616                 LLViewerObject* parent = (LLViewerObject*)(objectp->getParent());
03617                 if (NULL == parent) {
03618                         // if you are the parent
03619                         parent = objectp;
03620                 }
03621                 std::vector<LLPointer<LLViewerObject>,std::allocator<LLPointer<LLViewerObject> > > children = parent->getChildren();
03622                 for( std::vector<LLPointer<LLViewerObject>,std::allocator<LLPointer<LLViewerObject> > >::iterator i= children.begin(); i!= children.end(); ++i )
03623                 {
03624                         //go through
03625                         LLViewerObject* foo = *i;
03626                         foo->getRotation();
03627                 }
03628                 if (objectp->mbCanSelect)
03629                 {
03630                         te_offset = (te_offset == 16) ? NO_FACE : te_offset;
03631 
03632                         // If the hit object isn't a plant, store it as the frontmost non-flora object.
03633                         LLPCode pcode = objectp->getPCode();
03634                         if( (LL_PCODE_LEGACY_GRASS != pcode) &&
03635                                 (LL_PCODE_LEGACY_TREE != pcode) &&
03636                                 (LL_PCODE_TREE_NEW != pcode))
03637                         {
03638                                 nonflora_objectp = objectp;
03639                                 nonflora_name = name;
03640                                 nonflora_te_offset = te_offset;
03641                         }
03642                 }
03643                 else
03644                 {
03645                         //llinfos << "Hit object you can't select" << llendl;
03646                 }
03647         }
03648         else
03649         {
03650                 // was this name referring to a hud icon?
03651                 gLastHitHUDIcon = LLHUDIcon::handlePick(name);
03652         }
03653 
03654         analyzeHit( 
03655                 mPickPoint.mX, mPickPoint.mY, objectp, te_offset,
03656                 &gLastHitObjectID, &gLastHitObjectFace, &gLastHitPosGlobal, &gLastHitLand, &gLastHitUCoord, &gLastHitVCoord );
03657 
03658         if (objectp && !gLastHitObjectID.isNull())
03659         {
03660                 gLastHitObjectOffset = gAgent.calcFocusOffset(objectp, mPickPoint.mX, mPickPoint.mY);
03661         }
03662 
03663         if( objectp == nonflora_objectp )
03664         {
03665                 gLastHitNonFloraObjectID        = gLastHitObjectID;
03666                 gLastHitNonFloraObjectFace      = gLastHitObjectFace;
03667                 gLastHitNonFloraPosGlobal       = gLastHitPosGlobal;
03668                 gLastHitNonFloraObjectOffset= gLastHitObjectOffset;
03669         }
03670         else
03671         {
03672                 analyzeHit(  mPickPoint.mX, mPickPoint.mY, nonflora_objectp, nonflora_te_offset,
03673                         &gLastHitNonFloraObjectID, &gLastHitNonFloraObjectFace, &gLastHitNonFloraPosGlobal,
03674                         &gLastHitLand, &gLastHitUCoord, &gLastHitVCoord);
03675 
03676                 if( nonflora_objectp )
03677                 {
03678                         gLastHitNonFloraObjectOffset = gAgent.calcFocusOffset(nonflora_objectp, mPickPoint.mX, mPickPoint.mY);
03679                 }
03680         }
03681 
03682         if (mPickCallback)
03683         {
03684                 mPickCallback(mPickPoint.mX, mPickPoint.mY, mPickMask);
03685         }
03686 
03687         gPickFaces = FALSE;
03688 }
03689 
03690 // Performs the GL object/land pick.
03691 // Stores its results in globals, gHit*
03692 void LLViewerWindow::hitObjectOrLandGlobalImmediate(S32 x, S32 y_from_bot, void (*callback)(S32 x, S32 y, MASK mask), BOOL pick_transparent)
03693 {
03694         if (gNoRender)
03695         {
03696                 return;
03697         }
03698         
03699         hitObjectOrLandGlobalAsync(x, y_from_bot, gKeyboard->currentMask(TRUE), NULL, pick_transparent);
03700         performPick();
03701         if (callback)
03702         {
03703                 callback(x, y_from_bot, gKeyboard->currentMask(TRUE));
03704         }
03705 }
03706 
03707 LLViewerObject* LLViewerWindow::getObjectUnderCursor(const F32 depth)
03708 {
03709         S32 x = getCurrentMouseX();
03710         S32 y = getCurrentMouseY();
03711         
03712         LLVector3               mouse_direction_global = mouseDirectionGlobal(x,y);
03713         LLVector3               camera_pos_global = gCamera->getOrigin();
03714         LLVector3               pick_end = camera_pos_global + mouse_direction_global * depth;
03715         LLVector3               collision_point;
03716         return gPipeline.pickObject(camera_pos_global, pick_end, collision_point);
03717 }
03718 
03719 void LLViewerWindow::analyzeHit(
03720         S32                             x,                              // input
03721         S32                             y_from_bot,             // input
03722         LLViewerObject* objectp,                // input
03723         U32                             te_offset,              // input
03724         LLUUID*                 hit_object_id_p,// output
03725         S32*                    hit_face_p,             // output
03726         LLVector3d*             hit_pos_p,              // output
03727         BOOL*                   hit_land,               // output
03728         F32*                    hit_u_coord,    // output
03729         F32*                    hit_v_coord)    // output
03730 {
03731         // Clean up inputs
03732         S32 face = -1;
03733         
03734         if (te_offset != NO_FACE ) 
03735         {
03736                 face = te_offset;
03737         }
03738 
03739         *hit_land = FALSE;
03740 
03741         if (objectp)
03742         {
03743                 if( objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH )
03744                 {
03745                         // Hit land
03746                         *hit_land = TRUE;
03747 
03748                         // put global position into land_pos
03749                         LLVector3d land_pos;
03750                         if (mousePointOnLandGlobal(x, y_from_bot, &land_pos))
03751                         {
03752                                 *hit_object_id_p = LLUUID::null;
03753                                 *hit_face_p = -1;
03754 
03755                                 // Fudge the land focus a little bit above ground.
03756                                 *hit_pos_p = land_pos + LLVector3d(0.f, 0.f, 0.1f);
03757                                 //llinfos << "DEBUG Hit Land " << *hit_pos_p  << llendl;
03758                                 return;
03759                         }
03760                         else
03761                         {
03762                                 //llinfos << "Hit land but couldn't find position" << llendl;
03763                                 // Fall through to "Didn't hit anything"
03764                         }
03765                 }
03766                 else
03767                 {
03768                         *hit_object_id_p = objectp->mID;
03769                         *hit_face_p = face;
03770 
03771                         // Hit an object
03772                         if (objectp->isAvatar())
03773                         {
03774                                 *hit_pos_p = gAgent.getPosGlobalFromAgent(((LLVOAvatar*)objectp)->mPelvisp->getWorldPosition());
03775                         }
03776                         else if (objectp->mDrawable.notNull())
03777                         {
03778                                 *hit_pos_p = gAgent.getPosGlobalFromAgent(objectp->getRenderPosition());
03779                         }
03780                         else
03781                         {
03782                                 // regular object
03783                                 *hit_pos_p = objectp->getPositionGlobal();
03784                         }
03785 
03786                         if (gPickFaces && face > -1 &&
03787                                 objectp->mDrawable.notNull() && objectp->getPCode() == LL_PCODE_VOLUME &&
03788                                 face < objectp->mDrawable->getNumFaces())
03789                         {
03790                                 // render red-blue gradient to get 1/256 precision
03791                                 // then render green grid to get final 1/4096 precision
03792                                 S32 scaled_x = llround((F32)x * mDisplayScale.mV[VX]);
03793                                 S32 scaled_y = llround((F32)y_from_bot * mDisplayScale.mV[VY]);
03794                                 const S32 UV_PICK_WIDTH = 41;
03795                                 const S32 UV_PICK_HALF_WIDTH = (UV_PICK_WIDTH - 1) / 2;
03796                                 U8 uv_pick_buffer[UV_PICK_WIDTH * UV_PICK_WIDTH * 4];
03797                                 S32 pick_face = face;
03798                                 LLFace* facep = objectp->mDrawable->getFace(pick_face);
03799                                 gCamera->setPerspective(FOR_SELECTION, scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, FALSE);
03800                                 glViewport(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH);
03801                                 gPipeline.renderFaceForUVSelect(facep);
03802 
03803                                 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);
03804                                 U8* center_pixel = &uv_pick_buffer[4 * ((UV_PICK_WIDTH * UV_PICK_HALF_WIDTH) + UV_PICK_HALF_WIDTH + 1)];
03805                                 *hit_u_coord = (F32)((center_pixel[VGREEN] & 0xf) + (16.f * center_pixel[VRED])) / 4095.f;
03806                                 *hit_v_coord = (F32)((center_pixel[VGREEN] >> 4) + (16.f * center_pixel[VBLUE])) / 4095.f;
03807                         }
03808                         else
03809                         {
03810                                 *hit_u_coord = 0.f;
03811                                 *hit_v_coord = 0.f;
03812                         }
03813 
03814                         //llinfos << "DEBUG Hit Object " << *hit_pos_p << llendl;
03815                         return;
03816                 }
03817         }
03818 
03819         // Didn't hit anything.
03820         *hit_object_id_p = LLUUID::null;
03821         *hit_face_p = -1;
03822         *hit_pos_p = LLVector3d::zero;
03823         *hit_u_coord = 0.f;
03824         *hit_v_coord = 0.f;
03825         //llinfos << "DEBUG Hit Nothing " << llendl;
03826 }
03827 
03828 // Returns unit vector relative to camera
03829 // indicating direction of point on screen x,y
03830 LLVector3 LLViewerWindow::mouseDirectionGlobal(const S32 x, const S32 y) const
03831 {
03832         // find vertical field of view
03833         F32                     fov = gCamera->getView();
03834 
03835         // find screen resolution
03836         S32                     height = getWindowHeight();
03837         S32                     width = getWindowWidth();
03838 
03839         // calculate pixel distance to screen
03840         F32                     distance = (height / 2.f) / (tan(fov / 2.f));
03841 
03842         // calculate click point relative to middle of screen
03843         F32                     click_x = x - width / 2.f;
03844         F32                     click_y = y - height / 2.f;
03845 
03846         // compute mouse vector
03847         LLVector3       mouse_vector =  distance * gCamera->getAtAxis()
03848                                                                 - click_x * gCamera->getLeftAxis()
03849                                                                 + click_y * gCamera->getUpAxis();
03850 
03851         mouse_vector.normVec();
03852 
03853         return mouse_vector;
03854 }
03855 
03856 
03857 // Returns unit vector relative to camera in camera space
03858 // indicating direction of point on screen x,y
03859 LLVector3 LLViewerWindow::mouseDirectionCamera(const S32 x, const S32 y) const
03860 {
03861         // find vertical field of view
03862         F32                     fov_height = gCamera->getView();
03863         F32                     fov_width = fov_height * gCamera->getAspect();
03864 
03865         // find screen resolution
03866         S32                     height = getWindowHeight();
03867         S32                     width = getWindowWidth();
03868 
03869         // calculate click point relative to middle of screen
03870         F32                     click_x = (((F32)x / (F32)width) - 0.5f) * fov_width * -1.f;
03871         F32                     click_y = (((F32)y / (F32)height) - 0.5f) * fov_height;
03872 
03873         // compute mouse vector
03874         LLVector3       mouse_vector =  LLVector3(0.f, 0.f, -1.f);
03875         LLQuaternion mouse_rotate;
03876         mouse_rotate.setQuat(click_y, click_x, 0.f);
03877 
03878         mouse_vector = mouse_vector * mouse_rotate;
03879         // project to z = -1 plane;
03880         mouse_vector = mouse_vector * (-1.f / mouse_vector.mV[VZ]);
03881 
03882         return mouse_vector;
03883 }
03884 
03885 
03886 
03887 BOOL LLViewerWindow::mousePointOnPlaneGlobal(LLVector3d& point, const S32 x, const S32 y, 
03888                                                                                 const LLVector3d &plane_point_global, 
03889                                                                                 const LLVector3 &plane_normal_global)
03890 {
03891         LLVector3d      mouse_direction_global_d;
03892 
03893         mouse_direction_global_d.setVec(mouseDirectionGlobal(x,y));
03894         LLVector3d      plane_normal_global_d;
03895         plane_normal_global_d.setVec(plane_normal_global);
03896         F64 plane_mouse_dot = (plane_normal_global_d * mouse_direction_global_d);
03897         LLVector3d plane_origin_camera_rel = plane_point_global - gAgent.getCameraPositionGlobal();
03898         F64     mouse_look_at_scale = (plane_normal_global_d * plane_origin_camera_rel)
03899                                                                 / plane_mouse_dot;
03900         if (llabs(plane_mouse_dot) < 0.00001)
03901         {
03902                 // if mouse is parallel to plane, return closest point on line through plane origin
03903                 // that is parallel to camera plane by scaling mouse direction vector
03904                 // by distance to plane origin, modulated by deviation of mouse direction from plane origin
03905                 LLVector3d plane_origin_dir = plane_origin_camera_rel;
03906                 plane_origin_dir.normVec();
03907                 
03908                 mouse_look_at_scale = plane_origin_camera_rel.magVec() / (plane_origin_dir * mouse_direction_global_d);
03909         }
03910 
03911         point = gAgent.getCameraPositionGlobal() + mouse_look_at_scale * mouse_direction_global_d;
03912 
03913         return mouse_look_at_scale > 0.0;
03914 }
03915 
03916 
03917 // Returns global position
03918 BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d *land_position_global)
03919 {
03920         LLVector3               mouse_direction_global = mouseDirectionGlobal(x,y);
03921         F32                             mouse_dir_scale;
03922         BOOL                    hit_land = FALSE;
03923         LLViewerRegion  *regionp;
03924         F32                     land_z;
03925         const F32       FIRST_PASS_STEP = 1.0f;         // meters
03926         const F32       SECOND_PASS_STEP = 0.1f;        // meters
03927         LLVector3d      camera_pos_global;
03928 
03929         camera_pos_global = gAgent.getCameraPositionGlobal();
03930         LLVector3d              probe_point_global;
03931         LLVector3               probe_point_region;
03932 
03933         // walk forwards to find the point
03934         for (mouse_dir_scale = FIRST_PASS_STEP; mouse_dir_scale < gAgent.mDrawDistance; mouse_dir_scale += FIRST_PASS_STEP)
03935         {
03936                 LLVector3d mouse_direction_global_d;
03937                 mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale);
03938                 probe_point_global = camera_pos_global + mouse_direction_global_d;
03939 
03940                 regionp = gWorldPointer->resolveRegionGlobal(probe_point_region, probe_point_global);
03941 
03942                 if (!regionp)
03943                 {
03944                         // ...we're outside the world somehow
03945                         continue;
03946                 }
03947 
03948                 S32 i = (S32) (probe_point_region.mV[VX]/regionp->getLand().getMetersPerGrid());
03949                 S32 j = (S32) (probe_point_region.mV[VY]/regionp->getLand().getMetersPerGrid());
03950                 S32 grids_per_edge = (S32) regionp->getLand().mGridsPerEdge;
03951                 if ((i >= grids_per_edge) || (j >= grids_per_edge))
03952                 {
03953                         //llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl;
03954                         continue;
03955                 }
03956 
03957                 land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
03958 
03959                 //llinfos << "mousePointOnLand initial z " << land_z << llendl;
03960 
03961                 if (probe_point_region.mV[VZ] < land_z)
03962                 {
03963                         // ...just went under land
03964 
03965                         // cout << "under land at " << probe_point << " scale " << mouse_vec_scale << endl;
03966 
03967                         hit_land = TRUE;
03968                         break;
03969                 }
03970         }
03971 
03972 
03973         if (hit_land)
03974         {
03975                 // Don't go more than one step beyond where we stopped above.
03976                 // This can't just be "mouse_vec_scale" because floating point error
03977                 // will stop the loop before the last increment.... X - 1.0 + 0.1 + 0.1 + ... + 0.1 != X
03978                 F32 stop_mouse_dir_scale = mouse_dir_scale + FIRST_PASS_STEP;
03979 
03980                 // take a step backwards, then walk forwards again to refine position
03981                 for ( mouse_dir_scale -= FIRST_PASS_STEP; mouse_dir_scale <= stop_mouse_dir_scale; mouse_dir_scale += SECOND_PASS_STEP)
03982                 {
03983                         LLVector3d mouse_direction_global_d;
03984                         mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale);
03985                         probe_point_global = camera_pos_global + mouse_direction_global_d;
03986 
03987                         regionp = gWorldPointer->resolveRegionGlobal(probe_point_region, probe_point_global);
03988 
03989                         if (!regionp)
03990                         {
03991                                 // ...we're outside the world somehow
03992                                 continue;
03993                         }
03994 
03995                         /*
03996                         i = (S32) (local_probe_point.mV[VX]/regionp->getLand().getMetersPerGrid());
03997                         j = (S32) (local_probe_point.mV[VY]/regionp->getLand().getMetersPerGrid());
03998                         if ((i >= regionp->getLand().mGridsPerEdge) || (j >= regionp->getLand().mGridsPerEdge))
03999                         {
04000                                 // llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl;
04001                                 continue;
04002                         }
04003                         land_z = regionp->getLand().mSurfaceZ[ i + j * (regionp->getLand().mGridsPerEdge) ];
04004                         */
04005 
04006                         land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
04007 
04008                         //llinfos << "mousePointOnLand refine z " << land_z << llendl;
04009 
04010                         if (probe_point_region.mV[VZ] < land_z)
04011                         {
04012                                 // ...just went under land again
04013 
04014                                 *land_position_global = probe_point_global;
04015                                 return TRUE;
04016                         }
04017                 }
04018         }
04019 
04020         return FALSE;
04021 }
04022 
04023 // Saves an image to the harddrive as "SnapshotX" where X >= 1.
04024 BOOL LLViewerWindow::saveImageNumbered(LLImageRaw *raw, const LLString& extension_in)
04025 {
04026         if (! raw)
04027         {
04028                 return FALSE;
04029         }
04030 
04031         LLString extension(extension_in);
04032         if (extension.empty())
04033         {
04034                 extension = (gSavedSettings.getBOOL("CompressSnapshotsToDisk")) ? ".j2c" : ".bmp";
04035         }
04036 
04037         LLFilePicker::ESaveFilter pick_type;
04038         if (extension == ".j2c")
04039                 pick_type = LLFilePicker::FFSAVE_J2C;
04040         else if (extension == ".bmp")
04041                 pick_type = LLFilePicker::FFSAVE_BMP;
04042         else if (extension == ".tga")
04043                 pick_type = LLFilePicker::FFSAVE_TGA;
04044         else
04045                 pick_type = LLFilePicker::FFSAVE_ALL; // ???
04046         
04047         // Get a directory if this is the first time.
04048         if (strlen(sSnapshotDir) == 0)          /* Flawfinder: ignore */
04049         {
04050                 LLString proposed_name( sSnapshotBaseName );
04051                 proposed_name.append( extension );
04052 
04053                 // pick a directory in which to save
04054                 LLFilePicker& picker = LLFilePicker::instance();
04055                 if (!picker.getSaveFile(pick_type, proposed_name.c_str()))
04056                 {
04057                         // Clicked cancel
04058                         return FALSE;
04059                 }
04060 
04061                 // Copy the directory + file name
04062                 char directory[LL_MAX_PATH];            /* Flawfinder: ignore */
04063                 strncpy(directory, picker.getFirstFile(), LL_MAX_PATH -1);              /* Flawfinder: ignore */
04064                 directory[LL_MAX_PATH -1] = '\0';
04065 
04066                 // Smash the file extension
04067                 S32 length = strlen(directory);         /* Flawfinder: ignore */
04068                 S32 index = length;
04069 
04070                 // Back up over extension
04071                 index -= extension.length();
04072                 if (index >= 0 && directory[index] == '.')
04073                 {
04074                         directory[index] = '\0';
04075                 }
04076                 else
04077                 {
04078                         index = length;
04079                 }
04080 
04081                 // Find trailing backslash
04082                 while (index >= 0 && directory[index] != gDirUtilp->getDirDelimiter()[0])
04083                 {
04084                         index--;
04085                 }
04086 
04087                 // If we found one, truncate the string there
04088                 if (index >= 0)
04089                 {
04090                         if (index + 1 <= length)
04091                         {
04092                                 strncpy(LLViewerWindow::sSnapshotBaseName, directory + index + 1, LL_MAX_PATH -1);              /* Flawfinder: ignore */
04093                                 LLViewerWindow::sSnapshotBaseName[LL_MAX_PATH -1] = '\0';
04094                         }
04095 
04096                         index++;
04097                         directory[index] = '\0';
04098                         strncpy(LLViewerWindow::sSnapshotDir, directory, LL_MAX_PATH -1);               /* Flawfinder: ignore */
04099                         LLViewerWindow::sSnapshotDir[LL_MAX_PATH -1] = '\0';
04100                 }
04101         }
04102 
04103         // Look for an unused file name
04104         LLString filepath;
04105         S32 i = 1;
04106         S32 err = 0;
04107 
04108         do
04109         {
04110                 filepath = sSnapshotDir;
04111                 filepath += sSnapshotBaseName;
04112                 filepath += llformat("_%.3d",i);
04113                 filepath += extension;
04114 
04115                 struct stat stat_info;
04116                 err = gViewerWindow->mWindow->stat( filepath.c_str(), &stat_info );
04117                 i++;
04118         }
04119         while( -1 != err );  // search until the file is not found (i.e., stat() gives an error).
04120 
04121         LLPointer<LLImageFormatted> formatted_image = LLImageFormatted::createFromExtension(extension);
04122         LLImageBase::setSizeOverride(TRUE);
04123         BOOL success = formatted_image->encode(raw);
04124         if( success )
04125         {
04126                 success = formatted_image->save(filepath);
04127         }
04128         else
04129         {
04130                 llwarns << "Unable to encode bmp snapshot" << llendl;
04131         }
04132         LLImageBase::setSizeOverride(FALSE);
04133 
04134         return success;
04135 }
04136 
04137 void LLViewerWindow::saveMovieNumbered(void*)
04138 {
04139         if (!gbCapturing)
04140         {
04141                 // Get a directory if this is the first time.
04142                 if (strlen(sSnapshotDir) == 0)          /* Flawfinder: ignore */
04143                 {
04144                         LLString proposed_name( sMovieBaseName );
04145 #if LL_DARWIN
04146                         proposed_name.append( ".mov" );
04147 #else
04148                         proposed_name.append( ".avi" );
04149 #endif
04150 
04151                         // pick a directory in which to save
04152                         LLFilePicker &picker = LLFilePicker::instance();
04153                         if (!picker.getSaveFile(LLFilePicker::FFSAVE_AVI, proposed_name.c_str()))
04154                         {
04155                                 // Clicked cancel
04156                                 return;
04157                         }
04158 
04159                         // Copy the directory + file name
04160                         char directory[LL_MAX_PATH];            /* Flawfinder: ignore */
04161                         strncpy(directory, picker.getFirstFile(), LL_MAX_PATH -1);              /* Flawfinder: ignore */
04162                         directory[LL_MAX_PATH -1] = '\0';
04163 
04164                         // Smash the file extension
04165                         S32 length = strlen(directory);         /* Flawfinder: ignore */
04166                         S32 index = length;
04167 
04168                         // Back up over ".bmp"
04169                         index -= 4;
04170                         if (index >= 0 && directory[index] == '.')
04171                         {
04172                                 directory[index] = '\0';
04173                         }
04174                         else
04175                         {
04176                                 index = length;
04177                         }
04178 
04179                         // Find trailing backslash
04180                         while (index >= 0 && directory[index] != gDirUtilp->getDirDelimiter()[0])
04181                         {
04182                                 index--;
04183                         }
04184 
04185                         // If we found one, truncate the string there
04186                         if (index >= 0)
04187                         {
04188                                 if (index + 1 <= length)
04189                                 {
04190                                         strncpy(LLViewerWindow::sMovieBaseName, directory + index + 1, LL_MAX_PATH -1);         /* Flawfinder: ignore */
04191                                         LLViewerWindow::sMovieBaseName[LL_MAX_PATH -1] = '\0';
04192                                 }
04193 
04194                                 index++;
04195                                 directory[index] = '\0';
04196                                 strncpy(LLViewerWindow::sSnapshotDir, directory, LL_MAX_PATH -1);               /* Flawfinder: ignore */
04197                                 LLViewerWindow::sSnapshotDir[LL_MAX_PATH -1] = '\0';
04198                         }
04199                 }
04200 
04201                 // Look for an unused file name
04202                 LLString filepath;
04203                 S32 i = 1;
04204                 S32 err = 0;
04205 
04206                 do
04207                 {
04208                         char extension[100];            /* Flawfinder: ignore */
04209 #if LL_DARWIN
04210                         snprintf( extension, sizeof(extension), "_%.3d.mov", i );               /* Flawfinder: ignore */
04211 #else
04212                         snprintf( extension, sizeof(extension), "_%.3d.avi", i );               /* Flawfinder: ignore */
04213 #endif
04214                         filepath.assign( sSnapshotDir );
04215                         filepath.append( sMovieBaseName );
04216                         filepath.append( extension );
04217 
04218                         struct stat stat_info;
04219                         err = gViewerWindow->mWindow->stat( filepath.c_str(), &stat_info );
04220                         i++;
04221                 }
04222                 while( -1 != err );  // search until the file is not found (i.e., stat() gives an error).
04223                 S32 x = gViewerWindow->getWindowWidth();
04224                 S32 y = gViewerWindow->getWindowHeight();
04225 
04226                 gbCapturing = TRUE;
04227 #if !LL_SOLARIS
04228                 gMovieMaker.StartCapture((char *)filepath.c_str(), x, y);
04229 #endif
04230         }
04231         else
04232         {
04233 #if !LL_SOLARIS
04234                 gMovieMaker.EndCapture();
04235 #endif
04236                 gbCapturing = FALSE;
04237         }
04238 }
04239 
04240 static S32 BORDERHEIGHT = 0;
04241 static S32 BORDERWIDTH = 0;
04242 
04243 void LLViewerWindow::movieSize(S32 new_width, S32 new_height)
04244 {
04245         LLCoordScreen size;
04246         gViewerWindow->mWindow->getSize(&size);
04247         if (  (size.mX != new_width + BORDERWIDTH)
04248                 ||(size.mY != new_height + BORDERHEIGHT))
04249         {
04250                 S32 x = gViewerWindow->getWindowWidth();
04251                 S32 y = gViewerWindow->getWindowHeight();
04252                 BORDERWIDTH = size.mX - x;
04253                 BORDERHEIGHT = size.mY- y;
04254                 LLCoordScreen new_size(new_width + BORDERWIDTH, 
04255                                                            new_height + BORDERHEIGHT);
04256                 BOOL disable_sync = gSavedSettings.getBOOL("DisableVerticalSync");
04257                 if (gViewerWindow->mWindow->getFullscreen())
04258                 {
04259                         gViewerWindow->changeDisplaySettings(FALSE, 
04260                                                                                                 new_size, 
04261                                                                                                 disable_sync, 
04262                                                                                                 TRUE);
04263                 }
04264                 else
04265                 {
04266                         gViewerWindow->mWindow->setSize(new_size);
04267                 }
04268         }
04269 }
04270 
04271 BOOL LLViewerWindow::saveSnapshot( const LLString& filepath, S32 image_width, S32 image_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type)
04272 {
04273         llinfos << "Saving snapshot to: " << filepath << llendl;
04274 
04275         LLPointer<LLImageRaw> raw = new LLImageRaw;
04276         BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, show_ui, do_rebuild);
04277 
04278         if (success)
04279         {
04280                 LLPointer<LLImageBMP> bmp_image = new LLImageBMP;
04281                 success = bmp_image->encode(raw);
04282                 if( success )
04283                 {
04284                         success = bmp_image->save(filepath);
04285                 }
04286                 else
04287                 {
04288                         llwarns << "Unable to encode bmp snapshot" << llendl;
04289                 }
04290         }
04291         else
04292         {
04293                 llwarns << "Unable to capture raw snapshot" << llendl;
04294         }
04295 
04296         return success;
04297 }
04298 
04299 
04300 void LLViewerWindow::playSnapshotAnimAndSound()
04301 {
04302         gAgent.sendAnimationRequest(ANIM_AGENT_SNAPSHOT, ANIM_REQUEST_START);
04303         send_sound_trigger(LLUUID(gSavedSettings.getString("UISndSnapshot")), 1.0f);
04304 }
04305 
04306 
04307 // Saves the image from the screen to the specified filename and path.
04308 BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, 
04309                                                                  BOOL keep_window_aspect, BOOL show_ui, BOOL do_rebuild, ESnapshotType type)
04310 {
04311         F32 image_aspect_ratio = ((F32)image_width) / ((F32)image_height);
04312         F32 window_aspect_ratio = ((F32)getWindowWidth()) / ((F32)getWindowHeight());
04313 
04314         if ((!gWorldPointer) ||
04315                 (!raw))
04316         {
04317                 return FALSE;
04318         }
04319 
04320         // PRE SNAPSHOT
04321 
04322         glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
04323         setCursor(UI_CURSOR_WAIT);
04324 
04325         // Hide all the UI widgets first and draw a frame
04326         BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
04327 
04328         if ( prev_draw_ui != show_ui)
04329         {
04330                 LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
04331         }
04332 
04333 
04334         BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && LLPipeline::sShowHUDAttachments;
04335         if (hide_hud)
04336         {
04337                 LLPipeline::sShowHUDAttachments = FALSE;
04338         }
04339 
04340         // Copy screen to a buffer
04341         // crop sides or top and bottom, if taking a snapshot of different aspect ratio
04342         // from window
04343         S32 snapshot_width = mWindowRect.getWidth();
04344         S32 snapshot_height =  mWindowRect.getHeight();
04345         if (!keep_window_aspect)
04346         {
04347                 if (image_aspect_ratio > window_aspect_ratio)
04348                 {
04349                         snapshot_height  = llround((F32)snapshot_width / image_aspect_ratio);
04350                 }
04351                 else if (image_aspect_ratio < window_aspect_ratio)
04352                 {
04353                         snapshot_width = llround((F32)snapshot_height  * image_aspect_ratio);
04354                 }
04355         }
04356 
04357         F32 scale_factor = llmax(1.f, (F32)image_width / snapshot_width, (F32)image_height / snapshot_height);
04358         raw->resize(llfloor(snapshot_width*scale_factor), llfloor(snapshot_height *scale_factor), type == SNAPSHOT_TYPE_DEPTH ? 4 : 3);
04359 
04360         BOOL high_res = scale_factor > 1.f;
04361         if (high_res)
04362         {
04363                 send_agent_pause();
04364                 //rescale fonts
04365                 initFonts(scale_factor);
04366                 LLHUDText::reshape();
04367         }
04368 
04369         // SNAPSHOT
04370         S32 window_width = mWindowRect.getWidth();
04371         S32 window_height = mWindowRect.getHeight();
04372         S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f);
04373         S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f);
04374 
04375         S32 output_buffer_offset_y = 0;
04376 
04377         F32 depth_conversion_factor_1 = (gCamera->getFar() + gCamera->getNear()) / (2.f * gCamera->getFar() * gCamera->getNear());
04378         F32 depth_conversion_factor_2 = (gCamera->getFar() - gCamera->getNear()) / (2.f * gCamera->getFar() * gCamera->getNear());
04379 
04380         for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y)
04381         {
04382                 S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height);;
04383                 // handle fractional columns
04384                 U32 read_height = llmax(0, (window_height - subimage_y_offset) -
04385                         llmax(0, (window_height * (subimage_y + 1)) - (buffer_y_offset + raw->getHeight())));
04386 
04387                 S32 output_buffer_offset_x = 0;
04388                 for (int subimage_x = 0; subimage_x < scale_factor; ++subimage_x)
04389                 {
04390                         gDisplaySwapBuffers = FALSE;
04391                         if (type == SNAPSHOT_TYPE_OBJECT_ID)
04392                         {
04393                                 glClearColor(0.f, 0.f, 0.f, 0.f);
04394                                 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
04395 
04396                                 gCamera->setZoomParameters(scale_factor, subimage_x+(subimage_y*llceil(scale_factor)));
04397                                 setup3DRender();
04398                                 setupViewport();
04399                                 BOOL first_time_through = (subimage_x + subimage_y == 0);
04400                                 gPickTransparent = FALSE;
04401                                 gObjectList.renderObjectsForSelect(*gCamera, FALSE, !first_time_through);
04402                         }
04403                         else
04404                         {
04405                                 display(do_rebuild, scale_factor, subimage_x+(subimage_y*llceil(scale_factor)));
04406                         }
04407                         glFlush();
04408                         S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width);
04409                         // handle fractional rows
04410                         U32 read_width = llmax(0, (window_width - subimage_x_offset) -
04411                                                                         llmax(0, (window_width * (subimage_x + 1)) - (buffer_x_offset + raw->getWidth())));
04412                         for(U32 out_y = 0; out_y < read_height ; out_y++)
04413                         {
04414                                 if (type == SNAPSHOT_TYPE_OBJECT_ID || type == SNAPSHOT_TYPE_COLOR)
04415                                 {
04416                                         glReadPixels(
04417                                                 subimage_x_offset, out_y + subimage_y_offset,
04418                                                 read_width, 1,
04419                                                 GL_RGB, GL_UNSIGNED_BYTE,
04420                                                 raw->getData() + // current output pixel is beginning of buffer...
04421                                                         ( 
04422                                                                 (out_y * (raw->getWidth())) // ...plus iterated y...
04423                                                                 + (window_width * subimage_x) // ...plus subimage start in x...
04424                                                                 + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y...
04425                                                                 - output_buffer_offset_x // ...minus buffer padding x...
04426                                                                 - (output_buffer_offset_y * (raw->getWidth()))  // ...minus buffer padding y...
04427                                                         ) * 3 // times 3 bytes per pixel
04428                                         );
04429                                 }
04430                                 else // SNAPSHOT_TYPE_DEPTH
04431                                 {
04432                                         S32 output_buffer_offset = ( 
04433                                                                 (out_y * (raw->getWidth())) // ...plus iterated y...
04434                                                                 + (window_width * subimage_x) // ...plus subimage start in x...
04435                                                                 + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y...
04436                                                                 - output_buffer_offset_x // ...minus buffer padding x...
04437                                                                 - (output_buffer_offset_y * (raw->getWidth()))  // ...minus buffer padding y...
04438                                                         ) * 4; // times 4 bytes per pixel
04439 
04440                                         glReadPixels(
04441                                                 subimage_x_offset, out_y + subimage_y_offset,
04442                                                 read_width, 1,
04443                                                 GL_DEPTH_COMPONENT, GL_FLOAT,
04444                                                 raw->getData() + output_buffer_offset// current output pixel is beginning of buffer...
04445                                         );
04446 
04447                                         for (S32 i = output_buffer_offset; i < output_buffer_offset + (S32)read_width * 4; i += 4)
04448                                         {
04449                                                 F32 depth_float = *(F32*)(raw->getData() + i);
04450                                         
04451                                                 F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float * depth_conversion_factor_2));
04452                                                 U8 depth_byte = F32_to_U8(linear_depth_float, gCamera->getNear(), gCamera->getFar());
04453                                                 *(raw->getData() + i + 0) = depth_byte;
04454                                                 *(raw->getData() + i + 1) = depth_byte;
04455                                                 *(raw->getData() + i + 2) = depth_byte;
04456                                                 *(raw->getData() + i + 3) = 255;
04457                                         }
04458                                 }
04459                         }
04460                         output_buffer_offset_x += subimage_x_offset;
04461                         stop_glerror();
04462                 }
04463                 output_buffer_offset_y += subimage_y_offset;
04464         }
04465 
04466         // POST SNAPSHOT
04467         if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
04468         {
04469                 LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
04470         }
04471 
04472         if (hide_hud)
04473         {
04474                 LLPipeline::sShowHUDAttachments = TRUE;
04475         }
04476 
04477         if (high_res)
04478         {
04479                 initFonts(1.f);
04480                 LLHUDText::reshape();
04481         }
04482 
04483         gDisplaySwapBuffers = TRUE;
04484 
04485         // Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding)
04486         // Note: this formula depends on the number of components being 3.  Not obvious, but it's correct.
04487         image_width += (image_width * (type == SNAPSHOT_TYPE_DEPTH ? 4 : 3)) % 4;       
04488 
04489         // Resize image
04490         raw->scale( image_width, image_height );  
04491 
04492         setCursor(UI_CURSOR_ARROW);
04493 
04494         if (do_rebuild)
04495         {
04496                 // If we had to do a rebuild, that means that the lists of drawables to be rendered
04497                 // was empty before we started.
04498                 // Need to reset these, otherwise we call state sort on it again when render gets called the next time
04499                 // and we stand a good chance of crashing on rebuild because the render drawable arrays have multiple copies of
04500                 // objects on them.
04501                 gPipeline.resetDrawOrders();
04502         }
04503 
04504         if (high_res)
04505         {
04506                 send_agent_resume();
04507         }
04508 
04509         return TRUE;
04510 }
04511 
04512 void LLViewerWindow::destroyWindow()
04513 {
04514         if (mWindow)
04515         {
04516                 LLWindowManager::destroyWindow(mWindow);
04517         }
04518         mWindow = NULL;
04519 }
04520 
04521 
04522 void LLViewerWindow::drawMouselookInstructions()
04523 {
04524         // Draw instructions for mouselook ("Press ESC to leave Mouselook" in a box at the top of the screen.)
04525         const char* instructions = "Press ESC to leave Mouselook.";
04526         const LLFontGL* font = gResMgr->getRes( LLFONT_SANSSERIF );
04527 
04528         const S32 INSTRUCTIONS_PAD = 5;
04529         LLRect instructions_rect;
04530         instructions_rect.setLeftTopAndSize( 
04531                 INSTRUCTIONS_PAD,
04532                 gViewerWindow->getWindowHeight() - INSTRUCTIONS_PAD,
04533                 font->getWidth( instructions ) + 2 * INSTRUCTIONS_PAD,
04534                 llround(font->getLineHeight() + 2 * INSTRUCTIONS_PAD));
04535 
04536         {
04537                 LLGLSNoTexture gls_no_texture;
04538                 glColor4f( 0.9f, 0.9f, 0.9f, 1.0f );
04539                 gl_rect_2d( instructions_rect );
04540         }
04541         
04542         font->renderUTF8( 
04543                 instructions, 0,
04544                 instructions_rect.mLeft + INSTRUCTIONS_PAD,
04545                 instructions_rect.mTop - INSTRUCTIONS_PAD,
04546                 LLColor4( 0.0f, 0.0f, 0.0f, 1.f ),
04547                 LLFontGL::LEFT, LLFontGL::TOP);
04548 }
04549 
04550 
04551 // These functions are here only because LLViewerWindow used to do the work that gFocusMgr does now.
04552 // They let other objects continue to work without change.
04553 
04554 void LLViewerWindow::setKeyboardFocus(LLUICtrl* new_focus,void (*on_focus_lost)(LLUICtrl* old_focus))
04555 {
04556         gFocusMgr.setKeyboardFocus( new_focus, on_focus_lost );
04557 }
04558 
04559 LLUICtrl* LLViewerWindow::getKeyboardFocus()
04560 {
04561         return gFocusMgr.getKeyboardFocus();
04562 }
04563 
04564 BOOL LLViewerWindow::hasKeyboardFocus(const LLUICtrl* possible_focus) const
04565 {
04566         return possible_focus == gFocusMgr.getKeyboardFocus();
04567 }
04568 
04569 BOOL LLViewerWindow::childHasKeyboardFocus(const LLView* parent) const
04570 {
04571         return gFocusMgr.childHasKeyboardFocus( parent );
04572 }
04573 
04574 void LLViewerWindow::setMouseCapture(LLMouseHandler* new_captor)
04575 {
04576         gFocusMgr.setMouseCapture( new_captor );
04577 }
04578 
04579 LLMouseHandler* LLViewerWindow::getMouseCaptor() const
04580 {
04581         return gFocusMgr.getMouseCapture();
04582 }
04583 
04584 S32     LLViewerWindow::getWindowHeight()       const   
04585 { 
04586         return mVirtualWindowRect.getHeight(); 
04587 }
04588 
04589 S32     LLViewerWindow::getWindowWidth() const  
04590 { 
04591         return mVirtualWindowRect.getWidth(); 
04592 }
04593 
04594 S32     LLViewerWindow::getWindowDisplayHeight()        const   
04595 { 
04596         return mWindowRect.getHeight(); 
04597 }
04598 
04599 S32     LLViewerWindow::getWindowDisplayWidth() const   
04600 { 
04601         return mWindowRect.getWidth(); 
04602 }
04603 
04604 LLUICtrl* LLViewerWindow::getTopCtrl() const
04605 {
04606         return gFocusMgr.getTopCtrl();
04607 }
04608 
04609 BOOL LLViewerWindow::hasTopCtrl(LLView* view) const
04610 {
04611         return view == gFocusMgr.getTopCtrl();
04612 }
04613 
04614 void LLViewerWindow::setTopCtrl(LLUICtrl* new_top)
04615 {
04616         gFocusMgr.setTopCtrl( new_top );
04617 }
04618 
04619 void LLViewerWindow::setupViewport(S32 x_offset, S32 y_offset)
04620 {
04621         glViewport(x_offset, y_offset, mWindowRect.getWidth(), mWindowRect.getHeight());
04622 }
04623 
04624 void LLViewerWindow::setup3DRender()
04625 {
04626         gCamera->setPerspective(NOT_FOR_SELECTION, 0, 0,  mWindowRect.getWidth(), mWindowRect.getHeight(), FALSE, gCamera->getNear(), MAX_FAR_PLANE);
04627 }
04628 
04629 void LLViewerWindow::setup2DRender()
04630 {
04631         gl_state_for_2d(mWindowRect.getWidth(), mWindowRect.getHeight());
04632 }
04633 
04634 // Could cache the pointer from the last hitObjectOrLand here.
04635 LLViewerObject *LLViewerWindow::lastObjectHit()
04636 {
04637         return gObjectList.findObject( gLastHitObjectID );
04638 }
04639 
04640 const LLVector3d& LLViewerWindow::lastObjectHitOffset()
04641 {
04642         return gLastHitObjectOffset;
04643 }
04644 
04645 // Could cache the pointer from the last hitObjectOrLand here.
04646 LLViewerObject *LLViewerWindow::lastNonFloraObjectHit()
04647 {
04648         return gObjectList.findObject( gLastHitNonFloraObjectID );
04649 }
04650 
04651 const LLVector3d& LLViewerWindow::lastNonFloraObjectHitOffset()
04652 {
04653         return gLastHitNonFloraObjectOffset;
04654 }
04655 
04656 
04657 void LLViewerWindow::setShowProgress(const BOOL show)
04658 {
04659         if (mProgressView)
04660         {
04661                 mProgressView->setVisible(show);
04662         }
04663 }
04664 
04665 BOOL LLViewerWindow::getShowProgress() const
04666 {
04667         return (mProgressView && mProgressView->getVisible());
04668 }
04669 
04670 
04671 void LLViewerWindow::moveProgressViewToFront()
04672 {
04673         if( mProgressView && mRootView )
04674         {
04675                 mRootView->removeChild( mProgressView );
04676                 mRootView->addChild( mProgressView );
04677         }
04678 }
04679 
04680 void LLViewerWindow::setProgressString(const LLString& string)
04681 {
04682         if (mProgressView)
04683         {
04684                 mProgressView->setText(string);
04685         }
04686 }
04687 
04688 void LLViewerWindow::setProgressMessage(const LLString& msg)
04689 {
04690         if(mProgressView)
04691         {
04692                 mProgressView->setMessage(msg);
04693         }
04694 }
04695 
04696 void LLViewerWindow::setProgressPercent(const F32 percent)
04697 {
04698         if (mProgressView)
04699         {
04700                 mProgressView->setPercent(percent);
04701         }
04702 }
04703 
04704 void LLViewerWindow::setProgressCancelButtonVisible( BOOL b, const LLString& label )
04705 {
04706         if (mProgressView)
04707         {
04708                 mProgressView->setCancelButtonVisible( b, label );
04709         }
04710 }
04711 
04712 
04713 LLProgressView *LLViewerWindow::getProgressView() const
04714 {
04715         return mProgressView;
04716 }
04717 
04718 void LLViewerWindow::dumpState()
04719 {
04720         llinfos << "LLViewerWindow Active " << S32(mActive) << llendl;
04721         llinfos << "mWindow visible " << S32(mWindow->getVisible())
04722                 << " minimized " << S32(mWindow->getMinimized())
04723                 << llendl;
04724 }
04725 
04726 void LLViewerWindow::stopGL(BOOL save_state)
04727 {
04728         if (!gGLManager.mIsDisabled)
04729         {
04730                 llinfos << "Shutting down GL..." << llendl;
04731 
04732                 // Pause texture decode threads (will get unpaused during main loop)
04733                 gTextureCache->pause();
04734                 gImageDecodeThread->pause();
04735                 gTextureFetch->pause();
04736                 
04737                 gSky.destroyGL();
04738                 stop_glerror();
04739         
04740                 gImageList.destroyGL(save_state);
04741                 stop_glerror();
04742 
04743                 gBumpImageList.destroyGL();
04744                 stop_glerror();
04745 
04746                 LLFontGL::destroyGL();
04747                 stop_glerror();
04748 
04749                 LLVOAvatar::destroyGL();
04750                 stop_glerror();
04751 
04752                 LLDynamicTexture::destroyGL();
04753                 stop_glerror();
04754 
04755                 gPipeline.destroyGL();
04756                 
04757                 gCone.cleanupGL();
04758                 gBox.cleanupGL();
04759                 gSphere.cleanupGL();
04760                 gCylinder.cleanupGL();
04761                 
04762                 gGLManager.mIsDisabled = TRUE;
04763                 stop_glerror();
04764                 
04765                 llinfos << "Remaining allocated texture memory: " << LLImageGL::sGlobalTextureMemory << " bytes" << llendl;
04766         }
04767 }
04768 
04769 void LLViewerWindow::restoreGL(const LLString& progress_message)
04770 {
04771         if (gGLManager.mIsDisabled)
04772         {
04773                 llinfos << "Restoring GL..." << llendl;
04774                 gGLManager.mIsDisabled = FALSE;
04775 
04776                 // for future support of non-square pixels, and fonts that are properly stretched
04777                 //LLFontGL::destroyDefaultFonts();
04778                 initFonts();
04779                 initGLDefaults();
04780                 LLGLState::restoreGL();
04781                 gSky.restoreGL();
04782                 gPipeline.restoreGL();
04783                 LLDrawPoolWater::restoreGL();
04784                 LLManipTranslate::restoreGL();
04785                 gImageList.restoreGL();
04786                 gBumpImageList.restoreGL();
04787                 LLDynamicTexture::restoreGL();
04788                 LLVOAvatar::restoreGL();
04789 
04790                 if (gFloaterCustomize && gFloaterCustomize->getVisible())
04791                 {
04792                         LLVisualParamHint::requestHintUpdates();
04793                 }
04794 
04795                 if (!progress_message.empty())
04796                 {
04797                         gRestoreGLTimer.reset();
04798                         gRestoreGL = TRUE;
04799                         setShowProgress(TRUE);
04800                         setProgressString(progress_message);
04801                 }
04802                 llinfos << "...Restoring GL done" << llendl;
04803 #if LL_WINDOWS
04804                 if (SetUnhandledExceptionFilter(LLWinDebug::handleException) != LLWinDebug::handleException)
04805                 {
04806                         llwarns << " Someone took over my exception handler (post restoreGL)!" << llendl;
04807                 }
04808 #endif
04809 
04810         }
04811 }
04812 
04813 void LLViewerWindow::initFonts(F32 zoom_factor)
04814 {
04815         LLFontGL::destroyGL();
04816         LLFontGL::initDefaultFonts( gSavedSettings.getF32("FontScreenDPI"),
04817                                                                 mDisplayScale.mV[VX] * zoom_factor,
04818                                                                 mDisplayScale.mV[VY] * zoom_factor,
04819                                                                 gSavedSettings.getString("FontMonospace"),
04820                                                                 gSavedSettings.getF32("FontSizeMonospace"),
04821                                                                 gSavedSettings.getString("FontSansSerif"), 
04822                                                                 gSavedSettings.getString("FontSansSerifFallback"),
04823                                                                 gSavedSettings.getF32("FontSansSerifFallbackScale"),
04824                                                                 gSavedSettings.getF32("FontSizeSmall"), 
04825                                                                 gSavedSettings.getF32("FontSizeMedium"), 
04826                                                                 gSavedSettings.getF32("FontSizeLarge"),                  
04827                                                                 gSavedSettings.getF32("FontSizeHuge"),                   
04828                                                                 gSavedSettings.getString("FontSansSerifBold"),
04829                                                                 gSavedSettings.getF32("FontSizeMedium"),
04830                                                                 gDirUtilp->getAppRODataDir()
04831                                                         );
04832 }
04833 void LLViewerWindow::toggleFullscreen(BOOL show_progress)
04834 {
04835         if (mWindow)
04836         {
04837                 mWantFullscreen = mWindow->getFullscreen() ? FALSE : TRUE;
04838                 mShowFullscreenProgress = show_progress;
04839         }
04840 }
04841 
04842 void LLViewerWindow::getTargetWindow(BOOL& fullscreen, S32& width, S32& height) const
04843 {
04844         fullscreen = mWantFullscreen;
04845         
04846         if (gViewerWindow->mWindow
04847         &&  gViewerWindow->mWindow->getFullscreen() == mWantFullscreen)
04848         {
04849                 width = gViewerWindow->getWindowDisplayWidth();
04850                 height = gViewerWindow->getWindowDisplayHeight();
04851         }
04852         else if (mWantFullscreen)
04853         {
04854                 width = gSavedSettings.getS32("FullScreenWidth");
04855                 height = gSavedSettings.getS32("FullScreenHeight");
04856         }
04857         else
04858         {
04859                 width = gSavedSettings.getS32("WindowWidth");
04860                 height = gSavedSettings.getS32("WindowHeight");
04861         }
04862 }
04863 
04864 
04865 BOOL LLViewerWindow::checkSettings()
04866 {
04867         BOOL is_fullscreen = gViewerWindow->mWindow->getFullscreen();
04868         if (is_fullscreen && !mWantFullscreen)
04869         {
04870                 gViewerWindow->changeDisplaySettings(FALSE, 
04871                                                                                          LLCoordScreen(gSavedSettings.getS32("WindowWidth"),
04872                                                                                                                    gSavedSettings.getS32("WindowHeight")),
04873                                                                                          TRUE,
04874                                                                                          mShowFullscreenProgress);
04875                 return TRUE;
04876         }
04877         else if (!is_fullscreen && mWantFullscreen)
04878         {
04879                 if (!LLStartUp::canGoFullscreen())
04880                 {
04881                         return FALSE;
04882                 }
04883                 
04884                 gViewerWindow->changeDisplaySettings(TRUE, 
04885                                                                                          LLCoordScreen(gSavedSettings.getS32("FullScreenWidth"),
04886                                                                                                                    gSavedSettings.getS32("FullScreenHeight")),
04887                                                                                          gSavedSettings.getBOOL("DisableVerticalSync"),
04888                                                                                          mShowFullscreenProgress);
04889                 return TRUE;
04890         }
04891         return FALSE;
04892 }
04893 
04894 void LLViewerWindow::restartDisplay(BOOL show_progress_bar)
04895 {
04896         llinfos << "Restaring GL" << llendl;
04897         stopGL();
04898         if (show_progress_bar)
04899         {
04900                 restoreGL("Changing Resolution...");
04901         }
04902         else
04903         {
04904                 restoreGL();
04905         }
04906 }
04907 
04908 BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar)
04909 {
04910         BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized");
04911         mWantFullscreen = fullscreen;
04912         mShowFullscreenProgress = show_progress_bar;
04913         gSavedSettings.setBOOL("FullScreen", mWantFullscreen);
04914 
04915         BOOL old_fullscreen = mWindow->getFullscreen();
04916         if (!old_fullscreen && fullscreen && !LLStartUp::canGoFullscreen())
04917         {
04918                 // we can't do this now, so do it later
04919                 
04920                 gSavedSettings.setS32("FullScreenWidth", size.mX);
04921                 gSavedSettings.setS32("FullScreenHeight", size.mY);
04922                 //gSavedSettings.setBOOL("DisableVerticalSync", disable_vsync);
04923                 
04924                 return TRUE;    // a lie..., because we'll get to it later
04925         }
04926 
04927         // going from windowed to windowed
04928         if (!old_fullscreen && !fullscreen)
04929         {
04930                 // if not maximized, use the request size
04931                 if (!mWindow->getMaximized())
04932                 {
04933                         mWindow->setSize(size);
04934                 }
04935                 return TRUE;
04936         }
04937 
04938         // Close floaters that don't handle settings change
04939         LLFloaterSnapshot::hide(0);
04940         
04941         BOOL result_first_try = FALSE;
04942         BOOL result_second_try = FALSE;
04943 
04944         LLUICtrl* keyboard_focus = gFocusMgr.getKeyboardFocus();
04945         send_agent_pause();
04946         llinfos << "Stopping GL during changeDisplaySettings" << llendl;
04947         stopGL();
04948         mIgnoreActivate = TRUE;
04949         LLCoordScreen old_size;
04950         LLCoordScreen old_pos;
04951         mWindow->getSize(&old_size);
04952         BOOL got_position = mWindow->getPosition(&old_pos);
04953 
04954         if (!old_fullscreen && fullscreen && got_position)
04955         {
04956                 // switching from windowed to fullscreen, so save window position
04957                 gSavedSettings.setS32("WindowX", old_pos.mX);
04958                 gSavedSettings.setS32("WindowY", old_pos.mY);
04959         }
04960         
04961         result_first_try = mWindow->switchContext(fullscreen, size, disable_vsync);
04962         if (!result_first_try)
04963         {
04964                 // try to switch back
04965                 result_second_try = mWindow->switchContext(old_fullscreen, old_size, disable_vsync);
04966 
04967                 if (!result_second_try)
04968                 {
04969                         // we are stuck...try once again with a minimal resolution?
04970                         send_agent_resume();
04971                         mIgnoreActivate = FALSE;
04972                         return FALSE;
04973                 }
04974         }
04975         send_agent_resume();
04976 
04977         llinfos << "Restoring GL during resolution change" << llendl;
04978         if (show_progress_bar)
04979         {
04980                 restoreGL("Changing Resolution...");
04981         }
04982         else
04983         {
04984                 restoreGL();
04985         }
04986 
04987         if (!result_first_try)
04988         {
04989                 LLStringBase<char>::format_map_t args;
04990                 args["[RESX]"] = llformat("%d",size.mX);
04991                 args["[RESY]"] = llformat("%d",size.mY);
04992                 alertXml("ResolutionSwitchFail", args);
04993                 size = old_size; // for reshape below
04994         }
04995 
04996         BOOL success = result_first_try || result_second_try;
04997         if (success)
04998         {
04999 #if LL_WINDOWS
05000                 // Only trigger a reshape after switching to fullscreen; otherwise rely on the windows callback
05001                 // (otherwise size is wrong; this is the entire window size, reshape wants the visible window size)
05002                 if (fullscreen)
05003 #endif
05004                 {
05005                         reshape(size.mX, size.mY);
05006                 }
05007         }
05008 
05009         if (!mWindow->getFullscreen() && success)
05010         {
05011                 // maximize window if was maximized, else reposition
05012                 if (was_maximized)
05013                 {
05014                         mWindow->maximize();
05015                 }
05016                 else
05017                 {
05018                         S32 windowX = gSavedSettings.getS32("WindowX");
05019                         S32 windowY = gSavedSettings.getS32("WindowY");
05020 
05021                         mWindow->setPosition(LLCoordScreen ( windowX, windowY ) );
05022                 }
05023         }
05024 
05025         mIgnoreActivate = FALSE;
05026         gFocusMgr.setKeyboardFocus(keyboard_focus, NULL);
05027         mWantFullscreen = mWindow->getFullscreen();
05028         mShowFullscreenProgress = FALSE;
05029         
05030         return success;
05031 }
05032 
05033 
05034 F32 LLViewerWindow::getDisplayAspectRatio() const
05035 {
05036         if (mWindow->getFullscreen())
05037         {
05038                 if (gSavedSettings.getBOOL("FullScreenAutoDetectAspectRatio"))
05039                 {
05040                         return mWindow->getNativeAspectRatio(); 
05041                 }
05042                 else
05043                 {
05044                         return gSavedSettings.getF32("FullScreenAspectRatio");
05045                 }
05046         }
05047         else
05048         {
05049                 return mWindow->getNativeAspectRatio();
05050         }
05051 }
05052 
05053 
05054 void LLViewerWindow::drawPickBuffer() const
05055 {
05056         if (mPickBuffer)
05057         {
05058                 LLGLDisable no_blend(GL_BLEND);
05059                 LLGLDisable no_alpha_test(GL_ALPHA_TEST);
05060                 LLGLSNoTexture no_texture;
05061                 glPixelZoom(10.f, 10.f);
05062                 glRasterPos2f(((F32)mPickPoint.mX * mDisplayScale.mV[VX] + 10.f), 
05063                         ((F32)mPickPoint.mY * mDisplayScale.mV[VY] + 10.f));
05064                 glDrawPixels(PICK_DIAMETER, PICK_DIAMETER, GL_RGBA, GL_UNSIGNED_BYTE, mPickBuffer);
05065                 glPixelZoom(1.f, 1.f);
05066                 glColor4fv(LLColor4::white.mV);
05067                 gl_rect_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] - (F32)(PICK_HALF_WIDTH)), 
05068                         llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH)),
05069                         llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH)),
05070                         llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] - (F32)(PICK_HALF_WIDTH)),
05071                         FALSE);
05072                 gl_line_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] - (F32)(PICK_HALF_WIDTH)), 
05073                         llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH)),
05074                         llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + 10.f), 
05075                         llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_DIAMETER) * 10.f + 10.f));
05076                 gl_line_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH)),
05077                         llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] - (F32)(PICK_HALF_WIDTH)),
05078                         llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_DIAMETER) * 10.f + 10.f), 
05079                         llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + 10.f));
05080                 glTranslatef(10.f, 10.f, 0.f);
05081                 gl_rect_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX]), 
05082                         llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_DIAMETER) * 10.f),
05083                         llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_DIAMETER) * 10.f),
05084                         llround((F32)mPickPoint.mY * mDisplayScale.mV[VY]),
05085                         FALSE);
05086                 gl_rect_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH + mPickOffset.mX)* 10.f), 
05087                         llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH + mPickOffset.mY + 1) * 10.f),
05088                         llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH + mPickOffset.mX + 1) * 10.f),
05089                         llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH  + mPickOffset.mY) * 10.f),
05090                         FALSE);
05091                 glPopMatrix();
05092         }
05093 }
05094 
05095 void LLViewerWindow::calcDisplayScale()
05096 {
05097         F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor");
05098         LLVector2 display_scale;
05099         display_scale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
05100         F32 height_normalization = gSavedSettings.getBOOL("UIAutoScale") ? ((F32)mWindowRect.getHeight() / display_scale.mV[VY]) / 768.f : 1.f;
05101         if(mWindow->getFullscreen())
05102         {
05103                 display_scale *= (ui_scale_factor * height_normalization);
05104         }
05105         else
05106         {
05107                 display_scale *= ui_scale_factor;
05108         }
05109 
05110         // limit minimum display scale
05111         if (display_scale.mV[VX] < MIN_DISPLAY_SCALE || display_scale.mV[VY] < MIN_DISPLAY_SCALE)
05112         {
05113                 display_scale *= MIN_DISPLAY_SCALE / llmin(display_scale.mV[VX], display_scale.mV[VY]);
05114         }
05115 
05116         if (mWindow->getFullscreen())
05117         {
05118                 display_scale.mV[0] = llround(display_scale.mV[0], 2.0f/(F32) mWindowRect.getWidth());
05119                 display_scale.mV[1] = llround(display_scale.mV[1], 2.0f/(F32) mWindowRect.getHeight());
05120         }
05121         
05122         if (display_scale != mDisplayScale)
05123         {
05124                 llinfos << "Setting display scale to " << display_scale << llendl;
05125 
05126                 mDisplayScale = display_scale;
05127                 // Init default fonts
05128                 initFonts();
05129         }
05130 }
05131 
05132 //----------------------------------------------------------------------------
05133 
05134 // static
05135 bool LLViewerWindow::alertCallback(S32 modal)
05136 {
05137         if (gNoRender)
05138         {
05139                 return false;
05140         }
05141         else
05142         {
05143 //              if (modal) // we really always want to take you out of mouselook
05144                 {
05145                         // If we're in mouselook, the mouse is hidden and so the user can't click 
05146                         // the dialog buttons.  In that case, change to First Person instead.
05147                         if( gAgent.cameraMouselook() )
05148                         {
05149                                 gAgent.changeCameraToDefault();
05150                         }
05151                 }
05152                 return true;
05153         }
05154 }
05155 
05156 LLAlertDialog* LLViewerWindow::alertXml(const std::string& xml_filename,
05157                                                           LLAlertDialog::alert_callback_t callback, void* user_data)
05158 {
05159         LLString::format_map_t args;
05160         return alertXml( xml_filename, args, callback, user_data );
05161 }
05162 
05163 LLAlertDialog* LLViewerWindow::alertXml(const std::string& xml_filename, const LLString::format_map_t& args,
05164                                                           LLAlertDialog::alert_callback_t callback, void* user_data)
05165 {
05166         if (gNoRender)
05167         {
05168                 llinfos << "Alert: " << xml_filename << llendl;
05169                 if (callback)
05170                 {
05171                         callback(-1, user_data);
05172                 }
05173                 return NULL;
05174         }
05175 
05176         // If we're in mouselook, the mouse is hidden and so the user can't click 
05177         // the dialog buttons.  In that case, change to First Person instead.
05178         if( gAgent.cameraMouselook() )
05179         {
05180                 gAgent.changeCameraToDefault();
05181         }
05182 
05183         // Note: object adds, removes, and destroys itself.
05184         return LLAlertDialog::showXml( xml_filename, args, callback, user_data );
05185 }
05186 
05187 LLAlertDialog* LLViewerWindow::alertXmlEditText(const std::string& xml_filename, const LLString::format_map_t& args,
05188                                                                           LLAlertDialog::alert_callback_t callback, void* user_data,
05189                                                                           LLAlertDialog::alert_text_callback_t text_callback, void *text_data,
05190                                                                           const LLString::format_map_t& edit_args, BOOL draw_asterixes)
05191 {
05192         if (gNoRender)
05193         {
05194                 llinfos << "Alert: " << xml_filename << llendl;
05195                 if (callback)
05196                 {
05197                         callback(-1, user_data);
05198                 }
05199                 return NULL;
05200         }
05201 
05202         // If we're in mouselook, the mouse is hidden and so the user can't click 
05203         // the dialog buttons.  In that case, change to First Person instead.
05204         if( gAgent.cameraMouselook() )
05205         {
05206                 gAgent.changeCameraToDefault();
05207         }
05208 
05209         // Note: object adds, removes, and destroys itself.
05210         LLAlertDialog* alert = LLAlertDialog::createXml( xml_filename, args, callback, user_data );
05211         if (alert)
05212         {
05213                 if (text_callback)
05214                 {
05215                         alert->setEditTextCallback(text_callback, text_data);
05216                 }
05217                 alert->setEditTextArgs(edit_args);
05218                 alert->setDrawAsterixes(draw_asterixes);
05219                 alert->show();
05220         }
05221         return alert;
05222 }
05223 
05225 
05226 LLBottomPanel::LLBottomPanel(const LLString &name, const LLRect &rect) : 
05227         LLPanel(name, rect, FALSE),
05228         mIndicator(NULL)
05229 {
05230         // bottom panel is focus root, so Tab moves through the toolbar and button bar, and overlay
05231         setFocusRoot(TRUE);
05232         // don't capture mouse clicks that don't hit a child
05233         setMouseOpaque(FALSE);
05234         setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
05235         setIsChrome(TRUE);
05236 }
05237 
05238 void LLBottomPanel::setFocusIndicator(LLView * indicator)
05239 {
05240         mIndicator = indicator;
05241 }
05242 
05243 void LLBottomPanel::draw()
05244 {
05245         if(mIndicator)
05246         {
05247                 BOOL hasFocus = gFocusMgr.childHasKeyboardFocus(this);
05248                 mIndicator->setVisible(hasFocus);
05249                 mIndicator->setEnabled(hasFocus);
05250         }
05251         LLPanel::draw();
05252 }

Generated on Thu Jul 1 06:09:35 2010 for Second Life Viewer by  doxygen 1.4.7