Panda3D
cLwoPolygons.cxx
1 // Filename: cLwoPolygons.cxx
2 // Created by: drose (25Apr01)
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 "cLwoPolygons.h"
16 #include "lwoToEggConverter.h"
17 #include "cLwoPoints.h"
18 #include "cLwoLayer.h"
19 #include "cLwoSurface.h"
20 
21 #include "lwoPolygonTags.h"
22 #include "lwoTags.h"
23 #include "lwoDiscontinuousVertexMap.h"
24 #include "eggData.h"
25 #include "eggPolygon.h"
26 #include "eggPoint.h"
27 #include "deg_2_rad.h"
28 
29 ////////////////////////////////////////////////////////////////////
30 // Function: CLwoPolygons::add_ptags
31 // Access: Public
32 // Description: Associates the indicated PolygonTags and Tags with
33 // the polygons in this chunk. This may define features
34 // such as per-polygon surfaces, parts, and smoothing
35 // groups.
36 ////////////////////////////////////////////////////////////////////
37 void CLwoPolygons::
38 add_ptags(const LwoPolygonTags *lwo_ptags, const LwoTags *tags) {
39  if (_tags != (LwoTags *)NULL && _tags != tags) {
40  nout << "Multiple Tags fields in effect on the same polygons.\n";
41  }
42  _tags = tags;
43 
44  IffId type = lwo_ptags->_tag_type;
45 
46  bool inserted = _ptags.insert(PTags::value_type(type, lwo_ptags)).second;
47  if (!inserted) {
48  nout << "Multiple polygon tags on the same polygons of type "
49  << type << "\n";
50 
51  } else {
52  if (type == IffId("SURF")) {
53  _surf_ptags = lwo_ptags;
54  }
55  }
56 }
57 
58 ////////////////////////////////////////////////////////////////////
59 // Function: CLwoPolygons::add_vmad
60 // Access: Public
61 // Description: Associates the indicated DiscontinousVertexMap with
62 // the polygons. This can be used in conjunction with
63 // (or in place of) the VertexMap associated with the
64 // points set, to define per-polygon UV's etc.
65 ////////////////////////////////////////////////////////////////////
66 void CLwoPolygons::
68  IffId map_type = lwo_vmad->_map_type;
69  const string &name = lwo_vmad->_name;
70 
71  bool inserted;
72  if (map_type == IffId("TXUV")) {
73  inserted =
74  _txuv.insert(VMad::value_type(name, lwo_vmad)).second;
75 
76  } else {
77  return;
78  }
79 
80  if (!inserted) {
81  nout << "Multiple discontinous vertex maps on the same polygons of type "
82  << map_type << " named " << name << "\n";
83  }
84 }
85 
86 ////////////////////////////////////////////////////////////////////
87 // Function: CLwoPolygons::get_surface
88 // Access: Public
89 // Description: Returns the surface associated with the given
90 // polygon, or NULL if no surface is associated.
91 ////////////////////////////////////////////////////////////////////
93 get_surface(int polygon_index) const {
94  if (_surf_ptags == (LwoPolygonTags *)NULL) {
95  // No surface definitions.
96  return (CLwoSurface *)NULL;
97  }
98 
99  if (!_surf_ptags->has_tag(polygon_index)) {
100  // The polygon isn't tagged.
101  return (CLwoSurface *)NULL;
102  }
103 
104  int tag_index = _surf_ptags->get_tag(polygon_index);
105  if (_tags == (LwoTags *)NULL || tag_index < 0 ||
106  tag_index >= _tags->get_num_tags()) {
107  // The tag index is out-of-bounds.
108  nout << "Invalid polygon tag index " << tag_index << "\n";
109  return (CLwoSurface *)NULL;
110  }
111 
112  string tag = _tags->get_tag(tag_index);
113 
114  // Now look up the surface name in the header.
115  CLwoSurface *surface = _converter->get_surface(tag);
116  if (surface == (CLwoSurface *)NULL) {
117  nout << "Unknown surface " << tag << "\n";
118  return (CLwoSurface *)NULL;
119  }
120 
121  return surface;
122 }
123 
124 ////////////////////////////////////////////////////////////////////
125 // Function: CLwoPolygons::get_uv
126 // Access: Public
127 // Description: Returns true if there is a UV of the indicated name
128 // associated with the given vertex of the indicated
129 // polygon, false otherwise. If true, fills in uv with
130 // the value.
131 //
132 // This performs a lookup in the optional
133 // "discontinuous" vertex mapping, which provides the
134 // ability to map different UV's per each polygon for
135 // the same vertex. If the UV is not defined here, it
136 // may also be defined in the standard vertex map, which
137 // is associated with the points themselves.
138 ////////////////////////////////////////////////////////////////////
139 bool CLwoPolygons::
140 get_uv(const string &uv_name, int pi, int vi, LPoint2 &uv) const {
141  VMad::const_iterator ni = _txuv.find(uv_name);
142  if (ni == _txuv.end()) {
143  return false;
144  }
145 
146  const LwoDiscontinuousVertexMap *vmad = (*ni).second;
147  if (vmad->_dimension != 2) {
148  nout << "Unexpected dimension of " << vmad->_dimension
149  << " for discontinuous UV map " << uv_name << "\n";
150  return false;
151  }
152 
153  if (!vmad->has_value(pi, vi)) {
154  return false;
155  }
156 
157  PTA_stdfloat value = vmad->get_value(pi, vi);
158 
159  uv.set(value[0], value[1]);
160  return true;
161 }
162 
163 ////////////////////////////////////////////////////////////////////
164 // Function: CLwoPolygons::make_egg
165 // Access: Public
166 // Description: Creates the egg structures associated with this
167 // Lightwave object.
168 ////////////////////////////////////////////////////////////////////
169 void CLwoPolygons::
171  // First, we need a temporary group to hold all of the polygons
172  // we'll create.
173  _egg_group = new EggGroup;
174 
175  if (_polygons->_polygon_type == IffId("CURV")) {
176  nout << "Ignoring Catmull-Rom splines.\n";
177 
178  } else if (_polygons->_polygon_type == IffId("PTCH")) {
179  nout << "Treating subdivision patches as ordinary polygons.\n";
180  make_faces();
181 
182  } else if (_polygons->_polygon_type == IffId("MBAL")) {
183  nout << "Ignoring metaballs.\n";
184 
185  } else if (_polygons->_polygon_type == IffId("BONE")) {
186  nout << "Ignoring bones.\n";
187 
188  } else if (_polygons->_polygon_type == IffId("FACE")) {
189  make_faces();
190 
191  } else {
192  nout << "Ignoring unknown geometry type " << _polygons->_polygon_type
193  << ".\n";
194  }
195 }
196 
197 ////////////////////////////////////////////////////////////////////
198 // Function: CLwoPolygons::connect_egg
199 // Access: Public
200 // Description: Connects all the egg structures together.
201 ////////////////////////////////////////////////////////////////////
202 void CLwoPolygons::
204  nassertv(_points->_layer->_egg_group != (EggGroup *)NULL);
205  nassertv(_egg_group != (EggGroup *)NULL);
206  _points->_layer->_egg_group->steal_children(*_egg_group);
207 }
208 
209 
210 ////////////////////////////////////////////////////////////////////
211 // Function: CLwoPolygons::make_faces
212 // Access: Public
213 // Description: Generates "face" polygons, i.e. actual polygons.
214 ////////////////////////////////////////////////////////////////////
215 void CLwoPolygons::
216 make_faces() {
217  PN_stdfloat smooth_angle = -1.0;
218 
219  int num_polygons = _polygons->get_num_polygons();
220  for (int pindex = 0; pindex < num_polygons; pindex++) {
221  LwoPolygons::Polygon *poly = _polygons->get_polygon(pindex);
222  CLwoSurface *surface = get_surface(pindex);
223 
224  bool is_valid = true;
225 
226  // Set up the vertices.
227  const LwoPoints *points = _points->_points;
228  int num_points = points->get_num_points();
229  EggVertexPool *egg_vpool = _points->_egg_vpool;
230 
231  // We reverse the vertex ordering to compensate for Lightwave's
232  // clockwise ordering convention. We also want to start with the
233  // last vertex, so that the first convex angle is the first angle
234  // in the EggPolygon (for determining correct normals).
235  PT(EggPrimitive) egg_prim;
236 
237  if (poly->_vertices.size() == 1) {
238  egg_prim = new EggPoint;
239  } else {
240  egg_prim = new EggPolygon;
241  }
242 
243  // First, we have to create a temporary vector of vertices for the
244  // polygon, so we can possibly adjust the properties of these
245  // vertices (like the UV's) in the shader before we create them.
246  vector_PT_EggVertex egg_vertices;
247 
248  int num_vertices = poly->_vertices.size();
249  for (int vi = num_vertices; vi > 0; vi--) {
250  int vindex = poly->_vertices[vi % num_vertices];
251  if (vindex < 0 || vindex >= num_points) {
252  nout << "Invalid vertex index " << vindex << " in polygon.\n";
253  is_valid = false;
254  } else {
255  PT(EggVertex) egg_vertex = new EggVertex;
256  LPoint3d pos = LCAST(double, points->get_point(vindex));
257  egg_vertex->set_pos(pos);
258 
259  // Does the vertex used named UV's?
260  if (surface != (CLwoSurface *)NULL && surface->has_named_uvs()) {
261  string uv_name = surface->get_uv_name();
262  LPoint2 uv;
263  if (get_uv(uv_name, pindex, vindex, uv)) {
264  // This UV is defined in a "discontinuous" map, that
265  // associated a particular UV per each polygon.
266  egg_vertex->set_uv(LCAST(double, uv));
267 
268  } else if (_points->get_uv(uv_name, vindex, uv)) {
269  // The UV does not appear in a discontinuous map, but it
270  // is defined in the points set.
271  egg_vertex->set_uv(LCAST(double, uv));
272  }
273  }
274 
275  egg_vertices.push_back(egg_vertex);
276  }
277  }
278 
279  if (is_valid) {
280  if (surface != (CLwoSurface *)NULL) {
281  surface->apply_properties(egg_prim, egg_vertices, smooth_angle);
282  }
283 
284  // Now add all the vertices officially to the primitive.
285  vector_PT_EggVertex::const_iterator evi;
286  for (evi = egg_vertices.begin(); evi != egg_vertices.end(); ++evi) {
287  EggVertex *egg_vertex = (*evi);
288  EggVertex *new_vertex = egg_vpool->create_unique_vertex(*egg_vertex);
289  egg_prim->add_vertex(new_vertex);
290  }
291 
292  // And add the primitive to its parent.
293  _egg_group->add_child(egg_prim.p());
294  }
295  }
296 
297  CoordinateSystem cs = _converter->get_egg_data()->get_coordinate_system();
298  if (smooth_angle > 0.0) {
299  _egg_group->recompute_vertex_normals(rad_2_deg(smooth_angle), cs);
300  } else {
301  _egg_group->recompute_polygon_normals(cs);
302  }
303 }
304 
A base class for any of a number of kinds of geometry primitives: polygons, point lights...
Definition: eggPrimitive.h:51
CLwoSurface * get_surface(const string &name) const
Returns a pointer to the surface definition with the given name, or NULL if there is no such surface...
int get_num_points() const
Returns the number of points of this group.
Definition: lwoPoints.cxx:29
void add_vmad(const LwoDiscontinuousVertexMap *lwo_vmad)
Associates the indicated DiscontinousVertexMap with the polygons.
void add_ptags(const LwoPolygonTags *lwo_ptags, const LwoTags *tags)
Associates the indicated PolygonTags and Tags with the polygons in this chunk.
PTA_stdfloat get_value(int polygon_index, int vertex_index) const
Returns the mapping value associated with the given index, or an empty PTA_stdfloat if there is no ma...
An association of polygons defined in the most recent LwoPolygons chunk to tag ids defined in the mos...
CoordinateSystem get_coordinate_system() const
Returns the coordinate system in which the egg file is defined.
Definition: eggData.I:111
EggData * get_egg_data()
Returns the EggData structure.
bool has_value(int polygon_index, int vertex_index) const
Returns true if the map has a value associated with the given index, false otherwise.
const string & get_uv_name() const
Returns the name of the set of UV&#39;s that are associated with this surface, if has_named_uvs() is true...
Definition: cLwoSurface.I:50
int get_tag(int polygon_index) const
Returns the tag associated with the given polygon index, or -1 if there is no tag associated...
An array of tag strings that will be referenced by later chunks.
Definition: lwoTags.h:35
A single point, or a collection of points as defined by a single <PointLight> entry.
Definition: eggPoint.h:27
bool has_named_uvs() const
Returns true if the surface is set up to reference UV&#39;s stored on the vertices, by name (as opposed t...
Definition: cLwoSurface.I:37
void make_egg()
Creates the egg structures associated with this Lightwave object.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:36
const LPoint3 & get_point(int n) const
Returns the nth point of this group.
Definition: lwoPoints.cxx:39
This class is a wrapper around LwoSurface and stores additional information useful during the convers...
Definition: cLwoSurface.h:42
CLwoSurface * get_surface(int polygon_index) const
Returns the surface associated with the given polygon, or NULL if no surface is associated.
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal...
Definition: eggVertex.h:41
void apply_properties(EggPrimitive *egg_prim, vector_PT_EggVertex &egg_vertices, PN_stdfloat &smooth_angle)
Applies the color, texture, etc.
int get_num_tags() const
Returns the number of tags of this group.
Definition: lwoTags.cxx:29
A single polygon.
Definition: eggPolygon.h:26
bool get_uv(const string &uv_name, int pi, int vi, LPoint2 &uv) const
Returns true if there is a UV of the indicated name associated with the given vertex of the indicated...
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:544
string get_tag(int n) const
Returns the nth tag of this group.
Definition: lwoTags.cxx:39
bool get_uv(const string &uv_name, int n, LPoint2 &uv) const
Returns true if there is a UV of the indicated name associated with the given vertex, false otherwise.
Definition: cLwoPoints.cxx:62
This is a two-component point in space.
Definition: lpoint2.h:92
A four-byte chunk ID appearing in an "IFF" file.
Definition: iffId.h:29
void connect_egg()
Connects all the egg structures together.
A mapping of floating-point values per integer index.
EggVertex * create_unique_vertex(const EggVertex &copy)
Creates a new vertex in the pool that is a copy of the indicated one and returns it.
A collection of vertices.
Definition: eggVertexPool.h:46
bool has_tag(int polygon_index) const
Returns true if the map has a tag associated with the given polygon index, false otherwise.
An array of points that will be referenced by later chunks.
Definition: lwoPoints.h:29