summaryrefslogtreecommitdiff
path: root/indra/newview/llviewerwindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llviewerwindow.cpp')
-rw-r--r--indra/newview/llviewerwindow.cpp994
1 files changed, 516 insertions, 478 deletions
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 0296aee8ca..4c575ff139 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -203,32 +203,8 @@ extern S32 gJamesInt;
LLViewerWindow *gViewerWindow = NULL;
LLVelocityBar *gVelocityBar = NULL;
-LLVector3d gLastHitPosGlobal;
-LLVector3d gLastHitObjectOffset;
-LLUUID gLastHitObjectID;
-S32 gLastHitObjectFace = -1;
-BOOL gLastHitLand = FALSE;
-F32 gLastHitUCoord;
-F32 gLastHitVCoord;
-
-
-LLVector3d gLastHitNonFloraPosGlobal;
-LLVector3d gLastHitNonFloraObjectOffset;
-LLUUID gLastHitNonFloraObjectID;
-S32 gLastHitNonFloraObjectFace = -1;
-BOOL gLastHitParcelWall = FALSE;
-
-S32 gLastHitUIElement = 0;
-LLHUDIcon* gLastHitHUDIcon = NULL;
BOOL gDebugSelect = FALSE;
-U8 gLastPickAlpha = 255;
-BOOL gUseGLPick = FALSE;
-
-// On the next pick pass (whenever that happens)
-// should we try to pick individual faces?
-// Cleared to FALSE every time a pick happens.
-BOOL gPickFaces = FALSE;
LLFrameTimer gMouseIdleTimer;
LLFrameTimer gAwayTimer;
@@ -239,6 +215,11 @@ BOOL gShowOverlayTitle = FALSE;
BOOL gPickTransparent = TRUE;
BOOL gDebugFastUIRender = FALSE;
+LLViewerObject* gDebugRaycastObject = NULL;
+LLVector3 gDebugRaycastIntersection;
+LLVector2 gDebugRaycastTexCoord;
+LLVector3 gDebugRaycastNormal;
+LLVector3 gDebugRaycastBinormal;
// HUD display lines in lower right
BOOL gDisplayWindInfo = FALSE;
@@ -256,9 +237,6 @@ const F32 MIN_AFK_TIME = 2.f; // minimum time after setting away state before co
const F32 MAX_FAST_FRAME_TIME = 0.5f;
const F32 FAST_FRAME_INCREMENT = 0.1f;
-const S32 PICK_HALF_WIDTH = 5;
-const S32 PICK_DIAMETER = 2 * PICK_HALF_WIDTH+1;
-
const F32 MIN_DISPLAY_SCALE = 0.85f;
const S32 CONSOLE_BOTTOM_PAD = 40;
@@ -1509,8 +1487,8 @@ LLViewerWindow::LLViewerWindow(
mToolStored( NULL ),
mSuppressToolbox( FALSE ),
mHideCursorPermanent( FALSE ),
- mPickPending(FALSE),
- mIgnoreActivate( FALSE )
+ mIgnoreActivate( FALSE ),
+ mHoverPick()
{
// Default to application directory.
LLViewerWindow::sSnapshotBaseName = "Snapshot";
@@ -1618,8 +1596,6 @@ LLViewerWindow::LLViewerWindow(
mCurrentMousePoint.mX = getWindowWidth() / 2;
mCurrentMousePoint.mY = getWindowHeight() / 2;
- mPickBuffer = new U8[PICK_DIAMETER * PICK_DIAMETER * 4];
-
gShowOverlayTitle = gSavedSettings.getBOOL("ShowOverlayTitle");
mOverlayTitle = gSavedSettings.getString("OverlayTitle");
// Can't have spaces in settings.ini strings, so use underscores instead and convert them.
@@ -2032,9 +2008,6 @@ LLViewerWindow::~LLViewerWindow()
LLViewerImage::cleanupClass();
- delete[] mPickBuffer;
- mPickBuffer = NULL;
-
llinfos << "Cleaning up select manager" << llendl;
LLSelectMgr::getInstance()->cleanup();
@@ -2733,6 +2706,10 @@ BOOL LLViewerWindow::handlePerFrameHover()
LLView::sMouseHandlerMessage.clear();
+ S32 x = mCurrentMousePoint.mX;
+ S32 y = mCurrentMousePoint.mY;
+ MASK mask = gKeyboard->currentMask(TRUE);
+
//RN: fix for asynchronous notification of mouse leaving window not working
LLCoordWindow mouse_pos;
mWindow->getCursorPosition(&mouse_pos);
@@ -2748,6 +2725,7 @@ BOOL LLViewerWindow::handlePerFrameHover()
mMouseInWindow = TRUE;
}
+
S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::sGLScaleFactor.mV[VX]);
S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::sGLScaleFactor.mV[VY]);
@@ -2778,10 +2756,6 @@ BOOL LLViewerWindow::handlePerFrameHover()
return TRUE;
}
- S32 x = mCurrentMousePoint.mX;
- S32 y = mCurrentMousePoint.mY;
- MASK mask = gKeyboard->currentMask(TRUE);
-
// clean up current focus
LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus();
if (cur_focus)
@@ -3123,10 +3097,41 @@ BOOL LLViewerWindow::handlePerFrameHover()
LLSelectMgr::getInstance()->deselectUnused();
}
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
+ {
+ gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1,
+ NULL,
+ &gDebugRaycastIntersection,
+ &gDebugRaycastTexCoord,
+ &gDebugRaycastNormal,
+ &gDebugRaycastBinormal);
+ }
+
+ static U16 frame_counter = 0;
+ static S32 previous_x = -1;
+ static S32 previous_y = -1;
+
+ if (((previous_x != x) || (previous_y != y)) ||
+ ((gSavedSettings.getBOOL("PerFrameHoverPick"))
+ && ((frame_counter % gSavedSettings.getS32("PerFrameHoverPickCount")) == 0)))
+ {
+ pickAsync(getCurrentMouseX(), getCurrentMouseY(), mask, hoverPickCallback, TRUE);
+ }
+ frame_counter++;
+ previous_x = x;
+ previous_y = y;
+
return handled;
}
+/* static */
+void LLViewerWindow::hoverPickCallback(const LLPickInfo& pick_info)
+{
+ gViewerWindow->mHoverPick = pick_info;
+}
+
+
void LLViewerWindow::saveLastMouse(const LLCoordGL &point)
{
// Store last mouse location.
@@ -3220,7 +3225,7 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls,
glPushMatrix();
if (selection->getSelectType() == SELECT_TYPE_HUD)
{
- F32 zoom = gAgent.getAvatarObject()->mHUDCurZoom;
+ F32 zoom = gAgent.mHUDCurZoom;
glScalef(zoom, zoom, zoom);
}
@@ -3372,19 +3377,14 @@ BOOL LLViewerWindow::clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewe
return intersect;
}
-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)
+void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(const LLPickInfo& info), BOOL pick_transparent, BOOL get_surface_info)
{
if (gNoRender)
{
return;
}
- glClear(GL_DEPTH_BUFFER_BIT);
- gDepthDirty = TRUE;
-
- S32 scaled_x = llround((F32)x * mDisplayScale.mV[VX]);
- S32 scaled_y = llround((F32)y_from_bot * mDisplayScale.mV[VY]);
-
+ // push back pick info object
BOOL in_build_mode = gFloaterTools && gFloaterTools->getVisible();
if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha)
{
@@ -3392,29 +3392,44 @@ void LLViewerWindow::hitObjectOrLandGlobalAsync(S32 x, S32 y_from_bot, MASK mask
// "Show Debug Alpha" means no object actually transparent
pick_transparent = TRUE;
}
- gPickTransparent = pick_transparent;
- gUseGLPick = FALSE;
- mPickCallback = callback;
+ // center initial pick frame buffer region under mouse cursor
+ // since that area is guaranteed to be onscreen and hence a valid
+ // part of the framebuffer
+ if (mPicks.empty())
+ {
+ mPickScreenRegion.setCenterAndSize(x, y_from_bot, PICK_DIAMETER, PICK_DIAMETER);
- // Default to not hitting anything
- gLastHitPosGlobal.zeroVec();
- gLastHitObjectOffset.zeroVec();
- gLastHitObjectID.setNull();
- gLastHitObjectFace = -1;
+ if (mPickScreenRegion.mLeft < 0) mPickScreenRegion.translate(-mPickScreenRegion.mLeft, 0);
+ if (mPickScreenRegion.mBottom < 0) mPickScreenRegion.translate(0, -mPickScreenRegion.mBottom);
+ if (mPickScreenRegion.mRight > mWindowRect.getWidth() ) mPickScreenRegion.translate(mWindowRect.getWidth() - mPickScreenRegion.mRight, 0);
+ if (mPickScreenRegion.mTop > mWindowRect.getHeight() ) mPickScreenRegion.translate(0, mWindowRect.getHeight() - mPickScreenRegion.mTop);
+ }
- gLastHitNonFloraPosGlobal.zeroVec();
- gLastHitNonFloraObjectOffset.zeroVec();
- gLastHitNonFloraObjectID.setNull();
- gLastHitNonFloraObjectFace = -1;
+ // set frame buffer region for picking results
+ // stack multiple picks left to right
+ LLRect screen_region = mPickScreenRegion;
+ screen_region.translate(mPicks.size() * PICK_DIAMETER, 0);
- gLastHitParcelWall = FALSE;
+ LLPickInfo pick(LLCoordGL(x, y_from_bot), screen_region, mask, pick_transparent, get_surface_info, callback);
+ schedulePick(pick);
+}
+
+void LLViewerWindow::schedulePick(LLPickInfo& pick_info)
+{
+ llassert_always(pick_info.mScreenRegion.notNull());
+ mPicks.push_back(pick_info);
+
+ S32 scaled_x = llround((F32)pick_info.mMousePt.mX * mDisplayScale.mV[VX]);
+ S32 scaled_y = llround((F32)pick_info.mMousePt.mY * mDisplayScale.mV[VY]);
+
+ // Default to not hitting anything
LLCamera pick_camera;
pick_camera.setOrigin(LLViewerCamera::getInstance()->getOrigin());
pick_camera.setOriginAndLookAt(LLViewerCamera::getInstance()->getOrigin(),
LLViewerCamera::getInstance()->getUpAxis(),
- LLViewerCamera::getInstance()->getOrigin() + mouseDirectionGlobal(x, y_from_bot));
+ LLViewerCamera::getInstance()->getOrigin() + mouseDirectionGlobal(pick_info.mMousePt.mX, pick_info.mMousePt.mY));
pick_camera.setView(0.5f*DEG_TO_RAD);
pick_camera.setNear(LLViewerCamera::getInstance()->getNear());
pick_camera.setFar(LLViewerCamera::getInstance()->getFar());
@@ -3431,117 +3446,38 @@ void LLViewerWindow::hitObjectOrLandGlobalAsync(S32 x, S32 y_from_bot, MASK mask
glPushMatrix();
glLoadIdentity();
- // build perspective transform and picking viewport
- // Perform pick on a PICK_DIAMETER x PICK_DIAMETER pixel region around cursor point.
- // Don't limit the select distance for this pick.
- LLViewerCamera::getInstance()->setPerspective(FOR_SELECTION, scaled_x - (PICK_HALF_WIDTH + 2), scaled_y - (PICK_HALF_WIDTH + 2), PICK_DIAMETER + 4, PICK_DIAMETER + 4, FALSE);
- // make viewport big enough to handle antialiased frame buffers
- gGLViewport[0] = scaled_x - (PICK_HALF_WIDTH + 2);
- gGLViewport[1] = scaled_y - (PICK_HALF_WIDTH + 2);
- gGLViewport[2] = PICK_DIAMETER + 4;
- gGLViewport[3] = PICK_DIAMETER + 4;
- glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
- LLViewerCamera::updateFrustumPlanes(pick_camera);
- stop_glerror();
-
+ // clear work area
+ {
+ LLGLState scissor_state(GL_SCISSOR_TEST);
+ scissor_state.enable();
+ glScissor(pick_info.mScreenRegion.mLeft, pick_info.mScreenRegion.mBottom, pick_info.mScreenRegion.getWidth(), pick_info.mScreenRegion.getHeight());
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-
- // Draw the objects so the user can select them.
- // The starting ID is 1, since land is zero.
- gObjectList.renderObjectsForSelect(pick_camera, pick_parcel_walls);
-
- stop_glerror();
-
- // restore drawing state
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- setupViewport();
-
- mPickPoint.set(x, y_from_bot);
- mPickOffset.set(0, 0);
- mPickMask = mask;
- mPickPending = TRUE;
-
- // delay further event processing until we receive results of pick
- mWindow->delayInputProcessing();
-}
-
-void LLViewerWindow::hitUIElementImmediate(S32 x, S32 y, void (*callback)(S32 x, S32 y, MASK mask))
-{
- // Performs the GL UI pick.
- // Stores its results in global, gLastHitUIElement
- if (gNoRender)
- {
- return;
- }
-
- hitUIElementAsync(x, y, gKeyboard->currentMask(TRUE), NULL);
- performPick();
- if (callback)
- {
- callback(x, y, gKeyboard->currentMask(TRUE));
- }
-}
-
-//RN: this currently doesn't do anything
-void LLViewerWindow::hitUIElementAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(S32 x, S32 y, MASK mask))
-{
- if (gNoRender)
- {
- return;
}
-
-// F32 delta_time = gAlphaFadeTimer.getElapsedTimeAndResetF32();
-
- gUseGLPick = FALSE;
- mPickCallback = callback;
-
- // Default to not hitting anything
- gLastHitUIElement = 0;
-
- LLCamera pick_camera;
- pick_camera.setOrigin(LLViewerCamera::getInstance()->getOrigin());
- pick_camera.setOriginAndLookAt(LLViewerCamera::getInstance()->getOrigin(),
- LLViewerCamera::getInstance()->getUpAxis(),
- LLViewerCamera::getInstance()->getOrigin() + mouseDirectionGlobal(x, y_from_bot));
- pick_camera.setView(0.5f*DEG_TO_RAD);
- pick_camera.setNear(LLViewerCamera::getInstance()->getNear());
- pick_camera.setFar(LLViewerCamera::getInstance()->getFar());
- pick_camera.setAspect(1.f);
-
- // save our drawing state
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
-
- // build orthogonal transform and picking viewport
+ // build perspective transform and picking viewport
// Perform pick on a PICK_DIAMETER x PICK_DIAMETER pixel region around cursor point.
// Don't limit the select distance for this pick.
- setup2DRender();
- const LLVector2& display_scale = getDisplayScale();
- glScalef(display_scale.mV[VX], display_scale.mV[VY], 1.f);
+ LLViewerCamera::getInstance()->setPerspective(FOR_SELECTION, scaled_x - PICK_HALF_WIDTH, scaled_y - PICK_HALF_WIDTH, PICK_DIAMETER, PICK_DIAMETER, FALSE);
- gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+ // render for object picking
// make viewport big enough to handle antialiased frame buffers
- glViewport(x - (PICK_HALF_WIDTH + 2), y_from_bot - (PICK_HALF_WIDTH + 2), PICK_DIAMETER + 4, PICK_DIAMETER + 4);
- stop_glerror();
+ gGLViewport[0] = pick_info.mScreenRegion.mLeft;
+ gGLViewport[1] = pick_info.mScreenRegion.mBottom;
+ gGLViewport[2] = pick_info.mScreenRegion.getWidth();
+ gGLViewport[3] = pick_info.mScreenRegion.getHeight();
- glClearColor(0.f, 0.f, 0.f, 0.f);
- glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+ LLViewerCamera::updateFrustumPlanes(pick_camera);
+ stop_glerror();
// Draw the objects so the user can select them.
// The starting ID is 1, since land is zero.
- //drawForSelect();
+ LLRect pick_region;
+ pick_region.setOriginAndSize(scaled_x - PICK_HALF_WIDTH, scaled_y - PICK_HALF_WIDTH, PICK_DIAMETER, PICK_DIAMETER);
+ gObjectList.renderObjectsForSelect(pick_camera, pick_region, FALSE, pick_info.mPickTransparent);
stop_glerror();
@@ -3551,309 +3487,121 @@ void LLViewerWindow::hitUIElementAsync(S32 x, S32 y_from_bot, MASK mask, void (*
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
+ setup3DRender();
+ setup2DRender();
setupViewport();
- mPickPoint.set(x, y_from_bot);
- mPickOffset.set(0, 0);
- mPickMask = mask;
- mPickPending = TRUE;
+ // delay further event processing until we receive results of pick
+ mWindow->delayInputProcessing();
}
+
void LLViewerWindow::performPick()
{
- if (gNoRender || !mPickPending)
+ if (gNoRender)
{
return;
}
- mPickPending = FALSE;
- U32 te_offset = NO_FACE;
-
- // find pick region that is fully onscreen
- LLCoordGL scaled_pick_point = mPickPoint;
- scaled_pick_point.mX = llclamp(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX]), PICK_HALF_WIDTH, getWindowDisplayWidth() - PICK_HALF_WIDTH);
- scaled_pick_point.mY = llclamp(llround((F32)mPickPoint.mY * mDisplayScale.mV[VY]), PICK_HALF_WIDTH, getWindowDisplayHeight() - PICK_HALF_WIDTH);
-
- 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);
-
- S32 pixel_index = PICK_HALF_WIDTH * PICK_DIAMETER + PICK_HALF_WIDTH;
- S32 name = (U32)mPickBuffer[(pixel_index * 4) + 0] << 16 | (U32)mPickBuffer[(pixel_index * 4) + 1] << 8 | (U32)mPickBuffer[(pixel_index * 4) + 2];
- gLastPickAlpha = mPickBuffer[(pixel_index * 4) + 3];
-
- if (name >= (S32)GL_NAME_UI_RESERVED && name < (S32)GL_NAME_INDEX_OFFSET)
- {
- // hit a UI element
- gLastHitUIElement = name;
- if (mPickCallback)
- {
- mPickCallback(mPickPoint.mX, mPickPoint.mY, mPickMask);
- }
- }
-
- //imdebug("rgba rbga=bbba b=8 w=%d h=%d %p", PICK_DIAMETER, PICK_DIAMETER, mPickBuffer);
-
- S32 x_offset = mPickPoint.mX - llround((F32)scaled_pick_point.mX / mDisplayScale.mV[VX]);
- S32 y_offset = mPickPoint.mY - llround((F32)scaled_pick_point.mY / mDisplayScale.mV[VY]);
-
-
- // we hit nothing, scan surrounding pixels for something useful
- if (!name)
+ if (!mPicks.empty())
{
- S32 closest_distance = 10000;
- //S32 closest_pick_name = 0;
- for (S32 col = 0; col < PICK_DIAMETER; col++)
+ std::vector<LLPickInfo>::iterator pick_it;
+ for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it)
{
- for (S32 row = 0; row < PICK_DIAMETER; row++)
- {
- 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));
- pixel_index = row * PICK_DIAMETER + col;
- S32 test_name = (U32)mPickBuffer[(pixel_index * 4) + 0] << 16 | (U32)mPickBuffer[(pixel_index * 4) + 1] << 8 | (U32)mPickBuffer[(pixel_index * 4) + 2];
- gLastPickAlpha = mPickBuffer[(pixel_index * 4) + 3];
- if (test_name && distance_squared < closest_distance)
- {
- closest_distance = distance_squared;
- name = test_name;
- gLastPickAlpha = mPickBuffer[(pixel_index * 4) + 3];
- mPickOffset.mX = col - PICK_HALF_WIDTH;
- mPickOffset.mY = row - PICK_HALF_WIDTH;
- }
- }
+ pick_it->fetchResults();
}
- }
- if (name)
- {
- mPickPoint.mX += llround((F32)mPickOffset.mX * mDisplayScale.mV[VX]);
- mPickPoint.mY += llround((F32)mPickOffset.mY * mDisplayScale.mV[VY]);
- }
-
- if (gPickFaces)
- {
- te_offset = ((U32)name >> 20);
- name &= 0x000fffff;
- // don't clear gPickFaces, as we still need to check for UV coordinates
+ mLastPick = mPicks.back();
+ mPicks.clear();
}
- LLViewerObject *objectp = NULL;
-
- // Frontmost non-foreground object that isn't trees or grass
- LLViewerObject* nonflora_objectp = NULL;
- S32 nonflora_name = -1;
- S32 nonflora_te_offset = NO_FACE;
-
- if (name == (S32)GL_NAME_PARCEL_WALL)
- {
- gLastHitParcelWall = TRUE;
- }
-
- gLastHitHUDIcon = NULL;
-
- objectp = gObjectList.getSelectedObject(name);
- if (objectp)
- {
- LLViewerObject* parent = (LLViewerObject*)(objectp->getParent());
- if (NULL == parent) {
- // if you are the parent
- parent = objectp;
- }
- if (objectp->mbCanSelect)
- {
- te_offset = (te_offset == 16) ? NO_FACE : te_offset;
-
- // If the hit object isn't a plant, store it as the frontmost non-flora object.
- LLPCode pcode = objectp->getPCode();
- if( (LL_PCODE_LEGACY_GRASS != pcode) &&
- (LL_PCODE_LEGACY_TREE != pcode) &&
- (LL_PCODE_TREE_NEW != pcode))
- {
- nonflora_objectp = objectp;
- nonflora_name = name;
- nonflora_te_offset = te_offset;
- }
- }
- else
- {
- //llinfos << "Hit object you can't select" << llendl;
- }
- }
- else
- {
- // was this name referring to a hud icon?
- gLastHitHUDIcon = LLHUDIcon::handlePick(name);
- }
-
- analyzeHit(
- mPickPoint.mX, mPickPoint.mY, objectp, te_offset,
- &gLastHitObjectID, &gLastHitObjectFace, &gLastHitPosGlobal, &gLastHitLand, &gLastHitUCoord, &gLastHitVCoord );
-
- if (objectp && !gLastHitObjectID.isNull())
- {
- gLastHitObjectOffset = gAgent.calcFocusOffset(objectp, mPickPoint.mX, mPickPoint.mY);
- }
+}
- if( objectp == nonflora_objectp )
- {
- gLastHitNonFloraObjectID = gLastHitObjectID;
- gLastHitNonFloraObjectFace = gLastHitObjectFace;
- gLastHitNonFloraPosGlobal = gLastHitPosGlobal;
- gLastHitNonFloraObjectOffset= gLastHitObjectOffset;
- }
- else
+// Performs the GL object/land pick.
+LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent)
+{
+ if (gNoRender)
{
- analyzeHit( mPickPoint.mX, mPickPoint.mY, nonflora_objectp, nonflora_te_offset,
- &gLastHitNonFloraObjectID, &gLastHitNonFloraObjectFace, &gLastHitNonFloraPosGlobal,
- &gLastHitLand, &gLastHitUCoord, &gLastHitVCoord);
-
- if( nonflora_objectp )
- {
- gLastHitNonFloraObjectOffset = gAgent.calcFocusOffset(nonflora_objectp, mPickPoint.mX, mPickPoint.mY);
- }
+ return LLPickInfo();
}
- if (mPickCallback)
- {
- mPickCallback(mPickPoint.mX, mPickPoint.mY, mPickMask);
- }
+ pickAsync(x, y_from_bot, gKeyboard->currentMask(TRUE), NULL, pick_transparent);
+ // assume that pickAsync put the results in the back of the mPicks list
+ mLastPick = mPicks.back();
+ mLastPick.fetchResults();
+ mPicks.pop_back();
- gPickFaces = FALSE;
+ return mLastPick;
}
-// Performs the GL object/land pick.
-// Stores its results in globals, gHit*
-void LLViewerWindow::hitObjectOrLandGlobalImmediate(S32 x, S32 y_from_bot, void (*callback)(S32 x, S32 y, MASK mask), BOOL pick_transparent)
+LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 depth,
+ LLViewerObject *this_object,
+ S32 this_face,
+ S32* face_hit,
+ LLVector3 *intersection,
+ LLVector2 *uv,
+ LLVector3 *normal,
+ LLVector3 *binormal)
{
- if (gNoRender)
- {
- return;
- }
-
- hitObjectOrLandGlobalAsync(x, y_from_bot, gKeyboard->currentMask(TRUE), NULL, pick_transparent);
- performPick();
- if (callback)
+ S32 x = mouse_x;
+ S32 y = mouse_y;
+
+ if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position
{
- callback(x, y_from_bot, gKeyboard->currentMask(TRUE));
+ x = getCurrentMouseX();
+ y = getCurrentMouseY();
}
-}
-LLViewerObject* LLViewerWindow::getObjectUnderCursor(const F32 depth)
-{
- S32 x = getCurrentMouseX();
- S32 y = getCurrentMouseY();
+ // HUD coordinates of mouse
+ LLVector3 mouse_point_hud = mousePointHUD(x, y);
+ LLVector3 mouse_hud_start = mouse_point_hud - LLVector3(depth, 0, 0);
+ LLVector3 mouse_hud_end = mouse_point_hud + LLVector3(depth, 0, 0);
+ // world coordinates of mouse
LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
- LLVector3 camera_pos_global = LLViewerCamera::getInstance()->getOrigin();
- LLVector3 pick_end = camera_pos_global + mouse_direction_global * depth;
- LLVector3 collision_point;
- return gPipeline.pickObject(camera_pos_global, pick_end, collision_point);
-}
-
-void LLViewerWindow::analyzeHit(
- S32 x, // input
- S32 y_from_bot, // input
- LLViewerObject* objectp, // input
- U32 te_offset, // input
- LLUUID* hit_object_id_p,// output
- S32* hit_face_p, // output
- LLVector3d* hit_pos_p, // output
- BOOL* hit_land, // output
- F32* hit_u_coord, // output
- F32* hit_v_coord) // output
-{
- // Clean up inputs
- S32 face = -1;
-
- if (te_offset != NO_FACE )
- {
- face = te_offset;
- }
+ LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin();
+ LLVector3 mouse_world_start = mouse_point_global;
+ LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth;
- *hit_land = FALSE;
+
+ LLViewerObject* found = NULL;
- if (objectp)
+ if (this_object) // check only this object
{
- if( objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH )
+ if (this_object->isHUDAttachment()) // is a HUD object?
{
- // Hit land
- *hit_land = TRUE;
-
- // put global position into land_pos
- LLVector3d land_pos;
- if (mousePointOnLandGlobal(x, y_from_bot, &land_pos))
+ if (this_object->lineSegmentIntersect(mouse_hud_start, mouse_hud_end, this_face,
+ face_hit, intersection, uv, normal, binormal))
{
- *hit_object_id_p = LLUUID::null;
- *hit_face_p = -1;
-
- // Fudge the land focus a little bit above ground.
- *hit_pos_p = land_pos + LLVector3d(0.f, 0.f, 0.1f);
- //llinfos << "DEBUG Hit Land " << *hit_pos_p << llendl;
- return;
+ found = this_object;
}
- else
- {
- //llinfos << "Hit land but couldn't find position" << llendl;
- // Fall through to "Didn't hit anything"
}
- }
- else
+
+ else // is a world object
{
- *hit_object_id_p = objectp->mID;
- *hit_face_p = face;
-
- // Hit an object
- if (objectp->isAvatar())
+ if (this_object->lineSegmentIntersect(mouse_world_start, mouse_world_end, this_face,
+ face_hit, intersection, uv, normal, binormal))
{
- *hit_pos_p = gAgent.getPosGlobalFromAgent(((LLVOAvatar*)objectp)->mPelvisp->getWorldPosition());
+ found = this_object;
}
- else if (objectp->mDrawable.notNull())
- {
- *hit_pos_p = gAgent.getPosGlobalFromAgent(objectp->getRenderPosition());
}
- else
- {
- // regular object
- *hit_pos_p = objectp->getPositionGlobal();
}
- if (gPickFaces && face > -1 &&
- objectp->mDrawable.notNull() && objectp->getPCode() == LL_PCODE_VOLUME &&
- face < objectp->mDrawable->getNumFaces())
+ else // check ALL objects
{
- // render red-blue gradient to get 1/256 precision
- // then render green grid to get final 1/4096 precision
- S32 scaled_x = llround((F32)x * mDisplayScale.mV[VX]);
- S32 scaled_y = llround((F32)y_from_bot * mDisplayScale.mV[VY]);
- const S32 UV_PICK_WIDTH = 41;
- const S32 UV_PICK_HALF_WIDTH = (UV_PICK_WIDTH - 1) / 2;
- U8 uv_pick_buffer[UV_PICK_WIDTH * UV_PICK_WIDTH * 4];
- S32 pick_face = face;
- LLFace* facep = objectp->mDrawable->getFace(pick_face);
- LLViewerCamera::getInstance()->setPerspective(FOR_SELECTION, scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, FALSE);
- glViewport(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH);
- gPipeline.renderFaceForUVSelect(facep);
-
- 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);
- U8* center_pixel = &uv_pick_buffer[4 * ((UV_PICK_WIDTH * UV_PICK_HALF_WIDTH) + UV_PICK_HALF_WIDTH + 1)];
- *hit_u_coord = (F32)((center_pixel[VGREEN] & 0xf) + (16.f * center_pixel[VRED])) / 4095.f;
- *hit_v_coord = (F32)((center_pixel[VGREEN] >> 4) + (16.f * center_pixel[VBLUE])) / 4095.f;
- }
- else
+ found = gPipeline.lineSegmentIntersectInHUD(mouse_hud_start, mouse_hud_end,
+ face_hit, intersection, uv, normal, binormal);
+
+ if (!found) // if not found in HUD, look in world:
+
{
- *hit_u_coord = 0.f;
- *hit_v_coord = 0.f;
+ found = gPipeline.lineSegmentIntersectInWorld(mouse_world_start, mouse_world_end,
+ face_hit, intersection, uv, normal, binormal);
}
- //llinfos << "DEBUG Hit Object " << *hit_pos_p << llendl;
- return;
- }
}
- // Didn't hit anything.
- *hit_object_id_p = LLUUID::null;
- *hit_face_p = -1;
- *hit_pos_p = LLVector3d::zero;
- *hit_u_coord = 0.f;
- *hit_v_coord = 0.f;
- //llinfos << "DEBUG Hit Nothing " << llendl;
+ return found;
}
// Returns unit vector relative to camera
@@ -3884,6 +3632,18 @@ LLVector3 LLViewerWindow::mouseDirectionGlobal(const S32 x, const S32 y) const
return mouse_vector;
}
+LLVector3 LLViewerWindow::mousePointHUD(const S32 x, const S32 y) const
+{
+ // find screen resolution
+ S32 height = getWindowHeight();
+ S32 width = getWindowWidth();
+
+ // remap with uniform scale (1/height) so that top is -0.5, bottom is +0.5
+ F32 hud_x = -((F32)x - (F32)width/2.f) / height;
+ F32 hud_y = ((F32)y - (F32)height/2.f) / height;
+
+ return LLVector3(0.f, hud_x, hud_y);
+}
// Returns unit vector relative to camera in camera space
// indicating direction of point on screen x,y
@@ -4249,8 +4009,7 @@ BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 p
LLHUDText::setDisplayText(FALSE) ;
if (type == SNAPSHOT_TYPE_OBJECT_ID)
{
- gPickTransparent = FALSE;
- gObjectList.renderObjectsForSelect(*LLViewerCamera::getInstance(), FALSE, FALSE);
+ gObjectList.renderPickList(gViewerWindow->getVirtualWindowRect(), FALSE, FALSE);
}
else
{
@@ -4452,6 +4211,8 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
F32 depth_conversion_factor_1 = (LLViewerCamera::getInstance()->getFar() + LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear());
F32 depth_conversion_factor_2 = (LLViewerCamera::getInstance()->getFar() - LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear());
+ gObjectList.generatePickList(*LLViewerCamera::getInstance());
+
for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y)
{
S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height);;
@@ -4472,9 +4233,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
LLViewerCamera::getInstance()->setZoomParameters(scale_factor, subimage_x+(subimage_y*llceil(scale_factor)));
setup3DRender();
setupViewport();
- BOOL first_time_through = (subimage_x + subimage_y == 0);
- gPickTransparent = FALSE;
- gObjectList.renderObjectsForSelect(*LLViewerCamera::getInstance(), FALSE, !first_time_through);
+ gObjectList.renderPickList(gViewerWindow->getVirtualWindowRect(), FALSE, FALSE);
}
else
{
@@ -4723,27 +4482,6 @@ void LLViewerWindow::setup2DRender()
gl_state_for_2d(mWindowRect.getWidth(), mWindowRect.getHeight());
}
-// Could cache the pointer from the last hitObjectOrLand here.
-LLViewerObject *LLViewerWindow::lastObjectHit()
-{
- return gObjectList.findObject( gLastHitObjectID );
-}
-
-const LLVector3d& LLViewerWindow::lastObjectHitOffset()
-{
- return gLastHitObjectOffset;
-}
-
-// Could cache the pointer from the last hitObjectOrLand here.
-LLViewerObject *LLViewerWindow::lastNonFloraObjectHit()
-{
- return gObjectList.findObject( gLastHitNonFloraObjectID );
-}
-
-const LLVector3d& LLViewerWindow::lastNonFloraObjectHitOffset()
-{
- return gLastHitNonFloraObjectOffset;
-}
void LLViewerWindow::setShowProgress(const BOOL show)
@@ -5166,46 +4904,7 @@ F32 LLViewerWindow::getDisplayAspectRatio() const
void LLViewerWindow::drawPickBuffer() const
{
- if (mPickBuffer)
- {
- gGL.color4f(1,1,1,1);
- gGL.pushMatrix();
- LLGLDisable no_blend(GL_BLEND);
- LLGLDisable no_alpha_test(GL_ALPHA_TEST);
- LLGLSNoTexture no_texture;
- glPixelZoom(10.f, 10.f);
- glRasterPos2f(((F32)mPickPoint.mX * mDisplayScale.mV[VX] + 10.f),
- ((F32)mPickPoint.mY * mDisplayScale.mV[VY] + 10.f));
- glDrawPixels(PICK_DIAMETER, PICK_DIAMETER, GL_RGBA, GL_UNSIGNED_BYTE, mPickBuffer);
- glPixelZoom(1.f, 1.f);
- gGL.color4fv(LLColor4::white.mV);
- gl_rect_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] - (F32)(PICK_HALF_WIDTH)),
- llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH)),
- llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH)),
- llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] - (F32)(PICK_HALF_WIDTH)),
- FALSE);
- gl_line_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] - (F32)(PICK_HALF_WIDTH)),
- llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH)),
- llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + 10.f),
- llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_DIAMETER) * 10.f + 10.f));
- gl_line_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH)),
- llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] - (F32)(PICK_HALF_WIDTH)),
- llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_DIAMETER) * 10.f + 10.f),
- llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + 10.f));
- gGL.translatef(10.f, 10.f, 0.f);
- gl_rect_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX]),
- llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_DIAMETER) * 10.f),
- llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_DIAMETER) * 10.f),
- llround((F32)mPickPoint.mY * mDisplayScale.mV[VY]),
- FALSE);
- gl_rect_2d(llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH + mPickOffset.mX)* 10.f),
- llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH + mPickOffset.mY + 1) * 10.f),
- llround((F32)mPickPoint.mX * mDisplayScale.mV[VX] + (F32)(PICK_HALF_WIDTH + mPickOffset.mX + 1) * 10.f),
- llround((F32)mPickPoint.mY * mDisplayScale.mV[VY] + (F32)(PICK_HALF_WIDTH + mPickOffset.mY) * 10.f),
- FALSE);
- gGL.popMatrix();
- gGL.flush();
- }
+ mHoverPick.drawPickBuffer();
}
void LLViewerWindow::calcDisplayScale()
@@ -5394,3 +5093,342 @@ void* LLBottomPanel::createToolBar(void* data)
gToolBar = new LLToolBar();
return gToolBar;
}
+
+//
+// LLPickInfo
+//
+LLPickInfo::LLPickInfo()
+ : mKeyMask(MASK_NONE),
+ mPickCallback(NULL),
+ mPickType(PICK_INVALID),
+ mWantSurfaceInfo(FALSE),
+ mObjectFace(-1),
+ mUVCoords(-1.f, -1.f),
+ mSTCoords(-1.f, -1.f),
+ mXYCoords(-1, -1),
+ mIntersection(),
+ mNormal(),
+ mBinormal(),
+ mHUDIcon(NULL),
+ mPickTransparent(FALSE)
+{
+}
+
+LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos,
+ const LLRect& screen_region,
+ MASK keyboard_mask,
+ BOOL pick_transparent,
+ BOOL pick_uv_coords,
+ void (*pick_callback)(const LLPickInfo& pick_info))
+ : mMousePt(mouse_pos),
+ mScreenRegion(screen_region),
+ mKeyMask(keyboard_mask),
+ mPickCallback(pick_callback),
+ mPickType(PICK_INVALID),
+ mWantSurfaceInfo(pick_uv_coords),
+ mObjectFace(-1),
+ mUVCoords(-1.f, -1.f),
+ mSTCoords(-1.f, -1.f),
+ mXYCoords(-1, -1),
+ mNormal(),
+ mBinormal(),
+ mHUDIcon(NULL),
+ mPickTransparent(pick_transparent)
+{
+}
+
+LLPickInfo::~LLPickInfo()
+{
+}
+
+void LLPickInfo::fetchResults()
+{
+ // read back colors and depth values from buffer
+ glReadPixels(mScreenRegion.mLeft, mScreenRegion.mBottom, mScreenRegion.getWidth(), mScreenRegion.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, mPickBuffer);
+ glReadPixels(mScreenRegion.mLeft, mScreenRegion.mBottom, mScreenRegion.getWidth(), mScreenRegion.getHeight(), GL_DEPTH_COMPONENT, GL_FLOAT, mPickDepthBuffer );
+
+ // find pick region that is fully onscreen
+ LLCoordGL scaled_pick_point;;
+ scaled_pick_point.mX = llclamp(llround((F32)mMousePt.mX * gViewerWindow->getDisplayScale().mV[VX]), PICK_HALF_WIDTH, gViewerWindow->getWindowDisplayWidth() - PICK_HALF_WIDTH);
+ scaled_pick_point.mY = llclamp(llround((F32)mMousePt.mY * gViewerWindow->getDisplayScale().mV[VY]), PICK_HALF_WIDTH, gViewerWindow->getWindowDisplayHeight() - PICK_HALF_WIDTH);
+ S32 pixel_index = PICK_HALF_WIDTH * PICK_DIAMETER + PICK_HALF_WIDTH;
+ S32 pick_id = (U32)mPickBuffer[(pixel_index * 4) + 0] << 16 | (U32)mPickBuffer[(pixel_index * 4) + 1] << 8 | (U32)mPickBuffer[(pixel_index * 4) + 2];
+ F32 depth = mPickDepthBuffer[pixel_index];
+
+ S32 x_offset = mMousePt.mX - llround((F32)scaled_pick_point.mX / gViewerWindow->getDisplayScale().mV[VX]);
+ S32 y_offset = mMousePt.mY - llround((F32)scaled_pick_point.mY / gViewerWindow->getDisplayScale().mV[VY]);
+
+ mPickPt = mMousePt;
+
+ // we hit nothing, scan surrounding pixels for something useful
+ if (!pick_id)
+ {
+ S32 closest_distance = 10000;
+ //S32 closest_pick_name = 0;
+ for (S32 col = 0; col < PICK_DIAMETER; col++)
+ {
+ for (S32 row = 0; row < PICK_DIAMETER; row++)
+ {
+ 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));
+ pixel_index = row * PICK_DIAMETER + col;
+ S32 test_name = (U32)mPickBuffer[(pixel_index * 4) + 0] << 16 | (U32)mPickBuffer[(pixel_index * 4) + 1] << 8 | (U32)mPickBuffer[(pixel_index * 4) + 2];
+ if (test_name && distance_squared < closest_distance)
+ {
+ closest_distance = distance_squared;
+ pick_id = test_name;
+ depth = mPickDepthBuffer[pixel_index];
+ mPickPt.mX = mMousePt.mX + (col - PICK_HALF_WIDTH);
+ mPickPt.mY = mMousePt.mY + (row - PICK_HALF_WIDTH);
+ }
+ }
+ }
+ }
+
+ U32 te_offset = ((U32)pick_id >> 20);
+ pick_id &= 0x000fffff;
+
+ //unproject relative clicked coordinate from window coordinate using GL
+ GLint viewport[4];
+ GLdouble modelview[16];
+ GLdouble projection[16];
+ GLfloat winX, winY;
+ GLdouble posX, posY, posZ;
+
+ LLViewerObject* objectp = gObjectList.getSelectedObject(pick_id);
+
+ if (pick_id == (S32)GL_NAME_PARCEL_WALL)
+ {
+ mPickType = PICK_PARCEL_WALL;
+ }
+ else if (objectp)
+ {
+ if( objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH )
+ {
+ // Hit land
+ mPickType = PICK_LAND;
+ mObjectID.setNull(); // land has no id
+
+ // put global position into land_pos
+ LLVector3d land_pos;
+ if (gViewerWindow->mousePointOnLandGlobal(mPickPt.mX, mPickPt.mY, &land_pos))
+ {
+ // Fudge the land focus a little bit above ground.
+ mPosGlobal = land_pos + LLVector3d::z_axis * 0.1f;
+ }
+ }
+ else
+ {
+ if(isFlora(objectp))
+ {
+ mPickType = PICK_FLORA;
+ }
+ else
+ {
+ mPickType = PICK_OBJECT;
+ }
+ mObjectOffset = gAgent.calcFocusOffset(objectp, mPickPt.mX, mPickPt.mY);
+ mObjectID = objectp->mID;
+ mObjectFace = (te_offset == NO_FACE) ? -1 : (S32)te_offset;
+
+ glh::matrix4f newModel((F32*)LLViewerCamera::getInstance()->getModelview().mMatrix);
+
+ for(U32 i = 0; i < 16; ++i)
+ {
+ modelview[i] = newModel.m[i];
+ projection[i] = LLViewerCamera::getInstance()->getProjection().mMatrix[i/4][i%4];
+ }
+ glGetIntegerv( GL_VIEWPORT, viewport );
+
+ winX = ((F32)mPickPt.mX) * gViewerWindow->getDisplayScale().mV[VX];
+ winY = ((F32)mPickPt.mY) * gViewerWindow->getDisplayScale().mV[VY];
+
+ gluUnProject( winX, winY, depth, modelview, projection, viewport, &posX, &posY, &posZ);
+
+ mPosGlobal = gAgent.getPosGlobalFromAgent(LLVector3(posX, posY, posZ));
+
+ if (mWantSurfaceInfo)
+ {
+ getSurfaceInfo();
+ }
+ }
+ }
+ else
+ {
+ // was this name referring to a hud icon?
+ mHUDIcon = LLHUDIcon::handlePick(pick_id);
+ if (mHUDIcon)
+ {
+ mPickType = PICK_ICON;
+ mPosGlobal = mHUDIcon->getPositionGlobal();
+ }
+ }
+
+ if (mPickCallback)
+ {
+ mPickCallback(*this);
+ }
+}
+
+LLPointer<LLViewerObject> LLPickInfo::getObject() const
+{
+ return gObjectList.findObject( mObjectID );
+}
+
+void LLPickInfo::updateXYCoords()
+{
+ const LLTextureEntry* tep = getObject()->getTE(mObjectFace);
+ LLPointer<LLViewerImage> imagep = gImageList.getImage(tep->getID());
+ if(mUVCoords.mV[VX] >= 0.f && mUVCoords.mV[VY] >= 0.f && imagep.notNull())
+ {
+ LLCoordGL coords;
+
+ coords.mX = llround(mUVCoords.mV[VX] * (F32)imagep->getWidth());
+ coords.mY = llround(mUVCoords.mV[VY] * (F32)imagep->getHeight());
+
+ gViewerWindow->getWindow()->convertCoords(coords, &mXYCoords);
+ }
+}
+
+void LLPickInfo::drawPickBuffer() const
+{
+ if (mPickBuffer)
+ {
+ gGL.pushMatrix();
+ LLGLDisable no_blend(GL_BLEND);
+ LLGLDisable no_alpha_test(GL_ALPHA_TEST);
+ LLGLSNoTexture no_texture;
+ glPixelZoom(10.f, 10.f);
+ LLVector2 display_scale = gViewerWindow->getDisplayScale();
+ glRasterPos2f(((F32)mMousePt.mX * display_scale.mV[VX] + 10.f),
+ ((F32)mMousePt.mY * display_scale.mV[VY] + 10.f));
+ glDrawPixels(PICK_DIAMETER, PICK_DIAMETER, GL_RGBA, GL_UNSIGNED_BYTE, mPickBuffer);
+ glPixelZoom(1.f, 1.f);
+ gGL.color4fv(LLColor4::white.mV);
+ gl_rect_2d(llround((F32)mMousePt.mX * display_scale.mV[VX] - (F32)(PICK_HALF_WIDTH)),
+ llround((F32)mMousePt.mY * display_scale.mV[VY] + (F32)(PICK_HALF_WIDTH)),
+ llround((F32)mMousePt.mX * display_scale.mV[VX] + (F32)(PICK_HALF_WIDTH)),
+ llround((F32)mMousePt.mY * display_scale.mV[VY] - (F32)(PICK_HALF_WIDTH)),
+ FALSE);
+ gl_line_2d(llround((F32)mMousePt.mX * display_scale.mV[VX] - (F32)(PICK_HALF_WIDTH)),
+ llround((F32)mMousePt.mY * display_scale.mV[VY] + (F32)(PICK_HALF_WIDTH)),
+ llround((F32)mMousePt.mX * display_scale.mV[VX] + 10.f),
+ llround((F32)mMousePt.mY * display_scale.mV[VY] + (F32)(PICK_DIAMETER) * 10.f + 10.f));
+ gl_line_2d(llround((F32)mMousePt.mX * display_scale.mV[VX] + (F32)(PICK_HALF_WIDTH)),
+ llround((F32)mMousePt.mY * display_scale.mV[VY] - (F32)(PICK_HALF_WIDTH)),
+ llround((F32)mMousePt.mX * display_scale.mV[VX] + (F32)(PICK_DIAMETER) * 10.f + 10.f),
+ llround((F32)mMousePt.mY * display_scale.mV[VY] + 10.f));
+ gGL.translatef(10.f, 10.f, 0.f);
+ gl_rect_2d(llround((F32)mPickPt.mX * display_scale.mV[VX]),
+ llround((F32)mPickPt.mY * display_scale.mV[VY] + (F32)(PICK_DIAMETER) * 10.f),
+ llround((F32)mPickPt.mX * display_scale.mV[VX] + (F32)(PICK_DIAMETER) * 10.f),
+ llround((F32)mPickPt.mY * display_scale.mV[VY]),
+ FALSE);
+ gl_rect_2d(llround((F32)mPickPt.mX * display_scale.mV[VX]),
+ llround((F32)mPickPt.mY * display_scale.mV[VY] + 10.f),
+ llround((F32)mPickPt.mX * display_scale.mV[VX] + 10.f),
+ llround((F32)mPickPt.mY * display_scale.mV[VY]),
+ FALSE);
+ gGL.popMatrix();
+ }
+}
+
+void LLPickInfo::getSurfaceInfo()
+{
+ // set values to uninitialized - this is what we return if no intersection is found
+ mObjectFace = -1;
+ mUVCoords = LLVector2(-1, -1);
+ mSTCoords = LLVector2(-1, -1);
+ mXYCoords = LLCoordScreen(-1, -1);
+ mIntersection = LLVector3(0,0,0);
+ mNormal = LLVector3(0,0,0);
+ mBinormal = LLVector3(0,0,0);
+
+ LLViewerObject* objectp = getObject();
+
+ if (objectp)
+ {
+ if (gViewerWindow->cursorIntersect(llround((F32)mMousePt.mX), llround((F32)mMousePt.mY), 1024.f,
+ objectp, -1,
+ &mObjectFace,
+ &mIntersection,
+ &mSTCoords,
+ &mNormal,
+ &mBinormal))
+ {
+ // if we succeeded with the intersect above, compute the texture coordinates:
+
+ if (objectp->mDrawable.notNull())
+ {
+ LLFace* facep = objectp->mDrawable->getFace(mObjectFace);
+
+ mUVCoords = facep->surfaceToTexture(mSTCoords, mIntersection, mNormal);
+ }
+
+ // and XY coords:
+ updateXYCoords();
+
+ }
+ }
+}
+
+
+/* code to get UV via a special UV render - removed in lieu of raycast method
+LLVector2 LLPickInfo::pickUV()
+{
+ LLVector2 result(-1.f, -1.f);
+
+ LLViewerObject* objectp = getObject();
+ if (!objectp)
+ {
+ return result;
+ }
+
+ if (mObjectFace > -1 &&
+ objectp->mDrawable.notNull() && objectp->getPCode() == LL_PCODE_VOLUME &&
+ mObjectFace < objectp->mDrawable->getNumFaces())
+ {
+ S32 scaled_x = llround((F32)mPickPt.mX * gViewerWindow->getDisplayScale().mV[VX]);
+ S32 scaled_y = llround((F32)mPickPt.mY * gViewerWindow->getDisplayScale().mV[VY]);
+ const S32 UV_PICK_WIDTH = 5;
+ const S32 UV_PICK_HALF_WIDTH = (UV_PICK_WIDTH - 1) / 2;
+ U8 uv_pick_buffer[UV_PICK_WIDTH * UV_PICK_WIDTH * 4];
+ LLFace* facep = objectp->mDrawable->getFace(mObjectFace);
+ if (facep)
+ {
+ LLGLState scissor_state(GL_SCISSOR_TEST);
+ scissor_state.enable();
+ LLViewerCamera::getInstance()->setPerspective(FOR_SELECTION, scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, FALSE);
+ //glViewport(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH);
+ glScissor(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH);
+
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ facep->renderSelectedUV();
+
+ 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);
+ U8* center_pixel = &uv_pick_buffer[4 * ((UV_PICK_WIDTH * UV_PICK_HALF_WIDTH) + UV_PICK_HALF_WIDTH + 1)];
+
+ result.mV[VX] = (F32)((center_pixel[VGREEN] & 0xf) + (16.f * center_pixel[VRED])) / 4095.f;
+ result.mV[VY] = (F32)((center_pixel[VGREEN] >> 4) + (16.f * center_pixel[VBLUE])) / 4095.f;
+ }
+ }
+
+ return result;
+} */
+
+
+//static
+bool LLPickInfo::isFlora(LLViewerObject* object)
+{
+ if (!object) return false;
+
+ LLPCode pcode = object->getPCode();
+
+ if( (LL_PCODE_LEGACY_GRASS == pcode)
+ || (LL_PCODE_LEGACY_TREE == pcode)
+ || (LL_PCODE_TREE_NEW == pcode))
+ {
+ return true;
+ }
+ return false;
+}