Changes between Version 1 and Version 2 of Support/KnowledgeBase/SerializationSupport

Show
Ignore:
Timestamp:
02/04/10 16:58:25 (5 years ago)
Author:
bthrall (IP: 68.93.203.30)
Comment:

Some formatting improvements

Legend:

Unmodified
Added
Removed
Modified
  • Support/KnowledgeBase/SerializationSupport

    v1 v2  
    11The "second-generation" OSG format is introduced at the beginning of the year 2010, which is serialized, easy to extend, cross-format, and will be continuous updated to support all native OSG libraries. 
    22 
    3 The format reader writer plugin is located at src/osgPlugins/osg/ReaderWriterOSG2.cpp and wrappers at src/osgWrappers/serializers. 
    4  
    5 It supports two extensions at present:: 
    6 * .osgb The binary format 
    7 * .osgt The ascii format 
    8  
    9 Supported options are:: 
    10 * !WriteImageHint=<hint> 
    11 (Export option) Hint of writing image to stream. 
    12   * <!IncludeData> writes Image::data() directly; 
    13   * <!IncludeFile> writes the image file itself to stream; 
    14   * <!UseExternal> writes only the filename; 
    15   * <!WriteOut> writes Image::data() to disk as external file. 
    16 The first two hints only affect binary formats. By default, the image writer will check osg::Image::getWriteHint() to decide if save data or only the filename. 
    17  
    18 * Compressor=<name> 
    19 (Export option) Use an inbuilt or user-defined compressor to encode the stream. These only affect binary formats. 
    20  
    21 * !SchemaFile=<file> 
    22 (Import/Export option) Record an ascii schema file of writing properties orders, and use it while reading if necessary. 
    23  
    24 * ForceReadingImage 
    25 (Import option) Load an empty image with specified filename instead if required file missed. This is useful when converting from other formats. Image information won't be erased even without the external reference. 
    26  
    27 * Ascii 
    28 (Import/Export option) By default, the reading/writing format is guessed from the extension, and this option will force using the ascii format directly. 
    29  
    30 Main features:: 
    31 * Serialization I/O: Serialization is used for writing objects into memory buffer and "resurrected" them in the same or another computer environment, enabling simple and common input/output interfaces to be utilized. See osgDB/Serializer header for details. 
    32  
    33 * Binary/ascii file format: A dual binary/ascii format is supported based on different implementations of I/O classes in the osgDB/!StreamOperator header. These implementations could be found at osgPlugins/osg directory. The cross-format compatibility is provided by the object wrappers and their reader/writer classes. 
    34  
    35 * Object wrappers: Every class in the scene graph should have a corresponding wrapper, in which a series of templated serializers are used to bind reading and writing members. The wrapper should record all necessary setting/getting members of the object class, as well as the I/O order of these properties. See osgDB/!ObjectWrapper header for details. 
    36  
    37 * Compressors and decompressors: The compressor is used while the whole scene graph is already recorded, to reduce data size and encrypt the result buffer for variant reasons. A decompressor method should also be provided for decoding. See the osgDB/!ObjectWrapper header again. And the total output/input managers are declared in osgDB/!OutputStream and osgDB/!InputStream headers. 
    38  
    39 * Extendability: The object wrappers and compressors are always extendable. You may easily write wrappers for user-customized class derived from osg::Object base class and load them from applications or dynamic libraries. The wrapper may contain a series of predefined and custom serializers. 
    40  
    41 * Schema Definitions: The sequence of a class' properties is recorded in its wrapper class. These sequences could be write out as a "schema" list, which indicates the reading/writing orders of all existing classes in current OSG version. The schema may be used to force resort wrappers in another environment. According to the schema, any unrecognizable property name and disrupted orders will be automatically fixed while reading an external file. These will help applications to be backwards and forward compatible. 
     3The format reader writer plugin is located at `src/osgPlugins/osg/ReaderWriterOSG2.cpp` and wrappers at `src/osgWrappers/serializers`. 
     4 
     5It supports two extensions at present: 
     6 * `.osgb` The binary format 
     7 * `.osgt` The ascii format 
     8 
     9Supported options are: 
     10  * `WriteImageHint=<hint>` (Export option) Hint of writing image to stream. 
     11  * `<IncludeData>` writes Image::data() directly; 
     12  * `<IncludeFile>` writes the image file itself to stream; 
     13  * `<UseExternal>` writes only the filename; 
     14  * `<WriteOut>` writes Image::data() to disk as external file. 
     15The first two hints only affect binary formats. By default, the image writer will check `osg::Image::getWriteHint()` to decide if save data or only the filename. 
     16 
     17 * `Compressor=<name>` (Export option) Use an inbuilt or user-defined compressor to encode the stream. These only affect binary formats. 
     18 
     19 * `SchemaFile=<file>` (Import/Export option) Record an ascii schema file of writing properties orders, and use it while reading if necessary. 
     20 
     21 * `ForceReadingImage` (Import option) Load an empty image with specified filename instead if required file missed. This is useful when converting from other formats. Image information won't be erased even without the external reference. 
     22 
     23 * `Ascii` (Import/Export option) By default, the reading/writing format is guessed from the extension, and this option will force using the ascii format directly. 
     24 
     25Main features: 
     26 * '''Serialization I/O''': Serialization is used for writing objects into memory buffer and "resurrected" them in the same or another computer environment, enabling simple and common input/output interfaces to be utilized. See `osgDB/Serializer` header for details. 
     27 
     28 * '''Binary/ascii file format''': A dual binary/ascii format is supported based on different implementations of I/O classes in the `osgDB/StreamOperator` header. These implementations could be found at `osgPlugins/osg` directory. The cross-format compatibility is provided by the object wrappers and their reader/writer classes. 
     29 
     30 * '''Object wrappers''': Every class in the scene graph should have a corresponding wrapper, in which a series of templated serializers are used to bind reading and writing members. The wrapper should record all necessary setting/getting members of the object class, as well as the I/O order of these properties. See `osgDB/ObjectWrapper` header for details. 
     31 
     32 * '''Compressors and decompressors''': The compressor is used while the whole scene graph is already recorded, to reduce data size and encrypt the result buffer for variant reasons. A decompressor method should also be provided for decoding. See the `osgDB/ObjectWrapper` header again. And the total output/input managers are declared in `osgDB/OutputStream` and `osgDB/InputStream` headers. 
     33 
     34 * '''Extendability''': The object wrappers and compressors are always extendable. You may easily write wrappers for user-customized class derived from `osg::Object` base class and load them from applications or dynamic libraries. The wrapper may contain a series of predefined and custom serializers. 
     35 
     36 * '''Schema Definitions''': The sequence of a class' properties is recorded in its wrapper class. These sequences could be write out as a "schema" list, which indicates the reading/writing orders of all existing classes in current OSG version. The schema may be used to force resort wrappers in another environment. According to the schema, any unrecognizable property name and disrupted orders will be automatically fixed while reading an external file. These will help applications to be backwards and forward compatible. 
    4237 
    4338== A quick start guide == 
    4439 
    45 1.1 Make use of osgconv:: 
     40=== 1.1 Make use of osgconv === 
    4641 
    4742The osgconv will help us quickly realize all the features of the new OSG2 format. The commands below will generate and render a binary cow model: 
     
    5954To write out with specified writing image hint: 
    6055{{{ 
    61 # ./osgconv cow.osg cow.osgb -O !WriteImageHint=!IncludeData 
     56# ./osgconv cow.osg cow.osgb -O WriteImageHint=IncludeData 
    6257# ./osgviewer cow.osgb 
    6358}}} 
     
    7570}}} 
    7671 
    77 1.2 In your applications:: 
    78  
    79 The required plugin is osgdb_osg2.so (.dll), and related wrappers are recorded in different osgdb_serializers_* libraries. And user compressors and decompressors may be saved in a osgdb_compressor_* library. 
     72=== 1.2 In your applications === 
     73 
     74The required plugin is `osgdb_osg2.so` (`.dll`), and related wrappers are recorded in different `osgdb_serializers_*` libraries. And user compressors and decompressors may be saved in a `osgdb_compressor_*` library. 
    8075 
    8176To read node file directly: 
     
    8479}}} 
    8580 
    86 To write the scene into a binary file, with the "WriteImageHint" and "Compressor" option: 
     81To write the scene into a binary file, with the "!WriteImageHint" and "Compressor" option: 
    8782{{{ 
    8883osgDB::writeNodeFile(*node, "cow.osgb", new osgDB::Options("WriteImageHint=IncludeData Compressor=zlib")); 
     
    110105== How to write extended wrappers == 
    111106 
    112 2.1 Basic structure:: 
     107=== 2.1 Basic structure === 
    113108 
    114109A wrapper completely and correctly records all necessary properties of a scene object and its proto. In the reading process, the wrapper will create a clone from the proto, reread properties and add it to the proper position in the scene graph. 
     
    131126}}} 
    132127 
    133 A lot of macrodefinitions are used here to provide an easy to read structure. REGISTER_OBJECT_WRAPPER will automatically add the wrapper to a global manager at initial time. And the ADD_*_SERIALIZER statements will bring different serializers for reading/writing class members in sequence of names, which may be output as part of schema file. 
    134  
    135 Notice that the "osg::" prefix in the inheritance string is important. It indicates the system that osgdb_serializers_osg.so library should be loaded and all its wrappers will be put into use. A different namespace, like osgParticle, will cause a different library to be loaded and made use of. 
    136  
    137 2.2 Predefined serializers:: 
    138  
    139 Obviously, the ADD_BOOL_SERIALIZER(CullingActive) above is sure to call setCullingActive() and getCullingActive() methods of osg::Node class to set/get a boolean property. and ADD_HEXINT_SERIALIZER(NodeMask) similarly calls setNodeMask() and getNodeMask() to operate on an integer one. There are some more predefined serializers to do such repeated work, on the premise that the class methods' naming styles are acceptable. 
    140  
    141 * ADD_BOOL_SERIALIZER( NAME, DEF ) 
    142 Input/output with __void setNAME(bool)__ and __bool getNAME() const__ methods. DEF is the default value of the proto, which will not be saved into files. 
    143  
    144 * ADD_SHORT_SERIALIZER( NAME, DEF ) 
    145 Input/output with __void setNAME(short)__ and __short getNAME() const__ methods. 
    146  
    147 * ADD_USHORT_SERIALIZER( NAME, DEF ) 
    148 Input/output with __void setNAME(unsigned short)__ and __unsigned short getNAME() const__ methods. 
    149  
    150 * ADD_HEXSHORT_SERIALIZER( NAME, DEF ) 
    151 Same as ADD_USHORT_SERIALIZER, but use hex values instead. 
    152  
    153 * ADD_USHORT_SERIALIZER( NAME, DEF ) 
    154 Input/output with __void setNAME(unsigned short)__ and __unsigned short getNAME() const__ methods. 
    155  
    156 * ADD_INT_SERIALIZER( NAME, DEF ) 
    157 Input/output with __void setNAME(int)__ and __int getNAME() const__ methods. 
    158  
    159 * ADD_UINT_SERIALIZER( NAME, DEF ) 
    160 Input/output with __void setNAME(unsigned int)__ and __unsigned int getNAME() const__ methods. 
    161  
    162 * ADD_HEXINT_SERIALIZER( NAME, DEF ) 
    163 Same as ADD_UINT_SERIALIZER, but use hex values instead. 
    164  
    165 * ADD_FLOAT_SERIALIZER( NAME, DEF ) 
    166 Input/output with __void setNAME(float)__ and __float getNAME() const__ methods. 
    167  
    168 * ADD_DOUBLE_SERIALIZER( NAME, DEF ) 
    169 Input/output with __void setNAME(double)__ and __double getNAME() const__ methods. 
    170  
    171 * ADD_VEC3F_SERIALIZER( NAME, DEF ) 
    172 Input/output with __void setNAME(const Vec3f&)__ and __const Vec3f& getNAME() const__ methods. 
    173  
    174 * ADD_VEC3D_SERIALIZER( NAME, DEF ) 
    175 Input/output with __void setNAME(const Vec3d&)__ and __const Vec3d& getNAME() const__ methods. 
    176  
    177 * ADD_VEC3_SERIALIZER( NAME, DEF ) 
    178 Same as ADD_VEC3F_SERIALIZER. 
    179  
    180 * ADD_VEC4F_SERIALIZER( NAME, DEF ) 
    181 Input/output with __void setNAME(const Vec4f&)__ and __const Vec4f& getNAME() const__ methods. 
    182  
    183 * ADD_VEC4D_SERIALIZER( NAME, DEF ) 
    184 Input/output with __void setNAME(const Vec4d&)__ and __const Vec4d& getNAME() const__ methods. 
    185  
    186 * ADD_VEC4_SERIALIZER( NAME, DEF ) 
    187 Same as ADD_VEC4F_SERIALIZER. 
    188  
    189 * ADD_QUAT_SERIALIZER( NAME, DEF ) 
    190 Input/output with __void setNAME(const Quat&)__ and __const Quat& getNAME() const__ methods. 
    191  
    192 * ADD_PLANE_SERIALIZER( NAME, DEF ) 
    193 Input/output with __void setNAME(const Plane&)__ and __const Plane& getNAME() const__ methods. 
    194  
    195 * ADD_MATRIXF_SERIALIZER( NAME, DEF ) 
    196 Input/output with __void setNAME(const Matrixf&)__ and __const Matrixf& getNAME() const__ methods. 
    197  
    198 * ADD_MATRIXD_SERIALIZER( NAME, DEF ) 
    199 Input/output with __void setNAME(const Matrixd&)__ and __const Matrixd& getNAME() const__ methods. 
    200  
    201 * ADD_MATRIX_SERIALIZER( NAME, DEF ) 
    202 Input/output with __void setNAME(const Matrix&)__ and __const Matrix& getNAME() const__ methods. 
    203  
    204 * ADD_STRING_SERIALIZER( NAME, DEF ) 
    205 Input/output with __void setNAME(const std::string&)__ and __const std::string& getNAME() const__ methods. 
    206  
    207 * ADD_GLENUM_SERIALIZER( NAME, TYPE, DEF ) 
    208 Input/output with __void setNAME(TYPE)__ and __TYPE getNAME() const__ methods. TYPE here could be GLenum, GLbitfield, GLint and so on, to fit different method parameters. In ascii format, this serializer gets numerical values and saves corresponding OpenGL enumeration names to the buffer, and read it back in the opposite way. For example, it will map GL_NEVER to the string "NEVER", and vice versa. 
    209  
    210 * ADD_OBJECT_SERIALIZER( NAME, TYPE, DEF ) 
    211 Input/output with __void setNAME(TYPE*)__ and __const TYPE* getNAME() const__ methods. This serializer is used to record another object attached, that is, the wrapper of another object class will be called inside current reading/writing function and cause iteration of functions. 
    212  
    213 * ADD_IMAGE_SERIALIZER( NAME, TYPE, DEF ) 
    214 Same as ADD_OBJECT_SERIALIZER, but only read osg::Image* and inherited instances. 
    215  
    216 * ADD_LIST_SERIALIZER( NAME, TYPE ) 
    217 Input/output with __void setNAME(const TYPE&)__ and __const TYPE& getNAME() const__ methods. TYPE should be a std::vector like typename, because the serializer will assume a TYPE::const_iterator internal to traverse all elements. 
    218  
    219 * BEGIN_ENUM_SERIALIZER( NAME, DEF ) 
    220 Input/output with __void setNAME(NAME)__ and __NAME getNAME() const__ methods. This is used only for enum values, and the enum name and methods' names should strictly obey the naming rules. Another two macros ADD_ENUM_VALUE and END_ENUM_SERIALIZER will be also used to form a complete serializer. For example, in the osg::Object wrapper: 
     128A lot of macro definitions are used here to provide an easy to read structure. `REGISTER_OBJECT_WRAPPER` will automatically add the wrapper to a global manager at initial time. And the `ADD_*_SERIALIZER` statements will bring different serializers for reading/writing class members in sequence of names, which may be output as part of schema file. 
     129 
     130Notice that the "osg::" prefix in the inheritance string is important. It indicates the system that `osgdb_serializers_osg.so` library should be loaded and all its wrappers will be put into use. A different namespace, like `osgParticle`, will cause a different library to be loaded and made use of. 
     131 
     132=== 2.2 Predefined serializers === 
     133 
     134Obviously, the `ADD_BOOL_SERIALIZER(CullingActive)` above is sure to call `setCullingActive()` and `getCullingActive()` methods of `osg::Node` class to set/get a boolean property. and `ADD_HEXINT_SERIALIZER(NodeMask)` similarly calls `setNodeMask()` and `getNodeMask()` to operate on an integer one. There are some more predefined serializers to do such repeated work, on the premise that the class methods' naming styles are acceptable. 
     135 
     136|| `ADD_BOOL_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(bool)__ and __bool getNAME() const__ methods. DEF is the default value of the proto, which will not be saved into files. || 
     137|| `ADD_SHORT_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(short)__ and __short getNAME() const__ methods. || 
     138|| `ADD_USHORT_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(unsigned short)__ and __unsigned short getNAME() const__ methods. || 
     139|| `ADD_HEXSHORT_SERIALIZER( NAME, DEF )` || Same as ADD_USHORT_SERIALIZER, but use hex values instead. || 
     140|| `ADD_USHORT_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(unsigned short)__ and __unsigned short getNAME() const__ methods. || 
     141|| `ADD_INT_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(int)__ and __int getNAME() const__ methods. || 
     142|| `ADD_UINT_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(unsigned int)__ and __unsigned int getNAME() const__ methods. || 
     143|| `ADD_HEXINT_SERIALIZER( NAME, DEF )` || Same as ADD_UINT_SERIALIZER, but use hex values instead. || 
     144|| `ADD_FLOAT_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(float)__ and __float getNAME() const__ methods. || 
     145|| `ADD_DOUBLE_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(double)__ and __double getNAME() const__ methods. || 
     146|| `ADD_VEC3F_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(const Vec3f&)__ and __const Vec3f& getNAME() const__ methods. || 
     147|| `ADD_VEC3D_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(const Vec3d&)__ and __const Vec3d& getNAME() const__ methods. || 
     148|| `ADD_VEC3_SERIALIZER( NAME, DEF )` || Same as ADD_VEC3F_SERIALIZER. || 
     149|| `ADD_VEC4F_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(const Vec4f&)__ and __const Vec4f& getNAME() const__ methods. || 
     150|| `ADD_VEC4D_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(const Vec4d&)__ and __const Vec4d& getNAME() const__ methods. || 
     151|| `ADD_VEC4_SERIALIZER( NAME, DEF )` || Same as ADD_VEC4F_SERIALIZER. || 
     152|| `ADD_QUAT_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(const Quat&)__ and __const Quat& getNAME() const__ methods. || 
     153|| `ADD_PLANE_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(const Plane&)__ and __const Plane& getNAME() const__ methods. || 
     154|| `ADD_MATRIXF_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(const Matrixf&)__ and __const Matrixf& getNAME() const__ methods. || 
     155|| `ADD_MATRIXD_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(const Matrixd&)__ and __const Matrixd& getNAME() const__ methods. || 
     156|| `ADD_MATRIX_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(const Matrix&)__ and __const Matrix& getNAME() const__ methods. || 
     157|| `ADD_STRING_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(const std::string&)__ and __const std::string& getNAME() const__ methods. || 
     158|| `ADD_GLENUM_SERIALIZER( NAME, TYPE, DEF )` || Input/output with __void setNAME(TYPE)__ and __TYPE getNAME() const__ methods. TYPE here could be `GLenum`, `GLbitfield`, `GLint` and so on, to fit different method parameters. In ascii format, this serializer gets numerical values and saves corresponding OpenGL enumeration names to the buffer, and read it back in the opposite way. For example, it will map `GL_NEVER` to the string "NEVER", and vice versa. || 
     159|| `ADD_OBJECT_SERIALIZER( NAME, TYPE, DEF )` || Input/output with __void setNAME(TYPE*)__ and __const TYPE* getNAME() const__ methods. This serializer is used to record another object attached, that is, the wrapper of another object class will be called inside current reading/writing function and cause iteration of functions. || 
     160|| `ADD_IMAGE_SERIALIZER( NAME, TYPE, DEF )` || Same as ADD_OBJECT_SERIALIZER, but only read osg::Image* and inherited instances. || 
     161|| `ADD_LIST_SERIALIZER( NAME, TYPE )` || Input/output with __void setNAME(const TYPE&)__ and __const TYPE& getNAME() const__ methods. TYPE should be a `std::vector` like typename, because the serializer will assume a TYPE::const_iterator internal to traverse all elements. || 
     162|| `ADD_USER_SERIALIZER( NAME )` || Add a user-customizied serializer, with at least 3 static user functions for checking, reading and writing properties. See Chapter 2.3 for details. || 
     163|| `BEGIN_ENUM_SERIALIZER( NAME, DEF )` || Input/output with __void setNAME(NAME)__ and __NAME getNAME() const__ methods. This is used only for enum values, and the enum name and methods' names should strictly obey the naming rules. Another two macros `ADD_ENUM_VALUE` and `END_ENUM_SERIALIZER` will be also used to form a complete serializer. || 
     164 
     165An example of `BEGIN_ENUM_SERIALIZER` is in the `osg::Object` wrapper: 
    221166{{{ 
    222167BEGIN_ENUM_SERIALIZER( DataVariance, UNSPECIFIED ); 
     
    227172}}} 
    228173 
    229 The enum type osg::Object::DataVariance has 3 values: STATIC, DYNAMIC and UNSPECIFIED (default). They are all recorded in the serializer and in ascii format, will be automatically mapped to strings "STATIC", "DYNAMIC" and "UNSPECIFIED". 
    230  
    231 Sometimes the enum type is not declared in the form of Class::NAME, and the BEGIN_ENUM_SERIALIZER will failed then. Use BEGIN_ENUM_SERIALIZER2 instead at this time, for example: 
     174The enum type `osg::Object::DataVariance` has 3 values: `STATIC`, `DYNAMIC` and `UNSPECIFIED` (default). They are all recorded in the serializer and in ascii format, will be automatically mapped to strings "STATIC", "DYNAMIC" and "UNSPECIFIED". 
     175 
     176Sometimes the enum type is not declared in the form of `Class::NAME`, and the `BEGIN_ENUM_SERIALIZER` will failed then. Use `BEGIN_ENUM_SERIALIZER2` instead at this time, for example: 
    232177{{{ 
    233178BEGIN_ENUM_SERIALIZER2( Hint, osg::Multisample::Mode, DONT_CARE ); 
     
    238183}}} 
    239184 
    240 Here the binded methods are __void setHint(osg::Multisample::Mode)__ and __osg::Multisample::Mode getHint() const__. 
    241  
    242 * ADD_USER_SERIALIZER( NAME ) 
    243 Add a user-customizied serializer, with at least 3 static user functions for checking, reading and writing properties. See chapter 2.3 for details. 
     185Here the bound methods are __void setHint(osg::Multisample::Mode)__ and __osg::Multisample::Mode getHint() const__. 
    244186 
    245187With the predefinied serializers, we may easily add wrappers for most simple classes. A simple example is listed below: 
     
    256198}}} 
    257199 
    258 With no more than 10 lines, the osg::Box class wrapper is finished! In binary mode, it will be saved as a series of float and double values in bits. In ascii mode, the output text may look like: 
     200With no more than 10 lines, the `osg::Box` class wrapper is finished! In binary mode, it will be saved as a series of float and double values in bits. In ascii mode, the output text may look like: 
    259201{{{ 
    260202osg::Box { 
     
    267209}}} 
    268210 
    269 The properties of osg::Shape and osg::Object will also be recorded, unless they are not motioned in the inheritance string. 
    270  
    271 2.3 Custom serializers:: 
    272  
    273 There are often some member methods that should be recorded but don't obey all above naming rules for some reason. For instance, the setTextureAttribute() and getTextureAttribute() pairs of the osg::StateSet class. Both methods have an extra incoming parameter "unit" and can't be accepted by any prebuilt serializers. In this case, ADD_USER_SERIALIZER will be required to help. 
    274  
    275 Take the osg::Group wrapper as an example. A Group has multiple child nodes, but it doesn't have a setChildren() or getChildren() method. So a custom serializer writing children into files and reading them back is generated as below: 
     211The properties of `osg::Shape` and `osg::Object` will also be recorded, unless they are not motioned in the inheritance string. 
     212 
     213=== 2.3 Custom serializers === 
     214 
     215There are often some member methods that should be recorded but don't obey all above naming rules for some reason. For instance, the `setTextureAttribute()` and `getTextureAttribute()` pairs of the `osg::StateSet` class. Both methods have an extra incoming parameter "unit" and can't be accepted by any prebuilt serializers. In this case, `ADD_USER_SERIALIZER` will be required to help. 
     216 
     217Take the `osg::Group` wrapper as an example. A `Group` has multiple child nodes, but it doesn't have a `setChildren()` or `getChildren()` method. So a custom serializer writing children into files and reading them back is generated as below: 
    276218{{{ 
    277219static bool checkChildren( const osg::Group& node ); 
     
    288230}}} 
    289231 
    290 The ADD_USER_SERIALIZER macro, named "Children" and work for osg::Group class, will look for 3 static global functions in compile-time: 
    291 * __bool checkChildren(const osg::Group&)__ is used to check if the property should be recorded or not this time. Null pointers, default initial values, and 0 sized lists could always be ignored and not written to files. To tell the serializer to continue writing the binded property, return TRUE, otherwise FALSE. 
     232The `ADD_USER_SERIALIZER` macro, named "Children" and work for `osg::Group` class, will look for 3 static global functions in compile-time: 
     233 * __bool checkChildren(const osg::Group&)__ is used to check if the property should be recorded or not this time. Null pointers, default initial values, and 0 sized lists could always be ignored and not written to files. To tell the serializer to continue writing the bound property, return TRUE, otherwise FALSE. 
    292234{{{ 
    293235return node.getNumChildren()>0;  // Continue only if there is any child node to write 
    294236}}} 
    295237 
    296 * __bool writeChildren(osgDB::OutputStream&, const osg::Group&)__ is going to save the property to buffer with the OutputStream manager. It would usually call the getChild() function and write out child objects in a loop. Return TRUE if all is normal. 
     238 * __bool writeChildren(osgDB::!OutputStream&, const osg::Group&)__ is going to save the property to buffer with the `OutputStream` manager. It would usually call the getChild() function and write out child objects in a loop. Return TRUE if all is normal. 
    297239{{{ 
    298240unsigned int size = node.getNumChildren(); 
     
    306248}}} 
    307249 
    308 * __bool readChildren(osgDB::InputStream&, osg::Group&)__ is going to read data from the InputStream manager and set to the Group instance, using the addChild() method here. Return TRUE if there is nothing to warn during reading. 
     250 * __bool readChildren(osgDB::!InputStream&, osg::Group&)__ is going to read data from the `InputStream` manager and set to the `Group` instance, using the `addChild()` method here. Return `TRUE` if there is nothing to warn during reading. 
    309251{{{ 
    310252unsigned int size = 0; is >> size >> osgDB::BEGIN_BRACKET; 
     
    318260}}} 
    319261 
    320 The OutputStream accepts << operators on common data types directly. And you may use writeObject(), writeImage(), writePrimitiveSet() and writeArray() to apply specified OSG objects. Similarly, the InputStream could use >> operators, readObject(), readImage(), readPrimitiveSet() and readArray() to reread data from files and data buffer. 
    321  
    322 You will also notice that BEGIN_BRACKET and END_BRACKET macrodefinitions are used here. Actually, they tell there will be a bracket to indicate indentation and following subitems. Another useful helper macro is PROPERTY, which is used to mark out a property name and automatically check it while reading. PROPERTY is also planned to be used in XML mode later. 
     262The `OutputStream` accepts `<<` operators on common data types directly. And you may use `writeObject()`, `writeImage()`, `writePrimitiveSet()` and `writeArray()` to apply specified OSG objects. Similarly, the `InputStream` could use `>>` operators, `readObject()`, `readImage()`, `readPrimitiveSet()`` and `readArray()` to reread data from files and data buffer. 
     263 
     264You will also notice that `BEGIN_BRACKET` and `END_BRACKET` macrodefinitions are used here. Actually, they tell there will be a bracket to indicate indentation and following subitems. Another useful helper macro is `PROPERTY`, which is used to mark out a property name and automatically check it while reading. `PROPERTY` is also planned to be used in XML mode later. 
    323265 
    324266In ascii mode, such an output: 
     
    350292}}} 
    351293 
    352 '''Caution:''' the PROPERTY and std::string contents should not have any space inside, if work with << and >> operators. That is because the input stream will use spaces as separators and thus breaks the string itself and the reading order. Use writeWrappedString() and readWrappedString() instead. 
    353  
    354 The BEGIN_BRACKET, END_BRACKET and PROPERTY macros have no effects in binary mode. 
     294'''Caution:''' the `PROPERTY` and `std::string` contents should not have any space inside, if work with `<<` and `>>` operators. That is because the input stream will use spaces as separators and thus breaks the string itself and the reading order. Use `writeWrappedString()` and `readWrappedString()` instead. 
     295 
     296The `BEGIN_BRACKET`, `END_BRACKET` and `PROPERTY` macros have no effects in binary mode. 
    355297 
    356298There are some more convenience functions and macros for custom serializer programmers: 
    357 * __InputStream::matchString(const std::string&)__ checks if next token in the input stream matches its parameter. If not, it will rollback. This method only works in ascii mode. 
    358  
    359 * __InputStream::advanceToCurrentEndBracket()__ will keep reading and discarding data until it meets a END_BRACKET which is believed to end current block. This method only works in ascii mode. 
    360  
    361 * __InputStream::throwException(const std::string&)__ and __OutputStream::throwException(const std::string&)__ will throw a fatal exception and stop the reading/writing processes. 
    362  
    363 * __BEGIN_USER_TABLE__ macro is useful for user serializers to obtain a similar capacity of BEGIN_ENUM_SERIALIZER. You may define an enumeration table, a global read function and a write function, and use them to map values to strings in ascii mode. For example, 
     299 * __InputStream::matchString(const std::string&)__ checks if next token in the input stream matches its parameter. If not, it will rollback. This method only works in ascii mode. 
     300 
     301 * __InputStream::advanceToCurrentEndBracket()__ will keep reading and discarding data until it meets a `END_BRACKET` which is believed to end current block. This method only works in ascii mode. 
     302 
     303 * __InputStream::throwException(const std::string&)__ and __OutputStream::throwException(const std::string&)__ will throw a fatal exception and stop the reading/writing processes. 
     304 
     305 * __BEGIN_USER_TABLE__ macro is useful for user serializers to obtain a similar capacity of `BEGIN_ENUM_SERIALIZER`. You may define an enumeration table, a global read function and a write function, and use them to map values to strings in ascii mode. For example, 
    364306{{{ 
    365307BEGIN_USER_TABLE( Mode, osg::PolygonMode ); 
     
    384326}}} 
    385327 
    386 2.4 Custom compressor/decompressor:: 
    387  
    388 We have already had a zlib compressor, which is defined in src/osgDB/Compressor.cpp. But we could easily extend user compressors, with only two virtual functions overrided. 
    389  
    390 The example source code below will simply add an author information at the first of each result file. Note that REGISTER_COMPRESSOR macro should be declared somewhere. 
     328=== 2.4 Custom compressor/decompressor === 
     329 
     330We have already had a zlib compressor, which is defined in `src/osgDB/Compressor.cpp`. But we could easily extend user compressors, with only two virtual functions overrided. 
     331 
     332The example source code below will simply add an author information at the first of each result file. Note that `REGISTER_COMPRESSOR` macro should be declared somewhere. 
    391333{{{ 
    392334class TestCompressor : public osgDB::BaseCompressor 
     
    432374}}} 
    433375 
    434 The new TestCompressor class could either be placed in user applications or an osgdb_compressor_test.so library. Use the command to work with binary formats. 
     376The new `TestCompressor` class could either be placed in user applications or an `osgdb_compressor_test.so` library. Use the command to work with binary formats. 
    435377{{{ 
    436378# ./osgconv cow.osg cow.osgb -O Compressor=test 
     
    440382== Todo == 
    441383 
    442 1. Go on finish all other osg core class wrappers, besides osg, osgText and osgParticle. And do comprehensive tests to put the new mechanism and plugin into public use as soon as possible. 
    443  
    444 2. Add support for XML, without big changes to current class wrappers. 
    445  
    446 3. Compress float arrays and integer arrays to reduce file sizes, if necessary. 
    447  
    448 4. Write wrapper properties schema to the header of binary files if needed. This will improve the compatibilities of files created by different !OpenSceneGraph versions. We could also keep inbuilt schema for each stable osg releases and match the binary file version automatically. 
    449  
    450 5. Consider a method to replace parts of the functionalities of osgIntrospection, which provides an introspection/reflection framework for runtime querying and calling of class properties. This may be done by serializers in a slightly different way now. 
    451  
    452 6. So, what is next? :) 
     384 1. Go on finish all other osg core class wrappers, besides osg, osgText and osgParticle. And do comprehensive tests to put the new mechanism and plugin into public use as soon as possible. 
     385 
     386 2. Add support for XML, without big changes to current class wrappers. 
     387 
     388 3. Compress float arrays and integer arrays to reduce file sizes, if necessary. 
     389 
     390 4. Write wrapper properties schema to the header of binary files if needed. This will improve the compatibilities of files created by different !OpenSceneGraph versions. We could also keep inbuilt schema for each stable osg releases and match the binary file version automatically. 
     391 
     392 5. Consider a method to replace parts of the functionalities of `osgIntrospection`, which provides an introspection/reflection framework for runtime querying and calling of class properties. This may be done by serializers in a slightly different way now. 
     393 
     394 6. So, what is next? :)