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

📄 audioemitter.cc

📁 五行MMORPG引擎系统V1.0
💻 CC
📖 第 1 页 / 共 3 页
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------

#include "game/audioEmitter.h"
#include "game/ambientAudioManager.h"
#include "console/consoleTypes.h"
#include "editor/editor.h"
#include "dgl/dgl.h"
#include "sceneGraph/sceneState.h"
#include "game/gameConnection.h"

//------------------------------------------------------------------------------
static MRandomLCG sgRandom(0xdeadbeef);

#define UPDATE_BUMP_MS  50
extern ALuint alxGetWaveLen(ALuint buffer);
extern ALuint alxFindSource(AUDIOHANDLE handle);

IMPLEMENT_CO_NETOBJECT_V1(AudioEmitter);

//------------------------------------------------------------------------------
class AudioEmitterLoopEvent : public SimEvent
{
   public:
      void process(SimObject * object) {
         ((AudioEmitter*)object)->processLoopEvent();
      }
};

//------------------------------------------------------------------------------
AudioEmitter::AudioEmitter(bool client)
{
   // ::packData depends on these values... make sure it is updated with changes
   mTypeMask |= MarkerObjectType;

   if(client)
      mNetFlags = 0;
   else
      mNetFlags.set(Ghostable|ScopeAlways);

   mAudioHandle = NULL_AUDIOHANDLE;

   mAudioProfileId = 0;
   mAudioDescriptionId = 0;

   mLoopCount = smDefaultDescription.mLoopCount;
   mEventID = 0;

   mOwnedByClient = false;

   // field defaults
   mAudioProfile = 0;
   mAudioDescription = 0;
   mFilename = 0;
   mUseProfileDescription = false;
   mOutsideAmbient = true;
   mDescription = smDefaultDescription;

   mEnableVisualFeedback = true;
   mAnimRotAngle=0.f;
}

Audio::Description AudioEmitter::smDefaultDescription;

//------------------------------------------------------------------------------
void AudioEmitter::processLoopEvent()
{
   if(mLoopCount == 0)
      return;
   else if(mLoopCount > 0)
      mLoopCount--;

   if(mUseProfileDescription && mAudioProfileId)
      return;

   if(!mDescription.mIsLooping || ((mDescription.mLoopCount <= 0) && !mDescription.mMaxLoopGap))
      return;

   // check if still playing...
   U32 source = alxFindSource(mAudioHandle);
   if(source != -1)
   {
      ALint state = AL_STOPPED;
      alGetSourcei(source, AL_SOURCE_STATE, &state);
      if(state == AL_PLAYING)
      {
         mEventID = Sim::postEvent(this, new AudioEmitterLoopEvent, Sim::getCurrentTime() + UPDATE_BUMP_MS);
         return;
      }
   }

   mEventID = 0;
   mDirty.set(SourceMask);
   update();
}

