Initial commit
This commit is contained in:
715
Torque/SDK/engine/game/fx/weatherLightning.cpp
Normal file
715
Torque/SDK/engine/game/fx/weatherLightning.cpp
Normal file
@@ -0,0 +1,715 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "dgl/dgl.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "math/mRandom.h"
|
||||
#include "sceneGraph/sceneState.h"
|
||||
#include "audio/audioDataBlock.h"
|
||||
#include "game/fx/weatherLightning.h"
|
||||
|
||||
IMPLEMENT_CO_CLIENTEVENT_V1(WeatherLightningStrikeEvent);
|
||||
IMPLEMENT_CO_DATABLOCK_V1(WeatherLightningData);
|
||||
IMPLEMENT_CO_NETOBJECT_V1(WeatherLightning);
|
||||
|
||||
MRandomLCG sgRandomGen;
|
||||
|
||||
S32 QSORT_CALLBACK cmpWLSounds(const void* p1, const void* p2)
|
||||
{
|
||||
U32 i1 = *((const S32*)p1);
|
||||
U32 i2 = *((const S32*)p2);
|
||||
|
||||
if (i1 < i2) {
|
||||
return 1;
|
||||
} else if (i1 > i2) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
S32 QSORT_CALLBACK cmpWLTextures(const void* t1, const void* t2)
|
||||
{
|
||||
StringTableEntry ta = *(StringTableEntry*)t1;
|
||||
StringTableEntry tb = *(StringTableEntry*)t2;
|
||||
|
||||
if(ta && ta[0] != '\0')
|
||||
{
|
||||
if(tb && tb[0] != '\0')
|
||||
return dStricmp(ta, tb);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(tb && tb[0] != '\0')
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
WeatherLightningStrikeEvent::WeatherLightningStrikeEvent()
|
||||
{
|
||||
mLightning = NULL;
|
||||
}
|
||||
|
||||
WeatherLightningStrikeEvent::~WeatherLightningStrikeEvent()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void WeatherLightningStrikeEvent::pack(NetConnection* con, BitStream* stream)
|
||||
{
|
||||
if(!mLightning)
|
||||
{
|
||||
stream->writeFlag(false);
|
||||
return;
|
||||
}
|
||||
|
||||
S32 ghostIndex = con->getGhostIndex(mLightning);
|
||||
if(ghostIndex == -1)
|
||||
{
|
||||
stream->writeFlag(false);
|
||||
return;
|
||||
}
|
||||
|
||||
stream->writeFlag(true);
|
||||
stream->writeRangedU32(U32(ghostIndex), 0, NetConnection::MaxGhostCount);
|
||||
stream->writeFloat(mStart.x, PositionalBits);
|
||||
stream->writeFloat(mStart.y, PositionalBits);
|
||||
}
|
||||
|
||||
void WeatherLightningStrikeEvent::unpack(NetConnection* con, BitStream* stream)
|
||||
{
|
||||
if(!stream->readFlag())
|
||||
return;
|
||||
S32 ghostIndex = stream->readRangedU32(0, NetConnection::MaxGhostCount);
|
||||
mLightning = NULL;
|
||||
NetObject* pObject = con->resolveGhost(ghostIndex);
|
||||
if(pObject)
|
||||
mLightning = dynamic_cast<WeatherLightning*>(pObject);
|
||||
|
||||
mStart.x = stream->readFloat(PositionalBits);
|
||||
mStart.y = stream->readFloat(PositionalBits);
|
||||
}
|
||||
|
||||
void WeatherLightningStrikeEvent::process(NetConnection*)
|
||||
{
|
||||
if (mLightning)
|
||||
mLightning->processEvent(this);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
WeatherLightningData::WeatherLightningData()
|
||||
{
|
||||
dMemset(strikeTextureNames, 0, sizeof(strikeTextureNames));
|
||||
dMemset(flashTextureNames, 0, sizeof(flashTextureNames));
|
||||
dMemset(fuzzyTextureNames, 0, sizeof(fuzzyTextureNames));
|
||||
|
||||
dMemset(strikeTextures, 0, sizeof(strikeTextures));
|
||||
dMemset(flashTextures, 0, sizeof(flashTextures));
|
||||
dMemset(fuzzyTextures, 0, sizeof(fuzzyTextures));
|
||||
|
||||
strikeSoundId = -1;
|
||||
strikeSound = NULL_AUDIOHANDLE;
|
||||
for(U32 i = 0; i < MaxSounds; i++)
|
||||
{
|
||||
thunderSoundIds[i] = -1;
|
||||
thunderSounds[i] = NULL_AUDIOHANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
WeatherLightningData::~WeatherLightningData()
|
||||
{
|
||||
//
|
||||
};
|
||||
|
||||
void WeatherLightningData::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField("strikeTextures", TypeFilename, Offset(strikeTextureNames, WeatherLightningData), MaxStrikeTextures);
|
||||
addField("flashTextures", TypeFilename, Offset(flashTextureNames, WeatherLightningData), MaxFlashTextures);
|
||||
addField("fuzzyTextures", TypeFilename, Offset(fuzzyTextureNames, WeatherLightningData), MaxFuzzyTextures);
|
||||
|
||||
addField("strikeSound", TypeAudioProfilePtr, Offset(strikeSound, WeatherLightningData));
|
||||
addField("thunderSounds", TypeAudioProfilePtr, Offset(thunderSounds, WeatherLightningData), MaxSounds);
|
||||
}
|
||||
|
||||
bool WeatherLightningData::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
if(!strikeSound && strikeSoundId != -1)
|
||||
{
|
||||
if(Sim::findObject(strikeSoundId, strikeSound) == false)
|
||||
Con::errorf(ConsoleLogEntry::General, "WeatherLightningData::onAdd: Invalid packet, bad datablockId(sound: %d", strikeSound);
|
||||
}
|
||||
|
||||
for(U32 i = 0; i < MaxSounds; i++)
|
||||
{
|
||||
if(!thunderSounds[i] && thunderSoundIds[i] != -1)
|
||||
{
|
||||
if(Sim::findObject(thunderSoundIds[i], thunderSounds[i]) == false)
|
||||
Con::errorf(ConsoleLogEntry::General, "WeahterLightningData::onAdd: Invalid packet, bad datablockId(sound: %d", thunderSounds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WeatherLightningData::preload(bool server, char errorBuffer[256])
|
||||
{
|
||||
if(Parent::preload(server, errorBuffer) == false)
|
||||
return false;
|
||||
|
||||
dQsort(strikeTextureNames, MaxStrikeTextures, sizeof(StringTableEntry), cmpWLTextures);
|
||||
dQsort(flashTextureNames, MaxFlashTextures, sizeof(StringTableEntry), cmpWLTextures);
|
||||
dQsort(fuzzyTextureNames, MaxFuzzyTextures, sizeof(StringTableEntry), cmpWLTextures);
|
||||
|
||||
if(!server)
|
||||
{
|
||||
for(numStrikes = 0; numStrikes < MaxStrikeTextures; numStrikes++)
|
||||
{
|
||||
if(strikeTextureNames[numStrikes] && strikeTextureNames[numStrikes][0] != '\0')
|
||||
strikeTextures[numStrikes] = TextureHandle(strikeTextureNames[numStrikes], MeshTexture);
|
||||
else
|
||||
break;
|
||||
}
|
||||
for(numFlashes = 0; numFlashes < MaxFlashTextures && flashTextureNames[numFlashes] != NULL; numFlashes++)
|
||||
{
|
||||
if(flashTextureNames[numFlashes] && flashTextureNames[numFlashes][0] != '\0')
|
||||
flashTextures[numFlashes] = TextureHandle(flashTextureNames[numFlashes], MeshTexture);
|
||||
else
|
||||
break;
|
||||
}
|
||||
for(numFuzzes = 0; numFuzzes < MaxFuzzyTextures && fuzzyTextureNames[numFuzzes] != NULL; numFuzzes++)
|
||||
{
|
||||
if(fuzzyTextureNames[numFuzzes] && fuzzyTextureNames[numFuzzes][0] != '\0')
|
||||
fuzzyTextures[numFuzzes] = TextureHandle(fuzzyTextureNames[numFuzzes], MeshTexture);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dQsort(thunderSounds, MaxSounds, sizeof(AudioProfile*), cmpWLSounds);
|
||||
for(numSounds = 0; numSounds < MaxSounds && thunderSounds[numSounds] != NULL_AUDIOHANDLE; numSounds++) {
|
||||
//
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WeatherLightningData::packData(BitStream* stream)
|
||||
{
|
||||
Parent::packData(stream);
|
||||
|
||||
U32 i;
|
||||
for (i = 0; i < MaxStrikeTextures; i++)
|
||||
stream->writeString(strikeTextureNames[i]);
|
||||
for(i = 0; i < MaxFlashTextures; i++)
|
||||
stream->writeString(flashTextureNames[i]);
|
||||
for(i = 0; i < MaxFuzzyTextures; i++)
|
||||
stream->writeString(fuzzyTextureNames[i]);
|
||||
|
||||
if(stream->writeFlag(strikeSound != NULL_AUDIOHANDLE))
|
||||
stream->writeRangedU32(strikeSound->getId(), DataBlockObjectIdFirst,
|
||||
DataBlockObjectIdLast);
|
||||
|
||||
for(i = 0; i < MaxSounds; i++)
|
||||
{
|
||||
if(stream->writeFlag(thunderSounds[i] != NULL_AUDIOHANDLE))
|
||||
stream->writeRangedU32(thunderSounds[i]->getId(), DataBlockObjectIdFirst,
|
||||
DataBlockObjectIdLast);
|
||||
}
|
||||
}
|
||||
|
||||
void WeatherLightningData::unpackData(BitStream* stream)
|
||||
{
|
||||
Parent::unpackData(stream);
|
||||
|
||||
U32 i;
|
||||
for(i = 0; i < MaxStrikeTextures; i++)
|
||||
strikeTextureNames[i] = stream->readSTString();
|
||||
for(i = 0; i < MaxFlashTextures; i++)
|
||||
flashTextureNames[i] = stream->readSTString();
|
||||
for(i = 0; i < MaxFuzzyTextures; i++)
|
||||
fuzzyTextureNames[i] = stream->readSTString();
|
||||
|
||||
if(stream->readFlag())
|
||||
strikeSoundId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||
else
|
||||
strikeSoundId = -1;
|
||||
|
||||
for(i = 0; i < MaxSounds; i++)
|
||||
{
|
||||
if(stream->readFlag())
|
||||
thunderSoundIds[i] = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||
else
|
||||
thunderSoundIds[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
WeatherLightning::WeatherLightning()
|
||||
{
|
||||
mNetFlags.set(Ghostable | ScopeAlways);
|
||||
mTypeMask |= StaticObjectType|EnvironmentObjectType;
|
||||
|
||||
lastThink = 0;
|
||||
strikesPerMinute = 9;
|
||||
boltDeathAge = 1.5;
|
||||
}
|
||||
|
||||
WeatherLightning::~WeatherLightning()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
void WeatherLightning::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addNamedField(strikesPerMinute, TypeS32, WeatherLightning);
|
||||
addNamedField(boltDeathAge, TypeF32, WeatherLightning);
|
||||
}
|
||||
|
||||
bool WeatherLightning::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
mObjBox.min.set( -0.5, -0.5, -0.5 );
|
||||
mObjBox.max.set( 0.5, 0.5, 0.5 );
|
||||
resetWorldBox();
|
||||
|
||||
addToScene();
|
||||
return true;
|
||||
}
|
||||
|
||||
void WeatherLightning::onRemove()
|
||||
{
|
||||
while(mActiveBolts.size())
|
||||
{
|
||||
WeatherLightningBolt* bolt = mActiveBolts[0];
|
||||
delete bolt;
|
||||
mActiveBolts.erase_fast(U32(0));
|
||||
}
|
||||
while(mSoundEvents.size())
|
||||
mSoundEvents.erase_fast(U32(0));
|
||||
|
||||
removeFromScene();
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
bool WeatherLightning::onNewDataBlock(GameBaseData* dptr)
|
||||
{
|
||||
mDataBlock = dynamic_cast<WeatherLightningData*>(dptr);
|
||||
if(!mDataBlock || !Parent::onNewDataBlock(dptr))
|
||||
return false;
|
||||
|
||||
scriptOnNewDataBlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WeatherLightning::prepRenderImage(SceneState* state, const U32 stateKey, const U32, const bool)
|
||||
{
|
||||
if(isLastState(state, stateKey))
|
||||
return false;
|
||||
setLastState(state, stateKey);
|
||||
|
||||
// This should be sufficient for most objects that don't manage zones, and
|
||||
// don't need to return a specialized RenderImage...
|
||||
if(state->isObjectRendered(this))
|
||||
{
|
||||
SceneRenderImage* image = new SceneRenderImage;
|
||||
image->obj = this;
|
||||
image->isTranslucent = true;
|
||||
image->sortType = SceneRenderImage::EndSort;
|
||||
state->insertRenderImage(image);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void WeatherLightningBolt::render(const Point3F &camPos)
|
||||
{
|
||||
Point3F perpVec;
|
||||
Point3F lightUp = startPoint - endPoint;
|
||||
mCross(camPos - endPoint, lightUp, &perpVec);
|
||||
perpVec.normalize();
|
||||
|
||||
Point3F frontVec;
|
||||
mCross(perpVec, lightUp, &frontVec);
|
||||
frontVec.normalize();
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
|
||||
//
|
||||
// strike texture
|
||||
//
|
||||
|
||||
// setup alpha value
|
||||
F32 strikeAlpha;
|
||||
if(currentAge < (strikeTime / 3.0))
|
||||
{
|
||||
strikeAlpha = currentAge / (strikeTime / 3.0);
|
||||
strikeAlpha = mPow(strikeAlpha, F32(1.0 / 3.0));
|
||||
}
|
||||
else if(currentAge < (2.0 * strikeTime / 3.0))
|
||||
strikeAlpha = 1.0;
|
||||
else
|
||||
strikeAlpha = 1.0 - ((currentAge - (2.0 * strikeTime / 3.0)) / (strikeTime / 3.0));
|
||||
glColor4f(1.0f, 1.0f, 1.0f, strikeAlpha);
|
||||
|
||||
// generate texture coords
|
||||
Point3F points[4];
|
||||
F32 width = ((startPoint.z - endPoint.z) * 0.125f);
|
||||
points[0] = startPoint - perpVec * width;
|
||||
points[1] = startPoint + perpVec * width;
|
||||
points[2] = endPoint + perpVec * width;
|
||||
points[3] = endPoint - perpVec * width;
|
||||
|
||||
// bind and draw texture
|
||||
glBindTexture(GL_TEXTURE_2D, strikeTexture->getGLName());
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
glTexCoord2f(0, 0); glVertex3fv(points[0]);
|
||||
glTexCoord2f(0, 1); glVertex3fv(points[1]);
|
||||
glTexCoord2f(1, 1); glVertex3fv(points[2]);
|
||||
glTexCoord2f(1, 0); glVertex3fv(points[3]);
|
||||
//glTexCoord2f(0, 0); glVertex3fv(points[0]);
|
||||
//glTexCoord2f(1, 0); glVertex3fv(points[1]);
|
||||
//glTexCoord2f(1, 1); glVertex3fv(points[2]);
|
||||
//glTexCoord2f(0, 1); glVertex3fv(points[3]);
|
||||
glEnd();
|
||||
|
||||
//
|
||||
// fuzzy texture
|
||||
//
|
||||
|
||||
// setup alpha value
|
||||
F32 constAlpha;
|
||||
if(currentAge < strikeTime / 2.0)
|
||||
constAlpha = currentAge / (strikeTime / 2.0);
|
||||
else if(currentAge < (2.0 * strikeTime / 3.0))
|
||||
constAlpha = 1.0 - ((currentAge - (strikeTime / 2.0)) / (strikeTime / 6.0));
|
||||
else
|
||||
constAlpha = 0.0;
|
||||
glColor4f(1.0, 1.0, 1.0, constAlpha);
|
||||
|
||||
// generate texture coords
|
||||
width *= 4;
|
||||
points[0] = startPoint - perpVec * width;
|
||||
points[1] = startPoint + perpVec * width;
|
||||
points[2] = endPoint + perpVec * width;
|
||||
points[3] = endPoint - perpVec * width;
|
||||
|
||||
if(constAlpha != 0.0)
|
||||
{
|
||||
// bind and draw texture
|
||||
glBindTexture(GL_TEXTURE_2D, fuzzyTexture->getGLName());
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
glTexCoord2f(0, 0); glVertex3fv(points[0]);
|
||||
glTexCoord2f(0, 1); glVertex3fv(points[1]);
|
||||
glTexCoord2f(1, 1); glVertex3fv(points[2]);
|
||||
glTexCoord2f(1, 0); glVertex3fv(points[3]);
|
||||
//glTexCoord2f(0, 0); glVertex3fv(points[0]);
|
||||
//glTexCoord2f(1, 0); glVertex3fv(points[1]);
|
||||
//glTexCoord2f(1, 1); glVertex3fv(points[2]);
|
||||
//glTexCoord2f(0, 1); glVertex3fv(points[3]);
|
||||
glEnd();
|
||||
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
//
|
||||
// flash texture
|
||||
//
|
||||
|
||||
// setup alpha value
|
||||
glColor4f(1.0f, 1.0f, 1.0f, strikeAlpha);
|
||||
|
||||
// generate texture coords
|
||||
points[0] = startPoint - perpVec * width + frontVec * width;
|
||||
points[1] = startPoint - perpVec * width - frontVec * width;
|
||||
points[2] = startPoint + perpVec * width - frontVec * width;
|
||||
points[3] = startPoint + perpVec * width + frontVec * width;
|
||||
|
||||
// bind and draw texture
|
||||
glBindTexture(GL_TEXTURE_2D, flashTexture->getGLName());
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
glTexCoord2f(0, 0); glVertex3fv(points[0]);
|
||||
glTexCoord2f(0, 1); glVertex3fv(points[1]);
|
||||
glTexCoord2f(1, 1); glVertex3fv(points[2]);
|
||||
glTexCoord2f(1, 0); glVertex3fv(points[3]);
|
||||
//glTexCoord2f(0, 0); glVertex3fv(points[0]);
|
||||
//glTexCoord2f(1, 0); glVertex3fv(points[1]);
|
||||
//glTexCoord2f(1, 1); glVertex3fv(points[2]);
|
||||
//glTexCoord2f(0, 1); glVertex3fv(points[3]);
|
||||
glEnd();
|
||||
|
||||
//
|
||||
// finished
|
||||
//
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
void WeatherLightning::renderObject(SceneState* state, SceneRenderImage*)
|
||||
{
|
||||
if(mActiveBolts.size())
|
||||
{
|
||||
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
|
||||
|
||||
RectI viewport;
|
||||
F64 farPlane;
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
|
||||
dglGetViewport(&viewport);
|
||||
farPlane = state->getFarPlane();
|
||||
const Point3F &camPos = state->getCameraPosition();
|
||||
|
||||
// adjust far clip plane
|
||||
F64 distance = (getPosition() - camPos).lenSquared();
|
||||
state->setFarPlane(getMax(farPlane, distance));
|
||||
|
||||
state->setupObjectProjection(this);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
for(U32 i = 0; i < mActiveBolts.size(); i++)
|
||||
mActiveBolts[i]->render(camPos);
|
||||
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
state->setFarPlane(farPlane);
|
||||
dglSetViewport(viewport);
|
||||
|
||||
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
|
||||
}
|
||||
}
|
||||
|
||||
void WeatherLightning::processTick(const Move *move)
|
||||
{
|
||||
Parent::processTick(move);
|
||||
|
||||
if (isServerObject())
|
||||
{
|
||||
S32 msBetweenStrikes = (S32)(60.0 / strikesPerMinute * 1000.0);
|
||||
|
||||
lastThink += TickMs;
|
||||
if( lastThink > msBetweenStrikes )
|
||||
{
|
||||
strikeRandomPoint();
|
||||
lastThink -= msBetweenStrikes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WeatherLightning::advanceTime(F32 dt)
|
||||
{
|
||||
Parent::advanceTime(dt);
|
||||
|
||||
U32 i;
|
||||
|
||||
// loop through and erase any dead bolts
|
||||
for(i = 0; i < mActiveBolts.size();)
|
||||
{
|
||||
WeatherLightningBolt* bolt = mActiveBolts[i];
|
||||
bolt->currentAge += dt;
|
||||
if(bolt->currentAge > bolt->deathAge)
|
||||
{
|
||||
delete bolt;
|
||||
mActiveBolts.erase_fast(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
// loop through and find any pending sound events
|
||||
for(i = 0; i < mSoundEvents.size();)
|
||||
{
|
||||
SoundEvent *sEvent = &mSoundEvents[i];
|
||||
sEvent->time -= dt;
|
||||
if(sEvent->time <= 0.0)
|
||||
{
|
||||
// fire off the sound
|
||||
if(sEvent->soundBlockId != -1)
|
||||
alxPlay(mDataBlock->thunderSounds[sEvent->soundBlockId], &sEvent->position);
|
||||
mSoundEvents.erase_fast(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void WeatherLightning::strikeRandomPoint()
|
||||
{
|
||||
// choose random strike point within object bounds
|
||||
Point2F strikePoint;
|
||||
strikePoint.x = sgRandomGen.randF( 0.0, 1.0 );
|
||||
strikePoint.y = sgRandomGen.randF( 0.0, 1.0 );
|
||||
|
||||
SimGroup* pClientGroup = Sim::getClientGroup();
|
||||
for (SimGroup::iterator itr = pClientGroup->begin(); itr != pClientGroup->end(); itr++)
|
||||
{
|
||||
NetConnection* nc = static_cast<NetConnection*>(*itr);
|
||||
|
||||
WeatherLightningStrikeEvent* wlEvent = new WeatherLightningStrikeEvent;
|
||||
wlEvent->mLightning = this;
|
||||
wlEvent->mStart = strikePoint;
|
||||
|
||||
nc->postNetEvent(wlEvent);
|
||||
}
|
||||
}
|
||||
|
||||
TextureHandle* WeatherLightning::getRandomStrike()
|
||||
{
|
||||
U32 strike = (U32)(mCeil(mDataBlock->numStrikes * sgRandomGen.randF()) - 1.0f);
|
||||
return &mDataBlock->strikeTextures[strike];
|
||||
}
|
||||
|
||||
TextureHandle* WeatherLightning::getRandomFlash()
|
||||
{
|
||||
U32 flash = (U32)(mCeil(mDataBlock->numFlashes * sgRandomGen.randF()) - 1.0f);
|
||||
return &mDataBlock->flashTextures[flash];
|
||||
}
|
||||
|
||||
TextureHandle* WeatherLightning::getRandomFuzzy()
|
||||
{
|
||||
U32 fuzzy = (U32)(mCeil(mDataBlock->numFuzzes * sgRandomGen.randF()) - 1.0f);
|
||||
return &mDataBlock->fuzzyTextures[fuzzy];
|
||||
}
|
||||
|
||||
S32 WeatherLightning::getRandomSound()
|
||||
{
|
||||
U32 sound = (U32)(mCeil(mDataBlock->numSounds * sgRandomGen.randF()) - 1.0f);
|
||||
if(mDataBlock->thunderSounds[sound] != NULL_AUDIOHANDLE)
|
||||
return sound;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void WeatherLightning::processEvent(WeatherLightningStrikeEvent* wlEvent)
|
||||
{
|
||||
AssertFatal(wlEvent->mStart.x >= 0 && wlEvent->mStart.x <= 1.0, "Out of bounds coord!");
|
||||
|
||||
mActiveBolts.push_back(new WeatherLightningBolt);
|
||||
WeatherLightningBolt* bolt = mActiveBolts.last();
|
||||
|
||||
Point3F strikePoint(0.0, 0.0, 0.0);
|
||||
strikePoint.x = wlEvent->mStart.x;
|
||||
strikePoint.y = wlEvent->mStart.y;
|
||||
strikePoint *= mObjScale;
|
||||
strikePoint += getPosition();
|
||||
strikePoint += Point3F( -mObjScale.x * 0.5, -mObjScale.y * 0.5, 0.0 );
|
||||
|
||||
RayInfo rayInfo;
|
||||
Point3F start = strikePoint;
|
||||
start.z = mObjScale.z * 0.5 + getPosition().z;
|
||||
strikePoint.z += -mObjScale.z * 0.5;
|
||||
bool rayHit = gClientContainer.castRay(start, strikePoint, (STATIC_COLLISION_MASK | WaterObjectType), &rayInfo);
|
||||
if(rayHit)
|
||||
strikePoint.z = rayInfo.point.z;
|
||||
|
||||
F32 height = mObjScale.z * 0.5 + getPosition().z;
|
||||
|
||||
bolt->startPoint = Point3F(strikePoint.x, strikePoint.y, height);
|
||||
bolt->endPoint = strikePoint;
|
||||
|
||||
bolt->currentAge = 0.0f;
|
||||
bolt->deathAge = boltDeathAge;
|
||||
bolt->strikeTime = 0.35;
|
||||
|
||||
bolt->strikeTexture = getRandomStrike();
|
||||
bolt->flashTexture = getRandomFlash();
|
||||
bolt->fuzzyTexture = getRandomFuzzy();
|
||||
|
||||
// setup a thunder sound event
|
||||
Point3F listener;
|
||||
alxGetListenerPoint3F(AL_POSITION, &listener);
|
||||
|
||||
mSoundEvents.increment();
|
||||
SoundEvent& sEvent = mSoundEvents.last();
|
||||
|
||||
// find the length to the closest point on the bolt
|
||||
Point3F dHat = bolt->startPoint - bolt->endPoint;
|
||||
F32 boltLength = dHat.len();
|
||||
dHat /= boltLength;
|
||||
F32 distAlong = mDot((listener - bolt->endPoint), dHat);
|
||||
|
||||
Point3F contactPoint;
|
||||
if(distAlong >= boltLength)
|
||||
contactPoint = bolt->startPoint;
|
||||
else if(distAlong <= 0.0)
|
||||
contactPoint = bolt->endPoint;
|
||||
else
|
||||
contactPoint = bolt->endPoint + dHat * distAlong;
|
||||
|
||||
F32 delayDist = (listener - contactPoint).len();
|
||||
U32 delayTime = U32((delayDist / 330.0f) * 100.0f);
|
||||
|
||||
MatrixF trans(true);
|
||||
trans.setPosition(contactPoint);
|
||||
|
||||
sEvent.soundBlockId = getRandomSound();
|
||||
sEvent.position = trans;
|
||||
sEvent.time = delayTime;
|
||||
|
||||
// play strike sound
|
||||
trans.setPosition(strikePoint);
|
||||
if(mDataBlock->strikeSound)
|
||||
alxPlay(mDataBlock->strikeSound, &trans);
|
||||
}
|
||||
|
||||
U32 WeatherLightning::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
|
||||
{
|
||||
U32 retMask = Parent::packUpdate(conn, mask, stream);
|
||||
|
||||
// Only write data if this is the initial packet or we've been inspected.
|
||||
if (stream->writeFlag(mask & (InitialUpdateMask | ExtendedInfoMask)))
|
||||
{
|
||||
// Initial update
|
||||
mathWrite(*stream, getPosition());
|
||||
mathWrite(*stream, mObjScale);
|
||||
}
|
||||
|
||||
return retMask;
|
||||
}
|
||||
|
||||
void WeatherLightning::unpackUpdate(NetConnection *conn, BitStream *stream)
|
||||
{
|
||||
Parent::unpackUpdate(conn, stream);
|
||||
|
||||
if (stream->readFlag())
|
||||
{
|
||||
// Initial update
|
||||
Point3F pos;
|
||||
mathRead(*stream, &pos);
|
||||
setPosition( pos );
|
||||
|
||||
mathRead(*stream, &mObjScale);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user