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.
787 lines
23 KiB
787 lines
23 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 "HeadSpin.h" |
|
#include "plResponderAnim.h" |
|
#include "plResponderComponentPriv.h" |
|
#include "resource.h" |
|
#include "max.h" |
|
|
|
#include "MaxMain/plMaxNode.h" |
|
|
|
#include "plAnimComponent.h" |
|
#include "plAudioComponents.h" |
|
|
|
#include "plMaxAnimUtils.h" |
|
#include <vector> |
|
|
|
// Needed for anim msg creation |
|
#include "pnKeyedObject/plKey.h" |
|
#include "plMessage/plAnimCmdMsg.h" |
|
#include "plNotetrackAnim.h" |
|
|
|
// Needed for sound msg creation |
|
#include "pnSceneObject/plSceneObject.h" |
|
#include "pnSceneObject/plAudioInterface.h" |
|
#include "plAudible.h" |
|
#include "pnMessage/plSoundMsg.h" |
|
|
|
#include "MaxMain/plPlasmaRefMsgs.h" |
|
|
|
enum |
|
{ |
|
kRespAnimComp, |
|
kRespAnimLoop, |
|
kRespAnimType, |
|
kRespAnimOwner, |
|
kRespAnimObject, |
|
kRespAnimObjectType, |
|
}; |
|
|
|
enum AnimObjectType |
|
{ |
|
kNodePB, // Use the node in the PB |
|
kNodeResponder // Use the node the responder is attached to |
|
}; |
|
|
|
plResponderCmdAnim& plResponderCmdAnim::Instance() |
|
{ |
|
static plResponderCmdAnim theInstance; |
|
return theInstance; |
|
} |
|
|
|
// Use the old types, for backwards compatibility |
|
enum |
|
{ |
|
kRespondPlayAnim, |
|
kRespondStopAnim, |
|
kRespondToggleAnim, |
|
kRespondLoopAnimOn, |
|
kRespondLoopAnimOff, |
|
kRespondSetForeAnim=7, |
|
kRespondSetBackAnim, |
|
|
|
kRespondPlaySound, |
|
kRespondStopSound, |
|
kRespondToggleSound, |
|
kRespondSyncedPlaySound, |
|
|
|
kRespondPlayRndSound=19, |
|
kRespondStopRndSound, |
|
kRespondToggleRndSound, |
|
|
|
kRespondRewindAnim, |
|
kRespondRewindSound, |
|
kRespondFastForwardAnim, |
|
|
|
kNumTypes = 16 |
|
}; |
|
|
|
int plResponderCmdAnim::NumTypes() |
|
{ |
|
return kNumTypes; |
|
} |
|
|
|
static int IndexToOldType(int idx) |
|
{ |
|
static int oldTypes[] = |
|
{ |
|
kRespondPlayAnim, |
|
kRespondStopAnim, |
|
kRespondToggleAnim, |
|
kRespondLoopAnimOn, |
|
kRespondLoopAnimOff, |
|
kRespondSetForeAnim, |
|
kRespondSetBackAnim, |
|
|
|
kRespondPlaySound, |
|
kRespondStopSound, |
|
kRespondToggleSound, |
|
kRespondSyncedPlaySound, |
|
|
|
kRespondPlayRndSound, |
|
kRespondStopRndSound, |
|
kRespondToggleRndSound, |
|
|
|
kRespondRewindAnim, |
|
kRespondRewindSound, |
|
kRespondFastForwardAnim, |
|
}; |
|
|
|
hsAssert(idx < kNumTypes, "Bad index"); |
|
return oldTypes[idx]; |
|
} |
|
|
|
const char *plResponderCmdAnim::GetCategory(int idx) |
|
{ |
|
int type = IndexToOldType(idx); |
|
|
|
switch (type) |
|
{ |
|
case kRespondPlayAnim: |
|
case kRespondStopAnim: |
|
case kRespondToggleAnim: |
|
case kRespondLoopAnimOn: |
|
case kRespondLoopAnimOff: |
|
case kRespondSetForeAnim: |
|
case kRespondSetBackAnim: |
|
case kRespondRewindAnim: |
|
case kRespondFastForwardAnim: |
|
return "Animation"; |
|
|
|
case kRespondPlaySound: |
|
case kRespondStopSound: |
|
case kRespondToggleSound: |
|
case kRespondRewindSound: |
|
case kRespondSyncedPlaySound: |
|
return "Sound"; |
|
|
|
case kRespondPlayRndSound: |
|
case kRespondStopRndSound: |
|
case kRespondToggleRndSound: |
|
return "Random Sound"; |
|
} |
|
|
|
return nil; |
|
} |
|
|
|
const char *plResponderCmdAnim::GetName(int idx) |
|
{ |
|
int type = IndexToOldType(idx); |
|
|
|
switch (type) |
|
{ |
|
case kRespondPlayAnim: |
|
case kRespondPlaySound: |
|
case kRespondPlayRndSound: |
|
return "Play"; |
|
|
|
case kRespondStopAnim: |
|
case kRespondStopSound: |
|
case kRespondStopRndSound: |
|
return "Stop"; |
|
|
|
case kRespondToggleAnim: |
|
case kRespondToggleSound: |
|
case kRespondToggleRndSound: |
|
return "Toggle"; |
|
|
|
case kRespondLoopAnimOn: |
|
return "Set Looping On"; |
|
case kRespondLoopAnimOff: |
|
return "Set Looping Off"; |
|
case kRespondSetForeAnim: |
|
return "Set Forwards"; |
|
case kRespondSetBackAnim: |
|
return "Set Backwards"; |
|
|
|
case kRespondRewindAnim: |
|
case kRespondRewindSound: |
|
return "Rewind"; |
|
case kRespondFastForwardAnim: |
|
return "Fast Forward"; |
|
case kRespondSyncedPlaySound: |
|
return "Synched Play"; |
|
} |
|
|
|
return nil; |
|
} |
|
|
|
static const char *GetShortName(int type) |
|
{ |
|
switch (type) |
|
{ |
|
case kRespondPlayAnim: return "Anim Play"; |
|
case kRespondStopAnim: return "Anim Stop"; |
|
case kRespondToggleAnim: return "Anim Toggle"; |
|
case kRespondLoopAnimOn: return "Anim Loop On"; |
|
case kRespondLoopAnimOff: return "Anim Loop Off"; |
|
case kRespondSetForeAnim: return "Anim Set Fore"; |
|
case kRespondSetBackAnim: return "Anim Set Back"; |
|
case kRespondPlaySound: return "Snd Play"; |
|
case kRespondSyncedPlaySound: return "Snd Synched Play"; |
|
case kRespondStopSound: return "Snd Stop"; |
|
case kRespondToggleSound: return "Snd Toggle"; |
|
case kRespondPlayRndSound: return "Rnd Snd Play"; |
|
case kRespondStopRndSound: return "Rnd Snd Stop"; |
|
case kRespondToggleRndSound: return "Rnd Snd Toggle"; |
|
case kRespondRewindAnim: return "Anim Rewind"; |
|
case kRespondRewindSound: return "Snd Rewind"; |
|
case kRespondFastForwardAnim: return "Anim FFwd"; |
|
} |
|
|
|
return nil; |
|
} |
|
const char *plResponderCmdAnim::GetInstanceName(IParamBlock2 *pb) |
|
{ |
|
static char name[256]; |
|
|
|
const char *shortName = GetShortName(pb->GetInt(kRespAnimType)); |
|
plMaxNode *node = (plMaxNode*)pb->GetReferenceTarget(kRespAnimComp); |
|
sprintf(name, "%s (%s)", shortName, node ? node->GetName() : "none"); |
|
|
|
return name; |
|
} |
|
|
|
static bool IsSoundMsg(int type) |
|
{ |
|
if (type == kRespondPlaySound || |
|
type == kRespondSyncedPlaySound || |
|
type == kRespondStopSound || |
|
type == kRespondToggleSound || |
|
type == kRespondPlayRndSound || |
|
type == kRespondStopRndSound || |
|
type == kRespondToggleRndSound || |
|
type == kRespondRewindSound) |
|
return true; |
|
return false; |
|
} |
|
|
|
plComponentBase *plResponderCmdAnim::GetComponent(IParamBlock2 *pb) |
|
{ |
|
plMaxNode *node = (plMaxNode*)pb->GetReferenceTarget(kRespAnimComp); |
|
if (node) |
|
return node->ConvertToComponent(); |
|
else |
|
return nil; |
|
} |
|
|
|
plMessage *plResponderCmdAnim::CreateMsg(plMaxNode* node, plErrorMsg *pErrMsg, IParamBlock2 *pb) |
|
{ |
|
if (IsSoundMsg(pb->GetInt(kRespAnimType))) |
|
return ICreateSndMsg(node, pErrMsg, pb); |
|
else |
|
return ICreateAnimMsg(node, pErrMsg, pb); |
|
} |
|
|
|
bool GetCompAndNode(IParamBlock2* pb, plMaxNode* node, plComponentBase*& comp, plMaxNode*& targNode) |
|
{ |
|
plMaxNode *compNode = (plMaxNode*)pb->GetReferenceTarget(kRespAnimComp); |
|
if (!compNode) |
|
return false; |
|
|
|
comp = compNode->ConvertToComponent(); |
|
|
|
// KLUDGE: Anim group components don't need target nodes |
|
if (comp->ClassID() == ANIM_GROUP_COMP_CID) |
|
return true; |
|
|
|
if (pb->GetInt(kRespAnimObjectType) == kNodeResponder) |
|
targNode = node; |
|
else |
|
targNode = (plMaxNode*)pb->GetReferenceTarget(kRespAnimObject); |
|
|
|
if (!targNode) |
|
return false; |
|
|
|
if (!comp->IsTarget(targNode)) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
plMessage *plResponderCmdAnim::ICreateAnimMsg(plMaxNode* node, plErrorMsg *pErrMsg, IParamBlock2 *pb) |
|
{ |
|
plAnimComponentBase *comp = nil; |
|
plMaxNode *targNode = nil; |
|
if (!GetCompAndNode(pb, node, (plComponentBase*&)comp, targNode)) |
|
throw "A valid animation component and node were not found"; |
|
|
|
// Get the anim modifier keys for all nodes this comp is attached to |
|
plKey animKey = comp->GetModKey(targNode); |
|
if (!animKey) |
|
throw "Animation component didn't convert"; |
|
|
|
plAnimCmdMsg *msg = TRACKED_NEW plAnimCmdMsg; |
|
msg->AddReceiver(animKey); |
|
|
|
const char *tempAnimName = comp->GetAnimName(); |
|
msg->SetAnimName(tempAnimName); |
|
|
|
// Create and initialize a message for the command |
|
switch (pb->GetInt(kRespAnimType)) |
|
{ |
|
case kRespondPlayAnim: |
|
msg->SetCmd(plAnimCmdMsg::kContinue); |
|
break; |
|
case kRespondStopAnim: |
|
msg->SetCmd(plAnimCmdMsg::kStop); |
|
break; |
|
case kRespondToggleAnim: |
|
msg->SetCmd(plAnimCmdMsg::kToggleState); |
|
break; |
|
case kRespondSetForeAnim: |
|
msg->SetCmd(plAnimCmdMsg::kSetForewards); |
|
break; |
|
case kRespondSetBackAnim: |
|
msg->SetCmd(plAnimCmdMsg::kSetBackwards); |
|
break; |
|
case kRespondLoopAnimOn: |
|
{ |
|
msg->SetCmd(plAnimCmdMsg::kSetLooping); |
|
// KLUDGE - We send the loop to play by name here, so anim grouped components |
|
// could have loops with different begin and end points. However, apparently |
|
// that functionality was never implemented, whoops. So, we'll take out the |
|
// stuff that actually tries to set the begin and end points for now, so that |
|
// anims with a loop set in advance will actually work with this. -Colin |
|
// msg->SetCmd(plAnimCmdMsg::kSetLoopBegin); |
|
// msg->SetCmd(plAnimCmdMsg::kSetLoopEnd); |
|
const char *loopName = pb->GetStr(kAnimLoop); |
|
msg->SetLoopName(loopName); |
|
} |
|
break; |
|
case kRespondLoopAnimOff: |
|
msg->SetCmd(plAnimCmdMsg::kUnSetLooping); |
|
break; |
|
|
|
case kRespondRewindAnim: |
|
msg->SetCmd(plAnimCmdMsg::kGoToBegin); |
|
break; |
|
case kRespondFastForwardAnim: |
|
msg->SetCmd(plAnimCmdMsg::kGoToEnd); |
|
break; |
|
} |
|
|
|
return msg; |
|
} |
|
|
|
plMessage* plResponderCmdAnim::ICreateSndMsg(plMaxNode* node, plErrorMsg *pErrMsg, IParamBlock2 *pb) |
|
{ |
|
plComponentBase *comp; |
|
plMaxNode *targNode; |
|
if (!GetCompAndNode(pb, node, comp, targNode)) |
|
throw "A valid sound component and node were not found"; |
|
|
|
int type = pb->GetInt(kRespAnimType); |
|
switch (type) |
|
{ |
|
case kRespondPlaySound: |
|
case kRespondStopSound: |
|
case kRespondToggleSound: |
|
case kRespondRewindSound: |
|
case kRespondSyncedPlaySound: |
|
{ |
|
if (!targNode->GetSceneObject()) |
|
throw "Sound emitter didn't export"; |
|
|
|
int soundIdx = plAudioComp::GetSoundModIdx(comp, targNode); |
|
|
|
// Changed 8.26.2001 mcn - The audioInterface should be the message receiver, |
|
// not the audible itself. |
|
const plAudioInterface *ai = targNode->GetSceneObject()->GetAudioInterface(); |
|
plKey key = ai->GetKey(); |
|
|
|
plSoundMsg* msg = TRACKED_NEW plSoundMsg; |
|
msg->AddReceiver(key); |
|
msg->fIndex = soundIdx; |
|
|
|
if (type == kRespondPlaySound) |
|
msg->SetCmd(plSoundMsg::kPlay); |
|
else if (type == kRespondStopSound) |
|
msg->SetCmd(plSoundMsg::kStop); |
|
else if (type == kRespondToggleSound) |
|
msg->SetCmd(plSoundMsg::kToggleState); |
|
else if (type == kRespondRewindSound) |
|
{ |
|
msg->fTime = 0; |
|
msg->SetCmd(plSoundMsg::kGoToTime); |
|
} |
|
else if(type == kRespondSyncedPlaySound) |
|
msg->SetCmd(plSoundMsg::kSynchedPlay); |
|
|
|
if( plAudioComp::IsLocalOnly( comp ) ) |
|
msg->SetCmd( plSoundMsg::kIsLocalOnly ); |
|
|
|
return msg; |
|
} |
|
|
|
case kRespondPlayRndSound: |
|
case kRespondStopRndSound: |
|
case kRespondToggleRndSound: |
|
{ |
|
plKey key = plAudioComp::GetRandomSoundKey(comp, targNode); |
|
if (key) |
|
{ |
|
plAnimCmdMsg *msg = TRACKED_NEW plAnimCmdMsg; |
|
msg->AddReceiver(key); |
|
|
|
if (type == kRespondPlayRndSound) |
|
msg->SetCmd(plAnimCmdMsg::kContinue); |
|
else if (type == kRespondStopRndSound) |
|
msg->SetCmd(plAnimCmdMsg::kStop); |
|
else if (type == kRespondToggleRndSound) |
|
msg->SetCmd(plAnimCmdMsg::kToggleState); |
|
|
|
return msg; |
|
} |
|
} |
|
} |
|
|
|
throw "Unknown sound command"; |
|
} |
|
|
|
bool plResponderCmdAnim::IsWaitable(IParamBlock2 *pb) |
|
{ |
|
int type = pb->GetInt(kRespAnimType); |
|
if (type == kRespondPlayAnim || |
|
type == kRespondToggleAnim || |
|
type == kRespondStopAnim || |
|
type == kRespondPlaySound || |
|
type == kRespondSyncedPlaySound || |
|
type == kRespondToggleSound) |
|
return true; |
|
|
|
return false; |
|
} |
|
|
|
void plResponderCmdAnim::GetWaitPoints(IParamBlock2 *pb, WaitPoints& waitPoints) |
|
{ |
|
int type = pb->GetInt(kRespAnimType); |
|
|
|
// Don't try and get points for the stop anim, it can only stop at a stop point |
|
if (type == kRespondStopAnim || IsSoundMsg(type)) |
|
return; |
|
|
|
plAnimComponent *animComp = (plAnimComponent*)GetComponent(pb); |
|
const char *animName = animComp->GetAnimName(); |
|
|
|
if (animComp) |
|
{ |
|
plNotetrackAnim notetrackAnim(animComp, nil); |
|
plAnimInfo info = notetrackAnim.GetAnimInfo(animName); |
|
while (const char *marker = info.GetNextMarkerName()) |
|
waitPoints.push_back(marker); |
|
} |
|
} |
|
|
|
void plResponderCmdAnim::CreateWait(plMaxNode* node, plErrorMsg* pErrMsg, IParamBlock2 *pb, ResponderWaitInfo& waitInfo) |
|
{ |
|
plAnimCmdMsg *animMsg = plAnimCmdMsg::ConvertNoRef(waitInfo.msg); |
|
if (animMsg) |
|
animMsg->SetCmd(plAnimCmdMsg::kAddCallbacks); |
|
|
|
plSoundMsg *soundMsg = plSoundMsg::ConvertNoRef(waitInfo.msg); |
|
if (soundMsg) |
|
soundMsg->SetCmd(plSoundMsg::kAddCallbacks); |
|
|
|
plEventCallbackMsg *eventMsg = TRACKED_NEW plEventCallbackMsg; |
|
eventMsg->AddReceiver(waitInfo.receiver); |
|
eventMsg->fRepeats = 0; |
|
eventMsg->fUser = waitInfo.callbackUser; |
|
|
|
if (waitInfo.point) |
|
{ |
|
// FIXME COLIN - Error checking here? |
|
plAnimComponent *animComp = (plAnimComponent*)GetComponent(pb); |
|
const char *animName = animComp->GetAnimName(); |
|
|
|
plNotetrackAnim notetrackAnim(animComp, nil); |
|
plAnimInfo info = notetrackAnim.GetAnimInfo(animName); |
|
|
|
eventMsg->fEvent = kTime; |
|
eventMsg->fEventTime = info.GetMarkerTime(waitInfo.point); |
|
} |
|
else |
|
eventMsg->fEvent = kStop; |
|
|
|
plMessageWithCallbacks *callbackMsg = plMessageWithCallbacks::ConvertNoRef(waitInfo.msg); |
|
callbackMsg->AddCallback(eventMsg); |
|
// AddCallback adds it's own ref, so remove ours (the default of 1) |
|
hsRefCnt_SafeUnRef(eventMsg); |
|
} |
|
|
|
#include "plAnimCompProc.h" |
|
#include "plPickNode.h" |
|
#include "plResponderGetComp.h" |
|
|
|
class plResponderAnimProc : public plAnimCompProc |
|
{ |
|
public: |
|
plResponderAnimProc(); |
|
virtual BOOL DlgProc(TimeValue t, IParamMap2 *pm, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); |
|
|
|
protected: |
|
virtual void IPickComponent(IParamBlock2* pb); |
|
virtual void IPickNode(IParamBlock2* pb, plComponentBase* comp); |
|
|
|
virtual void ILoadUser(HWND hWnd, IParamBlock2* pb); |
|
virtual bool IUserCommand(HWND hWnd, IParamBlock2* pb, int cmd, int resID); |
|
|
|
virtual void IUpdateNodeButton(HWND hWnd, IParamBlock2* pb); |
|
}; |
|
static plResponderAnimProc gResponderAnimProc; |
|
|
|
plResponderAnimProc::plResponderAnimProc() |
|
{ |
|
fCompButtonID = IDC_ANIM_BUTTON; |
|
fCompParamID = kRespAnimComp; |
|
fNodeButtonID = IDC_OBJ_BUTTON; |
|
fNodeParamID = kRespAnimObject; |
|
} |
|
|
|
BOOL plResponderAnimProc::DlgProc(TimeValue t, IParamMap2 *pm, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
switch (msg) |
|
{ |
|
case WM_INITDIALOG: |
|
{ |
|
IParamBlock2 *pb = pm->GetParamBlock(); |
|
|
|
int type = pb->GetInt(kRespAnimType); |
|
|
|
// Only show the loop control if this is a loop command |
|
int show = (type == kRespondLoopAnimOn) ? SW_SHOW : SW_HIDE; |
|
ShowWindow(GetDlgItem(hWnd, IDC_LOOP_COMBO), show); |
|
ShowWindow(GetDlgItem(hWnd, IDC_LOOP_TEXT), show); |
|
// Resize the dialog if we're not using the loop control |
|
if (type != kRespondLoopAnimOn) |
|
{ |
|
RECT itemRect, clientRect; |
|
GetWindowRect(GetDlgItem(hWnd, IDC_LOOP_TEXT), &itemRect); |
|
GetWindowRect(hWnd, &clientRect); |
|
SetWindowPos(hWnd, NULL, 0, 0, clientRect.right-clientRect.left, |
|
itemRect.top-clientRect.top, SWP_NOMOVE | SWP_NOZORDER); |
|
} |
|
|
|
if (IsSoundMsg(type)) |
|
SetDlgItemText(hWnd, IDC_COMP_TEXT, "Sound Component"); |
|
} |
|
break; |
|
} |
|
|
|
return plAnimCompProc::DlgProc(t, pm, hWnd, msg, wParam, lParam); |
|
} |
|
|
|
bool plResponderAnimProc::IUserCommand(HWND hWnd, IParamBlock2* pb, int cmd, int resID) |
|
{ |
|
if (cmd == CBN_SELCHANGE && resID == IDC_LOOP_COMBO) |
|
{ |
|
HWND hCombo = GetDlgItem(hWnd, IDC_LOOP_COMBO); |
|
int sel = ComboBox_GetCurSel(hCombo); |
|
|
|
// If this is an actual loop (not the entire animation) get its name and save it |
|
if (sel != CB_ERR) |
|
{ |
|
if (ComboBox_GetItemData(hCombo, sel) == 1) |
|
{ |
|
char buf[256]; |
|
ComboBox_GetText(hCombo, buf, sizeof(buf)); |
|
pb->SetValue(kAnimLoop, 0, buf); |
|
} |
|
else |
|
pb->SetValue(kAnimLoop, 0, ""); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void plResponderAnimProc::IPickComponent(IParamBlock2* pb) |
|
{ |
|
std::vector<Class_ID> cids; |
|
|
|
int type = pb->GetInt(kRespAnimType); |
|
if (type == kRespondPlaySound || |
|
type == kRespondStopSound || |
|
type == kRespondToggleSound || |
|
type == kRespondRewindSound || |
|
type == kRespondSyncedPlaySound) |
|
{ |
|
cids.push_back(SOUND_3D_COMPONENT_ID); |
|
cids.push_back(BGND_MUSIC_COMPONENT_ID); |
|
cids.push_back(GUI_SOUND_COMPONENT_ID); |
|
} |
|
else if (type == kRespondPlayRndSound || |
|
type == kRespondStopRndSound || |
|
type == kRespondToggleRndSound) |
|
{ |
|
cids.push_back(RANDOM_SOUND_COMPONENT_ID); |
|
} |
|
else |
|
{ |
|
cids.push_back(ANIM_COMP_CID); |
|
cids.push_back(ANIM_GROUP_COMP_CID); |
|
} |
|
|
|
plPick::NodeRefKludge(pb, kRespAnimComp, &cids, true, false); |
|
} |
|
|
|
ParamBlockDesc2 gResponderAnimBlock |
|
( |
|
kResponderAnimBlk, _T("animCmd"), 0, NULL, P_AUTO_UI, |
|
|
|
IDD_COMP_RESPOND_ANIM, IDS_COMP_CMD_PARAMS, 0, 0, &gResponderAnimProc, |
|
|
|
kRespAnimComp, _T("comp"), TYPE_REFTARG, 0, 0, |
|
end, |
|
|
|
kRespAnimObject, _T("object"), TYPE_REFTARG, 0, 0, |
|
end, |
|
|
|
kRespAnimLoop, _T("loop"), TYPE_STRING, 0, 0, |
|
end, |
|
|
|
kRespAnimType, _T("type"), TYPE_INT, 0, 0, |
|
end, |
|
|
|
kRespAnimObjectType, _T("objType"), TYPE_INT, 0, 0, |
|
end, |
|
|
|
end |
|
); |
|
|
|
ParamBlockDesc2 *plResponderCmdAnim::GetDesc() |
|
{ |
|
return &gResponderAnimBlock; |
|
} |
|
|
|
IParamBlock2 *plResponderCmdAnim::CreatePB(int idx) |
|
{ |
|
int type = IndexToOldType(idx); |
|
|
|
// Create the paramblock and save it's type |
|
IParamBlock2 *pb = CreateParameterBlock2(&gResponderAnimBlock, nil); |
|
pb->SetValue(kRespAnimType, 0, type); |
|
|
|
return pb; |
|
} |
|
|
|
#include "plPickNodeBase.h" |
|
|
|
static const char* kResponderNodeName = "(Responder Node)"; |
|
|
|
class plPickRespNode : public plPickCompNode |
|
{ |
|
protected: |
|
int fTypeID; |
|
|
|
void IAddUserType(HWND hList) |
|
{ |
|
int idx = ListBox_AddString(hList, kResponderNodeName); |
|
|
|
int type = fPB->GetInt(fTypeID); |
|
if (type == kNodeResponder) |
|
ListBox_SetCurSel(hList, idx); |
|
} |
|
|
|
void ISetUserType(plMaxNode* node, const char* userType) |
|
{ |
|
if (userType && !strcmp(userType, kResponderNodeName)) |
|
{ |
|
ISetNodeValue(nil); |
|
fPB->SetValue(fTypeID, 0, kNodeResponder); |
|
} |
|
else |
|
fPB->SetValue(fTypeID, 0, kNodePB); |
|
} |
|
|
|
public: |
|
plPickRespNode(IParamBlock2* pb, int nodeParamID, int typeID, plComponentBase* comp) : |
|
plPickCompNode(pb, nodeParamID, comp), fTypeID(typeID) |
|
{ |
|
} |
|
}; |
|
|
|
void plResponderAnimProc::IPickNode(IParamBlock2* pb, plComponentBase* comp) |
|
{ |
|
plPickRespNode pick(pb, kRespAnimObject, kRespAnimObjectType, comp); |
|
pick.DoPick(); |
|
} |
|
|
|
#include "plNotetrackAnim.h" |
|
|
|
void plResponderAnimProc::ILoadUser(HWND hWnd, IParamBlock2 *pb) |
|
{ |
|
// Premptive strike. If this isn't a loop, don't bother! |
|
int type = pb->GetInt(kRespAnimType); |
|
if (type != kRespondLoopAnimOn) |
|
return; |
|
|
|
HWND hLoop = GetDlgItem(hWnd, IDC_LOOP_COMBO); |
|
|
|
const char *savedName = pb->GetStr(kAnimLoop); |
|
if (!savedName) |
|
savedName = ""; |
|
|
|
// Reset the combo and add the default selection |
|
ComboBox_ResetContent(hLoop); |
|
int sel = ComboBox_AddString(hLoop, ENTIRE_ANIMATION_NAME); |
|
ComboBox_SetCurSel(hLoop, sel); |
|
|
|
// FIXME |
|
plComponentBase *comp = plResponderCmdAnim::Instance().GetComponent(pb); |
|
if (comp && comp->ClassID() == ANIM_COMP_CID) |
|
{ |
|
const char *animName = ((plAnimComponent*)comp)->GetAnimName(); |
|
|
|
// Get the shared animations for all the nodes this component is applied to |
|
plNotetrackAnim anim(comp, nil); |
|
plAnimInfo info = anim.GetAnimInfo(animName); |
|
// Get all the loops in this animation |
|
while (const char *loopName = info.GetNextLoopName()) |
|
{ |
|
int idx = ComboBox_AddString(hLoop, loopName); |
|
ComboBox_SetItemData(hLoop, idx, 1); |
|
|
|
if (!strcmp(loopName, savedName)) |
|
ComboBox_SetCurSel(hLoop, idx); |
|
} |
|
|
|
EnableWindow(hLoop, TRUE); |
|
} |
|
else |
|
{ |
|
EnableWindow(hLoop, FALSE); |
|
} |
|
} |
|
|
|
void plResponderAnimProc::IUpdateNodeButton(HWND hWnd, IParamBlock2* pb) |
|
{ |
|
if (pb->GetInt(kRespAnimObjectType) == kNodeResponder) |
|
{ |
|
HWND hButton = GetDlgItem(hWnd, IDC_OBJ_BUTTON); |
|
SetWindowText(hButton, kResponderNodeName); |
|
} |
|
else |
|
plAnimCompProc::IUpdateNodeButton(hWnd, pb); |
|
} |