⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 precipitation.cc

📁 五行MMORPG引擎系统V1.0
💻 CC
📖 第 1 页 / 共 2 页
字号:
   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 + -