Added aqua_speed for rite geo 50 tryker
[ryzomcore.git] / nel / tools / 3d / object_viewer / particle_workspace.cpp
blob082ded1f910ec97a571a0614ae6b4e949cdcbbdc
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "std_afx.h"
21 #include <shlwapi.h>
23 #include "particle_workspace.h"
24 #include "object_viewer.h"
26 #include "nel/3d/shape_bank.h"
27 #include "nel/3d/particle_system_model.h"
28 #include "nel/3d/particle_system_shape.h"
29 #include "nel/3d/skeleton_model.h"
31 #include "nel/misc/o_xml.h"
32 #include "nel/misc/i_xml.h"
33 #include "nel/misc/file.h"
38 //***********************************************************************************************
39 CParticleWorkspace::CNode::CNode()
41 _PS = NULL;
42 _PSM = NULL;
43 _ShapeBank = NULL;
44 _Modified = false;
45 _ParentSkel = NULL;
46 _ResetAutoCount = false;
47 _WS = NULL;
50 //***********************************************************************************************
51 CParticleWorkspace::CNode::~CNode()
53 unload();
57 //***********************************************************************************************
58 void CParticleWorkspace::CNode::memorizeState()
60 nlassert(_WS);
61 if (!_PS) return;
62 _InitialPos.copySystemInitialPos(_PS);
65 //***********************************************************************************************
66 void CParticleWorkspace::CNode::restoreState()
68 nlassert(_WS);
69 if (!_PS) return;
70 _InitialPos.restoreSystem();
73 //**************************************************************************************************************************
74 bool CParticleWorkspace::CNode::isStateMemorized() const
76 return _InitialPos.isStateMemorized();
79 //**************************************************************************************************************************
80 void CParticleWorkspace::CNode::stickPSToSkeleton(NL3D::CSkeletonModel *skel,
81 uint bone,
82 const std::string &parentSkelName,
83 const std::string &parentBoneName)
85 nlassert(_WS);
86 if (!_PSM) return;
87 unstickPSFromSkeleton();
88 _ParentSkelName = parentSkelName;
89 _ParentBoneName = parentBoneName;
90 if (skel)
92 skel->stickObject(_PSM, bone);
93 _PSM->setMatrix(NLMISC::CMatrix::Identity);
94 _ParentSkel = skel;
96 if (_WS->getModificationCallback())
98 _WS->getModificationCallback()->nodeSkelParentChanged(*this);
102 //**************************************************************************************************************************
103 void CParticleWorkspace::CNode::unstickPSFromSkeleton()
105 nlassert(_WS);
106 _ParentSkelName.clear();
107 _ParentBoneName.clear();
108 if (!_PSM) return;
109 if (_ParentSkel)
111 _ParentSkel->detachSkeletonSon(_PSM);
112 _ParentSkel = NULL;
116 //***********************************************************************************************
117 void CParticleWorkspace::CNode::removeLocated(NL3D::CPSLocated *loc)
119 nlassert(_WS);
120 if (_InitialPos.isStateMemorized())
122 _InitialPos.removeLocated(loc);
126 //***********************************************************************************************
127 void CParticleWorkspace::CNode::removeLocatedBindable(NL3D::CPSLocatedBindable *lb)
129 nlassert(_WS);
130 if (_InitialPos.isStateMemorized())
132 _InitialPos.removeLocatedBindable(lb);
136 //***********************************************************************************************
137 void CParticleWorkspace::CNode::setModified(bool modified)
139 nlassert(_WS);
140 if (_Modified == modified) return;
141 _Modified = modified;
142 _WS->nodeModified(*this);
145 //***********************************************************************************************
146 void CParticleWorkspace::CNode::unload()
148 nlassert(_WS);
149 if (_PSM)
151 NL3D::CShapeBank *oldSB = NL3D::CNELU::Scene->getShapeBank();
152 NL3D::CNELU::Scene->setShapeBank(_ShapeBank);
153 NL3D::CNELU::Scene->deleteInstance(_PSM);
154 NL3D::CNELU::Scene->setShapeBank(oldSB);
155 _PSM = NULL;
157 delete _ShapeBank;
158 _ShapeBank = NULL;
159 _PS = NULL;
160 _ParentSkel = NULL;
164 //***********************************************************************************************
165 void CParticleWorkspace::CNode::setup(NL3D::CParticleSystemModel &psm)
167 nlassert(_WS);
168 psm.setTransformMode(NL3D::CTransform::DirectMatrix);
169 psm.setMatrix(NLMISC::CMatrix::Identity);
170 nlassert(_WS->getObjectViewer());
171 psm.setEditionMode(true); // this also force the system instanciation
172 for(uint k = 0; k < NL3D::MaxPSUserParam; ++k)
174 psm.bypassGlobalUserParamValue(k);
176 psm.enableAutoGetEllapsedTime(false);
177 psm.setEllapsedTime(0.f); // system is paused
178 // initialy, the ps is hidden
179 psm.hide();
180 // link to the root for manipulation
181 _WS->getObjectViewer()->getSceneRoot()->hrcLinkSon(&psm);
182 NL3D::CParticleSystem *ps = psm.getPS();
183 nlassert(ps);
184 ps->setFontManager(_WS->getFontManager());
185 ps->setFontGenerator(_WS->getFontGenerator());
186 ps->stopSound();
187 // flush textures
188 psm.Shape->flushTextures(*NL3D::CNELU::Driver, 0);
191 //***********************************************************************************************
192 void CParticleWorkspace::CNode::setTriggerAnim(const std::string &anim)
194 nlassert(_WS);
195 if (anim == _TriggerAnim) return;
196 _WS->touch();
197 _TriggerAnim = anim;
201 //***********************************************************************************************
202 void CParticleWorkspace::CNode::createEmptyPS()
204 nlassert(_WS);
205 NL3D::CParticleSystem emptyPS;
206 NL3D::CParticleSystemShape *pss = new NL3D::CParticleSystemShape;
207 pss->buildFromPS(emptyPS);
208 CUniquePtr<NL3D::CShapeBank> sb(new NL3D::CShapeBank);
209 std::string shapeName = NLMISC::CFile::getFilename(_RelativePath);
210 sb->add(shapeName, pss);
211 NL3D::CShapeBank *oldSB = NL3D::CNELU::Scene->getShapeBank();
212 NL3D::CNELU::Scene->setShapeBank(sb.get());
213 NL3D::CParticleSystemModel *psm = NLMISC::safe_cast<NL3D::CParticleSystemModel *>(NL3D::CNELU::Scene->createInstance(shapeName));
214 nlassert(psm);
215 NL3D::CNELU::Scene->setShapeBank(oldSB);
216 setup(*psm);
217 unload();
218 // commit new values
219 _PS = psm->getPS();
220 _PSM = psm;
221 _ShapeBank = sb.release();
222 _Modified = false;
225 //***********************************************************************************************
226 void CParticleWorkspace::CNode::init(CParticleWorkspace *ws)
228 nlassert(ws);
229 _WS = ws;
232 //***********************************************************************************************
233 void CParticleWorkspace::CNode::setRelativePath(const std::string &relativePath)
235 nlassert(_WS);
236 _RelativePath = relativePath;
239 //***********************************************************************************************
240 void CParticleWorkspace::CNode::serial(NLMISC::IStream &f)
242 nlassert(_WS);
243 f.xmlPush("PROJECT_FILE");
244 sint version = f.serialVersion(2);
245 f.xmlSerial(_RelativePath, "RELATIVE_PATH");
246 if (version >= 1)
248 f.xmlSerial(_TriggerAnim, "TRIGGER_ANIMATION");
250 if (version >= 2)
252 f.xmlSerial(_ParentSkelName, "PARENT_SKEL_NAME");
253 f.xmlSerial(_ParentBoneName, "PARENT_BONE_NAME");
255 f.xmlPop();
258 //***********************************************************************************************
259 void CParticleWorkspace::CNode::savePS()
261 savePSAs(getFullPath());
265 //***********************************************************************************************
266 void CParticleWorkspace::CNode::savePSAs(const std::string &fullPath)
268 nlassert(_WS);
269 if (!_PS) return;
270 // build a shape from our system, and save it
271 NL3D::CParticleSystemShape psc;
272 psc.buildFromPS(*_PS);
273 NL3D::CShapeStream st(&psc);
274 NLMISC::COFile oFile(fullPath);
275 oFile.serial(st);
278 //***********************************************************************************************
279 std::string CParticleWorkspace::CNode::getFullPath() const
281 nlassert(_WS);
282 return NLMISC::CPath::makePathAbsolute(_RelativePath, _WS->getPath(), true);
285 //***********************************************************************************************
286 bool CParticleWorkspace::CNode::loadPS()
288 nlassert(_WS);
289 // manually load the PS shape (so that we can deal with exceptions)
290 NL3D::CShapeStream ss;
291 NLMISC::CIFile inputFile;
292 // collapse name
293 inputFile.open(getFullPath());
294 ss.serial(inputFile);
295 CUniquePtr<NL3D::CShapeBank> sb(new NL3D::CShapeBank);
296 std::string shapeName = NLMISC::CFile::getFilename(_RelativePath);
297 sb->add(shapeName, ss.getShapePointer());
298 NL3D::CShapeBank *oldSB = NL3D::CNELU::Scene->getShapeBank();
299 NL3D::CNELU::Scene->setShapeBank(sb.get());
300 NL3D::CTransformShape *trs = NL3D::CNELU::Scene->createInstance(shapeName);
301 if (!trs)
303 NL3D::CNELU::Scene->setShapeBank(oldSB);
304 return false;
306 NL3D::CParticleSystemModel *psm = dynamic_cast<NL3D::CParticleSystemModel *>(trs);
307 if (!psm)
309 // Not a particle system
310 NL3D::CNELU::Scene->deleteInstance(trs);
311 return false;
313 NL3D::CNELU::Scene->setShapeBank(oldSB);
314 setup(*psm);
315 unload();
316 // commit new values
317 _PS = psm->getPS();
318 _PSM = psm;
319 _ShapeBank = sb.release();
320 _Modified = false;
321 return true;
325 //***********************************************************************************************
326 CParticleWorkspace::CParticleWorkspace()
328 _OV = NULL;
329 _Modified = false;
330 _FontManager = NULL;
331 _FontGenerator = NULL;
332 _ModificationCallback = NULL;
335 //***********************************************************************************************
336 CParticleWorkspace::~CParticleWorkspace()
340 //***********************************************************************************************
341 void CParticleWorkspace::init(CObjectViewer *ov,
342 const std::string &filename,
343 NL3D::CFontManager *fontManager,
344 NL3D::CFontGenerator *fontGenerator
347 nlassert(!_OV);
348 nlassert(ov);
349 _OV = ov;
350 _Filename = filename;
351 _FontManager = fontManager;
352 _FontGenerator = fontGenerator;
354 //***********************************************************************************************
355 void CParticleWorkspace::setName(const std::string &name)
357 _Name = name;
358 touch();
362 //***********************************************************************************************
363 CParticleWorkspace::CNode *CParticleWorkspace::addNode(const std::string &filenameWithFullPath)
365 nlassert(_OV);
366 // Check that file is not already inserted
367 std::string fileName = NLMISC::CFile::getFilename(filenameWithFullPath);
368 for(uint k = 0; k < _Nodes.size(); ++k)
370 if (NLMISC::nlstricmp(_Nodes[k]->getFilename(), fileName) == 0) return NULL;
373 // TODO: replace with NeL methods
374 TCHAR resultPath[MAX_PATH];
375 std::string dosPath = NLMISC::CPath::standardizeDosPath(getPath());
376 std::string relativePath;
377 if (!PathRelativePathTo(resultPath, nlUtf8ToTStr(dosPath), FILE_ATTRIBUTE_DIRECTORY, nlUtf8ToTStr(filenameWithFullPath), 0))
379 relativePath = filenameWithFullPath;
381 else
383 relativePath = NLMISC::tStrToUtf8(resultPath);
386 if (relativePath.size() >= 2)
388 if (relativePath[0] == '\\' && relativePath[1] != '\\')
390 relativePath = relativePath.substr(1);
394 CNode *newNode = new CNode;
395 newNode->init(this);
396 newNode->setRelativePath(relativePath);
397 _Nodes.push_back(newNode);
398 setModifiedFlag(true);
399 return newNode;
402 //***********************************************************************************************
403 void CParticleWorkspace::removeNode(uint index)
405 nlassert(_OV);
406 nlassert(index < _Nodes.size());
407 _Nodes[index] = NULL; // delete the smart-ptr target
408 _Nodes.erase(_Nodes.begin() + index);
409 touch();
412 //***********************************************************************************************
413 void CParticleWorkspace::removeNode(CNode *ptr)
415 sint index = getIndexFromNode(ptr);
416 nlassert(index != -1);
417 removeNode((uint) index);
420 //***********************************************************************************************
421 void CParticleWorkspace::save()
423 NLMISC::COFile stream;
424 stream.open(_Filename);
425 NLMISC::COXml xmlStream;
426 xmlStream.init(&stream);
427 this->serial(xmlStream);
428 clearModifiedFlag();
431 //***********************************************************************************************
432 void CParticleWorkspace::load()
434 NLMISC::CIFile stream;
435 stream.open(_Filename);
436 NLMISC::CIXml xmlStream;
437 xmlStream.init(stream);
438 this->serial(xmlStream);
439 clearModifiedFlag();
442 //***********************************************************************************************
443 void CParticleWorkspace::serial(NLMISC::IStream &f)
445 f.xmlPush("PARTICLE_WORKSPACE");
446 f.serialVersion(0);
447 f.xmlSerial(_Name, "NAME");
448 f.xmlPush("PS_LIST");
449 uint32 numNodes = (uint32)_Nodes.size();
450 // TODO : avoid to store the number of nodes
451 f.xmlSerial(numNodes, "NUM_NODES");
452 if (f.isReading())
454 for(uint k = 0; k < numNodes; ++k)
456 _Nodes.push_back(new CNode());
457 _Nodes.back()->init(this);
458 f.serial(*_Nodes.back());
461 else
463 for(uint k = 0; k < numNodes; ++k)
465 f.serial(*_Nodes[k]);
468 f.xmlPop();
469 f.xmlPop();
472 //***********************************************************************************************
473 std::string CParticleWorkspace::getPath() const
475 return NLMISC::CPath::standardizePath(NLMISC::CFile::getPath(_Filename));
478 //***********************************************************************************************
479 sint CParticleWorkspace::getIndexFromNode(CNode *node) const
481 nlassert(node);
482 nlassert(node->getWorkspace() == this);
483 for(uint k = 0; k < _Nodes.size(); ++k)
485 if (node == _Nodes[k]) return (sint) k;
487 return -1;
490 //***********************************************************************************************
491 bool CParticleWorkspace::containsFile(std::string filename) const
493 for(uint k = 0; k < _Nodes.size(); ++k)
495 if (NLMISC::nlstricmp(filename, _Nodes[k]->getFilename()) == 0) return true;
497 return false;
500 //***********************************************************************************************
501 void CParticleWorkspace::nodeModified(CNode &node)
503 nlassert(node.getWorkspace() == this);
504 if (_ModificationCallback)
506 _ModificationCallback->nodeModifiedFlagChanged(node);
510 //***********************************************************************************************
511 CParticleWorkspace::CNode *CParticleWorkspace::getNodeFromPS(NL3D::CParticleSystem *ps) const
513 for(uint k = 0; k < _Nodes.size(); ++k)
515 if (_Nodes[k]->getPSPointer() == ps) return _Nodes[k];
517 return NULL;
520 //***********************************************************************************************
521 void CParticleWorkspace::setModifiedFlag(bool modified)
523 if (_Modified == modified) return;
524 _Modified = modified;
525 if (_ModificationCallback) _ModificationCallback->workspaceModifiedFlagChanged(*this);
528 //***********************************************************************************************
529 // predicate for workspace sorting
530 class CParticleWorkspaceSorter
532 public:
533 CParticleWorkspace::ISort *Sorter;
534 bool operator()(const NLMISC::CSmartPtr<CParticleWorkspace::CNode> &lhs, const NLMISC::CSmartPtr<CParticleWorkspace::CNode> &rhs)
536 return Sorter->less(*lhs, *rhs);
540 //***********************************************************************************************
541 void CParticleWorkspace::sort(ISort &predicate)
543 CParticleWorkspaceSorter ws;
544 ws.Sorter = &predicate;
545 std::sort(_Nodes.begin(), _Nodes.end(), ws);
546 setModifiedFlag(true);
549 //***********************************************************************************************
550 bool CParticleWorkspace::isContentModified() const
552 for(uint k = 0; k < _Nodes.size(); ++k)
554 if (_Nodes[k]->isModified()) return true;
556 return false;
559 //***********************************************************************************************
560 void CParticleWorkspace::restickAllObjects(CObjectViewer *ov)
562 for(uint k = 0; k < _Nodes.size(); ++k)
564 std::string parentSkelName = _Nodes[k]->getParentSkelName();
565 std::string parentBoneName = _Nodes[k]->getParentBoneName();
567 _Nodes[k]->unstickPSFromSkeleton();
568 if (!parentSkelName.empty())
569 // find instance to stick to in the scene
570 for(uint l = 0; l < ov->getNumInstance(); ++l)
572 CInstanceInfo *ii = ov->getInstance(l);
573 if (ii->TransformShape && ii->Saved.ShapeFilename == parentSkelName)
575 NL3D::CSkeletonModel *skel = dynamic_cast<NL3D::CSkeletonModel *>(ii->TransformShape);
576 if (skel)
578 sint boneID = skel->getBoneIdByName(parentBoneName);
579 if (boneID != -1)
581 _Nodes[k]->stickPSToSkeleton(skel, (uint) boneID, parentSkelName, parentBoneName);
582 break;