#pragma once #include #include #include #include #include #include "lib_begin.h" #ifndef _WIN32 #include #include #endif /// the cgv namespace namespace cgv { /// the base namespace holds the base hierarchy, support for plugin registration and signals namespace base { /**@name control over the registration process */ //@{ //! Enable registration (default is that registration is disabled). /*! If registration has been disabled before, send all registration events that where emitted during disabled registration. */ extern void CGV_API enable_registration(); /// if registration is disable, all registration events are stored and sent at the momement when registration is enabled again. This feature is used when loading dlls extern void CGV_API disable_registration(); /// check whether registration is enabled extern bool CGV_API is_registration_enabled(); /// enable registration debugging extern void CGV_API enable_registration_debugging(); /// disable registration debugging extern void CGV_API disable_registration_debugging(); /// check whether registration debugging is enabled extern bool CGV_API is_registration_debugging_enabled(); /// register a registration listener that stores pointers to all registered objects extern void CGV_API enable_permanent_registration(); /// deregister registration listener and dereference pointers to registered objects extern void CGV_API disable_permanent_registration(); /// check whether permanent registration is enabled extern bool CGV_API is_permanent_registration_enabled(); /// unregister all existing objects to clean up extern void CGV_API unregister_all_objects(); /// access to number of permanently registered objects extern unsigned CGV_API get_nr_permanently_registered_objects(); /// access to i-th permanently registered object extern base_ptr CGV_API get_permanently_registered_object(unsigned i); //! Enable cleanup of registration events (default). /*! If registration event cleanup is disabled, registration events are not discarded as soon as objects have been registered. This makes objects available to listeners that are registered later. */ extern void CGV_API enable_registration_event_cleanup(); /// disable cleanup of registration events (see enable_registration_event_cleanup). extern void CGV_API disable_registration_event_cleanup(); /// return whether registration cleanup is enabled extern bool CGV_API is_registration_event_cleanup_enabled(); //@} /**@name object registration */ //@{ //! register an object. /*! This will send an event to all currently registered registration listeners. The options parameter can be used to select a specific listener. */ extern void CGV_API register_object(base_ptr object, const std::string& options = ""); /// unregister an object and send event to all currently registered registration listeners extern void CGV_API unregister_object(base_ptr object, const std::string& options = ""); // abstract base class of helpers to perform delayed registration and creation of objects in case that the registration is currently disabled struct CGV_API object_constructor : public cgv::base::base { public: // creation function virtual base_ptr construct_object() const = 0; }; // type specific specialization of helper class to perform delayed registration and creation of objects in case that the registration is disabled template class object_constructor_impl : public object_constructor { public: // creation function base_ptr construct_object() const { return base_ptr(new T()); } }; // type specific specialization of helper class to perform delayed registration and creation of objects in case that the registration is disabled template class object_constructor_impl_1 : public object_constructor { // buffer constructor argument CA ca; public: // construct from option object_constructor_impl_1(const CA& _ca) : ca(_ca) {} // creation function base_ptr construct_object() const { return base_ptr(new T(ca)); } }; // type specific specialization of helper class to perform delayed registration and creation of objects in case that the registration is disabled template class object_constructor_impl_2 : public object_constructor { // buffer constructor arguments CA1 ca1; CA2 ca2; public: // construct from option object_constructor_impl_2(const CA1& _ca1, const CA2& _ca2) : ca1(_ca1), ca2(_ca2) {} // creation function base_ptr construct_object() const { return base_ptr(new T(ca1,ca2)); } }; /// convenience class to register an object of the given class type template struct object_registration { /// pass information about the target registration listener in the options argument object_registration(const std::string& options) { if (is_registration_enabled()) register_object(base_ptr(new T()),options); else register_object(base_ptr(new object_constructor_impl()), options); } }; /// convenience class to register an object of the given class type with one constructor argument template struct object_registration_1 { /// pass information about the target registration listener in the options argument object_registration_1(const CA& arg, const std::string& options = "") { if (is_registration_enabled()) register_object(base_ptr(new T(arg)),options); else register_object(base_ptr(new object_constructor_impl_1(arg)), options); } }; /// convenience class to register an object of the given class type with two constructor arguments template struct object_registration_2 { /// pass information about the target registration listener in the options argument object_registration_2(const CA1& a1, const CA2& a2, const std::string& options = "") { if (is_registration_enabled()) register_object(base_ptr(new T(a1,a2)),options); else register_object(base_ptr(new object_constructor_impl_2(a1,a2)),options); } }; //@} /**@name support for driver, listener and factory registration*/ //@{ //! interfaces that add provides very basic functionality. /*! Servers are registered before drivers and before listeners. */ struct CGV_API server { }; //! interfaces that add several listeners and objects. /*! Drivers are special classes that provide extended functionality. They are registered after servers and before listeners. */ struct CGV_API driver { }; //! interfaces that allows to listen to registration events. /*! In order to allow registration of a registration listener, the implementation must also inherit cgv::base::base. When registration had been disabled and is enabled again, registration listeners are registered before all other objects. */ struct CGV_API registration_listener { /// overload to handle registration events virtual void register_object(base_ptr object, const std::string& options = "") = 0; /// overload to handle unregistration events virtual void unregister_object(base_ptr object, const std::string& options = "") = 0; }; //! interface for a factory that allows to create objects derived from cgv::base::base struct CGV_API factory : public base { protected: /// store the type name of the to be created objects std::string created_type_name; /// store whether the factory can only create one object bool is_singleton; /// pointer to the single object created by the factory in case is_singelton is true base_ptr singleton; /// store the options used for registering newly created objects std::string object_options; public: /// construct factory(const std::string& _created_type_name, bool _singleton = false, const std::string& _object_options = ""); /// return the options string used for object registration virtual std::string get_object_options() const; /// overload to return the type name of the objects that the factory can create const std::string& get_created_type_name() const; /// support creation of object by setting create property to true std::string get_property_declarations(); /// bool set_void(const std::string& property, const std::string& value_type, const void* value_ptr); /// bool get_void(const std::string& property, const std::string& value_type, void* value_ptr); /// return whether the factory can only generate one instance of the given type bool is_singleton_factory() const; /// return pointer to singleton base_ptr get_singleton() const; /// release the singleton pointer void release_singleton(); /// overload to create an object base_ptr create_object(); /// overload to create an object virtual base_ptr create_object_impl() = 0; }; /// implementation of factory for objects of type T using the standard constructor template struct factory_impl : public factory { inline factory_impl(const std::string& _created_type_name, bool _is_singleton = false, const std::string& _object_options = "") : factory(_created_type_name, _is_singleton, _object_options) {} inline base_ptr create_object_impl() { return base_ptr(new T()); } std::string get_type_name() const { return std::string("factory_impl<")+get_created_type_name()+">"; } }; /// implementation of factory for objects of type T using a constructor with one argument of type CA template struct factory_impl_1 : public factory { CA ca; inline factory_impl_1(CA _ca, const std::string& _created_type_name, bool is_singleton = false, const std::string& _object_options = "") : factory(_created_type_name, is_singleton, _object_options), ca(_ca) {} inline base_ptr create_object_impl() { return base_ptr(new T(ca)); } std::string get_type_name() const { return std::string("factory_impl_1<")+get_created_type_name()+">"; } }; /// implementation of factory for objects of type T using a constructor with two arguments of types CA1 and CA2 template struct factory_impl_2 : public factory { CA1 ca1; CA2 ca2; inline factory_impl_2(CA1 _ca1, CA2 _ca2, const std::string& _created_type_name, bool is_singleton = false, const std::string& _object_options = "") : factory(_created_type_name, is_singleton, _object_options), ca1(_ca1), ca2(_ca2) {} inline base_ptr create_object_impl() { return base_ptr(new T(ca2)); } std::string get_type_name() const { return std::string("factory_impl_2<")+get_created_type_name()+">"; } }; extern std::string CGV_API guess_created_type_name(const char* item_text); extern void CGV_API register_factory_object(base_ptr fo, const char* item_text, char shortcut); /// convenience class to register a factory of the given class type template struct factory_registration { //! this registers an instance of the default factory implementation /*! parameters: - \c _created_type_name ... name of the type of the instances created by the factory - \c _options ... semicolon separated options used to register the factory. For gui integration these can include assignments to "menu_path" and "shortcut" - \c _is_singleton ... whether the factory can create only one instance - \c _object_options ... options used to register created instances */ factory_registration(const std::string& _created_type_name, const std::string& _options = "", bool _is_singleton = false, const std::string& _object_options = "") { register_object(new factory_impl(_created_type_name, _is_singleton, _object_options), _options); } //! this constructor is only provided for downward compatibility and should not be used anymore. /*! Item text and shortcut can be specified in the option string via "menu_path=\"geometry/sphere\";shortcut='Q'". */ factory_registration(const char* item_text, char shortcut, bool is_singleton = false) { register_factory_object(new factory_impl(guess_created_type_name(item_text), is_singleton), item_text, shortcut); } }; /// convenience class to register a factory of the given class type that uses a constructor with one argument of type CA template struct factory_registration_1 { //! this registers an instance of a standard factory implementation /*! parameters: - \c _ca ... argument passed to the constructor of the created instances - \c _created_type_name ... name of the type of the instances created by the factory - \c _options ... semicolon separated options used to register the factory. For gui integration these can include assignments to "menu_path" and "shortcut" - \c _is_singleton ... whether the factory can create only one instance - \c _object_options ... options used to register created instances */ factory_registration_1(const std::string& _created_type_name, const CA& _ca, const std::string& _options = "", bool _is_singleton = false, const std::string& _object_options = "") { register_object(new factory_impl_1(_ca, _created_type_name, _is_singleton, _object_options), _options); } //! this constructor is only provided for downward compatibility and should not be used anymore. /*! Item text and shortcut can be specified in the option string via "menu_path=\"geometry/sphere\";shortcut='Q'". */ factory_registration_1(const char* item_text, char shortcut, const CA& _ca, bool is_singleton = false) { register_factory_object(new factory_impl_1(_ca, guess_created_type_name(item_text), is_singleton), item_text, shortcut); } }; /// convenience class to register a factory of the given class type that uses a constructor with one argument of type CA template struct factory_registration_2 { //! this registers an instance of a standard factory implementation /*! parameters: - \c _ca1, \c _ca2 ... arguments passed to the constructor of the created instances - \c _created_type_name ... name of the type of the instances created by the factory - \c _options ... semicolon separated options used to register the factory. For gui integration these can include assignments to "menu_path" and "shortcut" - \c _is_singleton ... whether the factory can create only one instance - \c _object_options ... options used to register created instances */ factory_registration_2(const std::string& _created_type_name, const CA1& _ca1, const CA2& _ca2, const std::string& _options = "", bool _is_singleton = false, const std::string& _object_options = "") { register_object(new factory_impl_2(_ca1, _ca2, _created_type_name, _is_singleton, _object_options), _options); } }; //@} /**@name test registration */ //@{ /// structure used to register a test function class CGV_API test : public base { public: /// static counter for all tests static int nr_failed; protected: /// name of test function std::string test_name; /// pointer to test function bool (*test_func)(); public: /// constructor for a test structure test(const std::string& _test_name, bool (*_test_func)()); /// implementation of the type name function of the base class std::string get_type_name() const; /// access to name of test function std::string get_test_name() const; /// execute test and return whether this was successful bool exec_test() const; }; /// use this macro in a test function to check whether expression V is true #define TEST_ASSERT(V) \ if (!(V)) { \ std::cerr << "\n" << __FILE__ << "(" << __LINE__ << ") : error: test failure" << std::endl; \ ++cgv::base::test::nr_failed; \ } /// use this macro in a test function to check whether the two expression V and Q are equal #define TEST_ASSERT_EQ(V,Q) \ if ((V) != (Q)) { \ std::cerr << "\n" << __FILE__ << "(" << __LINE__ << ") : error: test failure " << (V) << "!=" << (Q) << std::endl; \ ++cgv::base::test::nr_failed; \ } /// declare an instance of test_registration as static variable in order to register a test function in a test plugin struct CGV_API test_registration { /// the constructor creates a test structure and registeres the test test_registration(const std::string& _test_name, bool (*_test_func)()); }; //@} /**@name resource file registration */ //@{ /// information registered with each resource file struct CGV_API resource_file_info { /// at which location the resource file starts within the executable or dll unsigned int file_offset; /// length of the resource file in bytes unsigned int file_length; /// pointer to const char* file_data; /// name of std::string source_file; /// construct resource file info resource_file_info( unsigned int _file_offset = 0, unsigned int _file_length = 0, const char* _file_data = 0, const std::string& _source_file = ""); }; /// return a reference to a mapping of resource file names to resource file infos extern CGV_API std::map& ref_resource_file_map(); /// register a resource file extern CGV_API void register_resource_file(const std::string& file_path, unsigned int file_offset, unsigned int file_length, const char* file_data, const std::string& source_file = ""); /// convenience class to register a resource file struct CGV_API resource_file_registration { /// builds a resource file info and registers it with the register_resource_file function resource_file_registration(const char* symbol); }; //@} /**@name processing of commands*/ //@{ //! process a command. /*! Return whether the command was processed correctly. If eliminate_quotes is set to true, quotes around the command arguments are eliminated. This feature is used for commands specified on the command line, where spaces in the command arguments would split one command into pieces. Quotes are used then to protect the command from splitting. The following commands are supported: - show all ... print out information on all registered objects - plugin:file_name ... read a plugin - config:file_name ... read a config file - gui:file_name ... read a gui description file - name(xxx):assignment list ... find registered object by name xxx and process assignments on them - type(yyy):assignment list ... find registered object by type yyy and process assignments on them The assigment list in the name and type commands are of the form: member_name_1=value_1;member_name_2=value_2;... */ extern bool CGV_API process_command(const std::string& cmd, bool eliminate_quotes = true); /// show information about all registered members extern void CGV_API show_all(); //@} /**@name processing of command line arguments*/ //@{ //! set the file name of the current program. /*! simply pass argv[0] in the main procedure. This is done automatically in the process_command_line_args function.*/ extern CGV_API void register_prog_name(const char* prog_name); /// return a refence to the name of the started executable extern CGV_API std::string& ref_prog_name(); /// process the command line arguments: extract program name and load all plugins extern CGV_API void process_command_line_args(int argc, char** argv); //@} /**@name configuration and gui files*/ //@{ //! abstract interface for observers of config files. /*! The typically used implementation is found in the cgv_gui library.*/ struct config_file_observer { /// to be implemented method that adds permanent registration for a list of property assignments virtual void multi_observe(base_ptr bp, const std::string& property_assignments, unsigned off) = 0; }; //! abstract interface for a config file driver that handles permanent registration and gui config files. /*! The typically used implementation is found in the cgv_gui library.*/ struct config_file_driver { public: /// create or find a config_file_observer from the given file name and the read content of the config file virtual config_file_observer* find_config_file_observer(const std::string& file_name, const std::string& content) = 0; /// process a gui file virtual bool process_gui_file(const std::string& file_name) = 0; }; /// method to register a config_file_driver extern CGV_API void register_config_file_driver(config_file_driver* cfd); /// in case permanent registration is active, look for a registered object by name extern named_ptr CGV_API find_object_by_name(const std::string& name); /// in case permanent registration is active, look for a registered object by type name extern base_ptr CGV_API find_object_by_type(const std::string& type_name); /// interpret a config file extern bool CGV_API process_config_file(const std::string& file_name); /// interpret a gui file extern bool CGV_API process_gui_file(const std::string& file_name); //@} /**@name loading of plugins*/ //@{ //! load a plugin or dll and return a handle to the plugin, or 0 if loading was not successful. /*! During plugin loading the registration is always disabled in order to avoid deadlocks that can arise when a registered object triggers loading of another dll.*/ extern CGV_API void* load_plugin(const std::string& file_name); /// return a reference to the currently loaded plugin extern CGV_API std::string& ref_plugin_name(); /// unload the plugin with the given handle extern CGV_API bool unload_plugin(void* handle); //@} } } #include