1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "nel/3d/skeleton_spawn_script.h"
20 #include "nel/3d/skeleton_model.h"
21 #include "nel/3d/mesh_base_instance.h"
22 #include "nel/3d/scene.h"
23 #include "nel/3d/particle_system_model.h"
24 #include "nel/misc/common.h"
25 #include "nel/misc/algo.h"
28 using namespace NLMISC
;
37 // ***************************************************************************
38 CSkeletonSpawnScript::CSkeletonSpawnScript()
43 // ***************************************************************************
44 CSkeletonSpawnScript::~CSkeletonSpawnScript()
46 // the user has not called release
47 nlassert(_Instances
.empty());
51 // ***************************************************************************
52 void CSkeletonSpawnScript::evaluate(CSkeletonModel
*skeleton
)
54 // if same cache, don't need to update parsed instances
55 if(_Cache
!=skeleton
->getSpawnScript())
57 _Cache
=skeleton
->getSpawnScript();
58 parseCache(skeleton
->getOwnerScene(), skeleton
);
61 // each frame, update PS UserMatrix
62 for(uint i
=0;i
<_Instances
.size();i
++)
64 CInstance
&inst
= _Instances
[i
];
65 if(inst
.Model
&& inst
.PS
)
68 userMat
.setRot(CVector::I
, skeleton
->getSSSWODir(), CVector::K
);
69 userMat
.normalize(CMatrix::YZX
);
70 userMat
.setPos(skeleton
->getSSSWOPos());
71 inst
.PS
->setUserMatrix(userMat
);
77 // ***************************************************************************
78 void CSkeletonSpawnScript::release(CScene
*scene
)
80 // act as if the skeleton has an empty script
84 parseCache(scene
, NULL
);
88 // ***************************************************************************
89 void CSkeletonSpawnScript::parseCache(CScene
*scene
, CSkeletonModel
*skeleton
)
93 nlassert(_Cache
.empty() || skeleton
);
95 static std::vector
<std::string
> newLines
;
97 splitString(_Cache
,"\n",newLines
);
99 // **** compare the 2 set of script line to know what to add, and what to remove.
100 // NB: this is an O(N2), but the number of spawned objects should be small (0, 1 or 2 surely)
101 static std::vector
<bool> srcToRemove
;
102 static std::vector
<bool> dstToAdd
;
105 srcToRemove
.resize(_Instances
.size(), true);
106 dstToAdd
.resize(newLines
.size(), true);
107 for(uint i
=0;i
<_Instances
.size();i
++)
109 for(uint j
=0;j
<newLines
.size();j
++)
111 // if the new line script is the same than the old one, then reuse!
112 // NB: the script line contains an "instance number", so there is no risk of "reuse same twice"
113 if(newLines
[j
] == _Instances
[i
].ScriptLine
)
115 srcToRemove
[i
]= false;
121 // **** remove the no more used instances
122 vector
<CInstance
>::iterator it
= _Instances
.begin();
123 for(i
=0;i
<srcToRemove
.size();i
++)
125 // if must remove this entry
128 // then erase the entry
130 scene
->deleteInstance(it
->Model
);
131 it
= _Instances
.erase(it
);
137 // **** create the new instances
138 for(i
=0;i
<dstToAdd
.size();i
++)
144 const std::string
&line
= newLines
[i
];
145 static std::vector
<string
> words
;
147 splitString(line
, " ", words
);
153 // format: "objw inst shapeName"
154 // inst is a number only used to generate line difference (for cache comparison)
155 _Instances
.push_back(CInstance());
156 CInstance
&inst
= _Instances
.back();
157 inst
.ScriptLine
= line
;
159 // Delay the model creation at end of CScene::render()
160 CSSSModelRequest req
;
162 req
.InstanceId
= (uint
)_Instances
.size()-1;
164 // World Spawned Objects are sticked to the root bone (for CLod hiding behavior)
166 // but have a special feature to compute their world matrix
168 addModelCreationRequest(req
, scene
);
170 else if(words
[0]=="objl" && words
.size()>=4)
172 // format: "objl inst shapeName boneName"
173 // inst is a number only used to generate line difference (for cache comparison)
175 // get the bone name, but may have space in its name => words[3] is not the correct name
180 while(pos
<line
.size() && line
[pos
]==' ')
182 // count word until reach
183 while(pos
<line
.size())
191 // reach bone name! stop
203 // and get the bone name
204 string boneName
= line
.substr(pos
);
207 _Instances
.push_back(CInstance());
208 CInstance
&inst
= _Instances
.back();
209 inst
.ScriptLine
= line
;
210 // try to get the bone id from name
211 sint32 boneId
= skeleton
->getBoneIdByName(boneName
);
212 // if fails, then don't create the instance
215 // Delay the model creation at end of CScene::render()
216 CSSSModelRequest req
;
218 req
.InstanceId
= (uint
)_Instances
.size()-1;
222 addModelCreationRequest(req
, scene
);
226 // avoid flooding (animation)
228 nlwarning("ERROR: SkeletonSpawnScript: boneId not found in: %s", line
.c_str());
235 // avoid flooding (animation)
237 nlwarning("ERROR: SkeletonSpawnScript: error in command: %s", line
.c_str());
246 // ***************************************************************************
247 void CSkeletonSpawnScript::addModelCreationRequest(CSSSModelRequest
&req
, CScene
*scene
)
249 // if the scene is currently rendering, then process the request at end of CScene::render()
250 if(scene
->isRendering())
251 scene
->addSSSModelRequest(req
);
252 // else process it now!
258 // ***************************************************************************
259 void CSSSModelRequest::execute()
261 // If skeleton still exist
265 CSkeletonSpawnScript
&sss
= Skel
->getSSSScript();
266 CScene
*scene
= Skel
->getOwnerScene();
268 // test validity of the instanceId
269 if(InstanceId
>=sss
._Instances
.size())
271 // it must not have been already created (else error???)
272 if(sss
._Instances
[InstanceId
].Model
)
275 // OK, create the model
276 CSkeletonSpawnScript::CInstance
&inst
= sss
._Instances
[InstanceId
];
277 inst
.Model
= scene
->createInstance(Shape
);
278 inst
.PS
= dynamic_cast<CParticleSystemModel
*>((CTransformShape
*)inst
.Model
);
281 Skel
->stickObject(inst
.Model
, BoneId
);
282 inst
.Model
->setSSSWO(SSSWO
);