You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
328 lines
10 KiB
328 lines
10 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, Inc. |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
|
or by snail mail at: |
|
Cyan Worlds, Inc. |
|
14617 N Newport Hwy |
|
Mead, WA 99021 |
|
|
|
*==LICENSE==*/ |
|
#include "hsMatrix44.h" |
|
#include "hsTypes.h" |
|
#include "plListener.h" |
|
#include "plgDispatch.h" |
|
#include "../plAudio/plAudioSystem.h" |
|
#include "../pnMessage/plTimeMsg.h" |
|
#include "../pnMessage/plAudioSysMsg.h" |
|
#include "../pnKeyedObject/plKey.h" |
|
#include "../pnSceneObject/plSceneObject.h" |
|
#include "../pnSceneObject/plCoordinateInterface.h" |
|
#include "../pnSceneObject/plSimulationInterface.h" |
|
#include "../pfCamera/plVirtualCamNeu.h" |
|
#include "../plMessage/plListenerMsg.h" |
|
#include "../plNetClient/plNetClientMgr.h" |
|
#include "../plPipeline/plDebugText.h" |
|
|
|
#include "../plAvatar/plAvatarMgr.h" |
|
#include "../plAvatar/plArmatureMod.h" |
|
#include "../plAvatar/plPhysicalControllerCore.h" |
|
|
|
hsBool plListener::fPrintDbgInfo = false; |
|
|
|
hsBool plListener::IEval(double secs, hsScalar del, UInt32 dirty) |
|
{ |
|
// if (!plgAudioSys::Active()) |
|
// return true; |
|
plSceneObject *pRefObject = nil; |
|
|
|
int y = 16 + 12, x = 400; |
|
if( fPrintDbgInfo ) |
|
plDebugText::Instance().DrawString( x, 16, "Listener:", (UInt32)0xffffffff, plDebugText::kStyleBold ); |
|
|
|
// Get the avatar's SceneObject |
|
plKey key = plNetClientMgr::GetInstance()->GetLocalPlayerKey(); |
|
if(key) |
|
pRefObject = plSceneObject::ConvertNoRef(key->ObjectIsLoaded()); |
|
|
|
if( pRefObject == nil && fVCam == nil ) |
|
{ |
|
// We don't have a position to init by, so do NOT eval yet!!! |
|
if( fPrintDbgInfo ) |
|
plDebugText::Instance().DrawString( x, y, "Not eval-ing yet", (UInt32)0xffffffff ); |
|
return true; |
|
} |
|
|
|
// Changed 2.19.02 mcn - Basing it off the head bone isn't what we really want, esp. since |
|
// it isn't what the camera uses. What we *really* want is a head-ish-positioned non-bobbing node |
|
// that we base both off of. Until then, we're just going to have to use the avatar's root (i.e. his |
|
// feet) and add in an appropriate height. See plAvBrain.cpp::BindAudioListener() for the other half |
|
// of the hack. |
|
// Note the 2nd: since GetAxis() is buggy, we'll just add in a constant vector. Of course, this implies |
|
// that the avatar is always oriented up, but then it also implies he's always of constant height, so |
|
// there. |
|
const hsVector3 kAvatarHeightVector = hsVector3( 0, 0, 6.33f ); // isn't *everyone* 6'4"? |
|
|
|
/// Collect the current values for our parameters |
|
hsPoint3 position; |
|
hsVector3 velocity, dir, up; |
|
|
|
enum |
|
{ |
|
kInvalid = 0, |
|
kVCam, |
|
kObject |
|
} facingType = kInvalid, posType = kInvalid, velType = kInvalid; |
|
|
|
// Facing |
|
if( fFacingRatio == 1.f ) |
|
{ |
|
if( pRefObject != nil && pRefObject->GetCoordinateInterface() ) |
|
{ |
|
hsMatrix44 facingL2W = pRefObject->GetCoordinateInterface()->GetLocalToWorld(); |
|
dir = facingL2W.GetAxis( hsMatrix44::kView ); |
|
up = facingL2W.GetAxis( hsMatrix44::kUp ); |
|
|
|
facingType = kObject; |
|
} |
|
} |
|
else if( fVCam != nil ) |
|
{ |
|
dir = hsVector3( fVCam->GetCameraPOA() - fVCam->GetCameraPos() ); |
|
up = fVCam->GetCameraUp(); |
|
facingType = kVCam; |
|
} |
|
|
|
// Position |
|
if( fPosRatio == 1.f ) |
|
{ |
|
if( pRefObject != nil && pRefObject->GetCoordinateInterface() ) |
|
{ |
|
position = pRefObject->GetCoordinateInterface()->GetLocalToWorld().GetTranslate(); |
|
position += kAvatarHeightVector; |
|
posType = kObject; |
|
} |
|
} |
|
else if( fVCam != nil ) |
|
{ |
|
position = fVCam->GetCameraPos(); |
|
posType = kVCam; |
|
} |
|
|
|
// Velocity |
|
if( fVelRatio == 1.f ) |
|
{ |
|
if( pRefObject != nil ) |
|
{ |
|
plArmatureMod* arm = plAvatarMgr::GetInstance()->GetLocalAvatar(); |
|
if (arm) |
|
{ |
|
plPhysicalControllerCore* controller = arm->GetController(); |
|
if (controller) |
|
{ |
|
velocity = controller->GetLinearVelocity(); |
|
velType = kObject; |
|
} |
|
} |
|
} |
|
} |
|
else if( fVCam != nil ) |
|
{ |
|
// Darn, can't do it |
|
} |
|
|
|
if( facingType == kInvalid || posType == kInvalid || velType == kInvalid ) |
|
{ |
|
if( fPrintDbgInfo ) |
|
plDebugText::Instance().DrawString( x, y, "Not eval-ing: missing one or more parameter bases", (UInt32)0xff0000ff ); |
|
return true; |
|
} |
|
|
|
// Got the params, now construct and send out the message, as well as update the audio system |
|
plListenerMsg* msg = TRACKED_NEW plListenerMsg; |
|
msg->SetDirection( dir ); |
|
msg->SetUp( up ); |
|
msg->SetPosition( position ); |
|
msg->SetVelocity( velocity ); |
|
|
|
plgAudioSys::SetListenerOrientation( dir, up ); |
|
plgAudioSys::SetListenerPos( position ); |
|
plgAudioSys::SetListenerVelocity( velocity ); |
|
|
|
if( fPrintDbgInfo ) |
|
{ |
|
char str[ 256 ]; |
|
sprintf( str, "Direction: (%3.2f,%3.2f,%3.2f) from %s", dir.fX, dir.fY, dir.fZ, ( facingType == kObject ) ? pRefObject->GetKey()->GetUoid().GetObjectName() : "VCam" ); |
|
plDebugText::Instance().DrawString( x, y, str, (UInt32)0xffffffff ); |
|
y += 12; |
|
|
|
sprintf( str, "Up: (%3.2f,%3.2f,%3.2f) from %s", up.fX, up.fY, up.fZ, ( facingType == kObject ) ? pRefObject->GetKey()->GetUoid().GetObjectName() : "VCam" ); |
|
plDebugText::Instance().DrawString( x, y, str, (UInt32)0xffffffff ); |
|
y += 12; |
|
|
|
sprintf( str, "Position: (%3.2f,%3.2f,%3.2f) from %s", position.fX, position.fY, position.fZ, ( posType == kObject ) ? pRefObject->GetKey()->GetUoid().GetObjectName() : "VCam" ); |
|
plDebugText::Instance().DrawString( x, y, str, (UInt32)0xffffffff ); |
|
y += 12; |
|
|
|
sprintf( str, "Velocity: (%3.2f,%3.2f,%3.2f) from %s", velocity.fX, velocity.fY, velocity.fZ, ( velType == kObject ) ? pRefObject->GetKey()->GetUoid().GetObjectName() : "VCam" ); |
|
plDebugText::Instance().DrawString( x, y, str, (UInt32)0xffffffff ); |
|
y += 12; |
|
} |
|
plgDispatch::MsgSend( msg ); |
|
|
|
return true; |
|
} |
|
|
|
void plListener::ISetRef( const plKey &ref, hsBool binding, int type ) |
|
{ |
|
if( binding ) |
|
hsgResMgr::ResMgr()->AddViaNotify( ref, TRACKED_NEW plGenRefMsg( GetKey(), plGenRefMsg::kOnReplace, -1, type ), plRefFlags::kPassiveRef ); |
|
else |
|
GetKey()->Release( ref ); |
|
} |
|
|
|
void plListener::IEnsureVCamValid( void ) |
|
{ |
|
if( fPosRatio == 1.f && fFacingRatio == 1.f && fVelRatio == 1.f ) |
|
{ |
|
// All of our params are purely using objects, so we don't need a virtual camera pointer at all |
|
if( fVCam != nil ) |
|
ISetRef( fVCam->GetKey(), false, kRefVCam ); |
|
} |
|
else |
|
{ |
|
// One or more of our params are using the vcam as a basis, so make sure we have it |
|
if( fVCam == nil ) |
|
{ |
|
plVirtualCam1 *vCam = plVirtualCam1::Instance(); |
|
if( vCam == nil ) |
|
{ |
|
hsAssert( false, "Unable to grab virtual camera instance; no basis for listener!!!" ); |
|
return; |
|
} |
|
|
|
ISetRef( vCam->GetKey(), true, kRefVCam ); |
|
} |
|
} |
|
} |
|
|
|
void plListener::ICheckAudio( void ) const |
|
{ |
|
if( ( fPosRatio < 1.f || fFacingRatio < 1.f || fVelRatio < 1.f ) && fVCam == nil ) |
|
plgAudioSys::SetMuted( true ); |
|
} |
|
|
|
hsBool plListener::MsgReceive(plMessage* msg) |
|
{ |
|
plSetListenerMsg *setMsg = plSetListenerMsg::ConvertNoRef( msg ); |
|
if( setMsg != nil ) |
|
{ |
|
hsBool useVCam; |
|
|
|
if( setMsg->GetType() & plSetListenerMsg::kVCam ) |
|
{ |
|
// Reset any ratios |
|
if( setMsg->GetType() & plSetListenerMsg::kPosition ) |
|
fPosRatio = 0.f; |
|
|
|
if( setMsg->GetType() & plSetListenerMsg::kVelocity ) |
|
fVelRatio = 0.f; |
|
|
|
if( setMsg->GetType() & plSetListenerMsg::kFacing ) |
|
fFacingRatio = 0.f; |
|
|
|
IEnsureVCamValid(); |
|
} |
|
else |
|
{ |
|
useVCam = setMsg->IsBinding(); |
|
|
|
if( setMsg->GetType() & plSetListenerMsg::kPosition ) |
|
fPosRatio = 1.f; |
|
|
|
if( setMsg->GetType() & plSetListenerMsg::kVelocity ) |
|
fVelRatio = 1.f; |
|
|
|
if( setMsg->GetType() & plSetListenerMsg::kFacing ) |
|
fFacingRatio = 1.f; |
|
|
|
if( fPosRatio > 0.f || fVelRatio > 0.f || fFacingRatio > 0.f ) |
|
// Need this, so store it now |
|
ISetRef( setMsg->GetSrcKey(), setMsg->IsBinding(), kRefObject ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
plEvalMsg* pEMsg = plEvalMsg::ConvertNoRef(msg); |
|
if (pEMsg) |
|
{ |
|
IEval(pEMsg->GetTimeStamp(), pEMsg->DelSeconds(), true); |
|
|
|
if( fInitMe ) |
|
{ |
|
// By default, position and orientation are camera based |
|
plSetListenerMsg *set = TRACKED_NEW plSetListenerMsg( plSetListenerMsg::kVCam | plSetListenerMsg::kFacing, nil, true ); |
|
set->Send(); |
|
set = TRACKED_NEW plSetListenerMsg( plSetListenerMsg::kVCam | plSetListenerMsg::kPosition, nil, true ); |
|
set->Send(); |
|
|
|
fInitMe = false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
plGenRefMsg* refMsg = plGenRefMsg::ConvertNoRef( msg ); |
|
if( refMsg != nil ) |
|
{ |
|
if( refMsg->fType == kRefVCam ) |
|
{ |
|
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) ) |
|
{ |
|
fVCam = plVirtualCam1::ConvertNoRef( refMsg->GetRef() ); |
|
} |
|
else if( refMsg->GetContext() & ( plRefMsg::kOnRemove | plRefMsg::kOnDestroy ) ) |
|
{ |
|
if( plVirtualCam1::ConvertNoRef( refMsg->GetRef() ) == fVCam ) |
|
fVCam = nil; |
|
} |
|
ICheckAudio(); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
return plSingleModifier::MsgReceive(msg); |
|
} |