Files
OpenSceneGraph/src/osgPlugins/dae/daeRGeometry.cpp

499 lines
16 KiB
C++

/*
* Copyright 2006 Sony Computer Entertainment Inc.
*
* Licensed under the SCEA Shared Source License, Version 1.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the License at:
* http://research.scea.com/scea_shared_source_license.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing permissions and limitations under the
* License.
*/
#include "daeReader.h"
#include "domSourceReader.h"
#include <dae.h>
#include <dom/domCOLLADA.h>
#include <dom/domInstance_geometry.h>
#include <dom/domInstance_controller.h>
#include <dom/domController.h>
#include <osg/Geometry>
using namespace osgdae;
osg::Node* daeReader::processInstance_geometry( domInstance_geometry *ig )
{
//TODO: cache geometries so they don't get processed mulitple times.
//TODO: after cached need to check geometries and materials. both have to be the same for it
// to be the same instance.
daeElement *el = getElementFromURI( ig->getUrl() );
domGeometry *geom = daeSafeCast< domGeometry >( el );
if ( geom == NULL )
{
osg::notify( osg::WARN ) << "Failed to locate geometry " << ig->getUrl().getURI() << std::endl;
return NULL;
}
//check cache if geometry already exists
osg::Node *geo;
std::map< domGeometry*, osg::Node* >::iterator iter = geometryMap.find( geom );
if ( iter != geometryMap.end() )
{
geo = iter->second;
}
else
{
geo = processGeometry( geom );
geometryMap.insert( std::make_pair( geom, geo ) );
}
if ( geo == NULL )
{
osg::notify( osg::WARN ) << "Failed to load geometry " << ig->getUrl().getURI() << std::endl;
return NULL;
}
//process material bindings
if ( ig->getBind_material() != NULL )
{
processBindMaterial( ig->getBind_material(), geo );
}
return geo;
}
osg::Node* daeReader::processInstance_controller( domInstance_controller *ictrl )
{
//TODO: cache geometries so they don't get processed mulitple times.
//TODO: after cached need to check geometries and materials. both have to be the same for it
// to be the same instance.
//TODO: support skinning
osg::notify( osg::WARN ) << "Processing <instance_controller>. There is not skinning support but will display the base mesh." << std::endl;
daeElement *el = getElementFromURI( ictrl->getUrl() );
domController *ctrl = daeSafeCast< domController >( el );
if ( ctrl == NULL )
{
osg::notify( osg::WARN ) << "Failed to locate controller " << ictrl->getUrl().getURI() << std::endl;
return NULL;
}
el = NULL;
//## non init
daeURI *src=NULL;
if ( ctrl->getSkin() != NULL )
{
src = &ctrl->getSkin()->getSource();
el = getElementFromURI( ctrl->getSkin()->getSource() );
}
else if ( ctrl->getMorph() != NULL )
{
src = &ctrl->getSkin()->getSource();
el = getElementFromURI( ctrl->getMorph()->getSource() );
}
//non init case
if ( !src )
{
osg::notify( osg::WARN ) << "Failed to locate geometry : URI is NULL" << std::endl;
return NULL;
}
domGeometry *geom = daeSafeCast< domGeometry >( el );
if ( geom == NULL )
{
osg::notify( osg::WARN ) << "Failed to locate geometry " << src->getURI() << std::endl;
return NULL;
}
osg::Node *geo;
std::map< domGeometry*, osg::Node* >::iterator iter = geometryMap.find( geom );
if ( iter != geometryMap.end() )
{
geo = iter->second;
}
else
{
geo = processGeometry( geom );
geometryMap.insert( std::make_pair( geom, geo ) );
}
if ( geo == NULL )
{
osg::notify( osg::WARN ) << "Failed to load geometry " << src->getURI() << std::endl;
return NULL;
}
//process material bindings
if ( ictrl->getBind_material() != NULL )
{
processBindMaterial( ictrl->getBind_material(), geo );
}
return geo;
}
osg::Node *daeReader::processGeometry( domGeometry *geo )
{
domMesh *mesh = geo->getMesh();
if ( mesh == NULL )
{
osg::notify( osg::WARN ) << "Unsupported Geometry type loading " << geo->getId() << std::endl;
return NULL;
}
osg::Node *node = new osg::Group();
if ( geo->getId() != NULL )
{
node->setName( geo->getId() );
}
SourceMap sources;
size_t count = mesh->getContents().getCount();
for ( size_t i = 0; i < count; i++ )
{
if ( daeSafeCast< domVertices >( mesh->getContents()[i] ) != NULL ) continue;
domSource *s = daeSafeCast< domSource >( mesh->getContents()[i] );
if ( s != NULL )
{
sources.insert( std::make_pair( (daeElement*)mesh->getContents()[i],
domSourceReader( s ) ) );
continue;
}
osg::Node *n = NULL;
domTriangles *t = daeSafeCast< domTriangles >( mesh->getContents()[i] );
if ( t != NULL )
{
n = processSinglePPrimitive( t, sources, GL_TRIANGLES );
if ( n != NULL )
{
node->asGroup()->addChild( n );
}
continue;
}
domTristrips *ts = daeSafeCast< domTristrips >( mesh->getContents()[i] );
if ( ts != NULL )
{
n = processMultiPPrimitive( ts, sources, GL_TRIANGLE_STRIP );
if ( n != NULL )
{
node->asGroup()->addChild( n );
}
continue;
}
domTrifans *tf = daeSafeCast< domTrifans >( mesh->getContents()[i] );
if ( tf != NULL )
{
n = processMultiPPrimitive( tf, sources, GL_TRIANGLE_FAN );
if ( n != NULL )
{
node->asGroup()->addChild( n );
}
continue;
}
domLines *l = daeSafeCast< domLines >( mesh->getContents()[i] );
if ( l != NULL )
{
n = processSinglePPrimitive( l, sources, GL_LINES );
if ( n != NULL )
{
node->asGroup()->addChild( n );
}
continue;
}
domLinestrips *ls = daeSafeCast< domLinestrips >( mesh->getContents()[i] );
if ( ls != NULL )
{
n = processMultiPPrimitive( ls, sources, GL_LINE_STRIP );
if ( n != NULL )
{
node->asGroup()->addChild( n );
}
continue;
}
domPolygons *p = daeSafeCast< domPolygons >( mesh->getContents()[i] );
if ( p != NULL )
{
n = processMultiPPrimitive( p, sources, GL_POLYGON );
if ( n != NULL )
{
node->asGroup()->addChild( n );
}
continue;
}
domPolylist *pl = daeSafeCast< domPolylist >( mesh->getContents()[i] );
if ( pl != NULL )
{
n = processPolylist( pl, sources );
if ( n != NULL )
{
node->asGroup()->addChild( n );
}
continue;
}
osg::notify( osg::WARN ) << "Unsupported primitive type " << mesh->getContents()[i]->getTypeName() << " in geometry " << geo->getId() << std::endl;
}
return node;
}
template< typename T >
osg::Node* daeReader::processSinglePPrimitive( T *group, SourceMap &sources, GLenum mode )
{
osg::Geode* geode = new osg::Geode();
osg::Geometry *geometry = new osg::Geometry();
//Setting the name of the geode to the material symbol for easy binding later
if ( group->getMaterial() != NULL )
{
geode->setName( group->getMaterial() );
}
IndexMap index_map;
resolveArrays( group->getInput_array(), geometry, sources, index_map );
osg::DrawArrayLengths* dal = new osg::DrawArrayLengths( mode );
processP( group->getP(), geometry, index_map, dal/*mode*/ );
geometry->addPrimitiveSet( dal );
geode->addDrawable( geometry );
return geode;
}
template< typename T >
osg::Node* daeReader::processMultiPPrimitive( T *group, SourceMap &sources, GLenum mode )
{
osg::Geode* geode = new osg::Geode();
osg::Geometry *geometry = new osg::Geometry();
//Setting the name of the geode to the material symbol for easy binding later
if ( group->getMaterial() != NULL )
{
geode->setName( group->getMaterial() );
}
IndexMap index_map;
resolveArrays( group->getInput_array(), geometry, sources, index_map );
osg::DrawArrayLengths* dal = new osg::DrawArrayLengths( mode );
for ( size_t i = 0; i < group->getP_array().getCount(); i++ )
{
processP( group->getP_array()[i], geometry, index_map, dal/*mode*/ );
}
geometry->addPrimitiveSet( dal );
geode->addDrawable( geometry );
return geode;
}
osg::Node* daeReader::processPolylist( domPolylist *group, SourceMap &sources )
{
osg::Geode* geode = new osg::Geode();
osg::Geometry *geometry = new osg::Geometry();
//Setting the name of the geode to the material symbol for easy binding later
if ( group->getMaterial() != NULL )
{
geode->setName( group->getMaterial() );
}
IndexMap index_map;
resolveArrays( group->getInput_array(), geometry, sources, index_map );
osg::DrawArrayLengths* dal = new osg::DrawArrayLengths( GL_POLYGON );
//domPRef p = (domP*)(daeElement*)domP::_Meta->create(); //I don't condone creating elements like this but I don't care
domPRef p = (domP*)domP::registerElement(*dae)->create().cast();
//if it created properly because I never want it as part of the document. Its just a temporary
//element to trick the importer into loading polylists easier.
unsigned int maxOffset = 0;
for ( unsigned int i = 0; i < group->getInput_array().getCount(); i++ )
{
if ( group->getInput_array()[i]->getOffset() > maxOffset )
{
maxOffset = group->getInput_array()[i]->getOffset();
}
}
maxOffset++;
unsigned int pOffset = 0;
for ( unsigned int i = 0; i < group->getCount(); i++ )
{
p->getValue().clear();
for ( unsigned int x = 0; x < group->getVcount()->getValue()[i]; x++ )
{
for ( unsigned int y = 0; y < maxOffset; y++ )
{
p->getValue().append( group->getP()->getValue()[ pOffset + x*maxOffset + y ] );
}
}
pOffset += group->getVcount()->getValue()[i] * maxOffset;
processP( p, geometry, index_map, dal/*mode*/ );
}
geometry->addPrimitiveSet( dal );
geode->addDrawable( geometry );
return geode;
}
void daeReader::processP( domP *p, osg::Geometry *&/*geom*/, IndexMap &index_map, osg::DrawArrayLengths* dal /*GLenum mode*/ )
{
//osg::DrawArrayLengths* dal = new osg::DrawArrayLengths( mode );
int idxcount = index_map.size();
int count = p->getValue().getCount();
count = (count/idxcount)*idxcount;
dal->push_back(count/idxcount);
int j = 0;
while ( j < count ) {
for ( IndexMap::iterator k = index_map.begin(); k != index_map.end(); k++,j++ ) {
int tmp = p->getValue()[j];
k->second->push_back(tmp);
}
}
//geom->addPrimitiveSet( dal );
}
void daeReader::resolveArrays( domInputLocalOffset_Array &inputs, osg::Geometry *&geom,
SourceMap &sources, IndexMap &index_map )
{
domVertices* vertices = NULL;
daeElement* position_source = NULL;
daeElement* color_source = NULL;
daeElement* normal_source = NULL;
daeElement* texcoord_source = NULL;
int offset;
int set;
daeElement *tmp_el;
domInputLocalOffset *tmp_input;
if ( findInputSourceBySemantic( inputs, "VERTEX", tmp_el, &tmp_input ) ) {
vertices = daeSafeCast< domVertices >( tmp_el );
if ( vertices == NULL ) {
osg::notify( osg::WARN )<<"Could not get vertices"<<std::endl;
return;
}
offset = tmp_input->getOffset();
set = tmp_input->getSet(); //if it wasn't actually set it will initialize to 0 which is
//the value we would want anyways.
domInputLocal *tmp;
findInputSourceBySemantic( vertices->getInput_array(), "POSITION", position_source, &tmp );
findInputSourceBySemantic( vertices->getInput_array(), "COLOR", color_source, &tmp );
findInputSourceBySemantic( vertices->getInput_array(), "NORMAL", normal_source, &tmp );
findInputSourceBySemantic( vertices->getInput_array(), "TEXCOORD", texcoord_source, &tmp );
if ( index_map[offset] == NULL ) {
index_map[offset] = new osg::IntArray();
}
geom->setVertexIndices( index_map[offset] );
if ( position_source != NULL )
{
geom->setVertexArray( sources[position_source].getVec3Array() );
}
if ( color_source != NULL )
{
geom->setColorArray( sources[color_source].getVec4Array() );
geom->setColorIndices( index_map[offset] );
geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
}
if ( normal_source != NULL )
{
geom->setNormalArray( sources[normal_source].getVec3Array() );
geom->setNormalIndices( index_map[offset] );
geom->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
}
if ( texcoord_source != NULL )
{
domSourceReader *sc = &sources[texcoord_source];
switch( sc->getArrayType() ) {
case domSourceReader::Vec2:
geom->setTexCoordArray( set, sc->getVec2Array() );
break;
case domSourceReader::Vec3:
geom->setTexCoordArray( set, sc->getVec3Array() );
break;
default:
osg::notify( osg::WARN )<<"Unsupported array type: "<< sc->getArrayType() <<std::endl;
break;
}
geom->setTexCoordIndices( set, index_map[offset] );
}
}
else
{
osg::notify( osg::WARN )<<"Vertex data not found"<<std::endl;
return;
}
if ( findInputSourceBySemantic( inputs, "COLOR", color_source, &tmp_input ) ) {
offset = tmp_input->getOffset();
if ( index_map[offset] == NULL ) {
index_map[offset] = new osg::IntArray();
}
geom->setColorIndices( index_map[offset] );
}
if ( color_source != NULL ) {
geom->setColorArray( sources[color_source].getVec4Array() );
geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
}
if ( findInputSourceBySemantic( inputs, "NORMAL", normal_source, &tmp_input ) ) {
offset = tmp_input->getOffset();
if ( index_map[offset] == NULL ) {
index_map[offset] = new osg::IntArray();
}
geom->setNormalIndices( index_map[offset] );
}
if ( normal_source ) {
geom->setNormalArray( sources[normal_source].getVec3Array() );
geom->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
}
int unit = 0;
while ( findInputSourceBySemantic( inputs, "TEXCOORD", texcoord_source, &tmp_input, unit ) ) {
offset = tmp_input->getOffset();
set = tmp_input->getSet();
if ( index_map[offset] == NULL ) {
index_map[offset] = new osg::IntArray();
}
//this should really be set. Then when you bind_vertex_input you can adjust accordingly for the
//effect which currently only puts textures in texunit 0
geom->setTexCoordIndices( unit/*set*/, index_map[offset] );
if ( texcoord_source != NULL )
{
domSourceReader &sc = sources[texcoord_source];
switch( sc.getArrayType() ) {
case domSourceReader::Vec2:
geom->setTexCoordArray( unit/*set*/, sc.getVec2Array() );
break;
case domSourceReader::Vec3:
geom->setTexCoordArray( unit/*set*/, sc.getVec3Array() );
break;
default:
osg::notify( osg::WARN )<<"Unsupported array type: "<< sc.getArrayType() <<std::endl;
break;
}
}
unit++;
}
}