OpenSceneGraph/src/osgPlugins/dae/daeWSceneObjects.cpp

540 lines
20 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 "daeWriter.h"
#include <dom/domCOLLADA.h>
#include <dom/domNode.h>
#include <dom/domConstants.h>
#include <dom/domLibrary_cameras.h>
#include <dom/domLibrary_lights.h>
#include <dae/domAny.h>
//#include <dom/domVisual_scene.h>
//#include <dom/domLibrary_visual_scenes.h>
#include <osgSim/MultiSwitch>
#include <osg/Sequence>
#include <osg/Billboard>
#include <osg/CameraView>
using namespace osgDAE;
// Write non-standard node data as extra of type "Node" with "OpenSceneGraph" technique
void daeWriter::writeNodeExtra(osg::Node &node)
{
unsigned int numDesc = node.getDescriptions().size();
// Only create extra if descriptions are filled in
if (writeExtras && (numDesc > 0))
{
// Adds the following to a node
//<extra type="Node">
// <technique profile="OpenSceneGraph">
// <Descriptions>
// <Description>Some info</Description>
// </Descriptions>
// </technique>
//</extra>
domExtra *extra = daeSafeCast<domExtra>(currentNode->add( COLLADA_ELEMENT_EXTRA ));
extra->setType("Node");
domTechnique *teq = daeSafeCast<domTechnique>(extra->add( COLLADA_ELEMENT_TECHNIQUE ) );
teq->setProfile( "OpenSceneGraph" );
domAny *descriptions = (domAny*)teq->add( "Descriptions" );
for (unsigned int currDesc = 0; currDesc < numDesc; currDesc++)
{
std::string value = node.getDescription(currDesc);
if (!value.empty())
{
domAny *description = (domAny*)descriptions->add( "Description" );
description->setValue(value.c_str());
}
}
}
}
void daeWriter::apply( osg::Group &node )
{
debugPrint( node );
updateCurrentDaeNode();
currentNode = daeSafeCast< domNode >(currentNode->add( COLLADA_ELEMENT_NODE ) );
// If a multiswitch node, store it's data as extra "MultiSwitch" data in the "OpenSceneGraph" technique
osgSim::MultiSwitch* multiswitch = dynamic_cast<osgSim::MultiSwitch*>(&node);
if (writeExtras && multiswitch)
{
// Adds the following to a node
//<extra type="MultiSwitch">
// <technique profile="OpenSceneGraph">
// <ActiveSwitchSet>0</ActiveSwitchSet>
// <ValueLists>
// <ValueList>1 0</ValueList>
// <ValueList>0 1</ValueList>
// </ValueLists>
// </technique>
//</extra>
domExtra *extra = daeSafeCast<domExtra>(currentNode->add( COLLADA_ELEMENT_EXTRA ));
extra->setType("MultiSwitch");
domTechnique *teq = daeSafeCast<domTechnique>(extra->add( COLLADA_ELEMENT_TECHNIQUE ) );
teq->setProfile( "OpenSceneGraph" );
domAny *activeSwitchSet = (domAny*)teq->add("ActiveSwitchSet" );
activeSwitchSet->setValue(toString<unsigned int>(multiswitch->getActiveSwitchSet()).c_str());
domAny *valueLists = (domAny*)teq->add( "ValueLists" );
unsigned int pos = 0;
const osgSim::MultiSwitch::SwitchSetList& switchset = multiswitch->getSwitchSetList();
for(osgSim::MultiSwitch::SwitchSetList::const_iterator sitr=switchset.begin();
sitr!=switchset.end();
++sitr,++pos)
{
domAny *valueList = (domAny*)valueLists->add( "ValueList" );
std::stringstream fw;
const osgSim::MultiSwitch::ValueList& values = *sitr;
for(osgSim::MultiSwitch::ValueList::const_iterator itr=values.begin();
itr!=values.end();
++itr)
{
if (itr != values.begin())
{
fw << " ";
}
fw << *itr;
}
valueList->setValue(fw.str().c_str());
}
currentNode->setId(getNodeName(node,"multiswitch").c_str());
}
else
{
writeAnimations(node);
currentNode->setId(getNodeName(node,"group").c_str());
}
writeNodeExtra(node);
lastDepth = _nodePath.size();
traverse( node );
}
void daeWriter::apply( osg::Switch &node )
{
debugPrint( node );
updateCurrentDaeNode();
currentNode = daeSafeCast< domNode >(currentNode->add( COLLADA_ELEMENT_NODE ) );
currentNode->setId(getNodeName(node,"switch").c_str());
if (writeExtras)
{
// Adds the following to a node
//<extra type="Switch">
// <technique profile="OpenSceneGraph">
// <ValueList>1 0</ValueList>
// </technique>
//</extra>
domExtra *extra = daeSafeCast<domExtra>(currentNode->add( COLLADA_ELEMENT_EXTRA ));
extra->setType("Switch");
domTechnique *teq = daeSafeCast<domTechnique>(extra->add( COLLADA_ELEMENT_TECHNIQUE ) );
teq->setProfile( "OpenSceneGraph" );
domAny *valueList = (domAny*)teq->add( "ValueList" );
std::stringstream fw;
const osg::Switch::ValueList& values = node.getValueList();
for(osg::Switch::ValueList::const_iterator itr=values.begin();
itr!=values.end();
++itr)
{
if (itr != values.begin())
{
fw << " ";
}
fw << *itr;
}
valueList->setValue(fw.str().c_str());
}
writeNodeExtra(node);
lastDepth = _nodePath.size();
// Process all children
traverse( node );
}
void daeWriter::apply( osg::Sequence &node )
{
debugPrint( node );
updateCurrentDaeNode();
currentNode = daeSafeCast< domNode >(currentNode->add( COLLADA_ELEMENT_NODE ) );
currentNode->setId(getNodeName(node,"sequence").c_str());
// If a sequence node, store it's data as extra "Sequence" data in the "OpenSceneGraph" technique
if (writeExtras)
{
// Adds the following to a node
//<extra type="Sequence">
// <technique profile="OpenSceneGraph">
// <FrameTime>0 0</FrameTime>
// <LastFrameTime>0</LastFrameTime>
// <LoopMode>0</LoopMode>
// <IntervalBegin>0</IntervalBegin>
// <IntervalEnd>-1</IntervalEnd>
// <DurationSpeed>1</DurationSpeed>
// <DurationNReps>-1</DurationNReps>
// <SequenceMode>0</SequenceMode>
// </technique>
//</extra>
domExtra *extra = daeSafeCast<domExtra>(currentNode->add( COLLADA_ELEMENT_EXTRA ));
extra->setType("Sequence");
domTechnique *teq = daeSafeCast<domTechnique>(extra->add( COLLADA_ELEMENT_TECHNIQUE ) );
teq->setProfile( "OpenSceneGraph" );
domAny *frameTime = (domAny*)teq->add("FrameTime");
std::stringstream fw;
for (unsigned int i = 0; i < node.getNumChildren(); i++)
{
if (i > 0)
{
fw << " ";
}
fw << node.getTime(i);
}
frameTime->setValue(fw.str().c_str());
domAny *lastFrameTime = (domAny*)teq->add("LastFrameTime");
lastFrameTime->setValue(toString<double>(node.getLastFrameTime()).c_str());
// loop mode & interval
osg::Sequence::LoopMode mode;
int begin, end;
node.getInterval(mode, begin, end);
domAny *loopMode = (domAny*)teq->add("LoopMode");
loopMode->setValue(toString<osg::Sequence::LoopMode>(mode).c_str());
domAny *intervalBegin = (domAny*)teq->add("IntervalBegin");
intervalBegin->setValue(toString<int>(begin).c_str());
domAny *intervalEnd = (domAny*)teq->add("IntervalEnd");
intervalEnd->setValue(toString<int>(end).c_str());
// duration
float speed;
int nreps;
node.getDuration(speed, nreps);
domAny *durationSpeed = (domAny*)teq->add("DurationSpeed");
durationSpeed->setValue(toString<float>(speed).c_str());
domAny *durationNReps = (domAny*)teq->add("DurationNReps");
durationNReps->setValue(toString<int>(nreps).c_str());
// sequence mode
domAny *sequenceMode = (domAny*)teq->add("SequenceMode");
sequenceMode->setValue(toString<osg::Sequence::SequenceMode>(node.getMode()).c_str());
}
writeNodeExtra(node);
lastDepth = _nodePath.size();
traverse( node );
}
void daeWriter::apply( osg::LOD &node )
{
debugPrint( node );
updateCurrentDaeNode();
lastDepth = _nodePath.size();
currentNode = daeSafeCast< domNode >(currentNode->add( COLLADA_ELEMENT_NODE ) );
currentNode->setId(getNodeName(node,"LOD").c_str());
if (writeExtras)
{
// Store LOD data as extra "LOD" data in the "OpenSceneGraph" technique
// Adds the following to a node
//<extra type="LOD">
// <technique profile="OpenSceneGraph">
// <Center>1 2 3</Center> (optional )
// <Radius>-1</Radius> (required if Center is available)
// <RangeMode>0</RangeMode>
// <RangeList>
// <MinMax>0 300</MinMax>
// <MinMax>300 600</MinMax>
// </RangeList>
// </technique>
//</extra>
domExtra *extra = daeSafeCast<domExtra>(currentNode->add( COLLADA_ELEMENT_EXTRA ));
extra->setType("LOD");
domTechnique *teq = daeSafeCast<domTechnique>(extra->add( COLLADA_ELEMENT_TECHNIQUE ) );
teq->setProfile( "OpenSceneGraph" );
if (node.getCenterMode()==osg::LOD::USER_DEFINED_CENTER)
{
domAny *center = (domAny*)teq->add("Center");
center->setValue(toString(node.getCenter()).c_str());
domAny *radius = (domAny*)teq->add("Radius");
radius->setValue(toString<osg::LOD::value_type>(node.getRadius()).c_str());
}
domAny *rangeMode = (domAny*)teq->add("RangeMode");
rangeMode->setValue(toString<osg::LOD::RangeMode>(node.getRangeMode()).c_str());
domAny *valueLists = (domAny*)teq->add("RangeList");
unsigned int pos = 0;
const osg::LOD::RangeList& rangelist = node.getRangeList();
for(osg::LOD::RangeList::const_iterator sitr=rangelist.begin();
sitr!=rangelist.end();
++sitr,++pos)
{
domAny *valueList = (domAny*)valueLists->add("MinMax");
std::stringstream fw;
fw << sitr->first << " " << sitr->second;
valueList->setValue(fw.str().c_str());
}
}
writeNodeExtra(node);
// Process all children
traverse( node );
}
void daeWriter::apply( osg::ProxyNode &node )
{
OSG_WARN << "ProxyNode. Missing " << node.getNumChildren() << " children" << std::endl;
}
void daeWriter::apply( osg::LightSource &node )
{
debugPrint( node );
updateCurrentDaeNode();
domInstance_light *il = daeSafeCast< domInstance_light >( currentNode->add( COLLADA_ELEMENT_INSTANCE_LIGHT ) );
std::string name = node.getName();
if ( name.empty() )
{
name = uniquify( "light" );
}
std::string url = "#" + name;
il->setUrl( url.c_str() );
if ( lib_lights == NULL )
{
lib_lights = daeSafeCast< domLibrary_lights >( dom->add( COLLADA_ELEMENT_LIBRARY_LIGHTS ) );
}
domLight *light = daeSafeCast< domLight >( lib_lights->add( COLLADA_ELEMENT_LIGHT ) );
light->setId( name.c_str() );
osg::Light* pOsgLight = node.getLight();
domLight *pDomLight = daeSafeCast< domLight >( lib_lights->add( COLLADA_ELEMENT_LIGHT ) );
pDomLight->setId( name.c_str() );
domLight::domTechnique_common *domTechniqueCommon = daeSafeCast<domLight::domTechnique_common>(pDomLight->add(COLLADA_ELEMENT_TECHNIQUE_COMMON));
osg::Vec4 position = pOsgLight->getPosition();
osg::Vec3 direction = pOsgLight->getDirection();
osg::Vec4 ambientColor = pOsgLight->getAmbient();
osg::Vec4 diffuseColor = pOsgLight->getDiffuse();
osg::Vec4 specularColor = pOsgLight->getSpecular();
if (position.w() == 0)
{
// Directional light
domLight::domTechnique_common::domDirectional *domDirectional = daeSafeCast<domLight::domTechnique_common::domDirectional>(domTechniqueCommon->add(COLLADA_ELEMENT_DIRECTIONAL));
if ((position.x() != 0) || (position.y() != 0) || (position.z() != 0))
{
osg::Vec3 dir(-position.x(), -position.y(), -position.z());
// TODO wrap instance_light in a rotating node to translate default light [0,0,-1] into proper direction
}
domFloat3 color;
color.append3(diffuseColor.r(), diffuseColor.g(), diffuseColor.b());
domDirectional->add(COLLADA_ELEMENT_COLOR);
domDirectional->getColor()->setValue(color);
}
else if (direction.length() == 0)
{
// Omni/point light
domLight::domTechnique_common::domPoint *domPoint = daeSafeCast<domLight::domTechnique_common::domPoint>(domTechniqueCommon->add(COLLADA_ELEMENT_POINT));
domPoint->add(COLLADA_ELEMENT_CONSTANT_ATTENUATION);
domPoint->getConstant_attenuation()->setValue(pOsgLight->getConstantAttenuation());
domPoint->add(COLLADA_ELEMENT_LINEAR_ATTENUATION);
domPoint->getLinear_attenuation()->setValue(pOsgLight->getLinearAttenuation());
domPoint->add(COLLADA_ELEMENT_QUADRATIC_ATTENUATION);
domPoint->getQuadratic_attenuation()->setValue(pOsgLight->getQuadraticAttenuation());
if ((position.x() != 0) || (position.y() != 0) || (position.z() != 0))
{
// TODO wrap instance_light in a transforming node to translate default light [0,0,0] into proper position
}
domFloat3 color;
color.append3(diffuseColor.r(), diffuseColor.g(), diffuseColor.b());
domPoint->add(COLLADA_ELEMENT_COLOR);
domPoint->getColor()->setValue(color);
}
else
{
// Spot light
domLight::domTechnique_common::domSpot *domSpot = daeSafeCast<domLight::domTechnique_common::domSpot>(domTechniqueCommon->add(COLLADA_ELEMENT_SPOT));
domSpot->add(COLLADA_ELEMENT_CONSTANT_ATTENUATION);
domSpot->getConstant_attenuation()->setValue(pOsgLight->getConstantAttenuation());
domSpot->add(COLLADA_ELEMENT_LINEAR_ATTENUATION);
domSpot->getLinear_attenuation()->setValue(pOsgLight->getLinearAttenuation());
domSpot->add(COLLADA_ELEMENT_QUADRATIC_ATTENUATION);
domSpot->getQuadratic_attenuation()->setValue(pOsgLight->getQuadraticAttenuation());
if ((position.x() != 0) || (position.y() != 0) || (position.z() != 0))
{
// TODO wrap instance_light in a transforming node to translate default light [0,0,0] into proper position
// and rotate default direction [0,0,-1] into proper dir
}
domFloat3 color;
color.append3(diffuseColor.r(), diffuseColor.g(), diffuseColor.b());
domSpot->add(COLLADA_ELEMENT_COLOR);
domSpot->getColor()->setValue(color);
domSpot->add(COLLADA_ELEMENT_FALLOFF_ANGLE);
domSpot->getFalloff_angle()->setValue(pOsgLight->getSpotCutoff());
domSpot->add(COLLADA_ELEMENT_FALLOFF_EXPONENT);
domSpot->getFalloff_exponent()->setValue(pOsgLight->getSpotExponent());
}
// Write ambient as a separate Collada <ambient> light
if ((ambientColor.r() != 0) || (ambientColor.g() != 0) || (ambientColor.b() != 0))
{
domInstance_light *ambientDomInstanceLight = daeSafeCast< domInstance_light >(currentNode->add( COLLADA_ELEMENT_INSTANCE_LIGHT ));
std::string name = node.getName();
if (name.empty())
{
name = uniquify( "light-ambient" );
}
else
{
name += "-ambient";
}
std::string url = "#" + name;
ambientDomInstanceLight->setUrl( url.c_str() );
domLight *ambientDomLight = daeSafeCast< domLight >( lib_lights->add( COLLADA_ELEMENT_LIGHT ) );
ambientDomLight->setId(name.c_str());
domLight::domTechnique_common *ambientDomTechniqueCommon = daeSafeCast<domLight::domTechnique_common>(ambientDomLight->add(COLLADA_ELEMENT_TECHNIQUE_COMMON));
// Ambient light
domLight::domTechnique_common::domAmbient *domAmbient = daeSafeCast<domLight::domTechnique_common::domAmbient>(ambientDomTechniqueCommon->add(COLLADA_ELEMENT_AMBIENT));
domFloat3 color;
color.append3(ambientColor.r(), ambientColor.g(), ambientColor.b());
domAmbient->add(COLLADA_ELEMENT_COLOR);
domAmbient->getColor()->setValue(color);
}
traverse( node );
}
void daeWriter::apply( osg::Camera &node )
{
debugPrint( node );
updateCurrentDaeNode();
domInstance_camera *ic = daeSafeCast< domInstance_camera >( currentNode->add( COLLADA_ELEMENT_INSTANCE_CAMERA ) );
std::string name = node.getName();
if ( name.empty() )
{
name = uniquify( "camera" );
}
std::string url = "#" + name;
ic->setUrl( url.c_str() );
if ( lib_cameras == NULL )
{
lib_cameras = daeSafeCast< domLibrary_cameras >( dom->add( COLLADA_ELEMENT_LIBRARY_CAMERAS ) );
}
domCamera *cam = daeSafeCast< domCamera >( lib_cameras->add( COLLADA_ELEMENT_CAMERA ) );
cam->setId( name.c_str() );
traverse( node );
}
void daeWriter::apply( osg::CameraView &node)
{
debugPrint( node );
updateCurrentDaeNode();
domInstance_camera *ic = daeSafeCast< domInstance_camera >( currentNode->add(COLLADA_ELEMENT_INSTANCE_CAMERA));
std::string name = node.getName();
if ( name.empty() )
{
name = uniquify( "camera" );
}
std::string url = "#" + name;
ic->setUrl( url.c_str() );
if ( lib_cameras == NULL )
{
lib_cameras = daeSafeCast< domLibrary_cameras >( dom->add( COLLADA_ELEMENT_LIBRARY_CAMERAS ) );
}
domCamera *cam = daeSafeCast< domCamera >( lib_cameras->add( COLLADA_ELEMENT_CAMERA ) );
cam->setId( name.c_str() );
domCamera::domOptics *optics = daeSafeCast< domCamera::domOptics >( cam->add( COLLADA_ELEMENT_OPTICS ) );
domCamera::domOptics::domTechnique_common *techniqueCommon = daeSafeCast< domCamera::domOptics::domTechnique_common >( optics->add( COLLADA_ELEMENT_TECHNIQUE_COMMON ) );
domCamera::domOptics::domTechnique_common::domPerspective *pDomPerspective = daeSafeCast< domCamera::domOptics::domTechnique_common::domPerspective >( techniqueCommon->add( COLLADA_ELEMENT_PERSPECTIVE ) );
domTargetableFloat *pXfov = NULL;
domTargetableFloat *pYfov = NULL;
switch(node.getFieldOfViewMode())
{
case(osg::CameraView::UNCONSTRAINED):
pXfov = daeSafeCast< domTargetableFloat >( pDomPerspective->add( COLLADA_ELEMENT_XFOV ) );
pXfov->setValue(node.getFieldOfView());
break;
case(osg::CameraView::HORIZONTAL):
pXfov = daeSafeCast< domTargetableFloat >( pDomPerspective->add( COLLADA_ELEMENT_XFOV ) );
pXfov->setValue(node.getFieldOfView());
break;
case(osg::CameraView::VERTICAL):
pYfov = daeSafeCast< domTargetableFloat >( pDomPerspective->add( COLLADA_ELEMENT_YFOV ) );
pYfov->setValue(node.getFieldOfView());
break;
}
// Using hardcoded values for <aspect_ratio>, <znear> and <zfar>
domTargetableFloat *pAspectRatio = daeSafeCast< domTargetableFloat >( pDomPerspective->add( COLLADA_ELEMENT_ASPECT_RATIO ) );
pAspectRatio->setValue(1.0);
domTargetableFloat *pNear = daeSafeCast< domTargetableFloat >( pDomPerspective->add( COLLADA_ELEMENT_ZNEAR ) );
pNear->setValue(1);
domTargetableFloat *pFar = daeSafeCast< domTargetableFloat >( pDomPerspective->add( COLLADA_ELEMENT_ZFAR ) );
pFar->setValue(1000);
}