00001 // Filename: textureCollection.cxx 00002 // Created by: drose (16Mar02) 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 "textureCollection.h" 00016 #include "indent.h" 00017 00018 #ifdef HAVE_PYTHON 00019 #include "py_panda.h" 00020 #endif 00021 00022 //////////////////////////////////////////////////////////////////// 00023 // Function: TextureCollection::Constructor 00024 // Access: Published 00025 // Description: 00026 //////////////////////////////////////////////////////////////////// 00027 TextureCollection:: 00028 TextureCollection() { 00029 } 00030 00031 //////////////////////////////////////////////////////////////////// 00032 // Function: TextureCollection::Copy Constructor 00033 // Access: Published 00034 // Description: 00035 //////////////////////////////////////////////////////////////////// 00036 TextureCollection:: 00037 TextureCollection(const TextureCollection ©) : 00038 _textures(copy._textures) 00039 { 00040 } 00041 00042 //////////////////////////////////////////////////////////////////// 00043 // Function: TextureCollection::Copy Assignment Operator 00044 // Access: Published 00045 // Description: 00046 //////////////////////////////////////////////////////////////////// 00047 void TextureCollection:: 00048 operator = (const TextureCollection ©) { 00049 _textures = copy._textures; 00050 } 00051 00052 #ifdef HAVE_PYTHON 00053 //////////////////////////////////////////////////////////////////// 00054 // Function: TextureCollection::Constructor 00055 // Access: Published 00056 // Description: This special constructor accepts a Python list of 00057 // Textures. Since this constructor accepts a generic 00058 // PyObject *, it should be the last constructor listed 00059 // in the class record. 00060 //////////////////////////////////////////////////////////////////// 00061 TextureCollection:: 00062 TextureCollection(PyObject *self, PyObject *sequence) { 00063 // We have to pre-initialize self's "this" pointer when we receive 00064 // self in the constructor--the caller can't initialize this for us. 00065 ((Dtool_PyInstDef *)self)->_ptr_to_object = this; 00066 00067 if (!PySequence_Check(sequence)) { 00068 // If passed with a non-sequence, this isn't the right constructor. 00069 PyErr_SetString(PyExc_TypeError, "TextureCollection constructor requires a sequence"); 00070 return; 00071 } 00072 00073 int size = PySequence_Size(sequence); 00074 for (int i = 0; i < size; ++i) { 00075 PyObject *item = PySequence_GetItem(sequence, i); 00076 if (item == NULL) { 00077 return; 00078 } 00079 PyObject *result = PyObject_CallMethod(self, (char *)"addTexture", (char *)"O", item); 00080 Py_DECREF(item); 00081 if (result == NULL) { 00082 // Unable to add item--probably it wasn't of the appropriate type. 00083 ostringstream stream; 00084 stream << "Element " << i << " in sequence passed to TextureCollection constructor could not be added"; 00085 string str = stream.str(); 00086 PyErr_SetString(PyExc_TypeError, str.c_str()); 00087 return; 00088 } 00089 Py_DECREF(result); 00090 } 00091 } 00092 #endif // HAVE_PYTHON 00093 00094 #ifdef HAVE_PYTHON 00095 //////////////////////////////////////////////////////////////////// 00096 // Function: TextureCollection::__reduce__ 00097 // Access: Published 00098 // Description: This special Python method is implement to provide 00099 // support for the pickle module. 00100 //////////////////////////////////////////////////////////////////// 00101 PyObject *TextureCollection:: 00102 __reduce__(PyObject *self) const { 00103 // Here we will return a 4-tuple: (Class, (args), None, iterator), 00104 // where iterator is an iterator that will yield successive 00105 // Textures. 00106 00107 // We should return at least a 2-tuple, (Class, (args)): the 00108 // necessary class object whose constructor we should call 00109 // (e.g. this), and the arguments necessary to reconstruct this 00110 // object. 00111 00112 PyObject *this_class = PyObject_Type(self); 00113 if (this_class == NULL) { 00114 return NULL; 00115 } 00116 00117 // Since a TextureCollection is itself an iterator, we can simply 00118 // pass it as the fourth tuple component. 00119 PyObject *result = Py_BuildValue("(O()OO)", this_class, Py_None, self); 00120 Py_DECREF(this_class); 00121 return result; 00122 } 00123 #endif // HAVE_PYTHON 00124 00125 //////////////////////////////////////////////////////////////////// 00126 // Function: TextureCollection::add_texture 00127 // Access: Published 00128 // Description: Adds a new Texture to the collection. 00129 //////////////////////////////////////////////////////////////////// 00130 void TextureCollection:: 00131 add_texture(Texture *texture) { 00132 // If the pointer to our internal array is shared by any other 00133 // TextureCollections, we have to copy the array now so we won't 00134 // inadvertently modify any of our brethren TextureCollection 00135 // objects. 00136 00137 if (_textures.get_ref_count() > 1) { 00138 Textures old_textures = _textures; 00139 _textures = Textures::empty_array(0); 00140 _textures.v() = old_textures.v(); 00141 } 00142 00143 _textures.push_back(texture); 00144 } 00145 00146 //////////////////////////////////////////////////////////////////// 00147 // Function: TextureCollection::remove_texture 00148 // Access: Published 00149 // Description: Removes the indicated Texture from the collection. 00150 // Returns true if the texture was removed, false if it was 00151 // not a member of the collection. 00152 //////////////////////////////////////////////////////////////////// 00153 bool TextureCollection:: 00154 remove_texture(Texture *texture) { 00155 int texture_index = -1; 00156 for (int i = 0; texture_index == -1 && i < (int)_textures.size(); i++) { 00157 if (_textures[i] == texture) { 00158 texture_index = i; 00159 } 00160 } 00161 00162 if (texture_index == -1) { 00163 // The indicated texture was not a member of the collection. 00164 return false; 00165 } 00166 00167 // If the pointer to our internal array is shared by any other 00168 // TextureCollections, we have to copy the array now so we won't 00169 // inadvertently modify any of our brethren TextureCollection 00170 // objects. 00171 00172 if (_textures.get_ref_count() > 1) { 00173 Textures old_textures = _textures; 00174 _textures = Textures::empty_array(0); 00175 _textures.v() = old_textures.v(); 00176 } 00177 00178 _textures.erase(_textures.begin() + texture_index); 00179 return true; 00180 } 00181 00182 //////////////////////////////////////////////////////////////////// 00183 // Function: TextureCollection::add_textures_from 00184 // Access: Published 00185 // Description: Adds all the Textures indicated in the other 00186 // collection to this texture. The other textures are simply 00187 // appended to the end of the textures in this list; 00188 // duplicates are not automatically removed. 00189 //////////////////////////////////////////////////////////////////// 00190 void TextureCollection:: 00191 add_textures_from(const TextureCollection &other) { 00192 int other_num_textures = other.get_num_textures(); 00193 for (int i = 0; i < other_num_textures; i++) { 00194 add_texture(other.get_texture(i)); 00195 } 00196 } 00197 00198 00199 //////////////////////////////////////////////////////////////////// 00200 // Function: TextureCollection::remove_textures_from 00201 // Access: Published 00202 // Description: Removes from this collection all of the Textures 00203 // listed in the other collection. 00204 //////////////////////////////////////////////////////////////////// 00205 void TextureCollection:: 00206 remove_textures_from(const TextureCollection &other) { 00207 Textures new_textures; 00208 int num_textures = get_num_textures(); 00209 for (int i = 0; i < num_textures; i++) { 00210 PT(Texture) texture = get_texture(i); 00211 if (!other.has_texture(texture)) { 00212 new_textures.push_back(texture); 00213 } 00214 } 00215 _textures = new_textures; 00216 } 00217 00218 //////////////////////////////////////////////////////////////////// 00219 // Function: TextureCollection::remove_duplicate_textures 00220 // Access: Published 00221 // Description: Removes any duplicate entries of the same Textures 00222 // on this collection. If a Texture appears multiple 00223 // times, the first appearance is retained; subsequent 00224 // appearances are removed. 00225 //////////////////////////////////////////////////////////////////// 00226 void TextureCollection:: 00227 remove_duplicate_textures() { 00228 Textures new_textures; 00229 00230 int num_textures = get_num_textures(); 00231 for (int i = 0; i < num_textures; i++) { 00232 PT(Texture) texture = get_texture(i); 00233 bool duplicated = false; 00234 00235 for (int j = 0; j < i && !duplicated; j++) { 00236 duplicated = (texture == get_texture(j)); 00237 } 00238 00239 if (!duplicated) { 00240 new_textures.push_back(texture); 00241 } 00242 } 00243 00244 _textures = new_textures; 00245 } 00246 00247 //////////////////////////////////////////////////////////////////// 00248 // Function: TextureCollection::has_texture 00249 // Access: Published 00250 // Description: Returns true if the indicated Texture appears in 00251 // this collection, false otherwise. 00252 //////////////////////////////////////////////////////////////////// 00253 bool TextureCollection:: 00254 has_texture(Texture *texture) const { 00255 for (int i = 0; i < get_num_textures(); i++) { 00256 if (texture == get_texture(i)) { 00257 return true; 00258 } 00259 } 00260 return false; 00261 } 00262 00263 //////////////////////////////////////////////////////////////////// 00264 // Function: TextureCollection::clear 00265 // Access: Published 00266 // Description: Removes all Textures from the collection. 00267 //////////////////////////////////////////////////////////////////// 00268 void TextureCollection:: 00269 clear() { 00270 _textures.clear(); 00271 } 00272 00273 //////////////////////////////////////////////////////////////////// 00274 // Function: TextureCollection::find_texture 00275 // Access: Published 00276 // Description: Returns the texture in the collection with the 00277 // indicated name, if any, or NULL if no texture has 00278 // that name. 00279 //////////////////////////////////////////////////////////////////// 00280 Texture *TextureCollection:: 00281 find_texture(const string &name) const { 00282 int num_textures = get_num_textures(); 00283 for (int i = 0; i < num_textures; i++) { 00284 Texture *texture = get_texture(i); 00285 if (texture->get_name() == name) { 00286 return texture; 00287 } 00288 } 00289 return NULL; 00290 } 00291 00292 //////////////////////////////////////////////////////////////////// 00293 // Function: TextureCollection::get_num_textures 00294 // Access: Published 00295 // Description: Returns the number of Textures in the collection. 00296 //////////////////////////////////////////////////////////////////// 00297 int TextureCollection:: 00298 get_num_textures() const { 00299 return _textures.size(); 00300 } 00301 00302 //////////////////////////////////////////////////////////////////// 00303 // Function: TextureCollection::get_texture 00304 // Access: Published 00305 // Description: Returns the nth Texture in the collection. 00306 //////////////////////////////////////////////////////////////////// 00307 Texture *TextureCollection:: 00308 get_texture(int index) const { 00309 nassertr(index >= 0 && index < (int)_textures.size(), NULL); 00310 00311 return _textures[index]; 00312 } 00313 00314 //////////////////////////////////////////////////////////////////// 00315 // Function: TextureCollection::operator [] 00316 // Access: Published 00317 // Description: Returns the nth Texture in the collection. This is 00318 // the same as get_texture(), but it may be a more 00319 // convenient way to access it. 00320 //////////////////////////////////////////////////////////////////// 00321 Texture *TextureCollection:: 00322 operator [] (int index) const { 00323 nassertr(index >= 0 && index < (int)_textures.size(), NULL); 00324 00325 return _textures[index]; 00326 } 00327 00328 //////////////////////////////////////////////////////////////////// 00329 // Function: TextureCollection::size 00330 // Access: Published 00331 // Description: Returns the number of textures in the collection. This 00332 // is the same thing as get_num_textures(). 00333 //////////////////////////////////////////////////////////////////// 00334 int TextureCollection:: 00335 size() const { 00336 return _textures.size(); 00337 } 00338 00339 //////////////////////////////////////////////////////////////////// 00340 // Function: TextureCollection::output 00341 // Access: Published 00342 // Description: Writes a brief one-line description of the 00343 // TextureCollection to the indicated output stream. 00344 //////////////////////////////////////////////////////////////////// 00345 void TextureCollection:: 00346 output(ostream &out) const { 00347 if (get_num_textures() == 1) { 00348 out << "1 Texture"; 00349 } else { 00350 out << get_num_textures() << " Textures"; 00351 } 00352 } 00353 00354 //////////////////////////////////////////////////////////////////// 00355 // Function: TextureCollection::write 00356 // Access: Published 00357 // Description: Writes a complete multi-line description of the 00358 // TextureCollection to the indicated output stream. 00359 //////////////////////////////////////////////////////////////////// 00360 void TextureCollection:: 00361 write(ostream &out, int indent_level) const { 00362 for (int i = 0; i < get_num_textures(); i++) { 00363 indent(out, indent_level) << *get_texture(i) << "\n"; 00364 } 00365 }