1*70f497fbSAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*70f497fbSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*70f497fbSAndrew Rist * or more contributor license agreements. See the NOTICE file 5*70f497fbSAndrew Rist * distributed with this work for additional information 6*70f497fbSAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*70f497fbSAndrew Rist * to you under the Apache License, Version 2.0 (the 8*70f497fbSAndrew Rist * "License"); you may not use this file except in compliance 9*70f497fbSAndrew Rist * with the License. You may obtain a copy of the License at 10*70f497fbSAndrew Rist * 11*70f497fbSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12*70f497fbSAndrew Rist * 13*70f497fbSAndrew Rist * Unless required by applicable law or agreed to in writing, 14*70f497fbSAndrew Rist * software distributed under the License is distributed on an 15*70f497fbSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*70f497fbSAndrew Rist * KIND, either express or implied. See the License for the 17*70f497fbSAndrew Rist * specific language governing permissions and limitations 18*70f497fbSAndrew Rist * under the License. 19*70f497fbSAndrew Rist * 20*70f497fbSAndrew Rist *************************************************************/ 21*70f497fbSAndrew Rist 22*70f497fbSAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_slideshow.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir // must be first 28cdf0e10cSrcweir #include <canvas/debug.hxx> 29cdf0e10cSrcweir #include <canvas/verbosetrace.hxx> 30cdf0e10cSrcweir 31cdf0e10cSrcweir #include <simplecontinuousactivitybase.hxx> 32cdf0e10cSrcweir 33cdf0e10cSrcweir 34cdf0e10cSrcweir namespace slideshow 35cdf0e10cSrcweir { 36cdf0e10cSrcweir namespace internal 37cdf0e10cSrcweir { SimpleContinuousActivityBase(const ActivityParameters & rParms)38cdf0e10cSrcweir SimpleContinuousActivityBase::SimpleContinuousActivityBase( 39cdf0e10cSrcweir const ActivityParameters& rParms ) : 40cdf0e10cSrcweir ActivityBase( rParms ), 41cdf0e10cSrcweir maTimer( rParms.mrActivitiesQueue.getTimer() ), 42cdf0e10cSrcweir mnMinSimpleDuration( rParms.mnMinDuration ), 43cdf0e10cSrcweir mnMinNumberOfFrames( rParms.mnMinNumberOfFrames ), 44cdf0e10cSrcweir mnCurrPerformCalls( 0 ) 45cdf0e10cSrcweir { 46cdf0e10cSrcweir } 47cdf0e10cSrcweir startAnimation()48cdf0e10cSrcweir void SimpleContinuousActivityBase::startAnimation() 49cdf0e10cSrcweir { 50cdf0e10cSrcweir // init timer. We measure animation time only when we're 51cdf0e10cSrcweir // actually started. 52cdf0e10cSrcweir maTimer.reset(); 53cdf0e10cSrcweir } 54cdf0e10cSrcweir calcTimeLag() const55cdf0e10cSrcweir double SimpleContinuousActivityBase::calcTimeLag() const 56cdf0e10cSrcweir { 57cdf0e10cSrcweir ActivityBase::calcTimeLag(); 58cdf0e10cSrcweir if (! isActive()) 59cdf0e10cSrcweir return 0.0; 60cdf0e10cSrcweir 61cdf0e10cSrcweir // retrieve locally elapsed time 62cdf0e10cSrcweir const double nCurrElapsedTime( maTimer.getElapsedTime() ); 63cdf0e10cSrcweir 64cdf0e10cSrcweir // log time 65cdf0e10cSrcweir VERBOSE_TRACE( "SimpleContinuousActivityBase::calcTimeLag(): " 66cdf0e10cSrcweir "next step is based on time: %f", nCurrElapsedTime ); 67cdf0e10cSrcweir 68cdf0e10cSrcweir // go to great length to ensure a proper animation 69cdf0e10cSrcweir // run. Since we don't know how often we will be called 70cdf0e10cSrcweir // here, try to spread the animator calls uniquely over 71cdf0e10cSrcweir // the [0,1] parameter range. Be aware of the fact that 72cdf0e10cSrcweir // perform will be called at least mnMinNumberOfTurns 73cdf0e10cSrcweir // times. 74cdf0e10cSrcweir 75cdf0e10cSrcweir // fraction of time elapsed 76cdf0e10cSrcweir const double nFractionElapsedTime( 77cdf0e10cSrcweir nCurrElapsedTime / mnMinSimpleDuration ); 78cdf0e10cSrcweir 79cdf0e10cSrcweir // fraction of minimum calls performed 80cdf0e10cSrcweir const double nFractionRequiredCalls( 81cdf0e10cSrcweir double(mnCurrPerformCalls) / mnMinNumberOfFrames ); 82cdf0e10cSrcweir 83cdf0e10cSrcweir // okay, so now, the decision is easy: 84cdf0e10cSrcweir // 85cdf0e10cSrcweir // If the fraction of time elapsed is smaller than the 86cdf0e10cSrcweir // number of calls required to be performed, then we calc 87cdf0e10cSrcweir // the position on the animation range according to 88cdf0e10cSrcweir // elapsed time. That is, we're so to say ahead of time. 89cdf0e10cSrcweir // 90cdf0e10cSrcweir // In contrary, if the fraction of time elapsed is larger, 91cdf0e10cSrcweir // then we're lagging, and we thus calc the position on 92cdf0e10cSrcweir // the animation time line according to the fraction of 93cdf0e10cSrcweir // calls performed. Thus, the animation is forced to slow 94cdf0e10cSrcweir // down, and take the required minimal number of steps, 95cdf0e10cSrcweir // sufficiently equally distributed across the animation 96cdf0e10cSrcweir // time line. 97cdf0e10cSrcweir if( nFractionElapsedTime < nFractionRequiredCalls ) 98cdf0e10cSrcweir { 99cdf0e10cSrcweir VERBOSE_TRACE( "SimpleContinuousActivityBase::calcTimeLag(): " 100cdf0e10cSrcweir "t=%f is based on time", nFractionElapsedTime ); 101cdf0e10cSrcweir return 0.0; 102cdf0e10cSrcweir } 103cdf0e10cSrcweir else 104cdf0e10cSrcweir { 105cdf0e10cSrcweir VERBOSE_TRACE( "SimpleContinuousActivityBase::perform(): " 106cdf0e10cSrcweir "t=%f is based on number of calls", 107cdf0e10cSrcweir nFractionRequiredCalls ); 108cdf0e10cSrcweir 109cdf0e10cSrcweir // lag global time, so all other animations lag, too: 110cdf0e10cSrcweir return ((nFractionElapsedTime - nFractionRequiredCalls) 111cdf0e10cSrcweir * mnMinSimpleDuration); 112cdf0e10cSrcweir } 113cdf0e10cSrcweir } 114cdf0e10cSrcweir perform()115cdf0e10cSrcweir bool SimpleContinuousActivityBase::perform() 116cdf0e10cSrcweir { 117cdf0e10cSrcweir // call base class, for start() calls and end handling 118cdf0e10cSrcweir if( !ActivityBase::perform() ) 119cdf0e10cSrcweir return false; // done, we're ended 120cdf0e10cSrcweir 121cdf0e10cSrcweir 122cdf0e10cSrcweir // get relative animation position 123cdf0e10cSrcweir // =============================== 124cdf0e10cSrcweir 125cdf0e10cSrcweir const double nCurrElapsedTime( maTimer.getElapsedTime() ); 126cdf0e10cSrcweir double nT( nCurrElapsedTime / mnMinSimpleDuration ); 127cdf0e10cSrcweir 128cdf0e10cSrcweir 129cdf0e10cSrcweir // one of the stop criteria reached? 130cdf0e10cSrcweir // ================================= 131cdf0e10cSrcweir 132cdf0e10cSrcweir // will be set to true below, if one of the termination criteria 133cdf0e10cSrcweir // matched. 134cdf0e10cSrcweir bool bActivityEnding( false ); 135cdf0e10cSrcweir 136cdf0e10cSrcweir if( isRepeatCountValid() ) 137cdf0e10cSrcweir { 138cdf0e10cSrcweir // Finite duration 139cdf0e10cSrcweir // =============== 140cdf0e10cSrcweir 141cdf0e10cSrcweir // When we've autoreverse on, the repeat count 142cdf0e10cSrcweir // doubles 143cdf0e10cSrcweir const double nRepeatCount( getRepeatCount() ); 144cdf0e10cSrcweir const double nEffectiveRepeat( isAutoReverse() ? 145cdf0e10cSrcweir 2.0*nRepeatCount : 146cdf0e10cSrcweir nRepeatCount ); 147cdf0e10cSrcweir 148cdf0e10cSrcweir // time (or frame count) elapsed? 149cdf0e10cSrcweir if( nEffectiveRepeat <= nT ) 150cdf0e10cSrcweir { 151cdf0e10cSrcweir // okee. done for now. Will not exit right here, 152cdf0e10cSrcweir // to give animation the chance to render the last 153cdf0e10cSrcweir // frame below 154cdf0e10cSrcweir bActivityEnding = true; 155cdf0e10cSrcweir 156cdf0e10cSrcweir // clamp animation to max permissible value 157cdf0e10cSrcweir nT = nEffectiveRepeat; 158cdf0e10cSrcweir } 159cdf0e10cSrcweir } 160cdf0e10cSrcweir 161cdf0e10cSrcweir 162cdf0e10cSrcweir // need to do auto-reverse? 163cdf0e10cSrcweir // ======================== 164cdf0e10cSrcweir 165cdf0e10cSrcweir double nRepeats; 166cdf0e10cSrcweir double nRelativeSimpleTime; 167cdf0e10cSrcweir 168cdf0e10cSrcweir // TODO(Q3): Refactor this mess 169cdf0e10cSrcweir if( isAutoReverse() ) 170cdf0e10cSrcweir { 171cdf0e10cSrcweir // divert active duration into repeat and 172cdf0e10cSrcweir // fractional part. 173cdf0e10cSrcweir const double nFractionalActiveDuration( modf(nT, &nRepeats) ); 174cdf0e10cSrcweir 175cdf0e10cSrcweir // for auto-reverse, map ranges [1,2), [3,4), ... 176cdf0e10cSrcweir // to ranges [0,1), [1,2), etc. 177cdf0e10cSrcweir if( ((int)nRepeats) % 2 ) 178cdf0e10cSrcweir { 179cdf0e10cSrcweir // we're in an odd range, reverse sweep 180cdf0e10cSrcweir nRelativeSimpleTime = 1.0 - nFractionalActiveDuration; 181cdf0e10cSrcweir } 182cdf0e10cSrcweir else 183cdf0e10cSrcweir { 184cdf0e10cSrcweir // we're in an even range, pass on as is 185cdf0e10cSrcweir nRelativeSimpleTime = nFractionalActiveDuration; 186cdf0e10cSrcweir } 187cdf0e10cSrcweir 188cdf0e10cSrcweir // effective repeat count for autoreverse is half of 189cdf0e10cSrcweir // the input time's value (each run of an autoreverse 190cdf0e10cSrcweir // cycle is half of a repeat) 191cdf0e10cSrcweir nRepeats /= 2; 192cdf0e10cSrcweir } 193cdf0e10cSrcweir else 194cdf0e10cSrcweir { 195cdf0e10cSrcweir // determine repeat 196cdf0e10cSrcweir // ================ 197cdf0e10cSrcweir 198cdf0e10cSrcweir // calc simple time and number of repeats from nT 199cdf0e10cSrcweir // Now, that's easy, since the fractional part of 200cdf0e10cSrcweir // nT gives the relative simple time, and the 201cdf0e10cSrcweir // integer part the number of full repeats: 202cdf0e10cSrcweir nRelativeSimpleTime = modf(nT, &nRepeats); 203cdf0e10cSrcweir 204cdf0e10cSrcweir // clamp repeats to max permissible value (maRepeats.getValue() - 1.0) 205cdf0e10cSrcweir if( isRepeatCountValid() && 206cdf0e10cSrcweir nRepeats >= getRepeatCount() ) 207cdf0e10cSrcweir { 208cdf0e10cSrcweir // Note that this code here only gets 209cdf0e10cSrcweir // triggered if maRepeats.getValue() is an 210cdf0e10cSrcweir // _integer_. Otherwise, nRepeats will never 211cdf0e10cSrcweir // reach nor exceed 212cdf0e10cSrcweir // maRepeats.getValue(). Thus, the code below 213cdf0e10cSrcweir // does not need to handle cases of fractional 214cdf0e10cSrcweir // repeats, and can always assume that a full 215cdf0e10cSrcweir // animation run has ended (with 216cdf0e10cSrcweir // nRelativeSimpleTime=1.0 for 217cdf0e10cSrcweir // non-autoreversed activities). 218cdf0e10cSrcweir 219cdf0e10cSrcweir // with modf, nRelativeSimpleTime will never 220cdf0e10cSrcweir // become 1.0, since nRepeats is incremented and 221cdf0e10cSrcweir // nRelativeSimpleTime set to 0.0 then. 222cdf0e10cSrcweir // 223cdf0e10cSrcweir // For the animation to reach its final value, 224cdf0e10cSrcweir // nRepeats must although become 225cdf0e10cSrcweir // maRepeats.getValue()-1.0, and 226cdf0e10cSrcweir // nRelativeSimpleTime=1.0. 227cdf0e10cSrcweir nRelativeSimpleTime = 1.0; 228cdf0e10cSrcweir nRepeats -= 1.0; 229cdf0e10cSrcweir } 230cdf0e10cSrcweir } 231cdf0e10cSrcweir 232cdf0e10cSrcweir // actually perform something 233cdf0e10cSrcweir // ========================== 234cdf0e10cSrcweir 235cdf0e10cSrcweir simplePerform( nRelativeSimpleTime, 236cdf0e10cSrcweir // nRepeats is already integer-valued 237cdf0e10cSrcweir static_cast<sal_uInt32>( nRepeats ) ); 238cdf0e10cSrcweir 239cdf0e10cSrcweir 240cdf0e10cSrcweir // delayed endActivity() call from end condition check 241cdf0e10cSrcweir // below. Issued after the simplePerform() call above, to 242cdf0e10cSrcweir // give animations the chance to correctly reach the 243cdf0e10cSrcweir // animation end value, without spurious bail-outs because 244cdf0e10cSrcweir // of isActive() returning false. 245cdf0e10cSrcweir if( bActivityEnding ) 246cdf0e10cSrcweir endActivity(); 247cdf0e10cSrcweir 248cdf0e10cSrcweir // one more frame successfully performed 249cdf0e10cSrcweir ++mnCurrPerformCalls; 250cdf0e10cSrcweir 251cdf0e10cSrcweir return isActive(); 252cdf0e10cSrcweir } 253cdf0e10cSrcweir } 254cdf0e10cSrcweir } 255