DOM guide: Integration templates: Difference between revisions

From COLLADA Public Wiki
Jump to navigation Jump to search
Alorino (talk | contribs)
No edit summary
 
Alorino (talk | contribs)
No edit summary
Line 1: Line 1:
Integration templates convert COLLADA DAE objects into application-specific objects and back again. This page provides a step-by-step example of how to integrate application data structures with the COLLADA runtime infrastructure (COLLADA DOM). Detailed knowledge of the COLLADA DOM architecture is not necessary to understand this example or to successfully integrate your own application-specific data structures.
Integration templates convert COLLADA DAE objects into application-specific objects and back again. This page provides a step-by-step example of how to integrate application data structures with the COLLADA runtime infrastructure (COLLADA DOM). Detailed knowledge of the COLLADA DOM architecture is not necessary to understand this example or to successfully integrate your own application-specific data structures.
==Overview==
==Overview==
The COLLADA Object Model is a set of runtime COLLADA DAE objects that correspond to elements in a COLLADA XML instance document. For importing, they are built when a COLLADA XML instance document is parsed. For exporting, you might need to provide code to build them.To convert data contained in COLLADA DAE objects into your own application data structures, and the reverse, the DOM provides integration templates for every object. The integration templates provide plugin points where you can insert conversion code. After a document has been imported by the DOM into COLLADA DAE objects, or when you request an export, your integration code is called to perform the conversion.  
The COLLADA Object Model is a set of runtime COLLADA DAE objects that correspond to elements in a COLLADA XML instance document. For importing, they are built when a COLLADA XML instance document is parsed. For exporting, you might need to provide code to build them. To convert data contained in COLLADA DAE objects into your own application data structures, and the reverse, the DOM provides integration templates for every object. The integration templates provide plugin points where you can insert conversion code. After a document has been imported by the DOM into COLLADA DAE objects, or when you request an export, your integration code is called to perform the conversion.  
Figure 4 COLLADA DOM Integration Usage Model for Importing
 
The basic steps during integration are the following:
The basic steps during integration are the following:
(1) Initialize the COLLADA DOM by creating a new DAE object.
#Initialize the COLLADA DOM by creating a new DAE object.
(2) Register application-specific integration libraries.
#Register application-specific integration libraries.
(3) To convert after importing:
#To convert after importing:
(a) Import a COLLADA XML file by loading it; this places the data into runtime COLLADA DAE
##Import a COLLADA XML file by loading it; this places the data into runtime COLLADA DAE objects. COLLADA DAE objects with registered integration libraries automatically create their associated application data structures.
objects. COLLADA DAE objects with registered integration libraries automatically create their
##The COLLADA runtime calls the conversion methods in the integration libraries to convert the content of COLLADA DAE objects into their associated data structures.
associated application data structures.
#To convert before exporting:
(b) The COLLADA runtime calls the conversion methods in the integration libraries to convert the
##If matching COLLADA DAE objects don’t already exist, call createTo to create them.
content of COLLADA DAE objects into their associated data structures.
##Export the COLLADA DAE structure by saving it; the COLLADA runtime calls the conversion methods in the integration libraries to convert your data structures into COLLADA DAE objects and then export them.
(4) To convert before exporting:
 
(a) If matching COLLADA DAE objects don’t already exist, call createTo to create them.
==COLLADA DOM Integration Templates==
(b) Export the COLLADA DAE structure by saving it; the COLLADA runtime calls the conversion
At import time, elements in COLLADA instance documents are loaded into a run-time COLLADA Object Model. The COLLADA DOM provides integration templates to enable you to convert COLLADA data between the COLLADA Object Model and your own run-time structures.
methods in the integration libraries to convert your data structures into COLLADA DAE objects
 
and then export them.
Each element in the COLLADA Object Model has its own integration template consisting of a header (.h) file and a code (.cpp) file. Copy into your application directory the template files for the elements that you want to convert from DOM structures into application-specific structures or vice versa. These copies are the starting points for your customized integration libraries You can then add code to these integration libraries to convert data stored in the associated DOM object into your application object(s) and vice versa.
©SCEI
 
- 23 -
COLLADA DOM Integration Templates
At import time, elements in COLLADA instance documents are loaded into a run-time COLLADA Object
Model. The COLLADA DOM provides integration templates to enable you to convert COLLADA data
between the COLLADA Object Model and your own run-time structures.
Each element in the COLLADA Object Model has its own integration template consisting of a header (.h)
file and a code (.cpp) file. Copy into your application directory the template files for the elements that
you want to convert from DOM structures into application-specific structures or vice versa. These copies
are the starting points for your customized integration libraries You can then add code to these integration
libraries to convert data stored in the associated DOM object into your application object(s) and vice versa.
The plugin points for your code are identified in comments in the template source.
The plugin points for your code are identified in comments in the template source.
The COLLADA DOM provides two sets of integration templates:
The COLLADA DOM provides two sets of integration templates:
Simple Integration Templates: These templates are in the templates/integrationSimple
*Simple Integration Templates: These templates are in the templates/integrationSimple directory, and provide plugin points for the most commonly converted COLLADA DAE objects. These templates do not provide plugin points for the nested XML elements, such as the <author> element found in <asset> that is defined by the domAuthor class.
directory, and provide plugin points for the most commonly converted COLLADA DAE objects.
*Full Integration Templates: These templates are in the templates/integrationFull directory, and provide plugin points for all COLLADA DAE objects.
These templates do not provide plugin points for the nested XML elements, such as the <author>
 
element found in <asset> that is defined by the domAuthor class.
The DOM provides a pair of template files for each basic COLLADA DAE object. For example, the template files to convert domNode objects are intNode.cpp and intNode.h.
Full Integration Templates: These templates are in the templates/integrationFull directory,
 
and provide plugin points for all COLLADA DAE objects.
==Integration Objects==
The DOM provides a pair of template files for each basic COLLADA DAE object. For example, the
Your integration library for each element in the COLLADA Object Model provides the code that defines an integration object for the element. The integration object serves as the focal point for all information about the conversion. It defines methods that perform the conversion, and it provides data members that bind the COLLADA Object Model element with the application-specific data structure being converted to.
template files to convert domNode objects are intNode.cpp and intNode.h.
 
Integration Objects
Integration objects are represented with the daeIntegrationObject class. Every class derived from daeElement provides for an integration object through the data member daeElement::_intObject.
Your integration library for each element in the COLLADA Object Model provides the code that defines
 
an integration object for the element. The integration object serves as the focal point for all information
The integration object class for each element is defined with the prefix “int”. For example, the domGeometry class provides an intGeometry integration object.
about the conversion. It defines methods that perform the conversion, and it provides data members that
 
bind the COLLADA Object Model element with the application-specific data structure being converted to.
When you define integration code for an element, your code binds the element with your application-specific object, via the _element and _object data members of the integration object. You can use methods daeIntegrationObject::getElement() and getObject() to access these data members.
Integration objects are represented with the daeIntegrationObject class. Every class derived from
 
daeElement provides for an integration object through the data member daeElement::_intObject.
When you load a COLLADA instance document, the DOM automatically creates the appropriate integration objects.  
The integration object class for each element is defined with the prefix “int”. For example, the
 
