#################
Saving .red Files
#################


Before going any further, the first thing to do is to create a .red file:

.. include:: /tasks/ta_ca/ta_ca_file/tk_creating_a_red_file.rst

.. note:: 
    
  A file can be stored on disk or in memory depending on the method you used to create/load it through an abstraction provided by HOOPS Luminate: ``RED::IStream`` (see :doc:`/tasks/ta_ca/ta_ca_file/tk_creating_red_streams`).

File Header and Extra Information
*********************************

A file header (``RED::FileHeader``) is always present in a valid .red file. It gives information about the process which wrote the file and if data are encrypted or not. By default, you don't have anything to do to set this header and any .red file will be saved with default header values. Otherwise, you can set your own information by using ``RED::IREDFile::SetAuthor`` and ``RED::IREDFile::SetParentApplication``.

An additional optional chunk of information can be written to any .red file: the ``RED::FileInfo``. It gives extra information about the file content which can be seen as hints about how to process and render data. Notably, it contains a table of correspondence between ``RED::Object`` IDs and human readable names (``RED::FileInfo::GetIDToNamesMap``). 

Saving Data
***********

The most common usage of data saving in HOOPS Luminate is when you have a full set of data in memory (meshes, materials, lights, textures...) assembled in a DAG and want to make a file out of them (because you want to send the whole thing to a distant render server or just communicate with other developers or customers).

.. include:: /tasks/ta_ca/ta_ca_scenegraph/tk_streaming_a_dag_to_a_red_file.rst

But you also may want to save only a single data or just the things you want to by calling more atomic methods of the RED::IREDFile class (for an example, see :doc:`/tasks/ta_ca/ta_ca_image/tk_loading_and_saving_image_to_red_file`). 

You can also save your own data (not only RED ones) by declaring new chunks to the .red file format manager and adding support for them through callbacks. See under the section below **Extending the .red file format** for details.

The Streaming Policy
********************

The ``RED::StreamingPolicy`` describes the actions to take when loading or saving a RED file. This is where you can control the behaviour of the data encoders, the default actions to perform on loading unknown data, but also where you set some other miscellaneous informations. 

By default, every data is compressed in a .red file using a dedicated encoder. All the encoders perform lossless compression and are used only to try to get files with the minimal bytes size. As the encoder for geometry normals may be different from the one used for vertices, each encoder is associated to a geometry channel by default. Because your data may not be actually bound following the default HOOPS Luminate binding, you can override the encoders associations by using the ``RED::StreamingPolicy::SetChannelBinding`` method (which describes what data is expected on each geometry channel).

The ``RED::StreamingPolicy`` lets you also define a label which can be used to identify parts of a DAG which are roots of animation tracks. Because the .red file format supports saving and replaying of animations, you may need to distinguish between different animated parts and save them in separate animation tracks. This will be covered more in depth in this document in under the section below **Recording Animation Tracks**.

.. include:: /tasks/ta_ca/ta_ca_file/tk_defining_red_file_policy.rst


How to Save Encrypted .red Files?
*********************************

The .red file format supports encryption of data to make your file exchanges more secured. Encryption can be enabled at file creation time (RED::IREDFileCreate) by providing an encryption key: 

.. include:: /tasks/ta_ca/ta_ca_file/tk_save_encrypted_red_file.rst

Reloading of the file is as easy as saving it. See :doc:`/book/subjects/bk_rff/bk_redfileformat_load` under the section **How to Load Encrypted Files?** for detailed information about encrypted file reloading.

Recording Animation Tracks
**************************
 