//------------------------------------------------------------------------------
bool AudioEmitter::update()
{
   // object does not know it is really a client object if created through event
   AssertFatal(isClientObject() || mOwnedByClient, "AudioEmitter::update: only clients can update!");

   if(mDirty.test(LoopCount))
      mLoopCount = mDescription.mLoopCount;

   // updating source?
   if(mDirty.test(SourceMask|UseProfileDescription) || (!mUseProfileDescription &&
      ((mDescription.mIsLooping && mDirty.test(LoopingMask)) || mDirty.test(IsLooping|Is3D|AudioType))))
   {
      if(mAudioHandle != NULL_AUDIOHANDLE)
      {
         alxStop(mAudioHandle);
         mAudioHandle = NULL_AUDIOHANDLE;
      }

      // profile:
      if(mDirty.test(Profile))
      {
         if(!mAudioProfileId)
            mAudioProfile = 0;
         else
            mAudioProfile = dynamic_cast<AudioProfile*>(Sim::findObject(mAudioProfileId));
      }

      // description:
      if(mDirty.test(Description))
      {
         if(!mAudioDescriptionId)
            mAudioDescription = 0;
         else
            mAudioDescription = dynamic_cast<AudioDescription*>(Sim::findObject(mAudioDescriptionId));
      }

      MatrixF transform = getTransform();

      // use the profile?
      if(mUseProfileDescription && mAudioProfileId)
         mAudioHandle = alxCreateSource(mAudioProfile, &transform);
      else
      {
         // grab the filename
         const char * fileName = 0;
         if(mFilename && mFilename[0])
            fileName = mFilename;
         else if(mAudioProfile)
            fileName = mAudioProfile->mFilename;

         if(!fileName)
         {
            Con::errorf(ConsoleLogEntry::General, "AudioEmitter::update: invalid audio filename!");
            return(false);
         }

         // use a description?
         if(mAudioDescription)
            mAudioHandle = alxCreateSource(mAudioDescription, fileName, &transform);
         else
         {
            if(mDescription.mIsLooping)
            {
               S32 minGap = mClamp(mDescription.mMinLoopGap, 0, mDescription.mMaxLoopGap);
               S32 maxGap = mClamp(mDescription.mMaxLoopGap, mDescription.mMinLoopGap, mDescription.mMaxLoopGap);

               // controlling looping?
               if((mDescription.mLoopCount != -1) || maxGap)
               {
                  mDescription.mIsLooping = false;
                  mAudioHandle = alxCreateSource(&mDescription, fileName, &transform);
                  mDescription.mIsLooping = true;

                  // handle may come back as null.. (0 volume, no handles, ...), still
                  // want to try again (assume good buffer) since this is a looper
                  Resource<AudioBuffer> buffer = AudioBuffer::find(fileName);
                  S32 waveLen = 0;
                  if(bool(buffer))
                  {
                     ALuint alBuffer = buffer->getALBuffer();
                     waveLen = alxGetWaveLen(alBuffer);
                  }

                  if(waveLen)
                  {
                     S32 offset = waveLen + minGap + sgRandom.randI(minGap, maxGap);

                     if(mEventID)
                        Sim::cancelEvent(mEventID);
                     mEventID = Sim::postEvent(this, new AudioEmitterLoopEvent, Sim::getCurrentTime() + offset);

                     if(mAudioHandle == NULL_AUDIOHANDLE)
                        return(true);
                  }
               }
               else
                  mAudioHandle = alxCreateSource(&mDescription, fileName, &transform);
            }
            else
               mAudioHandle = alxCreateSource(&mDescription, fileName, &transform);
         }
      }

      if(mAudioHandle == NULL_AUDIOHANDLE)
      {
         Con::errorf(ConsoleLogEntry::General, "AudioEmitter::update: failed to create source!");
         return(false);
      }

      alxPlay(mAudioHandle);
   }
   else
   {
      // don't clear dirty flags until there is a source
      if(mAudioHandle == NULL_AUDIOHANDLE)
         return(true);

      if(mDirty.test(Transform))
      {
         // Update the position.
         Point3F pos;
         mObjToWorld.getColumn(3, &pos);
         alxSource3f(mAudioHandle, AL_POSITION, pos.x, pos.y, pos.z);

         //Make sure we update the direction also.
         mObjToWorld.getColumn(1, &pos);
         alSource3f(mAudioHandle, AL_DIRECTION, pos.x, pos.y, pos.z);
      }

      // grab the description
      const Audio::Description * desc = 0;

      if(mUseProfileDescription && mAudioProfile)
         desc = mAudioProfile->getDescription();
      else if(mAudioDescription)
         desc = mAudioDescription->getDescription();
      else
         desc = &mDescription;

      if(!desc)
         return(true);

      if(mDirty.test(Volume))
         alxSourcef(mAudioHandle, AL_GAIN_LINEAR, desc->mVolume);

      if(mDirty.test(ReferenceDistance|MaxDistance))
      {
         alxSourcef(mAudioHandle, AL_REFERENCE_DISTANCE, desc->mReferenceDistance);
         alxSourcef(mAudioHandle, AL_MAX_DISTANCE, desc->mMaxDistance);
      }

      if(mDirty.test(ConeInsideAngle))
         alxSourcei(mAudioHandle, AL_CONE_INNER_ANGLE, desc->mConeInsideAngle);

      if(mDirty.test(ConeOutsideAngle))
         alxSourcei(mAudioHandle, AL_CONE_OUTER_ANGLE, desc->mConeOutsideAngle);

      if(mDirty.test(ConeOutsideVolume))
         alxSourcef(mAudioHandle, AL_CONE_OUTER_GAIN, desc->mConeOutsideVolume);
   }

   mDirty.clear();
   return(true);
}

