OpenClonk
StdMeshLoader::StdMeshXML Class Reference

Public Member Functions

 StdMeshXML (const char *filename, const char *xml_data)
 
const char * RequireStrAttribute (TiXmlElement *element, const char *attribute) const
 
int RequireIntAttribute (TiXmlElement *element, const char *attribute) const
 
float RequireFloatAttribute (TiXmlElement *element, const char *attribute) const
 
TiXmlElement * RequireFirstChild (TiXmlElement *element, const char *child)
 
void LoadGeometry (StdMesh &mesh, std::vector< StdSubMesh::Vertex > &vertices, TiXmlElement *boneassignments_elem)
 
void LoadBoneAssignments (StdMesh &mesh, std::vector< StdSubMesh::Vertex > &vertices, TiXmlElement *boneassignments_elem)
 
void Error (const StdStrBuf &message, TiXmlElement *element) const
 
void Error (const StdStrBuf &message, int row) const
 

Detailed Description

Definition at line 25 of file StdMeshLoaderXml.cpp.

Constructor & Destructor Documentation

◆ StdMeshXML()

StdMeshLoader::StdMeshXML::StdMeshXML ( const char *  filename,
const char *  xml_data 
)

Definition at line 47 of file StdMeshLoaderXml.cpp.

47  :
48  FileName(filename)
49 {
50  Document.Parse(xml_data);
51  if (Document.Error())
52  Error(StdStrBuf(Document.ErrorDesc()), Document.ErrorRow());
53 }
void Error(const StdStrBuf &message, TiXmlElement *element) const

References Error().

Here is the call graph for this function:

Member Function Documentation

◆ Error() [1/2]

void StdMeshLoader::StdMeshXML::Error ( const StdStrBuf message,
int  row 
) const

Definition at line 103 of file StdMeshLoaderXml.cpp.

104 {
105  throw StdMeshLoader::LoaderException(FormatString("%s:%u: %s", FileName.getData(), row, message.getData()).getData());
106 }
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
const char * getData() const
Definition: StdBuf.h:442

References FormatString(), and StdStrBuf::getData().

Here is the call graph for this function:

◆ Error() [2/2]

void StdMeshLoader::StdMeshXML::Error ( const StdStrBuf message,
TiXmlElement *  element 
) const

Definition at line 98 of file StdMeshLoaderXml.cpp.

99 {
100  Error(message, element->Row());
101 }

Referenced by StdMeshLoader::LoadMeshXml(), and StdMeshXML().

Here is the caller graph for this function:

◆ LoadBoneAssignments()

void StdMeshLoader::StdMeshXML::LoadBoneAssignments ( StdMesh mesh,
std::vector< StdSubMesh::Vertex > &  vertices,
TiXmlElement *  boneassignments_elem 
)

Definition at line 209 of file StdMeshLoaderXml.cpp.

210 {
211  for (TiXmlElement* vertexboneassignment_elem = boneassignments_elem->FirstChildElement("vertexboneassignment"); vertexboneassignment_elem != nullptr; vertexboneassignment_elem = vertexboneassignment_elem->NextSiblingElement("vertexboneassignment"))
212  {
213  int BoneID = RequireIntAttribute(vertexboneassignment_elem, "boneindex");
214  int VertexIndex = RequireIntAttribute(vertexboneassignment_elem, "vertexindex");
215  float weight = RequireFloatAttribute(vertexboneassignment_elem, "weight");
216 
217  if (VertexIndex < 0 || static_cast<unsigned int>(VertexIndex) >= vertices.size())
218  Error(FormatString("Vertex index in bone assignment (%d) is out of range", VertexIndex), vertexboneassignment_elem);
219 
220  // maybe not needed, see comment below
221  const StdMeshBone* bone = nullptr;
222  for (unsigned int i = 0; !bone && i < mesh.GetSkeleton().GetNumBones(); ++i)
223  if (mesh.GetSkeleton().GetBone(i).ID == BoneID)
224  bone = &mesh.GetSkeleton().GetBone(i);
225 
226  if (!bone) Error(FormatString("There is no such bone with ID %d", BoneID), vertexboneassignment_elem);
227 
228  // Find first bone assignment with a zero weight (i.e. is unused)
229  StdSubMesh::Vertex& vertex = vertices[VertexIndex];
230  // Check quickly if all weight slots are used
231  if (vertex.bone_weight[StdMeshVertex::MaxBoneWeightCount - 1] != 0)
232  {
233  Error(FormatString("Vertex %d is influenced by more than %d bones", VertexIndex, static_cast<int>(StdMeshVertex::MaxBoneWeightCount)), vertexboneassignment_elem);
234  }
235  for (size_t weight_index = 0; weight_index < StdMeshVertex::MaxBoneWeightCount; ++weight_index)
236  {
237  if (vertex.bone_weight[weight_index] == 0)
238  {
239  vertex.bone_weight[weight_index] = weight;
240  vertex.bone_index[weight_index] = bone->Index;
241  break;
242  }
243  }
244  }
245 
246  // Normalize vertex bone assignment weights (this is not guaranteed in the
247  // Ogre file format).
248  for (auto & vertex : vertices)
249  {
250  float sum = 0.0;
251  for (float weight : vertex.bone_weight)
252  sum += weight;
253  if (sum != 0)
254  for (float &weight : vertex.bone_weight)
255  weight /= sum;
256  else
257  vertex.bone_weight[0] = 1.0f;
258  }
259 }
unsigned int Index
Definition: StdMesh.h:32
int ID
Definition: StdMesh.h:33
const StdMeshSkeleton & GetSkeleton() const
Definition: StdMesh.h:203
int RequireIntAttribute(TiXmlElement *element, const char *attribute) const
float RequireFloatAttribute(TiXmlElement *element, const char *attribute) const
const StdMeshBone & GetBone(size_t i) const
Definition: StdMesh.h:116
uint16_t bone_index[MaxBoneWeightCount]
Definition: StdMeshMath.h:45
static const size_t MaxBoneWeightCount
Definition: StdMeshMath.h:37
float bone_weight[MaxBoneWeightCount]
Definition: StdMeshMath.h:44