The .red files can record results of animations (not the animation descriptions themselves). Saving an animated scene is slightly different than saving a static one. You need to first save your data in their initial state (at frame #0) by calling ``RED::IREDFile::WriteDAG`` for example. Then, for each frame of the animation, update the scene to reflect the current animation frame and dump the modifications to the file with that sequence of calls:

1. ``RED::IREDFile::WriteDAG`` ()
2. ``RED::IResourceManager::BeginState`` ()
3. Apply modifications to the data to match frame #
4. ``RED::IREDFile::WriteDynamic`` ()
5. ``RED::IResourceManager::EndState`` ()
6. Loop to 2. until animation ends


Each call to ``RED::IREDFile::WriteDynamic`` save the modifications applied to the data during the current transaction (``RED::State``).
 
*Saving Multiple Animation Tracks*

If your scene contains several distinct animated objects or if all the animations are not of the same length, you can choose to save your data as separate animation tracks. You have two choices here: either you save each animated object separately using the method above in the same file, or you save a unique DAG with all your objects linked to. In the second case, you must use a nomenclature to let HOOPS Luminate to detect automatically which part of the DAG refers to distinct animation tracks. The nomenclature is defined by a string label which is set to the ``RED::StreamingPolicy`` (using ``RED::StreamingPolicy::SetAnimationTrackLabel``). If a node in the DAG contains this label in its name (the check is case sensitive), the node and all its children are considered as being part of the same animation track. When ``RED::IREDFile::WriteDAG`` is called each sub-part of the DAG satisfying the nomenclature criterion will be discarded from the saving operation (the filtering is recursive).

Let's take the example of two animated spheres ("Sphere01" and "Sphere02") over a static plane ("Plane01"). If we set the animation track label to "Sphere" by calling ``RED::StreamingPolicy::SetAnimationTrackLabel``, the DAG will be structured as follows for saving:

.. figure:: rff_animation_tracks_label.png
    :align: center
    
    **Filtering of a DAG according to the animation track label.**

The output file will contain only one track made of the root linked to the node "Plane01", i.e. the part of the DAG which do not satisfy the set label and which are therefore considered as static (not animated). The two others tracks (the animated ones) must be saved explicitly by calling ``RED::IREDFile::WriteAnimationTrackDescriptor`` and RED::IREDFile::WriteDag on each track root (i.e. "Sphere01" and "Sphere02"). To save the two animation tracks, you need to run the process described above twice (one for each sub-DAG).

The resulting file will be made of three different DAGS with no more relationship between them:

.. figure:: rff_multiple_dags.png
    :align: center
    
    **The DAG after export to a .red file is cut in three parts.**

One more thing must be added to the file in order the loading process can re-assemble the original scene graph: you need to store the initial DAGs hierarchy. This is accomplished using the ``RED::FileInfo`` object by setting the tracks hierarchy parameter. This parameter is a map which gives the list of child node IDs for each DAG node ID (when relevant). In our example, it will look like a map with a single entry:

{ node Root ID, { node Sphere01 ID, node Sphere 02 ID } }

It's up to the loading process to take this map into account and to restore the initial hierarchy by looking for the node and link them back to their parents.

Extending the .red File Format
******************************

The .red file format can be extended by the user to save some custom data along with the RED ones. This is a two-step process: first a serializable custom class must be created which supports writing to a RED stream; second a callback must be declared which knows how read back data from a RED stream.

*Creating a Custom Serializable Class*

To make a class serializable to a .red file, it must  inherit from both ``RED::Object`` and ``RED::IChunkSaver``. The ``RED::IChunkSaver`` interface defines the prototype of the method which is called internally by RED to save ``RED::Object`` instances. Your class must also support the dynamic casting mechanism of RED. Some useful macros already exist in RED.h to let you declare the needed methods: ``SET_CID`` and ``IMPLEMENT_AS``. Finally, you need to define a unique chunk signature for the data to be saved and declare it with the macro ``SET_CHUNK_SIGNATURE``. Hence, your class declaration should look something like the following:

.. code:: cpp

  class MyClass : public RED::Object, public RED::IChunkSaver
  {
    public:
    
    // Typing information:
    // -------------------

    SET_CID( CID_class_MyClass ); IMPLEMENT_AS();
    SET_CHUNK_SIGNATURE( MyClass_signature );
  };

The *CID_class_MyClass* value describes your class as a unique identifier. You can take any value not already used in ``REDCID.h``. The *MyClass_signature* value defines the unique identifier of your class data chunk in a .red file. It can be modified to support new versions of your class in new versions of the .red file.

The ``IMPLEMENT_AS`` macro forces you to implement two dynamic casting methods:

.. code:: cpp

  virtual void* As( const RED::CID& iCID );
  virtual const void* As( const RED::CID& iCID ) const;


Here is an example of what it could look like:

.. code:: cpp

  void* MyClass::As( const RED::CID& type )
  {
    if( type == RED::MyClass::GetClassID() )
    {
      return this;
    }
    else if( type == RED::IChunkSaver::GetClassID() )
    {
      return (RED::IChunkSaver*)this;
    }

    return RED::Object::As( type );
  }


Now, let's define the saving method declared by the ``RED::IChunkSaver`` interface:

.. code:: cpp
    
  RED_RC MyClass::Save( RED::IStream*          iStream, 
                        RED::StreamingPolicy&  iPolicy,
                        int                    iState ) const
  {
    if( iStream == NULL )
      return RED_BAD_PARAM;

    // Store the current stream position.
    RED::uint64 strpos;
    RED_RC_ASSERT( iStream->GetCurrentPosition( strpos ) );

    // Chunk signature.
    RED_RC_ASSERT( iStream->WriteDWord( GetChunkSignature() ) );

    // Chunk size (unknown at that moment): written to reserve space in the stream.
    RED_RC_ASSERT( iStream->WriteDWord( 0 ) );
    RED_RC_ASSERT( iStream->WriteDWord( 0 ) );

    // Stream all your class data...
    // ...
    // ...

    // Write the whole chunk size field.
    RED::uint64 strpos2;
    RED_RC_ASSERT( iStream->GetCurrentPosition( strpos2 ) );

    // Set the stream position to the start of the chunk size field.
    RED_RC_ASSERT( iStream->Move( strpos + 4 ) );

    RED_RC_ASSERT( iStream->WriteDDWord( strpos2 - strpos - 12 ) );

    RED_RC_ASSERT( iStream->Move( strpos2 ) );

    return RED_OK;
  }


A .red file is made of chunks. Each chunk must start with its 32bit signature followed by the 64bit chunk size in bytes. This is mandatory in order HOOPS Luminate to be able to load back .red file. This is what the method above does. The only thing left to the programmer is the actual writing of the class data to the stream.

This is for the writing part. We now must say to HOOPS Luminate how to reload chunks of that type as it's not a built-in type. To do so, simply add the following macro to the declaration of your class:

.. code:: cpp
    
  class MyClass : public RED::Object, public RED::IChunkSaver
  {
    public:
    
    // Typing information:
    // -------------------

    SET_CID( CID_class_MyClass ); IMPLEMENT_AS();
    SET_CHUNK_SIGNATURE( MyClass_signature );

    // Macro below is for .red file reloading.
    IMPLEMENT_CHUNKINTERPRETER();
  };


This macro forces you to define an Interpret method in your class which follows the declaration of ``RED::IChunkInterpreterProto``. You now need to register this method to the ``RED::ChunkInterpretersDictionary`` class to let HOOPS Luminate automatically call it when chunks of that type are encountered in .red streams.

.. code:: cpp
  
  RED_RC_ASSERT( RED::ChunkInterpretersDictionary::RegisterChunkInterpreter( MyClass_signature, MyClass::Interpret ) );

The code of that method is quite simple:

.. code:: cpp
    
  RED_RC MyClass::Interpret( RED::IReferenceManager*     iReferenceManager,
                            RED::IStream*               iStream,
                            const RED::StreamingPolicy& iPolicy,
                            unsigned int                iChunkSignature,
                            RED::uint64			            iChunkSize,
                            RED::Object**               oResult,
                            const RED::State&           iState )
  {
    // Check input parameters.
    if( ( iReferenceManager == NULL ) ||
        ( iStream == NULL ) ||
        ( oResult == NULL ) )
      return RED_BAD_PARAM;

    // Allocate the returned instance if the method needs to return an object.
    MyClass* self = rnew MyClass();
    if( self == NULL )
      return RED_ALLOC_FAILURE;
    else
      *oResult = self;

    // Read the class data from the stream...
    // ...
    // ...

    return RED_OK;
  }


.. note:: 
    
  The reading code do not read back chunk information as they have already been read by HOOPS Luminate to identify the chunk and call the right Interpret callback. The 'iStream' pointer is then set to the very first byte of the chunk data (signature and chunk size excluded).

.. note:: 
    
  A complete example of a .red file format customisation can be found in :doc:`/tutorials/workflows/wf_misc/wf_saving_and_reloading_a_custom_container`.

