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