Panda3D
|
00001 // Filename: cLwoPolygons.cxx 00002 // Created by: drose (25Apr01) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "cLwoPolygons.h" 00016 #include "lwoToEggConverter.h" 00017 #include "cLwoPoints.h" 00018 #include "cLwoLayer.h" 00019 #include "cLwoSurface.h" 00020 00021 #include "lwoPolygonTags.h" 00022 #include "lwoTags.h" 00023 #include "lwoDiscontinuousVertexMap.h" 00024 #include "eggData.h" 00025 #include "eggPolygon.h" 00026 #include "eggPoint.h" 00027 #include "deg_2_rad.h" 00028 00029 //////////////////////////////////////////////////////////////////// 00030 // Function: CLwoPolygons::add_ptags 00031 // Access: Public 00032 // Description: Associates the indicated PolygonTags and Tags with 00033 // the polygons in this chunk. This may define features 00034 // such as per-polygon surfaces, parts, and smoothing 00035 // groups. 00036 //////////////////////////////////////////////////////////////////// 00037 void CLwoPolygons:: 00038 add_ptags(const LwoPolygonTags *lwo_ptags, const LwoTags *tags) { 00039 if (_tags != (LwoTags *)NULL && _tags != tags) { 00040 nout << "Multiple Tags fields in effect on the same polygons.\n"; 00041 } 00042 _tags = tags; 00043 00044 IffId type = lwo_ptags->_tag_type; 00045 00046 bool inserted = _ptags.insert(PTags::value_type(type, lwo_ptags)).second; 00047 if (!inserted) { 00048 nout << "Multiple polygon tags on the same polygons of type " 00049 << type << "\n"; 00050 00051 } else { 00052 if (type == IffId("SURF")) { 00053 _surf_ptags = lwo_ptags; 00054 } 00055 } 00056 } 00057 00058 //////////////////////////////////////////////////////////////////// 00059 // Function: CLwoPolygons::add_vmad 00060 // Access: Public 00061 // Description: Associates the indicated DiscontinousVertexMap with 00062 // the polygons. This can be used in conjunction with 00063 // (or in place of) the VertexMap associated with the 00064 // points set, to define per-polygon UV's etc. 00065 //////////////////////////////////////////////////////////////////// 00066 void CLwoPolygons:: 00067 add_vmad(const LwoDiscontinuousVertexMap *lwo_vmad) { 00068 IffId map_type = lwo_vmad->_map_type; 00069 const string &name = lwo_vmad->_name; 00070 00071 bool inserted; 00072 if (map_type == IffId("TXUV")) { 00073 inserted = 00074 _txuv.insert(VMad::value_type(name, lwo_vmad)).second; 00075 00076 } else { 00077 return; 00078 } 00079 00080 if (!inserted) { 00081 nout << "Multiple discontinous vertex maps on the same polygons of type " 00082 << map_type << " named " << name << "\n"; 00083 } 00084 } 00085 00086 //////////////////////////////////////////////////////////////////// 00087 // Function: CLwoPolygons::get_surface 00088 // Access: Public 00089 // Description: Returns the surface associated with the given 00090 // polygon, or NULL if no surface is associated. 00091 //////////////////////////////////////////////////////////////////// 00092 CLwoSurface *CLwoPolygons:: 00093 get_surface(int polygon_index) const { 00094 if (_surf_ptags == (LwoPolygonTags *)NULL) { 00095 // No surface definitions. 00096 return (CLwoSurface *)NULL; 00097 } 00098 00099 if (!_surf_ptags->has_tag(polygon_index)) { 00100 // The polygon isn't tagged. 00101 return (CLwoSurface *)NULL; 00102 } 00103 00104 int tag_index = _surf_ptags->get_tag(polygon_index); 00105 if (_tags == (LwoTags *)NULL || tag_index < 0 || 00106 tag_index >= _tags->get_num_tags()) { 00107 // The tag index is out-of-bounds. 00108 nout << "Invalid polygon tag index " << tag_index << "\n"; 00109 return (CLwoSurface *)NULL; 00110 } 00111 00112 string tag = _tags->get_tag(tag_index); 00113 00114 // Now look up the surface name in the header. 00115 CLwoSurface *surface = _converter->get_surface(tag); 00116 if (surface == (CLwoSurface *)NULL) { 00117 nout << "Unknown surface " << tag << "\n"; 00118 return (CLwoSurface *)NULL; 00119 } 00120 00121 return surface; 00122 } 00123 00124 //////////////////////////////////////////////////////////////////// 00125 // Function: CLwoPolygons::get_uv 00126 // Access: Public 00127 // Description: Returns true if there is a UV of the indicated name 00128 // associated with the given vertex of the indicated 00129 // polygon, false otherwise. If true, fills in uv with 00130 // the value. 00131 // 00132 // This performs a lookup in the optional 00133 // "discontinuous" vertex mapping, which provides the 00134 // ability to map different UV's per each polygon for 00135 // the same vertex. If the UV is not defined here, it 00136 // may also be defined in the standard vertex map, which 00137 // is associated with the points themselves. 00138 //////////////////////////////////////////////////////////////////// 00139 bool CLwoPolygons:: 00140 get_uv(const string &uv_name, int pi, int vi, LPoint2 &uv) const { 00141 VMad::const_iterator ni = _txuv.find(uv_name); 00142 if (ni == _txuv.end()) { 00143 return false; 00144 } 00145 00146 const LwoDiscontinuousVertexMap *vmad = (*ni).second; 00147 if (vmad->_dimension != 2) { 00148 nout << "Unexpected dimension of " << vmad->_dimension 00149 << " for discontinuous UV map " << uv_name << "\n"; 00150 return false; 00151 } 00152 00153 if (!vmad->has_value(pi, vi)) { 00154 return false; 00155 } 00156 00157 PTA_stdfloat value = vmad->get_value(pi, vi); 00158 00159 uv.set(value[0], value[1]); 00160 return true; 00161 } 00162 00163 //////////////////////////////////////////////////////////////////// 00164 // Function: CLwoPolygons::make_egg 00165 // Access: Public 00166 // Description: Creates the egg structures associated with this 00167 // Lightwave object. 00168 //////////////////////////////////////////////////////////////////// 00169 void CLwoPolygons:: 00170 make_egg() { 00171 // First, we need a temporary group to hold all of the polygons 00172 // we'll create. 00173 _egg_group = new EggGroup; 00174 00175 if (_polygons->_polygon_type == IffId("CURV")) { 00176 nout << "Ignoring Catmull-Rom splines.\n"; 00177 00178 } else if (_polygons->_polygon_type == IffId("PTCH")) { 00179 nout << "Treating subdivision patches as ordinary polygons.\n"; 00180 make_faces(); 00181 00182 } else if (_polygons->_polygon_type == IffId("MBAL")) { 00183 nout << "Ignoring metaballs.\n"; 00184 00185 } else if (_polygons->_polygon_type == IffId("BONE")) { 00186 nout << "Ignoring bones.\n"; 00187 00188 } else if (_polygons->_polygon_type == IffId("FACE")) { 00189 make_faces(); 00190 00191 } else { 00192 nout << "Ignoring unknown geometry type " << _polygons->_polygon_type 00193 << ".\n"; 00194 } 00195 } 00196 00197 //////////////////////////////////////////////////////////////////// 00198 // Function: CLwoPolygons::connect_egg 00199 // Access: Public 00200 // Description: Connects all the egg structures together. 00201 //////////////////////////////////////////////////////////////////// 00202 void CLwoPolygons:: 00203 connect_egg() { 00204 nassertv(_points->_layer->_egg_group != (EggGroup *)NULL); 00205 nassertv(_egg_group != (EggGroup *)NULL); 00206 _points->_layer->_egg_group->steal_children(*_egg_group); 00207 } 00208 00209 00210 //////////////////////////////////////////////////////////////////// 00211 // Function: CLwoPolygons::make_faces 00212 // Access: Public 00213 // Description: Generates "face" polygons, i.e. actual polygons. 00214 //////////////////////////////////////////////////////////////////// 00215 void CLwoPolygons:: 00216 make_faces() { 00217 PN_stdfloat smooth_angle = -1.0; 00218 00219 int num_polygons = _polygons->get_num_polygons(); 00220 for (int pindex = 0; pindex < num_polygons; pindex++) { 00221 LwoPolygons::Polygon *poly = _polygons->get_polygon(pindex); 00222 CLwoSurface *surface = get_surface(pindex); 00223 00224 bool is_valid = true; 00225 00226 // Set up the vertices. 00227 const LwoPoints *points = _points->_points; 00228 int num_points = points->get_num_points(); 00229 EggVertexPool *egg_vpool = _points->_egg_vpool; 00230 00231 // We reverse the vertex ordering to compensate for Lightwave's 00232 // clockwise ordering convention. We also want to start with the 00233 // last vertex, so that the first convex angle is the first angle 00234 // in the EggPolygon (for determining correct normals). 00235 PT(EggPrimitive) egg_prim; 00236 00237 if (poly->_vertices.size() == 1) { 00238 egg_prim = new EggPoint; 00239 } else { 00240 egg_prim = new EggPolygon; 00241 } 00242 00243 // First, we have to create a temporary vector of vertices for the 00244 // polygon, so we can possibly adjust the properties of these 00245 // vertices (like the UV's) in the shader before we create them. 00246 vector_PT_EggVertex egg_vertices; 00247 00248 int num_vertices = poly->_vertices.size(); 00249 for (int vi = num_vertices; vi > 0; vi--) { 00250 int vindex = poly->_vertices[vi % num_vertices]; 00251 if (vindex < 0 || vindex >= num_points) { 00252 nout << "Invalid vertex index " << vindex << " in polygon.\n"; 00253 is_valid = false; 00254 } else { 00255 PT(EggVertex) egg_vertex = new EggVertex; 00256 LPoint3d pos = LCAST(double, points->get_point(vindex)); 00257 egg_vertex->set_pos(pos); 00258 00259 // Does the vertex used named UV's? 00260 if (surface != (CLwoSurface *)NULL && surface->has_named_uvs()) { 00261 string uv_name = surface->get_uv_name(); 00262 LPoint2 uv; 00263 if (get_uv(uv_name, pindex, vindex, uv)) { 00264 // This UV is defined in a "discontinuous" map, that 00265 // associated a particular UV per each polygon. 00266 egg_vertex->set_uv(LCAST(double, uv)); 00267 00268 } else if (_points->get_uv(uv_name, vindex, uv)) { 00269 // The UV does not appear in a discontinuous map, but it 00270 // is defined in the points set. 00271 egg_vertex->set_uv(LCAST(double, uv)); 00272 } 00273 } 00274 00275 egg_vertices.push_back(egg_vertex); 00276 } 00277 } 00278 00279 if (is_valid) { 00280 if (surface != (CLwoSurface *)NULL) { 00281 surface->apply_properties(egg_prim, egg_vertices, smooth_angle); 00282 } 00283 00284 // Now add all the vertices officially to the primitive. 00285 vector_PT_EggVertex::const_iterator evi; 00286 for (evi = egg_vertices.begin(); evi != egg_vertices.end(); ++evi) { 00287 EggVertex *egg_vertex = (*evi); 00288 EggVertex *new_vertex = egg_vpool->create_unique_vertex(*egg_vertex); 00289 egg_prim->add_vertex(new_vertex); 00290 } 00291 00292 // And add the primitive to its parent. 00293 _egg_group->add_child(egg_prim.p()); 00294 } 00295 } 00296 00297 CoordinateSystem cs = _converter->get_egg_data()->get_coordinate_system(); 00298 if (smooth_angle > 0.0) { 00299 _egg_group->recompute_vertex_normals(rad_2_deg(smooth_angle), cs); 00300 } else { 00301 _egg_group->recompute_polygon_normals(cs); 00302 } 00303 } 00304