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.

286 lines
15 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