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.
352 lines
11 KiB
352 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 "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); } |
|
|
|
bool 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 |
|
plString fName; |
|
plSharedMesh *fMeshes[kMaxNumLODLevels]; |
|
hsTArray<plMipmap **> fTextures; |
|
hsTArray<plString> fElementNames; |
|
hsTArray<plClothingElement *> fElements; |
|
uint8_t fGroup; // Each avatar can wear one of the available groups |
|
uint8_t fType; // Each group has multiple types of clothes (shirt/pants/etc) |
|
uint8_t fTileset; |
|
uint8_t fSortOrder; |
|
plString fDescription; |
|
plString fCustomText; |
|
plMipmap *fThumbnail; |
|
plClothingItem *fAccessory; // Forced accessory to always wear with this item. |
|
uint8_t fDefaultTint1[3]; |
|
uint8_t fDefaultTint2[3]; |
|
|
|
plString fAccessoryName; // Export only |
|
|
|
|
|
|
|
plClothingItem(); |
|
~plClothingItem(); |
|
|
|
CLASSNAME_REGISTER( plClothingItem ); |
|
GETINTERFACE_ANY( plClothingItem, hsKeyedObject ); |
|
|
|
void SetName(const plString &name) { fName = name; } |
|
plString GetName() const { return fName; } |
|
bool CanWearWith(plClothingItem *item); |
|
bool WearBefore(plClothingItem *item); // Should we come before the arg item? (texture gen order) |
|
bool HasBaseAlpha(); |
|
bool HasSameMeshes(plClothingItem *other); |
|
|
|
virtual void Read(hsStream* s, hsResMgr* mgr); |
|
virtual void Write(hsStream* s, hsResMgr* mgr); |
|
|
|
virtual bool MsgReceive(plMessage* msg); |
|
}; |
|
|
|
class plClosetItem |
|
{ |
|
public: |
|
plClosetItem() : fItem(nil) {} |
|
|
|
plClothingItem *fItem; |
|
plClothingItemOptions fOptions; |
|
|
|
bool IsMatch(plClosetItem *other); |
|
}; |
|
|
|
class plClothingBase : public hsKeyedObject |
|
{ |
|
public: |
|
plString fName; |
|
plMipmap *fBaseTexture; |
|
plString fLayoutName; |
|
|
|
plClothingBase(); |
|
|
|
CLASSNAME_REGISTER( plClothingBase ); |
|
GETINTERFACE_ANY( plClothingBase, hsKeyedObject ); |
|
|
|
void SetLayoutName(const plString &name) { fLayoutName = name; } |
|
|
|
virtual void Read(hsStream* s, hsResMgr* mgr); |
|
virtual void Write(hsStream* s, hsResMgr* mgr); |
|
|
|
virtual bool 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_t fGroup; |
|
bool fSynchClients; // set true if the next synch should be bcast |
|
hsColorRGBA fSkinTint; |
|
float fSkinBlends[plClothingElement::kLayerSkinLast - plClothingElement::kLayerSkinFirst]; // Controls the opacity between skin textures. |
|
|
|
plClothingOutfit(); |
|
~plClothingOutfit(); |
|
|
|
CLASSNAME_REGISTER( plClothingOutfit ); |
|
GETINTERFACE_ANY( plClothingOutfit, plSynchedObject ); |
|
|
|
void SaveCustomizations(bool retry = true); |
|
void AddItem(plClothingItem *item, bool update = true, bool broadcast = true, bool netForce=false); |
|
void RemoveItem(plClothingItem *item, bool update = true, bool netForce=false); |
|
void TintItem(plClothingItem *item, float red, float green, float blue, bool update = true, bool broadcast = true, |
|
bool netForce = false, bool retry = true, uint8_t fLayer = plClothingElement::kLayerTint1); |
|
void TintSkin(float red, float green, float blue, |
|
bool update = true, bool broadcast = true); |
|
void MorphItem(plClothingItem *item, uint8_t layer, uint8_t delta, float weight, bool retry = true); |
|
void SetAge(float age, bool update = true, bool broadcast = true); |
|
void SetSkinBlend(float blend, uint8_t layer, bool update = true, bool broadcast = true); |
|
float GetSkinBlend(uint8_t layer); |
|
hsColorRGBA GetItemTint(plClothingItem *item, uint8_t layer = 2) const; |
|
float 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); |
|
bool DirtySynchState(const plString& SDLStateName, uint32_t synchFlags); |
|
|
|
void StripAccessories(); |
|
void WearDefaultClothing(); |
|
void WearDefaultClothingType(uint32_t clothingType); |
|
void WearMaintainerOutfit(); |
|
void WearRandomOutfit(); |
|
void RemoveMaintainerOutfit(); |
|
|
|
bool ReadItems(hsStream* s, hsResMgr* mgr, bool broadcast = true); |
|
void WriteItems(hsStream* s, hsResMgr* mgr); |
|
|
|
void ForceUpdate(bool retry); // send updateTexture msg |
|
|
|
virtual bool 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 ReadClothing(); |
|
|
|
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; |
|
bool fVaultSaveEnabled; |
|
bool fMorphsInitDone; |
|
plFileName fClothingFile; |
|
|
|
void IAddItem(plClothingItem *item); |
|
void IRemoveItem(plClothingItem *item); |
|
bool ITintItem(plClothingItem *item, hsColorRGBA color, uint8_t layer); |
|
bool IMorphItem(plClothingItem *item, uint8_t layer, uint8_t delta, float 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(const plString &name) const; |
|
plClothingElement *FindElementByName(const plString &name) const; |
|
|
|
|
|
// 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 plString &name) const; |
|
hsTArray<plClothingItem*>& GetItemList() { return fItems; } |
|
void GetItemsByGroup(uint8_t group, hsTArray<plClothingItem*> &out); |
|
void GetItemsByGroupAndType(uint8_t group, uint8_t 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); |
|
bool IsLRMatch(plClothingItem *item1, plClothingItem *item2); |
|
|
|
static void ChangeAvatar(const plString& name, const plFileName &clothingFile = ""); |
|
|
|
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 bool 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
|
|
|