📄 precipitation.cc
字号:
AssertFatal(isClientObject(), "Precipitation is doing stuff on the server - BAD!");
if (mDoCollision)
{
VectorF windVel = getWindVelocity();
VectorF velocity = windVel / drop->mass - VectorF(0, 0, drop->velocity);
velocity.normalize();
Point3F end = drop->position + 100 * velocity;
Point3F start = drop->position - 500 * velocity;
RayInfo rInfo;
if (getContainer()->castRay(start, end, dropHitMask, &rInfo))
{
drop->hitPos = rInfo.point;
drop->hitType = rInfo.object->getTypeMask();
}
else
drop->hitPos = Point3F(0,0,-1000);
drop->valid = drop->position.z > drop->hitPos.z;
}
else
{
drop->hitPos = Point3F(0,0,-1000);
drop->valid = true;
}
PROFILE_END();
}
void Precipitation::createSplash(Raindrop *drop)
{
PROFILE_START(PrecipCreateSplash);
if (drop != mSplashHead && !(drop->nextSplashDrop || drop->prevSplashDrop))
{
if (!mSplashHead)
{
mSplashHead = drop;
drop->prevSplashDrop = NULL;
drop->nextSplashDrop = NULL;
}
else
{
mSplashHead->prevSplashDrop = drop;
drop->nextSplashDrop = mSplashHead;
drop->prevSplashDrop = NULL;
mSplashHead = drop;
}
}
drop->animStartTime = Platform::getVirtualMilliseconds();
PROFILE_END();
}
void Precipitation::destroySplash(Raindrop *drop)
{
PROFILE_START(PrecipDestroySplash);
if (drop == mSplashHead)
{
mSplashHead = NULL;
}
else
{
// Unlink.
if (drop->nextSplashDrop)
drop->nextSplashDrop->prevSplashDrop = drop->prevSplashDrop;
if (drop->prevSplashDrop)
drop->prevSplashDrop->nextSplashDrop = drop->nextSplashDrop;
drop->nextSplashDrop = NULL;
drop->prevSplashDrop = NULL;
}
PROFILE_END();
}
//--------------------------------------------------------------------------
// Processing
//--------------------------------------------------------------------------
void Precipitation::setPercentage(F32 pct)
{
mPercentage = pct;
if (isServerObject())
setMaskBits(PercentageMask);
}
void Precipitation::modifyStorm(F32 pct, U32 ms)
{
pct = mClampF(pct, 0, 1);
mStormData.endPct = pct;
mStormData.totalTime = ms;
if (isServerObject())
{
setMaskBits(StormMask);
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsClientObject
return;
#endif
}
mStormData.startTime = Platform::getVirtualMilliseconds();
mStormData.startPct = mPercentage;
mStormData.valid = true;
}
void Precipitation::interpolateTick(F32 delta)
{
PROFILE_START(PrecipInterpolate);
AssertFatal(isClientObject(), "Precipitation is doing stuff on the server - BAD!");
Raindrop* curr = mDropHead;
VectorF windVel = getWindVelocity();
F32 dt = 1-delta;
while (curr)
{
if (!curr->toRender)
{
curr = curr->next;
continue;
}
VectorF turbulence = dt * windVel;
if (mUseTurbulence)
{
F32 renderTime = curr->time + dt * mTurbulenceSpeed;
turbulence += VectorF(mSin(renderTime), mCos(renderTime), 0) * mMaxTurbulence;
}
curr->renderPosition = curr->position + turbulence / curr->mass;
curr->renderPosition.z -= dt * curr->velocity;
curr = curr->next;
}
PROFILE_END();
}
void Precipitation::processTick(const Move *)
{
//nothing to do on the server
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsClientObject
if (isServerObject())
return;
#endif
//we need to update positions and do some collision here
GameConnection* conn = GameConnection::getConnectionToServer();
if (!conn)
return; //need connection to server
ShapeBase* camObj = conn->getCameraObject();
if (!camObj)
return;
PROFILE_START(PrecipProcess);
//update the storm if necessary
if (mStormData.valid)
{
F32 t = (Platform::getVirtualMilliseconds() - mStormData.startTime) / (F32)mStormData.totalTime;
if (t >= 1)
{
mPercentage = mStormData.endPct;
mStormData.valid = false;
}
else
mPercentage = mStormData.startPct * (1-t) + mStormData.endPct * t;
fillDropList();
}
MatrixF camMat;
camObj->getEyeTransform(&camMat);
Point3F camPos, camDir;
camMat.getColumn(3, &camPos);
camMat.getColumn(1, &camDir);
camDir.normalize();
F32 fovDot = camObj->getCameraFov() / 180;
Raindrop* curr = mDropHead;
//make a box
Box3F box(camPos.x - mBoxWidth / 2, camPos.y - mBoxWidth / 2, camPos.z - mBoxHeight / 2,
camPos.x + mBoxWidth / 2, camPos.y + mBoxWidth / 2, camPos.z + mBoxHeight / 2);
//offset the renderbox in the direction of the camera direction
//in order to have more of the drops actually rendered
box.min.x += camDir.x * mBoxWidth / 4;
box.max.x += camDir.x * mBoxWidth / 4;
box.min.y += camDir.y * mBoxWidth / 4;
box.max.y += camDir.y * mBoxWidth / 4;
box.min.z += camDir.z * mBoxHeight / 4;
box.max.z += camDir.z * mBoxHeight / 4;
VectorF windVel = getWindVelocity();
while (curr)
{
//update position
if (mUseTurbulence)
curr->time += mTurbulenceSpeed;
curr->position += windVel / curr->mass;
curr->position.z -= curr->velocity;
//wrap position
wrapDrop(curr, box);
if (curr->valid)
{
if (curr->position.z < curr->hitPos.z)
{
curr->valid = false;
// Bump back so we don't spawn splashes where they ought not
// be. It might be better to revisit this and use the hitPos.
curr->position -= windVel / curr->mass;
curr->position.z += curr->velocity;
//do some funky effect thingy for hitting something
if (mSplashHandle.getGLName() != 0)
createSplash(curr);
}
}
//render test
VectorF lookVec = curr->position - camPos;
curr->toRender = curr->valid ? mDot(lookVec, camDir) > fovDot : false;
curr = curr->next;
}
//update splashes
curr = mSplashHead;
U32 currTime = Platform::getVirtualMilliseconds();
while (curr)
{
F32 pct = (F32)(currTime - curr->animStartTime) / mDataBlock->mSplashMS;
if (pct >= 1.0f)
{
Raindrop *next = curr->nextSplashDrop;
destroySplash(curr);
curr = next;
continue;
}
curr->splashIndex = (U32)((FRAMES_PER_SIDE*FRAMES_PER_SIDE) * pct);
curr = curr->nextSplashDrop;
}
PROFILE_END();
}
//--------------------------------------------------------------------------
// Rendering
//--------------------------------------------------------------------------
bool Precipitation::prepRenderImage(SceneState* state, const U32 stateKey,
const U32 /*startZone*/, const bool /*modifyBaseState*/)
{
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);
}
if (!mAudioHandle && mDataBlock->soundProfile)
mAudioHandle = alxPlay(mDataBlock->soundProfile, &getTransform());
return false;
}
void Precipitation::renderObject(SceneState* state, SceneRenderImage*)
{
PROFILE_START(PrecipRender);
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
RectI viewport;
glMatrixMode(GL_PROJECTION);
glPushMatrix();
dglGetViewport(&viewport);
// Uncomment this if this is a "simple" (non-zone managing) object
state->setupObjectProjection(this);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
renderPrecip(state);
renderSplashes(state);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
dglSetViewport(viewport);
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
PROFILE_END();
}
//--------------------------------------------------------------------------
void Precipitation::renderPrecip(SceneState *state)
{
GameConnection* conn = GameConnection::getConnectionToServer();
if (!conn)
return; //need connection to server
ShapeBase* camObj = conn->getCameraObject();
if (!camObj)
return;
PROFILE_START(PrecipRenderPrecip);
Point3F camPos = state->getCameraPosition();
VectorF camVel = camObj->getVelocity();
Raindrop *curr = mDropHead;
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, mDropHandle.getGLName());
static Point3F verts[4];
glVertexPointer(3, GL_FLOAT, 0, verts);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glColor3f(1.0, 1.0, 1.0);
VectorF windVel = getWindVelocity();
while (curr)
{
if (!curr->toRender)
{
curr = curr->next;
continue;
}
Point3F pos = curr->renderPosition;
VectorF orthoDir = (camPos - pos);
VectorF velocity = windVel / curr->mass;
if (mRotateWithCamVel && camVel != VectorF(0,0,0))
{
F32 distance = orthoDir.len();
velocity -= camVel / (distance > 2 ? distance : 2) * 0.3;
}
velocity.z -= curr->velocity;
velocity.normalize();
orthoDir.normalize();
VectorF right;
VectorF up;
// two forms of billboards - true billboards (1st codeblock)
// or axis-aligned with velocity (2nd codeblock)
// the axis-aligned billboards are aligned with the velocity
// of the raindrop, and tilted slightly towards the camera
if (mDataBlock->mUseTrueBillboards)
{
state->mModelview.getRow(0,&right);
state->mModelview.getRow(2,&up);
right.normalize();
up.normalize();
}
else
{
right = mCross(-velocity, orthoDir);
right.normalize();
up = mCross(orthoDir, right) * 0.5 - velocity * 0.5;
up.normalize();
}
right *= mDataBlock->mDropSize;
up *= mDataBlock->mDropSize;
verts[0] = pos + right + up;
verts[1] = pos - right + up;
verts[2] = pos - right - up;
verts[3] = pos + right - up;
glTexCoordPointer(2, GL_FLOAT, 0, &texCoords[4*curr->texCoordIndex]);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
//debug collision render
//if (curr->cutoffHeight != -1000)
//{
// VectorF windVel = getWindVelocity();
// VectorF velocity = windVel / curr->mass - VectorF(0, 0, curr->velocity);
// velocity.normalize();
// Point3F start = curr->position;// - 10000 * velocity;
// F32 height = start.z - curr->cutoffHeight;
// F32 t = height / velocity.z;
// Point3F end = start - t * velocity;
// glDisable(GL_TEXTURE_2D);
// glDisable(GL_BLEND);
// glBegin(GL_LINES);
// glColor3f(1.0, 0.0, 0.0);
// glVertex3fv(&(start.x));
// glColor3f(0.0, 1.0, 0.0);
// glVertex3fv(&(end.x));
// glEnd();
// glBegin(GL_TRIANGLE_FAN);
// glColor3f(0.0,0.0,1.0);
// glVertex3fv(&((end - right + up).x));
// glVertex3fv(&((end + right + up).x));
// glVertex3fv(&((end + right - up).x));
// glVertex3fv(&((end - right - up).x));
// glEnd();
// glEnable(GL_TEXTURE_2D);
// glEnable(GL_BLEND);
//}
//end debug collision render
curr = curr->next;
}
glDisable(GL_TEXTURE_2D);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
PROFILE_END();
}
void Precipitation::renderSplashes(SceneState *state)
{
PROFILE_START(PrecipRenderSplash);
//setup the billboard
VectorF right, up;
state->mModelview.getRow(0, &right);
state->mModelview.getRow(2, &up);
right.normalize();
up.normalize();
right *= mDataBlock->mSplashSize;
up *= mDataBlock->mSplashSize;
glColor3f(1.0, 1.0, 1.0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, mSplashHandle.getGLName());
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
static Point3F verts[4];
glVertexPointer(3, GL_FLOAT, 0, verts);
Raindrop *curr = mSplashHead;
while (curr)
{
verts[0] = curr->hitPos + right + up;
verts[1] = curr->hitPos - right + up;
verts[2] = curr->hitPos - right - up;
verts[3] = curr->hitPos + right - up;
glTexCoordPointer(2, GL_FLOAT, 0, &splashCoords[4*curr->splashIndex]);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
curr = curr->nextSplashDrop;
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glDisable(GL_TEXTURE_2D);
PROFILE_END();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -