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.
285 lines
11 KiB
285 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/>. |
|
|
|
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 plCreatable_inc |
|
#define plCreatable_inc |
|
|
|
#include "hsRefCnt.h" |
|
#include "plFactory.h" |
|
|
|
class plCreator; |
|
class hsStream; |
|
class hsResMgr; |
|
|
|
|
|
class plCreatable : public hsRefCnt |
|
{ |
|
public: |
|
virtual const char* ClassName() const = 0; |
|
virtual plCreatable* GetInterface(UInt16 hClass) { return nil; } |
|
virtual const plCreatable* GetConstInterface(UInt16 hClass) const { return nil; } |
|
static hsBool HasBaseClass(UInt16 hBase) { return false; } |
|
virtual UInt16 ClassIndex() const = 0; |
|
|
|
virtual void Read(hsStream* s, hsResMgr* mgr) {} |
|
virtual void Write(hsStream* s, hsResMgr* mgr) {} |
|
|
|
// WriteVersion writes the current version of this creatable and ReadVersion will read in |
|
// any previous version. |
|
virtual void ReadVersion(hsStream* s, hsResMgr* mgr) { hsAssert(0, "ReadVersion not implemented!"); } |
|
virtual void WriteVersion(hsStream* s, hsResMgr* mgr) { hsAssert(0, "WriteVersion not implemented!"); } |
|
}; |
|
|
|
|
|
// Macros: |
|
// NOTE: Comfortable use of these macros assumes the compiler is comfortable eating |
|
// a spurious semi-colon (;) following a curly brace. If that isn't the case, they |
|
// can easily be wrapped in something like do { original macro } while(0) or the like. |
|
// |
|
// Normal setup for a class: |
|
// In public section of class declaration, insert the following two macros: |
|
// CLASSNAME_REGISTER( myClassName ); |
|
// GETINTERFACE_ANY( myClassName, classIWasDerivedFromName ); |
|
// Then in the *Creatable.h file for that library (e.g. plSurfaceCreatable.h), add macro |
|
// REGISTER_CREATABLE( myClassName ) |
|
// Finally, add an enum to the plCreatableIndex.h file using CLASS_INDEX(className) |
|
// ( e.g. CLASS_INDEX(hsGMaterial) ) |
|
// |
|
// CLASSNAME_REGISTER( plClassName ) - Sets up identification for this |
|
// class. The exposed methods are |
|
// static UInt16 Index() - returns the index for that class. |
|
// virtual UInt16 ClassIndex() - returns index for this object's class. |
|
// static plClassName* Convert(plCreatable* c) - if c exposes an interface |
|
// as plClassName, return that, else nil. Incs the ref count of the object. |
|
// static plClassName* ConvertNoRef(plCreatable* c) - Same as Convert(), but |
|
// doesn't inc the ref count. |
|
// static plClassName* Create() - returns a new object of type plClassName |
|
// Insert into public section of class definition. |
|
// |
|
// Normally one of the next 3 macros should follow CLASSNAME_REGISTER |
|
// GETINTERFACE_ANY - allows an interface to an object as plClassName if an object |
|
// is or is derived from plClassName. |
|
// GETINTERFACE_EXACT - allows an interface as plClassName only if the type is |
|
// exactly of type plClassName |
|
// GETINTERFACE_NONE - Never provide an interface as plClassName. |
|
// Instead of using these macros, the class can provide a method |
|
// virtual plCreatable* GetInterface(UInt16 hClass) which returns an object of |
|
// type matching class handle hClass. |
|
// Insert into public section of class definition (like right after CLASSNAME_REGISTER). |
|
// |
|
// REGISTER_CREATABLE( plClassName ) - normal creatable type, any you can instantiate. |
|
// or |
|
// REGISTER_NONCREATABLE( plClassName ) - can't be created either because it's pure virtual |
|
// or just doesn't want to be creatable. It's Create member returns nil. But Convert |
|
// may return an interface, depending on the GETINTERFACE above. |
|
// - This line is the only exposure to the plCreator. |
|
// This will define a Creator for class plClassName, instantiate it as a static, and register |
|
// it with the Factory. The registration also sets the class index value in the plCreator |
|
// subclass, as well as in the class being registered. |
|
// Put after includes in the *Creatable.h file for the library the class belongs to.. |
|
// |
|
// USAGE: |
|
// There is a method of identifying an object's type. You should rarely need it, |
|
// using Create() and Convert() instead. |
|
// ClassIndex() the class handle is an immutable index to this class. It provides an |
|
// instantaneous lookup. It may be stored, loaded, sent over the wire, etc. |
|
// |
|
// Create() |
|
// If you know what type object you want to create at compile time, use |
|
// <ObjectType>::Create() |
|
// But if you have a class index at run-time (e.g. loaded from file), use |
|
// plCreatable* plFactory::Create(hClass); |
|
// The ultra-safe way to do this is: |
|
// plCreatable* tmp = plFactory::Create(idx); |
|
// plWantClassName* p = plWantClassName::Convert(tmp); |
|
// hsRefCnt_SafeUnRef(tmp); |
|
// |
|
// If you have a fred interface to an object f, and want a wilma interface, use |
|
// fred* f = fred::Create(); more likely f was passed in. |
|
// wilma* w = wilma::Convert(f) |
|
// NOTE that two strange things may be true here: |
|
// 1) f != nil, w == nil |
|
// either fred's not really derived from wilma, |
|
// or fred doesn't like to be cast down, |
|
// or wilma just doesn't want to expose an interface. |
|
// 2) f != nil, w != nil, and f != w |
|
// fred has pulled a sneaky and created a wilma to return. |
|
// so unrelated classes can still "Convert" as one another. |
|
// |
|
// |
|
//////////////////////////// |
|
// EAp - 01/10/2003 |
|
// Added macros to support multiple AUX interfaces primarily, |
|
// but they are not limited to that. Usage example: |
|
// |
|
// plBeginInterfaceMap( plMyClass, plBaseClass ); |
|
// plAddInterfaceAux( plFooClass, fFooMember ); |
|
// plAddInterfaceAux( plBarClass, fBarMember ); |
|
// plAddInterface( plSomeOtherClass ); |
|
// plEndInterfaceMap(); |
|
// |
|
|
|
|
|
#define CLASSNAME_REGISTER( plClassName ) \ |
|
public: \ |
|
virtual const char* ClassName() const { return #plClassName; } \ |
|
private: \ |
|
static UInt16 plClassName##ClassIndex; \ |
|
static void SetClassIndex(UInt16 hClass) { \ |
|
plClassName##ClassIndex = hClass; \ |
|
} \ |
|
public: \ |
|
virtual UInt16 ClassIndex() const { \ |
|
return plClassName::Index(); \ |
|
} \ |
|
static UInt16 Index() { \ |
|
return plClassName##ClassIndex; \ |
|
} \ |
|
static plClassName * Create() { \ |
|
return (plClassName*)plFactory::Create(plClassName##ClassIndex); \ |
|
} \ |
|
static plClassName * ConvertNoRef(plCreatable* c) { \ |
|
plClassName* retVal = c \ |
|
? (plClassName *)c->GetInterface(plClassName##ClassIndex) \ |
|
: nil; \ |
|
return retVal; \ |
|
} \ |
|
static const plClassName * ConvertNoRef(const plCreatable* c) { \ |
|
const plClassName* retVal = c \ |
|
? (const plClassName *)c->GetConstInterface(plClassName##ClassIndex) \ |
|
: nil; \ |
|
return retVal; \ |
|
} \ |
|
static plClassName * Convert(plCreatable* c) { \ |
|
plClassName* retVal = ConvertNoRef(c); \ |
|
hsRefCnt_SafeRef(retVal); \ |
|
return retVal; \ |
|
} \ |
|
static hsBool HasDerivedClass(UInt16 hDer) { \ |
|
return plFactory::DerivesFrom(plClassName##ClassIndex, hDer); \ |
|
} \ |
|
friend class plClassName##__Creator; |
|
|
|
#define GETINTERFACE_ANY( plClassName, plBaseName ) \ |
|
static hsBool HasBaseClass(UInt16 hBaseClass) { \ |
|
if( hBaseClass == plClassName##ClassIndex ) \ |
|
return true; \ |
|
else \ |
|
return plBaseName::HasBaseClass(hBaseClass); \ |
|
} \ |
|
virtual plCreatable* GetInterface(UInt16 hClass) { \ |
|
if( hClass == plClassName##ClassIndex ) \ |
|
return this; \ |
|
else \ |
|
return plBaseName::GetInterface(hClass); \ |
|
} \ |
|
virtual const plCreatable* GetConstInterface(UInt16 hClass) const { \ |
|
if( hClass == plClassName##ClassIndex ) \ |
|
return this; \ |
|
else \ |
|
return plBaseName::GetConstInterface(hClass); \ |
|
} |
|
|
|
#define GETINTERFACE_EXACT( plClassName ) \ |
|
static hsBool HasBaseClass(UInt16 hBaseClass) { \ |
|
return hBaseClass == plClassName##ClassIndex; \ |
|
} \ |
|
virtual plCreatable* GetInterface(UInt16 hClass) { \ |
|
return hClass == plClassName##ClassIndex ? this : nil; \ |
|
} \ |
|
virtual const plCreatable* GetConstInterface(UInt16 hClass) const { \ |
|
return hClass == plClassName##ClassIndex ? this : nil; \ |
|
} |
|
|
|
#define GETINTERFACE_NONE( plClassName ) \ |
|
static hsBool HasBaseClass(UInt16 hBaseClass) { return false; } \ |
|
virtual plCreatable* GetInterface(UInt16 hClass) { \ |
|
return nil; \ |
|
} \ |
|
virtual const plCreatable* GetConstInterface(UInt16 hClass) const { \ |
|
return nil; \ |
|
} |
|
|
|
// |
|
// Macro for converting to base class OR a class member |
|
// |
|
#define GETINTERFACE_ANY_AUX( plClassName, plBaseName, plAuxClassName, plAuxClassMember ) \ |
|
static hsBool HasBaseClass(UInt16 hBaseClass) { \ |
|
if( hBaseClass == plClassName##ClassIndex ) \ |
|
return true; \ |
|
else \ |
|
return plBaseName::HasBaseClass(hBaseClass); \ |
|
} \ |
|
virtual plCreatable* GetInterface(UInt16 hClass) { \ |
|
if( hClass == plClassName##ClassIndex ) \ |
|
return this; \ |
|
else \ |
|
if (hClass == plAuxClassName::Index()) \ |
|
return &plAuxClassMember; \ |
|
else \ |
|
return plBaseName::GetInterface(hClass); \ |
|
} \ |
|
virtual const plCreatable* GetConstInterface(UInt16 hClass) const { \ |
|
if( hClass == plClassName##ClassIndex ) \ |
|
return this; \ |
|
else \ |
|
if (hClass == plAuxClassName::Index()) \ |
|
return &plAuxClassMember; \ |
|
else \ |
|
return plBaseName::GetConstInterface(hClass); \ |
|
} |
|
|
|
#define plBeginInterfaceMap( plClassName, plBaseName ) \ |
|
static hsBool HasBaseClass(UInt16 hBaseClass) { \ |
|
if( hBaseClass == plClassName##ClassIndex ) \ |
|
return true; \ |
|
else \ |
|
return plBaseName::HasBaseClass(hBaseClass); \ |
|
} \ |
|
virtual plCreatable* GetInterface(UInt16 hClass) { \ |
|
/* NOTE: pulling const off the ptr should be ok, right? */ \ |
|
return const_cast<plCreatable*>( GetConstInterface( hClass ) ); \ |
|
} \ |
|
virtual const plCreatable* GetConstInterface(UInt16 hClass) const { \ |
|
typedef plBaseName MyBaseClass; \ |
|
if( hClass == plClassName##ClassIndex ) \ |
|
return this |
|
|
|
#define plAddInterface( plClassName ) \ |
|
else if ( hClass == plClassName::Index() ) \ |
|
return plClassName::GetConstInterface(hClass) |
|
|
|
#define plAddInterfaceAux( plAuxClassName, plAuxClassMember ) \ |
|
else if ( hClass == plAuxClassName::Index() ) \ |
|
return &plAuxClassMember |
|
|
|
#define plEndInterfaceMap() \ |
|
else \ |
|
return MyBaseClass::GetConstInterface(hClass); \ |
|
} |
|
|
|
|
|
#endif // plCreatable_inc
|
|
|