// Description: // Block View smooth rotation // // Copyright (C) 2003 Frank Becker // // This program is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software // Foundation; either version 2 of the License, or (at your option) any later // version. // // This program 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 General Public License for more details // #include #include #include const float DEFAULT_ROTATION_SPEED = 5.0f; const int DEFAULT_MOVE_STEPS = 10; BlockViewSmooth::BlockViewSmooth( BlockModel &model): BlockViewBase(model), _rotationSpeed(DEFAULT_ROTATION_SPEED), _moveSteps(DEFAULT_MOVE_STEPS), _numSteps(0) { XTRACE(); resetRotations(); ConfigS::instance()->getFloat( "rotationSpeed", _rotationSpeed); ConfigS::instance()->getInteger( "moveSteps", _moveSteps); } BlockViewSmooth::~BlockViewSmooth() { XTRACE(); } void BlockViewSmooth::resetRotations( void) { _prevAxis = Point3D(1,0,0); _prevAngle = 0; _prevQ.set( _prevAngle, _prevAxis); _currentAxis = Point3D(1,0,0); _currentAngle = 0; _targetAngle = 0; _prev2Angle = _currentAngle; } void BlockViewSmooth::update( void) { _prevOffset = _currentOffset; _prev2Angle = _currentAngle; if( (_currentAngle+_rotationSpeed)<_targetAngle) _currentAngle+=_rotationSpeed; else _currentAngle = _targetAngle; if( _numSteps) { _currentOffset = _currentOffset + _delta; _numSteps--; } Point3Di &offset = _model.getBlockOffset(); if( _oldOffset != offset) { _targetOffset = offset; // Point3D = Point3Di _oldOffset = offset; _delta = _targetOffset - _currentOffset; _delta = _delta / (float)_moveSteps; _numSteps = _moveSteps; } } void BlockViewSmooth::notifyNewBlock( void) { // LOG_INFO << "New Block. Resetting rotations\n"; resetRotations(); _oldOffset = _model.getBlockOffset(); _currentOffset = _oldOffset; // Point3D = Point3Di } #if 0 A sequence of rotations: Q(rotate origin to current orientation) * Q(rotate current to final orientation) t: partial rotation (angle*t) 0B Q(1) * Q(AB)t 2. at 'a' rotate request B->C Q(Aa) * Q(aBC)t = Q(Aa) * Q(aC)t 3. at 'b' rotate request C->D Q(Aab) * Q(bCD)t = Q(Ab) * Q(bD)t A----a B \ __b __-- D C #endif //TODO: check if slerping is cheaper... void BlockViewSmooth::notifyNewRotation( const Quaternion &q) { Quaternion tmpQ; //convert the ongoing rotation into a quaternion: tmpQ = Q(ab) tmpQ.set( _currentAngle, _currentAxis); //combine rotations -> Q(Aab) = Q(Ab) //prevQ = Q(Aa) _prevQ = tmpQ * _prevQ; //get the angle and axis for the new static rotation _prevQ.get( _prevAngle, _prevAxis); //convert the not yet executed portion of the rotation into a quaternion //tmpQ = Q(bC) tmpQ.set( _targetAngle-_currentAngle, _currentAxis); //set the new rotation Q(CD) _targetQ = q; //combine rotations -> Q(bCD) = Q(bD) _targetQ = _targetQ * tmpQ; //get the angle and axis for the new ongoing rotation _targetQ.get( _targetAngle, _currentAxis); //reset the current angle in the ongoing rotation _currentAngle = 0; } Point3D &BlockViewSmooth::getInterpolatedOffset( void) { float gf = GameState::frameFraction; _interpOffset = _prevOffset + (_currentOffset-_prevOffset)*gf; return _interpOffset; } float BlockViewSmooth::getInterpolatedAngle( void) { float gf = GameState::frameFraction; return _prev2Angle + (_currentAngle-_prev2Angle)*gf; }