Moderator: Oleg
#include <scene/ISplineNode.h>
ZRESULT CMyRoadTool::queryLayout(scene::INode* pNode, core::eLevel level, core::ui::IViewport* pViewport)
{
ZPtr<scene::ISplineNode> pSplineNode;
if (ZRESULT_OK != pNode->QueryInterface(IID_(scene::ISplineNode), (void**)&pSplineNode))
return ZRESULT_FALSE;//not suitable node for "road tool", don't include it in context menu;
//
// may be add some extra verification code here. e.g. check, whether this spline node is
// already "under control" of your road tool;
return ZRESULT_OK; //allow road tool to appear in context menu;
}
#include <helpers/sceneNavigation.h>
ZRESULT CMyRoadTool::apply(core::IProcParams* pParams, DWORD* pRetVal)
{
resetError();
ZPtr<scene::IScene> pScene;
g_pZModeler->getScene(&pScene);
//
// loop on nodes
scene::CSubsetIterator it;
if (ZFAILED(it.initialize(pParams)))
return REPORT_ERROR(NULL, _T("CMyRoadTool::apply -> Missing or empty subset."));
// core::undo::beginUndoBranch(_T("my tool"));
while (it.next())
{
if (!it.isAllowEditing())
continue;
ZPtr<scene::ISplineNode> pSplineNode;
if (ZRESULT_OK != it.queryNode(IID_(scene::ISplineNode), (void**)&pSplineNode))
continue;
//
// pSplineNode is the spline in "subset" (the item the context menu was fired for)
// :TODO: add your code here;
}//while
//core::undo::commitUndoBranch();
return ZRESULT_OK;
}
#include <core/ui/controls/IUserDefinedOptions.h>
{
// inside some routine
// pSplineNode is scene::ISplineNode (or any scene::INode you have)
ZPtr<core::ui::controls::IUserDefinedOptions> pUserOpt;
if (ZRESULT_OK == pSplineNode->QueryInterface(IID_(core::ui::controls::IUserDefinedOptions), (void**)&pUserOpt))
{
// use pUserOpt interface to add/query/edit options on a node:
pUserOpt->addOption("Convert", core::ui::controls::checkBox, "1"); //spline should be converted
pUserOpt->addOption("Width", core::ui::controls::floatBox2, "6.5");// width of road to generate from spline
}
}
{
// inside some export routine, given pSplineNode found in scene:
ZPtr<core::ui::controls::IUserDefinedOptions> pUserOpt;
ZString str;
if (ZRESULT_OK == pSplineNode->QueryInterface(IID_(core::ui::controls::IUserDefinedOptions), (void**)&pUserOpt) &&
ZRESULT_OK == pUserOpt->getOptionValueByName("Convert", str) && str.length() > 0 &&
((LPCTSTR)str)[0] == '1')
{
// option of type "checkbox" named "Convert" was found, and checkmark was set on it
// (user-defined option value is '1' when checkmark is set, and '0' when not set)
float fWidth = 3.0f; //default width
if (ZRESULT_OK == pUserOpt->getOptionValueByName("Width", str) && str.length() > 0 &&
1 == _stscanf(str, "%f", &fWidth))
zmath::clamp(fWidth, 1.0f, 12.0f); //ensure user has specified correct width: clamp to min/max range;
//
// ok, pSplineNode should be converted into a road with a known width in meters.
}
}
class CRoadSplineNodes
{
public:
void addSpline(scene::ISplineNode *pNode)
{ m_aSplines.push_back(pNode); }
scene::ISplineNode *getSpline(size_t nIndex)
{
if (m_aSplines[nIndex])
return m_aSplines[nIndex];
return 0;
}
size_t numSplines(void)
{ return m_aSplines.size(); }
void removeSpline(scene::ISplineNode *pNode)
{
std::vector<scene::ISplineNode*>::iterator it = m_aSplines.begin();
while (it != m_aSplines.end())
{
if (*it == pNode)
{
m_aSplines.erase(it);
break;
}
}
}
private:
std::vector<scene::ISplineNode*> m_aSplines;
};
extern CRoadSplineNodes g_roadSplines;
ZUnknown* pNodeUnk = pNode->GetControllingUnknown(); //this method does not AddRef();
while (it != m_aSplines.end())
{
if ((*it)->GetControllingUnknown() == pNodeUnk) //comparing on "ZUnknwon" address is safe
{
....
#include "Tool.h"
#include "ContextTool.h"
ZM_LIBRARY_DEFAULT_DECLARE()
ZM_LIBRARY_NO_COPYRIGHT_INFO()
ZM_LIBRARY_COLLECTION_BEGIN()
ZM_LIBRARY_REG(core::tools::CPSDLRoadTool, ZM_CLASS_TOOL)
ZM_LIBRARY_REG(core::tools::CPSDLRoadsContextTool, ZM_CLASS_TOOL)
ZM_LIBRARY_COLLECTION_END()
ZM_LIBRARY_DEFAULT_END()
ZM_DLLMAIN_DEFAULT_BEGIN()
ZM_LIBRARY_DEFAULT()
ZM_LIBRARY_DESCRIPTION(_T("PSDL Functions for ZModeler 2"))
ZM_LIBRARY_REGISTER()
ZM_DLLMAIN_DEFAULT_END()
//
// interface part:
#include <services/IService.h>
#include <core::events::IZMEventHandler.h>
#include <core::events::ISceneEventHandler.h>
#include <scene::ISplineNode.h>
#include <core::io::ISerializeable.h>
typedef std::vector<ZPtr<scene::ISplineNode> > tSplineNodeList;
namespace services
{
class IRoadSplineNodes : public IService
{
public:
virtual void addSpline(scene::ISplineNode *pNode) = 0;
virtual scene::ISplineNode *getSpline(size_t nIndex) = 0;
virtual size_t numSplines(void) = 0;
virtual void removeSpline(scene::ISplineNode *pNode) = 0;
};
};//services
//
// implementation part:
namespace services
{
class CRoadSplineNodes : public services::IRoadSplineNodes,
public core::events::IZMEventHandler,
// quite suitable to be a "scene handler" too
// public core::events::ISceneEventHandler,
public core::io::ISerializeable
{
public:
CRoadSplineNodes()
{
}
virtual ~CRoadSplineNodes();
INTERFACE_DECLAREMAP(CRoadSplineNodes)
public:
//-----------------------
// services::IService
//-----------------------
ZRESULT init(void); //will need to subscribe to "ZM events"
public:
//-----------------------
// IRoadSplineNodes
//-----------------------
void addSpline(scene::ISplineNode *pNode)
{ m_aSplines.push_back(pNode); }
scene::ISplineNode *getSpline(size_t nIndex)
{
if (m_aSplines[nIndex])
return m_aSplines[nIndex];
return 0;
}
size_t numSplines(void)
{ return m_aSplines.size(); }
void removeSpline(scene::ISplineNode *pNode)
{
tSplineNodeList::iterator it = m_aSplines.begin();
ZUnknwon pUnk = pNode ? pNode->GetControllingUnknown() : NULL;
while (it != m_aSplines.end())
{
if ((*it)->GetControllingUnknown() == pUnk)
{
m_aSplines.erase(it);
break;
}
}
}
public:
//-----------------------
// IZMEventHandler
//-----------------------
//get rid of controller pointers when closing;
virtual ZRESULT onClose(void) { m_aSplines.clear(); return ZRESULT_FALSE; }
//... and when scene is reset:
virtual ZRESULT onNew(void) { return onClose(); }
//do nothing on other events:
virtual ZRESULT onStart(bool bDone=false) { return ZRESULT_FALSE;}
virtual ZRESULT onOpen(LPCTSTR psz, bool bDone=false) { return ZRESULT_FALSE;}
virtual ZRESULT onMerge(LPCTSTR psz, bool bDone=false, scene::CNodeCol* pNodes=NULL) { return ZRESULT_FALSE;}
virtual ZRESULT onSave(LPCTSTR psz, bool bDone=false) { return ZRESULT_FALSE;}
virtual ZRESULT onImport(LPCTSTR psz, bool bDone=false){ return ZRESULT_FALSE;}
virtual ZRESULT onExport(LPCTSTR psz, bool bDone=false){ return ZRESULT_FALSE;}
public:
//-----------------------
// core::io::ISerializeable
//-----------------------
virtual ZRESULT saveDeclaration(core::io::IStream* pStream, IOpenSaveService* pSrv, LPCTSTR pszResolver=NULL);
virtual ZRESULT saveData(core::io::IStream* pStream, DWORD dwID, IOpenSaveService* pSrv);
virtual ZRESULT loadData(core::io::IStream* pStream, IOpenSaveService* pSrv, DWORD dwSize, DWORD dwVersion=0, bool bMerge=false);
virtual ZRESULT getReCreationMode(core::io::eReCreationMode& mode);
private:
//-----------------------
// data members; the splines we control:
//-----------------------
tSplineNodeList m_aSplines;
};
//
// global pointer to your service;
extern CRoadSplineNodes* g_pSplineNodes;
};//serivces
//
// example implementation
#include <helpers/serializeable.h>
namespace services
{
INTERFACE_BEGINMAP(CRoadSplineNodes)
INTERFACE_ENTRY(services::IService)
INTERFACE_RELATIVE_ENTRY(core::events::IEventHandler, core::events::IZMEventHandler)
INTERFACE_ENTRY(core::events::IZMEventHandler)
INTERFACE_ENTRY(core::io::ISerializeable)
INTERFACE_ENDMAP()
CRoadSplineNodes* g_pSplineNodes = NULL;
CRoadSplineNodes::~CRoadSplineNodes()
{
//
// detach from event handling:
ZPtr<core::events::IEventDispatcher> pEvntDsp;
ZPtr<core::events::IEventHandler> pHandler;
if (ZRESULT_OK == QueryInterface(IID_(core::events::IEventHandler), (void**)&pHandler))
{
if (ZRESULT_OK == g_pZModeler->getEventDispatcher(core::events::EVENT_ZM, &pEvntDsp))
pEvntDsp->setEventHandler(core::events::EVENT_ZM, pHandler, core::BO_SUBTRACT); //detach
pEvntDsp = NULL;
// and in case of scene event handling:
//if (ZRESULT_OK == g_pZModeler->getEventDispatcher(core::events::EVENT_SCENE, &pEvntDsp))
// pEvntDsp->setEventHandler(core::events::EVENT_SCENE, pHandler, core::BO_SUBTRACT); //detach
}
}
ZRESULT CRoadSplineNodes::init(void)
{
//
// register service in _zm_ events;
ZPtr<core::events::IEventDispatcher> pEvntDsp;
ZPtr<core::events::IEventHandler> pHandler;
QueryInterface(IID_(core::events::IEventHandler), (void**)&pHandler);
if (pHandler)
{
if (ZRESULT_OK == g_pZModeler->getEventDispatcher(core::events::EVENT_ZM, &pEvntDsp))
pEvntDsp->setEventHandler(core::events::EVENT_ZM, pHandler, core::BO_UNITE);
pEvntDsp = NULL;
// and in case of scene event handling:
//if (ZRESULT_OK == g_pZModeler->getEventDispatcher(core::events::EVENT_SCENE, &pEvntDsp))
// pEvntDsp->setEventHandler(core::events::EVENT_SCENE, pHandler, core::BO_UNITE);
}
return ZRESULT_OK;
}
//-----------------------
// core::io::ISerializeable
//-----------------------
ZRESULT CRoadSplineNodes::saveDeclaration(core::io::IStream* pStream, IOpenSaveService* pSrv, LPCTSTR pszResolver)
{
resetError();
if (NULL == pStream || NULL == pSrv)
return ZRESULT_INVALID_ARG;
core::io::writeDeclaration(pStream, _T("services::CRoadSplineNodes"), this, pSrv, 0, pszResolver);
//
// actually, scene nodes are registered (already or will be), so
// you don't need to register them. However, the code below will
// not harm at all:
ZPtr<core::io::ISerializeable> pSerial;
tSplineNodeList::iterator it = m_aSplines.begin();
while (it != m_aSplines.end())
if (ZRESULT_OK == (*it)->QueryInterface(IID_(core::io::ISerializeable), (void**)&pSerial))
{
pSrv->addPersistentSerializeable(pSerial, false);
pSerial = NULL;
}
return ZRESULT_OK;
}
ZRESULT CRoadSplineNodes::saveData(core::io::IStream* pStream, DWORD dwID, IOpenSaveService* pSrv)
{
// saving data includes saving of array length and spline pointers.
// pointers are saved using unique ID of respective interface. These
// IDs are maintained (assigned) by open/save service:
CDataChunk splines(pStream, dwID, 0x02020600); //a block of data, version 2.2.6;
// amount of pointers followed:
writeLong(pStream, (long)m_aSplines.size());
tSplineNodeList::iterator it = m_aSplines.begin();
while (it != m_aSplines.end())
{
ZUnknwon* pInterface = (*it)->GetControllingUnknown();
core::io::writeInterface(pStream, pSrv, pUnk);//will write ID of respective ZUnknown;
}
return ZRESULT_OK;
}
ZRESULT CRoadSplineNodes::loadData(core::io::IStream* pStream, IOpenSaveService* pSrv, DWORD dwSize, DWORD dwVersion, bool bMerge)
{
if (!bMerge)
m_aSplines.clear();
// loading data is as follows:
// 1. read amount of interfaces first:
long num = 0;
pStream->read(&num, 4);
for (long t = 0; t < num; t++)
{
// read interfaces and push_back em:
// interface is read and resolved using the service (a helper routine does it in one call):
ZPtr<scene::ISplineNode> pSNode;
core::io::readInterface(pStream, pSrv, IID_(scene::ISplineNode), (void**)&pSNode);
if (pSNode)
addSpline(pSNode);
}
return ZRESULT_OK;
}
ZRESULT CRoadSplineNodes::getReCreationMode(core::io::eReCreationMode& mode)
{
//
// persisten service is the IService instance, which is already available, so "saver"
// already has an instance and will call "saveDeclaration" and then "saveData", and
// opener will use "getService" logic with a class name specified as
// "services::CRoadSplineNodes" in a row of code in ::saveDeclaration (see above).
mode = ERC_PERSISTENT_SERVICE;
return ZRESULT_OK;
}
//
// and a fragment of DllMain:
#include <helpers/serializeable.h>
ZM_LIBRARY_DEFAULT_DECLARE()
ZM_LIBRARY_NO_COPYRIGHT_INFO()
ZM_LIBRARY_COLLECTION_BEGIN()
ZM_LIBRARY_REG(services::CRoadSplineNodes, ZM_CLASS_SERVICE)
ZM_LIBRARY_REG(core::tools::CPSDLRoadTool, ZM_CLASS_TOOL)
ZM_LIBRARY_REG(core::tools::CPSDLRoadsContextTool, ZM_CLASS_TOOL)
ZM_LIBRARY_COLLECTION_END()
ZM_LIBRARY_REQUIRES(ZM_LIBREQUIRES_STARTUP)
ZM_LIBRARY_STARTUP(startupLibrary)
ZM_LIBRARY_DEFAULT_END()
ZM_DLLMAIN_DEFAULT_BEGIN()
ZM_LIBRARY_DEFAULT()
ZM_LIBRARY_DESCRIPTION(_T("PSDL Functions for ZModeler 2"))
ZM_LIBRARY_REGISTER()
ZM_DLLMAIN_DEFAULT_END()
ZRESULT startupLibrary()
{
//
// you don't create an instance explicity; let ZModeler create a service
// for your correctly; your services is correctly exported from your plugin
// and repository will call "init" on an instance for you too.
ZPtr<core::IRepository> pRepos;
ZPtr<services::IService> pService;
if (ZRESULT_OK == g_pZModeler->getRepository(&pRepos) &&
ZRESULT_OK == pRepos->getService(_T("services::CRoadSplineNodes"), &pService))
{
// service instantated; it's "init" was called, so this instance is alreay
// subscribed to event handling; all you need to do, is to add this instance
// to open/save service, so it's used during save operation:
core::io::registerSerializeable(pService);
// and let the global variable save the pointer to an instance.
// it's safe to keep a pointer, since an instance of your service will not
// get released until ZModeler closes (it's subscribed to event handling, so
// at least event dispatcher guarantees an instance exists). Your code is safe
// to access service via "g_pSplineNodes", just ensure it's not NULL and go on.
ZPtr<services::IRoadSplineNodes> pMyService;
if (ZRESULT_OK == pService->QueryInterface(IID_(services::IRoadSplineNodes), (void**)&pMyService))
services::g_pSplineNodes = pMyService;
}
return ZRESULT_OK;
}
Return to SDK (Software Development Kit)
Users browsing this forum: No registered users and 3 guests