RigsofRods
Soft-body Physics Simulation
FlexMesh.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 "FlexMesh.h"
23 
24 #include <Ogre.h>
25 
26 #include "ApproxMath.h"
27 #include "SimData.h"
28 #include "GfxActor.h"
29 
30 using namespace Ogre;
31 using namespace RoR;
32 
33 FlexMesh::FlexMesh(
34  Ogre::String const & name,
35  RoR::GfxActor* gfx_actor,
36  NodeNum_t n1,
37  NodeNum_t n2,
38  NodeNum_t nstart,
39  int nrays,
40  Ogre::String const& face_material_name,
41  Ogre::String const& face_material_rg,
42  Ogre::String const& band_material_name,
43  Ogre::String const& band_material_rg,
44  bool rimmed,
45  float rim_ratio
46 ) :
47  m_is_rimmed(rimmed)
48  , m_num_rays(nrays)
49  , m_gfx_actor(gfx_actor)
50 {
51  // Create the mesh via the MeshManager
52  m_mesh = MeshManager::getSingleton().createManual(name, gfx_actor->GetResourceGroup());
53 
54  // Create submeshes
55  m_submesh_wheelface = m_mesh->createSubMesh();
56  m_submesh_tiretread = m_mesh->createSubMesh();
57 
58  //materials
59  m_submesh_wheelface->setMaterialName(face_material_name, face_material_rg);
60  m_submesh_tiretread->setMaterialName(band_material_name, band_material_rg);
61 
62  // Define the vertices
63  size_t vertex_count = 4*nrays+2; // each ray needs 4 verts (2 for sidewalls and 2 for band). The axis needs an extra 2.
64  if (m_is_rimmed) // For truckfile sections "[mesh]wheels2".
65  {
66  vertex_count+=2*nrays; // 1 extra vertex for each sidewall.
67  }
68  m_vertices.resize(vertex_count);
69  m_vertex_nodes.resize(vertex_count, NODENUM_INVALID);
70 
71  //define node ids
72  m_vertex_nodes[0]=n1;
73  m_vertex_nodes[1]=n2;
74  int i;
75  for (i=0; i<nrays; i++)
76  {
77  //face
78  m_vertex_nodes[2+i*2]=nstart+i*2;
79  m_vertex_nodes[2+i*2+1]=nstart+i*2+1;
80  if (m_is_rimmed)
81  {
82  //band
83  m_vertex_nodes[2+2*nrays+i*2] = nstart+2*nrays+i*2;
84  m_vertex_nodes[2+2*nrays+i*2+1] = nstart+2*nrays+i*2+1;
85  //face2 (outer)
86  m_vertex_nodes[2+4*nrays+i*2] = nstart+2*nrays+i*2;
87  m_vertex_nodes[2+4*nrays+i*2+1] = nstart+2*nrays+i*2+1;
88  } else
89  {
90  //band
91  m_vertex_nodes[2+2*nrays+i*2] = nstart+i*2;
92  m_vertex_nodes[2+2*nrays+i*2+1] = nstart+i*2+1;
93  }
94  }
95 
96  //textures coordinates
97  m_vertices[0].texcoord=Vector2(0.5, 0.5); // Axis vertices - texcoord is middle of the wheelface texture.
98  m_vertices[1].texcoord=Vector2(0.5, 0.5);
99  const bool odd_num_rays = (nrays % 2 == 0);
100  for (i=0; i<nrays; i++)
101  {
102  //band
103  int band_vert = 2+2*nrays+i*2;
104  if (i % 2 == 0) // Even index
105  {
106  if (odd_num_rays && ((i+1) == nrays))
107  {
108  // Finalize a wheel with odd number of rays like 'bombinette.load' in 'miniredmars' map.
109  m_vertices[band_vert].texcoord=Vector2(0.5, 0.0); // Stretch the texture over 2 quads instead of 1... ugly, but best we can do here
110  m_vertices[band_vert+1].texcoord=Vector2(0.5, 1.0);
111  }
112  else
113  {
114  m_vertices[band_vert].texcoord=Vector2(0.0, 0.0);
115  m_vertices[band_vert+1].texcoord=Vector2(0.0, 1.0);
116  }
117  }
118  else // Odd index
119  {
120  m_vertices[band_vert].texcoord=Vector2(1.0, 0.0);
121  m_vertices[band_vert+1].texcoord=Vector2(1.0, 1.0);
122  }
123 
124  //face
125  if (m_is_rimmed)
126  {
127  m_vertices[2+i*2].texcoord=Vector2(0.5+0.5*rim_ratio*sin((float)i*2.0*3.14159/nrays), 0.5+0.5*rim_ratio*cos((float)i*2.0*3.14159/nrays));
128  m_vertices[2+i*2+1].texcoord=m_vertices[2+i*2].texcoord;
129  m_vertices[2+4*nrays+i*2].texcoord=Vector2(0.5+0.5*sin(((float)i+0.5)*2.0*3.14159/nrays), 0.5+0.5*cos(((float)i+0.5)*2.0*3.14159/nrays));
130  m_vertices[2+4*nrays+i*2+1].texcoord=m_vertices[2+4*nrays+i*2].texcoord;
131  } else
132  {
133  m_vertices[2+i*2].texcoord=Vector2(0.5+0.5*sin(i*2.0*3.14159/nrays), 0.5+0.5*cos(i*2.0*3.14159/nrays));
134  m_vertices[2+i*2+1].texcoord=m_vertices[2+i*2].texcoord;
135  }
136  }
137 
138  // Define triangles
139  // The values in this table refer to vertices in the above table
140  size_t tiretread_num_indices = 3*2*nrays;
141  size_t wheelface_num_indices = 3*2*nrays;
142  if (m_is_rimmed) wheelface_num_indices=wheelface_num_indices*3;
143  m_wheelface_indices.resize(wheelface_num_indices, 0);
144  m_tiretread_indices.resize(tiretread_num_indices, 0);
145  for (i=0; i<nrays; i++)
146  {
147  //wheel sides
148  m_wheelface_indices[3*(i*2)]=0; m_wheelface_indices[3*(i*2)+1]=2+i*2; m_wheelface_indices[3*(i*2)+2]=2+((i+1)%nrays)*2;
149  m_wheelface_indices[3*(i*2+1)]=1; m_wheelface_indices[3*(i*2+1)+2]=2+i*2+1; m_wheelface_indices[3*(i*2+1)+1]=2+((i+1)%nrays)*2+1;
150  if (m_is_rimmed)
151  {
152  m_wheelface_indices[3*(i*4+0+2*nrays)]=2+i*2; m_wheelface_indices[3*(i*4+0+2*nrays)+1]=2+4*nrays+i*2; m_wheelface_indices[3*(i*4+0+2*nrays)+2]=2+((i+1)%nrays)*2;
153  m_wheelface_indices[3*(i*4+1+2*nrays)]=2+4*nrays+i*2; m_wheelface_indices[3*(i*4+1+2*nrays)+1]=2+4*nrays+((i+1)%nrays)*2; m_wheelface_indices[3*(i*4+1+2*nrays)+2]=2+((i+1)%nrays)*2;
154  m_wheelface_indices[3*(i*4+2+2*nrays)]=2+i*2+1; m_wheelface_indices[3*(i*4+2+2*nrays)+2]=2+4*nrays+i*2+1; m_wheelface_indices[3*(i*4+2+2*nrays)+1]=2+((i+1)%nrays)*2+1;
155  m_wheelface_indices[3*(i*4+3+2*nrays)]=2+4*nrays+i*2+1; m_wheelface_indices[3*(i*4+3+2*nrays)+2]=2+4*nrays+((i+1)%nrays)*2+1; m_wheelface_indices[3*(i*4+3+2*nrays)+1]=2+((i+1)%nrays)*2+1;
156  }
157  //wheel band
158  m_tiretread_indices[3*(i*2)]=2+2*nrays+i*2; m_tiretread_indices[3*(i*2)+1]=2+2*nrays+i*2+1; m_tiretread_indices[3*(i*2)+2]=2+2*nrays+((i+1)%nrays)*2;
159  m_tiretread_indices[3*(i*2+1)]=2+2*nrays+((i+1)%nrays)*2; m_tiretread_indices[3*(i*2+1)+2]=2+2*nrays+((i+1)%nrays)*2+1; m_tiretread_indices[3*(i*2+1)+1]=2+2*nrays+i*2+1;
160  }
161 
162  //update coords
163  updateVertices();
164 
165  // Create vertex data structure for 8 vertices shared between submeshes
166  m_mesh->sharedVertexData = new VertexData();
167  m_mesh->sharedVertexData->vertexCount = vertex_count;
168 
169  // Create declaration (memory format) of vertex data
170  m_vertex_format = m_mesh->sharedVertexData->vertexDeclaration;
171  size_t offset = 0;
172  m_vertex_format->addElement(0, offset, VET_FLOAT3, VES_POSITION);
173  offset += VertexElement::getTypeSize(VET_FLOAT3);
174  m_vertex_format->addElement(0, offset, VET_FLOAT3, VES_NORMAL);
175  offset += VertexElement::getTypeSize(VET_FLOAT3);
176 // m_vertex_format->addElement(0, offset, VET_FLOAT3, VES_DIFFUSE);
177 // offset += VertexElement::getTypeSize(VET_FLOAT3);
178  m_vertex_format->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
179  offset += VertexElement::getTypeSize(VET_FLOAT2);
180 
181  // Allocate vertex buffer of the requested number of vertices (vertexCount)
182  // and bytes per vertex (offset)
183  m_hw_vbuf =
184  HardwareBufferManager::getSingleton().createVertexBuffer(
185  offset, m_mesh->sharedVertexData->vertexCount, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
186 
187  // Upload the vertex data to the card
188  m_hw_vbuf->writeData(0, m_hw_vbuf->getSizeInBytes(), m_vertices.data(), true);
189 
190  // Set vertex buffer binding so buffer 0 is bound to our vertex buffer
191  VertexBufferBinding* bind = m_mesh->sharedVertexData->vertexBufferBinding;
192  bind->setBinding(0, m_hw_vbuf);
193 
194  //for the sideface
195  // Allocate index buffer of the requested number of vertices (ibufCount)
196  HardwareIndexBufferSharedPtr faceibuf = HardwareBufferManager::getSingleton().
197  createIndexBuffer(
198  HardwareIndexBuffer::IT_16BIT,
199  wheelface_num_indices,
200  HardwareBuffer::HBU_STATIC_WRITE_ONLY);
201 
202  // Upload the index data to the card
203  faceibuf->writeData(0, faceibuf->getSizeInBytes(), m_wheelface_indices.data(), true);
204 
205  // Set parameters of the submesh
206  m_submesh_wheelface->useSharedVertices = true;
207  m_submesh_wheelface->indexData->indexBuffer = faceibuf;
208  m_submesh_wheelface->indexData->indexCount = wheelface_num_indices;
209  m_submesh_wheelface->indexData->indexStart = 0;
210 
211  //for the band
212  // Allocate index buffer of the requested number of vertices (ibufCount)
213  HardwareIndexBufferSharedPtr bandibuf = HardwareBufferManager::getSingleton().
214  createIndexBuffer(
215  HardwareIndexBuffer::IT_16BIT,
216  tiretread_num_indices,
217  HardwareBuffer::HBU_STATIC_WRITE_ONLY);
218 
219  // Upload the index data to the card
220  bandibuf->writeData(0, bandibuf->getSizeInBytes(), m_tiretread_indices.data(), true);
221 
222  // Set parameters of the submesh
223  m_submesh_tiretread->useSharedVertices = true;
224  m_submesh_tiretread->indexData->indexBuffer = bandibuf;
225  m_submesh_tiretread->indexData->indexCount = tiretread_num_indices;
226  m_submesh_tiretread->indexData->indexStart = 0;
227 
228  // Set bounding information (for culling)
229  m_mesh->_setBounds(AxisAlignedBox(-1,-1,0,1,1,0), true);
230 
231  m_mesh->load();
232 }
233 
235 {
236  if (!m_mesh.isNull())
237  {
238  Ogre::MeshManager::getSingleton().remove(m_mesh->getName());
239  m_mesh.setNull();
240  }
241 }
242 
244 {
245  RoR::NodeSB* all_nodes = m_gfx_actor->GetSimNodeBuffer();
246  Vector3 center = (all_nodes[m_vertex_nodes[0]].AbsPosition + all_nodes[m_vertex_nodes[1]].AbsPosition) / 2.0;
247 
248  //optimization possible here : just copy bands on face
249 
250  m_vertices[0].position=all_nodes[m_vertex_nodes[0]].AbsPosition-center;
251  //normals
252  m_vertices[0].normal=approx_normalise(all_nodes[m_vertex_nodes[0]].AbsPosition-all_nodes[m_vertex_nodes[1]].AbsPosition);
253 
254  m_vertices[1].position=all_nodes[m_vertex_nodes[1]].AbsPosition-center;
255  //normals
256  m_vertices[1].normal=-m_vertices[0].normal;
257 
258  for (int i=0; i<m_num_rays*2; i++)
259  {
260  m_vertices[2+i].position=all_nodes[m_vertex_nodes[2+i]].AbsPosition-center;
261  //normals
262  if ((i%2)==0)
263  {
264  m_vertices[2+i].normal=approx_normalise(all_nodes[m_vertex_nodes[0]].AbsPosition-all_nodes[m_vertex_nodes[1]].AbsPosition);
265  } else
266  {
267  m_vertices[2+i].normal=-m_vertices[2+i-1].normal;
268  }
269  if (m_is_rimmed)
270  {
271  m_vertices[2+4*m_num_rays+i].position=all_nodes[m_vertex_nodes[2+4*m_num_rays+i]].AbsPosition-center;
272  //normals
273  if ((i%2)==0)
274  {
275  m_vertices[2+4*m_num_rays+i].normal=approx_normalise(all_nodes[m_vertex_nodes[2+4*m_num_rays+i]].AbsPosition-all_nodes[m_vertex_nodes[2+4*m_num_rays+i+1]].AbsPosition);
276  } else
277  {
278  m_vertices[2+4*m_num_rays+i].normal=-m_vertices[2+4*m_num_rays+i-1].normal;
279  }
280  //bands
281  m_vertices[2+2*m_num_rays+i].position=m_vertices[2+4*m_num_rays+i].position;
282  m_vertices[2+2*m_num_rays+i].normal=approx_normalise(m_vertices[2+4*m_num_rays+i].position);
283  } else
284  {
285  //bands
286  m_vertices[2+2*m_num_rays+i].position=m_vertices[2+i].position;
287  m_vertices[2+2*m_num_rays+i].normal=approx_normalise(m_vertices[2+i].position);
288  }
289  }
290  return center;
291 }
292 
294 {
296 }
297 
299 {
300  m_hw_vbuf->writeData(0, m_hw_vbuf->getSizeInBytes(), m_vertices.data(), true);
301  return m_flexit_center;
302 }
RoR::FlexMesh::m_num_rays
int m_num_rays
Definition: FlexMesh.h:86
RoR::NodeSB
Definition: SimBuffers.h:67
RoR::FlexMesh::m_submesh_wheelface
Ogre::SubMesh * m_submesh_wheelface
Definition: FlexMesh.h:91
RoR::FlexMesh::m_is_rimmed
bool m_is_rimmed
Definition: FlexMesh.h:87
RoR::GfxActor::GetSimNodeBuffer
NodeSB * GetSimNodeBuffer()
Definition: GfxActor.h:120
RoR::NODENUM_INVALID
static const NodeNum_t NODENUM_INVALID
Definition: ForwardDeclarations.h:53
RoR::FlexMesh::m_vertices
std::vector< FlexMeshVertex > m_vertices
Definition: FlexMesh.h:97
RoR::FlexMesh::m_submesh_tiretread
Ogre::SubMesh * m_submesh_tiretread
Definition: FlexMesh.h:92
RoR::FlexMesh::flexitCompute
void flexitCompute()
Definition: FlexMesh.cpp:293
RoR::FlexMesh::m_wheelface_indices
std::vector< uint16_t > m_wheelface_indices
Definition: FlexMesh.h:101
RoR::FlexMesh::updateVertices
Ogre::Vector3 updateVertices()
Definition: FlexMesh.cpp:243
RoR::FlexMesh::flexitFinal
Ogre::Vector3 flexitFinal()
Definition: FlexMesh.cpp:298
RoR::FlexMesh::m_vertex_nodes
std::vector< NodeNum_t > m_vertex_nodes
Definition: FlexMesh.h:98
RoR::NodeNum_t
uint16_t NodeNum_t
Node position within Actor::ar_nodes; use RoR::NODENUM_INVALID as empty value.
Definition: ForwardDeclarations.h:52
SimData.h
Core data structures for simulation; Everything affected by by either physics, network or user intera...
RoR::FlexMesh::~FlexMesh
~FlexMesh()
Definition: FlexMesh.cpp:234
approx_normalise
Ogre::Vector3 approx_normalise(Ogre::Vector3 v)
Definition: ApproxMath.h:146
RoR::FlexMesh::m_vertex_format
Ogre::VertexDeclaration * m_vertex_format
Definition: FlexMesh.h:93
FlexMesh.h
ApproxMath.h
RoR::NodeSB::AbsPosition
Ogre::Vector3 AbsPosition
Definition: SimBuffers.h:69
RoR::FlexMesh::m_hw_vbuf
Ogre::HardwareVertexBufferSharedPtr m_hw_vbuf
Definition: FlexMesh.h:94
RoR::FlexMesh::m_gfx_actor
RoR::GfxActor * m_gfx_actor
Definition: FlexMesh.h:85
RoR::GfxActor
Definition: GfxActor.h:52
Ogre
Definition: ExtinguishableFireAffector.cpp:35
GfxActor.h
Manager for all visuals belonging to a single actor.
RoR::FlexMesh::m_tiretread_indices
std::vector< uint16_t > m_tiretread_indices
Definition: FlexMesh.h:102
RoR::GfxActor::GetResourceGroup
Ogre::String GetResourceGroup()
Definition: GfxActor.h:139
RoR
Definition: AppContext.h:36
RoR::FlexMesh::m_flexit_center
Ogre::Vector3 m_flexit_center
Definition: FlexMesh.h:84
RoR::FlexMesh::m_mesh
Ogre::MeshPtr m_mesh
Definition: FlexMesh.h:90