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.
351 lines
11 KiB
351 lines
11 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==*/ |
|
#ifndef PLAVATARCLOTHING_INC |
|
#define PLAVATARCLOTHING_INC |
|
|
|
#include "../pnUtils/pnUtils.h" |
|
#include "../pnNetCommon/plSynchedObject.h" |
|
#include "../CoreLib/hsColorRGBA.h" |
|
#include "hsBitVector.h" |
|
#include "plClothingLayout.h" |
|
|
|
class hsGMaterial; |
|
class plMipmap; |
|
class plLayer; |
|
class hsStream; |
|
class plSceneObject; |
|
class plGeometrySpan; |
|
class plClothingLayout; |
|
class plClothingElement; |
|
class plArmatureMod; |
|
class plSharedMesh; |
|
class plStateDataRecord; |
|
class plDXPipeline; |
|
|
|
class plClothingItemOptions |
|
{ |
|
public: |
|
hsColorRGBA fTint1; |
|
hsColorRGBA fTint2; |
|
|
|
plClothingItemOptions() { fTint1.Set(1.f, 1.f, 1.f, 1.f); fTint2.Set(1.f, 1.f, 1.f, 1.f); } |
|
|
|
hsBool IsMatch(plClothingItemOptions *other) { return fTint1 == other->fTint1 && fTint2 == other->fTint2; } |
|
}; |
|
|
|
class plClothingItem : public hsKeyedObject |
|
{ |
|
public: |
|
enum |
|
{ |
|
kLODHigh, |
|
kLODMedium, |
|
kLODLow, |
|
kMaxNumLODLevels, |
|
}; |
|
|
|
// If you change the format of a clothing item, chances are you need |
|
// to change plClothingMgr::IsLRMatch() as well |
|
char *fName; |
|
plSharedMesh *fMeshes[kMaxNumLODLevels]; |
|
hsTArray<plMipmap **> fTextures; |
|
hsTArray<char *> fElementNames; |
|
hsTArray<plClothingElement *> fElements; |
|
UInt8 fGroup; // Each avatar can wear one of the available groups |
|
UInt8 fType; // Each group has multiple types of clothes (shirt/pants/etc) |
|
UInt8 fTileset; |
|
UInt8 fSortOrder; |
|
char *fDescription; |
|
char *fCustomText; |
|
plMipmap *fThumbnail; |
|
plClothingItem *fAccessory; // Forced accessory to always wear with this item. |
|
UInt8 fDefaultTint1[3]; |
|
UInt8 fDefaultTint2[3]; |
|
|
|
char *fAccessoryName; // Export only |
|
|
|
|
|
|
|
plClothingItem(); |
|
~plClothingItem(); |
|
|
|
CLASSNAME_REGISTER( plClothingItem ); |
|
GETINTERFACE_ANY( plClothingItem, hsKeyedObject ); |
|
|
|
void SetName(char *name) { delete fName; fName = hsStrcpy(name); } |
|
const char* GetName() { return fName; } |
|
hsBool CanWearWith(plClothingItem *item); |
|
hsBool WearBefore(plClothingItem *item); // Should we come before the arg item? (texture gen order) |
|
hsBool HasBaseAlpha(); |
|
hsBool HasSameMeshes(plClothingItem *other); |
|
|
|
virtual void Read(hsStream* s, hsResMgr* mgr); |
|
virtual void Write(hsStream* s, hsResMgr* mgr); |
|
|
|
virtual hsBool MsgReceive(plMessage* msg); |
|
}; |
|
|
|
class plClosetItem |
|
{ |
|
public: |
|
plClosetItem() : fItem(nil) {} |
|
|
|
plClothingItem *fItem; |
|
plClothingItemOptions fOptions; |
|
|
|
hsBool IsMatch(plClosetItem *other); |
|
}; |
|
|
|
class plClothingBase : public hsKeyedObject |
|
{ |
|
public: |
|
char *fName; |
|
plMipmap *fBaseTexture; |
|
char *fLayoutName; |
|
|
|
plClothingBase(); |
|
~plClothingBase(); |
|
|
|
CLASSNAME_REGISTER( plClothingBase ); |
|
GETINTERFACE_ANY( plClothingBase, hsKeyedObject ); |
|
|
|
void SetLayoutName(char *name) { delete fLayoutName; fLayoutName = hsStrcpy(name); } |
|
|
|
virtual void Read(hsStream* s, hsResMgr* mgr); |
|
virtual void Write(hsStream* s, hsResMgr* mgr); |
|
|
|
virtual hsBool MsgReceive(plMessage* msg); |
|
}; |
|
|
|
class plClothingOutfit : public plSynchedObject |
|
{ |
|
friend class plDXPipeline; |
|
|
|
public: |
|
plArmatureMod *fAvatar; |
|
plLayer *fTargetLayer; |
|
hsGMaterial *fMaterial; // Needed to tell swapped geometry what material to use. |
|
hsTArray<plClothingItem*> fItems; |
|
hsTArray<plClothingItemOptions*> fOptions; |
|
plClothingBase *fBase; |
|
UInt8 fGroup; |
|
bool fSynchClients; // set true if the next synch should be bcast |
|
hsColorRGBA fSkinTint; |
|
hsScalar fSkinBlends[plClothingElement::kLayerSkinLast - plClothingElement::kLayerSkinFirst]; // Controls the opacity between skin textures. |
|
|
|
plClothingOutfit(); |
|
~plClothingOutfit(); |
|
|
|
CLASSNAME_REGISTER( plClothingOutfit ); |
|
GETINTERFACE_ANY( plClothingOutfit, plSynchedObject ); |
|
|
|
void SaveCustomizations(hsBool retry = true); |
|
void AddItem(plClothingItem *item, hsBool update = true, hsBool broadcast = true, hsBool netForce=false); |
|
void RemoveItem(plClothingItem *item, hsBool update = true, hsBool netForce=false); |
|
void TintItem(plClothingItem *item, hsScalar red, hsScalar green, hsScalar blue, hsBool update = true, hsBool broadcast = true, |
|
hsBool netForce = false, hsBool retry = true, UInt8 fLayer = plClothingElement::kLayerTint1); |
|
void TintSkin(hsScalar red, hsScalar green, hsScalar blue, |
|
hsBool update = true, hsBool broadcast = true); |
|
void MorphItem(plClothingItem *item, UInt8 layer, UInt8 delta, hsScalar weight, hsBool retry = true); |
|
void SetAge(hsScalar age, hsBool update = true, hsBool broadcast = true); |
|
void SetSkinBlend(hsScalar blend, UInt8 layer, hsBool update = true, hsBool broadcast = true); |
|
hsScalar GetSkinBlend(UInt8 layer); |
|
hsColorRGBA GetItemTint(plClothingItem *item, UInt8 layer = 2) const; |
|
hsScalar GetAge() const { return fSkinBlends[0]; } |
|
hsTArray<plClothingItem*> &GetItemList() { return fItems; } |
|
hsTArray<plClothingItemOptions*> &GetOptionList() { return fOptions; } |
|
|
|
virtual void Read(hsStream* s, hsResMgr* mgr); |
|
virtual void Write(hsStream* s, hsResMgr* mgr); |
|
hsBool DirtySynchState(const char* SDLStateName, UInt32 synchFlags); |
|
|
|
void StripAccessories(); |
|
void WearDefaultClothing(hsBool broadcast = false); |
|
void WearDefaultClothingType(UInt32 clothingType, hsBool broadcast = false); |
|
void WearMaintainerOutfit(); |
|
void WearRandomOutfit(); |
|
void RemoveMaintainerOutfit(); |
|
|
|
hsBool ReadItems(hsStream* s, hsResMgr* mgr, hsBool broadcast = true); |
|
void WriteItems(hsStream* s, hsResMgr* mgr); |
|
|
|
void ForceUpdate(bool retry); // send updateTexture msg |
|
|
|
virtual hsBool MsgReceive(plMessage* msg); |
|
|
|
void IInstanceSharedMeshes(plClothingItem *item); |
|
void IRemoveSharedMeshes(plClothingItem *item); |
|
|
|
//** This will load the avatar clothing. If a clothing file is set, |
|
* we will load from the file, otherwise from the vault. |
|
*// |
|
bool ReadFromFile(); |
|
|
|
void WriteToVault(); |
|
void WriteToVault(const ARRAY(plStateDataRecord*) & SDRs); |
|
|
|
//** Write the avatar clothing to a file *// |
|
bool WriteToFile(const plFileName &filename); |
|
|
|
void SetupMorphSDL(); |
|
|
|
// XXX Don't use this. Temp function for a temp HACK console command. |
|
void DirtyTileset(int tileset); |
|
|
|
//** Instruct this plClothingOutfit to read clothing from the given file *// |
|
void SetClothingFile(const plFileName &file) { fClothingFile = file; } |
|
|
|
//** Returns the clothing file of this outfit. If there is none, an empty string will be returned.// |
|
plFileName GetClothingFile() const { return fClothingFile; } |
|
|
|
protected: |
|
hsBitVector fDirtyItems; |
|
hsBool fVaultSaveEnabled; |
|
bool fMorphsInitDone; |
|
plFileName fClothingFile; |
|
|
|
void IAddItem(plClothingItem *item); |
|
void IRemoveItem(plClothingItem *item); |
|
hsBool ITintItem(plClothingItem *item, hsColorRGBA color, UInt8 layer); |
|
hsBool IMorphItem(plClothingItem *item, UInt8 layer, UInt8 delta, hsScalar weight); |
|
void IHandleMorphSDR(plStateDataRecord *sdr); |
|
|
|
bool IReadFromVault(); |
|
|
|
//** Read the avatar clothing from a file.// |
|
// * A local avatar will change the clothing group to the one in the file.// |
|
// * A local avatar will be invisible if the file does not exist. (used in the Startup age)// |
|
|
|
bool IReadFromFile(const plFileName &filename); |
|
|
|
void IUpdate(); |
|
|
|
}; |
|
|
|
class plClothingMgr : public hsKeyedObject |
|
{ |
|
protected: |
|
static plClothingMgr *fInstance; |
|
|
|
hsTArray<plClothingElement*> fElements; |
|
hsTArray<plClothingItem*> fItems; |
|
hsTArray<plClothingLayout*> fLayouts; |
|
|
|
void IInit(); |
|
void IAddItem(plClothingItem *item); |
|
|
|
public: |
|
plClothingMgr(); |
|
~plClothingMgr(); |
|
|
|
CLASSNAME_REGISTER( plClothingMgr ); |
|
GETINTERFACE_ANY( plClothingMgr, hsKeyedObject ); |
|
|
|
plClothingLayout *GetLayout(char *name); |
|
plClothingElement *FindElementByName(char *name); |
|
|
|
|
|
// Functions that just relate to the clothing you have permission to wear (closet) |
|
void AddItemsToCloset(hsTArray<plClosetItem> &items); |
|
void GetClosetItems(hsTArray<plClosetItem> &out); |
|
|
|
// Functions that relate to all existing clothing |
|
plClothingItem *FindItemByName(const char *name); |
|
hsTArray<plClothingItem*>& GetItemList() { return fItems; } |
|
void GetItemsByGroup(UInt8 group, hsTArray<plClothingItem*> &out); |
|
void GetItemsByGroupAndType(UInt8 group, UInt8 type, hsTArray<plClothingItem*> &out); |
|
void GetAllWithSameMesh(plClothingItem *item, hsTArray<plClothingItem*> &out); |
|
|
|
// Give an array of items (from one of the above functions, for example) |
|
// and this will yank out items so that only item is in the array for each mesh. |
|
void FilterUniqueMeshes(hsTArray<plClothingItem*> &items); |
|
|
|
// For a pair of items that go together (ie gloves) give us one, we'll give you the other |
|
plClothingItem *GetLRMatch(plClothingItem *item); |
|
hsBool IsLRMatch(plClothingItem *item1, plClothingItem *item2); |
|
|
|
static void ChangeAvatar(char *name); |
|
|
|
static plClothingMgr *GetClothingMgr() { return fInstance; } |
|
static void Init(); |
|
static void DeInit(); |
|
|
|
//virtual void Read(hsStream* s, hsResMgr* mgr); |
|
//virtual void Write(hsStream* s, hsResMgr* mgr); |
|
|
|
virtual hsBool MsgReceive(plMessage* msg); |
|
|
|
|
|
// NOTE: |
|
// NOTE: |
|
// NOTE: The following two enums are duplicated in Python, so... |
|
// DON'T CHANGE THEIR CURRENT VALUES, ADD NEW ONES ON THE END OF THE LIST! |
|
enum |
|
{ |
|
kClothingBaseMale = 0, |
|
kClothingBaseFemale, |
|
kClothingBaseNoOptions, // Custom avatars |
|
kMaxGroup |
|
}; |
|
enum |
|
{ |
|
kTypePants = 0, |
|
kTypeShirt, |
|
kTypeLeftHand, |
|
kTypeRightHand, |
|
kTypeFace, |
|
kTypeHair, |
|
kTypeLeftFoot, |
|
kTypeRightFoot, |
|
kTypeAccessory, |
|
kMaxType, |
|
}; |
|
|
|
static const char *GroupStrings[]; |
|
static const char *TypeStrings[]; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|