Referenced by StdMeshLoader::LoadMeshXml().

Here is the caller graph for this function:

◆ LoadGeometry()

void StdMeshLoader::StdMeshXML::LoadGeometry ( StdMesh mesh,
std::vector< StdSubMesh::Vertex > &  vertices,
TiXmlElement *  boneassignments_elem 
)

Definition at line 108 of file StdMeshLoaderXml.cpp.

109 {
110  // Check whether mesh has any vertices so far -- we need this later for
111  // initialization of bounding box and bounding sphere.
112  bool hasVertices = false;
113  if(!mesh.SharedVertices.empty()) hasVertices = true;
114  for(auto & SubMesh : mesh.SubMeshes)
115  if(!SubMesh.Vertices.empty())
116  hasVertices = true;
117 
118  int VertexCount = RequireIntAttribute(geometry_elem, "vertexcount");
119  vertices.resize(VertexCount);
120 
121  static const unsigned int POSITIONS = 1;
122  static const unsigned int NORMALS = 2;
123  static const unsigned int TEXCOORDS = 4;
124 
125  // Individual vertex attributes can be split up in multiple vertex buffers
126  unsigned int loaded_attributes = 0;
127  for(TiXmlElement* buffer_elem = geometry_elem->FirstChildElement("vertexbuffer"); buffer_elem != nullptr; buffer_elem = buffer_elem->NextSiblingElement("vertexbuffer"))
128  {
129  unsigned int attributes = 0;
130  if(buffer_elem->Attribute("positions")) attributes |= POSITIONS;
131  if(buffer_elem->Attribute("normals")) attributes |= NORMALS;
132  if(buffer_elem->Attribute("texture_coords")) attributes |= TEXCOORDS;
133 
134  unsigned int i;
135  TiXmlElement* vertex_elem;
136  for (vertex_elem = buffer_elem->FirstChildElement("vertex"), i = 0; vertex_elem != nullptr && i < vertices.size(); vertex_elem = vertex_elem->NextSiblingElement("vertex"), ++i)
137  {
138  if(attributes & POSITIONS)
139  {
140  TiXmlElement* position_elem = RequireFirstChild(vertex_elem, "position");
141 
142  vertices[i].x = RequireFloatAttribute(position_elem, "x");
143  vertices[i].y = RequireFloatAttribute(position_elem, "y");
144  vertices[i].z = RequireFloatAttribute(position_elem, "z");
145  }
146 
147  if(attributes & NORMALS)
148  {
149  TiXmlElement* normal_elem = RequireFirstChild(vertex_elem, "normal");
150 
151  vertices[i].nx = RequireFloatAttribute(normal_elem, "x");
152  vertices[i].ny = RequireFloatAttribute(normal_elem, "y");
153  vertices[i].nz = RequireFloatAttribute(normal_elem, "z");
154  }
155 
156  if(attributes & TEXCOORDS)
157  {
158  // FIXME: The Ogre format supports denoting multiple texture coordinates, but the rendering code only supports one
159  // currently only the first set is read, any additional ones are ignored
160  TiXmlElement* texcoord_elem = RequireFirstChild(vertex_elem, "texcoord");
161  vertices[i].u = RequireFloatAttribute(texcoord_elem, "u");
162  vertices[i].v = RequireFloatAttribute(texcoord_elem, "v");
163  }
164 
165  vertices[i] = OgreToClonk::TransformVertex(vertices[i]);
166 
167  if (attributes & POSITIONS)
168  {
169  const float d = std::sqrt(vertices[i].x*vertices[i].x
170  + vertices[i].y*vertices[i].y
171  + vertices[i].z*vertices[i].z);
172 
173  // Construct BoundingBox
174  StdMeshBox& BoundingBox = mesh.BoundingBox;
175  if (i == 0 && !hasVertices)
176  {
177  // First vertex
178  BoundingBox.x1 = BoundingBox.x2 = vertices[i].x;
179  BoundingBox.y1 = BoundingBox.y2 = vertices[i].y;
180  BoundingBox.z1 = BoundingBox.z2 = vertices[i].z;
181  mesh.BoundingRadius = d;
182  }
183  else
184  {
185  BoundingBox.x1 = std::min(vertices[i].x, BoundingBox.x1);
186  BoundingBox.x2 = std::max(vertices[i].x, BoundingBox.x2);
187  BoundingBox.y1 = std::min(vertices[i].y, BoundingBox.y1);
188  BoundingBox.y2 = std::max(vertices[i].y, BoundingBox.y2);
189  BoundingBox.z1 = std::min(vertices[i].z, BoundingBox.z1);
190  BoundingBox.z2 = std::max(vertices[i].z, BoundingBox.z2);
191  mesh.BoundingRadius = std::max(mesh.BoundingRadius, d);
192  }
193  }
194  }
195 
196  if(vertex_elem != nullptr)
197  Error(FormatString("Too many vertices in vertexbuffer"), buffer_elem);
198  if(i < vertices.size())
199  Error(FormatString("Not enough vertices in vertexbuffer"), buffer_elem);
200 
201  loaded_attributes |= attributes;
202  }
203 
204  static const unsigned int REQUIRED_ATTRIBUTES = POSITIONS | NORMALS | TEXCOORDS;
205  if((loaded_attributes & REQUIRED_ATTRIBUTES) != REQUIRED_ATTRIBUTES)
206  Error(FormatString("Not all required vertex attributes (positions, normals, texcoords) present in mesh geometry"), geometry_elem);
207 }
#define z
TiXmlElement * RequireFirstChild(TiXmlElement *element, const char *child)
StdSubMesh::Vertex TransformVertex(const StdSubMesh::Vertex &vertex)
float y2
Definition: StdMesh.h:147
float z1
Definition: StdMesh.h:146
float z2
Definition: StdMesh.h:147
float x2
Definition: StdMesh.h:147
float y1
Definition: StdMesh.h:146
float x1
Definition: StdMesh.h:146

