void LLViewerCamera::updateCameraLocation(const LLVector3 ¢er, const LLVector3 &up_direction, const LLVector3 &point_of_interest) { // do not update if avatar didn't move if (!LLViewerJoystick::getInstance()->getCameraNeedsUpdate()) { return; } LLVector3 last_position; LLVector3 last_axis; last_position = getOrigin(); last_axis = getAtAxis(); mLastPointOfInterest = point_of_interest; // constrain to max distance from avatar LLVector3 camera_offset = center - gAgent.getPositionAgent(); LLViewerRegion * regp = gAgent.getRegion(); F32 water_height = (NULL != regp) ? regp->getWaterHeight() : 0.f; LLVector3 origin = center; if (origin.mV[2] > water_height) { origin.mV[2] = llmax(origin.mV[2], water_height+0.20f); } else { origin.mV[2] = llmin(origin.mV[2], water_height-0.20f); } setOriginAndLookAt(origin, up_direction, point_of_interest); mVelocityDir = center - last_position ; F32 dpos = mVelocityDir.normVec() ; LLQuaternion rotation; rotation.shortestArc(last_axis, getAtAxis()); F32 x, y, z; F32 drot; rotation.getAngleAxis(&drot, &x, &y, &z); mVelocityStat.addValue(dpos); mAngularVelocityStat.addValue(drot); mAverageSpeed = mVelocityStat.getMeanPerSec() ; mAverageAngularSpeed = mAngularVelocityStat.getMeanPerSec() ; mCosHalfCameraFOV = cosf(0.5f * getView() * llmax(1.0f, getAspect())); // update pixel meter ratio using default fov, not modified one mPixelMeterRatio = getViewHeightInPixels()/ (2.f*tanf(mCameraFOVDefault*0.5)); // update screen pixel area mScreenPixelArea =(S32)((F32)getViewHeightInPixels() * ((F32)getViewHeightInPixels() * getAspect())); }
void LLViewerCamera::getPixelVectors(const LLVector3 &pos_agent, LLVector3 &up, LLVector3 &right) { LLVector3 to_vec = pos_agent - getOrigin(); F32 at_dist = to_vec * getAtAxis(); F32 height_meters = at_dist* (F32)tan(getView()/2.f); F32 height_pixels = getViewHeightInPixels()/2.f; F32 pixel_aspect = gViewerWindow->getWindow()->getPixelAspectRatio(); F32 meters_per_pixel = height_meters / height_pixels; up = getUpAxis() * meters_per_pixel * gViewerWindow->getDisplayScale().mV[VY]; right = -1.f * pixel_aspect * meters_per_pixel * getLeftAxis() * gViewerWindow->getDisplayScale().mV[VX]; }
// Uses the last GL matrices set in set_perspective to project a point from // the agent's region space to the nearest edge in screen coordinates. // Returns TRUE if projection succeeds. BOOL LLViewerCamera::projectPosAgentToScreenEdge(const LLVector3 &pos_agent, LLCoordGL &out_point) const { LLVector3 dir_to_point = pos_agent - getOrigin(); dir_to_point /= dir_to_point.magVec(); BOOL in_front = TRUE; if (dir_to_point * getAtAxis() < 0.f) { in_front = FALSE; } LLRect world_view_rect = gViewerWindow->getWorldViewRectRaw(); S32 viewport[4]; viewport[0] = world_view_rect.mLeft; viewport[1] = world_view_rect.mBottom; viewport[2] = world_view_rect.getWidth(); viewport[3] = world_view_rect.getHeight(); GLdouble x, y, z; // object's window coords, GL-style if (GL_TRUE == gluProject(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ], gGLModelView, gGLProjection, (GLint*)viewport, &x, &y, &z)) { x /= gViewerWindow->getDisplayScale().mV[VX]; y /= gViewerWindow->getDisplayScale().mV[VY]; // should now have the x,y coords of grab_point in screen space const LLRect& world_rect = gViewerWindow->getWorldViewRectScaled(); // ...sanity check S32 int_x = lltrunc(x); S32 int_y = lltrunc(y); // find the center GLdouble center_x = (GLdouble)world_rect.getCenterX(); GLdouble center_y = (GLdouble)world_rect.getCenterY(); if (x == center_x && y == center_y) { // can't project to edge from exact center return FALSE; } // find the line from center to local GLdouble line_x = x - center_x; GLdouble line_y = y - center_y; int_x = lltrunc(center_x); int_y = lltrunc(center_y); if (0.f == line_x) { // the slope of the line is undefined if (line_y > 0.f) { int_y = world_rect.mTop; } else { int_y = world_rect.mBottom; } } else if (0 == world_rect.getWidth()) { // the diagonal slope of the view is undefined if (y < world_rect.mBottom) { int_y = world_rect.mBottom; } else if ( y > world_rect.mTop) { int_y = world_rect.mTop; } } else { F32 line_slope = (F32)(line_y / line_x); F32 rect_slope = ((F32)world_rect.getHeight()) / ((F32)world_rect.getWidth()); if (fabs(line_slope) > rect_slope) { if (line_y < 0.f) { // bottom int_y = world_rect.mBottom; } else { // top int_y = world_rect.mTop; } int_x = lltrunc(((GLdouble)int_y - center_y) / line_slope + center_x); } else if (fabs(line_slope) < rect_slope) { if (line_x < 0.f) { // left int_x = world_rect.mLeft; } else { // right int_x = world_rect.mRight; } int_y = lltrunc(((GLdouble)int_x - center_x) * line_slope + center_y); } else { // exactly parallel ==> push to the corners if (line_x > 0.f) { int_x = world_rect.mRight; } else { int_x = world_rect.mLeft; } if (line_y > 0.0f) { int_y = world_rect.mTop; } else { int_y = world_rect.mBottom; } } } if (!in_front) { int_x = world_rect.mLeft + world_rect.mRight - int_x; int_y = world_rect.mBottom + world_rect.mTop - int_y; } out_point.mX = int_x + world_rect.mLeft; out_point.mY = int_y + world_rect.mBottom; return TRUE; } return FALSE; }
// Uses the last GL matrices set in set_perspective to project a point from // the agent's region space to screen coordinates. Returns TRUE if point in within // the current window. BOOL LLViewerCamera::projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoordGL &out_point, const BOOL clamp) const { BOOL in_front = TRUE; GLdouble x, y, z; // object's window coords, GL-style LLVector3 dir_to_point = pos_agent - getOrigin(); dir_to_point /= dir_to_point.magVec(); if (dir_to_point * getAtAxis() < 0.f) { if (clamp) { return FALSE; } else { in_front = FALSE; } } LLRect world_view_rect = gViewerWindow->getWorldViewRectRaw(); S32 viewport[4]; viewport[0] = world_view_rect.mLeft; viewport[1] = world_view_rect.mBottom; viewport[2] = world_view_rect.getWidth(); viewport[3] = world_view_rect.getHeight(); if (GL_TRUE == gluProject(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ], gGLModelView, gGLProjection, (GLint*)viewport, &x, &y, &z)) { // convert screen coordinates to virtual UI coordinates x /= gViewerWindow->getDisplayScale().mV[VX]; y /= gViewerWindow->getDisplayScale().mV[VY]; // should now have the x,y coords of grab_point in screen space LLRect world_rect = gViewerWindow->getWorldViewRectScaled(); // convert to pixel coordinates S32 int_x = lltrunc(x); S32 int_y = lltrunc(y); BOOL valid = TRUE; if (clamp) { if (int_x < world_rect.mLeft) { out_point.mX = world_rect.mLeft; valid = FALSE; } else if (int_x > world_rect.mRight) { out_point.mX = world_rect.mRight; valid = FALSE; } else { out_point.mX = int_x; } if (int_y < world_rect.mBottom) { out_point.mY = world_rect.mBottom; valid = FALSE; } else if (int_y > world_rect.mTop) { out_point.mY = world_rect.mTop; valid = FALSE; } else { out_point.mY = int_y; } return valid; } else { out_point.mX = int_x; out_point.mY = int_y; if (int_x < world_rect.mLeft) { valid = FALSE; } else if (int_x > world_rect.mRight) { valid = FALSE; } if (int_y < world_rect.mBottom) { valid = FALSE; } else if (int_y > world_rect.mTop) { valid = FALSE; } return in_front && valid; } } else { return FALSE; } }
// Uses the last GL matrices set in set_perspective to project a point from // the agent's region space to screen coordinates. Returns TRUE if point in within // the current window. BOOL LLViewerCamera::projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoordGL &out_point, const BOOL clamp) const { BOOL in_front = TRUE; LLVector3 window_coordinates; LLVector3 dir_to_point = pos_agent - getOrigin(); dir_to_point /= dir_to_point.magVec(); if (dir_to_point * getAtAxis() < 0.f) { if (clamp) { return FALSE; } else { in_front = FALSE; } } const LLRect& world_view_rect = gViewerWindow->getWorldViewRectRaw(); if (gGL.projectf(pos_agent, gGLModelView, gGLProjection, world_view_rect, window_coordinates)) { F32 &x = window_coordinates.mV[VX]; F32 &y = window_coordinates.mV[VY]; // convert screen coordinates to virtual UI coordinates x /= gViewerWindow->getDisplayScale().mV[VX]; y /= gViewerWindow->getDisplayScale().mV[VY]; // should now have the x,y coords of grab_point in screen space LLRect world_rect = gViewerWindow->getWorldViewRectScaled(); // ...sanity check S32 int_x = lltrunc(x); S32 int_y = lltrunc(y); BOOL valid = TRUE; if (clamp) { if (int_x < world_rect.mLeft) { out_point.mX = world_rect.mLeft; valid = FALSE; } else if (int_x > world_rect.mRight) { out_point.mX = world_rect.mRight; valid = FALSE; } else { out_point.mX = int_x; } if (int_y < world_rect.mBottom) { out_point.mY = world_rect.mBottom; valid = FALSE; } else if (int_y > world_rect.mTop) { out_point.mY = world_rect.mTop; valid = FALSE; } else { out_point.mY = int_y; } return valid; } else { out_point.mX = int_x; out_point.mY = int_y; if (int_x < world_rect.mLeft) { valid = FALSE; } else if (int_x > world_rect.mRight) { valid = FALSE; } if (int_y < world_rect.mBottom) { valid = FALSE; } else if (int_y > world_rect.mTop) { valid = FALSE; } return in_front && valid; } } else { return FALSE; } }