00001 // Filename: pandaSystem.cxx 00002 // Created by: drose (26Jan05) 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 "pandaSystem.h" 00016 #include "pandaVersion.h" 00017 #include "dtool_platform.h" 00018 00019 PandaSystem *PandaSystem::_global_ptr = NULL; 00020 TypeHandle PandaSystem::_type_handle; 00021 00022 //////////////////////////////////////////////////////////////////// 00023 // Function: PandaSystem::Constructor 00024 // Access: Protected 00025 // Description: Don't try to construct a PandaSystem object; there is 00026 // only one of these, and it constructs itself. Use 00027 // get_global_ptr() to get a pointer to the one 00028 // PandaSystem. 00029 //////////////////////////////////////////////////////////////////// 00030 PandaSystem:: 00031 PandaSystem() : 00032 _systems(get_class_type()) 00033 { 00034 _system_names_dirty = false; 00035 00036 // These are settable via Config.prc, but only in development 00037 // (!NDEBUG) mode, and only if they are not already defined. 00038 _package_version_string = PANDA_PACKAGE_VERSION_STR; 00039 _package_host_url = PANDA_PACKAGE_HOST_URL; 00040 00041 #ifdef STDFLOAT_DOUBLE 00042 add_system("stdfloat-double"); 00043 #endif 00044 00045 #ifdef HAVE_EIGEN 00046 add_system("eigen"); 00047 #ifdef LINMATH_ALIGN 00048 set_system_tag("eigen", "vectorize", "1"); 00049 #else 00050 set_system_tag("eigen", "vectorize", "0"); 00051 #endif 00052 #endif // HAVE_EIGEN 00053 00054 #ifdef USE_MEMORY_DLMALLOC 00055 set_system_tag("system", "malloc", "dlmalloc"); 00056 #elif defined(USE_MEMORY_PTMALLOC2) 00057 set_system_tag("system", "malloc", "ptmalloc2"); 00058 #else 00059 set_system_tag("system", "malloc", "malloc"); 00060 #endif 00061 } 00062 00063 //////////////////////////////////////////////////////////////////// 00064 // Function: PandaSystem::Destructor 00065 // Access: Protected 00066 // Description: Don't try to destruct the global PandaSystem object. 00067 //////////////////////////////////////////////////////////////////// 00068 PandaSystem:: 00069 ~PandaSystem() { 00070 } 00071 00072 //////////////////////////////////////////////////////////////////// 00073 // Function: PandaSystem::get_version_string 00074 // Access: Published, Static 00075 // Description: Returns the current version of Panda, expressed as a 00076 // string, e.g. "1.0.0". The string will end in the 00077 // letter "c" if this build does not represent an 00078 // official version. 00079 //////////////////////////////////////////////////////////////////// 00080 string PandaSystem:: 00081 get_version_string() { 00082 return PANDA_VERSION_STR; 00083 } 00084 00085 //////////////////////////////////////////////////////////////////// 00086 // Function: PandaSystem::get_package_version_string 00087 // Access: Published, Static 00088 // Description: Returns the version of the Panda3D distributable 00089 // package that provides this build of Panda. 00090 // 00091 // When the currently-executing version of Panda was 00092 // loaded from a distributable package, such as via the 00093 // browser plugin, then this string will be nonempty and 00094 // will contain the corresponding version string. You 00095 // can build applications that use this particular 00096 // version of Panda by requesting it in the pdef file, 00097 // using "panda3d", this version string, and the 00098 // download host provided by get_package_host_url(). 00099 // 00100 // If this string is empty, then the currently-executing 00101 // Panda was built independently, and is not part of a 00102 // distributable package. 00103 // 00104 // This string is set explicitly at compilation time. 00105 // Normally, it should be set to a nonempty string only 00106 // when building a Panda3D package for distribution. 00107 //////////////////////////////////////////////////////////////////// 00108 string PandaSystem:: 00109 get_package_version_string() { 00110 #ifdef NDEBUG 00111 return PANDA_PACKAGE_VERSION_STR; 00112 #else 00113 return get_global_ptr()->_package_version_string; 00114 #endif 00115 } 00116 00117 //////////////////////////////////////////////////////////////////// 00118 // Function: PandaSystem::get_package_host_url 00119 // Access: Published, Static 00120 // Description: Returns the URL of the download server that provides 00121 // the Panda3D distributable package currently running. 00122 // This can be used, along with the 00123 // get_package_version_string(), to uniquely identify 00124 // the running version of Panda among distributable 00125 // Panda versions. 00126 // 00127 // See get_package_version_string() for more information. 00128 // 00129 // This string is set explicitly at compilation time. 00130 // Normally, it should be set to a nonempty string only 00131 // when building a Panda3D package for distribution. 00132 //////////////////////////////////////////////////////////////////// 00133 string PandaSystem:: 00134 get_package_host_url() { 00135 #ifdef NDEBUG 00136 return PANDA_PACKAGE_HOST_URL; 00137 #else 00138 return get_global_ptr()->_package_host_url; 00139 #endif 00140 } 00141 00142 //////////////////////////////////////////////////////////////////// 00143 // Function: PandaSystem::get_p3d_coreapi_version_string 00144 // Access: Published, Static 00145 // Description: Returns the current version of Panda's Core API, 00146 // expressed as a string of dot-delimited integers. 00147 // There are usually four integers in this version, but 00148 // this is not guaranteed. 00149 // 00150 // The Core API is used during the runtime (plugin) 00151 // environment only. This may be the empty string if 00152 // the current version of Panda is not built to provide 00153 // a particular Core API, which will be the normal case 00154 // in a development SDK. However, you should not use 00155 // this method to determine whether you are running in a 00156 // runtime environment or not. 00157 //////////////////////////////////////////////////////////////////// 00158 string PandaSystem:: 00159 get_p3d_coreapi_version_string() { 00160 #ifndef P3D_COREAPI_VERSION_STR 00161 return ""; 00162 #else 00163 return P3D_COREAPI_VERSION_STR; 00164 #endif 00165 } 00166 00167 //////////////////////////////////////////////////////////////////// 00168 // Function: PandaSystem::get_major_version 00169 // Access: Published, Static 00170 // Description: Returns the major version number of the current 00171 // version of Panda. This is the first number of the 00172 // dotted triple returned by get_version_string(). It 00173 // changes very rarely. 00174 //////////////////////////////////////////////////////////////////// 00175 int PandaSystem:: 00176 get_major_version() { 00177 return PANDA_MAJOR_VERSION; 00178 } 00179 00180 //////////////////////////////////////////////////////////////////// 00181 // Function: PandaSystem::get_minor_version 00182 // Access: Published, Static 00183 // Description: Returns the minor version number of the current 00184 // version of Panda. This is the second number of the 00185 // dotted triple returned by get_version_string(). It 00186 // changes with each release that introduces new 00187 // features. 00188 //////////////////////////////////////////////////////////////////// 00189 int PandaSystem:: 00190 get_minor_version() { 00191 return PANDA_MINOR_VERSION; 00192 } 00193 00194 //////////////////////////////////////////////////////////////////// 00195 // Function: PandaSystem::get_sequence_version 00196 // Access: Published, Static 00197 // Description: Returns the sequence version number of the current 00198 // version of Panda. This is the third number of the 00199 // dotted triple returned by get_version_string(). It 00200 // changes with bugfix updates and very minor feature 00201 // updates. 00202 //////////////////////////////////////////////////////////////////// 00203 int PandaSystem:: 00204 get_sequence_version() { 00205 return PANDA_SEQUENCE_VERSION; 00206 } 00207 00208 //////////////////////////////////////////////////////////////////// 00209 // Function: PandaSystem::is_official_version 00210 // Access: Published, Static 00211 // Description: Returns true if current version of Panda claims to be 00212 // an "official" version, that is, one that was compiled 00213 // by an official distributor of Panda using a specific 00214 // version of the panda source tree. If this is true, 00215 // there will not be a "c" at the end of the version 00216 // string returned by get_version_string(). 00217 // 00218 // Note that we must take the distributor's word for it 00219 // here. 00220 //////////////////////////////////////////////////////////////////// 00221 bool PandaSystem:: 00222 is_official_version() { 00223 #ifdef PANDA_OFFICIAL_VERSION 00224 return true; 00225 #else 00226 return false; 00227 #endif 00228 } 00229 00230 //////////////////////////////////////////////////////////////////// 00231 // Function: PandaSystem::get_distributor 00232 // Access: Published, Static 00233 // Description: Returns the string defined by the distributor of this 00234 // version of Panda, or "homebuilt" if this version was 00235 // built directly from the sources by the end-user. 00236 // This is a completely arbitrary string. 00237 //////////////////////////////////////////////////////////////////// 00238 string PandaSystem:: 00239 get_distributor() { 00240 return PANDA_DISTRIBUTOR; 00241 } 00242 00243 //////////////////////////////////////////////////////////////////// 00244 // Function: PandaSystem::get_compiler 00245 // Access: Published, Static 00246 // Description: Returns a string representing the compiler that was 00247 // used to generate this version of Panda, if it is 00248 // available, or "unknown" if it is not. 00249 //////////////////////////////////////////////////////////////////// 00250 string PandaSystem:: 00251 get_compiler() { 00252 #if defined(_MSC_VER) 00253 // MSVC defines this macro. It's an integer; we need to format it. 00254 ostringstream strm; 00255 strm << "MSC v." << _MSC_VER; 00256 00257 // We also get this suite of macros that tells us what the build 00258 // platform is. 00259 #if defined(_M_IX86) 00260 #ifdef MS_WIN64 00261 strm << " 64 bit (Intel)"; 00262 #else // MS_WIN64 00263 strm << " 32 bit (Intel)"; 00264 #endif // MS_WIN64 00265 #elif defined(_M_IA64) 00266 strm << " 64 bit (Itanium)"; 00267 #elif defined(_M_AMD64) 00268 strm << " 64 bit (AMD64)"; 00269 #endif 00270 00271 return strm.str(); 00272 00273 #elif defined(__GNUC__) 00274 // GCC defines this simple macro. 00275 return "GCC " __VERSION__; 00276 00277 #else 00278 // For other compilers, you're on your own. 00279 return "unknown"; 00280 #endif 00281 } 00282 00283 //////////////////////////////////////////////////////////////////// 00284 // Function: PandaSystem::get_build_date 00285 // Access: Published, Static 00286 // Description: Returns a string representing the date and time at 00287 // which this version of Panda (or at least dtool) was 00288 // compiled, if available. 00289 //////////////////////////////////////////////////////////////////// 00290 string PandaSystem:: 00291 get_build_date() { 00292 return __DATE__ " " __TIME__; 00293 } 00294 00295 //////////////////////////////////////////////////////////////////// 00296 // Function: PandaSystem::get_platform 00297 // Access: Published, Static 00298 // Description: Returns a string representing the runtime platform 00299 // that we are currently running on. This will be 00300 // something like "win32" or "osx.i386" or 00301 // "linux.amd64". 00302 //////////////////////////////////////////////////////////////////// 00303 string PandaSystem:: 00304 get_platform() { 00305 return DTOOL_PLATFORM; 00306 } 00307 00308 //////////////////////////////////////////////////////////////////// 00309 // Function: PandaSystem::has_system 00310 // Access: Published 00311 // Description: Returns true if the current version of Panda claims 00312 // to have the indicated subsystem installed, false 00313 // otherwise. The set of available subsystems is 00314 // implementation defined. 00315 //////////////////////////////////////////////////////////////////// 00316 bool PandaSystem:: 00317 has_system(const string &system) const { 00318 Systems::const_iterator si; 00319 si = _systems.find(system); 00320 return (si != _systems.end()); 00321 } 00322 00323 //////////////////////////////////////////////////////////////////// 00324 // Function: PandaSystem::get_num_systems 00325 // Access: Published 00326 // Description: Returns the number of Panda subsystems that have 00327 // registered themselves. This can be used with 00328 // get_system() to iterate through the entire list of 00329 // available Panda subsystems. 00330 //////////////////////////////////////////////////////////////////// 00331 int PandaSystem:: 00332 get_num_systems() const { 00333 return _systems.size(); 00334 } 00335 00336 //////////////////////////////////////////////////////////////////// 00337 // Function: PandaSystem::get_system 00338 // Access: Published 00339 // Description: Returns the nth Panda subsystem that has registered 00340 // itself. This list will be sorted in alphabetical 00341 // order. 00342 //////////////////////////////////////////////////////////////////// 00343 string PandaSystem:: 00344 get_system(int n) const { 00345 if (n < 0 || n >= (int)_systems.size()) { 00346 return string(); 00347 } 00348 00349 if (_system_names_dirty) { 00350 ((PandaSystem *)this)->reset_system_names(); 00351 } 00352 00353 return _system_names[n]; 00354 } 00355 00356 //////////////////////////////////////////////////////////////////// 00357 // Function: PandaSystem::get_system_tag 00358 // Access: Published 00359 // Description: Returns the value associated with the indicated tag 00360 // for the given system. This provides a standard way 00361 // to query each subsystem's advertised capabilities. 00362 // The set of tags and values are per-system and 00363 // implementation-defined. 00364 // 00365 // The return value is the empty string if the indicated 00366 // system is undefined or if does not define the 00367 // indicated tag. 00368 //////////////////////////////////////////////////////////////////// 00369 string PandaSystem:: 00370 get_system_tag(const string &system, const string &tag) const { 00371 Systems::const_iterator si; 00372 si = _systems.find(system); 00373 if (si != _systems.end()) { 00374 const SystemTags &tags = (*si).second; 00375 SystemTags::const_iterator ti; 00376 ti = tags.find(tag); 00377 if (ti != tags.end()) { 00378 return (*ti).second; 00379 } 00380 } 00381 00382 return string(); 00383 } 00384 00385 //////////////////////////////////////////////////////////////////// 00386 // Function: PandaSystem::add_system 00387 // Access: Published 00388 // Description: Intended for use by each subsystem to register itself 00389 // at startup. 00390 //////////////////////////////////////////////////////////////////// 00391 void PandaSystem:: 00392 add_system(const string &system) { 00393 bool inserted = _systems.insert(Systems::value_type(system, SystemTags(get_class_type()))).second; 00394 if (inserted) { 00395 _system_names_dirty = true; 00396 } 00397 } 00398 00399 //////////////////////////////////////////////////////////////////// 00400 // Function: PandaSystem::set_system_tag 00401 // Access: Published 00402 // Description: Intended for use by each subsystem to register its 00403 // set of capabilities at startup. 00404 //////////////////////////////////////////////////////////////////// 00405 void PandaSystem:: 00406 set_system_tag(const string &system, const string &tag, 00407 const string &value) { 00408 pair<Systems::iterator, bool> result; 00409 result = _systems.insert(Systems::value_type(system, SystemTags(get_class_type()))); 00410 if (result.second) { 00411 _system_names_dirty = true; 00412 } 00413 00414 SystemTags &tags = (*result.first).second; 00415 tags[tag] = value; 00416 } 00417 00418 //////////////////////////////////////////////////////////////////// 00419 // Function: PandaSystem::heap_trim 00420 // Access: Published 00421 // Description: Attempts to release memory back to the system, if 00422 // possible. The pad argument is the minimum amount of 00423 // unused memory to keep in the heap (against future 00424 // allocations). Any memory above that may be released 00425 // to the system, reducing the memory size of this 00426 // process. There is no guarantee that any memory may 00427 // be released. 00428 // 00429 // Returns true if any memory was actually released, 00430 // false otherwise. 00431 //////////////////////////////////////////////////////////////////// 00432 bool PandaSystem:: 00433 heap_trim(size_t pad) { 00434 // This actually just vectors into _memory_hook, which isn't 00435 // published. This method only exists on PandaSystem for the 00436 // convenience of Python programmers. 00437 return memory_hook->heap_trim(pad); 00438 } 00439 00440 //////////////////////////////////////////////////////////////////// 00441 // Function: PandaSystem::output 00442 // Access: Published 00443 // Description: 00444 //////////////////////////////////////////////////////////////////// 00445 void PandaSystem:: 00446 output(ostream &out) const { 00447 out << "Panda version " << get_version_string(); 00448 } 00449 00450 //////////////////////////////////////////////////////////////////// 00451 // Function: PandaSystem::write 00452 // Access: Published 00453 // Description: 00454 //////////////////////////////////////////////////////////////////// 00455 void PandaSystem:: 00456 write(ostream &out) const { 00457 out << *this << "\n" 00458 << "compiled on " << get_build_date() << " by " 00459 << get_distributor() << "\n" 00460 << "with compiler " << PandaSystem::get_compiler() << "\n\n"; 00461 00462 out << "Optional systems:\n"; 00463 for (Systems::const_iterator si = _systems.begin(); 00464 si != _systems.end(); 00465 ++si) { 00466 out << " " << (*si).first << "\n"; 00467 const SystemTags &tags = (*si).second; 00468 SystemTags::const_iterator ti; 00469 for (ti = tags.begin(); ti != tags.end(); ++ti) { 00470 out << " " << (*ti).first << " " << (*ti).second << "\n"; 00471 } 00472 } 00473 } 00474 00475 00476 //////////////////////////////////////////////////////////////////// 00477 // Function: PandaSystem::get_global_ptr 00478 // Access: Published, Static 00479 // Description: Returns the global PandaSystem object. 00480 //////////////////////////////////////////////////////////////////// 00481 PandaSystem *PandaSystem:: 00482 get_global_ptr() { 00483 if (_global_ptr == (PandaSystem *)NULL) { 00484 _global_ptr = new PandaSystem; 00485 } 00486 00487 return _global_ptr; 00488 } 00489 00490 //////////////////////////////////////////////////////////////////// 00491 // Function: PandaSystem::reset_system_names 00492 // Access: Private 00493 // Description: Refills the _system_names vector, which is used for 00494 // get_system_name(), from the current set of available 00495 // system names. 00496 //////////////////////////////////////////////////////////////////// 00497 void PandaSystem:: 00498 reset_system_names() { 00499 _system_names.clear(); 00500 _system_names.reserve(_systems.size()); 00501 00502 Systems::const_iterator si; 00503 for (si = _systems.begin(); si != _systems.end(); ++si) { 00504 _system_names.push_back((*si).first); 00505 } 00506 00507 _system_names_dirty = false; 00508 } 00509 00510 //////////////////////////////////////////////////////////////////// 00511 // Function: PandaSystem::set_package_version_string 00512 // Access: Private 00513 // Description: Loads the value returned by 00514 // get_package_version_string(). This is intended to be 00515 // called by ConfigPageManager to preload the value from 00516 // the panda-package-version config variable, for 00517 // developer's convenience. This has no effect if the 00518 // PANDA_PACKAGE_VERSION_STR configure variable is 00519 // defined at compilation time. This also has no effect 00520 // in NDEBUG mode. 00521 //////////////////////////////////////////////////////////////////// 00522 void PandaSystem:: 00523 set_package_version_string(const string &package_version_string) { 00524 _package_version_string = PANDA_PACKAGE_VERSION_STR; 00525 if (_package_version_string.empty()) { 00526 _package_version_string = package_version_string; 00527 } 00528 } 00529 00530 //////////////////////////////////////////////////////////////////// 00531 // Function: PandaSystem::set_package_host_url 00532 // Access: Private 00533 // Description: Loads the value returned by 00534 // get_package_host_url(). This is intended to be 00535 // called by ConfigPageManager to preload the value from 00536 // the panda-package-host-url config variable, for 00537 // developer's convenience. This has no effect if the 00538 // PANDA_PACKAGE_HOST_URL configure variable is defined 00539 // at compilation time. This also has no effect in 00540 // NDEBUG mode. 00541 //////////////////////////////////////////////////////////////////// 00542 void PandaSystem:: 00543 set_package_host_url(const string &package_host_url) { 00544 _package_host_url = PANDA_PACKAGE_HOST_URL; 00545 if (_package_host_url.empty()) { 00546 _package_host_url = package_host_url; 00547 } 00548 }