Rigs of Rods 2023.09
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
FlexBody.cpp
Go to the documentation of this file.
1/*
2 This source file is part of Rigs of Rods
3 Copyright 2005-2012 Pierre-Michel Ricordel
4 Copyright 2007-2012 Thomas Fischer
5 Copyright 2013-2020 Petr Ohlidal
6
7 For more information, see http://www.rigsofrods.org/
8
9 Rigs of Rods is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 3, as
11 published by the Free Software Foundation.
12
13 Rigs of Rods is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "FlexBody.h"
23
24#include "Application.h"
25#include "ApproxMath.h"
26#include "Console.h"
27#include "SimData.h"
28#include "FlexFactory.h"
29#include "GfxActor.h"
30#include "GfxScene.h"
31#include "RigDef_File.h"
32
33#include <Ogre.h>
34
35using namespace Ogre;
36using namespace RoR;
37
39 RoR::FlexBodyCacheData* preloaded_from_cache,
40 RoR::GfxActor* gfx_actor,
41 Ogre::Entity* ent,
42 NodeNum_t ref,
43 NodeNum_t nx,
44 NodeNum_t ny,
45 Ogre::Vector3 offset,
46 Ogre::Quaternion const & rot,
47 std::vector<unsigned int> & node_indices,
48 std::vector<ForvertTempData>& forvert_data
49):
50 m_center_offset(offset)
51 , m_node_center(ref)
52 , m_node_x(nx)
53 , m_node_y(ny)
54 , m_scene_entity(ent)
55 , m_gfx_actor(gfx_actor)
56{
59
60 Ogre::Vector3* vertices = nullptr;
61 std::string mesh_name = ent->getMesh()->getName();
62
63 Vector3 normal = Vector3::UNIT_Y;
64 Vector3 position = Vector3::ZERO;
65 Quaternion orientation = Quaternion::ZERO;
66
68
70 {
71 Vector3 diffX = nodes[nx].AbsPosition-nodes[ref].AbsPosition;
72 Vector3 diffY = nodes[ny].AbsPosition-nodes[ref].AbsPosition;
73
74 normal = (diffY.crossProduct(diffX)).normalisedCopy();
75
76 // position
77 position = nodes[ref].AbsPosition + offset.x * diffX + offset.y * diffY;
78 position = position + offset.z * normal;
79
80 // orientation
81 Vector3 refX = diffX.normalisedCopy();
82 Vector3 refY = refX.crossProduct(normal);
83 orientation = Quaternion(refX, normal, refY) * rot;
84 }
85 else
86 {
87 // special case!
88 normal = Vector3::UNIT_Y;
89 position = nodes[0].AbsPosition + offset;
90 orientation = rot;
91 }
92
93 Ogre::MeshPtr mesh=ent->getMesh();
94 m_orig_mesh_info = RoR::PrintMeshInfo("Original", mesh); // For diagnostics only
95 int num_submeshes = static_cast<int>(mesh->getNumSubMeshes());
96 if (preloaded_from_cache == nullptr)
97 {
98 //determine if we have texture coordinates everywhere
99 if (mesh->sharedVertexData && mesh->sharedVertexData->vertexDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES)==0)
100 {
101 m_has_texture=false;
102 }
103 for (int i=0; i<num_submeshes; i++)
104 {
105 if (!mesh->getSubMesh(i)->useSharedVertices && mesh->getSubMesh(i)->vertexData->vertexDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES)==0)
106 {
107 m_has_texture=false;
108 }
109 }
110 if (!m_has_texture)
111 {
112 LOG("FLEXBODY Warning: at least one part of this mesh does not have texture coordinates, switching off texturing!");
114 }
115
116 //detect the anomalous case where a mesh is exported without normal vectors
117 bool havenormal=true;
118 if (mesh->sharedVertexData && mesh->sharedVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL)==0)
119 {
120 havenormal=false;
121 }
122 for (int i=0; i<num_submeshes; i++)
123 {
124 if (!mesh->getSubMesh(i)->useSharedVertices && mesh->getSubMesh(i)->vertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL)==0)
125 {
126 havenormal=false;
127 }
128 }
129 if (!havenormal)
130 {
131 LOG("FLEXBODY Error: at least one part of this mesh does not have normal vectors, export your mesh with normal vectors! Disabling flexbody");
132 // NOTE: Intentionally not disabling, for compatibility with v0.4.0.7
133 }
134 }
135 else
136 {
139 }
140
141 //create optimal VertexDeclaration
142 VertexDeclaration* optimalVD=HardwareBufferManager::getSingleton().createVertexDeclaration();
143 optimalVD->addElement(0, 0, VET_FLOAT3, VES_POSITION);
144 optimalVD->addElement(1, 0, VET_FLOAT3, VES_NORMAL);
145 if (m_has_texture_blend) optimalVD->addElement(2, 0, VET_COLOUR_ARGB, VES_DIFFUSE);
146 if (m_has_texture) optimalVD->addElement(3, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES);
147 optimalVD->sort();
148 optimalVD->closeGapsInSource();
149 BufferUsageList optimalBufferUsages;
150 for (size_t u = 0; u <= optimalVD->getMaxSource(); ++u)
151 {
152 optimalBufferUsages.push_back(HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
153 }
154
155 //adding color buffers, well get the reference later
157 {
158 if (mesh->sharedVertexData)
159 {
160 if (mesh->sharedVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE)==0)
161 {
162 //add buffer
163 int index=mesh->sharedVertexData->vertexDeclaration->getMaxSource()+1;
164 mesh->sharedVertexData->vertexDeclaration->addElement(index, 0, VET_COLOUR_ARGB, VES_DIFFUSE);
165 mesh->sharedVertexData->vertexDeclaration->sort();
166 index=mesh->sharedVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE)->getSource();
167 HardwareVertexBufferSharedPtr vbuf=HardwareBufferManager::getSingleton().createVertexBuffer(VertexElement::getTypeSize(VET_COLOUR_ARGB), mesh->sharedVertexData->vertexCount, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
168 mesh->sharedVertexData->vertexBufferBinding->setBinding(index, vbuf);
169 }
170 }
171 for (int i=0; i<num_submeshes; i++)
172 {
173 if (!mesh->getSubMesh(i)->useSharedVertices)
174 {
175 Ogre::VertexData* vertex_data = mesh->getSubMesh(i)->vertexData;
176 Ogre::VertexDeclaration* vertex_decl = vertex_data->vertexDeclaration;
177 if (vertex_decl->findElementBySemantic(VES_DIFFUSE)==0)
178 {
179 //add buffer
180 int index = vertex_decl->getMaxSource()+1;
181 vertex_decl->addElement(index, 0, VET_COLOUR_ARGB, VES_DIFFUSE);
182 vertex_decl->sort();
183 vertex_decl->findElementBySemantic(VES_DIFFUSE)->getSource();
184 HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
185 VertexElement::getTypeSize(VET_COLOUR_ARGB), vertex_data->vertexCount, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
186 vertex_data->vertexBufferBinding->setBinding(index, vbuf);
187 }
188 }
189 }
190 }
191
192 //reorg
193 //LOG("FLEXBODY reorganizing buffers");
194 if (mesh->sharedVertexData)
195 {
196 mesh->sharedVertexData->reorganiseBuffers(optimalVD, optimalBufferUsages);
197 mesh->sharedVertexData->removeUnusedBuffers();
198 mesh->sharedVertexData->closeGapsInBindings();
199 }
200 Mesh::SubMeshIterator smIt = mesh->getSubMeshIterator();
201 while (smIt.hasMoreElements())
202 {
203 SubMesh* sm = smIt.getNext();
204 if (!sm->useSharedVertices)
205 {
206 sm->vertexData->reorganiseBuffers(optimalVD->clone(), optimalBufferUsages);
207 sm->vertexData->removeUnusedBuffers();
208 sm->vertexData->closeGapsInBindings();
209 }
210 }
211
212 //print mesh information
213 //LOG("FLEXBODY Printing modififed mesh informations:");
214 //printMeshInfo(ent->getMesh().get());
215
216 //get the buffers
217 //getMeshInformation(ent->getMesh().get(),m_vertex_count,vertices,index_count,indices, position, orientation, Vector3(1,1,1));
218
219 //getting vertex counts
220 if (preloaded_from_cache == nullptr)
221 {
225 if (mesh->sharedVertexData)
226 {
227 m_vertex_count+=mesh->sharedVertexData->vertexCount;
229 }
230 for (int i=0; i<num_submeshes; i++)
231 {
232 if (!mesh->getSubMesh(i)->useSharedVertices)
233 {
234 m_vertex_count+=mesh->getSubMesh(i)->vertexData->vertexCount;
236 }
237 }
238 } else
239 {
240 m_vertex_count = preloaded_from_cache->header.vertex_count;
242 m_num_submesh_vbufs = preloaded_from_cache->header.num_submesh_vbufs;
243 }
244
245 // Profiler data
246 double stat_manual_buffers_created_time = -1;
247 double stat_transformed_time = -1;
248 double stat_located_time = -1;
249 if (preloaded_from_cache != nullptr)
250 {
251 m_dst_pos = preloaded_from_cache->dst_pos;
252 m_src_normals = preloaded_from_cache->src_normals;
253 m_locators = preloaded_from_cache->locators;
254 m_dst_normals = (Vector3*)malloc(sizeof(Vector3)*m_vertex_count); // Use malloc() for compatibility
255
257 {
258 m_src_colors = preloaded_from_cache->src_colors;
259 }
260
261 if (mesh->sharedVertexData)
262 {
263 m_shared_buf_num_verts=(int)mesh->sharedVertexData->vertexCount;
264
265 //vertices
266 int source=mesh->sharedVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION)->getSource();
267 m_shared_vbuf_pos=mesh->sharedVertexData->vertexBufferBinding->getBuffer(source);
268 //normals
269 source=mesh->sharedVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL)->getSource();
270 m_shared_vbuf_norm=mesh->sharedVertexData->vertexBufferBinding->getBuffer(source);
271 //colors
273 {
274 source=mesh->sharedVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE)->getSource();
275 m_shared_vbuf_color=mesh->sharedVertexData->vertexBufferBinding->getBuffer(source);
276 }
277 }
278 unsigned int curr_submesh_idx = 0;
279 for (int i=0; i<num_submeshes; i++)
280 {
281 const Ogre::SubMesh* submesh = mesh->getSubMesh(i);
282 if (submesh->useSharedVertices)
283 {
284 continue;
285 }
286 const Ogre::VertexData* vertex_data = submesh->vertexData;
287 m_submesh_vbufs_vertex_counts[curr_submesh_idx] = (int)vertex_data->vertexCount;
288
289 int source_pos = vertex_data->vertexDeclaration->findElementBySemantic(VES_POSITION)->getSource();
290 int source_norm = vertex_data->vertexDeclaration->findElementBySemantic(VES_NORMAL)->getSource();
291 m_submesh_vbufs_pos [curr_submesh_idx] = vertex_data->vertexBufferBinding->getBuffer(source_pos);
292 m_submesh_vbufs_norm[curr_submesh_idx] = vertex_data->vertexBufferBinding->getBuffer(source_norm);
293
295 {
296 int source_color = vertex_data->vertexDeclaration->findElementBySemantic(VES_DIFFUSE)->getSource();
297 m_submesh_vbufs_color[curr_submesh_idx] = vertex_data->vertexBufferBinding->getBuffer(source_color);
298 }
299 curr_submesh_idx++;
300 }
301 }
302 else
303 {
304 vertices=(Vector3*)malloc(sizeof(Vector3)*m_vertex_count);
305 m_dst_pos=(Vector3*)malloc(sizeof(Vector3)*m_vertex_count);
306 m_src_normals=(Vector3*)malloc(sizeof(Vector3)*m_vertex_count);
307 m_dst_normals=(Vector3*)malloc(sizeof(Vector3)*m_vertex_count);
309 {
310 m_src_colors=(ARGB*)malloc(sizeof(ARGB)*m_vertex_count);
311 for (int i=0; i<(int)m_vertex_count; i++) m_src_colors[i]=0x00000000;
312 }
313 Vector3* vpt=vertices;
314 Vector3* npt=m_src_normals;
315 if (mesh->sharedVertexData)
316 {
317 m_shared_buf_num_verts=(int)mesh->sharedVertexData->vertexCount;
318 //vertices
319 int source=mesh->sharedVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION)->getSource();
320 m_shared_vbuf_pos=mesh->sharedVertexData->vertexBufferBinding->getBuffer(source);
321 m_shared_vbuf_pos->readData(0, mesh->sharedVertexData->vertexCount*sizeof(Vector3), (void*)vpt);
322 vpt+=mesh->sharedVertexData->vertexCount;
323 //normals
324 source=mesh->sharedVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL)->getSource();
325 m_shared_vbuf_norm=mesh->sharedVertexData->vertexBufferBinding->getBuffer(source);
326 m_shared_vbuf_norm->readData(0, mesh->sharedVertexData->vertexCount*sizeof(Vector3), (void*)npt);
327 npt+=mesh->sharedVertexData->vertexCount;
328 //colors
330 {
331 source=mesh->sharedVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE)->getSource();
332 m_shared_vbuf_color=mesh->sharedVertexData->vertexBufferBinding->getBuffer(source);
333 m_shared_vbuf_color->writeData(0, mesh->sharedVertexData->vertexCount*sizeof(ARGB), (void*)m_src_colors);
334 }
335 }
336 int cursubmesh=0;
337 for (int i=0; i<num_submeshes; i++)
338 {
339 const Ogre::SubMesh* submesh = mesh->getSubMesh(i);
340 if (submesh->useSharedVertices)
341 {
342 continue;
343 }
344 const Ogre::VertexData* vertex_data = submesh->vertexData;
345 int vertex_count = (int)vertex_data->vertexCount;
346 m_submesh_vbufs_vertex_counts[cursubmesh] = vertex_count;
347 //vertices
348 int source = vertex_data->vertexDeclaration->findElementBySemantic(VES_POSITION)->getSource();
349 m_submesh_vbufs_pos[cursubmesh]=vertex_data->vertexBufferBinding->getBuffer(source);
350 m_submesh_vbufs_pos[cursubmesh]->readData(0, vertex_count*sizeof(Vector3), (void*)vpt);
351 vpt += vertex_count;
352 //normals
353 source = vertex_data->vertexDeclaration->findElementBySemantic(VES_NORMAL)->getSource();
354 m_submesh_vbufs_norm[cursubmesh]=vertex_data->vertexBufferBinding->getBuffer(source);
355 m_submesh_vbufs_norm[cursubmesh]->readData(0, vertex_count*sizeof(Vector3), (void*)npt);
356 npt += vertex_count;
357 //colors
359 {
360 source = vertex_data->vertexDeclaration->findElementBySemantic(VES_DIFFUSE)->getSource();
361 m_submesh_vbufs_color[cursubmesh] = vertex_data->vertexBufferBinding->getBuffer(source);
362 m_submesh_vbufs_color[cursubmesh]->writeData(0, vertex_count*sizeof(ARGB), (void*)m_src_colors);
363 }
364 cursubmesh++;
365 }
366
367 //transform
368 for (int i=0; i<(int)m_vertex_count; i++)
369 {
370 vertices[i]=(orientation*vertices[i])+position;
371 }
372
374 for (int i=0; i<(int)m_vertex_count; i++)
375 {
376 // Is this locator is manually specified via directive 'forvert'?
377 auto forvert_itor = std::find_if(forvert_data.begin(), forvert_data.end(),
378 [i](const ForvertTempData& data) { return data.vert_index == i; });
379 if (forvert_itor != forvert_data.end())
380 {
381 m_locators[i].ref = forvert_itor->nref;
382 m_locators[i].nx = forvert_itor->nx;
383 m_locators[i].ny = forvert_itor->ny;
384 m_locators[i].is_forvert = true;
385 LOG(fmt::format("FLEXBODY vertex {} overriden for nodes REF:{}, VX:{}, VY:{}",
386 i, m_locators[i].ref, m_locators[i].nx, m_locators[i].ny));
387 }
388 else
389 {
390
391 //search nearest node as the local origin
392 float closest_node_distance = std::numeric_limits<float>::max();
393 int closest_node_index = -1;
394 for (auto node_index : node_indices)
395 {
396 float node_distance = vertices[i].squaredDistance(nodes[node_index].AbsPosition);
397 if (node_distance < closest_node_distance)
398 {
399 closest_node_distance = node_distance;
400 closest_node_index = node_index;
401 }
402 }
403 if (closest_node_index == -1)
404 {
405 LOG("FLEXBODY ERROR on mesh " + mesh_name + ": REF node not found");
406 closest_node_index = 0;
407 }
408 m_locators[i].ref = closest_node_index;
409
410 //search the second nearest node as the X vector
411 closest_node_distance = std::numeric_limits<float>::max();
412 closest_node_index = -1;
413 for (auto node_index : node_indices)
414 {
415 if (node_index == m_locators[i].ref)
416 {
417 continue;
418 }
419 float node_distance = vertices[i].squaredDistance(nodes[node_index].AbsPosition);
420 if (node_distance < closest_node_distance)
421 {
422 closest_node_distance = node_distance;
423 closest_node_index = node_index;
424 }
425 }
426 if (closest_node_index == -1)
427 {
428 LOG("FLEXBODY ERROR on mesh " + mesh_name + ": VX node not found");
429 closest_node_index = 0;
430 }
431 m_locators[i].nx = closest_node_index;
432
433 //search another close, orthogonal node as the Y vector
434 closest_node_distance = std::numeric_limits<float>::max();
435 closest_node_index = -1;
436 Vector3 vx = (nodes[m_locators[i].nx].AbsPosition - nodes[m_locators[i].ref].AbsPosition).normalisedCopy();
437 for (auto node_index : node_indices)
438 {
439 if (node_index == m_locators[i].ref || node_index == m_locators[i].nx)
440 {
441 continue;
442 }
443 float node_distance = vertices[i].squaredDistance(nodes[node_index].AbsPosition);
444 if (node_distance < closest_node_distance)
445 {
446 Vector3 vt = (nodes[node_index].AbsPosition - nodes[m_locators[i].ref].AbsPosition).normalisedCopy();
447 float cost = vx.dotProduct(vt);
448 if (std::abs(cost) > std::sqrt(2.0f) / 2.0f)
449 {
450 continue; //rejection, fails the orthogonality criterion (+-45 degree)
451 }
452 closest_node_distance = node_distance;
453 closest_node_index = node_index;
454 }
455 }
456 if (closest_node_index == -1)
457 {
458 LOG("FLEXBODY ERROR on mesh " + mesh_name + ": VY node not found");
459 closest_node_index = 0;
460 }
461 m_locators[i].ny = closest_node_index;
462 }
463
464 Matrix3 mat;
465 Vector3 diffX = nodes[m_locators[i].nx].AbsPosition-nodes[m_locators[i].ref].AbsPosition;
466 Vector3 diffY = nodes[m_locators[i].ny].AbsPosition-nodes[m_locators[i].ref].AbsPosition;
467
468 mat.SetColumn(0, diffX);
469 mat.SetColumn(1, diffY);
470 mat.SetColumn(2, (diffX.crossProduct(diffY)).normalisedCopy()); // Old version: mat.SetColumn(2, nodes[loc.nz].AbsPosition-nodes[loc.ref].AbsPosition);
471
472 mat = mat.Inverse();
473
474 //compute coordinates in the newly formed Euclidean basis
475 m_locators[i].coords = mat * (vertices[i] - nodes[m_locators[i].ref].AbsPosition);
476
477 // that's it!
478 }
479
480 } // if (preloaded_from_cache == nullptr)
481
482 //adjusting bounds
483 AxisAlignedBox aab=mesh->getBounds();
484 Vector3 v=aab.getMinimum();
485 float mi=v.x;
486 if (v.y<mi) mi=v.y;
487 if (v.z<mi) mi=v.z;
488 mi=fabs(mi);
489 v=aab.getMaximum();
490 float ma=v.x;
491 if (ma<v.y) ma=v.y;
492 if (ma<v.z) ma=v.z;
493 ma=fabs(ma);
494 if (mi>ma) ma=mi;
495 aab.setMinimum(Vector3(-ma,-ma,-ma));
496 aab.setMaximum(Vector3(ma,ma,ma));
497 mesh->_setBounds(aab, true);
498
499 //okay, show the mesh now
500 m_scene_node=App::GetGfxScene()->GetSceneManager()->getRootSceneNode()->createChildSceneNode();
501 m_scene_node->attachObject(ent);
502 m_scene_node->setPosition(position);
503
504 if (preloaded_from_cache == nullptr)
505 {
506 for (int i=0; i<(int)m_vertex_count; i++)
507 {
508 Matrix3 mat;
509 Vector3 diffX = nodes[m_locators[i].nx].AbsPosition-nodes[m_locators[i].ref].AbsPosition;
510 Vector3 diffY = nodes[m_locators[i].ny].AbsPosition-nodes[m_locators[i].ref].AbsPosition;
511
512 mat.SetColumn(0, diffX);
513 mat.SetColumn(1, diffY);
514 mat.SetColumn(2, diffX.crossProduct(diffY).normalisedCopy()); // Old version: mat.SetColumn(2, nodes[loc.nz].AbsPosition-nodes[loc.ref].AbsPosition);
515
516 mat = mat.Inverse();
517
518 // compute coordinates in the Euclidean basis
519 m_src_normals[i] = mat*(orientation * m_src_normals[i]);
520 }
521 }
522
523 if (vertices != nullptr) { free(vertices); }
524
525 // Keep the forset nodes for diagnostics
526 for (unsigned int nodenum : node_indices)
527 {
528 m_forset_nodes.push_back((NodeNum_t)nodenum);
529 }
530
531 if (App::GetConsole()->cVarGet("flexbody_defrag_enabled", CVAR_TYPE_BOOL)->getBool()
532 // For simplicity, only take 1-submesh meshes (almost always the case anyway)
533 && m_scene_entity->getMesh()->getNumSubMeshes() == 1)
534 {
536 }
537}
538
539FlexBody::FlexBody(PlaceholderType p_type, FlexbodyID_t id, const std::string& orig_meshname)
540{
542 m_id = id;
543 m_orig_mesh_name = orig_meshname;
544 m_placeholder_type = p_type;
545}
546
548{
549 // Stuff using <new>
550 if (m_locators != nullptr) { delete[] m_locators; }
551 // Stuff using malloc()
552 if (m_src_normals != nullptr) { free(m_src_normals); }
553 if (m_dst_normals != nullptr) { free(m_dst_normals); }
554 if (m_dst_pos != nullptr) { free(m_dst_pos ); }
555 if (m_src_colors != nullptr) { free(m_src_colors ); }
556
557 this->destroyOgreObjects();
558}
559
561{
562 switch (type)
563 {
564 case PlaceholderType::NOT_A_PLACEHOLDER: return "NOT_A_PLACEHOLDER";
565 case PlaceholderType::TUNING_REMOVED_PLACEHOLDER: return "TUNING_REMOVED_PLACEHOLDER";
566 case PlaceholderType::FAULTY_FORSET_PLACEHOLDER: return "FAULTY_FORSET_PLACEHOLDER";
567 case PlaceholderType::FAULTY_MESH_PLACEHOLDER: return "FAULTY_MESH_PLACEHOLDER";
568 default: return "";
569 }
570}
571
573{
574 // Separated out from destructor so that exceptions can be handled separately (C++ destructor cannot propagate exceptions)
575 // -----------------------------------------------------------------------------------------------------------------------
576
577 // OGRE resource - scene node
578 if (m_scene_node != nullptr)
579 {
580 m_scene_node->getParentSceneNode()->removeChild(m_scene_node);
581 App::GetGfxScene()->GetSceneManager()->destroySceneNode(m_scene_node);
582 }
583 m_scene_node = nullptr;
584
585 // OGRE resource - scene entity
586 if (m_scene_entity != nullptr)
587 {
588 Ogre::MeshPtr mesh = m_scene_entity->getMesh();
590
591 // OGRE resource - mesh (unique copy - should be destroyed)
592 Ogre::MeshManager::getSingleton().remove(mesh->getHandle());
593 }
594 m_scene_entity = nullptr;
595}
596
598{
599 // Scene node is NULL if disabled via addonpart/tuneup.
600 return m_scene_node
601 && m_scene_node->isInSceneGraph()
602 && m_scene_node->getAttachedObject(0)->isVisible();
603
604}
605
606void FlexBody::setVisible(bool visible)
607{
608 // Scene node is NULL if disabled via addonpart/tuneup.
609 if (m_scene_node)
610 m_scene_node->setVisible(visible);
611}
612
614{
615 // Scene entity is NULL if disabled via addonpart/tuneup.
616 if (m_scene_entity)
617 m_scene_entity->setCastShadows(val);
618}
619
621{
623
625
626 // compute the local center
627 if (m_node_center >= 0)
628 {
629 Vector3 diffX = nodes[m_node_x].AbsPosition - nodes[m_node_center].AbsPosition;
630 Vector3 diffY = nodes[m_node_y].AbsPosition - nodes[m_node_center].AbsPosition;
631 Ogre::Vector3 flexit_normal = fast_normalise(diffY.crossProduct(diffX));
632
634 m_flexit_center += m_center_offset.z * flexit_normal;
635 }
636 else
637 {
638 m_flexit_center = nodes[0].AbsPosition;
639 }
640
641 for (int i=0; i<(int)m_vertex_count; i++)
642 {
643 Vector3 diffX = nodes[m_locators[i].nx].AbsPosition - nodes[m_locators[i].ref].AbsPosition;
644 Vector3 diffY = nodes[m_locators[i].ny].AbsPosition - nodes[m_locators[i].ref].AbsPosition;
645 Vector3 nCross = fast_normalise(diffX.crossProduct(diffY)); //nCross.normalise();
646
647 m_dst_pos[i].x = diffX.x * m_locators[i].coords.x + diffY.x * m_locators[i].coords.y + nCross.x * m_locators[i].coords.z;
648 m_dst_pos[i].y = diffX.y * m_locators[i].coords.x + diffY.y * m_locators[i].coords.y + nCross.y * m_locators[i].coords.z;
649 m_dst_pos[i].z = diffX.z * m_locators[i].coords.x + diffY.z * m_locators[i].coords.y + nCross.z * m_locators[i].coords.z;
650
652
653 m_dst_normals[i].x = diffX.x * m_src_normals[i].x + diffY.x * m_src_normals[i].y + nCross.x * m_src_normals[i].z;
654 m_dst_normals[i].y = diffX.y * m_src_normals[i].x + diffY.y * m_src_normals[i].y + nCross.y * m_src_normals[i].z;
655 m_dst_normals[i].z = diffX.z * m_src_normals[i].x + diffY.z * m_src_normals[i].y + nCross.z * m_src_normals[i].z;
656
658 }
659}
660
662{
663 if (!m_scene_node) // Disabled via addonpart/tuneup
664 return;
665
666 Vector3 *ppt = m_dst_pos;
667 Vector3 *npt = m_dst_normals;
669 {
670 m_shared_vbuf_pos->writeData(0, m_shared_buf_num_verts*sizeof(Vector3), ppt, true);
672 m_shared_vbuf_norm->writeData(0, m_shared_buf_num_verts*sizeof(Vector3), npt, true);
674 }
675 for (int i=0; i<m_num_submesh_vbufs; i++)
676 {
677 m_submesh_vbufs_pos[i]->writeData(0, m_submesh_vbufs_vertex_counts[i]*sizeof(Vector3), ppt, true);
679 m_submesh_vbufs_norm[i]->writeData(0, m_submesh_vbufs_vertex_counts[i]*sizeof(Vector3), npt, true);
681 }
682
683 if (m_blend_changed)
684 {
685 writeBlend();
686 m_blend_changed = false;
687 }
688
689 m_scene_node->setPosition(m_flexit_center);
690}
691
693{
695 {
696 for (int i=0; i<(int)m_vertex_count; i++) m_src_colors[i]=0x00000000;
697 writeBlend();
698 }
699}
700
702{
703 if (!m_has_texture_blend) return;
704 ARGB *cpt = m_src_colors;
706 {
707 m_shared_vbuf_color->writeData(0, m_shared_buf_num_verts*sizeof(ARGB), (void*)cpt, true);
709 }
710 for (int i=0; i<m_num_submesh_vbufs; i++)
711 {
712 m_submesh_vbufs_color[i]->writeData(0, m_submesh_vbufs_vertex_counts[i]*sizeof(ARGB), (void*)cpt, true);
714 }
715}
716
717void FlexBody::updateBlend() //so easy!
718{
720 for (int i=0; i<(int)m_vertex_count; i++)
721 {
722 RoR::NodeSB *nd = &nodes[m_locators[i].ref];
723 ARGB col = m_src_colors[i];
724 if (nd->nd_has_contact && !(col&0xFF000000))
725 {
726 m_src_colors[i]=col|0xFF000000;
727 m_blend_changed = true;
728 }
729 if (nd->nd_is_wet ^ ((col&0x000000FF)>0))
730 {
731 m_src_colors[i]=(col&0xFFFFFF00)+0x000000FF*nd->nd_is_wet;
732 m_blend_changed = true;
733 }
734 }
735}
736
738{
739 if (a > b)
740 {
743 }
744 else if (a < b)
745 {
748 }
749 else
750 {
751 return 0;
752 }
753}
754
764
765template<typename uint_T> void reorderIndexBuffer(Ogre::IndexData* idx_data, std::vector<int> const& new_index_lookup)
766{
767 uint_T* workibuf = new uint_T[idx_data->indexCount];
768 idx_data->indexBuffer->readData(0, idx_data->indexBuffer->getSizeInBytes(), workibuf);
769 for (size_t i = 0; i < idx_data->indexCount; i++)
770 {
771 workibuf[i] = new_index_lookup[workibuf[i]];
772 }
773 idx_data->indexBuffer->writeData(0, idx_data->indexBuffer->getSizeInBytes(), workibuf);
774 delete[] workibuf;
775}
776
777void reorderVertexBuffer(Ogre::HardwareVertexBufferSharedPtr vert_buf, const Ogre::VertexElement* vert_elem, std::vector<int> const& new_index_lookup)
778{
779 char* workbuf_src = new char[vert_buf->getSizeInBytes()];
780 char* workbuf_dst = new char[vert_buf->getSizeInBytes()];
781 vert_buf->readData(0, vert_buf->getSizeInBytes(), workbuf_src);
782 for (size_t i = 0; i < vert_buf->getNumVertices(); i++)
783 {
784 void* src = workbuf_src + (i * vert_elem->getSize());
785 void* dst = workbuf_dst + (new_index_lookup[i] * vert_elem->getSize());
786 std::memcpy(dst, src, vert_elem->getSize());
787 }
788 vert_buf->writeData(0, vert_buf->getSizeInBytes(), workbuf_dst);
789 delete[] workbuf_src;
790 delete[] workbuf_dst;
791}
792
794{
795 // Analysis
796 NodeNum_t forset_max = std::numeric_limits<NodeNum_t>::min();
797 NodeNum_t forset_min = std::numeric_limits<NodeNum_t>::max();
798 for (NodeNum_t n : this->getForsetNodes())
799 {
800 if (n > forset_max) { forset_max = n; }
801 if (n < forset_min) { forset_min = n; }
802 }
803
804 std::vector<int> new_index_lookup(m_vertex_count);
805 for (int i = 0; i < (int)m_vertex_count; i++)
806 {
807 new_index_lookup[i] = i;
808 }
809
810 Locator_t prev_loc;
811 // edge values to start with
812 prev_loc.ref = forset_min;
813 prev_loc.nx = forset_min;
814 prev_loc.ny = forset_min;
815
816 // SELECTION SORT (https://www.geeksforgeeks.org/selection-sort/)
817 for (int i = 0; i < m_vertex_count; i++)
818 {
819 // Find the next locator closest in memory
820 int closest_loc = i;
821 int closest_loc_penalty = INT_MAX;
822 for (int j = i; j < m_vertex_count; j++)
823 {
824 int penalty = evalMemoryDistance(prev_loc, m_locators[j]);
825 if (penalty < closest_loc_penalty)
826 {
827 closest_loc_penalty = penalty;
828 closest_loc = j;
829 }
830 }
831
832 // Swap locators+normals in memory, update lookup
833 Locator_t loc_tmp = m_locators[closest_loc];
834 Ogre::Vector3 norm_tmp = m_src_normals[closest_loc];
835 int idx_tmp = new_index_lookup[closest_loc];
836
837 m_locators[closest_loc] = m_locators[i];
838 m_src_normals[closest_loc] = m_src_normals[i];
839 new_index_lookup[closest_loc] = new_index_lookup[i];
840
841 m_locators[i] = loc_tmp;
842 m_src_normals[i] = norm_tmp;
843 new_index_lookup[i] = idx_tmp;
844
845 // Go next
846 prev_loc = m_locators[i];
847 }
848
850 {
851 std::vector<int> inverted_lookup(m_vertex_count);
852 for (int i = 0; i < (int)m_vertex_count; i++)
853 {
854 inverted_lookup[new_index_lookup[i]] = i;
855 }
856 for (int i = 0; i < (int)m_vertex_count; i++)
857 {
858 new_index_lookup[i] = inverted_lookup[i];
859 }
860 }
861
862 // REORDERING VERTICES
863 // * positions/normals are calculated, no action needed.
864 // * texcoords (aka UV-coords) must be fixed.
866 {
867 Ogre::VertexData* vert_data = nullptr;
868 if (m_scene_entity->getMesh()->sharedVertexData)
869 {
870 vert_data = m_scene_entity->getMesh()->sharedVertexData;
871 }
872 else
873 {
874 // for simplicity we only support single submesh
875 vert_data = m_scene_entity->getMesh()->getSubMesh(0)->vertexData;
876 }
877 const Ogre::VertexElement* uv_elem = vert_data->vertexDeclaration->findElementBySemantic(Ogre::VES_TEXTURE_COORDINATES);
878 Ogre::HardwareVertexBufferSharedPtr uv_buf = vert_data->vertexBufferBinding->getBuffer(uv_elem->getSource());
879 reorderVertexBuffer(uv_buf, uv_elem, new_index_lookup);
880 }
881
882 // REORDERING INDICES
884 {
885 Ogre::IndexData* idx_data = m_scene_entity->getMesh()->getSubMesh(0)->indexData;
886 // Index can be 16-bit or 32-bit!
887 if (idx_data->indexBuffer->getType() == Ogre::HardwareIndexBuffer::IT_16BIT)
888 {
889 reorderIndexBuffer<uint16_t>(idx_data, new_index_lookup);
890 }
891 else
892 {
893 reorderIndexBuffer<uint32_t>(idx_data, new_index_lookup);
894 }
895 }
896}
Central state/object manager and communications hub.
#define ROR_ASSERT(_EXPR)
Definition Application.h:40
void LOG(const char *msg)
Legacy alias - formerly a macro.
Ogre::Vector3 fast_normalise(Ogre::Vector3 v)
Definition ApproxMath.h:151
#define BITMASK_IS_1(VAR, FLAGS)
Definition BitFlags.h:14
void reorderIndexBuffer(Ogre::IndexData *idx_data, std::vector< int > const &new_index_lookup)
Definition FlexBody.cpp:765
int evalMemoryDistance(Locator_t &a, Locator_t &b)
Definition FlexBody.cpp:755
int evalNodeDistance(NodeNum_t a, NodeNum_t b)
Definition FlexBody.cpp:737
void reorderVertexBuffer(Ogre::HardwareVertexBufferSharedPtr vert_buf, const Ogre::VertexElement *vert_elem, std::vector< int > const &new_index_lookup)
Definition FlexBody.cpp:777
Manager for all visuals belonging to a single actor.
Data structures representing 'truck' file format, see https://docs.rigsofrods.org/vehicle-creation/fi...
Core data structures for simulation; Everything affected by by either physics, network or user intera...
bool getBool() const
Definition CVar.h:98
int getInt() const
Definition CVar.h:97
CVar * cVarGet(std::string const &input_name, int flags)
Get cvar by short/long name, or create new one using input as short name.
Definition CVar.cpp:295
void updateFlexbodyVertexBuffers()
Definition FlexBody.cpp:661
std::string m_orig_mesh_name
Definition FlexBody.h:153
Ogre::ARGB * m_src_colors
Definition FlexBody.h:123
FlexBody(RoR::FlexBodyCacheData *preloaded_from_cache, RoR::GfxActor *gfx_actor, Ogre::Entity *entity, NodeNum_t ref, NodeNum_t nx, NodeNum_t ny, Ogre::Vector3 offset, Ogre::Quaternion const &rot, std::vector< unsigned int > &node_indices, std::vector< ForvertTempData > &forvert_data)
Definition FlexBody.cpp:38
Ogre::SceneNode * m_scene_node
Definition FlexBody.h:130
Ogre::HardwareVertexBufferSharedPtr m_submesh_vbufs_norm[16]
normals
Definition FlexBody.h:142
Locator_t * m_locators
1 loc per vertex
Definition FlexBody.h:124
std::vector< NodeNum_t > m_forset_nodes
Definition FlexBody.h:151
void updateBlend()
Definition FlexBody.cpp:717
NodeNum_t m_node_y
Definition FlexBody.h:128
Ogre::Entity * m_scene_entity
Definition FlexBody.h:131
static const char * PlaceholderTypeToString(PlaceholderType type)
Definition FlexBody.cpp:560
int m_num_submesh_vbufs
Definition FlexBody.h:139
Ogre::Vector3 m_center_offset
Definition FlexBody.h:129
NodeNum_t m_node_center
Definition FlexBody.h:126
void defragmentFlexbodyMesh()
Definition FlexBody.cpp:793
bool m_has_texture
Definition FlexBody.h:146
int m_submesh_vbufs_vertex_counts[16]
Definition FlexBody.h:140
RoR::GfxActor * m_gfx_actor
Definition FlexBody.h:114
void setFlexbodyCastShadow(bool val)
Definition FlexBody.cpp:613
std::string m_orig_mesh_info
Definition FlexBody.h:152
Ogre::HardwareVertexBufferSharedPtr m_shared_vbuf_pos
Definition FlexBody.h:135
void setVisible(bool visible)
Definition FlexBody.cpp:606
Ogre::HardwareVertexBufferSharedPtr m_submesh_vbufs_pos[16]
positions
Definition FlexBody.h:141
size_t m_vertex_count
Definition FlexBody.h:115
Ogre::HardwareVertexBufferSharedPtr m_shared_vbuf_color
Definition FlexBody.h:137
int m_camera_mode
Visibility control {-2 = always, -1 = 3rdPerson only, 0+ = cinecam index}.
Definition FlexBody.h:132
FlexbodyID_t m_id
Definition FlexBody.h:117
bool m_has_texture_blend
Definition FlexBody.h:147
void writeBlend()
Definition FlexBody.cpp:701
void destroyOgreObjects()
Definition FlexBody.cpp:572
bool isVisible() const
Definition FlexBody.cpp:597
Ogre::Vector3 * m_dst_pos
Definition FlexBody.h:120
int m_shared_buf_num_verts
Definition FlexBody.h:134
Ogre::HardwareVertexBufferSharedPtr m_submesh_vbufs_color[16]
colors
Definition FlexBody.h:143
void computeFlexbody()
Updates mesh deformation; works on CPU using local copy of vertex data.
Definition FlexBody.cpp:620
Ogre::Vector3 m_flexit_center
Updated per frame.
Definition FlexBody.h:116
Ogre::Vector3 * m_src_normals
Definition FlexBody.h:121
bool m_blend_changed
Definition FlexBody.h:148
PlaceholderType m_placeholder_type
Definition FlexBody.h:118
Ogre::Vector3 * m_dst_normals
Definition FlexBody.h:122
bool m_uses_shared_vertex_data
Definition FlexBody.h:145
NodeNum_t m_node_x
Definition FlexBody.h:127
std::vector< NodeNum_t > & getForsetNodes()
Definition FlexBody.h:98
Ogre::HardwareVertexBufferSharedPtr m_shared_vbuf_norm
Definition FlexBody.h:136
NodeSB * GetSimNodeBuffer()
Definition GfxActor.h:129
Ogre::SceneManager * GetSceneManager()
Definition GfxScene.h:83
@ CVAR_TYPE_BOOL
Definition CVar.h:38
CVar * flexbody_defrag_const_penalty
CVar * flexbody_defrag_reorder_texcoords
CVar * flexbody_defrag_prog_down_penalty
GfxScene * GetGfxScene()
Console * GetConsole()
CVar * flexbody_defrag_reorder_indices
CVar * flexbody_defrag_invert_lookup
static const NodeNum_t NODENUM_INVALID
int FlexbodyID_t
Index to GfxActor::m_flexbodies, use RoR::FLEXBODYID_INVALID as empty value.
std::string PrintMeshInfo(std::string const &title, Ogre::MeshPtr mesh)
uint16_t NodeNum_t
Node position within Actor::ar_nodes; use RoR::NODENUM_INVALID as empty value.
static CameraMode_t CAMERA_MODE_ALWAYS_HIDDEN
Ogre::Vector3 * dst_pos
Definition FlexFactory.h:79
Ogre::ARGB * src_colors
Definition FlexFactory.h:81
Ogre::Vector3 * src_normals
Definition FlexFactory.h:80
FlexBodyRecordHeader header
Definition FlexFactory.h:77
Locator_t * locators
1 loc per vertex
Definition FlexFactory.h:82
static const BitMask_t HAS_TEXTURE_BLEND
Definition FlexFactory.h:63
static const BitMask_t HAS_TEXTURE
Definition FlexFactory.h:62
static const BitMask_t USES_SHARED_VERTEX_DATA
Definition FlexFactory.h:61
< Node resolution must be done in ActorSpawner, but vert resolution in FlexBody
Definition Locator_t.h:24
NodeNum_t ref
Definition Locator_t.h:12
NodeNum_t nx
Definition Locator_t.h:13
NodeNum_t getSmallestNode()
Definition Locator_t.h:18
NodeNum_t ny
Definition Locator_t.h:14
Ogre::Vector3 coords
Definition Locator_t.h:15
NodeNum_t getMean()
Definition Locator_t.h:20
bool nd_has_contact
Definition SimBuffers.h:70
Ogre::Vector3 AbsPosition
Definition SimBuffers.h:69
bool nd_is_wet
Definition SimBuffers.h:71