domGeometry class provides an intGeometry integration object.
To get the integration object for an element, use the method daeElement::getIntObject(), which also initiates the conversion process for any objects that have not yet been converted.
When you define integration code for an element, your code binds the element with your
 
application-specific object, via the _element and _object data members of the integration object. You
==Integration Template Plugin Points==
can use methods daeIntegrationObject::getElement() and getObject() to access these data
The integration class for each COLLADA Object Model element provides six plugin points into which you can add conversion code. The plugin points are implemented as methods; you need to provide the code for the method bodies. You need to implement only the body of the methods for those plugin points that are relevant to your application.
members.
*createFrom(): Defines the code to create the application-specific data structure associated with the DOM class for this template. This method sets up the integration object for the DOM class.
When you load a COLLADA instance document into a new collection, the DOM automatically creates the
*fromCOLLADA(): Defines the code to covert the COLLADA Object Model data structure into your application-specific data structure.
appropriate integration objects. To get the integration object for an element, use the method
*fromCOLLADAPostProcess(): Defines any postprocessing code that must execute after the basic conversion to your application data structure.
daeElement::getIntObject(), which also initiates the conversion process for any objects that have
*createTo(): Defines code to create the COLLADA Object Model data structure associated with the DOM class for this template if such a structure does not already exist (for example, if it was not created while importing).
not yet been converted.
*toCOLLADA(): Defines the code to covert the content of your application’s data structures into COLLADA Object Model data structures.
Note. The beta release of the COLLADA DOM does not automatically call the plugin code to update the COLLADA
*toCOLLADAPostProcess(): Defines any postprocessing code that must execute after the basic conversion from your application’s data structure.
Object Model data structures from your application objects prior to saving the database. If you wish to write the
 
changed application data out to a new COLLADA instance document, you must ensure that the COLLADA Object
==Geometry Integration Example==
Model structures are updated by calling the “to” plugin points in your application code, which can usually be
accomplished by calling the daeElement::getIntObject() method, since this method converts application
objects both to and from their associated COLLADA DAE Objects.
©SCEI
- 24 -
Integration Template Plugin Points
The integration class for each COLLADA Object Model element provides six plugin points into which you
can add conversion code. The plugin points are implemented as methods; you need to provide the code
for the method bodies. You need to implement only the body of the methods for those plugin points that
are relevant to your application.
createFrom(): Defines the code to create the application-specific data structure associated with the
DOM class for this template. This method sets up the integration object for the DOM class.
fromCOLLADA(): Defines the code to covert the COLLADA Object Model data structure into your
application-specific data structure.
fromCOLLADAPostProcess(): Defines any postprocessing code that must execute after the basic
conversion to your application data structure.
createTo(): Defines code to create the COLLADA Object Model data structure associated with the
DOM class for this template if such a structure does not already exist (for example, if it was not
created while importing).
toCOLLADA(): Defines the code to covert the content of your application’s data structures into
COLLADA Object Model data structures.
toCOLLADAPostProcess(): Defines any postprocessing code that must execute after the basic
conversion from your application’s data structure.
Geometry Integration Example
This example demonstrates integration with the <geometry> element.
This example demonstrates integration with the <geometry> element.
Creating the example has three basic steps. You copy the corresponding integration templates to
application-specific versions. You register these classes with the COLLADA DOM. In the application
Creating the example has three basic steps. You copy the corresponding integration templates to application-specific versions. You register these classes with the COLLADA DOM. In the application runtime, you add code to initialize the COLLADA DOM, call the file load, and request application objects from the integration classes.
runtime, you add code to initialize the COLLADA DOM, call the file load, and request application objects
 
from the integration classes.
===Make Copies of Relevant Integration Templates===
Figure 5 Files Used in this Example
The first step in the process of creating conversion code is to copy the relevant integration template files from the integration subdirectory into your application’s directory. For this example, the relevant integration templates are intGeometry.cpp and intGeometry.h. You will modify the copied files to contain your conversion code.
Make Copies of Relevant Integration Templates
 
The first step in the process of creating conversion code is to copy the relevant integration template files
===Register Integration Libraries with the DOM===
from the integration subdirectory into your application’s directory. For this example, the relevant
For the DOM to create integration objects during parse time or before exporting, you must register the integration objects with the infrastructure. To do this, call the registerElement() method on each integration library that you are using. A convenience function to register these classes with the COLLADA DOM is defined in intRegisterElements.cpp, which is also found in the template directory. You can copy this function into your application’s directory. The relevant code for this example is shown here:  
integration templates are intGeometry.cpp and intGeometry.h. You will modify the copied files to
void intRegisterElements()
contain your conversion code.
{
©SCEI
    intGeometry::registerElement();
- 25 -
}
Register Integration Libraries with the DOM
The integration library file provides the definition for the intGeometry class. Its contents are explained in a later step.
For the DOM to create integration objects during parse time or before exporting, you must register the
 
integration objects with the infrastructure. To do this, call the registerElement() method on each
After the intRegisterElements() function is defined, pass a handle to this function into the DAE::setIntegrationLibrary() method, as described in the “Invoke Integration Libraries Registration” section.
integration library that you are using. A convenience function to register these classes with the COLLADA
 
DOM is defined in intRegisterElements.cpp, which is also found in the template directory. You can
===Setting up the Integration Library Header File===
copy this function into your application’s directory. The relevant code for this example is shown here:
Now we begin the process of editing the new integration library for the objects we want to convert. We start with the intGeometry.h integration library copied from the intGeometry.h template. The template must be modified to add information about the application object(s) to or from which the COLLADA Object Model structure will be converted. For the header, we need to declare the class we are converting into or from:
void intRegisterElements()
// class myGeometry is fully defined in an application header file.
{
class myGeometry;
intGeometry::registerElement();
We also add code to define the relevant structures and provide a method to return those structures. These definitions fall within the body of the intGeometry integration object declaration:
}
class intGeometry : public daeIntegrationObject
The integration library file provides the definition for the intGeometry class. Its contents are explained
{
in a later step.
    // intGeometry template declarations provided here
After the intRegisterElements() function is defined, pass a handle to this function into the
    . . .
DAE::setIntegrationLibrary() method, as described in the “Invoke Integration Libraries
public: // USER CODE
Registration” section.
    virtual ~intGeometry();
Setting up the Integration Library Header File
    // define the accessor for the myGeometry object
Now we begin the process of editing the new integration library for the objects we want to convert. We
    myGeometry *getGeometry() { return _object; }
start with the intGeometry.h integration library copied from the intGeometry.h template. The
private: // USER CODE
template must be modified to add information about the application object(s) to or from which the
    // declare the types for the integration object data members
COLLADA Object Model structure will be converted. For the header, we need to declare the class we are
    myGeometry *_object;
converting into or from:
    daeElement *_element;
// class myGeometry is fully defined in an application header file.
};
class myGeometry;
 
We also add code to define the relevant structures and provide a method to return those structures. These
===Defining Your Application Data Structure===
definitions fall within the body of the intGeometry integration object declaration:
Within the integration library files, you need to provide the code to create your application-specific data structure for the COLLADA DAE objects that you want to convert.
class intGeometry : public daeIntegrationObject
 