References OgreToClonk::TransformVertex(), StdMeshBox::x1, StdMeshBox::x2, StdMeshBox::y1, StdMeshBox::y2, z, StdMeshBox::z1, and StdMeshBox::z2.

Referenced by StdMeshLoader::LoadMeshXml().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ RequireFirstChild()

TiXmlElement * StdMeshLoader::StdMeshXML::RequireFirstChild ( TiXmlElement *  element,
const char *  child 
)

Definition at line 78 of file StdMeshLoaderXml.cpp.

79 {
80  TiXmlElement* retval;
81 
82  if (element)
83  {
84  retval = element->FirstChildElement(child);
85  if (!retval)
86  Error(FormatString("Element '%s' does not contain '%s' child", element->Value(), child), element);
87  }
88  else
89  {
90  retval = Document.RootElement();
91  if (strcmp(retval->Value(), child) != 0)
92  Error(FormatString("Root element is not '%s'", child), retval);
93  }
94 
95  return retval;
96 }

Referenced by StdMeshLoader::LoadMeshXml().

Here is the caller graph for this function:

◆ RequireFloatAttribute()

float StdMeshLoader::StdMeshXML::RequireFloatAttribute ( TiXmlElement *  element,
const char *  attribute 
) const

Definition at line 70 of file StdMeshLoaderXml.cpp.

71 {
72  float retval = 0;
73  if (element->QueryFloatAttribute(attribute, &retval) != TIXML_SUCCESS)
74  Error(FormatString("Element '%s' does not have floating point attribute '%s'", element->Value(), attribute), element);
75  return retval;
76 }

◆ RequireIntAttribute()

int StdMeshLoader::StdMeshXML::RequireIntAttribute ( TiXmlElement *  element,
const char *  attribute 
) const

Definition at line 62 of file StdMeshLoaderXml.cpp.

63 {
64  int retval;
65  if (element->QueryIntAttribute(attribute, &retval) != TIXML_SUCCESS)
66  Error(FormatString("Element '%s' does not have integer attribute '%s'", element->Value(), attribute), element);
67  return retval;
68 }

Referenced by StdMeshLoader::LoadMeshXml().

Here is the caller graph for this function:

◆ RequireStrAttribute()

const char * StdMeshLoader::StdMeshXML::RequireStrAttribute ( TiXmlElement *  element,
const char *  attribute 
) const

Definition at line 55 of file StdMeshLoaderXml.cpp.

56 {
57  const char* value = element->Attribute(attribute);
58  if (!value) Error(FormatString("Element '%s' does not have attribute '%s'", element->Value(), attribute), element);
59  return value;
60 }

Referenced by StdMeshLoader::LoadMeshXml().

Here is the caller graph for this function:

The documentation for this class was generated from the following file: