LLVector3 LLSurface::resolveNormalGlobal(const LLVector3d& pos_global) const { if (!mSurfaceZ) { // Hmm. Uninitialized surface! return LLVector3::z_axis; } // // Returns the vector normal to a surface at location specified by vector v // F32 oometerspergrid = 1.f/mMetersPerGrid; LLVector3 normal; F32 dzx, dzy; if (pos_global.mdV[VX] >= mOriginGlobal.mdV[VX] && pos_global.mdV[VX] < mOriginGlobal.mdV[VX] + mMetersPerEdge && pos_global.mdV[VY] >= mOriginGlobal.mdV[VY] && pos_global.mdV[VY] < mOriginGlobal.mdV[VY] + mMetersPerEdge) { U32 i, j, k; F32 dx, dy; i = (U32) ((pos_global.mdV[VX] - mOriginGlobal.mdV[VX]) * oometerspergrid); j = (U32) ((pos_global.mdV[VY] - mOriginGlobal.mdV[VY]) * oometerspergrid ); k = i + j*mGridsPerEdge; // Figure out if v is in first or second triangle of the square // and calculate the slopes accordingly // | | // -(k+N)---(k+1+N)-- // | 1 / | ^ // | / 2 | | // | / | j // --(k)----(k+1)-- // | | // // i -> // where N = mGridsPerEdge // dx and dy are incremental steps from (mSurface + k) dx = (F32)(pos_global.mdV[VX] - i*mMetersPerGrid - mOriginGlobal.mdV[VX]); dy = (F32)(pos_global.mdV[VY] - j*mMetersPerGrid - mOriginGlobal.mdV[VY]); if (dy > dx) { // triangle 1 dzx = *(mSurfaceZ + k + 1 + mGridsPerEdge) - *(mSurfaceZ + k + mGridsPerEdge); dzy = *(mSurfaceZ + k) - *(mSurfaceZ + k + mGridsPerEdge); normal.setVec(-dzx,dzy,1); } else { // triangle 2 dzx = *(mSurfaceZ + k) - *(mSurfaceZ + k + 1); dzy = *(mSurfaceZ + k + 1 + mGridsPerEdge) - *(mSurfaceZ + k + 1); normal.setVec(dzx,-dzy,1); } } normal.normVec(); return normal; }
void LLVOTree::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax) { F32 radius = getScale().magVec()*0.05f; LLVector3 center = getRenderPosition(); F32 sz = mBillboardScale*mBillboardRatio*radius*0.5f; LLVector3 size(sz,sz,sz); center += LLVector3(0, 0, size.mV[2]) * getRotation(); newMin.setVec(center-size); newMax.setVec(center+size); mDrawable->setPositionGroup(center); }
//----------------------------------------------------------------------- void LLAudioEngine_FMOD::updateWind(LLVector3 wind_vec, F32 camera_height_above_water) { LLVector3 wind_pos; F64 pitch; F64 center_freq; if (!mEnableWind) { return; } if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) { // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) // need to convert this to the conventional orientation DS3D and OpenAL use // where +X = right, +Y = up, +Z = backwards wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); // cerr << "Wind update" << endl; pitch = 1.0 + mapWindVecToPitch(wind_vec); center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0)); mWindGen->mTargetFreq = (F32)center_freq; mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); } }
BOOL ray_sphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &sphere_center, F32 sphere_radius, LLVector3 &intersection, LLVector3 &intersection_normal) { LLVector3 ray_to_sphere = sphere_center - ray_point; F32 dot = ray_to_sphere * ray_direction; LLVector3 closest_approach = dot * ray_direction - ray_to_sphere; F32 shortest_distance = closest_approach.magVecSquared(); F32 radius_squared = sphere_radius * sphere_radius; if (shortest_distance > radius_squared) { return FALSE; } F32 half_chord = (F32) sqrt(radius_squared - shortest_distance); closest_approach = sphere_center + closest_approach; // closest_approach now in absolute coordinates intersection = closest_approach + half_chord * ray_direction; dot = ray_direction * (intersection - ray_point); if (dot < 0.0f) { // ray shoots away from sphere and is not inside it return FALSE; } shortest_distance = ray_direction * ((closest_approach - half_chord * ray_direction) - ray_point); if (shortest_distance > 0.0f) { // ray enters sphere intersection = intersection - (2.0f * half_chord) * ray_direction; } else { // do nothing // ray starts inside sphere and intersects as it leaves the sphere } intersection_normal = intersection - sphere_center; if (sphere_radius > 0.0f) { intersection_normal *= 1.0f / sphere_radius; } else { intersection_normal.setVec(0.0f, 0.0f, 0.0f); } return TRUE; }
//------------------------------------------------------------------------------------- BOOL LLFollowCam::updateBehindnessConstraint(LLVector3 focus, LLVector3& cam_position) { BOOL constraint_active = FALSE; // only apply this stuff if the behindness angle is something other than opened up all the way if ( mBehindnessMaxAngle < FOLLOW_CAM_MAX_BEHINDNESS_ANGLE - FOLLOW_CAM_BEHINDNESS_EPSILON ) { //-------------------------------------------------------------- // horizontalized vector from focus to camera //-------------------------------------------------------------- LLVector3 horizontalVectorFromFocusToCamera; horizontalVectorFromFocusToCamera.setVec(cam_position - focus); horizontalVectorFromFocusToCamera.mV[ VZ ] = 0.0f; F32 cameraZ = cam_position.mV[ VZ ]; //-------------------------------------------------------------- // distance of horizontalized vector //-------------------------------------------------------------- F32 horizontalDistance = horizontalVectorFromFocusToCamera.magVec(); //-------------------------------------------------------------------------------------------------- // calculate horizontalized back vector of the subject and scale by horizontalDistance //-------------------------------------------------------------------------------------------------- LLVector3 horizontalSubjectBack( -1.0f, 0.0f, 0.0f ); horizontalSubjectBack *= mSubjectRotation; horizontalSubjectBack.mV[ VZ ] = 0.0f; horizontalSubjectBack.normVec(); // because horizontalizing might make it shorter than 1 horizontalSubjectBack *= horizontalDistance; //-------------------------------------------------------------------------------------------------- // find the angle (in degrees) between these vectors //-------------------------------------------------------------------------------------------------- F32 cameraOffsetAngle = 0.f; LLVector3 cameraOffsetRotationAxis; LLQuaternion camera_offset_rotation; camera_offset_rotation.shortestArc(horizontalSubjectBack, horizontalVectorFromFocusToCamera); camera_offset_rotation.getAngleAxis(&cameraOffsetAngle, cameraOffsetRotationAxis); cameraOffsetAngle *= RAD_TO_DEG; if ( cameraOffsetAngle > mBehindnessMaxAngle ) { F32 fraction = ((cameraOffsetAngle - mBehindnessMaxAngle) / cameraOffsetAngle) * LLCriticalDamp::getInterpolant(mBehindnessLag); cam_position = focus + horizontalSubjectBack * (slerp(fraction, camera_offset_rotation, LLQuaternion::DEFAULT)); cam_position.mV[VZ] = cameraZ; // clamp z value back to what it was before we started messing with it constraint_active = TRUE; } } return constraint_active; }
void LLAudioEngine_OpenAL::updateWind(LLVector3 wind_vec, F32 camera_altitude) { LLVector3 wind_pos; F64 pitch; F64 center_freq; ALenum error; if (!mEnableWind) return; if(!mWindBuf) return; if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) { // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) // need to convert this to the conventional orientation DS3D and OpenAL use // where +X = right, +Y = up, +Z = backwards wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); pitch = 1.0 + mapWindVecToPitch(wind_vec); center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0)); mWindGen->mTargetFreq = (F32)center_freq; mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); alSourcei(mWindSource, AL_LOOPING, AL_FALSE); alSource3f(mWindSource, AL_POSITION, 0.0, 0.0, 0.0); alSource3f(mWindSource, AL_VELOCITY, 0.0, 0.0, 0.0); alSourcef(mWindSource, AL_ROLLOFF_FACTOR, 0.0); alSourcei(mWindSource, AL_SOURCE_RELATIVE, AL_TRUE); } // ok lets make a wind buffer now int processed, queued, unprocessed; alGetSourcei(mWindSource, AL_BUFFERS_PROCESSED, &processed); alGetSourcei(mWindSource, AL_BUFFERS_QUEUED, &queued); unprocessed = queued - processed; // ensure that there are always at least 3x as many filled buffers // queued as we managed to empty since last time. mNumEmptyWindALBuffers = llmin(mNumEmptyWindALBuffers + processed * 3 - unprocessed, MAX_NUM_WIND_BUFFERS-unprocessed); mNumEmptyWindALBuffers = llmax(mNumEmptyWindALBuffers, 0); //LL_INFOS("OpenAL") << "mNumEmptyWindALBuffers: " << mNumEmptyWindALBuffers <<" (" << unprocessed << ":" << processed << ")" << LL_ENDL; while(processed--) // unqueue old buffers { ALuint buffer; int error; alGetError(); /* clear error */ alSourceUnqueueBuffers(mWindSource, 1, &buffer); error = alGetError(); if(error != AL_NO_ERROR) { LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::updateWind() error swapping (unqueuing) buffers" << LL_ENDL; } else { alDeleteBuffers(1, &buffer); } } unprocessed += mNumEmptyWindALBuffers; while (mNumEmptyWindALBuffers > 0) // fill+queue new buffers { ALuint buffer; alGetError(); /* clear error */ alGenBuffers(1,&buffer); if((error=alGetError()) != AL_NO_ERROR) { LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::initWind() Error creating wind buffer: " << error << LL_ENDL; break; } alBufferData(buffer, AL_FORMAT_STEREO16, mWindGen->windGenerate(mWindBuf, mWindBufSamples, 2), mWindBufBytes, mWindBufFreq); error = alGetError(); if(error != AL_NO_ERROR) LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::updateWind() error swapping (bufferdata) buffers" << LL_ENDL; alSourceQueueBuffers(mWindSource, 1, &buffer); error = alGetError(); if(error != AL_NO_ERROR) LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::updateWind() error swapping (queuing) buffers" << LL_ENDL; --mNumEmptyWindALBuffers; } int playing; alGetSourcei(mWindSource, AL_SOURCE_STATE, &playing); if(playing != AL_PLAYING) { alSourcePlay(mWindSource); LL_INFOS("OpenAL") << "Wind had stopped - probably ran out of buffers - restarting: " << (unprocessed+mNumEmptyWindALBuffers) << " now queued." << LL_ENDL; } }
//----------------------------------------------------------------------------- // LLEyeMotion::onUpdate() //----------------------------------------------------------------------------- BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask) { // Compute eye rotation. LLQuaternion target_eye_rot; LLVector3 eye_look_at; F32 vergence; //calculate jitter if (mEyeJitterTimer.getElapsedTimeF32() > mEyeJitterTime) { mEyeJitterTime = EYE_JITTER_MIN_TIME + ll_frand(EYE_JITTER_MAX_TIME - EYE_JITTER_MIN_TIME); mEyeJitterYaw = (ll_frand(2.f) - 1.f) * EYE_JITTER_MAX_YAW; mEyeJitterPitch = (ll_frand(2.f) - 1.f) * EYE_JITTER_MAX_PITCH; // make sure lookaway time count gets updated, because we're resetting the timer mEyeLookAwayTime -= llmax(0.f, mEyeJitterTimer.getElapsedTimeF32()); mEyeJitterTimer.reset(); } else if (mEyeJitterTimer.getElapsedTimeF32() > mEyeLookAwayTime) { if (ll_frand() > 0.1f) { // blink while moving eyes some percentage of the time mEyeBlinkTime = mEyeBlinkTimer.getElapsedTimeF32(); } if (mEyeLookAwayYaw == 0.f && mEyeLookAwayPitch == 0.f) { mEyeLookAwayYaw = (ll_frand(2.f) - 1.f) * EYE_LOOK_AWAY_MAX_YAW; mEyeLookAwayPitch = (ll_frand(2.f) - 1.f) * EYE_LOOK_AWAY_MAX_PITCH; mEyeLookAwayTime = EYE_LOOK_BACK_MIN_TIME + ll_frand(EYE_LOOK_BACK_MAX_TIME - EYE_LOOK_BACK_MIN_TIME); } else { mEyeLookAwayYaw = 0.f; mEyeLookAwayPitch = 0.f; mEyeLookAwayTime = EYE_LOOK_AWAY_MIN_TIME + ll_frand(EYE_LOOK_AWAY_MAX_TIME - EYE_LOOK_AWAY_MIN_TIME); } } // do blinking if (!mEyesClosed && mEyeBlinkTimer.getElapsedTimeF32() >= mEyeBlinkTime) { F32 leftEyeBlinkMorph = mEyeBlinkTimer.getElapsedTimeF32() - mEyeBlinkTime; F32 rightEyeBlinkMorph = leftEyeBlinkMorph - EYE_BLINK_TIME_DELTA; leftEyeBlinkMorph = llclamp(leftEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f); rightEyeBlinkMorph = llclamp(rightEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f); mCharacter->setVisualParamWeight("Blink_Left", leftEyeBlinkMorph); mCharacter->setVisualParamWeight("Blink_Right", rightEyeBlinkMorph); mCharacter->updateVisualParams(); if (rightEyeBlinkMorph == 1.f) { mEyesClosed = TRUE; mEyeBlinkTime = EYE_BLINK_CLOSE_TIME; mEyeBlinkTimer.reset(); } } else if (mEyesClosed) { if (mEyeBlinkTimer.getElapsedTimeF32() >= mEyeBlinkTime) { F32 leftEyeBlinkMorph = mEyeBlinkTimer.getElapsedTimeF32() - mEyeBlinkTime; F32 rightEyeBlinkMorph = leftEyeBlinkMorph - EYE_BLINK_TIME_DELTA; leftEyeBlinkMorph = 1.f - llclamp(leftEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f); rightEyeBlinkMorph = 1.f - llclamp(rightEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f); mCharacter->setVisualParamWeight("Blink_Left", leftEyeBlinkMorph); mCharacter->setVisualParamWeight("Blink_Right", rightEyeBlinkMorph); mCharacter->updateVisualParams(); if (rightEyeBlinkMorph == 0.f) { mEyesClosed = FALSE; mEyeBlinkTime = EYE_BLINK_MIN_TIME + ll_frand(EYE_BLINK_MAX_TIME - EYE_BLINK_MIN_TIME); mEyeBlinkTimer.reset(); } } } BOOL has_eye_target = FALSE; LLVector3* targetPos = (LLVector3*)mCharacter->getAnimationData("LookAtPoint"); if (targetPos) { LLVector3 skyward(0.f, 0.f, 1.f); LLVector3 left; LLVector3 up; eye_look_at = *targetPos; has_eye_target = TRUE; F32 lookAtDistance = eye_look_at.normVec(); left.setVec(skyward % eye_look_at); up.setVec(eye_look_at % left); target_eye_rot = LLQuaternion(eye_look_at, left, up); // convert target rotation to head-local coordinates target_eye_rot *= ~mHeadJoint->getWorldRotation(); // eliminate any Euler roll - we're lucky that roll is applied last. F32 roll, pitch, yaw; target_eye_rot.getEulerAngles(&roll, &pitch, &yaw); target_eye_rot.setQuat(0.0f, pitch, yaw); // constrain target orientation to be in front of avatar's face target_eye_rot.constrain(EYE_ROT_LIMIT_ANGLE); // calculate vergence F32 interocular_dist = (mLeftEyeState->getJoint()->getWorldPosition() - mRightEyeState->getJoint()->getWorldPosition()).magVec(); vergence = -atan2((interocular_dist / 2.f), lookAtDistance); llclamp(vergence, -F_PI_BY_TWO, 0.f); } else { target_eye_rot = LLQuaternion::DEFAULT; vergence = 0.f; } //RN: subtract 4 degrees to account for foveal angular offset relative to pupil vergence += 4.f * DEG_TO_RAD; // calculate eye jitter LLQuaternion eye_jitter_rot; // vergence not too high... if (vergence > -0.05f) { //...go ahead and jitter eye_jitter_rot.setQuat(0.f, mEyeJitterPitch + mEyeLookAwayPitch, mEyeJitterYaw + mEyeLookAwayYaw); } else { //...or don't eye_jitter_rot.loadIdentity(); } // calculate vergence of eyes as an object gets closer to the avatar's head LLQuaternion vergence_quat; if (has_eye_target) { vergence_quat.setQuat(vergence, LLVector3(0.f, 0.f, 1.f)); } else { vergence_quat.loadIdentity(); } // calculate eye rotations LLQuaternion left_eye_rot = target_eye_rot; left_eye_rot = vergence_quat * eye_jitter_rot * left_eye_rot; LLQuaternion right_eye_rot = target_eye_rot; vergence_quat.transQuat(); right_eye_rot = vergence_quat * eye_jitter_rot * right_eye_rot; //if in appearance, set the eyes straight forward if(mCharacter->getAppearanceFlag()) // no idea why this variable is reversed { LLVector3 forward(1.f, 0.0, 0.0); LLVector3 left; LLVector3 up; left.setVec(forward % forward); up.setVec(forward % left); target_eye_rot = LLQuaternion(forward, left, up); mLeftEyeState->setRotation( target_eye_rot ); mRightEyeState->setRotation( target_eye_rot ); return TRUE; } mLeftEyeState->setRotation( left_eye_rot ); mRightEyeState->setRotation( right_eye_rot ); return TRUE; }
//----------------------------------------------------------------------------- // LLEditingMotion::onUpdate() //----------------------------------------------------------------------------- BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask) { LLVector3 focus_pt; LLVector3* pointAtPt = (LLVector3*)mCharacter->getAnimationData("PointAtPoint"); BOOL result = TRUE; if (!pointAtPt) { focus_pt = mLastSelectPt; result = FALSE; } else { focus_pt = *pointAtPt; mLastSelectPt = focus_pt; } focus_pt += mCharacter->getCharacterPosition(); // propagate joint positions to kinematic chain mParentJoint.setPosition( mParentState->getJoint()->getWorldPosition() ); mShoulderJoint.setPosition( mShoulderState->getJoint()->getPosition() ); mElbowJoint.setPosition( mElbowState->getJoint()->getPosition() ); mWristJoint.setPosition( mWristState->getJoint()->getPosition() + mWristOffset ); // propagate current joint rotations to kinematic chain mParentJoint.setRotation( mParentState->getJoint()->getWorldRotation() ); mShoulderJoint.setRotation( mShoulderState->getJoint()->getRotation() ); mElbowJoint.setRotation( mElbowState->getJoint()->getRotation() ); // update target position from character LLVector3 target = focus_pt - mParentJoint.getPosition(); F32 target_dist = target.normVec(); LLVector3 edit_plane_normal(1.f / F_SQRT2, 1.f / F_SQRT2, 0.f); edit_plane_normal.normVec(); edit_plane_normal.rotVec(mTorsoState->getJoint()->getWorldRotation()); F32 dot = edit_plane_normal * target; if (dot < 0.f) { target = target + (edit_plane_normal * (dot * 2.f)); target.mV[VZ] += clamp_rescale(dot, 0.f, -1.f, 0.f, 5.f); target.normVec(); } target = target * target_dist; if (!target.isFinite()) { LL_WARNS() << "Non finite target in editing motion with target distance of " << target_dist << " and focus point " << focus_pt << " and pointAtPt: "; if (pointAtPt) { LL_CONT << *pointAtPt; } else { LL_CONT << "NULL"; } LL_CONT << LL_ENDL; target.setVec(1.f, 1.f, 1.f); } mTarget.setPosition( target + mParentJoint.getPosition()); // LL_INFOS() << "Point At: " << mTarget.getPosition() << LL_ENDL; // update the ikSolver if (!mTarget.getPosition().isExactlyZero()) { LLQuaternion shoulderRot = mShoulderJoint.getRotation(); LLQuaternion elbowRot = mElbowJoint.getRotation(); mIKSolver.solve(); // use blending... F32 slerp_amt = LLSmoothInterpolation::getInterpolant(TARGET_LAG_HALF_LIFE); shoulderRot = slerp(slerp_amt, mShoulderJoint.getRotation(), shoulderRot); elbowRot = slerp(slerp_amt, mElbowJoint.getRotation(), elbowRot); // now put blended values back into joints llassert(shoulderRot.isFinite()); llassert(elbowRot.isFinite()); mShoulderState->setRotation(shoulderRot); mElbowState->setRotation(elbowRot); mWristState->setRotation(LLQuaternion::DEFAULT); } mCharacter->setAnimationData("Hand Pose", &sHandPose); mCharacter->setAnimationData("Hand Pose Priority", &sHandPosePriority); return result; }
// Takes a line defined by "point_a" and "point_b" and determines the closest (to point_a) // point where the the line intersects an object or the land surface. Stores the results // in "intersection" and "intersection_normal" and returns a scalar value that represents // the normalized distance along the line from "point_a" to "intersection". // // Currently assumes point_a and point_b only differ in z-direction, // but it may eventually become more general. F32 LLWorld::resolveStepHeightGlobal(const LLVOAvatar* avatarp, const LLVector3d &point_a, const LLVector3d &point_b, LLVector3d &intersection, LLVector3 &intersection_normal, LLViewerObject **viewerObjectPtr) { // initialize return value to null if (viewerObjectPtr) { *viewerObjectPtr = NULL; } LLViewerRegion *regionp = getRegionFromPosGlobal(point_a); if (!regionp) { // We're outside the world intersection = 0.5f * (point_a + point_b); intersection_normal.setVec(0.0f, 0.0f, 1.0f); return 0.5f; } // calculate the length of the segment F32 segment_length = (F32)((point_a - point_b).length()); if (0.0f == segment_length) { intersection = point_a; intersection_normal.setVec(0.0f, 0.0f, 1.0f); return segment_length; } // get land height // Note: we assume that the line is parallel to z-axis here LLVector3d land_intersection = point_a; F32 normalized_land_distance; land_intersection.mdV[VZ] = regionp->getLand().resolveHeightGlobal(point_a); normalized_land_distance = (F32)(point_a.mdV[VZ] - land_intersection.mdV[VZ]) / segment_length; intersection = land_intersection; intersection_normal = resolveLandNormalGlobal(land_intersection); if (avatarp && !avatarp->mFootPlane.isExactlyClear()) { LLVector3 foot_plane_normal(avatarp->mFootPlane.mV); LLVector3 start_pt = avatarp->getRegion()->getPosRegionFromGlobal(point_a); // added 0.05 meters to compensate for error in foot plane reported by Havok F32 norm_dist_from_plane = ((start_pt * foot_plane_normal) - avatarp->mFootPlane.mV[VW]) + 0.05f; norm_dist_from_plane = llclamp(norm_dist_from_plane / segment_length, 0.f, 1.f); if (norm_dist_from_plane < normalized_land_distance) { // collided with object before land normalized_land_distance = norm_dist_from_plane; intersection = point_a; intersection.mdV[VZ] -= norm_dist_from_plane * segment_length; intersection_normal = foot_plane_normal; } else { intersection = land_intersection; intersection_normal = resolveLandNormalGlobal(land_intersection); } } return normalized_land_distance; }
//--------------------------------------------------------------------------------------------------------- void LLFollowCam::update() { //#################################################################################### // update Focus //#################################################################################### LLVector3 offsetSubjectPosition = mSubjectPosition + (mFocusOffset * mSubjectRotation); LLVector3 simulated_pos_agent = gAgent.getPosAgentFromGlobal(mSimulatedPositionGlobal); LLVector3 vectorFromCameraToSubject = offsetSubjectPosition - simulated_pos_agent; F32 distanceFromCameraToSubject = vectorFromCameraToSubject.magVec(); LLVector3 whereFocusWantsToBe = mFocus; LLVector3 focus_pt_agent = gAgent.getPosAgentFromGlobal(mSimulatedFocusGlobal); if ( mFocusLocked ) // if focus is locked, only relative focus needs to be updated { mRelativeFocus = (focus_pt_agent - mSubjectPosition) * ~mSubjectRotation; } else { LLVector3 focusOffset = offsetSubjectPosition - focus_pt_agent; F32 focusOffsetDistance = focusOffset.magVec(); LLVector3 focusOffsetDirection = focusOffset / focusOffsetDistance; whereFocusWantsToBe = focus_pt_agent + (focusOffsetDirection * (focusOffsetDistance - mFocusThreshold)); if ( focusOffsetDistance > mFocusThreshold ) { // this version normalizes focus threshold by distance // so that the effect is not changed with distance /* F32 focusThresholdNormalizedByDistance = distanceFromCameraToSubject * mFocusThreshold; if ( focusOffsetDistance > focusThresholdNormalizedByDistance ) { LLVector3 focusOffsetDirection = focusOffset / focusOffsetDistance; F32 force = focusOffsetDistance - focusThresholdNormalizedByDistance; */ F32 focusLagLerp = LLCriticalDamp::getInterpolant( mFocusLag ); focus_pt_agent = lerp( focus_pt_agent, whereFocusWantsToBe, focusLagLerp ); mSimulatedFocusGlobal = gAgent.getPosGlobalFromAgent(focus_pt_agent); } mRelativeFocus = lerp(mRelativeFocus, (focus_pt_agent - mSubjectPosition) * ~mSubjectRotation, LLCriticalDamp::getInterpolant(0.05f)); }// if focus is not locked --------------------------------------------- LLVector3 whereCameraPositionWantsToBe = gAgent.getPosAgentFromGlobal(mSimulatedPositionGlobal); if ( mPositionLocked ) { mRelativePos = (whereCameraPositionWantsToBe - mSubjectPosition) * ~mSubjectRotation; } else { //#################################################################################### // update Position //#################################################################################### //------------------------------------------------------------------------- // I determine the horizontal vector from the camera to the subject //------------------------------------------------------------------------- LLVector3 horizontalVectorFromCameraToSubject = vectorFromCameraToSubject; horizontalVectorFromCameraToSubject.mV[VZ] = 0.0f; //--------------------------------------------------------- // Now I determine the horizontal distance //--------------------------------------------------------- F32 horizontalDistanceFromCameraToSubject = horizontalVectorFromCameraToSubject.magVec(); //--------------------------------------------------------- // Then I get the (normalized) horizontal direction... //--------------------------------------------------------- LLVector3 horizontalDirectionFromCameraToSubject; if ( horizontalDistanceFromCameraToSubject < DISTANCE_EPSILON ) { // make sure we still have a normalized vector if distance is really small // (this case is rare and fleeting) horizontalDirectionFromCameraToSubject = LLVector3::z_axis; } else { // I'm not using the "normalize" method, because I can just divide by horizontalDistanceFromCameraToSubject horizontalDirectionFromCameraToSubject = horizontalVectorFromCameraToSubject / horizontalDistanceFromCameraToSubject; } //------------------------------------------------------------------------------------------------------------ // Here is where I determine an offset relative to subject position in oder to set the ideal position. //------------------------------------------------------------------------------------------------------------ if ( mPitchSineAndCosineNeedToBeUpdated ) { calculatePitchSineAndCosine(); mPitchSineAndCosineNeedToBeUpdated = false; } LLVector3 positionOffsetFromSubject; positionOffsetFromSubject.setVec ( horizontalDirectionFromCameraToSubject.mV[ VX ] * mPitchCos, horizontalDirectionFromCameraToSubject.mV[ VY ] * mPitchCos, -mPitchSin ); positionOffsetFromSubject *= mSimulatedDistance; //---------------------------------------------------------------------- // Finally, ideal position is set by taking the subject position and // extending the positionOffsetFromSubject from that //---------------------------------------------------------------------- LLVector3 idealCameraPosition = offsetSubjectPosition - positionOffsetFromSubject; //-------------------------------------------------------------------------------- // Now I prepare to move the current camera position towards its ideal position... //-------------------------------------------------------------------------------- LLVector3 vectorFromPositionToIdealPosition = idealCameraPosition - simulated_pos_agent; F32 distanceFromPositionToIdealPosition = vectorFromPositionToIdealPosition.magVec(); //put this inside of the block? LLVector3 normalFromPositionToIdealPosition = vectorFromPositionToIdealPosition / distanceFromPositionToIdealPosition; whereCameraPositionWantsToBe = simulated_pos_agent + (normalFromPositionToIdealPosition * (distanceFromPositionToIdealPosition - mPositionThreshold)); //------------------------------------------------------------------------------------------------- // The following method takes the target camera position and resets it so that it stays "behind" the subject, // using behindness angle and behindness force as parameters affecting the exact behavior //------------------------------------------------------------------------------------------------- if ( distanceFromPositionToIdealPosition > mPositionThreshold ) { F32 positionPullLerp = LLCriticalDamp::getInterpolant( mPositionLag ); simulated_pos_agent = lerp( simulated_pos_agent, whereCameraPositionWantsToBe, positionPullLerp ); } //-------------------------------------------------------------------- // don't let the camera get farther than its official max distance //-------------------------------------------------------------------- if ( distanceFromCameraToSubject > mMaxCameraDistantFromSubject ) { LLVector3 directionFromCameraToSubject = vectorFromCameraToSubject / distanceFromCameraToSubject; simulated_pos_agent = offsetSubjectPosition - directionFromCameraToSubject * mMaxCameraDistantFromSubject; } ////------------------------------------------------------------------------------------------------- //// The following method takes mSimulatedPositionGlobal and resets it so that it stays "behind" the subject, //// using behindness angle and behindness force as parameters affecting the exact behavior ////------------------------------------------------------------------------------------------------- updateBehindnessConstraint(gAgent.getPosAgentFromGlobal(mSimulatedFocusGlobal), simulated_pos_agent); mSimulatedPositionGlobal = gAgent.getPosGlobalFromAgent(simulated_pos_agent); mRelativePos = lerp(mRelativePos, (simulated_pos_agent - mSubjectPosition) * ~mSubjectRotation, LLCriticalDamp::getInterpolant(0.05f)); } // if position is not locked ----------------------------------------------------------- //#################################################################################### // update UpVector //#################################################################################### // this just points upward for now, but I anticipate future effects requiring // some rolling ("banking" effects for fun, swoopy vehicles, etc.) mUpVector = LLVector3::z_axis; }
//----------------------------------------------------------------------------- // LLWalkAdjustMotion::onUpdate() //----------------------------------------------------------------------------- BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask) { LLVector3 footCorrection; LLVector3 vel = mCharacter->getCharacterVelocity() * mCharacter->getTimeDilation(); F32 deltaTime = llclamp(time - mLastTime, 0.f, MAX_TIME_DELTA); mLastTime = time; LLQuaternion inv_rotation = ~mPelvisJoint->getWorldRotation(); // get speed and normalize velocity vector LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation(); F32 speed = llmin(vel.normVec(), MAX_WALK_PLAYBACK_SPEED); mAvgSpeed = lerp(mAvgSpeed, speed, LLCriticalDamp::getInterpolant(0.2f)); // calculate facing vector in pelvis-local space // (either straight forward or back, depending on velocity) LLVector3 localVel = vel * inv_rotation; if (localVel.mV[VX] > 0.f) { mRelativeDir = 1.f; } else if (localVel.mV[VX] < 0.f) { mRelativeDir = -1.f; } // calculate world-space foot drift LLVector3 leftFootDelta; LLVector3 leftFootWorldPosition = mLeftAnkleJoint->getWorldPosition(); LLVector3d leftFootGlobalPosition = mCharacter->getPosGlobalFromAgent(leftFootWorldPosition); leftFootDelta.setVec(mLastLeftAnklePos - leftFootGlobalPosition); mLastLeftAnklePos = leftFootGlobalPosition; LLVector3 rightFootDelta; LLVector3 rightFootWorldPosition = mRightAnkleJoint->getWorldPosition(); LLVector3d rightFootGlobalPosition = mCharacter->getPosGlobalFromAgent(rightFootWorldPosition); rightFootDelta.setVec(mLastRightAnklePos - rightFootGlobalPosition); mLastRightAnklePos = rightFootGlobalPosition; // find foot drift along velocity vector if (mAvgSpeed > 0.1) { // walking/running F32 leftFootDriftAmt = leftFootDelta * vel; F32 rightFootDriftAmt = rightFootDelta * vel; if (rightFootDriftAmt > leftFootDriftAmt) { footCorrection = rightFootDelta; } else { footCorrection = leftFootDelta; } } else { mAvgSpeed = ang_vel.magVec() * mAnkleOffset; mRelativeDir = 1.f; // standing/turning // find the lower foot if (leftFootWorldPosition.mV[VZ] < rightFootWorldPosition.mV[VZ]) { // pivot on left foot footCorrection = leftFootDelta; } else { // pivot on right foot footCorrection = rightFootDelta; } } // rotate into avatar coordinates footCorrection = footCorrection * inv_rotation; // calculate ideal pelvis offset so that foot is glued to ground and damp towards it // the amount of foot slippage this frame + the offset applied last frame mPelvisOffset = mPelvisState->getPosition() + lerp(LLVector3::zero, footCorrection, LLCriticalDamp::getInterpolant(0.2f)); // pelvis drift (along walk direction) mAvgCorrection = lerp(mAvgCorrection, footCorrection.mV[VX] * mRelativeDir, LLCriticalDamp::getInterpolant(0.1f)); // calculate average velocity of foot slippage F32 footSlipVelocity = (deltaTime != 0.f) ? (-mAvgCorrection / deltaTime) : 0.f; F32 newSpeedAdjust = 0.f; // modulate speed by dot products of facing and velocity // so that if we are moving sideways, we slow down the animation // and if we're moving backward, we walk backward F32 directional_factor = localVel.mV[VX] * mRelativeDir; if (speed > 0.1f) { // calculate ratio of desired foot velocity to detected foot velocity newSpeedAdjust = llclamp(footSlipVelocity - mAvgSpeed * (1.f - directional_factor), -SPEED_ADJUST_MAX, SPEED_ADJUST_MAX); newSpeedAdjust = lerp(mSpeedAdjust, newSpeedAdjust, LLCriticalDamp::getInterpolant(0.2f)); F32 speedDelta = newSpeedAdjust - mSpeedAdjust; speedDelta = llclamp(speedDelta, -SPEED_ADJUST_MAX_SEC * deltaTime, SPEED_ADJUST_MAX_SEC * deltaTime); mSpeedAdjust = mSpeedAdjust + speedDelta; } else { mSpeedAdjust = lerp(mSpeedAdjust, 0.f, LLCriticalDamp::getInterpolant(0.2f)); } mAnimSpeed = (mAvgSpeed + mSpeedAdjust) * mRelativeDir; // char debug_text[64]; // sprintf(debug_text, "Foot slip vel: %.2f", footSlipVelocity); // mCharacter->addDebugText(debug_text); // sprintf(debug_text, "Speed: %.2f", mAvgSpeed); // mCharacter->addDebugText(debug_text); // sprintf(debug_text, "Speed Adjust: %.2f", mSpeedAdjust); // mCharacter->addDebugText(debug_text); // sprintf(debug_text, "Animation Playback Speed: %.2f", mAnimSpeed); // mCharacter->addDebugText(debug_text); mCharacter->setAnimationData("Walk Speed", &mAnimSpeed); // clamp pelvis offset to a 90 degree arc behind the nominal position F32 drift_comp_max = llclamp(speed, 0.f, DRIFT_COMP_MAX_SPEED) / DRIFT_COMP_MAX_SPEED; drift_comp_max *= DRIFT_COMP_MAX_TOTAL; LLVector3 currentPelvisPos = mPelvisState->getJoint()->getPosition(); // NB: this is an ADDITIVE amount that is accumulated every frame, so clamping it alone won't do the trick // must clamp with absolute position of pelvis in mind mPelvisOffset.mV[VX] = llclamp( mPelvisOffset.mV[VX], -drift_comp_max - currentPelvisPos.mV[VX], drift_comp_max - currentPelvisPos.mV[VX] ); mPelvisOffset.mV[VY] = llclamp( mPelvisOffset.mV[VY], -drift_comp_max - currentPelvisPos.mV[VY], drift_comp_max - currentPelvisPos.mV[VY]); mPelvisOffset.mV[VZ] = 0.f; // set position mPelvisState->setPosition(mPelvisOffset); mCharacter->setAnimationData("Pelvis Offset", &mPelvisOffset); return TRUE; }
BOOL ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation, LLVector3 &intersection, LLVector3 &intersection_normal) { // calculate the centers of the cylinder caps in the absolute frame LLVector3 cyl_top(0.0f, 0.0f, 0.5f * cyl_scale.mV[VZ]); LLVector3 cyl_bottom(0.0f, 0.0f, -cyl_top.mV[VZ]); cyl_top = (cyl_top * cyl_rotation) + cyl_center; cyl_bottom = (cyl_bottom * cyl_rotation) + cyl_center; // we only handle cylinders with circular cross-sections at the moment F32 cyl_radius = 0.5f * llmax(cyl_scale.mV[VX], cyl_scale.mV[VY]); // HACK until scaled cylinders are supported // This implementation is based on the intcyl() function from Graphics_Gems_IV, page 361 LLVector3 cyl_axis; // axis direction (bottom toward top) LLVector3 ray_to_cyl; // ray_point to cyl_top F32 shortest_distance; // shortest distance from ray to axis F32 cyl_length; LLVector3 shortest_direction; LLVector3 temp_vector; cyl_axis = cyl_bottom - cyl_top; cyl_length = cyl_axis.normVec(); ray_to_cyl = ray_point - cyl_bottom; shortest_direction = ray_direction % cyl_axis; shortest_distance = shortest_direction.normVec(); // recycle shortest_distance // check for ray parallel to cylinder axis if (0.0f == shortest_distance) { // ray is parallel to cylinder axis temp_vector = ray_to_cyl - (ray_to_cyl * cyl_axis) * cyl_axis; shortest_distance = temp_vector.magVec(); if (shortest_distance <= cyl_radius) { shortest_distance = ray_to_cyl * cyl_axis; F32 dot = ray_direction * cyl_axis; if (shortest_distance > 0.0) { if (dot > 0.0f) { // ray points away from cylinder bottom return FALSE; } // ray hit bottom of cylinder from outside intersection = ray_point - shortest_distance * cyl_axis; intersection_normal = cyl_axis; } else if (shortest_distance > -cyl_length) { // ray starts inside cylinder if (dot < 0.0f) { // ray hit top from inside intersection = ray_point - (cyl_length + shortest_distance) * cyl_axis; intersection_normal = -cyl_axis; } else { // ray hit bottom from inside intersection = ray_point - shortest_distance * cyl_axis; intersection_normal = cyl_axis; } } else { if (dot < 0.0f) { // ray points away from cylinder bottom return FALSE; } // ray hit top from outside intersection = ray_point - (shortest_distance + cyl_length) * cyl_axis; intersection_normal = -cyl_axis; } return TRUE; } return FALSE; } // check for intersection with infinite cylinder shortest_distance = (F32) fabs(ray_to_cyl * shortest_direction); if (shortest_distance <= cyl_radius) { F32 dist_to_closest_point; // dist from ray_point to closest_point F32 half_chord_length; // half length of intersection chord F32 in, out; // distances to entering/exiting points temp_vector = ray_to_cyl % cyl_axis; dist_to_closest_point = - (temp_vector * shortest_direction); temp_vector = shortest_direction % cyl_axis; temp_vector.normVec(); half_chord_length = (F32) fabs( sqrt(cyl_radius*cyl_radius - shortest_distance * shortest_distance) / (ray_direction * temp_vector) ); out = dist_to_closest_point + half_chord_length; // dist to exiting point if (out < 0.0f) { // cylinder is behind the ray, so we return FALSE return FALSE; } in = dist_to_closest_point - half_chord_length; // dist to entering point if (in < 0.0f) { // ray_point is inside the cylinder // so we store the exiting intersection intersection = ray_point + out * ray_direction; shortest_distance = out; } else { // ray hit cylinder from outside // so we store the entering intersection intersection = ray_point + in * ray_direction; shortest_distance = in; } // calculate the normal at intersection if (0.0f == cyl_radius) { intersection_normal.setVec(0.0f, 0.0f, 0.0f); } else { temp_vector = intersection - cyl_bottom; intersection_normal = temp_vector - (temp_vector * cyl_axis) * cyl_axis; intersection_normal.normVec(); } // check for intersection with end caps // calculate intersection of ray and top plane if (line_plane(ray_point, ray_direction, cyl_top, -cyl_axis, temp_vector)) // NOTE side-effect: changing temp_vector { shortest_distance = (temp_vector - ray_point).magVec(); if ( (ray_direction * cyl_axis) > 0.0f) { // ray potentially enters the cylinder at top if (shortest_distance > out) { // ray missed the finite cylinder return FALSE; } if (shortest_distance > in) { // ray intersects cylinder at top plane intersection = temp_vector; intersection_normal = -cyl_axis; return TRUE; } } else { // ray potentially exits the cylinder at top if (shortest_distance < in) { // missed the finite cylinder return FALSE; } } // calculate intersection of ray and bottom plane line_plane(ray_point, ray_direction, cyl_bottom, cyl_axis, temp_vector); // NOTE side-effect: changing temp_vector shortest_distance = (temp_vector - ray_point).magVec(); if ( (ray_direction * cyl_axis) < 0.0) { // ray potentially enters the cylinder at bottom if (shortest_distance > out) { // ray missed the finite cylinder return FALSE; } if (shortest_distance > in) { // ray intersects cylinder at bottom plane intersection = temp_vector; intersection_normal = cyl_axis; return TRUE; } } else { // ray potentially exits the cylinder at bottom if (shortest_distance < in) { // ray missed the finite cylinder return FALSE; } } } else { // ray is parallel to end cap planes temp_vector = cyl_bottom - ray_point; shortest_distance = temp_vector * cyl_axis; if (shortest_distance < 0.0f || shortest_distance > cyl_length) { // ray missed finite cylinder return FALSE; } } return TRUE; } return FALSE; }
BOOL LLVOTree::updateGeometry(LLDrawable *drawable) { LLFastTimer ftm(LLFastTimer::FTM_UPDATE_TREE); const F32 SRR3 = 0.577350269f; // sqrt(1/3) const F32 SRR2 = 0.707106781f; // sqrt(1/2) U32 i, j; U32 slices = MAX_SLICES; S32 max_indices = LEAF_INDICES; S32 max_vertices = LEAF_VERTICES; S32 lod; LLFace *face = drawable->getFace(0); face->mCenterAgent = getPositionAgent(); face->mCenterLocal = face->mCenterAgent; for (lod = 0; lod < 4; lod++) { slices = sLODSlices[lod]; sLODVertexOffset[lod] = max_vertices; sLODVertexCount[lod] = slices*slices; sLODIndexOffset[lod] = max_indices; sLODIndexCount[lod] = (slices-1)*(slices-1)*6; max_indices += sLODIndexCount[lod]; max_vertices += sLODVertexCount[lod]; } LLStrider<LLVector3> vertices; LLStrider<LLVector3> normals; LLStrider<LLVector2> tex_coords; LLStrider<U16> indicesp; face->setSize(max_vertices, max_indices); face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); face->mVertexBuffer->allocateBuffer(max_vertices, max_indices, TRUE); face->setGeomIndex(0); face->setIndicesIndex(0); face->getGeometry(vertices, normals, tex_coords, indicesp); S32 vertex_count = 0; S32 index_count = 0; // First leaf *(normals++) = LLVector3(-SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f); vertex_count++; *(normals++) = LLVector3(SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f); vertex_count++; *(normals++) = LLVector3(-SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f); vertex_count++; *(normals++) = LLVector3(SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f); vertex_count++; *(indicesp++) = 0; index_count++; *(indicesp++) = 1; index_count++; *(indicesp++) = 2; index_count++; *(indicesp++) = 0; index_count++; *(indicesp++) = 3; index_count++; *(indicesp++) = 1; index_count++; // Same leaf, inverse winding/normals *(normals++) = LLVector3(-SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f); vertex_count++; *(normals++) = LLVector3(SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f); vertex_count++; *(normals++) = LLVector3(-SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f); vertex_count++; *(normals++) = LLVector3(SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f); vertex_count++; *(indicesp++) = 4; index_count++; *(indicesp++) = 6; index_count++; *(indicesp++) = 5; index_count++; *(indicesp++) = 4; index_count++; *(indicesp++) = 5; index_count++; *(indicesp++) = 7; index_count++; // next leaf *(normals++) = LLVector3(SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f); vertex_count++; *(normals++) = LLVector3(SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f); vertex_count++; *(normals++) = LLVector3(SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f); vertex_count++; *(normals++) = LLVector3(SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f); vertex_count++; *(indicesp++) = 8; index_count++; *(indicesp++) = 9; index_count++; *(indicesp++) = 10; index_count++; *(indicesp++) = 8; index_count++; *(indicesp++) = 11; index_count++; *(indicesp++) = 9; index_count++; // other side of same leaf *(normals++) = LLVector3(-SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f); vertex_count++; *(normals++) = LLVector3(-SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f); vertex_count++; *(normals++) = LLVector3(-SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f); vertex_count++; *(normals++) = LLVector3(-SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f); vertex_count++; *(indicesp++) = 12; index_count++; *(indicesp++) = 14; index_count++; *(indicesp++) = 13; index_count++; *(indicesp++) = 12; index_count++; *(indicesp++) = 13; index_count++; *(indicesp++) = 15; index_count++; // Generate geometry for the cylinders // Different LOD's // Generate the vertices // Generate the indices for (lod = 0; lod < 4; lod++) { slices = sLODSlices[lod]; F32 base_radius = 0.65f; F32 top_radius = base_radius * sSpeciesTable[mSpecies]->mTaper; //llinfos << "Species " << ((U32) mSpecies) << ", taper = " << sSpeciesTable[mSpecies].mTaper << llendl; //llinfos << "Droop " << mDroop << ", branchlength: " << mBranchLength << llendl; F32 angle = 0; F32 angle_inc = 360.f/(slices-1); F32 z = 0.f; F32 z_inc = 1.f; if (slices > 3) { z_inc = 1.f/(slices - 3); } F32 radius = base_radius; F32 x1,y1; F32 noise_scale = sSpeciesTable[mSpecies]->mNoiseMag; LLVector3 nvec; const F32 cap_nudge = 0.1f; // Height to 'peak' the caps on top/bottom of branch const S32 fractal_depth = 5; F32 nvec_scale = 1.f * sSpeciesTable[mSpecies]->mNoiseScale; F32 nvec_scalez = 4.f * sSpeciesTable[mSpecies]->mNoiseScale; F32 tex_z_repeat = sSpeciesTable[mSpecies]->mRepeatTrunkZ; F32 start_radius; F32 nangle = 0; F32 height = 1.f; F32 r0; for (i = 0; i < slices; i++) { if (i == 0) { z = - cap_nudge; r0 = 0.0; } else if (i == (slices - 1)) { z = 1.f + cap_nudge;//((i - 2) * z_inc) + cap_nudge; r0 = 0.0; } else { z = (i - 1) * z_inc; r0 = base_radius + (top_radius - base_radius)*z; } for (j = 0; j < slices; j++) { if (slices - 1 == j) { angle = 0.f; } else { angle = j*angle_inc; } nangle = angle; x1 = cos(angle * DEG_TO_RAD); y1 = sin(angle * DEG_TO_RAD); LLVector2 tc; // This isn't totally accurate. Should compute based on slope as well. start_radius = r0 * (1.f + 1.2f*fabs(z - 0.66f*height)/height); nvec.setVec( cos(nangle * DEG_TO_RAD)*start_radius*nvec_scale, sin(nangle * DEG_TO_RAD)*start_radius*nvec_scale, z*nvec_scalez); // First and last slice at 0 radius (to bring in top/bottom of structure) radius = start_radius + turbulence3((F32*)&nvec.mV, (F32)fractal_depth)*noise_scale; if (slices - 1 == j) { // Not 0.5 for slight slop factor to avoid edges on leaves tc = LLVector2(0.490f, (1.f - z/2.f)*tex_z_repeat); } else { tc = LLVector2((angle/360.f)*0.5f, (1.f - z/2.f)*tex_z_repeat); } *(vertices++) = LLVector3(x1*radius, y1*radius, z); *(normals++) = LLVector3(x1, y1, 0.f); *(tex_coords++) = tc; vertex_count++; } } for (i = 0; i < (slices - 1); i++) { for (j = 0; j < (slices - 1); j++) { S32 x1_offset = j+1; if ((j+1) == slices) { x1_offset = 0; } // Generate the matching quads *(indicesp) = j + (i*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; *(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; *(indicesp) = j + ((i+1)*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; *(indicesp) = j + (i*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; *(indicesp) = x1_offset + (i*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; *(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; } } slices /= 2; } face->mVertexBuffer->setBuffer(0); llassert(vertex_count == max_vertices); llassert(index_count == max_indices); return TRUE; }
BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics ) { LLVector3 ray_start_region; LLVector3 ray_end_region; LLViewerRegion* regionp = NULL; BOOL b_hit_land = FALSE; S32 hit_face = -1; LLViewerObject* hit_obj = NULL; U8 state = 0; BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); if( !success ) { return FALSE; } if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) { // Can't create objects on avatars or attachments return FALSE; } if (NULL == regionp) { llwarns << "regionp was NULL; aborting function." << llendl; return FALSE; } if (regionp->getRegionFlags() & REGION_FLAGS_SANDBOX) { LLFirstUse::useSandbox(); } // Set params for new object based on its PCode. LLQuaternion rotation; LLVector3 scale = LLVector3( gSavedSettings.getF32("EmeraldBuildPrefs_Xsize"), gSavedSettings.getF32("EmeraldBuildPrefs_Ysize"), gSavedSettings.getF32("EmeraldBuildPrefs_Zsize")); U8 material = LL_MCODE_WOOD; if(gSavedSettings.getString("EmeraldBuildPrefs_Material")== "Stone") material = LL_MCODE_STONE; if(gSavedSettings.getString("EmeraldBuildPrefs_Material")== "Metal") material = LL_MCODE_METAL; if(gSavedSettings.getString("EmeraldBuildPrefs_Material")== "Wood") material = LL_MCODE_WOOD; if(gSavedSettings.getString("EmeraldBuildPrefs_Material")== "Flesh") material = LL_MCODE_FLESH; if(gSavedSettings.getString("EmeraldBuildPrefs_Material")== "Rubber") material = LL_MCODE_RUBBER; if(gSavedSettings.getString("EmeraldBuildPrefs_Material")== "Plastic") material = LL_MCODE_PLASTIC; BOOL create_selected = FALSE; LLVolumeParams volume_params; switch (pcode) { case LL_PCODE_LEGACY_GRASS: // Randomize size of grass patch scale.setVec(10.f + ll_frand(20.f), 10.f + ll_frand(20.f), 1.f + ll_frand(2.f)); state = rand() % LLVOGrass::sMaxGrassSpecies; break; case LL_PCODE_LEGACY_TREE: case LL_PCODE_TREE_NEW: state = rand() % LLVOTree::sMaxTreeSpecies; break; case LL_PCODE_SPHERE: case LL_PCODE_CONE: case LL_PCODE_CUBE: case LL_PCODE_CYLINDER: case LL_PCODE_TORUS: case LLViewerObject::LL_VO_SQUARE_TORUS: case LLViewerObject::LL_VO_TRIANGLE_TORUS: default: create_selected = TRUE; break; } // Play creation sound if (gAudiop) { gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")), gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); } gMessageSystem->newMessageFast(_PREHASH_ObjectAdd); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); //MOYMOD 2009-05, If avatar is in land group/land owner group, // it rezzes it with it to prevent autoreturn/whatever if(gSavedSettings.getBOOL("mm_alwaysRezWithLandGroup")){ LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if(gAgent.isInGroup(parcel->getGroupID())){ gMessageSystem->addUUIDFast(_PREHASH_GroupID, parcel->getGroupID()); }else if(gAgent.isInGroup(parcel->getOwnerID())){ gMessageSystem->addUUIDFast(_PREHASH_GroupID, parcel->getOwnerID()); }else gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); }else gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); gMessageSystem->nextBlockFast(_PREHASH_ObjectData); gMessageSystem->addU8Fast(_PREHASH_Material, material); U32 flags = 0; // not selected if (use_physics || gSavedSettings.getBOOL("EmeraldBuildPrefs_Physical")) { flags |= FLAGS_USE_PHYSICS; } //if (create_selected) // [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0b) | Added: RLVa-1.0.0b if ( (create_selected) && (!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) ) // [/RLVa:KB] { flags |= FLAGS_CREATE_SELECTED; } gMessageSystem->addU32Fast(_PREHASH_AddFlags, flags ); LLPCode volume_pcode; // ...PCODE_VOLUME, or the original on error switch (pcode) { case LL_PCODE_SPHERE: rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 1, 1 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_TORUS: rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 1.f, 0.25f ); // "top size" volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LLViewerObject::LL_VO_SQUARE_TORUS: rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_CIRCLE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 1.f, 0.25f ); // "top size" volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LLViewerObject::LL_VO_TRIANGLE_TORUS: rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_CIRCLE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 1.f, 0.25f ); // "top size" volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_SPHERE_HEMI: volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); //volume_params.setBeginAndEndS( 0.5f, 1.f ); volume_params.setBeginAndEndT( 0.f, 0.5f ); volume_params.setRatio ( 1, 1 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_CUBE: volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 1, 1 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_PRISM: volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 0, 1 ); volume_params.setShear ( -0.5f, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_PYRAMID: volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 0, 0 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_TETRAHEDRON: volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 0, 0 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_CYLINDER: volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 1, 1 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_CYLINDER_HEMI: volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.25f, 0.75f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 1, 1 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_CONE: volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 0, 0 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_CONE_HEMI: volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.25f, 0.75f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 0, 0 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; default: LLVolumeMessage::packVolumeParams(0, gMessageSystem); volume_pcode = pcode; break; } gMessageSystem->addU8Fast(_PREHASH_PCode, volume_pcode); gMessageSystem->addVector3Fast(_PREHASH_Scale, scale ); gMessageSystem->addQuatFast(_PREHASH_Rotation, rotation ); gMessageSystem->addVector3Fast(_PREHASH_RayStart, ray_start_region ); gMessageSystem->addVector3Fast(_PREHASH_RayEnd, ray_end_region ); gMessageSystem->addU8Fast(_PREHASH_BypassRaycast, (U8)b_hit_land ); gMessageSystem->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)FALSE ); gMessageSystem->addU8Fast(_PREHASH_State, state); // Limit raycast to a single object. // Speeds up server raycast + avoid problems with server ray hitting objects // that were clipped by the near plane or culled on the viewer. LLUUID ray_target_id; if( hit_obj ) { ray_target_id = hit_obj->getID(); } else { ray_target_id.setNull(); } gMessageSystem->addUUIDFast(_PREHASH_RayTargetID, ray_target_id ); // Pack in name value pairs gMessageSystem->sendReliable(regionp->getHost()); //lgg set flag to set texture here gImportTracker.expectRez(); // Spawns a message, so must be after above send if (create_selected) { LLSelectMgr::getInstance()->deselectAll(); gViewerWindow->getWindow()->incBusyCount(); } // VEFFECT: AddObject LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE); effectp->setSourceObject((LLViewerObject*)gAgent.getAvatarObject()); effectp->setPositionGlobal(regionp->getPosGlobalFromRegion(ray_end_region)); effectp->setDuration(LL_HUD_DUR_SHORT); effectp->setColor(LLColor4U(gAgent.getEffectColor())); LLViewerStats::getInstance()->incStat(LLViewerStats::ST_CREATE_COUNT); return TRUE; }
BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics ) { LLVector3 ray_start_region; LLVector3 ray_end_region; LLViewerRegion* regionp = NULL; BOOL b_hit_land = FALSE; S32 hit_face = -1; LLViewerObject* hit_obj = NULL; U8 state = 0; BOOL success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, ®ionp ); if( !success ) { return FALSE; } if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) ) { // Can't create objects on avatars or attachments return FALSE; } if (NULL == regionp) { llwarns << "regionp was NULL; aborting function." << llendl; return FALSE; } if (regionp->getRegionFlags() & REGION_FLAGS_SANDBOX) { LLFirstUse::useSandbox(); } // Set params for new object based on its PCode. LLQuaternion rotation; LLVector3 scale = DEFAULT_OBJECT_SCALE; U8 material = LL_MCODE_WOOD; BOOL create_selected = FALSE; LLVolumeParams volume_params; switch (pcode) { case LL_PCODE_LEGACY_GRASS: // Randomize size of grass patch scale.setVec(10.f + ll_frand(20.f), 10.f + ll_frand(20.f), 1.f + ll_frand(2.f)); state = rand() % LLVOGrass::sMaxGrassSpecies; break; case LL_PCODE_LEGACY_TREE: case LL_PCODE_TREE_NEW: state = rand() % LLVOTree::sMaxTreeSpecies; break; case LL_PCODE_SPHERE: case LL_PCODE_CONE: case LL_PCODE_CUBE: case LL_PCODE_CYLINDER: case LL_PCODE_TORUS: case LLViewerObject::LL_VO_SQUARE_TORUS: case LLViewerObject::LL_VO_TRIANGLE_TORUS: default: create_selected = TRUE; break; } // Play creation sound if (gAudiop) { F32 volume = gSavedSettings.getBOOL("MuteUI") ? 0.f : gSavedSettings.getF32("AudioLevelUI"); gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")), gAgent.getID(), volume); } gMessageSystem->newMessageFast(_PREHASH_ObjectAdd); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); gMessageSystem->nextBlockFast(_PREHASH_ObjectData); gMessageSystem->addU8Fast(_PREHASH_Material, material); U32 flags = 0; // not selected if (use_physics) { flags |= FLAGS_USE_PHYSICS; } if (create_selected) { flags |= FLAGS_CREATE_SELECTED; } gMessageSystem->addU32Fast(_PREHASH_AddFlags, flags ); LLPCode volume_pcode; // ...PCODE_VOLUME, or the original on error switch (pcode) { case LL_PCODE_SPHERE: rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 1, 1 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_TORUS: rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 1.f, 0.25f ); // "top size" volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LLViewerObject::LL_VO_SQUARE_TORUS: rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_CIRCLE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 1.f, 0.25f ); // "top size" volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LLViewerObject::LL_VO_TRIANGLE_TORUS: rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_CIRCLE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 1.f, 0.25f ); // "top size" volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_SPHERE_HEMI: volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); //volume_params.setBeginAndEndS( 0.5f, 1.f ); volume_params.setBeginAndEndT( 0.f, 0.5f ); volume_params.setRatio ( 1, 1 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_CUBE: volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 1, 1 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_PRISM: volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 0, 1 ); volume_params.setShear ( -0.5f, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_PYRAMID: volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 0, 0 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_TETRAHEDRON: volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 0, 0 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_CYLINDER: volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 1, 1 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_CYLINDER_HEMI: volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.25f, 0.75f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 1, 1 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_CONE: volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.f, 1.f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 0, 0 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; case LL_PCODE_CONE_HEMI: volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); volume_params.setBeginAndEndS( 0.25f, 0.75f ); volume_params.setBeginAndEndT( 0.f, 1.f ); volume_params.setRatio ( 0, 0 ); volume_params.setShear ( 0, 0 ); LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem); volume_pcode = LL_PCODE_VOLUME; break; default: LLVolumeMessage::packVolumeParams(0, gMessageSystem); volume_pcode = pcode; break; } gMessageSystem->addU8Fast(_PREHASH_PCode, volume_pcode); gMessageSystem->addVector3Fast(_PREHASH_Scale, scale ); gMessageSystem->addQuatFast(_PREHASH_Rotation, rotation ); gMessageSystem->addVector3Fast(_PREHASH_RayStart, ray_start_region ); gMessageSystem->addVector3Fast(_PREHASH_RayEnd, ray_end_region ); gMessageSystem->addU8Fast(_PREHASH_BypassRaycast, (U8)b_hit_land ); gMessageSystem->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)FALSE ); gMessageSystem->addU8Fast(_PREHASH_State, state); // Limit raycast to a single object. // Speeds up server raycast + avoid problems with server ray hitting objects // that were clipped by the near plane or culled on the viewer. LLUUID ray_target_id; if( hit_obj ) { ray_target_id = hit_obj->getID(); } else { ray_target_id.setNull(); } gMessageSystem->addUUIDFast(_PREHASH_RayTargetID, ray_target_id ); // Pack in name value pairs gMessageSystem->sendReliable(regionp->getHost()); // Spawns a message, so must be after above send if (create_selected) { gSelectMgr->deselectAll(); gViewerWindow->getWindow()->incBusyCount(); } // VEFFECT: AddObject LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE); effectp->setSourceObject((LLViewerObject*)gAgent.getAvatarObject()); effectp->setPositionGlobal(regionp->getPosGlobalFromRegion(ray_end_region)); effectp->setDuration(LL_HUD_DUR_SHORT); effectp->setColor(LLColor4U(gAgent.getEffectColor())); gViewerStats->incStat(LLViewerStats::ST_CREATE_COUNT); return TRUE; }
// writes contents to datapacker BOOL LLBVHLoader::serialize(LLDataPacker& dp) { JointVector::iterator ji; KeyVector::iterator ki; F32 time; // count number of non-ignored joints S32 numJoints = 0; for (ji=mJoints.begin(); ji!=mJoints.end(); ++ji) { Joint *joint = *ji; if ( ! joint->mIgnore ) numJoints++; } // print header dp.packU16(KEYFRAME_MOTION_VERSION, "version"); dp.packU16(KEYFRAME_MOTION_SUBVERSION, "sub_version"); dp.packS32(mPriority, "base_priority"); dp.packF32(mDuration, "duration"); dp.packString(mEmoteName, "emote_name"); dp.packF32(mLoopInPoint, "loop_in_point"); dp.packF32(mLoopOutPoint, "loop_out_point"); dp.packS32(mLoop, "loop"); dp.packF32(mEaseIn, "ease_in_duration"); dp.packF32(mEaseOut, "ease_out_duration"); dp.packU32(mHand, "hand_pose"); dp.packU32(numJoints, "num_joints"); for ( ji = mJoints.begin(); ji != mJoints.end(); ++ji ) { Joint *joint = *ji; // if ignored, skip it if ( joint->mIgnore ) continue; LLQuaternion first_frame_rot; LLQuaternion fixup_rot; dp.packString(joint->mOutName, "joint_name"); dp.packS32(joint->mPriority, "joint_priority"); // compute coordinate frame rotation LLQuaternion frameRot( joint->mFrameMatrix ); LLQuaternion frameRotInv = ~frameRot; LLQuaternion offsetRot( joint->mOffsetMatrix ); // find mergechild and mergeparent joints, if specified LLQuaternion mergeParentRot; LLQuaternion mergeChildRot; Joint *mergeParent = NULL; Joint *mergeChild = NULL; JointVector::iterator mji; for (mji=mJoints.begin(); mji!=mJoints.end(); ++mji) { Joint *mjoint = *mji; if ( !joint->mMergeParentName.empty() && (mjoint->mName == joint->mMergeParentName) ) { mergeParent = *mji; } if ( !joint->mMergeChildName.empty() && (mjoint->mName == joint->mMergeChildName) ) { mergeChild = *mji; } } dp.packS32(joint->mNumRotKeys, "num_rot_keys"); LLQuaternion::Order order = bvhStringToOrder( joint->mOrder ); S32 outcount = 0; S32 frame = 1; for ( ki = joint->mKeys.begin(); ki != joint->mKeys.end(); ++ki ) { if ((frame == 1) && joint->mRelativeRotationKey) { first_frame_rot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order); fixup_rot.shortestArc(LLVector3::z_axis * first_frame_rot * frameRot, LLVector3::z_axis); } if (ki->mIgnoreRot) { frame++; continue; } time = (F32)frame * mFrameTime; if (mergeParent) { mergeParentRot = mayaQ( mergeParent->mKeys[frame-1].mRot[0], mergeParent->mKeys[frame-1].mRot[1], mergeParent->mKeys[frame-1].mRot[2], bvhStringToOrder(mergeParent->mOrder) ); LLQuaternion parentFrameRot( mergeParent->mFrameMatrix ); LLQuaternion parentOffsetRot( mergeParent->mOffsetMatrix ); mergeParentRot = ~parentFrameRot * mergeParentRot * parentFrameRot * parentOffsetRot; } else { mergeParentRot.loadIdentity(); } if (mergeChild) { mergeChildRot = mayaQ( mergeChild->mKeys[frame-1].mRot[0], mergeChild->mKeys[frame-1].mRot[1], mergeChild->mKeys[frame-1].mRot[2], bvhStringToOrder(mergeChild->mOrder) ); LLQuaternion childFrameRot( mergeChild->mFrameMatrix ); LLQuaternion childOffsetRot( mergeChild->mOffsetMatrix ); mergeChildRot = ~childFrameRot * mergeChildRot * childFrameRot * childOffsetRot; } else { mergeChildRot.loadIdentity(); } LLQuaternion inRot = mayaQ( ki->mRot[0], ki->mRot[1], ki->mRot[2], order); LLQuaternion outRot = frameRotInv* mergeChildRot * inRot * mergeParentRot * ~first_frame_rot * frameRot * offsetRot; U16 time_short = F32_to_U16(time, 0.f, mDuration); dp.packU16(time_short, "time"); U16 x, y, z; LLVector3 rot_vec = outRot.packToVector3(); rot_vec.quantize16(-1.f, 1.f, -1.f, 1.f); x = F32_to_U16(rot_vec.mV[VX], -1.f, 1.f); y = F32_to_U16(rot_vec.mV[VY], -1.f, 1.f); z = F32_to_U16(rot_vec.mV[VZ], -1.f, 1.f); dp.packU16(x, "rot_angle_x"); dp.packU16(y, "rot_angle_y"); dp.packU16(z, "rot_angle_z"); outcount++; frame++; } // output position keys (only for 1st joint) if ( ji == mJoints.begin() && !joint->mIgnorePositions ) { dp.packS32(joint->mNumPosKeys, "num_pos_keys"); LLVector3 relPos = joint->mRelativePosition; LLVector3 relKey; frame = 1; for ( ki = joint->mKeys.begin(); ki != joint->mKeys.end(); ++ki ) { if ((frame == 1) && joint->mRelativePositionKey) { relKey.setVec(ki->mPos); } if (ki->mIgnorePos) { frame++; continue; } time = (F32)frame * mFrameTime; LLVector3 inPos = (LLVector3(ki->mPos) - relKey) * ~first_frame_rot;// * fixup_rot; LLVector3 outPos = inPos * frameRot * offsetRot; outPos *= INCHES_TO_METERS; outPos -= relPos; outPos.clamp(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); U16 time_short = F32_to_U16(time, 0.f, mDuration); dp.packU16(time_short, "time"); U16 x, y, z; outPos.quantize16(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); x = F32_to_U16(outPos.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); y = F32_to_U16(outPos.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); z = F32_to_U16(outPos.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); dp.packU16(x, "pos_x"); dp.packU16(y, "pos_y"); dp.packU16(z, "pos_z"); frame++; } } else { dp.packS32(0, "num_pos_keys"); } } S32 num_constraints = (S32)mConstraints.size(); dp.packS32(num_constraints, "num_constraints"); for (ConstraintVector::iterator constraint_it = mConstraints.begin(); constraint_it != mConstraints.end(); constraint_it++) { U8 byte = constraint_it->mChainLength; dp.packU8(byte, "chain_lenght"); byte = constraint_it->mConstraintType; dp.packU8(byte, "constraint_type"); dp.packBinaryDataFixed((U8*)constraint_it->mSourceJointName, 16, "source_volume"); dp.packVector3(constraint_it->mSourceOffset, "source_offset"); dp.packBinaryDataFixed((U8*)constraint_it->mTargetJointName, 16, "target_volume"); dp.packVector3(constraint_it->mTargetOffset, "target_offset"); dp.packVector3(constraint_it->mTargetDir, "target_dir"); dp.packF32(constraint_it->mEaseInStart, "ease_in_start"); dp.packF32(constraint_it->mEaseInStop, "ease_in_stop"); dp.packF32(constraint_it->mEaseOutStart, "ease_out_start"); dp.packF32(constraint_it->mEaseOutStop, "ease_out_stop"); } return TRUE; }
void LLAudioEngine_OpenAL::updateWind(LLVector3 wind_vec, F32 camera_altitude) { if (true) return; LLVector3 wind_pos; F32 pitch; F32 center_freq; if (!mEnableWind) return; if(!mWindData) return; if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) { // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) // need to convert this to the conventional orientation DS3D and OpenAL use // where +X = right, +Y = up, +Z = backwards wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); pitch = 1.0f + mapWindVecToPitch(wind_vec); center_freq = 80.0f * powf(pitch,2.5f*(mapWindVecToGain(wind_vec)+1.0f)); //TESTING mMaxWindGain=1.0; mTargetFreq = center_freq; mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); ALfloat source0Pos[]={mListenerp->getPosition().mV[0],mListenerp->getPosition().mV[1],mListenerp->getPosition().mV[2]}; ALfloat source0Vel[]={ 0.0, 0.0, 0.0}; alSourcef(mWindSource, AL_GAIN, mTargetGain); alSourcef(mWindSource, AL_PITCH, pitch); alSourcefv(mWindSource, AL_POSITION, source0Pos); alSourcefv(mWindSource, AL_VELOCITY, source0Vel); alSourcei(mWindSource, AL_LOOPING, AL_FALSE); } int processed; alGetSourcei(mWindSource, AL_BUFFERS_PROCESSED, &processed); while(processed--) { ALuint buffer; alSourceUnqueueBuffers(mWindSource, 1, &buffer); checkALError(); alBufferData(buffer,AL_FORMAT_STEREO16,windDSP((void*)mWindData,mWindDataSize/mBytesPerSample),mWindDataSize,mSampleRate); checkALError(); alSourceQueueBuffers(mWindSource, 1, &buffer); checkALError(); } int playing; alGetSourcei(mWindSource, AL_SOURCE_STATE, &playing); if(playing==AL_STOPPED) alSourcePlay(mWindSource); checkALError(); }
// ----------------------------------------------------------------------------- void LLViewerJoystick::moveObjects(bool reset) { static bool toggle_send_to_sim = false; if (!gFocusMgr.getAppHasFocus() || mDriverState != JDS_INITIALIZED || !gSavedSettings.getBOOL("JoystickEnabled") || !gSavedSettings.getBOOL("JoystickBuildEnabled")) { return; } S32 axis[] = { gSavedSettings.getS32("JoystickAxis0"), gSavedSettings.getS32("JoystickAxis1"), gSavedSettings.getS32("JoystickAxis2"), gSavedSettings.getS32("JoystickAxis3"), gSavedSettings.getS32("JoystickAxis4"), gSavedSettings.getS32("JoystickAxis5"), }; if (reset || mResetFlag) { resetDeltas(axis); return; } F32 axis_scale[] = { gSavedSettings.getF32("BuildAxisScale0"), gSavedSettings.getF32("BuildAxisScale1"), gSavedSettings.getF32("BuildAxisScale2"), gSavedSettings.getF32("BuildAxisScale3"), gSavedSettings.getF32("BuildAxisScale4"), gSavedSettings.getF32("BuildAxisScale5"), }; F32 dead_zone[] = { gSavedSettings.getF32("BuildAxisDeadZone0"), gSavedSettings.getF32("BuildAxisDeadZone1"), gSavedSettings.getF32("BuildAxisDeadZone2"), gSavedSettings.getF32("BuildAxisDeadZone3"), gSavedSettings.getF32("BuildAxisDeadZone4"), gSavedSettings.getF32("BuildAxisDeadZone5"), }; F32 cur_delta[6]; F32 time = gFrameIntervalSeconds; // avoid making ridicously big movements if there's a big drop in fps if (time > .2f) { time = .2f; } // max feather is 32 F32 feather = gSavedSettings.getF32("BuildFeathering"); bool is_zero = true, absolute = gSavedSettings.getBOOL("Cursor3D"); for (U32 i = 0; i < 6; i++) { cur_delta[i] = -mAxes[axis[i]]; F32 tmp = cur_delta[i]; if (absolute) { cur_delta[i] = cur_delta[i] - sLastDelta[i]; } sLastDelta[i] = tmp; is_zero = is_zero && (cur_delta[i] == 0.f); if (cur_delta[i] > 0) { cur_delta[i] = llmax(cur_delta[i]-dead_zone[i], 0.f); } else { cur_delta[i] = llmin(cur_delta[i]+dead_zone[i], 0.f); } cur_delta[i] *= axis_scale[i]; if (!absolute) { cur_delta[i] *= time; } sDelta[i] = sDelta[i] + (cur_delta[i]-sDelta[i])*time*feather; } U32 upd_type = UPD_NONE; LLVector3 v; if (!is_zero) { // Clear AFK state if moved beyond the deadzone if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME) { gAgent.clearAFK(); } if (sDelta[0] || sDelta[1] || sDelta[2]) { upd_type |= UPD_POSITION; v.setVec(sDelta[0], sDelta[1], sDelta[2]); } if (sDelta[3] || sDelta[4] || sDelta[5]) { upd_type |= UPD_ROTATION; } // the selection update could fail, so we won't send if (LLSelectMgr::getInstance()->selectionMove(v, sDelta[3],sDelta[4],sDelta[5], upd_type)) { toggle_send_to_sim = true; } } else if (toggle_send_to_sim) { LLSelectMgr::getInstance()->sendSelectionMove(); toggle_send_to_sim = false; } }
BOOL LLFace::getGeometryVolume(const LLVolume& volume, const S32 &f, const LLMatrix4& mat_vert_in, const LLMatrix3& mat_norm_in, const U16 &index_offset, bool force_rebuild) { llassert(verify()); const LLVolumeFace &vf = volume.getVolumeFace(f); S32 num_vertices = (S32)vf.mNumVertices; S32 num_indices = (S32) vf.mNumIndices; if (mVertexBuffer.notNull()) { if (num_indices + (S32) mIndicesIndex > mVertexBuffer->getNumIndices()) { llwarns << "Index buffer overflow!" << llendl; llwarns << "Indices Count: " << mIndicesCount << " VF Num Indices: " << num_indices << " Indices Index: " << mIndicesIndex << " VB Num Indices: " << mVertexBuffer->getNumIndices() << llendl; llwarns << "Last Indices Count: " << mLastIndicesCount << " Last Indices Index: " << mLastIndicesIndex << " Face Index: " << f << " Pool Type: " << mPoolType << llendl; return FALSE; } if (num_vertices + mGeomIndex > mVertexBuffer->getNumVerts()) { llwarns << "Vertex buffer overflow!" << llendl; return FALSE; } } LLStrider<LLVector3> vertices; LLStrider<LLVector2> tex_coords; LLStrider<LLVector2> tex_coords2; LLStrider<LLVector3> normals; LLStrider<LLColor4U> colors; LLStrider<LLVector3> binormals; LLStrider<U16> indicesp; #if MESH_ENABLED LLStrider<LLVector4> weights; #endif //MESH_ENABLED BOOL full_rebuild = force_rebuild || mDrawablep->isState(LLDrawable::REBUILD_VOLUME); BOOL global_volume = mDrawablep->getVOVolume()->isVolumeGlobal(); LLVector3 scale; if (global_volume) { scale.setVec(1,1,1); } else { scale = mVObjp->getScale(); } bool rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION); bool rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR); bool rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD); bool rebuild_normal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); bool rebuild_binormal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_BINORMAL); #if MESH_ENABLED bool rebuild_weights = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_WEIGHT4); #endif //MESH_ENABLED const LLTextureEntry *tep = mVObjp->getTE(f); if (!tep) rebuild_color = FALSE; // can't get color when tep is NULL U8 bump_code = tep ? tep->getBumpmap() : 0; BOOL is_static = mDrawablep->isStatic(); BOOL is_global = is_static; LLVector3 center_sum(0.f, 0.f, 0.f); if (is_global) { setState(GLOBAL); } else { clearState(GLOBAL); } LLColor4U color = (tep ? LLColor4U(tep->getColor()) : LLColor4U::white); if (rebuild_color) // FALSE if tep == NULL { if (tep) { GLfloat alpha[4] = { 0.00f, 0.25f, 0.5f, 0.75f }; if (getPoolType() != LLDrawPool::POOL_ALPHA && (LLPipeline::sRenderDeferred || (LLPipeline::sRenderBump && tep->getShiny()))) { color.mV[3] = U8 (alpha[tep->getShiny()] * 255); } } } // INDICES if (full_rebuild) { mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex); for (U32 i = 0; i < (U32) num_indices; i++) { indicesp[i] = vf.mIndices[i] + index_offset; } //mVertexBuffer->setBuffer(0); } LLMatrix4a mat_normal; mat_normal.loadu(mat_norm_in); //if it's not fullbright and has no normals, bake sunlight based on face normal //bool bake_sunlight = !getTextureEntry()->getFullbright() && // !mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0; if (rebuild_tcoord) { bool do_xform; if (tep) { r = tep->getRotation(); os = tep->mOffsetS; ot = tep->mOffsetT; ms = tep->mScaleS; mt = tep->mScaleT; cos_ang = cos(r); sin_ang = sin(r); if (cos_ang != 1.f || sin_ang != 0.f || os != 0.f || ot != 0.f || ms != 1.f || mt != 1.f) { do_xform = true; } else { do_xform = false; } } else { do_xform = false; } //bump setup LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f ); LLVector4a bump_s_primary_light_ray(0.f, 0.f, 0.f); LLVector4a bump_t_primary_light_ray(0.f, 0.f, 0.f); LLQuaternion bump_quat; if (mDrawablep->isActive()) { bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); } if (bump_code) { mVObjp->getVolume()->genBinormals(f); F32 offset_multiple; switch( bump_code ) { case BE_NO_BUMP: offset_multiple = 0.f; break; case BE_BRIGHTNESS: case BE_DARKNESS: if( mTexture.notNull() && mTexture->hasGLTexture()) { // Offset by approximately one texel S32 cur_discard = mTexture->getDiscardLevel(); S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() ); max_size <<= cur_discard; const F32 ARTIFICIAL_OFFSET = 2.f; offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size; } else { offset_multiple = 1.f/256; } break; default: // Standard bumpmap textures. Assumed to be 256x256 offset_multiple = 1.f / 256; break; } F32 s_scale = 1.f; F32 t_scale = 1.f; if( tep ) { tep->getScale( &s_scale, &t_scale ); } // Use the nudged south when coming from above sun angle, such // that emboss mapping always shows up on the upward faces of cubes when // it's noon (since a lot of builders build with the sun forced to noon). LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir; LLVector3 moon_ray = gSky.getMoonDirection(); LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray; bump_s_primary_light_ray.load3((offset_multiple * s_scale * primary_light_ray).mV); bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV); } U8 texgen = getTextureEntry()->getTexGen(); if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT) { //planar texgen needs binormals mVObjp->getVolume()->genBinormals(f); } U8 tex_mode = 0; if (isState(TEXTURE_ANIM)) { LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; tex_mode = vobj->mTexAnimMode; if (!tex_mode) { clearState(TEXTURE_ANIM); } else { os = ot = 0.f; r = 0.f; cos_ang = 1.f; sin_ang = 0.f; ms = mt = 1.f; do_xform = false; } if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) { //don't override texture transform during tc bake tex_mode = 0; } } LLVector4a scalea; scalea.load3(scale.mV); bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); bool do_tex_mat = tex_mode && mTextureMatrix; if (!do_bump) { //not in atlas or not bump mapped, might be able to do a cheap update mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex); if (texgen != LLTextureEntry::TEX_GEN_PLANAR) { if (!do_tex_mat) { if (!do_xform) { tex_coords.assignArray((U8*) vf.mTexCoords, sizeof(vf.mTexCoords[0]), num_vertices); } else { for (S32 i = 0; i < num_vertices; i++) { LLVector2 tc(vf.mTexCoords[i]); xform(tc, cos_ang, sin_ang, os, ot, ms, mt); *tex_coords++ = tc; } } } else { //do tex mat, no texgen, no atlas, no bump for (S32 i = 0; i < num_vertices; i++) { LLVector2 tc(vf.mTexCoords[i]); //LLVector4a& norm = vf.mNormals[i]; //LLVector4a& center = *(vf.mCenter); LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); tmp = tmp * *mTextureMatrix; tc.mV[0] = tmp.mV[0]; tc.mV[1] = tmp.mV[1]; *tex_coords++ = tc; } } } else { //no bump, no atlas, tex gen planar if (do_tex_mat) { for (S32 i = 0; i < num_vertices; i++) { LLVector2 tc(vf.mTexCoords[i]); LLVector4a& norm = vf.mNormals[i]; LLVector4a& center = *(vf.mCenter); LLVector4a vec = vf.mPositions[i]; vec.mul(scalea); planarProjection(tc, norm, center, vec); LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); tmp = tmp * *mTextureMatrix; tc.mV[0] = tmp.mV[0]; tc.mV[1] = tmp.mV[1]; *tex_coords++ = tc; } } else { for (S32 i = 0; i < num_vertices; i++) { LLVector2 tc(vf.mTexCoords[i]); LLVector4a& norm = vf.mNormals[i]; LLVector4a& center = *(vf.mCenter); LLVector4a vec = vf.mPositions[i]; vec.mul(scalea); planarProjection(tc, norm, center, vec); xform(tc, cos_ang, sin_ang, os, ot, ms, mt); *tex_coords++ = tc; } } } //mVertexBuffer->setBuffer(0); } else { //either bump mapped or in atlas, just do the whole expensive loop mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex); std::vector<LLVector2> bump_tc; for (S32 i = 0; i < num_vertices; i++) { LLVector2 tc(vf.mTexCoords[i]); LLVector4a& norm = vf.mNormals[i]; LLVector4a& center = *(vf.mCenter); if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) { LLVector4a vec = vf.mPositions[i]; vec.mul(scalea); switch (texgen) { case LLTextureEntry::TEX_GEN_PLANAR: planarProjection(tc, norm, center, vec); break; case LLTextureEntry::TEX_GEN_SPHERICAL: sphericalProjection(tc, norm, center, vec); break; case LLTextureEntry::TEX_GEN_CYLINDRICAL: cylindricalProjection(tc, norm, center, vec); break; default: break; } } if (tex_mode && mTextureMatrix) { LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); tmp = tmp * *mTextureMatrix; tc.mV[0] = tmp.mV[0]; tc.mV[1] = tmp.mV[1]; } else { xform(tc, cos_ang, sin_ang, os, ot, ms, mt); } *tex_coords++ = tc; if (do_bump) { bump_tc.push_back(tc); } } //mVertexBuffer->setBuffer(0); if (do_bump) { mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex); for (S32 i = 0; i < num_vertices; i++) { LLVector4a tangent; tangent.setCross3(vf.mBinormals[i], vf.mNormals[i]); LLMatrix4a tangent_to_object; tangent_to_object.setRows(tangent, vf.mBinormals[i], vf.mNormals[i]); LLVector4a t; tangent_to_object.rotate(binormal_dir, t); LLVector4a binormal; mat_normal.rotate(t, binormal); //VECTORIZE THIS if (mDrawablep->isActive()) { LLVector3 t; t.set(binormal.getF32ptr()); t *= bump_quat; binormal.load3(t.mV); } binormal.normalize3fast(); LLVector2 tc = bump_tc[i]; tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() ); *tex_coords2++ = tc; } //mVertexBuffer->setBuffer(0); } } } if (rebuild_pos) { llassert(num_vertices > 0); mVertexBuffer->getVertexStrider(vertices, mGeomIndex); LLMatrix4a mat_vert; mat_vert.loadu(mat_vert_in); LLVector4a* src = vf.mPositions; LLVector4a position; for (S32 i = 0; i < num_vertices; i++) { mat_vert.affineTransform(src[i], position); vertices[i].set(position.getF32ptr()); } //mVertexBuffer->setBuffer(0); } if (rebuild_normal) { mVertexBuffer->getNormalStrider(normals, mGeomIndex); for (S32 i = 0; i < num_vertices; i++) { LLVector4a normal; mat_normal.rotate(vf.mNormals[i], normal); normal.normalize3fast(); normals[i].set(normal.getF32ptr()); } //mVertexBuffer->setBuffer(0); } if (rebuild_binormal) { mVertexBuffer->getBinormalStrider(binormals, mGeomIndex); for (S32 i = 0; i < num_vertices; i++) { LLVector4a binormal; mat_normal.rotate(vf.mBinormals[i], binormal); binormal.normalize3fast(); binormals[i].set(binormal.getF32ptr()); } //mVertexBuffer->setBuffer(0); } #if MESH_ENABLED if (rebuild_weights && vf.mWeights) { mVertexBuffer->getWeight4Strider(weights, mGeomIndex); weights.assignArray((U8*) vf.mWeights, sizeof(vf.mWeights[0]), num_vertices); //mVertexBuffer->setBuffer(0); } #endif //MESH_ENABLED if (rebuild_color) { mVertexBuffer->getColorStrider(colors, mGeomIndex); for (S32 i = 0; i < num_vertices; i++) { colors[i] = color; } //mVertexBuffer->setBuffer(0); } if (rebuild_tcoord) { mTexExtents[0].setVec(0,0); mTexExtents[1].setVec(1,1); xform(mTexExtents[0], cos_ang, sin_ang, os, ot, ms, mt); xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt); F32 es = vf.mTexCoordExtents[1].mV[0] - vf.mTexCoordExtents[0].mV[0] ; F32 et = vf.mTexCoordExtents[1].mV[1] - vf.mTexCoordExtents[0].mV[1] ; mTexExtents[0][0] *= es ; mTexExtents[1][0] *= es ; mTexExtents[0][1] *= et ; mTexExtents[1][1] *= et ; } mLastVertexBuffer = mVertexBuffer; mLastGeomCount = mGeomCount; mLastGeomIndex = mGeomIndex; mLastIndicesCount = mIndicesCount; mLastIndicesIndex = mIndicesIndex; return TRUE; }