{
For this example, we have an application-specific data structure used to represent geometry, defined in an application header file, in this case, myGeometry.h:
// intGeometry template declarations provided here
// Definition of application's myPologon class also included here
. . .
class myGeometry
public: // USER CODE
{
virtual ~intGeometry();
public:
// define the accessor for the myGeometry object
    unsigned int _iVertexCount;
myGeometry *getGeometry() { return _object; }
    float *_pVertices;
private: // USER CODE
    std::vector<myPolygon> _vPolygons;
// declare the types for the integration object data members
};
myGeometry *_object;
 
daeElement *_element;
===Provide the Plugin Code to Create an Application Object for Importing===
};
The plugin method relevant to this step for importing is the createFrom() method. Within the createFrom() method, we add code to create a new myGeometry object, initialize it, and initialize the intGeometry integration object data members. Within intGeometry.cpp:  
Defining Your Application Data Structure
void intGeometry::createFrom(daeElementRef element)
Within the integration library files, you need to provide the code to create your application-specific data
{
structure for the COLLADA DAE objects that you want to convert.
    // create class to hold geometry information and
©SCEI
    // initialize the new object as empty
- 26 -
    _object = new myGeometry();
For this example, we have an application-specific data structure used to represent geometry, defined in an
    _object->pVertices = NULL;
application header file, in this case, myGeometry.h:
    // set up the _element data member of the integration object
// Definition of application's myPologon class also included here
    _element = element;
class myGeometry
}
{
Now, when a COLLADA instance document is loaded into the COLLADA runtime database and a domGeometry object is encountered, the createFrom() method automatically creates a new myGeometry object, because the intGeometry integration library has been registered with the DOM.
public:
 
unsigned int _iVertexCount;
===Build Conversion Code for Importing===
float *_pVertices;
Now we must add code to the integration library to translate the data stored in a DOM object to its associated application object. The fromCOLLADA() method is the plugin point for the basic application-specific conversion code. The fromCOLLADAPostProcess() method provides additional flexibility for the conversion process.
std::vector<myPolygon> _vPolygons;
 
};
Depending on the COLLADA DAE object and the application object, the code may vary significantly. For this example, we use the intGeometry::fromCOLLADA() method to create new vertex buffers from the COLLADA DAE geometry object.
Provide the Plugin Code to Create an Application Object for Importing
 
The plugin method relevant to this step for importing is the createFrom() method.Within the
createFrom() method, we add code to create a new myGeometry object, initialize it, and initialize the
intGeometry integration object data members. Within intGeometry.cpp:
void intGeometry::createFrom(daeElementRef element)
{
// create class to hold geometry information and
// initialize the new object as empty
_object = new myGeometry();
_object->pVertices = NULL;
// set up the _element data member of the integration object
_element = element;
}
Now, when a COLLADA instance document is loaded into the COLLADA runtime database and a
domGeometry object is encountered, the createFrom() method automatically creates a new
myGeometry object, because the intGeometry integration library has been registered with the DOM.
Build Conversion Code for Importing
Now we must add code to the integration library to translate the data stored in a DOM object to its
associated application object. The fromCOLLADA() method is the plugin point for the basic
application-specific conversion code. The fromCOLLADAPostProcess() method provides additional
flexibility for the conversion process.
Depending on the COLLADA DAE object and the application object, the code may vary significantly. For
this example, we use the intGeometry::fromCOLLADA() method to create new vertex buffers from the
COLLADA DAE geometry object.
The following code retrieves the mesh object from the COLLADA domGeometry object:
The following code retrieves the mesh object from the COLLADA domGeometry object:
// Get the geometry element from this integration object
// Get the geometry element from this integration object
domGeometry* geomElement = (domGeometry*)(domElement*)getElement();
domGeometry* geomElement = (domGeometry*)(domElement*)getElement();
domMesh *meshEl = geomElement->getMesh();
domMesh *meshEl = geomElement->getMesh();
When we have the mesh, we can construct our application-specific data structure iVertices for the
When we have the mesh, we can construct our application-specific data structure iVertices for the myGeometry object. The following code shows how to create the new vertex buffer.
myGeometry object. The following code shows how to create the new vertex buffer.
// Get a pointer to the application-defined geometry object that was
// Get a pointer to the application-defined geometry object that was
// automatically created during load by calling createFrom.
// automatically created during load by calling createFrom.
myGeometry *local = (myGeometry *)_object;
myGeometry *local = (myGeometry *)_object;
// Get a pointer to the domPolygons in this domMesh. To simplify this example,
// Get a pointer to the domPolygons in this domMesh. To simplify this example,
// we will handle only a domMesh that has a single domPolygons.
// we will handle only a domMesh that has a single domPolygons.
if(meshElement->getPolygons_array().getCount() != 1)
©SCEI
{
- 27 -
    fprintf(stderr, "This example supports only one domPolygons per domMesh\n");
if(meshElement->getPolygons_array().getCount() != 1)
    return;
{
}
fprintf(stderr,
domPolygons *polygons = meshElement->getPolygons_array()[0];
"This example supports only one domPolygons per domMesh\n");
int polygonCount = polygons->getCount();
return;
// To simplify this example, we assume the domPolygons has only one domInput.
}
if(polygons->getInput_array().getCount() != 1)
domPolygons *polygons = meshElement->getPolygons_array()[0];
{
int polygonCount = polygons->getCount();
    fprintf(stderr, "This example supports only one domInput per domPolygons\n");
// To simplify this example, we assume the domPolygons has only one domInput.
    return;
if(polygons->getInput_array().getCount() != 1)
}
{
// Loop over all the polygons in the domPolygons element
fprintf(stderr,
for (int i=0;i<polygonCount;i++)
"This example supports only one domInput per domPolygons\n");
{
return;
    myPolygon myPoly;
}
    // Get pointer to this polygon (domP).
// Loop over all the polygons in the domPolygons element
    domPolygons::domP *poly = polygons->getP_array()[i];
for (int i=0;i<polygonCount;i++)
    // Get the number of indices from the domP and save it in my structure.
{
    myPoly._iIndexCount = poly->getValue().getCount();
myPolygon myPoly;
    // You can modify the data as you copy it from
// Get pointer to this polygon (domP).
    // the COLLADA object to your object.
domPolygons::domP *poly = polygons->getP_array()[i];
    // Here we repeat the first index in list as the last index,
// Get the number of indices from the domP and save it in my structure.
    // to form a closed loop that can be drawn as a line strip.
myPoly._iIndexCount = poly->getValue().getCount();
    myPoly._iIndexCount++;
// You can modify the data as you copy it from
    myPoly._pIndexes = new unsigned short[myPoly._iIndexCount];
// the COLLADA object to your object.
    // Copy all the indices from the domP into my structure.
// Here we repeat the first index in list as the last index,
    for (int j=0;j<myPoly._iIndexCount-1;j++)
// to form a closed loop that can be drawn as a line strip.
    myPoly._pIndexes[j] = poly->getValue()[j];
myPoly._iIndexCount++;
    // Repeat the first index at the end of the list to create a closed loop.
myPoly._pIndexes = new unsigned short[myPoly._iIndexCount];
    myPoly._pIndexes[j] = myPoly._pIndexes[0];
// Copy all the indices from the domP into my structure.
    // Push this polygon into the list of polygons in my structure.
for (int j=0;j<myPoly._iIndexCount-1;j++)
    local->_vPolygons.push_back(myPoly);
myPoly._pIndexes[j] = poly->getValue()[j];
}
// Repeat the first index at the end of the list to create a closed loop.
// Copy the vertices we are going to use into myGeometry. To keep things simple,
myPoly._pIndexes[j] = myPoly._pIndexes[0];
// we will assume there is only one domSource and domFloatArray in the domMesh,
// Push this polygon into the list of polygons in my structure.
// that it is the array of vertices, and that it is in X, Y, Z format. A real
local->_vPolygons.push_back(myPoly);
// app would find the vertices by starting with domPolygons and following
}
// the links through the domInput, domVertices, domSource, domFloat_array,
// Copy the vertices we are going to use into myGeometry. To keep things simple,
// and domTechnique.
// we will assume there is only one domSource and domFloatArray in the domMesh,
if(meshElement->getSource_array().getCount() != 1)
// that it is the array of vertices, and that it is in X, Y, Z format. A real
{
// app would find the vertices by starting with domPolygons and following
    fprintf(stderr, "This example supports only one source array per domMesh\n");
// the links through the domInput, domVertices, domSource, domFloat_array,
    return;
// and domTechnique.
}
if(meshElement->getSource_array().getCount() != 1)
domSource *source = meshElement->getSource_array()[0];
{
if(source->getFloat_array().getCount() != 1)
fprintf(stderr,
{
"This example supports only one source array per domMesh\n");
    fprintf(stderr, "This example supports only one float array per source\n");
return;
}
}
domFloat_array *floatArray = source->getFloat_array_array()[0];
domSource *source = meshElement->getSource_array()[0];
// Assume there are 3 values per vertex with a stride of 3.
if(source->getFloat_array_array().getCount() != 1)
local->_iVertexCount = floatArray->getCount()/3;
{
local->_pVertices = new float[local->_iVertexCount*3];
fprintf(stderr,
// Copy the vertices into my structure one-by-one
"This example supports only one float array per source\n");
// (converts from COLLADA's doubles to floats).
©SCEI
for ( unsigned int i = 0; i < local->_iVertexCount*3; i++ )  
- 28 -
{
}
    local->_pVertices[i] = floatArray->getValue()[i];
domFloat_array *floatArray = source->getFloat_array_array()[0];
}
// Assume there are 3 values per vertex with a stride of 3.
 
