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.
490 lines
14 KiB
490 lines
14 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 "plMultistageStage.h" |
|
#include "max.h" |
|
#include "hsStream.h" |
|
#include "resource.h" |
|
|
|
|
|
#include "plAvatar/plAnimStage.h" |
|
|
|
// We don't want to be subject to any changes to ReadSafeString, so we just keep |
|
// our own version now. Unfortunately, some files were saved with a modified |
|
// version of it, so we need to keep all the backwards compatability BS |
|
char* MyReadSafeString(hsStream* s) |
|
{ |
|
char *name = nil; |
|
uint16_t numChars = s->ReadLE16(); |
|
|
|
bool oldFormat = !(numChars & 0xf000); |
|
if (oldFormat) |
|
s->ReadLE16(); |
|
|
|
numChars &= ~0xf000; |
|
hsAssert(numChars <= s->GetSizeLeft(), "Bad string"); |
|
if (numChars > 0) |
|
{ |
|
name = new char[numChars+1]; |
|
s->Read(numChars, name); |
|
name[numChars] = '\0'; |
|
} |
|
|
|
return name; |
|
} |
|
|
|
void MyWriteSafeString(hsStream* s, const char* str) |
|
{ |
|
int len = hsStrlen(str); |
|
hsAssert(len<0xf000, "String too long"); |
|
s->WriteLE16(len | 0xf000); |
|
if (len > 0) |
|
s->Write(len, str); |
|
} |
|
|
|
plBaseStage::plBaseStage() |
|
{ |
|
fName = nil; |
|
} |
|
|
|
plBaseStage::~plBaseStage() |
|
{ |
|
delete [] fName; |
|
} |
|
|
|
BOOL plBaseStage::IStaticDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
if (msg == WM_INITDIALOG) |
|
SetWindowLong(hDlg, GWL_USERDATA, lParam); |
|
|
|
plBaseStage *stage = (plBaseStage*)GetWindowLong(hDlg, GWL_USERDATA); |
|
|
|
if (!stage) |
|
return FALSE; |
|
|
|
return stage->IDlgProc(hDlg, msg, wParam, lParam); |
|
} |
|
|
|
BOOL plBaseStage::IDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
return FALSE; |
|
} |
|
|
|
HWND plBaseStage::ICreateDlg(int dialogID, char* title) |
|
{ |
|
return GetCOREInterface()->AddRollupPage(hInstance, |
|
MAKEINTRESOURCE(dialogID), |
|
IStaticDlgProc, |
|
title, |
|
(LPARAM)this); |
|
} |
|
|
|
void plBaseStage::IDestroyDlg(HWND hDlg) |
|
{ |
|
if (hDlg) |
|
GetCOREInterface()->DeleteRollupPage(hDlg); |
|
} |
|
|
|
const char* plBaseStage::GetName() |
|
{ |
|
if (!fName) |
|
fName = hsStrcpy("DefaultName"); |
|
return fName; |
|
} |
|
|
|
void plBaseStage::SetName(const char* name) |
|
{ |
|
delete [] fName; |
|
fName = hsStrcpy(name); |
|
} |
|
|
|
void plBaseStage::Read(hsStream *stream) |
|
{ |
|
int version = stream->ReadLE16(); |
|
delete [] fName; |
|
fName = MyReadSafeString(stream); |
|
} |
|
|
|
void plBaseStage::Write(hsStream *stream) |
|
{ |
|
stream->WriteLE16(1); |
|
MyWriteSafeString(stream, fName); |
|
} |
|
|
|
void plBaseStage::IBaseClone(plBaseStage* clone) |
|
{ |
|
clone->fName = hsStrcpy(fName); |
|
} |
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
HWND plStandardStage::fDlg = NULL; |
|
|
|
plStandardStage::plStandardStage() |
|
{ |
|
fAnimName = nil; |
|
fNumLoops = 0; |
|
fLoopForever = false; |
|
fForward = 0; |
|
fBackward = 0; |
|
fStageAdvance = 0; |
|
fStageRegress = 0; |
|
fNotify = 0; |
|
fUseGlobalCoord = false; |
|
fDoAdvanceTo = false; |
|
fAdvanceTo = 0; |
|
fDoRegressTo = false; |
|
fRegressTo = 0; |
|
} |
|
|
|
plStandardStage::~plStandardStage() |
|
{ |
|
delete [] fAnimName; |
|
} |
|
|
|
void plStandardStage::Read(hsStream *stream) |
|
{ |
|
plBaseStage::Read(stream); |
|
|
|
uint16_t version = stream->ReadLE16(); |
|
|
|
delete [] fAnimName; |
|
fAnimName = MyReadSafeString(stream); |
|
fNumLoops = stream->ReadLE32(); |
|
fLoopForever = stream->Readbool(); |
|
fForward = stream->ReadByte(); |
|
fBackward = stream->ReadByte(); |
|
fStageAdvance = stream->ReadByte(); |
|
fStageRegress = stream->ReadByte(); |
|
fNotify = stream->ReadByte(); |
|
fUseGlobalCoord = stream->Readbool(); |
|
if(version > 1) |
|
{ |
|
// these guys were added in version 2 |
|
fDoAdvanceTo = stream->Readbool(); |
|
fAdvanceTo = stream->ReadLE32(); |
|
fDoRegressTo = stream->Readbool(); |
|
fRegressTo = stream->ReadLE32(); |
|
} |
|
} |
|
|
|
void plStandardStage::Write(hsStream *stream) |
|
{ |
|
plBaseStage::Write(stream); |
|
|
|
stream->WriteLE16(2); |
|
|
|
MyWriteSafeString(stream, fAnimName); |
|
stream->WriteLE32(fNumLoops); |
|
stream->Writebool(fLoopForever); |
|
stream->WriteByte(fForward); |
|
stream->WriteByte(fBackward); |
|
stream->WriteByte(fStageAdvance); |
|
stream->WriteByte(fStageRegress); |
|
stream->WriteByte(fNotify); |
|
stream->Writebool(fUseGlobalCoord); |
|
|
|
// these next 4 were added in version 2 |
|
stream->Writebool(fDoAdvanceTo); |
|
stream->WriteLE32(fAdvanceTo); |
|
stream->Writebool(fDoRegressTo); |
|
stream->WriteLE32(fRegressTo); |
|
} |
|
|
|
void plStandardStage::CreateDlg() |
|
{ |
|
hsAssert(!fDlg, "Dialog wasn't destroyed"); |
|
fDlg = ICreateDlg(IDD_COMP_MULTIBEH_NORMAL, "Standard Stage"); |
|
|
|
IInitDlg(); |
|
} |
|
|
|
void plStandardStage::DestroyDlg() |
|
{ |
|
// This shitty Max edit box doesn't notify of changes if it has focus during |
|
// shutdown, so we just get it no matter what. |
|
IGetAnimName(); |
|
|
|
IDestroyDlg(fDlg); |
|
fDlg = nil; |
|
} |
|
|
|
#define SetBit(f,b,on) on ? hsSetBits(f,b) : hsClearBits(f,b) |
|
|
|
BOOL plStandardStage::IDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
switch (msg) |
|
{ |
|
case WM_COMMAND: |
|
{ |
|
int code = HIWORD(wParam); |
|
int id = LOWORD(wParam); |
|
|
|
// Combo changed |
|
if (code == CBN_SELCHANGE) |
|
{ |
|
int sel = ComboBox_GetCurSel((HWND)lParam); |
|
int type = ComboBox_GetItemData((HWND)lParam, sel); |
|
|
|
if (id == IDC_FORWARD_COMBO) |
|
fForward = type; |
|
else if (id == IDC_BACKWARD) |
|
fBackward = type; |
|
else if (id == IDC_ADVANCE) |
|
fStageAdvance = type; |
|
else if (id == IDC_REGRESS) |
|
fStageRegress = type; |
|
|
|
SetSaveRequiredFlag(); |
|
|
|
return TRUE; |
|
} |
|
// Button clicked or checkbox checked |
|
else if (code == BN_CLICKED) |
|
{ |
|
bool isChecked = (Button_GetCheck((HWND)lParam) == BST_CHECKED); |
|
if (id == IDC_LOOP_FOREVER) |
|
{ |
|
fLoopForever = isChecked; |
|
|
|
ISpinnerControl *spin = GetISpinner(GetDlgItem(fDlg, IDC_NUM_LOOPS_SPIN)); |
|
spin->Enable(!fLoopForever); |
|
} |
|
else if (id == IDC_GLOBAL_COORD) |
|
{ |
|
fUseGlobalCoord = isChecked; |
|
} |
|
else if (id == IDC_CHECK_ENTER) |
|
SetBit(fNotify, plAnimStage::kNotifyEnter, isChecked); |
|
else if (id == IDC_CHECK_LOOP) |
|
SetBit(fNotify, plAnimStage::kNotifyLoop, isChecked); |
|
else if (id == IDC_CHECK_ADVANCE) |
|
SetBit(fNotify, plAnimStage::kNotifyAdvance, isChecked); |
|
else if (id == IDC_CHECK_REGRESS) |
|
SetBit(fNotify, plAnimStage::kNotifyRegress, isChecked); |
|
else if (id == IDC_DO_ADVANCE_TO) |
|
{ |
|
fDoAdvanceTo = isChecked; |
|
ISpinnerControl *spin = GetISpinner(GetDlgItem(fDlg, IDC_ADVANCE_STAGE_SPIN)); |
|
spin->Enable(fDoAdvanceTo); |
|
} else if (id == IDC_DO_REGRESS_TO) |
|
{ |
|
fDoRegressTo = isChecked; |
|
ISpinnerControl *spin = GetISpinner(GetDlgItem(fDlg, IDC_REGRESS_STAGE_SPIN)); |
|
spin->Enable(fDoRegressTo); |
|
} |
|
|
|
SetSaveRequiredFlag(); |
|
|
|
return TRUE; |
|
} |
|
} |
|
break; |
|
|
|
// Num loops spinner changed |
|
case CC_SPINNER_CHANGE: |
|
{ |
|
ISpinnerControl* spin = (ISpinnerControl*)lParam; |
|
if (LOWORD(wParam) == IDC_NUM_LOOPS_SPIN) |
|
{ |
|
fNumLoops = spin->GetIVal(); |
|
} else if (LOWORD(wParam) == IDC_ADVANCE_STAGE_SPIN) { |
|
fAdvanceTo = spin->GetIVal(); |
|
} else if (LOWORD(wParam) == IDC_REGRESS_STAGE_SPIN) { |
|
fRegressTo = spin->GetIVal(); |
|
} |
|
|
|
SetSaveRequiredFlag(); |
|
return TRUE; |
|
} |
|
break; |
|
|
|
// Anim name changed |
|
case WM_CUSTEDIT_ENTER: |
|
if (LOWORD(wParam) == IDC_ANIM_NAME) |
|
{ |
|
IGetAnimName(); |
|
return TRUE; |
|
} |
|
break; |
|
} |
|
return FALSE; |
|
} |
|
|
|
void plStandardStage::IGetAnimName() |
|
{ |
|
ICustEdit* edit = GetICustEdit(GetDlgItem(fDlg, IDC_ANIM_NAME)); |
|
char buf[256]; |
|
edit->GetText(buf, sizeof(buf)); |
|
|
|
if (!hsStrEQ(buf, fAnimName)) |
|
{ |
|
delete [] fAnimName; |
|
fAnimName = hsStrcpy(buf); |
|
|
|
SetSaveRequiredFlag(); |
|
} |
|
} |
|
|
|
struct NameType |
|
{ |
|
const char* name; |
|
int type; |
|
}; |
|
|
|
static NameType gForward[] = |
|
{ |
|
{ "None", plAnimStage::kForwardNone }, |
|
{ "Keyboard", plAnimStage::kForwardKey }, |
|
{ "Automatic", plAnimStage::kForwardAuto } |
|
}; |
|
|
|
static NameType gBackward[] = |
|
{ |
|
{ "None", plAnimStage::kBackNone }, |
|
{ "Keyboard", plAnimStage::kBackKey }, |
|
{ "Automatic", plAnimStage::kBackAuto } |
|
}; |
|
|
|
static NameType gAdvance[] = |
|
{ |
|
{ "None", plAnimStage::kAdvanceNone }, |
|
{ "Auto At End",plAnimStage::kAdvanceAuto } |
|
}; |
|
|
|
static NameType gRegress[] = |
|
{ |
|
{ "None", plAnimStage::kRegressNone }, |
|
{ "Auto At End",plAnimStage::kRegressAuto } |
|
}; |
|
|
|
static void LoadCombo(HWND hCombo, NameType* nameInt, int size, int curVal) |
|
{ |
|
int num = size / sizeof(NameType); |
|
|
|
for (int i = 0; i < num; i++) |
|
{ |
|
int idx = ComboBox_AddString(hCombo, nameInt[i].name); |
|
ComboBox_SetItemData(hCombo, idx, nameInt[i].type); |
|
|
|
if (nameInt[i].type == curVal) |
|
ComboBox_SetCurSel(hCombo, idx); |
|
} |
|
} |
|
|
|
void plStandardStage::IInitDlg() |
|
{ |
|
ICustEdit* edit = GetICustEdit(GetDlgItem(fDlg, IDC_ANIM_NAME)); |
|
edit->SetText(fAnimName); |
|
|
|
HWND hForward = GetDlgItem(fDlg, IDC_FORWARD_COMBO); |
|
LoadCombo(hForward, gForward, sizeof(gForward), fForward); |
|
|
|
HWND hBackward = GetDlgItem(fDlg, IDC_BACKWARD); |
|
LoadCombo(hBackward, gBackward, sizeof(gBackward), fBackward); |
|
|
|
HWND hAdvance = GetDlgItem(fDlg, IDC_ADVANCE); |
|
LoadCombo(hAdvance, gAdvance, sizeof(gAdvance), fStageAdvance); |
|
|
|
HWND hRegress = GetDlgItem(fDlg, IDC_REGRESS); |
|
LoadCombo(hRegress, gRegress, sizeof(gRegress), fStageRegress); |
|
|
|
CheckDlgButton(fDlg, IDC_CHECK_ENTER, (fNotify & plAnimStage::kNotifyEnter) ? BST_CHECKED : BST_UNCHECKED); |
|
CheckDlgButton(fDlg, IDC_CHECK_LOOP, (fNotify & plAnimStage::kNotifyLoop) ? BST_CHECKED : BST_UNCHECKED); |
|
CheckDlgButton(fDlg, IDC_CHECK_ADVANCE, (fNotify & plAnimStage::kNotifyAdvance) ? BST_CHECKED : BST_UNCHECKED); |
|
CheckDlgButton(fDlg, IDC_CHECK_REGRESS, (fNotify & plAnimStage::kNotifyRegress) ? BST_CHECKED : BST_UNCHECKED); |
|
|
|
ISpinnerControl *spin = SetupIntSpinner(fDlg, IDC_NUM_LOOPS_SPIN, IDC_NUM_LOOPS_EDIT, 0, 10000, fNumLoops); |
|
|
|
CheckDlgButton(fDlg, IDC_LOOP_FOREVER, fLoopForever ? BST_CHECKED : BST_UNCHECKED); |
|
if (fLoopForever) |
|
spin->Disable(); |
|
|
|
spin = SetupIntSpinner(fDlg, IDC_ADVANCE_STAGE_SPIN, IDC_ADVANCE_STAGE_EDIT, -1, 100, fAdvanceTo); |
|
CheckDlgButton(fDlg, IDC_DO_ADVANCE_TO, fDoAdvanceTo ? BST_CHECKED : BST_UNCHECKED); |
|
if (! fDoAdvanceTo) |
|
spin->Disable(); |
|
|
|
spin = SetupIntSpinner(fDlg, IDC_REGRESS_STAGE_SPIN, IDC_REGRESS_STAGE_EDIT, -1, 100, fRegressTo); |
|
CheckDlgButton(fDlg, IDC_DO_REGRESS_TO, fDoRegressTo ? BST_CHECKED : BST_UNCHECKED); |
|
if (! fDoRegressTo) |
|
spin->Disable(); |
|
|
|
CheckDlgButton(fDlg, IDC_GLOBAL_COORD, fUseGlobalCoord ? BST_CHECKED : BST_UNCHECKED); |
|
} |
|
|
|
plAnimStage* plStandardStage::CreateStage() |
|
{ |
|
int loopCount = fLoopForever ? -1 : fNumLoops; |
|
plAnimStage* stage = new plAnimStage(fAnimName, |
|
fNotify, |
|
(plAnimStage::ForwardType)fForward, |
|
(plAnimStage::BackType)fBackward, |
|
(plAnimStage::AdvanceType)fStageAdvance, |
|
(plAnimStage::RegressType)fStageRegress, |
|
loopCount, |
|
fDoAdvanceTo, |
|
fAdvanceTo, |
|
fDoRegressTo, |
|
fRegressTo); |
|
|
|
return stage; |
|
} |
|
|
|
plBaseStage* plStandardStage::Clone() |
|
{ |
|
plStandardStage* clone = new plStandardStage; |
|
clone->fAnimName = hsStrcpy(fAnimName); |
|
clone->fNumLoops = fNumLoops; |
|
clone->fLoopForever = fLoopForever; |
|
clone->fForward = fForward; |
|
clone->fBackward = fBackward; |
|
clone->fStageAdvance = fStageAdvance; |
|
clone->fStageRegress = fStageRegress; |
|
clone->fNotify = fNotify; |
|
clone->fUseGlobalCoord = fUseGlobalCoord; |
|
|
|
IBaseClone(clone); |
|
|
|
return clone; |
|
}
|
|
|