00001 // Filename: graphicsPipeSelection.cxx 00002 // Created by: drose (15Aug02) 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 "graphicsPipeSelection.h" 00020 #include "mutexHolder.h" 00021 #include "string_utils.h" 00022 #include "filename.h" 00023 #include "load_dso.h" 00024 #include "config_display.h" 00025 00026 GraphicsPipeSelection *GraphicsPipeSelection::_global_ptr = NULL; 00027 00028 //////////////////////////////////////////////////////////////////// 00029 // Function: GraphicsPipeSelection::Constructor 00030 // Access: Protected 00031 // Description: 00032 //////////////////////////////////////////////////////////////////// 00033 GraphicsPipeSelection:: 00034 GraphicsPipeSelection() { 00035 // Get the set of modules named in the various aux-display Configrc 00036 // variables. We'll want to know this when we call load_modules() 00037 // later. 00038 Config::ConfigTable::Symbol disp; 00039 config_display.GetAll("aux-display", disp); 00040 00041 Config::ConfigTable::Symbol::iterator ci; 00042 for (ci = disp.begin(); ci != disp.end(); ++ci) { 00043 _display_modules.insert((*ci).Val()); 00044 } 00045 00046 // Also get the name of the default module from the load-display 00047 // variable. We get this explicitly from Configrc now (instead of 00048 // retrieving it in config_display), in case this constructor is 00049 // running at static init time. 00050 string load_display = config_display.GetString("load-display", ""); 00051 load_display = trim_right(load_display); 00052 size_t space = load_display.rfind(' '); 00053 if (space != string::npos) { 00054 // If there's a space, it indicates the name of the GraphicsPipe 00055 // class to prefer. 00056 _default_pipe_name = load_display.substr(space + 1); 00057 load_display = trim_right(load_display.substr(0, space)); 00058 } 00059 00060 // Everything else is the name of the .dll (or .so) file to load. 00061 _default_display_module = load_display; 00062 00063 if (_default_display_module == "*") { 00064 // '*' or empty string is the key for all display modules. 00065 _default_display_module = string(); 00066 00067 } else if (!_default_display_module.empty()) { 00068 _display_modules.insert(_default_display_module); 00069 } 00070 00071 _default_module_loaded = false; 00072 } 00073 00074 //////////////////////////////////////////////////////////////////// 00075 // Function: GraphicsPipeSelection::Destructor 00076 // Access: Protected 00077 // Description: 00078 //////////////////////////////////////////////////////////////////// 00079 GraphicsPipeSelection:: 00080 ~GraphicsPipeSelection() { 00081 } 00082 00083 //////////////////////////////////////////////////////////////////// 00084 // Function: GraphicsPipeSelection::get_num_pipe_types 00085 // Access: Published 00086 // Description: Returns the number of different types of 00087 // GraphicsPipes that are available to create through 00088 // this interface. 00089 //////////////////////////////////////////////////////////////////// 00090 int GraphicsPipeSelection:: 00091 get_num_pipe_types() const { 00092 load_default_module(); 00093 00094 int result; 00095 { 00096 MutexHolder holder(_lock); 00097 result = _pipe_types.size(); 00098 } 00099 return result; 00100 } 00101 00102 //////////////////////////////////////////////////////////////////// 00103 // Function: GraphicsPipeSelection::get_pipe_type 00104 // Access: Published 00105 // Description: Returns the nth type of GraphicsPipe available 00106 // through this interface. 00107 //////////////////////////////////////////////////////////////////// 00108 TypeHandle GraphicsPipeSelection:: 00109 get_pipe_type(int n) const { 00110 load_default_module(); 00111 00112 TypeHandle result; 00113 { 00114 MutexHolder holder(_lock); 00115 if (n >= 0 && n < (int)_pipe_types.size()) { 00116 result = _pipe_types[n]._type; 00117 } 00118 } 00119 return result; 00120 } 00121 00122 //////////////////////////////////////////////////////////////////// 00123 // Function: GraphicsPipeSelection::print_pipe_types 00124 // Access: Published 00125 // Description: Writes a list of the currently known GraphicsPipe 00126 // types to nout, for the user's information. 00127 //////////////////////////////////////////////////////////////////// 00128 void GraphicsPipeSelection:: 00129 print_pipe_types() const { 00130 load_default_module(); 00131 00132 MutexHolder holder(_lock); 00133 nout << "Known pipe types:" << endl; 00134 PipeTypes::const_iterator pi; 00135 for (pi = _pipe_types.begin(); pi != _pipe_types.end(); ++pi) { 00136 const PipeType &pipe_type = (*pi); 00137 nout << " " << pipe_type._type << "\n"; 00138 } 00139 if (_display_modules.empty()) { 00140 nout << "(all display modules loaded.)\n"; 00141 } else { 00142 nout << "(" << _display_modules.size() 00143 << " aux display modules not yet loaded.)\n"; 00144 } 00145 } 00146 00147 //////////////////////////////////////////////////////////////////// 00148 // Function: GraphicsPipeSelection::make_pipe 00149 // Access: Published 00150 // Description: Creates a new GraphicsPipe of the indicated type (or 00151 // a type more specific than the indicated type, if 00152 // necessary) and returns it. Returns NULL if the type 00153 // cannot be matched. 00154 //////////////////////////////////////////////////////////////////// 00155 PT(GraphicsPipe) GraphicsPipeSelection:: 00156 make_pipe(TypeHandle type) { 00157 load_default_module(); 00158 00159 MutexHolder holder(_lock); 00160 PipeTypes::const_iterator ti; 00161 00162 // First, look for an exact match of the requested type. 00163 for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { 00164 const PipeType &ptype = (*ti); 00165 if (ptype._type == type) { 00166 // Here's an exact match. 00167 PT(GraphicsPipe) pipe = (*ptype._constructor)(); 00168 if (pipe != (GraphicsPipe *)NULL) { 00169 return pipe; 00170 } 00171 } 00172 } 00173 00174 // Now look for a more-specific type. 00175 for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { 00176 const PipeType &ptype = (*ti); 00177 if (ptype._type.is_derived_from(type)) { 00178 // Here's an approximate match. 00179 PT(GraphicsPipe) pipe = (*ptype._constructor)(); 00180 if (pipe != (GraphicsPipe *)NULL) { 00181 return pipe; 00182 } 00183 } 00184 } 00185 00186 // Couldn't find a matching pipe type. 00187 return NULL; 00188 } 00189 00190 //////////////////////////////////////////////////////////////////// 00191 // Function: GraphicsPipeSelection::make_default_pipe 00192 // Access: Published 00193 // Description: Creates a new GraphicsPipe of some arbitrary type. 00194 // The user may specify a preference using the Configrc 00195 // file; otherwise, one will be chosen arbitrarily. 00196 //////////////////////////////////////////////////////////////////// 00197 PT(GraphicsPipe) GraphicsPipeSelection:: 00198 make_default_pipe() { 00199 load_default_module(); 00200 00201 MutexHolder holder(_lock); 00202 PipeTypes::const_iterator ti; 00203 00204 if (!_default_pipe_name.empty()) { 00205 // First, look for an exact match of the default type name from 00206 // the Configrc file (excepting case and hyphen/underscore). 00207 for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { 00208 const PipeType &ptype = (*ti); 00209 if (cmp_nocase_uh(ptype._type.get_name(), _default_pipe_name) == 0) { 00210 // Here's an exact match. 00211 PT(GraphicsPipe) pipe = (*ptype._constructor)(); 00212 if (pipe != (GraphicsPipe *)NULL) { 00213 return pipe; 00214 } 00215 } 00216 } 00217 00218 // No match; look for a substring match. 00219 string preferred_name = downcase(_default_pipe_name); 00220 for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { 00221 const PipeType &ptype = (*ti); 00222 string ptype_name = downcase(ptype._type.get_name()); 00223 if (ptype_name.find(preferred_name) != string::npos) { 00224 // Here's a substring match. 00225 PT(GraphicsPipe) pipe = (*ptype._constructor)(); 00226 if (pipe != (GraphicsPipe *)NULL) { 00227 return pipe; 00228 } 00229 } 00230 } 00231 } 00232 00233 // Couldn't find a matching pipe type; choose one arbitrarily. 00234 for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { 00235 const PipeType &ptype = (*ti); 00236 PT(GraphicsPipe) pipe = (*ptype._constructor)(); 00237 if (pipe != (GraphicsPipe *)NULL) { 00238 return pipe; 00239 } 00240 } 00241 00242 // Nothing. Probably the list was empty. 00243 return NULL; 00244 } 00245 00246 //////////////////////////////////////////////////////////////////// 00247 // Function: GraphicsPipeSelection::load_aux_modules 00248 // Access: Published 00249 // Description: Loads all the modules named in the aux-display 00250 // Configrc variable, making as many graphics pipes as 00251 // possible available. 00252 //////////////////////////////////////////////////////////////////// 00253 void GraphicsPipeSelection:: 00254 load_aux_modules() { 00255 DisplayModules::iterator di; 00256 for (di = _display_modules.begin(); di != _display_modules.end(); ++di) { 00257 load_named_module(*di); 00258 } 00259 00260 _display_modules.clear(); 00261 _default_module_loaded = true; 00262 } 00263 00264 //////////////////////////////////////////////////////////////////// 00265 // Function: GraphicsPipeSelection::add_pipe_type 00266 // Access: Public 00267 // Description: Adds a new kind of GraphicsPipe to the list of 00268 // available pipes for creation. Normally, this is 00269 // called at static init type by the various shared 00270 // libraries as they are linked in. Returns true on 00271 // success, false on failure. 00272 //////////////////////////////////////////////////////////////////// 00273 bool GraphicsPipeSelection:: 00274 add_pipe_type(TypeHandle type, PipeConstructorFunc *func) { 00275 if (!type.is_derived_from(GraphicsPipe::get_class_type())) { 00276 display_cat.warning() 00277 << "Attempt to register " << type << " as a GraphicsPipe type.\n"; 00278 return false; 00279 } 00280 00281 // First, make sure we don't already have a GraphicsPipe of this 00282 // type. 00283 MutexHolder holder(_lock); 00284 PipeTypes::const_iterator ti; 00285 for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { 00286 const PipeType &ptype = (*ti); 00287 if (ptype._type == type) { 00288 display_cat.warning() 00289 << "Attempt to register GraphicsPipe type " << type 00290 << " more than once.\n"; 00291 return false; 00292 } 00293 } 00294 00295 // Ok, now add a new entry. 00296 _pipe_types.push_back(PipeType(type, func)); 00297 00298 return true; 00299 } 00300 00301 00302 //////////////////////////////////////////////////////////////////// 00303 // Function: GraphicsPipeSelection::do_load_default_module 00304 // Access: Private 00305 // Description: Loads the particular display module listed in the 00306 // load-display Configrc variable, which should default 00307 // the default pipe time. If this string is empty or 00308 // "*", loads all modules named in aux-display. 00309 //////////////////////////////////////////////////////////////////// 00310 void GraphicsPipeSelection:: 00311 do_load_default_module() { 00312 _default_module_loaded = true; 00313 00314 if (_default_display_module.empty()) { 00315 load_aux_modules(); 00316 return; 00317 } 00318 00319 load_named_module(_default_display_module); 00320 _display_modules.erase(_default_display_module); 00321 } 00322 00323 //////////////////////////////////////////////////////////////////// 00324 // Function: GraphicsPipeSelection::load_named_module 00325 // Access: Private 00326 // Description: Loads the indicated display module by looking for a 00327 // matching .dll or .so file. 00328 //////////////////////////////////////////////////////////////////// 00329 void GraphicsPipeSelection:: 00330 load_named_module(const string &name) { 00331 Filename dlname = Filename::dso_filename("lib" + name + ".so"); 00332 display_cat.info() 00333 << "loading display module: " << dlname.to_os_specific() << endl; 00334 void *tmp = load_dso(dlname); 00335 if (tmp == (void *)NULL) { 00336 display_cat.info() 00337 << "Unable to load: " << load_dso_error() << endl; 00338 } 00339 }