local->_iVertexCount = floatArray->getCount()/3;
===Access COLLADA Objects from the Application===
local->_pVertices = new float[local->_iVertexCount*3];
We can now put together the application code that registers the integration libraries, loads the COLLADA data into the in-memory DOM structures, and accesses the converted data.  
// Copy the vertices into my structure one-by-one
 
// (converts from COLLADA's doubles to floats).
====Invoke Integration Libraries Registration====
for ( unsigned int i = 0; i < local->_iVertexCount*3; i++ ) {
You defined the intRegisterElements() function as described in “Register Integration Libraries with the DOM.” Now you must pass a handle to this function into the DAE::setIntegrationLibrary() method.
local->_pVertices[i] = floatArray->getValue()[i];
 
}
With this step, the elements that you want to convert are registered with the DOM, and are converted from COLLADA Object Model structures to application-specific structures when a COLLADA instance document is loaded into the DOM, or the reverse when an object is saved.
Access COLLADA Objects from the Application
 
We can now put together the application code that registers the integration libraries, loads the COLLADA
For example, your main application code could pass a handle to the integration library registration function as follows:
data into the in-memory DOM structures, and accesses the converted data.
// Instantiate the reference implementation
Invoke Integration Libraries Registration
daeObject = new DAE;
You defined the intRegisterElements() function as described in “Register Integration Libraries with
//register the integration objects
the DOM.” Now you must pass a handle to this function into the DAE::setIntegrationLibrary()
daeObject->setIntegrationLibrary(&intRegisterElements);
method.
 
With this step, the elements that you want to convert are registered with the DOM, and are converted
====Parse a COLLADA File====
from COLLADA Object Model structures to application-specific structures when a COLLADA instance
Now we are ready to parse a COLLADA instance into the run-time COLLADA Object Model. The load step creates the integration objects and invokes the createFrom() and fromCOLLADA() methods to convert the data from the COLLADA Object Model structures into the application-defined structures.
document is loaded into the DOM, or the reverse when an object is saved.
//load the COLLADA file
For example, your main application code could pass a handle to the integration library registration
int res = daeObject->load(filename);
function as follows:
 
// Instantiate the reference implementation
====Access a COLLADA Object====
daeObject = new DAE;
With the COLLADA file parsed and loaded into in-memory database objects, it is now possible to request objects from the database. Here we request that the database return the first geometry element, placing it into pElem.
//register the integration objects
//query the runtime to retrieve an element
daeObject->setIntegrationLibrary(&intRegisterElements);
int res = daeObject->getDatabase()->getElement
Parse a COLLADA File
((daeElement**)&pElem,0,NULL,COLLADA_ELEMENT_GEOMETRY);
Now we are ready to parse a COLLADA instance into the run-time COLLADA Object Model. The load
 
step creates the integration objects and invokes the createFrom() and fromCOLLADA() methods to
====Acquire the Converted Application Object====
convert the data from the COLLADA Object Model structures into the application-defined structures.
In the following code, the myGeometry class represents the application object containing geometry data. The COLLADA DAE object retrieved above into pElem contains a reference to its associated integration object (thanks to its earlier registration). The intGeometry class converts the COLLADA data and returns the converted data as a myGeometry instance via the getGeometry()method, which was defined in importGeometry.h.
//load the COLLADA file
// Get the integration object from the element
int res = daeObject->load(filename);
daeIntegrationObject *pIntegrationObj = pElem->getIntObject();
Access a COLLADA Object
intGeometry *importGeometry =(intGeometry *)pIntegrationObj;
With the COLLADA file parsed and loaded into in-memory database objects, it is now possible to request
//extract the user data from the integration object
objects from the database. Here we request that the database return the first geometry element, placing it
myGeometry geom = importGeometry->getGeometry();
into pElem.
 
//query the runtime to retrieve an element
==Exporting Using Integration==
int res = daeObject->getDatabase()->getElement
The preceding sections showed how to set up your integration objects, import a COLLADA instance document, and ensure that the data is converted into data structures specific to your application.
((daeElement**)&pElem,0,NULL,COLLADA_ELEMENT_GEOMETRY);
 
©SCEI
If you modify data values and want to write it to a COLLADA instance document, the process is similar to reversing the import-and-convert process, although there are some differences.  
- 29 -
 
Acquire the Converted Application Object
===Modifying a COLLADA DOM Object Structure===
In the following code, the myGeometry class represents the application object containing geometry data.
In some cases, your application might modify the structure of your application objects that you loaded from a COLLADA DOM object. If you want to export the data back to a COLLADA instance document, you must change the structure of the COLLADA DOM object to match your changes before converting from your application-specific structures. The example code does not show how to do this.
The COLLADA DAE object retrieved above into pElem contains a reference to its associated integration
 
object (thanks to its earlier registration). The intGeometry class converts the COLLADA data and returns
===Creating a New COLLADA DOM Object Using createTo===
the converted data as a myGeometry instance via the getGeometry()method, which was defined in
In some cases, you might need to export your data to an entirely new COLLADA document, such as when the data originated in your application rather than by being imported from an existing COLLADA instance document. In this cases, to use the integration methods to convert from your application structure to a DOM object and then export to a new COLLADA instance document, you must create the matching COLLADA DOM structure before you can convert from your application’s structure.
importGeometry.h.
 
