Controlling the Reading and Writing Process

Overview

In addition to the high-level read/write functions which support reading from and writing to a disk file, the HOOPS/Stream Toolkit also supports writing and reading HOOPS Stream File information to and from a user-specified location. This is a powerful feature which enables the application developer to store the HOOPS Stream File information within a custom application specific file format (or any location) and retrieve it from the custom location, rather than use a separate HSF file. More importantly, the data can be incrementally streamed into the reading application’s scene-graph.

For example, many technical applications that also visualize 2D/3D information utilize a custom file format that contains application specific data. When the file is read in, the application then goes through a laborious process of recreating the 2D/3D information associated with the application data. By utilizing the HOOPS/Stream Toolkit, a developer could cache the scene-graph geometry in their own proprietary file format file by actually embedding the HSF information in their file. File load time and initial rendering is drastically reduced, the custom file format remains intact, and the highly compressed HSF information minimizes the increase of file size.

Controlling Reading

First review the section about reading HSF files. To control the reading process, a piece of binary data that has been read from an HSF file is presented to the BStreamFileToolkit object for parsing and insertion into your custom data structures by calling the BStreamFileToolkit::ParseBuffer method. This method doesn’t care where the data originated from, but simply reads the data from the buffer passed to it, and calls the Read and Execute methods of the opcode handler registered to handle the current opcode being processed. Therefore, if you want to access custom HSF objects, you will need to have first registered custom opcode handlers for the objects of interest (and implement the Execute methods to do something with the data.)

The following code example demonstrates how data could be manually read from a local file and inserted into your custom data structures using BStreamFileToolkit::ParseBuffer. A file is open and pieces of data are read from it using the BStreamFileToolkit wrapper functions for file opening and reading ( BStreamFileToolkit::OpenFile and BStreamFileToolkit::ReadBuffer ). Data is continually read and passed to BStreamFileToolkit::ParseBuffer until it returns #TK_Complete, indicating that reading is complete, or until an error occurs. Example:

void Read_Stream_File (char const * filename)
{
        auto    char            block[BUFFER_SIZE];
        auto    TK_Status       status = TK_Normal;
        auto    int                     amount;

        BStreamFileToolkit * tk = new BStreamFileToolkit;

        // our sample custom toolkit only cares about segment and shells
        tk->SetOpcodeHandler (TKE_Open_Segment, new TK_My_Open_Segment);
        tk->SetOpcodeHandler (TKE_Close_Segment, new TK_My_Close_Segment);
        tk->SetOpcodeHandler (TKE_Shell, new TK_My_Shell);

        if ((status = tk->OpenFile (filename)) != TK_Normal)
                return status;
        do
        {
                if (tk->ReadBuffer (block, BUFFER_SIZE, amount) != TK_Normal)
                        break;
                status = tk->ParseBuffer(block, amount);

                if (status == TK_Error)
                {
                        // whatever...
                        break;
                }
        } while (status != TK_Complete);

        tk->CloseFile ();

        delete tk;
}

Controlling Writing

Controlling writing using the base classes is already explained in the section on writing HSF files. Since writing out an HSF file using the base classes must be done manually anyway (because the developer has to supply their own logic to traverse the graphics information and directly export HSF objects), exporting to a user-supplied/controlled buffer rather than a file is just a special case of the WriteObject function described in the example programs in that section. The only difference would be to omit the ‘fwrite’ call, and deal with the HSF data buffer directly. (Perhaps you wish to send the HSF data to another application, or export it to your own custom filetype, etc…)