//------------------------------------------------------------------------------
bool AudioEmitter::onAdd()
{
   if(!Parent::onAdd())
      return(false);

   // object does not know it is really a client object if created through event
   if(isServerObject() && !mOwnedByClient)
   {
      // validate the object data
      mDescription.mVolume = mClampF(mDescription.mVolume, 0.0f, 1.0f);
      mDescription.mLoopCount = mClamp(mDescription.mLoopCount, -1, mDescription.mLoopCount);
      mDescription.mMaxLoopGap = mClamp(mDescription.mMaxLoopGap, mDescription.mMinLoopGap, mDescription.mMaxLoopGap);
      mDescription.mMinLoopGap = mClamp(mDescription.mMinLoopGap, 0, mDescription.mMaxLoopGap);

      if(mDescription.mIs3D)
      {
         mDescription.mReferenceDistance = mClampF(mDescription.mReferenceDistance, 0.f, mDescription.mReferenceDistance);
         mDescription.mMaxDistance = (mDescription.mMaxDistance > mDescription.mReferenceDistance) ? mDescription.mMaxDistance : (mDescription.mReferenceDistance+0.01f);
         mDescription.mConeInsideAngle = mClamp(mDescription.mConeInsideAngle, 0, 360);
         mDescription.mConeOutsideAngle = mClamp(mDescription.mConeOutsideAngle, mDescription.mConeInsideAngle, 360);
         mDescription.mConeOutsideVolume = mClampF(mDescription.mConeOutsideVolume, 0.0f, 1.0f);
         mDescription.mConeVector.normalize();
      }
#ifndef TGE_RPGCLIENT2 /// TGE_RPGIsServerObject
   }
   else
   {
#endif
      if(!update())
      {
         Con::errorf(ConsoleLogEntry::General, "AudioEmitter::onAdd: client failed initial update!");
         if(mOwnedByClient)
            return(false);
      }
      gAmbientAudioManager.addEmitter(this);
   }

   //
   mObjBox.max = mObjScale;
   mObjBox.min = mObjScale;
   mObjBox.min.neg();
   resetWorldBox();
   addToScene();

   return(true);
}

void AudioEmitter::onRemove()
{
   if(isClientObject())
   {
      gAmbientAudioManager.removeEmitter(this);
      if(mAudioHandle != NULL_AUDIOHANDLE)
         alxStop(mAudioHandle);
   }
   removeFromScene();
   Parent::onRemove();
}

void AudioEmitter::setTransform(const MatrixF & mat)
{
    // Set the transform directly from the matrix created by inspector
    // Also, be sure to strip out the pointing vector and place it in the cone vector
    Point3F pointing;
    mat.getColumn(1, &pointing);
    mDescription.mConeVector = pointing;
    Parent::setTransform(mat);
    setMaskBits(TransformUpdateMask);
}

void AudioEmitter::setScale(const VectorF &)
{
}

//------------------------------------------------------------------------------
namespace {
   static Point3F cubePoints[8] = {
      Point3F(-1, -1, -1), Point3F(-1, -1,  1), Point3F(-1,  1, -1), Point3F(-1,  1,  1),
      Point3F( 1, -1, -1), Point3F( 1, -1,  1), Point3F( 1,  1, -1), Point3F( 1,  1,  1)
   };

   static U32 cubeFaces[6][4] = {
      { 0, 2, 6, 4 }, { 0, 2, 3, 1 }, { 0, 1, 5, 4 },
      { 3, 2, 6, 7 }, { 7, 6, 4, 5 }, { 3, 7, 5, 1 }
   };

   static Point2F textureCoords[4] = {
      Point2F(0, 0), Point2F(1, 0), Point2F(1, 1), Point2F(0, 1)
   };
}

bool AudioEmitter::prepRenderImage(SceneState * state, const U32 stateKey, const U32, const bool)
{
   if(!gEditingMission || isLastState(state, stateKey))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -