00001 // Filename: eggVertexPool.cxx 00002 // Created by: drose (16Jan99) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved 00008 // 00009 // All use of this software is subject to the terms of the Panda 3d 00010 // Software license. You should have received a copy of this license 00011 // along with this source code; you will also find a current copy of 00012 // the license at http://www.panda3d.org/license.txt . 00013 // 00014 // To contact the maintainers of this program write to 00015 // panda3d@yahoogroups.com . 00016 // 00017 //////////////////////////////////////////////////////////////////// 00018 00019 #include "eggVertexPool.h" 00020 #include "eggPrimitive.h" 00021 #include "eggUtilities.h" 00022 00023 #include <indent.h> 00024 00025 TypeHandle EggVertexPool::_type_handle; 00026 00027 //////////////////////////////////////////////////////////////////// 00028 // Function: EggVertexPool::Constructor 00029 // Access: Public 00030 // Description: 00031 //////////////////////////////////////////////////////////////////// 00032 EggVertexPool:: 00033 EggVertexPool(const string &name) : EggNode(name) { 00034 } 00035 00036 //////////////////////////////////////////////////////////////////// 00037 // Function: EggVertexPool::Copy Constructor 00038 // Access: Public 00039 // Description: Copying a vertex pool is of questionable value, since 00040 // it will copy all of the vertices and assign new 00041 // pointers to them all. There will be no polygons 00042 // referring to the new vertices. 00043 //////////////////////////////////////////////////////////////////// 00044 EggVertexPool:: 00045 EggVertexPool(const EggVertexPool ©) : EggNode(copy) { 00046 iterator i; 00047 for (i = copy.begin(); i != copy.end(); ++i) { 00048 add_vertex(new EggVertex(*(*i)), (*i)->get_index()); 00049 } 00050 } 00051 00052 00053 //////////////////////////////////////////////////////////////////// 00054 // Function: EggVertexPool::Destructor 00055 // Access: Public 00056 // Description: 00057 //////////////////////////////////////////////////////////////////// 00058 EggVertexPool:: 00059 ~EggVertexPool() { 00060 // Remove all vertices from the pool when it destructs. 00061 00062 // Sanity check. 00063 nassertv(_index_vertices.size() == _unique_vertices.size()); 00064 00065 iterator i; 00066 for (i = begin(); i != end(); ++i) { 00067 // Sanity checks on our internal data structures. 00068 nassertv((*i)->_pool == this); 00069 nassertv(get_vertex((*i)->_index) == (*i)); 00070 00071 (*i)->_pool = NULL; 00072 (*i)->_index = -1; 00073 } 00074 00075 _index_vertices.erase(_index_vertices.begin(), _index_vertices.end()); 00076 _unique_vertices.erase(_unique_vertices.begin(), _unique_vertices.end()); 00077 } 00078 00079 00080 //////////////////////////////////////////////////////////////////// 00081 // Function: EggVertexPool::get_vertex 00082 // Access: Public 00083 // Description: Returns the vertex in the pool with the indicated 00084 // index number, or NULL if no vertices have that index 00085 // number. 00086 //////////////////////////////////////////////////////////////////// 00087 EggVertex *EggVertexPool:: 00088 get_vertex(int index) const { 00089 IndexVertices::const_iterator ivi = _index_vertices.find(index); 00090 00091 if (ivi == _index_vertices.end()) { 00092 return NULL; 00093 } else { 00094 return (*ivi).second; 00095 } 00096 } 00097 00098 //////////////////////////////////////////////////////////////////// 00099 // Function: EggVertexPool::get_highest_index 00100 // Access: Public 00101 // Description: Returns the highest index number used by any vertex 00102 // in the pool. 00103 //////////////////////////////////////////////////////////////////// 00104 int EggVertexPool:: 00105 get_highest_index() const { 00106 if (_index_vertices.empty()) { 00107 return 0; 00108 } 00109 IndexVertices::const_reverse_iterator ivi = _index_vertices.rbegin(); 00110 nassertr((*ivi).first == (*ivi).second->get_index(), 0); 00111 return (*ivi).first; 00112 } 00113 00114 //////////////////////////////////////////////////////////////////// 00115 // Function: EggVertexPool::begin() 00116 // Access: Public 00117 // Description: Returns an iterator that can be used to traverse 00118 // through all the vertices in the pool. 00119 //////////////////////////////////////////////////////////////////// 00120 EggVertexPool::iterator EggVertexPool:: 00121 begin() const { 00122 nassertr(_index_vertices.size() == _unique_vertices.size(), 00123 iterator(_index_vertices.begin())); 00124 return iterator(_index_vertices.begin()); 00125 } 00126 00127 //////////////////////////////////////////////////////////////////// 00128 // Function: EggVertexPool::end() 00129 // Access: Public 00130 // Description: Returns an iterator that can be used to traverse 00131 // through all the vertices in the pool. 00132 //////////////////////////////////////////////////////////////////// 00133 EggVertexPool::iterator EggVertexPool:: 00134 end() const { 00135 return iterator(_index_vertices.end()); 00136 } 00137 00138 //////////////////////////////////////////////////////////////////// 00139 // Function: EggVertexPool::empty() 00140 // Access: Public 00141 // Description: Returns true if the pool is empty. 00142 //////////////////////////////////////////////////////////////////// 00143 bool EggVertexPool:: 00144 empty() const { 00145 return _index_vertices.empty(); 00146 } 00147 00148 //////////////////////////////////////////////////////////////////// 00149 // Function: EggVertexPool::size() 00150 // Access: Public 00151 // Description: Returns the number of vertices in the pool. 00152 //////////////////////////////////////////////////////////////////// 00153 EggVertexPool::size_type EggVertexPool:: 00154 size() const { 00155 nassertr(_index_vertices.size() == _unique_vertices.size(), 0); 00156 return _index_vertices.size(); 00157 } 00158 00159 //////////////////////////////////////////////////////////////////// 00160 // Function: EggVertexPool::add_vertex 00161 // Access: Public 00162 // Description: Adds the indicated vertex to the pool. It is an 00163 // error if the vertex is already a member of this or 00164 // any other pool. The vertex must have been allocated 00165 // from the free store; its pointer will now be owned by 00166 // the vertex pool. If the index number is supplied, 00167 // tries to assign that index number; it is an error if 00168 // the index number is already in use. 00169 //////////////////////////////////////////////////////////////////// 00170 void EggVertexPool:: 00171 add_vertex(EggVertex *vertex, int index) { 00172 // Don't try to add a vertex while it still belongs to another pool. 00173 nassertv(vertex->_pool == NULL); 00174 00175 if (index == -1) { 00176 index = get_highest_index() + 1; 00177 } 00178 // Always supply an index number >= 0. 00179 nassertv(index >= 0); 00180 00181 // Don't try to duplicate index numbers within a vertex pool. 00182 nassertv(_index_vertices.find(index) == _index_vertices.end()); 00183 00184 _unique_vertices.insert(vertex); 00185 _index_vertices[index] = vertex; 00186 00187 vertex->_pool = this; 00188 vertex->_index = index; 00189 } 00190 00191 00192 //////////////////////////////////////////////////////////////////// 00193 // Function: EggVertexPool::create_unique_vertex 00194 // Access: Public 00195 // Description: Creates a new vertex in the pool that is a copy of 00196 // the indicated one and returns it. If there is 00197 // already a vertex in the pool like the indicated one, 00198 // simply returns that one. 00199 //////////////////////////////////////////////////////////////////// 00200 EggVertex *EggVertexPool:: 00201 create_unique_vertex(const EggVertex ©) { 00202 UniqueVertices::iterator uvi; 00203 uvi = _unique_vertices.find((EggVertex *)©); 00204 00205 if (uvi != _unique_vertices.end()) { 00206 // There was already such a vertex. Return it. 00207 return (*uvi); 00208 } 00209 00210 // Create a new vertex. 00211 EggVertex *vtx = new EggVertex(copy); 00212 add_vertex(vtx); 00213 return vtx; 00214 } 00215 00216 00217 //////////////////////////////////////////////////////////////////// 00218 // Function: EggVertexPool::remove_vertex 00219 // Access: Public 00220 // Description: Removes the vertex from the pool. It is an error if 00221 // the vertex is not already a member of the pool. 00222 //////////////////////////////////////////////////////////////////// 00223 void EggVertexPool:: 00224 remove_vertex(EggVertex *vertex) { 00225 // Make sure the vertex is already a member of this pool. 00226 nassertv(vertex->_pool == this); 00227 00228 // Sanity check. Is the vertex actually in the pool? 00229 nassertv(get_vertex(vertex->_index) == vertex); 00230 00231 // Removing the vertex from the indexed list is simple. 00232 _index_vertices.erase(vertex->_index); 00233 00234 // Removing the vertex from the unique list is a bit trickier--there 00235 // might be several other vertices that are considered identical to 00236 // this one, and so we have to walk through all the identical 00237 // vertices until we find the right one. 00238 UniqueVertices::iterator uvi; 00239 uvi = _unique_vertices.find(vertex); 00240 00241 // Sanity check. Is the vertex actually in the pool? 00242 nassertv(uvi != _unique_vertices.end()); 00243 00244 while ((*uvi) != vertex) { 00245 ++uvi; 00246 // Sanity check. Is the vertex actually in the pool? 00247 nassertv(uvi != _unique_vertices.end()); 00248 } 00249 00250 _unique_vertices.erase(uvi); 00251 00252 vertex->_pool = NULL; 00253 } 00254 00255 //////////////////////////////////////////////////////////////////// 00256 // Function: EggVertexPool::remove_unused_vertices 00257 // Access: Public 00258 // Description: Removes all vertices from the pool that are not 00259 // referenced by at least one primitive. Also renumbers 00260 // all vertices after the operation so their indices are 00261 // consecutive, beginning at zero. Returns the number 00262 // of vertices removed. 00263 //////////////////////////////////////////////////////////////////// 00264 int EggVertexPool:: 00265 remove_unused_vertices() { 00266 int num_removed = 0; 00267 00268 UniqueVertices new_unique_vertices; 00269 IndexVertices new_index_vertices; 00270 00271 IndexVertices::const_iterator ivi; 00272 for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) { 00273 EggVertex *vertex = (*ivi).second; 00274 if (vertex->pref_size() == 0) { 00275 // This vertex is not used. Don't add it to the new lists. 00276 vertex->clear_grefs(); 00277 vertex->_pool = NULL; 00278 num_removed++; 00279 00280 } else { 00281 // The vertex *is* used somewhere. Renumber it and add it to 00282 // the new lists. 00283 vertex->_index = new_index_vertices.size(); 00284 new_index_vertices.insert(IndexVertices::value_type(vertex->_index, vertex)); 00285 new_unique_vertices.insert(vertex); 00286 } 00287 } 00288 00289 // All done. Lose the old lists. 00290 _unique_vertices.swap(new_unique_vertices); 00291 _index_vertices.swap(new_index_vertices); 00292 00293 nassertr(_index_vertices.size() == _unique_vertices.size(), num_removed); 00294 00295 return num_removed; 00296 } 00297 00298 // A function object for split_vertex(), used in transform(), below. 00299 class IsLocalVertexSplitter { 00300 public: 00301 int operator () (const EggPrimitive *prim) const { 00302 return (prim->is_local_coord() ? 1 : 0); 00303 } 00304 }; 00305 00306 //////////////////////////////////////////////////////////////////// 00307 // Function: EggVertexPool::transform 00308 // Access: Public 00309 // Description: Applies the indicated transformation matrix to all 00310 // the vertices. However, vertices that are attached to 00311 // primitives that believe their vertices are in a local 00312 // coordinate system are transformed only by the scale 00313 // and rotation component. If a vertex happens to be 00314 // attached both to a local and a global primitive, and 00315 // the transformation includes a translation component, 00316 // the vertex will be split. 00317 //////////////////////////////////////////////////////////////////// 00318 void EggVertexPool:: 00319 transform(const LMatrix4d &mat) { 00320 LVector3d translation = mat.get_row3(3); 00321 00322 if (translation == LVector3d(0.0, 0.0, 0.0)) { 00323 // If the matrix does not have a translation component, we can 00324 // treat the local and global vertices the same. This makes 00325 // things much easier. 00326 iterator i; 00327 for (i = begin(); i != end(); ++i) { 00328 EggVertex *vert = *i; 00329 vert->transform(mat); 00330 } 00331 00332 } else { 00333 // The matrix does have a translation component. That means we 00334 // have to treat the global and local vertices differently. 00335 // Yucky. 00336 00337 // First, transform the global vertices. Get a copy of the list 00338 // of vertices in this pool. We must have a copy because we might 00339 // be modifying the list as we traverse it. 00340 00341 typedef pvector<EggVertex *> Verts; 00342 Verts verts; 00343 verts.reserve(size()); 00344 copy(begin(), end(), back_inserter(verts)); 00345 00346 Verts::const_iterator vi; 00347 for (vi = verts.begin(); vi != verts.end(); ++vi) { 00348 EggVertex *vert = *vi; 00349 int num_local_coord = vert->get_num_local_coord(); 00350 int num_global_coord = vert->get_num_global_coord(); 00351 00352 if (num_global_coord != 0) { 00353 // This vertex will be transformed. 00354 if (num_local_coord != 0) { 00355 // It also needs to be split! Yuck. 00356 split_vertex(vert, IsLocalVertexSplitter()); 00357 } 00358 00359 vert->transform(mat); 00360 } 00361 } 00362 00363 // Now transform the local vertices. We can walk through the list 00364 // directly now, because we won't be modifying the list this time. 00365 LMatrix4d local_mat = mat; 00366 local_mat.set_row(3, LVector3d(0.0, 0.0, 0.0)); 00367 00368 iterator i; 00369 for (i = begin(); i != end(); ++i) { 00370 EggVertex *vert = *i; 00371 if (vert->get_num_local_coord() != 0) { 00372 00373 // This should be guaranteed by the vertex-splitting logic 00374 // above. 00375 nassertv(vert->get_num_global_coord() == 0); 00376 vert->transform(local_mat); 00377 } 00378 } 00379 } 00380 } 00381 00382 00383 //////////////////////////////////////////////////////////////////// 00384 // Function: EggVertexPool::write 00385 // Access: Public 00386 // Description: Writes the vertex pool to the indicated output stream 00387 // in Egg format. 00388 //////////////////////////////////////////////////////////////////// 00389 void EggVertexPool:: 00390 write(ostream &out, int indent_level) const { 00391 write_header(out, indent_level, "<VertexPool>"); 00392 00393 iterator i; 00394 for (i = begin(); i != end(); ++i) { 00395 (*i)->write(out, indent_level+2); 00396 } 00397 00398 indent(out, indent_level) 00399 << "}\n"; 00400 } 00401 00402 00403 //////////////////////////////////////////////////////////////////// 00404 // Function: EggVertexPool::r_transform 00405 // Access: Protected, Virtual 00406 // Description: This is called from within the egg code by 00407 // transform(). It applies a transformation matrix 00408 // to the current node in some sensible way, then 00409 // continues down the tree. 00410 // 00411 // The first matrix is the transformation to apply; the 00412 // second is its inverse. The third parameter is the 00413 // coordinate system we are changing to, or CS_default 00414 // if we are not changing coordinate systems. 00415 //////////////////////////////////////////////////////////////////// 00416 void EggVertexPool:: 00417 r_transform(const LMatrix4d &mat, const LMatrix4d &, CoordinateSystem) { 00418 transform(mat); 00419 } 00420 00421 //////////////////////////////////////////////////////////////////// 00422 // Function: EggVertexPool::r_transform_vertices 00423 // Access: Protected, Virtual 00424 // Description: This is called from within the egg code by 00425 // transform_vertices_only()(). It applies a 00426 // transformation matrix to the current node in some 00427 // sensible way (if the current node is a vertex pool 00428 // with vertices), then continues down the tree. 00429 //////////////////////////////////////////////////////////////////// 00430 void EggVertexPool:: 00431 r_transform_vertices(const LMatrix4d &mat) { 00432 transform(mat); 00433 }