// Get the integration object from the element
Compare with the import process: When your application loads a COLLADA instance document, the COLLADA DOM automatically creates DAE objects in which to load the COLLADA data, then calls your customized createFrom for each element that has an integration class, which creates your application-specific objects. Then it calls fromCOLLADA, which copies the data from the DAE objects to your application objects.
daeIntegrationObject *pIntegrationObj = pElem->getIntObject();
 
intGeometry *importGeometry =(intGeometry *)pIntegrationObj;
If you create a new application object, there are no COLLADA elements (no DAE objects) associated with it. If you simply save the file, this new data is not written. The purpose of createTo is to create these COLLADA elements and associate them with the application object. createTo is not called automatically when a new application object is created; you must call it explicitly. After createTo has been called, the rest of the saving process is automatic, that is, if you have registered your integration library, when you call save, toCOLLADA is called for every COLLADA element with an integration class to copy the data from the application objects into the COLLADA objects.
//extract the user data from the integration object
 
myGeometry geom = importGeometry->getGeometry();
Exporting Using Integration
The preceding sections showed how to set up your integration objects, import a COLLADA instance
document, and ensure that the data is converted into data structures specific to your application.
If you modify data values and want to write it to a COLLADA instance document, the process is similar to
reversing the import-and-convert process, although there are some differences.
Figure 6 COLLADA DOM Integration Usage Model for Exporting
Modifying a COLLADA DOM Object Structure
In some cases, your application might modify the structure of your application objects that you loaded
from a COLLADA DOM object. If you want to export the data back to a COLLADA instance document,
you must change the structure of the COLLADA DOM object to match your changes before converting
from your application-specific structures. The example code does not show how to do this.
Creating a New COLLADA DOM Object Using createTo
In some cases, you might need to export your data to an entirely new COLLADA document, such as when
the data originated in your application rather than by being imported from an existing COLLADA
instance document. In this cases, to use the integration methods to convert from your application
structure to a DOM object and then export to a new COLLADA instance document, you must create the
matching COLLADA DOM structure before you can convert from your application’s structure.
Compare with the import process: When your application loads a COLLADA instance document, the
COLLADA DOM automatically creates DAE objects in which to load the COLLADA data, then calls your
customized createFrom for each element that has an integration class, which creates your
©SCEI
- 30 -
application-specific objects. Then it calls fromCOLLADA, which copies the data from the DAE objects to
your application objects.
If you create a new application object, there are no COLLADA elements (no DAE objects) associated with
it. If you simply save the file, this new data is not written. The purpose of createTo is to create these
COLLADA elements and associate them with the application object. createTo is not called automatically
when a new application object is created; you must call it explicitly. After createTo has been called, the
rest of the saving process is automatic, that is, if you have registered your integration library, when you
call save, toCOLLADA is called for every COLLADA element with an integration class to copy the data
from the application objects into the COLLADA objects.
This example code does not show how to do this. The createTo method looks like this:
This example code does not show how to do this. The createTo method looks like this:
void
void intGeometry::createTo(void *userData)
intGeometry::createTo(void *userData)
{
{
    // This function would create new COLLADA elements from an
// This function would create new COLLADA elements from an
    // application- defined object
// application- defined object
    // It is NOT called automatically by the COLLADA DOM.
// It is NOT called automatically by the COLLADA DOM.
    // The user needs to call this when creating a new
// The user needs to call this when creating a new
    // application-specific object.
// application-specific object.
}
}
 
Exporting Data Value Modifications
===Exporting Data Value Modifications===
If you have modified only the values of the COLLADA data and want to export to a revised COLLADA
If you have modified only the values of the COLLADA data and want to export to a revised COLLADA instance document, this example shows how you might convert the data.
instance document, this example shows how you might convert the data.
 
The saving process for this example is automatic because you have registered your integration library.
The saving process for this example is automatic because you have registered your integration library. When you call save, toCOLLADA is called for every COLLADA element with an integration class. This copies the data from the application objects into the COLLADA ones.
When you call save, toCOLLADA is called for every COLLADA element with an integration class. This
 
copies the data from the application objects into the COLLADA ones.
Note that the code is essentially the reverse of the fromCOLLADA code in the importing example.
Note that the code is essentially the reverse of the fromCOLLADA code in the importing example.
void
void intGeometry::toCOLLADA()
intGeometry::toCOLLADA()
{
{
    // INSERT CODE TO TRANSLATE TO YOUR RUNTIME HERE
// INSERT CODE TO TRANSLATE TO YOUR RUNTIME HERE
    // The following lines are example code from the template:
// The following lines are example code from the template:
    // myRuntimeClassType* local = (myRuntimeClassType*)_object;
// myRuntimeClassType* local = (myRuntimeClassType*)_object;
    // element->foo = local->foo;
// element->foo = local->foo;
    // element->subelem[0]->bar = local->bar;
// element->subelem[0]->bar = local->bar;
    // This code takes data from an application-defined object and
// This code takes data from an application-defined object and
    // puts it back into the appropriate collada objects.
// puts it back into the appropriate collada objects.
    // Get a pointer to the COLLADA domGeometry element
// Get a pointer to the COLLADA domGeometry element
    // (this is the element that called us)
// (this is the element that called us)
    domGeometry* geometryElement = (domGeometry*)(domElement*)_element;
domGeometry* geometryElement = (domGeometry*)(domElement*)_element;
    // Get a pointer to the domGeometry's domMesh element
// Get a pointer to the domGeometry's domMesh element
    domMesh *meshElement = geometryElement->getMesh();
domMesh *meshElement = geometryElement->getMesh();
    // Get a pointer to my object that's assocated with this collada object
// Get a pointer to my object that's assocated with this collada object
    myGeometry *local = (myGeometry *)_object;
myGeometry *local = (myGeometry *)_object;
    // Get a pointer to the domPolygons in this domMesh.
// Get a pointer to the domPolygons in this domMesh.
    // To simplify this example,
// To simplify this example,
    // we will handle only a domMesh that has a single domPolygons
// we will handle only a domMesh that has a single domPolygons
    if(meshElement->getPolygons_array().getCount() != 1)
if(meshElement->getPolygons_array().getCount() != 1)
    {
©SCEI
        fprintf(stderr, "this example supports only one domPolygons per domMesh\n");
- 31 -
        return;
{
    }
fprintf(stderr,
    domPolygons *polygons = meshElement->getPolygons_array()[0];
"this example supports only one domPolygons per domMesh\n");
    int polygonCount = local->_vPolygons.size();
return;
    // To simplify this example, we assume that the domPolygons has
}
    // only one domInput
domPolygons *polygons = meshElement->getPolygons_array()[0];
    if(polygons->getInput_array().getCount() != 1)
int polygonCount = local->_vPolygons.size();
    {
// To simplify this example, we assume that the domPolygons has
        fprintf(stderr, "this example supports only one domInput per domPolygons\n");
// only one domInput
        return;
if(polygons->getInput_array().getCount() != 1)
    }
{
    // Loop over all the polygons in the domPolygons element and
fprintf(stderr,
    // put the data from
"this example supports only one domInput per domPolygons\n");
    // myGeometry back into it. For the purposes of the example,
return;
    // assume the number of polygons and indices hasn't changed
}
    // so we can just update the values in place
// Loop over all the polygons in the domPolygons element and
    polygons->setCount(polygonCount);
// put the data from
    for (int i=0;i<polygonCount;i++)
// myGeometry back into it. For the purposes of the example,
    {
// assume the number of polygons and indices hasn't changed
        // Get pointer to this polygon (domP)
// so we can just update the values in place
        domPolygons::domP *poly = polygons->getP_array()[i];
polygons->setCount(polygonCount);
        // Copy all the indices from my structure back to the domP
for (int i=0;i<polygonCount;i++)
        for (int j=0;j< local->_vPolygons[i]._iIndexCount-1;j++)
{
            poly->getValue()[j] = local->_vPolygons[i]._pIndexes[j] ;
// Get pointer to this polygon (domP)
    }
domPolygons::domP *poly = polygons->getP_array()[i];
    // Now copy the vertices from myGeometry back to the source.
// Copy all the indices from my structure back to the domP
    // Assume that the number of
for (int j=0;j< local->_vPolygons[i]._iIndexCount-1;j++)
    // vertices hasn't changed so we can just update them in place.
poly->getValue()[j] =
    if(meshElement->getSource_array().getCount() != 1)
local->_vPolygons[i]._pIndexes[j] ;
    {
}
        fprintf(stderr, "this example supports only one source array per domMesh\n");
// Now copy the vertices from myGeometry back to the source.
        return;
// Assume that the number of
    }
// vertices hasn't changed so we can just update them in place.
    domSource *source = meshElement->getSource_array()[0];
if(meshElement->getSource_array().getCount() != 1)
    if(source->getFloat_array_array().getCount() != 1)
{
    {
fprintf(stderr,
        fprintf(stderr, "this example supports only one float array per source\n");
"this example supports only one source array per domMesh\n");
    }
return;
    domFloat_array *floatArray = source->getFloat_array_array()[0];
}
    // Copy the vertices into from myGeometry back into the
domSource *source = meshElement->getSource_array()[0];
    // COLLADA float array
if(source->getFloat_array_array().getCount() != 1)
    floatArray->setCount(local->_iVertexCount*3);
{
    for ( unsigned int i = 0; i < local->_iVertexCount*3; i++ )  
fprintf(stderr,
    {
"this example supports only one float array per source\n");
        floatArray->getValue()[i] = local->_pVertices[i];
}
    }
domFloat_array *floatArray = source->getFloat_array_array()[0];
}
// Copy the vertices into from myGeometry back into the
// COLLADA float array
floatArray->setCount(local->_iVertexCount*3);
for ( unsigned int i = 0; i < local->_iVertexCount*3; i++ ) {
floatArray->getValue()[i] = local->_pVertices[i];
}
}

