/** * @file llwlanimator.cpp * @brief Implementation for the LLWLAnimator class. * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llwlanimator.h" #include "llsky.h" #include "pipeline.h" #include "llwlparammanager.h" #include "llwaterparammanager.h" extern LLControlGroup gSavedSettings; F64 LLWLAnimator::INTERP_TOTAL_SECONDS = 3.f; LLWLAnimator::LLWLAnimator() : mStartTime(0.f), mDayRate(1.f), mDayTime(0.f), mIsRunning(FALSE), mIsInterpolating(FALSE), mTimeType(TIME_LINDEN), mInterpStartTime(), mInterpEndTime() { mInterpBeginWL = new LLWLParamSet(); mInterpBeginWater = new LLWaterParamSet(); mInterpEndWater = new LLWaterParamSet(); } void LLWLAnimator::update(LLWLParamSet& curParams) { //llassert(mUseLindenTime != mUseLocalTime); F64 curTime; curTime = getDayTime(); // don't do anything if empty if(mTimeTrack.size() == 0) { return; } // start it off mFirstIt = mTimeTrack.begin(); mSecondIt = mTimeTrack.begin(); mSecondIt++; // grab the two tween iterators while(mSecondIt != mTimeTrack.end() && curTime > mSecondIt->first) { mFirstIt++; mSecondIt++; } // scroll it around when you get to the end if(mSecondIt == mTimeTrack.end() || mFirstIt->first > curTime) { mSecondIt = mTimeTrack.begin(); mFirstIt = mTimeTrack.end(); mFirstIt--; } F32 weight = 0; if(mFirstIt->first < mSecondIt->first) { // get the delta time and the proper weight weight = F32 (curTime - mFirstIt->first) / (mSecondIt->first - mFirstIt->first); // handle the ends } else if(mFirstIt->first > mSecondIt->first) { // right edge of time line if(curTime >= mFirstIt->first) { weight = F32 (curTime - mFirstIt->first) / ((1 + mSecondIt->first) - mFirstIt->first); // left edge of time line } else { weight = F32 ((1 + curTime) - mFirstIt->first) / ((1 + mSecondIt->first) - mFirstIt->first); } // handle same as whatever the last one is } else { weight = 1; } if(mIsInterpolating) { // *TODO_JACOB: this is kind of laggy. Not sure why. The part that lags is the curParams.mix call, and none of the other mixes. It works, though. clock_t current = clock(); if(current >= mInterpEndTime) { mIsInterpolating = false; return; } // determine moving target for final interpolation value LLWLParamSet buf = LLWLParamSet(); buf.setAll(LLWLParamManager::getInstance()->mParamList[mFirstIt->second].getAll()); // just give it some values, otherwise it has no params to begin with (see comment in constructor) buf.mix(LLWLParamManager::getInstance()->mParamList[mFirstIt->second], LLWLParamManager::getInstance()->mParamList[mSecondIt->second], weight); // mix to determine moving target for interpolation finish (as below) // mix from previous value to moving target weight = (current - mInterpStartTime) / (INTERP_TOTAL_SECONDS * CLOCKS_PER_SEC); curParams.mix(*mInterpBeginWL, buf, weight); // mix water LLWaterParamManager::getInstance()->mCurParams.mix(*mInterpBeginWater, *mInterpEndWater, weight); } else { // do the interpolation and set the parameters curParams.mix(LLWLParamManager::getInstance()->mParamList[mFirstIt->second], LLWLParamManager::getInstance()->mParamList[mSecondIt->second], weight); } } F64 LLWLAnimator::getDayTime() { if(!mIsRunning) { return mDayTime; } else if(mTimeType == TIME_LINDEN) { F32 phase = gSky.getSunPhase() / F_PI; // we're not solving the non-linear equation that determines sun phase // we're just linearly interpolating between the major points if (phase <= 5.0 / 4.0) { mDayTime = (1.0 / 3.0) * phase + (1.0 / 3.0); } else { mDayTime = phase - (1.0 / 2.0); } if(mDayTime > 1) { mDayTime--; } return mDayTime; } else if(mTimeType == TIME_LOCAL) { return getLocalTime(); } // get the time; mDayTime = (LLTimer::getElapsedSeconds() - mStartTime) / mDayRate; // clamp it if(mDayTime < 0) { mDayTime = 0; } while(mDayTime > 1) { mDayTime--; } return (F32)mDayTime; } void LLWLAnimator::setDayTime(F64 dayTime) { //retroactively set start time; mStartTime = LLTimer::getElapsedSeconds() - dayTime * mDayRate; mDayTime = dayTime; // clamp it if(mDayTime < 0) { mDayTime = 0; } else if(mDayTime > 1) { mDayTime = 1; } } void LLWLAnimator::setTrack(std::map& curTrack, F32 dayRate, F64 dayTime, bool run) { mTimeTrack = curTrack; mDayRate = dayRate; setDayTime(dayTime); mIsRunning = run; } void LLWLAnimator::startInterpolation(LLSD& targetWater) { mInterpBeginWL->setAll(LLWLParamManager::getInstance()->mCurParams.getAll()); mInterpBeginWater->setAll(LLWaterParamManager::getInstance()->mCurParams.getAll()); mInterpStartTime = clock(); mInterpEndTime = mInterpStartTime + clock_t(INTERP_TOTAL_SECONDS) * CLOCKS_PER_SEC; // Don't set any ending WL -- this is continuously calculated as the animator updates since it's a moving target mInterpEndWater->setAll(targetWater); mIsInterpolating = true; } std::string LLWLAnimator::timeToString(F32 curTime) { S32 hours; S32 min; bool isPM = false; // get hours and minutes hours = (S32) (24.0 * curTime); curTime -= ((F32) hours / 24.0f); min = llround(24.0f * 60.0f * curTime); // handle case where it's 60 if(min == 60) { hours++; min = 0; } // set for PM if(hours >= 12 && hours < 24) { isPM = true; } // convert to non-military notation if(hours >= 24) { hours = 12; } else if(hours > 12) { hours -= 12; } else if(hours == 0) { hours = 12; } // make the string std::stringstream newTime; newTime << hours << ":"; // double 0 if(min < 10) { newTime << 0; } // finish it newTime << min << " "; if(isPM) { newTime << "PM"; } else { newTime << "AM"; } return newTime.str(); } F64 LLWLAnimator::getLocalTime() { char buffer[9]; time_t rawtime; struct tm* timeinfo; time(&rawtime); timeinfo = localtime(&rawtime); strftime(buffer, 9, "%H:%M:%S", timeinfo); std::string timeStr(buffer); F64 tod = ((F64)atoi(timeStr.substr(0,2).c_str())) / 24.f + ((F64)atoi(timeStr.substr(3,2).c_str())) / 1440.f + ((F64)atoi(timeStr.substr(6,2).c_str())) / 86400.f; return tod; }