Panda3D
 All Classes Functions Variables Enumerations
xFileMaker.cxx
1 // Filename: xFileMaker.cxx
2 // Created by: drose (19Jun01)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "xFileMaker.h"
16 #include "xFileMesh.h"
17 #include "xFileMaterial.h"
18 #include "config_xfile.h"
19 
20 #include "pnotify.h"
21 #include "eggGroupNode.h"
22 #include "eggGroup.h"
23 #include "eggBin.h"
24 #include "eggPolysetMaker.h"
25 #include "eggVertexPool.h"
26 #include "eggVertex.h"
27 #include "eggPolygon.h"
28 #include "eggData.h"
29 #include "pvector.h"
30 #include "vector_int.h"
31 #include "string_utils.h"
32 #include "datagram.h"
33 
34 ////////////////////////////////////////////////////////////////////
35 // Function: XFileMaker::Constructor
36 // Access: Public
37 // Description:
38 ////////////////////////////////////////////////////////////////////
39 XFileMaker::
40 XFileMaker() {
41  _mesh_index = 0;
42  _x_file = new XFile;
43 }
44 
45 ////////////////////////////////////////////////////////////////////
46 // Function: XFileMaker::Destructor
47 // Access: Public
48 // Description:
49 ////////////////////////////////////////////////////////////////////
50 XFileMaker::
51 ~XFileMaker() {
52 }
53 
54 ////////////////////////////////////////////////////////////////////
55 // Function: XFileMaker::write
56 // Access: Public
57 // Description: Writes the .x file data to the indicated filename;
58 // returns true on success, false otherwise.
59 ////////////////////////////////////////////////////////////////////
60 bool XFileMaker::
61 write(const Filename &filename) {
62  return _x_file->write(filename);
63 }
64 
65 ////////////////////////////////////////////////////////////////////
66 // Function: XFileMaker::add_tree
67 // Access: Public
68 // Description: Adds the egg tree rooted at the indicated node to the
69 // X structure. This may be somewhat destructive of
70 // the egg tree. Returns true on success, false on
71 // failure.
72 ////////////////////////////////////////////////////////////////////
73 bool XFileMaker::
74 add_tree(EggData *egg_data) {
75  _meshes.clear();
76 
77  // Now collect all the polygons together into polysets.
78  EggPolysetMaker pmaker;
79  pmaker.make_bins(egg_data);
80 
81  // And now we're ready to traverse the egg hierarchy.
82  if (!recurse_nodes(egg_data, _x_file)) {
83  return false;
84  }
85 
86  // Create X structures for all of the meshes we built up.
87  Meshes::iterator mi;
88  for (mi = _meshes.begin(); mi != _meshes.end(); ++mi) {
89  if (!finalize_mesh((*mi).first, (*mi).second)) {
90  return false;
91  }
92  }
93  _meshes.clear();
94 
95  return true;
96 }
97 
98 ////////////////////////////////////////////////////////////////////
99 // Function: XFileMaker::add_node
100 // Access: Private
101 // Description: Adds the node to the DX structure, in whatever form
102 // it is supported.
103 ////////////////////////////////////////////////////////////////////
104 bool XFileMaker::
105 add_node(EggNode *egg_node, XFileNode *x_parent) {
106  if (egg_node->is_of_type(EggBin::get_class_type())) {
107  return add_bin(DCAST(EggBin, egg_node), x_parent);
108 
109  } else if (egg_node->is_of_type(EggGroup::get_class_type())) {
110  return add_group(DCAST(EggGroup, egg_node), x_parent);
111 
112  } else if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
113  // A grouping node of some kind.
114  EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
115 
116  if (xfile_one_mesh) {
117  // Don't create any additional frames representing the egg
118  // hierarchy.
119  if (!recurse_nodes(egg_group, x_parent)) {
120  return false;
121  }
122 
123  } else {
124  // Create a Frame for each EggGroup.
125  XFileDataNode *x_frame = x_parent->add_Frame(egg_group->get_name());
126 
127  if (!recurse_nodes(egg_group, x_frame)) {
128  return false;
129  }
130  }
131 
132  return true;
133  }
134 
135  // Some unsupported node type. Ignore it.
136  return true;
137 }
138 
139 ////////////////////////////////////////////////////////////////////
140 // Function: XFileMaker::add_group
141 // Access: Private
142 // Description: Adds a frame for the indicated group node.
143 ////////////////////////////////////////////////////////////////////
144 bool XFileMaker::
145 add_group(EggGroup *egg_group, XFileNode *x_parent) {
146  if (xfile_one_mesh) {
147  // Don't create any additional frames representing the egg
148  // hierarchy.
149  if (!recurse_nodes(egg_group, x_parent)) {
150  return false;
151  }
152 
153  } else {
154  // Create a frame for each EggGroup.
155  XFileDataNode *x_frame = x_parent->add_Frame(egg_group->get_name());
156 
157  // Set the transform on the frame, if we have one.
158  if (egg_group->has_transform()) {
159  x_frame->add_FrameTransformMatrix(egg_group->get_transform3d());
160  }
161 
162  if (!recurse_nodes(egg_group, x_frame)) {
163  return false;
164  }
165  }
166 
167  return true;
168 }
169 
170 ////////////////////////////////////////////////////////////////////
171 // Function: XFileMaker::add_bin
172 // Access: Private
173 // Description: Determines what kind of object needs to be added for
174 // the indicated bin node.
175 ////////////////////////////////////////////////////////////////////
176 bool XFileMaker::
177 add_bin(EggBin *egg_bin, XFileNode *x_parent) {
178  switch (egg_bin->get_bin_number()) {
179  case EggPolysetMaker::BN_polyset:
180  return add_polyset(egg_bin, x_parent);
181  }
182 
183  xfile_cat.error()
184  << "Unexpected bin type " << egg_bin->get_bin_number() << "\n";
185  return false;
186 }
187 
188 ////////////////////////////////////////////////////////////////////
189 // Function: XFileMaker::add_polyset
190 // Access: Private
191 // Description: Adds a mesh object corresponding to the collection of
192 // polygons within the indicated bin.
193 ////////////////////////////////////////////////////////////////////
194 bool XFileMaker::
195 add_polyset(EggBin *egg_bin, XFileNode *x_parent) {
196  // Make sure that all our polygons are reasonable.
197  egg_bin->remove_invalid_primitives(true);
198 
199  XFileMesh *mesh = get_mesh(x_parent);
200 
201  EggGroupNode::iterator ci;
202  for (ci = egg_bin->begin(); ci != egg_bin->end(); ++ci) {
203  EggPolygon *poly;
204  DCAST_INTO_R(poly, *ci, false);
205 
206  mesh->add_polygon(poly);
207  }
208 
209  return true;
210 }
211 
212 
213 ////////////////////////////////////////////////////////////////////
214 // Function: XFileMaker::recurse_nodes
215 // Access: Private
216 // Description: Adds each child of the indicated Node as a child of
217 // the indicated DX object.
218 ////////////////////////////////////////////////////////////////////
219 bool XFileMaker::
220 recurse_nodes(EggGroupNode *egg_node, XFileNode *x_parent) {
221  EggGroupNode::iterator ci;
222  for (ci = egg_node->begin(); ci != egg_node->end(); ++ci) {
223  EggNode *child = (*ci);
224  if (!add_node(child, x_parent)) {
225  return false;
226  }
227  }
228 
229  return true;
230 }
231 
232 ////////////////////////////////////////////////////////////////////
233 // Function: XFileMaker::get_mesh
234 // Access: Private
235 // Description: Returns a suitable XFileMesh object for creating
236 // meshes within the indicated x_parent object.
237 ////////////////////////////////////////////////////////////////////
238 XFileMesh *XFileMaker::
239 get_mesh(XFileNode *x_parent) {
240  Meshes::iterator mi = _meshes.find(x_parent);
241  if (mi != _meshes.end()) {
242  // We've already started working on this x_parent before; use the
243  // same mesh object.
244  return (*mi).second;
245  }
246 
247  // We haven't seen this x_parent before; create a new mesh object.
248  XFileMesh *mesh = new XFileMesh;
249  _meshes.insert(Meshes::value_type(x_parent, mesh));
250  return mesh;
251 }
252 
253 
254 ////////////////////////////////////////////////////////////////////
255 // Function: XFileMaker::finalize_mesh
256 // Access: Private
257 // Description: Creates the actual X structures corresponding to
258 // the indicated XFileMesh object.
259 ////////////////////////////////////////////////////////////////////
260 bool XFileMaker::
261 finalize_mesh(XFileNode *x_parent, XFileMesh *mesh) {
262  // Get a unique number for each mesh.
263  _mesh_index++;
264  string mesh_index = format_string(_mesh_index);
265 
266  // Finally, create the Mesh object.
267  mesh->make_x_mesh(x_parent, mesh_index);
268 
269  return true;
270 }
const LMatrix4d & get_transform3d() const
Returns the overall transform as a 4x4 matrix.
Definition: eggTransform.I:251
This is a collection of polygons; i.e.
Definition: xFileMesh.h:45
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:51
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
This is the primary interface into all the egg data, and the root of the egg file structure...
Definition: eggData.h:41
bool add_tree(EggData *egg_data)
Adds the egg tree rooted at the indicated node to the X structure.
Definition: xFileMaker.cxx:74
void add_polygon(EggPolygon *egg_poly)
Adds the indicated polygon to the mesh.
Definition: xFileMesh.cxx:101
The main glue of the egg hierarchy, this corresponds to the &lt;Group&gt;, &lt;Instance&gt;, and &lt;Joint&gt; type nod...
Definition: eggGroup.h:36
A single node of an X file.
Definition: xFileNode.h:42
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
int remove_invalid_primitives(bool recurse)
Removes primitives at this level and below which appear to be degenerate; e.g.
XFileDataNode * add_Frame(const string &name)
Creates a new Frame instance, as a child of this node.
Definition: xFileNode.cxx:499
XFileDataNode * add_FrameTransformMatrix(const LMatrix4d &mat)
Creates a new FrameTransformMatrix instance, as a child of this node.
Definition: xFileNode.cxx:517
bool has_transform() const
Returns true if the transform is nonempty, false if it is empty (no transform components have been ad...
Definition: eggTransform.I:163
A single polygon.
Definition: eggPolygon.h:26
XFileDataNode * make_x_mesh(XFileNode *x_parent, const string &suffix)
Creates an X structure corresponding to the mesh.
Definition: xFileMesh.cxx:493
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:38
This is an abstract base class for an XFileNode which is also an XFileDataObject. ...
Definition: xFileDataNode.h:36
int make_bins(EggGroupNode *root_group)
The main entry point to EggBinMaker.
Definition: eggBinMaker.cxx:77
A specialization on EggBinMaker for making polysets that share the same basic rendering characteristi...
This represents the complete contents of an X file (file.x) in memory.
Definition: xFile.h:35
bool write(const Filename &filename)
Writes the .x file data to the indicated filename; returns true on success, false otherwise...
Definition: xFileMaker.cxx:61
A type of group node that holds related subnodes.
Definition: eggBin.h:30