Revision as of 17:23, 26 March 2007

Integration templates convert COLLADA DAE objects into application-specific objects and back again. This page provides a step-by-step example of how to integrate application data structures with the COLLADA runtime infrastructure (COLLADA DOM). Detailed knowledge of the COLLADA DOM architecture is not necessary to understand this example or to successfully integrate your own application-specific data structures.

Overview

The COLLADA Object Model is a set of runtime COLLADA DAE objects that correspond to elements in a COLLADA XML instance document. For importing, they are built when a COLLADA XML instance document is parsed. For exporting, you might need to provide code to build them. To convert data contained in COLLADA DAE objects into your own application data structures, and the reverse, the DOM provides integration templates for every object. The integration templates provide plugin points where you can insert conversion code. After a document has been imported by the DOM into COLLADA DAE objects, or when you request an export, your integration code is called to perform the conversion.

The basic steps during integration are the following:

  1. Initialize the COLLADA DOM by creating a new DAE object.
  2. Register application-specific integration libraries.
  3. To convert after importing:
    1. Import a COLLADA XML file by loading it; this places the data into runtime COLLADA DAE objects. COLLADA DAE objects with registered integration libraries automatically create their associated application data structures.
    2. The COLLADA runtime calls the conversion methods in the integration libraries to convert the content of COLLADA DAE objects into their associated data structures.
  4. To convert before exporting:
    1. If matching COLLADA DAE objects don’t already exist, call createTo to create them.
    2. Export the COLLADA DAE structure by saving it; the COLLADA runtime calls the conversion methods in the integration libraries to convert your data structures into COLLADA DAE objects and then export them.

COLLADA DOM Integration Templates

At import time, elements in COLLADA instance documents are loaded into a run-time COLLADA Object Model. The COLLADA DOM provides integration templates to enable you to convert COLLADA data between the COLLADA Object Model and your own run-time structures.

Each element in the COLLADA Object Model has its own integration template consisting of a header (.h) file and a code (.cpp) file. Copy into your application directory the template files for the elements that you want to convert from DOM structures into application-specific structures or vice versa. These copies are the starting points for your customized integration libraries You can then add code to these integration libraries to convert data stored in the associated DOM object into your application object(s) and vice versa.

The plugin points for your code are identified in comments in the template source.

The COLLADA DOM provides two sets of integration templates:

  • Simple Integration Templates: These templates are in the templates/integrationSimple directory, and provide plugin points for the most commonly converted COLLADA DAE objects. These templates do not provide plugin points for the nested XML elements, such as the <author> element found in <asset> that is defined by the domAuthor class.
  • Full Integration Templates: These templates are in the templates/integrationFull directory, and provide plugin points for all COLLADA DAE objects.

The DOM provides a pair of template files for each basic COLLADA DAE object. For example, the template files to convert domNode objects are intNode.cpp and intNode.h.

Integration Objects

Your integration library for each element in the COLLADA Object Model provides the code that defines an integration object for the element. The integration object serves as the focal point for all information about the conversion. It defines methods that perform the conversion, and it provides data members that bind the COLLADA Object Model element with the application-specific data structure being converted to.

Integration objects are represented with the daeIntegrationObject class. Every class derived from daeElement provides for an integration object through the data member daeElement::_intObject.

The integration object class for each element is defined with the prefix “int”. For example, the domGeometry class provides an intGeometry integration object.

When you define integration code for an element, your code binds the element with your application-specific object, via the _element and _object data members of the integration object. You can use methods daeIntegrationObject::getElement() and getObject() to access these data members.

When you load a COLLADA instance document, the DOM automatically creates the appropriate integration objects.

To get the integration object for an element, use the method daeElement::getIntObject(), which also initiates the conversion process for any objects that have not yet been converted.

Integration Template Plugin Points

The integration class for each COLLADA Object Model element provides six plugin points into which you can add conversion code. The plugin points are implemented as methods; you need to provide the code for the method bodies. You need to implement only the body of the methods for those plugin points that are relevant to your application.

  • createFrom(): Defines the code to create the application-specific data structure associated with the DOM class for this template. This method sets up the integration object for the DOM class.
  • fromCOLLADA(): Defines the code to covert the COLLADA Object Model data structure into your application-specific data structure.
  • fromCOLLADAPostProcess(): Defines any postprocessing code that must execute after the basic conversion to your application data structure.
  • createTo(): Defines code to create the COLLADA Object Model data structure associated with the DOM class for this template if such a structure does not already exist (for example, if it was not created while importing).
  • toCOLLADA(): Defines the code to covert the content of your application’s data structures into COLLADA Object Model data structures.
  • toCOLLADAPostProcess(): Defines any postprocessing code that must execute after the basic conversion from your application’s data structure.

