RigsofRods
Soft-body Physics Simulation
FlexObj.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 "FlexObj.h"
23 
24 #include "ApproxMath.h" // fast_normalise()
25 #include "GfxActor.h"
26 
27 #include <Ogre.h>
28 
29 using namespace Ogre;
30 using namespace RoR;
31 
32 FlexObj::FlexObj(RoR::GfxActor* gfx_actor, node_t* all_nodes, std::vector<CabTexcoord>& texcoords, int numtriangles,
33  int* triangles, std::vector<CabSubmesh>& submesh_defs,
34  char* texname, const char* name, char* backtexname, char* transtexname):
35  m_gfx_actor(gfx_actor)
36 {
37  m_triangle_count = numtriangles;
38 
39  // Create the mesh via the MeshManager
40  m_mesh = MeshManager::getSingleton().createManual(name, gfx_actor->GetResourceGroup());
41 
42  // Create submeshes
43  m_submeshes.reserve(submesh_defs.size());
44  for (size_t j=0; j<submesh_defs.size(); j++)
45  {
46  Ogre::SubMesh* submesh = m_mesh->createSubMesh();
47  switch (submesh_defs[j].backmesh_type)
48  {
49  case CabSubmesh::BACKMESH_OPAQUE: submesh->setMaterialName(backtexname); break;
50  case CabSubmesh::BACKMESH_TRANSPARENT: submesh->setMaterialName(transtexname); break;
51  default: submesh->setMaterialName(texname);
52  }
53  m_submeshes.push_back(submesh);
54  };
55 
56  // Define the m_vertices_raw (8 vertices, each consisting of 3 groups of 3 floats
57  m_vertex_count = texcoords.size();
58  m_vertices_raw=(float*)malloc(((2*3+2)*m_vertex_count)*sizeof(float));
59  m_vertex_nodes=(int*)malloc(m_vertex_count*sizeof(int));
60 
61  for (size_t i=0; i<m_vertex_count; i++)
62  {
63  m_vertex_nodes[i] = texcoords[i].node_id; //define node ids
64  m_vertices[i].texcoord=Vector2(texcoords[i].texcoord_u, texcoords[i].texcoord_v); //textures coordinates
65  }
66 
67  // Define triangles
68  // The values in this table refer to vertices in the above table
69  m_index_count = 3*numtriangles;
70  m_indices=(unsigned short*)malloc(m_index_count*sizeof(unsigned short));
71  for (size_t i=0; i<m_index_count; i++)
72  {
73  m_indices[i]=ComputeVertexPos(static_cast<int>(i/3), triangles[i], submesh_defs);
74  }
75 
76  m_s_ref=(float*)malloc(numtriangles*sizeof(float));
77 
78  for (size_t i=0; i<(unsigned int)numtriangles;i++)
79  {
80  Ogre::Vector3 base_pos = all_nodes[m_vertex_nodes[m_indices[i*3]]].RelPosition;
81  Ogre::Vector3 v1 = all_nodes[m_vertex_nodes[m_indices[i*3+1]]].RelPosition - base_pos;
82  Ogre::Vector3 v2 = all_nodes[m_vertex_nodes[m_indices[i*3+2]]].RelPosition - base_pos;
83  m_s_ref[i]=v1.crossProduct(v2).length()*2.0;
84  }
85 
86  this->UpdateMesh(); // Initialize the dynamic mesh
87 
88  // Create vertex data structure for vertices shared between submeshes
89  m_mesh->sharedVertexData = new VertexData();
90  m_mesh->sharedVertexData->vertexCount = m_vertex_count;
91 
92  // Create declaration (memory format) of vertex data
93  m_vertex_format = m_mesh->sharedVertexData->vertexDeclaration;
94  size_t offset = 0;
95  m_vertex_format->addElement(0, offset, VET_FLOAT3, VES_POSITION);
96  offset += VertexElement::getTypeSize(VET_FLOAT3);
97  m_vertex_format->addElement(0, offset, VET_FLOAT3, VES_NORMAL);
98  offset += VertexElement::getTypeSize(VET_FLOAT3);
99  m_vertex_format->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
100  offset += VertexElement::getTypeSize(VET_FLOAT2);
101 
102  // Allocate vertex buffer of the requested number of vertices (vertexCount)
103  // and bytes per vertex (offset)
104  m_hw_vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
105  offset, m_mesh->sharedVertexData->vertexCount, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
106 
107  // Upload the vertex data to the card
108  m_hw_vbuf->writeData(0, m_hw_vbuf->getSizeInBytes(), m_vertices_raw, true);
109 
110  // Set vertex buffer binding so buffer 0 is bound to our vertex buffer
111  VertexBufferBinding* bind = m_mesh->sharedVertexData->vertexBufferBinding;
112  bind->setBinding(0, m_hw_vbuf);
113 
114  // Set parameters of the submeshes
115  for (size_t j=0; j<m_submeshes.size(); j++)
116  {
117  size_t index_count;
118  if (j == 0)
119  index_count = 3*submesh_defs[j].cabs_pos;
120  else
121  index_count = 3*(submesh_defs[j].cabs_pos-submesh_defs[j-1].cabs_pos); // 3 indices per triangle
122 
123  m_submeshes[j]->useSharedVertices = true;
124  HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton().createIndexBuffer(
125  HardwareIndexBuffer::IT_16BIT,
126  index_count,
127  HardwareBuffer::HBU_STATIC_WRITE_ONLY);
128 
129  // Upload the index data to the card
130  unsigned short* faces_ptr;
131  if (j == 0)
132  faces_ptr = &m_indices[0];
133  else
134  faces_ptr = &m_indices[submesh_defs[j-1].cabs_pos * 3];
135 
136  ibuf->writeData(0, ibuf->getSizeInBytes(), faces_ptr, true);
137  m_submeshes[j]->indexData->indexBuffer = ibuf;
138  m_submeshes[j]->indexData->indexCount = index_count;
139  m_submeshes[j]->indexData->indexStart = 0;
140  }
141 
142  // Set bounding information (for culling)
143  m_mesh->_setBounds(AxisAlignedBox(-100,-100,-100,100,100,100), true);
144 
145  // Notify Mesh object that it has been loaded
146  m_mesh->load();
147 }
148 
149 void FlexObj::ScaleFlexObj(float factor)
150 {
151  for (int i=0; i<m_triangle_count;i++)
152  {
153  m_s_ref[i] *= factor;
154  }
155 }
156 
158 int FlexObj::ComputeVertexPos(int tidx, int v, std::vector<CabSubmesh>& submeshes)
159 {
160  // --- NOTE: The following logic is arcane, I'm keeping it mostly like I found it for stability ~ only_a_ptr, 08/2017
161 
162  // Find the 'context' - a submesh (and respective span of vertices) which the vertex belong to.
163  int context;
164  int num_submeshes = static_cast<int>(submeshes.size());
165  for (context = 0; context < num_submeshes; ++context)
166  {
167  if (tidx < submeshes[context].cabs_pos)
168  {
169  --context;
170  break;
171  }
172  }
173 
174  // Find the vertex itself
175  int i_min = (context < 0) ? 0 : static_cast<int>(submeshes[context].texcoords_pos); // Fix for single-submesh case... It seems to have worked with a negative index until now ~ only_a_ptr, 08/2017
176  int i_max = static_cast<int>(submeshes[context + 1].texcoords_pos);
177  for (int i = i_min; i < i_max; ++i)
178  {
179  if (m_vertex_nodes[i] == v)
180  return i;
181  }
182 
183  return 0;
184 }
185 
187 {
188  RoR::NodeSB* all_nodes = m_gfx_actor->GetSimNodeBuffer();
189  Ogre::Vector3 center=(all_nodes[m_vertex_nodes[0]].AbsPosition+all_nodes[m_vertex_nodes[1]].AbsPosition)/2.0;
190  for (size_t i=0; i<m_vertex_count; i++)
191  {
192  //set position
193  m_vertices[i].position=all_nodes[m_vertex_nodes[i]].AbsPosition-center;
194  //reset normals
195  m_vertices[i].normal=Vector3::ZERO;
196  }
197  //accumulate normals per triangle
198  for (size_t i=0; i<m_index_count/3; i++)
199  {
200  Vector3 v1, v2;
201  v1=all_nodes[m_vertex_nodes[m_indices[i*3+1]]].AbsPosition-all_nodes[m_vertex_nodes[m_indices[i*3]]].AbsPosition;
202  v2=all_nodes[m_vertex_nodes[m_indices[i*3+2]]].AbsPosition-all_nodes[m_vertex_nodes[m_indices[i*3]]].AbsPosition;
203  v1=v1.crossProduct(v2);
204  float s=v1.length();
205 
206  //avoid large tris
207  if (s>m_s_ref[i])
208  {
209  m_vertices[m_indices[i*3+1]].position=m_vertices[m_indices[i*3]].position+Vector3(0.1,0,0);
210  m_vertices[m_indices[i*3+2]].position=m_vertices[m_indices[i*3]].position+Vector3(0,0,0.1);
211  }
212 
213  if (s == 0)
214  continue;
215 
216  v1=v1/s;
217  m_vertices[m_indices[i*3]].normal+=v1;
218  m_vertices[m_indices[i*3+1]].normal+=v1;
219  m_vertices[m_indices[i*3+2]].normal+=v1;
220  }
221  //normalize
222  for (size_t i=0; i<m_vertex_count; i++)
223  {
225  }
226 
227  return center;
228 }
229 
231 {
232  Ogre::Vector3 center = this->UpdateMesh();
233  m_hw_vbuf->writeData(0, m_hw_vbuf->getSizeInBytes(), m_vertices_raw, true);
234  return center;
235 }
236 
238 {
239  if (!m_mesh.isNull())
240  {
241  Ogre::MeshManager::getSingleton().remove(m_mesh->getHandle());
242  m_mesh.setNull();
243  }
244 
245  if (m_vertices_raw != nullptr) { free (m_vertices_raw); }
246  if (m_vertex_nodes != nullptr) { free (m_vertex_nodes); }
247  if (m_indices != nullptr) { free (m_indices); }
248  if (m_s_ref != nullptr) { free (m_s_ref); }
249 }
RoR::FlexObj::~FlexObj
~FlexObj()
Definition: FlexObj.cpp:237
RoR::NodeSB
Definition: SimBuffers.h:67
RoR::FlexObj::UpdateMesh
Ogre::Vector3 UpdateMesh()
Definition: FlexObj.cpp:186
RoR::GfxActor::GetSimNodeBuffer
NodeSB * GetSimNodeBuffer()
Definition: GfxActor.h:120
RoR::FlexObj::m_vertex_nodes
int * m_vertex_nodes
Definition: FlexObj.h:99
RoR::FlexObj::FlexObjVertex::texcoord
Ogre::Vector2 texcoord
Definition: FlexObj.h:86
RoR::FlexObj::m_indices
unsigned short * m_indices
Definition: FlexObj.h:109
RoR::FlexObj::FlexObjVertex::normal
Ogre::Vector3 normal
Definition: FlexObj.h:85
RoR::FlexObj::m_hw_vbuf
Ogre::HardwareVertexBufferSharedPtr m_hw_vbuf
Definition: FlexObj.h:101
RoR::FlexObj::m_vertices_raw
float * m_vertices_raw
Definition: FlexObj.h:104
RoR::node_t::RelPosition
Ogre::Vector3 RelPosition
relative to the local physics origin (one origin per actor) (shaky)
Definition: SimData.h:292
RoR::FlexObj::m_vertex_count
size_t m_vertex_count
Definition: FlexObj.h:98
RoR::FlexObj::m_vertices
FlexObjVertex * m_vertices
Definition: FlexObj.h:105
RoR::FlexObj::m_mesh
Ogre::MeshPtr m_mesh
Definition: FlexObj.h:93
RoR::FlexObj::m_submeshes
std::vector< Ogre::SubMesh * > m_submeshes
Definition: FlexObj.h:94
RoR::FlexObj::m_s_ref
float * m_s_ref
Definition: FlexObj.h:96
RoR::CabSubmesh::BACKMESH_OPAQUE
@ BACKMESH_OPAQUE
Definition: FlexObj.h:48
approx_normalise
Ogre::Vector3 approx_normalise(Ogre::Vector3 v)
Definition: ApproxMath.h:146
RoR::FlexObj::m_index_count
size_t m_index_count
Definition: FlexObj.h:108
RoR::node_t
Physics: A vertex in the softbody structure.
Definition: SimData.h:285
RoR::FlexObj::ComputeVertexPos
int ComputeVertexPos(int tidx, int v, std::vector< CabSubmesh > &submeshes)
Compute vertex position in the vertexbuffer (0-based offset) for node v of triangle tidx
Definition: FlexObj.cpp:158
ApproxMath.h
RoR::NodeSB::AbsPosition
Ogre::Vector3 AbsPosition
Definition: SimBuffers.h:69
RoR::CabSubmesh::BACKMESH_TRANSPARENT
@ BACKMESH_TRANSPARENT
Definition: FlexObj.h:48
RoR::FlexObj::ScaleFlexObj
void ScaleFlexObj(float factor)
Definition: FlexObj.cpp:149
RoR::FlexObj::FlexObjVertex::position
Ogre::Vector3 position
Definition: FlexObj.h:84
RoR::GfxActor
Definition: GfxActor.h:52
Ogre
Definition: ExtinguishableFireAffector.cpp:35
GfxActor.h
Manager for all visuals belonging to a single actor.
FlexObj.h
RoR::FlexObj::m_gfx_actor
RoR::GfxActor * m_gfx_actor
Definition: FlexObj.h:95
RoR::GfxActor::GetResourceGroup
Ogre::String GetResourceGroup()
Definition: GfxActor.h:139
RoR::FlexObj::m_triangle_count
int m_triangle_count
Definition: FlexObj.h:110
RoR
Definition: AppContext.h:36
RoR::FlexObj::UpdateFlexObj
Ogre::Vector3 UpdateFlexObj()
Definition: FlexObj.cpp:230
RoR::FlexObj::m_vertex_format
Ogre::VertexDeclaration * m_vertex_format
Definition: FlexObj.h:100