diff --git a/dtool/src/prc/configVariableBase.cxx b/dtool/src/prc/configVariableBase.cxx index 372d82953b..973a808f05 100644 --- a/dtool/src/prc/configVariableBase.cxx +++ b/dtool/src/prc/configVariableBase.cxx @@ -33,10 +33,10 @@ ConfigVariableBase(const string &name, if (value_type != VT_undefined) { _core->set_value_type(value_type); } - if (flags != 0) { - _core->set_flags(flags); - } if (!description.empty()) { _core->set_description(description); } + if (flags != 0) { + _core->set_flags(flags); + } } diff --git a/dtool/src/prc/configVariableCore.cxx b/dtool/src/prc/configVariableCore.cxx index 4d473cddba..8c730b784c 100644 --- a/dtool/src/prc/configVariableCore.cxx +++ b/dtool/src/prc/configVariableCore.cxx @@ -46,6 +46,31 @@ ConfigVariableCore(const string &name) : { } +//////////////////////////////////////////////////////////////////// +// Function: ConfigVariableCore::Copy Constructor +// Access: Private +// Description: This is used by ConfigVariableManager to create the +// variable from a template--basically, another variable +// with all of the initial properties pre-defined. +//////////////////////////////////////////////////////////////////// +ConfigVariableCore:: +ConfigVariableCore(const ConfigVariableCore &templ, const string &name) : + _name(name), + _is_used(templ._is_used), + _value_type(templ._value_type), + _description(templ._description), + _flags(templ._flags), + _default_value(NULL), + _local_value(NULL), + _declarations_sorted(false), + _value_queried(false), + _value_seq(0) +{ + if (templ._default_value != (ConfigDeclaration *)NULL) { + set_default_value(templ._default_value->get_string_value()); + } +} + //////////////////////////////////////////////////////////////////// // Function: ConfigVariableCore::Destructor // Access: Private diff --git a/dtool/src/prc/configVariableCore.h b/dtool/src/prc/configVariableCore.h index 3bcc982f5f..382deb75b7 100644 --- a/dtool/src/prc/configVariableCore.h +++ b/dtool/src/prc/configVariableCore.h @@ -42,6 +42,7 @@ class ConfigDeclaration; class EXPCL_DTOOLCONFIG ConfigVariableCore : public ConfigFlags { private: ConfigVariableCore(const string &name); + ConfigVariableCore(const ConfigVariableCore &templ, const string &name); ~ConfigVariableCore(); public: diff --git a/dtool/src/prc/configVariableManager.cxx b/dtool/src/prc/configVariableManager.cxx index dd6d8a6edc..fba4edef81 100644 --- a/dtool/src/prc/configVariableManager.cxx +++ b/dtool/src/prc/configVariableManager.cxx @@ -66,12 +66,113 @@ make_variable(const string &name) { return (*ni).second; } - ConfigVariableCore *variable = new ConfigVariableCore(name); + ConfigVariableCore *variable = NULL; + + // See if there's a template that matches this name. + VariableTemplates::const_iterator ti; + for (ti = _variable_templates.begin(); + ti != _variable_templates.end() && variable == (ConfigVariableCore *)NULL; + ++ti) { + const GlobPattern &pattern = (*ti).first; + ConfigVariableCore *templ = (*ti).second; + if (pattern.matches(name)) { + variable = new ConfigVariableCore(*templ, name); + } + } + + if (variable == (ConfigVariableCore *)NULL) { + variable = new ConfigVariableCore(name); + } + _variables_by_name[name] = variable; _variables.push_back(variable); return variable; } +//////////////////////////////////////////////////////////////////// +// Function: ConfigVariableManager::make_variable_template +// Access: Published +// Description: Defines a variable "template" to match against +// dynamically-defined variables that may or may not be +// created in the future. +// +// The template consists of a glob pattern, +// e.g. "notify-level-*", which will be tested against +// any config variable passed to a future call to +// make_variable(). If the pattern matches, the +// returned ConfigVariableCore is copied to define the +// new variable, instead of creating a default, empty +// one. +// +// This is useful to pre-specify default values for a +// family of variables that all have similar properties, +// and all may not be created at the same time. It is +// especially useful to avoid cluttering up the list of +// available variables with user-declared variables that +// have not been defined yet by the application +// (e.g. "egg-object-type-*"). +// +// This method basically pre-defines all variables that +// match the specified glob pattern. +//////////////////////////////////////////////////////////////////// +ConfigVariableCore *ConfigVariableManager:: +make_variable_template(const string &pattern, + ConfigFlags::ValueType value_type, + const string &default_value, + const string &description, int flags) { + ConfigVariableCore *core; + + GlobPattern gp(pattern); + VariableTemplates::const_iterator ti = _variable_templates.find(gp); + if (ti != _variable_templates.end()) { + core = (*ti).second; + + } else { + core = new ConfigVariableCore(pattern); + _variable_templates[gp] = core; + } + + if (value_type != ConfigFlags::VT_undefined) { + core->set_value_type(value_type); + } + if (!default_value.empty() || + core->get_default_value() == (ConfigDeclaration *)NULL) { + core->set_default_value(default_value); + } + if (!description.empty()) { + core->set_description(description); + } + if (flags != 0) { + core->set_flags(flags); + } + core->set_used(); + + // Also apply the same changes to any previously-defined variables + // that match the pattern. + Variables::iterator vi; + for (vi = _variables.begin(); vi != _variables.end(); ++vi) { + ConfigVariableCore *variable = (*vi); + if (gp.matches(variable->get_name())) { + if (value_type != ConfigFlags::VT_undefined) { + variable->set_value_type(value_type); + } + if (!default_value.empty() || + variable->get_default_value() == (ConfigDeclaration *)NULL) { + variable->set_default_value(default_value); + } + if (!description.empty()) { + variable->set_description(description); + } + if (flags != 0) { + variable->set_flags(flags); + } + variable->set_used(); + } + } + + return core; +} + //////////////////////////////////////////////////////////////////// // Function: ConfigVariableManager::get_variable_name // Access: Published diff --git a/dtool/src/prc/configVariableManager.h b/dtool/src/prc/configVariableManager.h index c05727ec9e..cd64442cd6 100644 --- a/dtool/src/prc/configVariableManager.h +++ b/dtool/src/prc/configVariableManager.h @@ -20,7 +20,9 @@ #define CONFIGVARIABLEMANAGER_H #include "dtoolbase.h" +#include "configFlags.h" #include "notify.h" +#include "globPattern.h" #include "pvector.h" #include "pmap.h" @@ -39,6 +41,12 @@ protected: PUBLISHED: ConfigVariableCore *make_variable(const string &name); + ConfigVariableCore *make_variable_template(const string &pattern, + ConfigFlags::ValueType type, + const string &default_value, + const string &description = string(), + int flags = 0); + INLINE int get_num_variables() const; INLINE ConfigVariableCore *get_variable(int n) const; @@ -64,6 +72,9 @@ private: typedef pmap VariablesByName; VariablesByName _variables_by_name; + typedef pmap VariableTemplates; + VariableTemplates _variable_templates; + static ConfigVariableManager *_global_ptr; }; diff --git a/dtool/src/prc/globPattern.I b/dtool/src/prc/globPattern.I index bcee2b0b1f..27080469f3 100644 --- a/dtool/src/prc/globPattern.I +++ b/dtool/src/prc/globPattern.I @@ -50,6 +50,39 @@ operator = (const GlobPattern ©) { _case_sensitive = copy._case_sensitive; } +//////////////////////////////////////////////////////////////////// +// Function: GlobPattern::operator == +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool GlobPattern:: +operator == (const GlobPattern &other) const { + return (_pattern == other._pattern && _case_sensitive == other._case_sensitive); +} + +//////////////////////////////////////////////////////////////////// +// Function: GlobPattern::operator != +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool GlobPattern:: +operator != (const GlobPattern &other) const { + return !operator == (other); +} + +//////////////////////////////////////////////////////////////////// +// Function: GlobPattern::operator < +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool GlobPattern:: +operator < (const GlobPattern &other) const { + if (_case_sensitive != other._case_sensitive) { + return (int)_case_sensitive < (int)other._case_sensitive; + } + return _pattern < other._pattern; +} + //////////////////////////////////////////////////////////////////// // Function: GlobPattern::set_pattern // Access: Public diff --git a/dtool/src/prc/globPattern.h b/dtool/src/prc/globPattern.h index bf073734b9..1703dd431c 100644 --- a/dtool/src/prc/globPattern.h +++ b/dtool/src/prc/globPattern.h @@ -44,6 +44,10 @@ PUBLISHED: INLINE GlobPattern(const GlobPattern ©); INLINE void operator = (const GlobPattern ©); + INLINE bool operator == (const GlobPattern &other) const; + INLINE bool operator != (const GlobPattern &other) const; + INLINE bool operator < (const GlobPattern &other) const; + INLINE void set_pattern(const string &pattern); INLINE const string &get_pattern() const; diff --git a/panda/src/egg2pg/config_egg2pg.cxx b/panda/src/egg2pg/config_egg2pg.cxx index 9afdbf98ea..58172cf321 100644 --- a/panda/src/egg2pg/config_egg2pg.cxx +++ b/panda/src/egg2pg/config_egg2pg.cxx @@ -22,6 +22,8 @@ #include "get_config_path.h" #include "loaderFileTypeEgg.h" #include "loaderFileTypeRegistry.h" +#include "configVariableManager.h" +#include "configVariableCore.h" ConfigureDef(config_egg2pg); NotifyCategoryDef(egg2pg, ""); @@ -108,6 +110,17 @@ init_libegg2pg() { } initialized = true; + // Define a template for all egg-object-type-* variables, so the + // system knows that these variables are defined when it finds them + // in a user's prc file, even if we haven't actually read an egg + // file that uses the particular field. + ConfigVariableManager *cv_mgr = ConfigVariableManager::get_global_ptr(); + cv_mgr->make_variable_template + ("egg-object-type-*", + ConfigVariableCore::VT_string, "", + "Defines egg syntax for the named object type.", + ConfigVariableCore::F_dynamic); + // Get egg-coordinate-system string csstr = config_egg2pg.GetString("egg-coordinate-system", "default"); CoordinateSystem cs = parse_coordinate_system_string(csstr); diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index d6a02a6693..4e824ca785 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -80,6 +80,7 @@ #include "ropeNode.h" #include "sheetNode.h" #include "look_at.h" +#include "configVariableString.h" #include #include @@ -2773,10 +2774,11 @@ do_expand_object_type(EggGroup *egg_group, const pset &expanded, // Try to find the egg syntax that the given objecttype is // shorthand for. First, look in the config file. - string egg_syntax = - config_egg2pg.GetString("egg-object-type-" + downcase(object_type), "none"); + ConfigVariableString egg_object_type + ("egg-object-type-" + downcase(object_type), ""); + string egg_syntax = egg_object_type; - if (egg_syntax == "none") { + if (!egg_object_type.has_value()) { // It wasn't defined in a config file. Maybe it's built in? if (cmp_nocase_uh(object_type, "barrier") == 0) {