Geometry Integration Example

This example demonstrates integration with the <geometry> element.

Creating the example has three basic steps. You copy the corresponding integration templates to application-specific versions. You register these classes with the COLLADA DOM. In the application runtime, you add code to initialize the COLLADA DOM, call the file load, and request application objects from the integration classes.

Make Copies of Relevant Integration Templates

The first step in the process of creating conversion code is to copy the relevant integration template files from the integration subdirectory into your application’s directory. For this example, the relevant integration templates are intGeometry.cpp and intGeometry.h. You will modify the copied files to contain your conversion code.

Register Integration Libraries with the DOM

For the DOM to create integration objects during parse time or before exporting, you must register the integration objects with the infrastructure. To do this, call the registerElement() method on each integration library that you are using. A convenience function to register these classes with the COLLADA DOM is defined in intRegisterElements.cpp, which is also found in the template directory. You can copy this function into your application’s directory. The relevant code for this example is shown here:

void intRegisterElements()
{
    intGeometry::registerElement();
}

The integration library file provides the definition for the intGeometry class. Its contents are explained in a later step.

After the intRegisterElements() function is defined, pass a handle to this function into the DAE::setIntegrationLibrary() method, as described in the “Invoke Integration Libraries Registration” section.

Setting up the Integration Library Header File

Now we begin the process of editing the new integration library for the objects we want to convert. We start with the intGeometry.h integration library copied from the intGeometry.h template. The template must be modified to add information about the application object(s) to or from which the COLLADA Object Model structure will be converted. For the header, we need to declare the class we are converting into or from:

// class myGeometry is fully defined in an application header file.
class myGeometry;

We also add code to define the relevant structures and provide a method to return those structures. These definitions fall within the body of the intGeometry integration object declaration:

class intGeometry : public daeIntegrationObject
{
    // intGeometry template declarations provided here
    . . .
public: // USER CODE
    virtual ~intGeometry();
    // define the accessor for the myGeometry object
    myGeometry *getGeometry() { return _object; }
private: // USER CODE
    // declare the types for the integration object data members
    myGeometry *_object;
    daeElement *_element;
};

Defining Your Application Data Structure

Within the integration library files, you need to provide the code to create your application-specific data structure for the COLLADA DAE objects that you want to convert.

For this example, we have an application-specific data structure used to represent geometry, defined in an application header file, in this case, myGeometry.h:

// Definition of application's myPologon class also included here
class myGeometry
{
public:
    unsigned int _iVertexCount;
    float *_pVertices;
    std::vector<myPolygon> _vPolygons;
};

Provide the Plugin Code to Create an Application Object for Importing

The plugin method relevant to this step for importing is the createFrom() method. Within the createFrom() method, we add code to create a new myGeometry object, initialize it, and initialize the intGeometry integration object data members. Within intGeometry.cpp:

void intGeometry::createFrom(daeElementRef element)
{
    // create class to hold geometry information and
    // initialize the new object as empty
    _object = new myGeometry();
    _object->pVertices = NULL;
    // set up the _element data member of the integration object
    _element = element;
}

Now, when a COLLADA instance document is loaded into the COLLADA runtime database and a domGeometry object is encountered, the createFrom() method automatically creates a new myGeometry object, because the intGeometry integration library has been registered with the DOM.

Build Conversion Code for Importing

Now we must add code to the integration library to translate the data stored in a DOM object to its associated application object. The fromCOLLADA() method is the plugin point for the basic application-specific conversion code. The fromCOLLADAPostProcess() method provides additional flexibility for the conversion process.

Depending on the COLLADA DAE object and the application object, the code may vary significantly. For this example, we use the intGeometry::fromCOLLADA() method to create new vertex buffers from the COLLADA DAE geometry object.

The following code retrieves the mesh object from the COLLADA domGeometry object:

// Get the geometry element from this integration object
domGeometry* geomElement = (domGeometry*)(domElement*)getElement();
domMesh *meshEl = geomElement->getMesh();

When we have the mesh, we can construct our application-specific data structure iVertices for the myGeometry object. The following code shows how to create the new vertex buffer.

// Get a pointer to the application-defined geometry object that was
// automatically created during load by calling createFrom.
myGeometry *local = (myGeometry *)_object;
// Get a pointer to the domPolygons in this domMesh. To simplify this example,
// we will handle only a domMesh that has a single domPolygons.
if(meshElement->getPolygons_array().getCount() != 1)
{
    fprintf(stderr, "This example supports only one domPolygons per domMesh\n");
    return;
}
domPolygons *polygons = meshElement->getPolygons_array()[0];
int polygonCount = polygons->getCount();
// To simplify this example, we assume the domPolygons has only one domInput.
if(polygons->getInput_array().getCount() != 1)
{
    fprintf(stderr, "This example supports only one domInput per domPolygons\n");
    return;
}
// Loop over all the polygons in the domPolygons element
for (int i=0;i<polygonCount;i++)
{
    myPolygon myPoly;
    // Get pointer to this polygon (domP).
    domPolygons::domP *poly = polygons->getP_array()[i];
    // Get the number of indices from the domP and save it in my structure.
    myPoly._iIndexCount = poly->getValue().getCount();
    // You can modify the data as you copy it from
    // the COLLADA object to your object.
    // Here we repeat the first index in list as the last index,
    // to form a closed loop that can be drawn as a line strip.
    myPoly._iIndexCount++;
    myPoly._pIndexes = new unsigned short[myPoly._iIndexCount];
    // Copy all the indices from the domP into my structure.
    for (int j=0;j<myPoly._iIndexCount-1;j++)
    myPoly._pIndexes[j] = poly->getValue()[j];
    // Repeat the first index at the end of the list to create a closed loop.
    myPoly._pIndexes[j] = myPoly._pIndexes[0];
    // Push this polygon into the list of polygons in my structure.
    local->_vPolygons.push_back(myPoly);
}
// Copy the vertices we are going to use into myGeometry. To keep things simple,
// we will assume there is only one domSource and domFloatArray in the domMesh,
// that it is the array of vertices, and that it is in X, Y, Z format. A real
// app would find the vertices by starting with domPolygons and following
// the links through the domInput, domVertices, domSource, domFloat_array,
// and domTechnique.
if(meshElement->getSource_array().getCount() != 1)
{
    fprintf(stderr, "This example supports only one source array per domMesh\n");
    return;
}
domSource *source = meshElement->getSource_array()[0];
if(source->getFloat_array().getCount() != 1)
{
    fprintf(stderr, "This example supports only one float array per source\n");
}
domFloat_array *floatArray = source->getFloat_array_array()[0];
// Assume there are 3 values per vertex with a stride of 3.
local->_iVertexCount = floatArray->getCount()/3;
local->_pVertices = new float[local->_iVertexCount*3];
// Copy the vertices into my structure one-by-one
// (converts from COLLADA's doubles to floats).
for ( unsigned int i = 0; i < local->_iVertexCount*3; i++ ) 
{
    local->_pVertices[i] = floatArray->getValue()[i];
}

Access COLLADA Objects from the Application

