| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | #include <osgPresentation/AnimationMaterial> |
|---|
| 14 | |
|---|
| 15 | #include <osg/MatrixTransform> |
|---|
| 16 | #include <osg/PositionAttitudeTransform> |
|---|
| 17 | #include <osg/Notify> |
|---|
| 18 | #include <osg/io_utils> |
|---|
| 19 | |
|---|
| 20 | using namespace osgPresentation; |
|---|
| 21 | |
|---|
| 22 | void AnimationMaterial::insert(double time,osg::Material* material) |
|---|
| 23 | { |
|---|
| 24 | _timeControlPointMap[time] = material; |
|---|
| 25 | } |
|---|
| 26 | |
|---|
| 27 | bool AnimationMaterial::getMaterial(double time,osg::Material& material) const |
|---|
| 28 | { |
|---|
| 29 | if (_timeControlPointMap.empty()) return false; |
|---|
| 30 | |
|---|
| 31 | switch(_loopMode) |
|---|
| 32 | { |
|---|
| 33 | case(SWING): |
|---|
| 34 | { |
|---|
| 35 | double modulated_time = (time - getFirstTime())/(getPeriod()*2.0); |
|---|
| 36 | double fraction_part = modulated_time - floor(modulated_time); |
|---|
| 37 | if (fraction_part>0.5) fraction_part = 1.0-fraction_part; |
|---|
| 38 | |
|---|
| 39 | time = getFirstTime()+(fraction_part*2.0) * getPeriod(); |
|---|
| 40 | break; |
|---|
| 41 | } |
|---|
| 42 | case(LOOP): |
|---|
| 43 | { |
|---|
| 44 | double modulated_time = (time - getFirstTime())/getPeriod(); |
|---|
| 45 | double fraction_part = modulated_time - floor(modulated_time); |
|---|
| 46 | time = getFirstTime()+fraction_part * getPeriod(); |
|---|
| 47 | break; |
|---|
| 48 | } |
|---|
| 49 | case(NO_LOOPING): |
|---|
| 50 | |
|---|
| 51 | break; |
|---|
| 52 | } |
|---|
| 53 | |
|---|
| 54 | |
|---|
| 55 | |
|---|
| 56 | TimeControlPointMap::const_iterator second = _timeControlPointMap.lower_bound(time); |
|---|
| 57 | if (second==_timeControlPointMap.begin()) |
|---|
| 58 | { |
|---|
| 59 | material = *(second->second); |
|---|
| 60 | } |
|---|
| 61 | else if (second!=_timeControlPointMap.end()) |
|---|
| 62 | { |
|---|
| 63 | TimeControlPointMap::const_iterator first = second; |
|---|
| 64 | --first; |
|---|
| 65 | |
|---|
| 66 | |
|---|
| 67 | |
|---|
| 68 | |
|---|
| 69 | double delta_time = second->first - first->first; |
|---|
| 70 | |
|---|
| 71 | if (delta_time==0.0) |
|---|
| 72 | material = *(first->second); |
|---|
| 73 | else |
|---|
| 74 | { |
|---|
| 75 | interpolate(material,(time - first->first)/delta_time, *first->second, *second->second); |
|---|
| 76 | } |
|---|
| 77 | } |
|---|
| 78 | else |
|---|
| 79 | { |
|---|
| 80 | material = *(_timeControlPointMap.rbegin()->second); |
|---|
| 81 | } |
|---|
| 82 | return true; |
|---|
| 83 | } |
|---|
| 84 | |
|---|
| 85 | template<class T> |
|---|
| 86 | T interp(float r, const T& lhs, const T& rhs) |
|---|
| 87 | { |
|---|
| 88 | return lhs*(1.0f-r)+rhs*r; |
|---|
| 89 | } |
|---|
| 90 | |
|---|
| 91 | |
|---|
| 92 | void AnimationMaterial::interpolate(osg::Material& material, float r, const osg::Material& lhs,const osg::Material& rhs) const |
|---|
| 93 | { |
|---|
| 94 | material.setColorMode(lhs.getColorMode()); |
|---|
| 95 | |
|---|
| 96 | material.setAmbient(osg::Material::FRONT_AND_BACK,interp(r, lhs.getAmbient(osg::Material::FRONT),rhs.getAmbient(osg::Material::FRONT))); |
|---|
| 97 | if (!material.getAmbientFrontAndBack()) |
|---|
| 98 | material.setAmbient(osg::Material::BACK,interp(r, lhs.getAmbient(osg::Material::BACK),rhs.getAmbient(osg::Material::BACK))); |
|---|
| 99 | |
|---|
| 100 | material.setDiffuse(osg::Material::FRONT_AND_BACK,interp(r, lhs.getDiffuse(osg::Material::FRONT),rhs.getDiffuse(osg::Material::FRONT))); |
|---|
| 101 | if (!material.getDiffuseFrontAndBack()) |
|---|
| 102 | material.setDiffuse(osg::Material::BACK,interp(r, lhs.getDiffuse(osg::Material::BACK),rhs.getDiffuse(osg::Material::BACK))); |
|---|
| 103 | |
|---|
| 104 | material.setSpecular(osg::Material::FRONT_AND_BACK,interp(r, lhs.getSpecular(osg::Material::FRONT),rhs.getSpecular(osg::Material::FRONT))); |
|---|
| 105 | if (!material.getSpecularFrontAndBack()) |
|---|
| 106 | material.setSpecular(osg::Material::BACK,interp(r, lhs.getSpecular(osg::Material::BACK),rhs.getSpecular(osg::Material::BACK))); |
|---|
| 107 | |
|---|
| 108 | material.setEmission(osg::Material::FRONT_AND_BACK,interp(r, lhs.getEmission(osg::Material::FRONT),rhs.getEmission(osg::Material::FRONT))); |
|---|
| 109 | if (!material.getEmissionFrontAndBack()) |
|---|
| 110 | material.setEmission(osg::Material::BACK,interp(r, lhs.getEmission(osg::Material::BACK),rhs.getEmission(osg::Material::BACK))); |
|---|
| 111 | |
|---|
| 112 | material.setShininess(osg::Material::FRONT_AND_BACK,interp(r, lhs.getShininess(osg::Material::FRONT),rhs.getShininess(osg::Material::FRONT))); |
|---|
| 113 | if (!material.getShininessFrontAndBack()) |
|---|
| 114 | material.setShininess(osg::Material::BACK,interp(r, lhs.getShininess(osg::Material::BACK),rhs.getShininess(osg::Material::BACK))); |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | void AnimationMaterial::read(std::istream& in) |
|---|
| 118 | { |
|---|
| 119 | while (!in.eof()) |
|---|
| 120 | { |
|---|
| 121 | double time; |
|---|
| 122 | osg::Vec4 color; |
|---|
| 123 | in >> time >> color[0] >> color[1] >> color[2] >> color[3]; |
|---|
| 124 | if(!in.eof()) |
|---|
| 125 | { |
|---|
| 126 | osg::Material* material = new osg::Material; |
|---|
| 127 | material->setAmbient(osg::Material::FRONT_AND_BACK,color); |
|---|
| 128 | material->setDiffuse(osg::Material::FRONT_AND_BACK,color); |
|---|
| 129 | insert(time,material); |
|---|
| 130 | } |
|---|
| 131 | } |
|---|
| 132 | } |
|---|
| 133 | |
|---|
| 134 | void AnimationMaterial::write(std::ostream& fout) const |
|---|
| 135 | { |
|---|
| 136 | const TimeControlPointMap& tcpm = getTimeControlPointMap(); |
|---|
| 137 | for(TimeControlPointMap::const_iterator tcpmitr=tcpm.begin(); |
|---|
| 138 | tcpmitr!=tcpm.end(); |
|---|
| 139 | ++tcpmitr) |
|---|
| 140 | { |
|---|
| 141 | fout<<tcpmitr->first<<" "<<tcpmitr->second->getDiffuse(osg::Material::FRONT)<<std::endl; |
|---|
| 142 | } |
|---|
| 143 | } |
|---|
| 144 | |
|---|
| 145 | bool AnimationMaterial::requiresBlending() const |
|---|
| 146 | { |
|---|
| 147 | const TimeControlPointMap& tcpm = getTimeControlPointMap(); |
|---|
| 148 | for(TimeControlPointMap::const_iterator tcpmitr=tcpm.begin(); |
|---|
| 149 | tcpmitr!=tcpm.end(); |
|---|
| 150 | ++tcpmitr) |
|---|
| 151 | { |
|---|
| 152 | if ((tcpmitr->second->getDiffuse(osg::Material::FRONT))[3]!=1.0f) return true; |
|---|
| 153 | } |
|---|
| 154 | return false; |
|---|
| 155 | } |
|---|
| 156 | |
|---|
| 157 | |
|---|
| 158 | void AnimationMaterialCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) |
|---|
| 159 | { |
|---|
| 160 | if (_animationMaterial.valid() && |
|---|
| 161 | nv->getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR && |
|---|
| 162 | nv->getFrameStamp()) |
|---|
| 163 | { |
|---|
| 164 | double time = nv->getFrameStamp()->getReferenceTime(); |
|---|
| 165 | _latestTime = time; |
|---|
| 166 | |
|---|
| 167 | if (!_pause) |
|---|
| 168 | { |
|---|
| 169 | |
|---|
| 170 | if (_firstTime==DBL_MAX) |
|---|
| 171 | { |
|---|
| 172 | OSG_INFO<<"AnimationMaterialCallback::operator() resetting _firstTime to "<<time<<std::endl; |
|---|
| 173 | _firstTime = time; |
|---|
| 174 | } |
|---|
| 175 | update(*node); |
|---|
| 176 | |
|---|
| 177 | } |
|---|
| 178 | } |
|---|
| 179 | |
|---|
| 180 | |
|---|
| 181 | NodeCallback::traverse(node,nv); |
|---|
| 182 | } |
|---|
| 183 | |
|---|
| 184 | double AnimationMaterialCallback::getAnimationTime() const |
|---|
| 185 | { |
|---|
| 186 | if (_firstTime==DBL_MAX) return 0.0f; |
|---|
| 187 | else return ((_latestTime-_firstTime)-_timeOffset)*_timeMultiplier; |
|---|
| 188 | } |
|---|
| 189 | |
|---|
| 190 | void AnimationMaterialCallback::update(osg::Node& node) |
|---|
| 191 | { |
|---|
| 192 | osg::StateSet* stateset = node.getOrCreateStateSet(); |
|---|
| 193 | osg::Material* material = |
|---|
| 194 | dynamic_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL)); |
|---|
| 195 | |
|---|
| 196 | if (!material) |
|---|
| 197 | { |
|---|
| 198 | material = new osg::Material; |
|---|
| 199 | stateset->setAttribute(material,osg::StateAttribute::OVERRIDE); |
|---|
| 200 | } |
|---|
| 201 | |
|---|
| 202 | _animationMaterial->getMaterial(getAnimationTime(),*material); |
|---|
| 203 | } |
|---|
| 204 | |
|---|
| 205 | |
|---|
| 206 | void AnimationMaterialCallback::reset() |
|---|
| 207 | { |
|---|
| 208 | #if 1 |
|---|
| 209 | _firstTime = DBL_MAX; |
|---|
| 210 | _pauseTime = DBL_MAX; |
|---|
| 211 | #else |
|---|
| 212 | _firstTime = _latestTime; |
|---|
| 213 | _pauseTime = _latestTime; |
|---|
| 214 | #endif |
|---|
| 215 | } |
|---|
| 216 | |
|---|
| 217 | void AnimationMaterialCallback::setPause(bool pause) |
|---|
| 218 | { |
|---|
| 219 | if (_pause==pause) |
|---|
| 220 | { |
|---|
| 221 | return; |
|---|
| 222 | } |
|---|
| 223 | |
|---|
| 224 | _pause = pause; |
|---|
| 225 | |
|---|
| 226 | if (_firstTime==DBL_MAX) return; |
|---|
| 227 | |
|---|
| 228 | if (_pause) |
|---|
| 229 | { |
|---|
| 230 | _pauseTime = _latestTime; |
|---|
| 231 | } |
|---|
| 232 | else |
|---|
| 233 | { |
|---|
| 234 | _firstTime += (_latestTime-_pauseTime); |
|---|
| 235 | } |
|---|
| 236 | } |
|---|