00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <PVLE/Entity/Explosion.h>
00028 #include <PVLE/3D/Commons.h>
00029 #include <PVLE/Util/Math.h>
00030 #include <PVLE/Physics/Utility.h>
00031 #include <PVLE/Physics/Contact.h>
00032 #include <PVLE/Physics/Body.h>
00033
00034 #include <PVLE/Game/PVLEGame.h>
00035 #include <algorithm>
00036
00037 #include <osg/CullFace>
00038 #include <osg/BlendFunc>
00039 #include <osg/Billboard>
00040 #include <osg/Geode>
00041 #include <osg/ShapeDrawable>
00042 #include <osg/Material>
00043 #include <osg/ImageSequence>
00044 #include <osg/Texture2D>
00045 #include <osg/Depth>
00046
00047 #include <osg/LightSource>
00048 #include <PVLE/Util/DebugGlobals.h>
00049
00050 #include <limits.h>
00051
00052 ExplosionParams::ExplosionParams()
00053 : renderMode(RENDER_BILLBOARD_DEPTH_ALWAYS),
00054 maxRadius(1), growingSpeed(1),
00055 maxForce(0),
00056 colorAttenuationPow(1.5f),
00057
00058
00059 diffuseColor(1,.9f,.3f,.75f), emissionColor(.8f,.4f,0,1),
00060 spriteEmission(.9f, .9f, .9f, 1),
00061 lightDiffuse(1,.8f,0,1),
00062 lightLinearAttenuation(.003f),
00063 lightNumber(7), pLSM(NULL), lightBasePriority(1), pLightStateSet(NULL)
00064 {
00065 }
00066
00067
00068 Explosion::Explosion(bool createAnimation, const C3DPhy * pInheritTeamAndPlayer) :
00069 C3DPhy(pInheritTeamAndPlayer),
00070 radius(0),
00071 pSpriteIS(NULL), pSphere(NULL), pLight(NULL),
00072 spriteTime(0)
00073 {
00074 init(createAnimation);
00075 }
00076
00077
00078 Explosion::Explosion(const ExplosionParams & params, bool createAnimation, const C3DPhy * pInheritTeamAndPlayer) :
00079 ExplosionParams(params),
00080 C3DPhy(pInheritTeamAndPlayer),
00081 radius(0),
00082 pSpriteIS(NULL), pSphere(NULL), pLight(NULL),
00083 spriteTime(0)
00084 {
00085 init(createAnimation);
00086 }
00087
00088
00089 void Explosion::init(bool createAnimation) {
00090 ASSERT(maxRadius>0);
00091 std::fill(vParams, vParams+WeaponEnergy::MAX_WEAPON_ENERGY, 0.f);
00092
00093
00094 if (maxForce>0) {
00095 Physics::Geom * pGeom = Physics::createCanonicalSphereGeom(radius);
00096 addGeom(pGeom);
00097 }
00098
00099
00100
00101 setModel(new osg::MatrixTransform);
00102
00103
00104 {
00105 pSphere = createShapeGeodeSphere(maxRadius);
00106 pModel->addChild(pSphere);
00107 osg::StateSet * pStateSet = pSphere->getOrCreateStateSet();
00108
00109
00110 pStateSet->setAttributeAndModes(new osg::CullFace(osg::CullFace::FRONT), osg::StateAttribute::OFF);
00111 pStateSet->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK), osg::StateAttribute::OFF);
00112
00113 pStateSet->setAttributeAndModes(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
00114 pStateSet->setAttributeAndModes(new osg::Depth(osg::Depth::LEQUAL, 0, 1, false));
00115 pStateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
00116
00117 boost::polymorphic_downcast<osg::Geode *>(pSphere->getChild(0))->getDrawable(0)->setUseDisplayList(false);
00118
00119 osg::Material * pMaterial = new osg::Material();
00120 pMaterial->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,0));
00121
00122 pStateSet->setAttributeAndModes(pMaterial);
00123 }
00124
00125
00126 if (createAnimation) {
00127 pSpriteIS = new osg::ImageSequence;
00128 pSpriteIS->setLength(growingSpeed>0 ? maxRadius / growingSpeed : 1);
00129
00130 pSpriteIS->setMode(osg::ImageSequence::PRE_LOAD_ALL_IMAGES);
00131
00132 pSpriteIS->play();
00133
00134 osg::Texture2D* pTexture = new osg::Texture2D;
00135 pTexture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
00136 pTexture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR);
00137 pTexture->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP);
00138 pTexture->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP);
00139
00140 pTexture->setImage(pSpriteIS);
00141
00142 osg::Geode * pSprite = NULL;
00143 if (renderMode == RENDER_SPRITE) pSprite = new osg::Geode;
00144 else {
00145 osg::Billboard * billboard = new osg::Billboard;
00146 billboard->setMode(osg::Billboard::POINT_ROT_EYE);
00147 pSprite = billboard;
00148 }
00149
00150 pModel->addChild(pSprite);
00151 float spriteSize = maxRadius * 1.4f;
00152 pSprite->addDrawable(osg::createTexturedQuadGeometry(osg::Vec3(spriteSize/2,0,-spriteSize/2), osg::Vec3(-spriteSize,0,0), osg::Vec3(0,0,spriteSize)));
00153 osg::StateSet * pStateSet = pSprite->getOrCreateStateSet();
00154 pStateSet->setTextureAttributeAndModes(0,pTexture,osg::StateAttribute::ON);
00155
00156 pStateSet->setAttributeAndModes(new osg::CullFace(osg::CullFace::FRONT_AND_BACK), osg::StateAttribute::OFF);
00157 pStateSet->setAttributeAndModes(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE));
00158 if (renderMode == RENDER_BILLBOARD_DEPTH_ALWAYS) {
00159 pStateSet->setAttributeAndModes(new osg::Depth(osg::Depth::ALWAYS, 0, 1, false));
00160 } else {
00161 pStateSet->setAttributeAndModes(new osg::Depth(osg::Depth::LEQUAL, 0, 1, false));
00162 }
00163 pStateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
00164
00165
00166 osg::Material * pMaterial = new osg::Material();
00167 pMaterial->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,spriteEmission.w()));
00168
00169 pMaterial->setEmission(osg::Material::FRONT_AND_BACK, spriteEmission);
00170
00171 pStateSet->setAttributeAndModes(pMaterial);
00172
00173
00174
00175
00176 }
00177
00178
00179 if (pLightStateSet) {
00180 if (pLSM) lightNumber = pLSM->request(this, lightBasePriority, new LSCallback(), true);
00181 if (lightNumber != UINT_MAX) createLight(lightNumber);
00182 }
00183
00184 bind();
00185 }
00186
00187
00188 void Explosion::createLight(UINT lightNumber) {
00189 ASSERT(pLightStateSet);
00190 ASSERT(lightNumber != UINT_MAX);
00191
00192 pLight = new osg::LightSource;
00193 pModel->addChild(pLight);
00194 osg::Light * pLightParams = new osg::Light;
00195 pLightParams->setAmbient(osg::Vec4());
00196 pLightParams->setDiffuse(lightDiffuse);
00197 pLightParams->setSpecular(lightDiffuse);
00198 pLightParams->setPosition(osg::Vec4f(0,0,0,1));
00199 pLightParams->setLinearAttenuation(lightLinearAttenuation);
00200
00201 pLightParams->setLightNum(lightNumber);
00202 pLight->setLight(pLightParams);
00203
00204 pLight->setStateSetModes(*pLightStateSet, osg::StateAttribute::ON);
00205
00206
00207 }
00208
00209
00210 Explosion::~Explosion() {
00211 if (pLightStateSet && pLight) {
00212 pLight->setStateSetModes(*pLightStateSet, osg::StateAttribute::OFF);
00213 }
00214 if (pLSM) pLSM->remove(this);
00215
00216
00217 }
00218
00219
00220
00221 void Explosion::step(dReal stepSize) {
00222 spriteTime += stepSize;
00223 if (growingSpeed<=0) radius = maxRadius;
00224 else {
00225 radius += growingSpeed * stepSize;
00226 if (radius >= maxRadius) {
00227
00228 radius = maxRadius;
00229
00230
00231 if (pSpriteIS && spriteTime >= pSpriteIS->getLength() * pSpriteIS->getTimeMultiplier() * .97)
00232 onTTLZero();
00233 }
00234 }
00235
00236
00237 if (maxForce>0) {
00238 ASSERT(!vGeoms.empty());
00239 boost::polymorphic_downcast<Physics::SphereHandler *>( vGeoms[0]->getHandler() )->setRadius(radius);
00240 }
00241
00242
00243 osg::Geode * pGeode = boost::polymorphic_downcast<osg::Geode *>(pSphere->getChild(0));
00244 boost::polymorphic_downcast<osg::Sphere *>(pGeode->getDrawable(0)->getShape())->setRadius(radius);
00245
00246
00247 ASSERT(maxRadius>0 && radius>=0);
00248 float growth = radius / maxRadius;
00249 float attenuation = 1 - powf(growth, colorAttenuationPow);
00250 clamp(attenuation, 0.f, 1.f);
00251
00252
00253
00254
00255 osg::StateSet * pStateSet = pSphere->getOrCreateStateSet();
00256 osg::Material * pMaterial = boost::polymorphic_downcast<osg::Material *>(pStateSet->getAttribute(osg::StateAttribute::MATERIAL));
00257 ASSERT(pMaterial);
00258
00259 pMaterial->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(diffuseColor.x(), diffuseColor.y(), diffuseColor.z(), diffuseColor.w() * attenuation));
00260
00261 pMaterial->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(emissionColor.x(), emissionColor.y(), emissionColor.z(), emissionColor.w() * attenuation));
00262 pStateSet->setAttributeAndModes(pMaterial);
00263
00264 if (pLightStateSet && pLight) {
00265 osg::Light * pLightParams = pLight->getLight();
00266
00267 pLightParams->setDiffuse(lightDiffuse * attenuation);
00268
00269 pLightParams->setSpecular(lightDiffuse * attenuation);
00270 }
00271 if (pLSM) {
00272 pLSM->updatePriority(this, static_cast<LightSourceManager::Priority>(lightBasePriority * attenuation));
00273 }
00274
00275
00276 }
00277
00278 bool Explosion::hitBefore(Physics::Contact * pContacts, unsigned int nbContacts, Physics::Contact * pMaxEnergyContact, Physics::Geom & thisGeom, Physics::Geom & otherGeom, Physics::Body *& inout_pThisBody, Physics::Body *& inout_pOtherBody) {
00279 ASSERT(maxForce>0);
00280 if (radius == maxRadius) return false;
00281
00282
00283 ASSERT(&thisGeom == vGeoms[0]);
00284 if (inout_pOtherBody) {
00285 const osg::Vec3f & contactPos = pMaxEnergyContact->getPos();
00286 osg::Vec3 force(contactPos - dGeomGetPositionV(thisGeom));
00287 float len = force.length();
00288 if (len > 0) {
00289 ASSERT(maxRadius>0 && radius>=0);
00290 float growth = radius / maxRadius;
00291
00292 float attenuation = 1 - growth*growth;
00293 clamp(attenuation, 0.f, 1.f);
00294 force *= maxForce * attenuation / len;
00295
00296 dBodyEnable(*inout_pOtherBody);
00297 dBodyAddForceAtPos(*inout_pOtherBody, force, contactPos);
00298 }
00299 }
00300
00301 C3DPhy * pOther3DPhy = NULL;
00302 IGeomCollisionContainer * pContainer = otherGeom.getCollisionContainer();
00303 if (pContainer) pOther3DPhy = pContainer->as3DPhy();
00304
00305
00306 float friendlyFireCoef = 1;
00307 if (pTeam && pTeam == pOther3DPhy->getTeam()) {
00308
00309
00310 friendlyFireCoef = PVLEGameHolder::instance().get()->getFriendlyFire();
00311 }
00312
00313 if (friendlyFireCoef>0) {
00314
00315 ASSERT(maxRadius>0 && radius>=0);
00316 float growth = radius / maxRadius;
00317 float attenuation = 1 - powf(growth, colorAttenuationPow);
00318 clamp(attenuation, 0.f, 1.f);
00319 ASSERT(vParams[WeaponEnergy::PERFORANT] == 0);
00320 for(int it=0; it!=WeaponEnergy::MAX_WEAPON_ENERGY; ++it) {
00321 pOther3DPhy->isHitBy(static_cast<WeaponEnergy::EEneryType>(it), vParams[it] * attenuation * friendlyFireCoef, pMaxEnergyContact->getPos());
00322 }
00323 }
00324
00325 return false;
00326 }
00327
00328
00329 bool Explosion::LSCallback::onSourceTaken(LightSourceManager * pLightSourceManager, osg::Referenced * pUserObject, UINT lightNumber) {
00330 Explosion & exp = *boost::polymorphic_cast<Explosion*>(pUserObject);
00331 if (exp.pLightStateSet && exp.pLight) {
00332 ASSERT(exp.pLight->getLight()->getLightNum() == lightNumber);
00333 exp.pLight->setStateSetModes(*exp.pLightStateSet, osg::StateAttribute::OFF);
00334 exp.pLight = NULL;
00335 }
00336
00337 if (_nestedCallback.valid()) return _nestedCallback->onSourceTaken(pLightSourceManager, pUserObject, lightNumber);
00338 else return true;
00339 }
00340
00341
00342 bool Explosion::LSCallback::onSourceAvailable(LightSourceManager * pLightSourceManager, osg::Referenced * pUserObject, UINT lightNumber) {
00343 if (_nestedCallback.valid()) return _nestedCallback->onSourceAvailable(pLightSourceManager, pUserObject, lightNumber);
00344
00345 Explosion & exp = *boost::polymorphic_cast<Explosion*>(pUserObject);
00346 exp.createLight(lightNumber);
00347 return true;
00348 }
00349
00350 void Explosion::LSCallback::onUserDropped(LightSourceManager * pLightSourceManager, osg::Referenced * pUserObject) {
00351 Explosion & exp = *boost::polymorphic_cast<Explosion*>(pUserObject);
00352 exp.pLSM = NULL;
00353 }