void PhysicsContactEffectManager::physicsContact(const PhysicsContact &contact)
	{
		// WARNING: unsafe IGamePhysicsObject -> AbstractPhysicsObject casts!
		AbstractPhysicsObject *o1 = (AbstractPhysicsObject *)contact.obj1;
		AbstractPhysicsObject *o2 = (AbstractPhysicsObject *)contact.obj2;
		//assert(o1 != NULL);
		//assert(o2 != NULL);
		assert(contact.physicsObject1);
		assert(contact.physicsObject2);

#ifdef PHYSICS_PHYSX
		int sm1 = contact.physicsObject1->getIntData();
		int sm2 = contact.physicsObject2->getIntData();
		if(sm1 == SOUNDMATERIALPARSER_NO_SOUND_INDEX || sm2 == SOUNDMATERIALPARSER_NO_SOUND_INDEX)
		{
			return;
		}
#else
		if (o1->getSoundMaterial() == SOUNDMATERIALPARSER_NO_SOUND_INDEX
			|| o2->getSoundMaterial() == SOUNDMATERIALPARSER_NO_SOUND_INDEX)
		{
			return;
		}
#endif

		const util::SoundMaterialParser::SoundMaterialList &smlist = impl->soundmp->getSoundMaterials();
		for (int i = 0; i < 2; i++)
		{
			AbstractPhysicsObject *o = o1;
			if (i == 1) 
			{
				o = o2;
			}
#ifdef PHYSICS_PHYSX
			int smindex = sm1;
			if (i == 1) 
			{
				smindex = sm2;
			}
			assert(smindex >= 0 && smindex < (int)smlist.size());
#else
			int smindex = o->getSoundMaterial();
#endif

			bool makeEffect = false;
			VC3 effectpos;

			if(o)
			{
				if(contact.contactForceLen >= smlist[smindex].requiredEffectForce)
				{
					effectpos = contact.contactPosition;

					VC3 accel = o->getAcceleration();
					VC3 angaccel = o->getAngularAcceleration();

					if (accel.GetSquareLength() >= smlist[smindex].requiredEffectAcceleration * smlist[smindex].requiredEffectAcceleration
						|| angaccel.GetSquareLength() >= smlist[smindex].requiredEffectAngularAcceleration * smlist[smindex].requiredEffectAngularAcceleration)
					{
						makeEffect = true;
					}

				}
			}
			else
			{
				if(contact.contactForceLen >= smlist[smindex].requiredEffectForce)
				{
					makeEffect = true;
					effectpos = contact.contactPosition;
				}
			}

			if(makeEffect)
			{
				if (o)
				{
					if (impl->game->gameTimer < o->getLastEffectTick() + (smlist[smindex].effectMaxRate / GAME_TICK_MSEC))
					{
						makeEffect = false;
					} else {
						o->setLastEffectTick(impl->game->gameTimer);
					}
				}
			}

			if(makeEffect)
			{
				std::vector<std::string> effectlist = smlist[smindex].effects;
				if (effectlist.size() > 0)
				{
					float effectFactor = 1.0f;
					if (smlist[smindex].requiredEffectForce > 0.0f)
					{
						// 0% - 100% effect factor (100% required force - 200% required force)
						effectFactor = (contact.contactForceLen / smlist[smindex].requiredEffectForce) - 1.0f;
						if (effectFactor > 1.0f)
							effectFactor = 1.0f;

						assert(effectFactor >= 0.0f);
						assert(effectFactor <= 1.0f);
					}

					int effnum = (int)(effectFactor * (effectlist.size() - 1));
					if (effnum < 0) effnum = 0;
					if (effnum >= (int)effectlist.size()) effnum = (int)effectlist.size() - 1;
					const char *effname = effectlist[effnum].c_str();

					ui::VisualEffectManager *vefman = impl->game->gameUI->getVisualEffectManager();
					if (vefman != NULL)
					{
						assert(effname != NULL);

						// TODO: optimize this!!!
						int visualEffId = vefman->getVisualEffectIdByName(effname);

						if (visualEffId != -1)
						{
							// TODO: proper lifetime
							int lifetime = GAME_TICKS_PER_SECOND / 2;
							VisualEffect *vef = vefman->createNewManagedVisualEffect(visualEffId, lifetime, NULL, NULL,
								effectpos, effectpos, VC3(0,0,0), VC3(0,0,0), impl->game);

							if (vef == NULL)
							{
								Logger::getInstance()->error("PhysicsContactEffectManager::physicsContact - Failed to create visual effect.");
								Logger::getInstance()->debug(effname);
							}
						} else {
							Logger::getInstance()->error("PhysicsContactEffectManager::physicsContact - Given visual effect name not found.");
							Logger::getInstance()->debug(effname);
						}
					}
				}
			}
		}
	}
	void PhysicsContactSoundManager::physicsContact(const PhysicsContact &contact)
	{
		// WARNING: unsafe IGamePhysicsObject -> AbstractPhysicsObject casts!
		AbstractPhysicsObject *o1 = (AbstractPhysicsObject *)contact.obj1;
		AbstractPhysicsObject *o2 = (AbstractPhysicsObject *)contact.obj2;
		//assert(o1 != NULL);
		//assert(o2 != NULL);
		assert(contact.physicsObject1);
		assert(contact.physicsObject2);

#ifdef PHYSICS_PHYSX
		int sm1 = contact.physicsObject1->getIntData();
		int sm2 = contact.physicsObject2->getIntData();

		// int claw_material = impl->soundmp->getMaterialIndexByName( "claw" );
		// int claw_body_material = impl->soundmp->getMaterialIndexByName( "claw_body" );

		if(sm1 == SOUNDMATERIALPARSER_NO_SOUND_INDEX || sm2 == SOUNDMATERIALPARSER_NO_SOUND_INDEX)
		{
			return;
		}
#else
		if (o1->getSoundMaterial() == SOUNDMATERIALPARSER_NO_SOUND_INDEX
			|| o2->getSoundMaterial() == SOUNDMATERIALPARSER_NO_SOUND_INDEX)
		{
			return;
		}
#endif

		const util::SoundMaterialParser::SoundMaterialList &smlist = impl->soundmp->getSoundMaterials();
		for (int i = 0; i < 2; i++)
		{
			AbstractPhysicsObject *o = o1;
			if (i == 1) 
			{
				o = o2;
			}
#ifdef PHYSICS_PHYSX
			int smindex = sm1;
			if (i == 1) 
			{
				smindex = sm2;
			}
			assert(smindex >= 0 && smindex < (int)smlist.size());
#else
			int smindex = o->getSoundMaterial();
#endif

			bool makeSound = false;
			VC3 soundpos;

			if(o)
			{
				/*
				// debug logging
				if( contact.contactForceLen > 1.0f && smlist[smindex].sounds.empty() == false )
				{
					VC3 accel = o->getAcceleration();
					VC3 angaccel = o->getAngularAcceleration();

					std::stringstream ss;
					ss << contact.contactForceLen << ", " << accel.GetLength() << ", " << angaccel.GetLength() << std::endl;
					Logger::getInstance()->error( ss.str().c_str() );
				}
				*/

				if(contact.contactForceLen >= smlist[smindex].requiredForce)
				{
					// TODO: use contact position instead of object's position.
					soundpos = o->getPosition();

					VC3 accel = o->getAcceleration();
					VC3 angaccel = o->getAngularAcceleration();

					

					

					if (accel.GetSquareLength() >= smlist[smindex].requiredAcceleration * smlist[smindex].requiredAcceleration
						|| angaccel.GetSquareLength() >= smlist[smindex].requiredAngularAcceleration * smlist[smindex].requiredAngularAcceleration)
					{
						makeSound = true;

						/*
						std::vector<std::string> soundlist = smlist[smindex].sounds;
						if (soundlist.size() > 0)
						{
							// TODO: some better pseudo-random logic here maybe...
							int sndnum = rand() % soundlist.size();
							const char *soundfile = soundlist[sndnum].c_str();

							float volumeFactor = 1.0f;
							if (smlist[smindex].requiredForce > 0.0f)
							{
								// 40% - 100% volume factor (100% required force - 200% required force)
								volumeFactor = (contact.contactForceLen / smlist[smindex].requiredForce) - 1.0f;
								volumeFactor *= 0.6f;
								volumeFactor += 0.4f;
								if (volumeFactor > 1.0f)
									volumeFactor = 1.0f;

								assert(volumeFactor >= 0.4f);
								assert(volumeFactor <= 1.0f);
							}

							impl->gameUI->playSoundEffect(soundfile, soundpos.x, soundpos.y, soundpos.z, 
								false, (int)(DEFAULT_SOUND_EFFECT_VOLUME * volumeFactor), DEFAULT_SOUND_RANGE, DEFAULT_SOUND_PRIORITY_NORMAL);
						}
						*/
					}

				}

				// not to repeat the effect too frequently
				if( o != NULL && makeSound && ( impl->gameUI->game->gameTimer - o->getLastEffectSoundTick() ) > ( 200 / GAME_TICK_MSEC ) )
				{
					o->setLastEffectSoundTick( impl->gameUI->game->gameTimer ); 
				}
				else
				{
					makeSound = false;
				}
			}
			else
			{
				if(contact.contactForceLen >= smlist[smindex].requiredForce)
				{
					makeSound = true;

#ifdef PHYSICS_PHYSX
					if(i == 0)
						contact.physicsObject1->getPosition(soundpos);
					else
						contact.physicsObject2->getPosition(soundpos);
#endif
				}
			}

			if(makeSound)
			{
				std::vector<std::string> soundlist = smlist[smindex].sounds;
				if (soundlist.size() > 0)
				{
					// TODO: some better pseudo-random logic here maybe...
					int sndnum = rand() % soundlist.size();
					// const char *soundfile = soundlist[sndnum].c_str();
					
					float volumeFactor = 1.0f;
					std::string soundfile = soundlist[sndnum];

					if (smlist[smindex].requiredForce > 0.0f)
					{
						// 100% required force - 500% required force
						float contactFactor = contact.contactForceLen / ( smlist[smindex].requiredForce * 5.0f );
						if( contactFactor > 1.0f ) 
							contactFactor = 1.0f;

						int sndnum = (int)((float)( soundlist.size() - 1 ) * contactFactor + 0.5f);
						sndnum += ( rand() % 3 ) - 1;

						if( sndnum < 0 ) 
							sndnum = 0;
						
						if( sndnum > (signed)( soundlist.size() - 1 ) ) 
							sndnum = (signed)( soundlist.size() - 1 );
						
						soundfile = soundlist[sndnum];
						/*
						// 40% - 100% volume factor (100% required force - 200% required force)
						volumeFactor = (contact.contactForceLen / smlist[smindex].requiredForce) - 1.0f;
						volumeFactor *= 0.6f;
						volumeFactor += 0.4f;
						if (volumeFactor > 1.0f)
							volumeFactor = 1.0f;

						assert(volumeFactor >= 0.4f);
						assert(volumeFactor <= 1.0f);
						*/
					}

					impl->gameUI->playSoundEffect(soundfile.c_str(), soundpos.x, soundpos.y, soundpos.z, 
						false, (int)(DEFAULT_SOUND_EFFECT_VOLUME * volumeFactor), DEFAULT_SOUND_RANGE, DEFAULT_SOUND_PRIORITY_NORMAL);
				}
			}
		}
	}