We can now put together the application code that registers the integration libraries, loads the COLLADA data into the in-memory DOM structures, and accesses the converted data.

Invoke Integration Libraries Registration

You defined the intRegisterElements() function as described in “Register Integration Libraries with the DOM.” Now you must pass a handle to this function into the DAE::setIntegrationLibrary() method.

With this step, the elements that you want to convert are registered with the DOM, and are converted from COLLADA Object Model structures to application-specific structures when a COLLADA instance document is loaded into the DOM, or the reverse when an object is saved.

For example, your main application code could pass a handle to the integration library registration function as follows:

// Instantiate the reference implementation
daeObject = new DAE;
//register the integration objects
daeObject->setIntegrationLibrary(&intRegisterElements);

Parse a COLLADA File

Now we are ready to parse a COLLADA instance into the run-time COLLADA Object Model. The load step creates the integration objects and invokes the createFrom() and fromCOLLADA() methods to convert the data from the COLLADA Object Model structures into the application-defined structures.

//load the COLLADA file
int res = daeObject->load(filename);

Access a COLLADA Object

With the COLLADA file parsed and loaded into in-memory database objects, it is now possible to request objects from the database. Here we request that the database return the first geometry element, placing it into pElem.

//query the runtime to retrieve an element
int res = daeObject->getDatabase()->getElement
((daeElement**)&pElem,0,NULL,COLLADA_ELEMENT_GEOMETRY);

Acquire the Converted Application Object

In the following code, the myGeometry class represents the application object containing geometry data. The COLLADA DAE object retrieved above into pElem contains a reference to its associated integration object (thanks to its earlier registration). The intGeometry class converts the COLLADA data and returns the converted data as a myGeometry instance via the getGeometry()method, which was defined in importGeometry.h.

// Get the integration object from the element
daeIntegrationObject *pIntegrationObj = pElem->getIntObject();
intGeometry *importGeometry =(intGeometry *)pIntegrationObj;
//extract the user data from the integration object
myGeometry geom = importGeometry->getGeometry();

Exporting Using Integration

The preceding sections showed how to set up your integration objects, import a COLLADA instance document, and ensure that the data is converted into data structures specific to your application.

If you modify data values and want to write it to a COLLADA instance document, the process is similar to reversing the import-and-convert process, although there are some differences.

Modifying a COLLADA DOM Object Structure

In some cases, your application might modify the structure of your application objects that you loaded from a COLLADA DOM object. If you want to export the data back to a COLLADA instance document, you must change the structure of the COLLADA DOM object to match your changes before converting from your application-specific structures. The example code does not show how to do this.

Creating a New COLLADA DOM Object Using createTo

In some cases, you might need to export your data to an entirely new COLLADA document, such as when the data originated in your application rather than by being imported from an existing COLLADA instance document. In this cases, to use the integration methods to convert from your application structure to a DOM object and then export to a new COLLADA instance document, you must create the matching COLLADA DOM structure before you can convert from your application’s structure.

Compare with the import process: When your application loads a COLLADA instance document, the COLLADA DOM automatically creates DAE objects in which to load the COLLADA data, then calls your customized createFrom for each element that has an integration class, which creates your application-specific objects. Then it calls fromCOLLADA, which copies the data from the DAE objects to your application objects.

If you create a new application object, there are no COLLADA elements (no DAE objects) associated with it. If you simply save the file, this new data is not written. The purpose of createTo is to create these COLLADA elements and associate them with the application object. createTo is not called automatically when a new application object is created; you must call it explicitly. After createTo has been called, the rest of the saving process is automatic, that is, if you have registered your integration library, when you call save, toCOLLADA is called for every COLLADA element with an integration class to copy the data from the application objects into the COLLADA objects.

This example code does not show how to do this. The createTo method looks like this:

void intGeometry::createTo(void *userData)
{
    // This function would create new COLLADA elements from an
    // application- defined object
    // It is NOT called automatically by the COLLADA DOM.
    // The user needs to call this when creating a new
    // application-specific object.
}

Exporting Data Value Modifications

If you have modified only the values of the COLLADA data and want to export to a revised COLLADA instance document, this example shows how you might convert the data.

The saving process for this example is automatic because you have registered your integration library. When you call save, toCOLLADA is called for every COLLADA element with an integration class. This copies the data from the application objects into the COLLADA ones.

Note that the code is essentially the reverse of the fromCOLLADA code in the importing example.

void intGeometry::toCOLLADA()
{
    // INSERT CODE TO TRANSLATE TO YOUR RUNTIME HERE
    // The following lines are example code from the template:
    // myRuntimeClassType* local = (myRuntimeClassType*)_object;
    // element->foo = local->foo;
    // element->subelem[0]->bar = local->bar;
    // This code takes data from an application-defined object and
    // puts it back into the appropriate collada objects.
    // Get a pointer to the COLLADA domGeometry element
    // (this is the element that called us)
    domGeometry* geometryElement = (domGeometry*)(domElement*)_element;
    // Get a pointer to the domGeometry's domMesh element
    domMesh *meshElement = geometryElement->getMesh();
    // Get a pointer to my object that's assocated with this collada object
    myGeometry *local = (myGeometry *)_object;
    // Get a pointer to the domPolygons in this domMesh.
    // To simplify this example,
    // we will handle only a domMesh that has a single domPolygons
    if(meshElement->getPolygons_array().getCount() != 1)
    {
        fprintf(stderr, "this example supports only one domPolygons per domMesh\n");
        return;
    }
    domPolygons *polygons = meshElement->getPolygons_array()[0];
    int polygonCount = local->_vPolygons.size();
    // To simplify this example, we assume that the domPolygons has
    // only one domInput
    if(polygons->getInput_array().getCount() != 1)
    {
        fprintf(stderr, "this example supports only one domInput per domPolygons\n");
        return;
    }
    // Loop over all the polygons in the domPolygons element and
    // put the data from
    // myGeometry back into it. For the purposes of the example,
    // assume the number of polygons and indices hasn't changed
    // so we can just update the values in place
    polygons->setCount(polygonCount);
    for (int i=0;i<polygonCount;i++)
    {
        // Get pointer to this polygon (domP)
        domPolygons::domP *poly = polygons->getP_array()[i];
        // Copy all the indices from my structure back to the domP
        for (int j=0;j< local->_vPolygons[i]._iIndexCount-1;j++)
            poly->getValue()[j] = local->_vPolygons[i]._pIndexes[j] ;
    }
    // Now copy the vertices from myGeometry back to the source.
    // Assume that the number of
    // vertices hasn't changed so we can just update them in place.
    if(meshElement->getSource_array().getCount() != 1)
    {
        fprintf(stderr, "this example supports only one source array per domMesh\n");
        return;
    }
    domSource *source = meshElement->getSource_array()[0];
    if(source->getFloat_array_array().getCount() != 1)
    {
        fprintf(stderr, "this example supports only one float array per source\n");
    }
    domFloat_array *floatArray = source->getFloat_array_array()[0];
    // Copy the vertices into from myGeometry back into the
    // COLLADA float array
    floatArray->setCount(local->_iVertexCount*3);
    for ( unsigned int i = 0; i < local->_iVertexCount*3; i++ ) 
    {
        floatArray->getValue()[i] = local->_pVertices[i];
    }
}