Updated to slideshow3D to support animation + pausing of animation.

Updated associated osg/osgUtil classes that provide animation pausing.
This commit is contained in:
Robert Osfield
2003-11-03 23:13:31 +00:00
parent de77cede2b
commit bc7622149d
13 changed files with 679 additions and 116 deletions

View File

@@ -10,6 +10,8 @@
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include <sstream>
/**
* OpenSceneGraph plugin wrapper/converter.
@@ -57,7 +59,23 @@ public:
return _colorMap[str];
}
inline bool read(const char* str, float& value) const;
inline bool read(const char* str, osg::Vec2& value) const;
inline bool read(const char* str, osg::Vec3& value) const;
inline bool read(const char* str, osg::Vec4& value) const;
inline bool read(const std::string& str, float& value) const;
inline bool read(const std::string& str, osg::Vec2& value) const;
inline bool read(const std::string& str, osg::Vec3& value) const;
inline bool read(const std::string& str, osg::Vec4& value) const;
bool getProperty(xmlNodePtr cur, const char* token) const;
bool getProperty(xmlNodePtr cur, const char* token, float& value) const;
bool getProperty(xmlNodePtr cur, const char* token, osg::Vec2& value) const;
bool getProperty(xmlNodePtr cur, const char* token, osg::Vec3& value) const;
bool getProperty(xmlNodePtr cur, const char* token, osg::Vec4& value) const;
bool getProperty(xmlNodePtr cur, const char* token, std::string& value) const;
std::map<std::string,osg::Vec4> _colorMap;
};
@@ -65,46 +83,206 @@ public:
// Register with Registry to instantiate the above reader/writer.
osgDB::RegisterReaderWriterProxy<ReaderWriterSS3D> g_readerWriter_SS3D_Proxy;
bool ReaderWriterSS3D::read(const char* str, float& value) const
{
if (!str) return false;
std::istringstream iss((const char*)str);
iss >> value;
return !iss.fail();
}
bool ReaderWriterSS3D::read(const char* str, osg::Vec2& value) const
{
if (!str) return false;
std::istringstream iss((const char*)str);
iss >> value.x() >> value.y();
return !iss.fail();
}
bool ReaderWriterSS3D::read(const char* str, osg::Vec3& value) const
{
if (!str) return false;
std::istringstream iss((const char*)str);
iss >> value.x() >> value.y() >> value.z();
return !iss.fail();
}
bool ReaderWriterSS3D::read(const char* str, osg::Vec4& value) const
{
if (!str) return false;
std::istringstream iss((const char*)str);
iss >> value.x() >> value.y() >> value.z() >> value.w();
return !iss.fail();
}
bool ReaderWriterSS3D::read(const std::string& str, float& value) const
{
std::istringstream iss(str);
iss >> value;
return !iss.fail();
}
bool ReaderWriterSS3D::read(const std::string& str, osg::Vec2& value) const
{
std::istringstream iss(str);
iss >> value.x() >> value.y();
return !iss.fail();
}
bool ReaderWriterSS3D::read(const std::string& str, osg::Vec3& value) const
{
std::istringstream iss(str);
iss >> value.x() >> value.y() >> value.z();
return !iss.fail();
}
bool ReaderWriterSS3D::read(const std::string& str, osg::Vec4& value) const
{
std::istringstream iss(str);
iss >> value.x() >> value.y() >> value.z() >> value.w();
return !iss.fail();
}
bool ReaderWriterSS3D::getProperty(xmlNodePtr cur, const char* token) const
{
bool success = false;
xmlChar *key;
key = xmlGetProp (cur, (const xmlChar *)token);
if (key) success=true;
xmlFree(key);
return success;
}
bool ReaderWriterSS3D::getProperty(xmlNodePtr cur, const char* token, float& value) const
{
xmlChar *key;
key = xmlGetProp (cur, (const xmlChar *)token);
bool success = read((const char*)key,value);
xmlFree(key);
return success;
}
bool ReaderWriterSS3D::getProperty(xmlNodePtr cur, const char* token, osg::Vec2& value) const
{
xmlChar *key;
key = xmlGetProp (cur, (const xmlChar *)token);
bool success = read((const char*)key,value);
xmlFree(key);
return success;
}
bool ReaderWriterSS3D::getProperty(xmlNodePtr cur, const char* token, osg::Vec3& value) const
{
xmlChar *key;
key = xmlGetProp (cur, (const xmlChar *)token);
bool success = read((const char*)key,value);
xmlFree(key);
return success;
}
bool ReaderWriterSS3D::getProperty(xmlNodePtr cur, const char* token, osg::Vec4& value) const
{
xmlChar *key;
key = xmlGetProp (cur, (const xmlChar *)token);
bool success = read((const char*)key,value);
xmlFree(key);
return success;
}
bool ReaderWriterSS3D::getProperty(xmlNodePtr cur, const char* token, std::string& value) const
{
bool success = false;
xmlChar *key;
key = xmlGetProp (cur, (const xmlChar *)token);
if (key)
{
success = true;
value = (const char*)key;
}
xmlFree(key);
return success;
}
void ReaderWriterSS3D::parseModel(SlideShowConstructor& constructor, xmlDocPtr doc, xmlNodePtr cur)
{
std::string filename;
float scale = 1.0f;
float rotation = 0.0f;
float position = 0.5f;
xmlChar *key;
cur = cur->xmlChildrenNode;
while (cur != NULL)
SlideShowConstructor::CoordinateFrame coordinate_frame = SlideShowConstructor::SLIDE;
osg::Vec3 position(0.0f,1.0f,0.0f);
osg::Vec4 rotate(0.0f,0.0f,0.0f,1.0f);
float scale = 1.0f;
osg::Vec4 rotation(0.0f,0.0f,0.0f,1.0f);
std::string animation_path;
std::string camera_path;
// temporary
std::string str;
if (getProperty(cur, "coordinate_frame", str))
{
if ((!xmlStrcmp(cur->name, (const xmlChar *)"filename")))
{
key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
if (key) filename = (const char*)key;
xmlFree(key);
}
else if ((!xmlStrcmp(cur->name, (const xmlChar *)"scale")))
{
key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
if (key) scale = atoi((const char*)key);
xmlFree(key);
}
else if ((!xmlStrcmp(cur->name, (const xmlChar *)"rotation")))
{
key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
if (key) rotation = atoi((const char*)key);
xmlFree(key);
}
else if ((!xmlStrcmp(cur->name, (const xmlChar *)"position")))
{
key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
if (key) position = atoi((const char*)key)/100.0f;
xmlFree(key);
}
cur = cur->next;
if (str=="model") coordinate_frame = SlideShowConstructor::MODEL;
else if (str=="slide") coordinate_frame = SlideShowConstructor::SLIDE;
else std::cout<<"Parser error - coordinate_frame=\""<<str<<"\" unrecongonized value"<<std::endl;
}
if (getProperty(cur, "position", str))
{
bool fail = false;
if (str=="center") position.set(0.0f,1.0f,0.0f);
else if (str=="eye") position.set(0.0f,0.0f,0.0f);
else if (!read(str,position)) fail = true;
if (fail) std::cout<<"Parser error - position=\""<<str<<"\" unrecongonized value"<<std::endl;
else std::cout<<"Read position="<<position<<std::endl;
}
if (!filename.empty()) constructor.addModel(filename,scale,rotation,position);
if (getProperty(cur, "scale", scale))
{
std::cout<<"scale read "<<scale<<std::endl;
}
if (getProperty(cur, "rotate", rotate))
{
std::cout<<"rotate read "<<rotate<<std::endl;
}
if (getProperty(cur, "rotation", rotation))
{
std::cout<<"rotation read "<<rotation<<std::endl;
}
if (getProperty(cur, "path", animation_path))
{
std::cout<<"path read "<<animation_path<<std::endl;
}
if (getProperty(cur, "camera_path", camera_path))
{
std::cout<<"camera path read "<<camera_path<<std::endl;
}
xmlChar *key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
if (key) filename = (const char*)key;
xmlFree(key);
if (!filename.empty())
{
if (!camera_path.empty())
{
constructor.addModelWithCameraPath(filename,coordinate_frame,position,scale,rotate,camera_path);
}
else if (!animation_path.empty())
{
constructor.addModelWithPath(filename,coordinate_frame,position,scale,rotate,animation_path);
}
else
{
constructor.addModel(filename,coordinate_frame,position,scale,rotate,rotation);
}
}
}
void ReaderWriterSS3D::parseStereoPair(SlideShowConstructor& constructor, xmlDocPtr doc, xmlNodePtr cur)
@@ -115,7 +293,7 @@ void ReaderWriterSS3D::parseStereoPair(SlideShowConstructor& constructor, xmlDoc
float height = 1.0f;
xmlChar *key;
key = xmlGetProp (cur, (const xmlChar *)"height");
if (key) height = atoi((const char*)key);
if (key) height = atof((const char*)key);
xmlFree(key);
cur = cur->xmlChildrenNode;

View File

@@ -1,6 +1,9 @@
#include "SlideEventHandler.h"
#include "SlideShowConstructor.h"
#include <osg/AnimationPath>
#include <osgUtil/TransformCallback>
class FindNamedSwitchVisitor : public osg::NodeVisitor
{
public:
@@ -109,7 +112,7 @@ bool SlideEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIAction
{
case(osgGA::GUIEventAdapter::FRAME):
{
if (_autoSteppingActive)
if (_autoSteppingActive && !_pause)
{
double time = ea.time();
@@ -183,12 +186,17 @@ bool SlideEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIAction
previousSlide();
return true;
}
else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Pause)
else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Pause ||
ea.getKey()=='p')
{
_pause = !_pause;
if (_pause) std::cout<<"Pause"<<std::endl;
else std::cout<<"End Pause"<<std::endl;
resetUpdateCallbackActivity();
}
else if (ea.getKey()=='r')
{
resetUpdateCallbacks();
}
return false;
@@ -297,3 +305,71 @@ bool SlideEventHandler::previousLayer()
if (_activeLayer>0) return selectLayer(_activeLayer-1);
else return false;
}
class ResetUpdateCallbacksVisitor : public osg::NodeVisitor
{
public:
ResetUpdateCallbacksVisitor(bool pause):
// osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
_pause(pause) {}
void apply(osg::Node& node)
{
osg::AnimationPathCallback* apc = dynamic_cast<osg::AnimationPathCallback*>(node.getUpdateCallback());
osgUtil::TransformCallback* tc = dynamic_cast<osgUtil::TransformCallback*>(node.getUpdateCallback());
if (apc)
{
apc->reset();
apc->update(node);
}
if (tc)
{
//tc->reset();
}
traverse(node);
}
bool _pause;
};
void SlideEventHandler::resetUpdateCallbacks()
{
ResetUpdateCallbacksVisitor rucv(_pause);
_presentationSwitch->accept(rucv);
}
class ActivityUpdateCallbacksVisitor : public osg::NodeVisitor
{
public:
ActivityUpdateCallbacksVisitor(bool pause):
// osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
_pause(pause) {}
void apply(osg::Node& node)
{
osg::AnimationPathCallback* apc = dynamic_cast<osg::AnimationPathCallback*>(node.getUpdateCallback());
osgUtil::TransformCallback* tc = dynamic_cast<osgUtil::TransformCallback*>(node.getUpdateCallback());
if (apc)
{
apc->setPause(_pause);
}
if (tc)
{
tc->setPause(_pause);
}
traverse(node);
}
bool _pause;
};
void SlideEventHandler::resetUpdateCallbackActivity()
{
ActivityUpdateCallbacksVisitor aucv(_pause);
_presentationSwitch->accept(aucv);
}

View File

@@ -77,6 +77,9 @@ protected:
bool _autoSteppingActive;
bool _loopPresentation;
bool _pause;
void resetUpdateCallbacks();
void resetUpdateCallbackActivity();
};

View File

@@ -6,19 +6,23 @@
#include <osg/Texture2D>
#include <osg/MatrixTransform>
#include <osgUtil/TransformCallback>
#include <osgDB/ReadFile>
#include <osgDB/FileUtils>
#include <osgText/Text>
SlideShowConstructor::SlideShowConstructor()
{
_slideOrigin.set(0.0f,0.0f,0.0f);
_slideDistance = osg::DisplaySettings::instance()->getScreenDistance();
_slideHeight = osg::DisplaySettings::instance()->getScreenHeight();
_slideWidth = _slideHeight*1280.0f/1024.f;
_slideOrigin.set(-_slideWidth*0.5f,_slideDistance,-_slideHeight*0.5f);
_backgroundColor.set(0.0f,0.0f,0.0f,1.0f);
_textColor.set(1.0f,1.0f,1.0f,1.0f);
_textFont = "fonts/arial.ttf";
@@ -77,11 +81,9 @@ void SlideShowConstructor::createPresentation()
_root->addChild(_presentationSwitch.get());
osg::Vec3 slideCenter = _slideOrigin + osg::Vec3(_slideWidth*0.5f,0.0f,_slideHeight*0.5f);
float distanceToHeightRatio = osg::DisplaySettings::instance()->getScreenDistance()/osg::DisplaySettings::instance()->getScreenHeight();
HomePosition* hp = new HomePosition;
hp->eye = slideCenter+osg::Vec3(0.0f,-distanceToHeightRatio*_slideHeight,0.0f);
hp->eye.set(0.0f,0.0f,0.0f);
hp->center = slideCenter;
hp->up.set(0.0f,0.0f,1.0f);
@@ -374,7 +376,7 @@ void SlideShowConstructor::addStereoImagePair(const std::string& filenameLeft,co
_currentLayer->addChild(stereopair);
}
void SlideShowConstructor::addModel(const std::string& filename,float scale,float rotation,float position)
void SlideShowConstructor::addModel(const std::string& filename, CoordinateFrame coordinate_frame, const osg::Vec3& position, float scale, const osg::Vec4& rotate, const osg::Vec4& rotation)
{
if (!_currentLayer) addLayer();
@@ -382,24 +384,232 @@ void SlideShowConstructor::addModel(const std::string& filename,float scale,floa
if (!model) return;
osg::Vec3 pos = _modelLeft*(1.0f-position) + _modelRight*position;
float radius = scale*_slideHeight*0.7f;
osg::Quat quat;
quat.makeRotate(osg::DegreesToRadians(rotation),0.0f,0.0f,1.0f);
if (coordinate_frame==SLIDE)
{
osg::Vec3 pos(_slideWidth*position.x(),
_slideDistance*position.y(),
_slideHeight*position.z());
const osg::BoundingSphere& bs = model->getBound();
float model_scale = scale*_slideHeight*0.7f/bs.radius();
osg::MatrixTransform* transform = new osg::MatrixTransform;
const osg::BoundingSphere& bs = model->getBound();
transform->setDataVariance(osg::Object::STATIC);
transform->setMatrix(osg::Matrix::translate(-bs.center())*
osg::Matrix::scale(radius/bs.radius(),radius/bs.radius(),radius/bs.radius())*
osg::Matrix::rotate(quat)*
osg::Matrix::translate(pos));
transform->addChild(model);
_currentLayer->addChild(transform);
osg::MatrixTransform* transform = new osg::MatrixTransform;
transform->setDataVariance(osg::Object::STATIC);
transform->setMatrix(osg::Matrix::translate(-bs.center())*
osg::Matrix::scale(model_scale,model_scale,model_scale)*
osg::Matrix::rotate(osg::DegreesToRadians(rotate[0]),rotate[1],rotate[2],rotate[3])*
osg::Matrix::translate(pos));
transform->addChild(model);
if (rotation[0]!=0.0)
{
osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
animation_transform->setDataVariance(osg::Object::DYNAMIC);
animation_transform->setUpdateCallback(new osgUtil::TransformCallback(pos,osg::Vec3(rotation[1],rotation[2],rotation[3]),osg::DegreesToRadians(rotation[0])));
animation_transform->addChild(transform);
_currentLayer->addChild(animation_transform);
}
else
{
_currentLayer->addChild(transform);
}
}
else
{
osg::MatrixTransform* transform = new osg::MatrixTransform;
transform->setDataVariance(osg::Object::STATIC);
transform->setMatrix(osg::Matrix::translate(-position)*
osg::Matrix::scale(scale,scale,scale)*
osg::Matrix::rotate(osg::DegreesToRadians(rotate[0]),rotate[1],rotate[2],rotate[3]));
transform->addChild(model);
if (rotation[0]!=0.0)
{
osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
animation_transform->setDataVariance(osg::Object::DYNAMIC);
animation_transform->setUpdateCallback(new osgUtil::TransformCallback(osg::Vec3(0.0f,0.0f,0.0f),osg::Vec3(rotation[1],rotation[2],rotation[3]),osg::DegreesToRadians(rotation[0])));
animation_transform->addChild(transform);
_currentLayer->addChild(animation_transform);
}
else
{
_currentLayer->addChild(transform);
}
}
}
void SlideShowConstructor::addModelWithPath(const std::string& filename, CoordinateFrame coordinate_frame, const osg::Vec3& position, float scale, const osg::Vec4& rotate, const std::string& animation_path)
{
if (!_currentLayer) addLayer();
osg::Node* model = osgDB::readNodeFile(filename);
if (!model) return;
osg::AnimationPath* animation = 0;
if (!animation_path.empty())
{
std::string absolute_animation_file_path = osgDB::findDataFile(animation_path);
if (!absolute_animation_file_path.empty())
{
std::ifstream animation_filestream(absolute_animation_file_path.c_str());
if (!animation_filestream.eof())
{
animation = new osg::AnimationPath;
animation->read(animation_filestream);
}
}
}
if (coordinate_frame==SLIDE)
{
osg::Vec3 pos(_slideWidth*position.x(),
_slideDistance*position.y(),
_slideHeight*position.z());
const osg::BoundingSphere& bs = model->getBound();
float model_scale = scale*_slideHeight*0.7f/bs.radius();
osg::MatrixTransform* transform = new osg::MatrixTransform;
transform->setDataVariance(osg::Object::STATIC);
transform->setMatrix(osg::Matrix::translate(-bs.center())*
osg::Matrix::scale(model_scale,model_scale,model_scale)*
osg::Matrix::rotate(osg::DegreesToRadians(rotate[0]),rotate[1],rotate[2],rotate[3])*
osg::Matrix::translate(pos));
transform->addChild(model);
_currentLayer->addChild(transform);
}
else
{
osg::MatrixTransform* transform = new osg::MatrixTransform;
transform->setDataVariance(osg::Object::STATIC);
transform->setMatrix(osg::Matrix::translate(-position)*
osg::Matrix::scale(scale,scale,scale)*
osg::Matrix::rotate(osg::DegreesToRadians(rotate[0]),rotate[1],rotate[2],rotate[3]));
transform->addChild(model);
if (animation)
{
osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
animation_transform->setDataVariance(osg::Object::DYNAMIC);
osg::AnimationPathCallback* apc = new osg::AnimationPathCallback(animation);
animation_transform->setUpdateCallback(apc);
animation_transform->addChild(transform);
_currentLayer->addChild(animation_transform);
//
// osg::MatrixTransform* orientation_transform = new osg::MatrixTransform;
// orientation_transform->setDataVariance(osg::Object::STATIC);
// orientation_transform->addChild(animation_transform);
//
// //orientation_transform->setMatrix(osg::Matrix::rotate(osg::DegreesToRadians(-00.0f),0.0f,1.0f,0.0f));
// //orientation_transform->setMatrix(osg::Matrix::inverse(osg::Matrix::lookAt(osg::Vec3(0.0,0.0,0.0),osg::Vec3(0.0,1.0,0.0),osg::Vec3(0.0,0.0,1.0))));
//
// _currentLayer->addChild(orientation_transform);
}
else
{
_currentLayer->addChild(transform);
}
}
}
void SlideShowConstructor::addModelWithCameraPath(const std::string& filename, CoordinateFrame coordinate_frame, const osg::Vec3& position, float scale, const osg::Vec4& rotate, const std::string& animation_path)
{
if (!_currentLayer) addLayer();
osg::Node* model = osgDB::readNodeFile(filename);
if (!model) return;
osg::AnimationPath* animation = 0;
if (!animation_path.empty())
{
std::string absolute_animation_file_path = osgDB::findDataFile(animation_path);
if (!absolute_animation_file_path.empty())
{
std::ifstream animation_filestream(absolute_animation_file_path.c_str());
if (!animation_filestream.eof())
{
animation = new osg::AnimationPath;
animation->read(animation_filestream);
}
}
}
if (coordinate_frame==SLIDE)
{
osg::Vec3 pos(_slideWidth*position.x(),
_slideDistance*position.y(),
_slideHeight*position.z());
const osg::BoundingSphere& bs = model->getBound();
float model_scale = scale*_slideHeight*0.7f/bs.radius();
osg::MatrixTransform* transform = new osg::MatrixTransform;
transform->setDataVariance(osg::Object::STATIC);
transform->setMatrix(osg::Matrix::translate(-bs.center())*
osg::Matrix::scale(model_scale,model_scale,model_scale)*
osg::Matrix::rotate(osg::DegreesToRadians(rotate[0]),rotate[1],rotate[2],rotate[3])*
osg::Matrix::translate(pos));
transform->addChild(model);
_currentLayer->addChild(transform);
}
else
{
osg::MatrixTransform* transform = new osg::MatrixTransform;
transform->setDataVariance(osg::Object::STATIC);
transform->setMatrix(osg::Matrix::translate(-position)*
osg::Matrix::scale(scale,scale,scale)*
osg::Matrix::rotate(osg::DegreesToRadians(rotate[0]),rotate[1],rotate[2],rotate[3]));
transform->addChild(model);
if (animation)
{
osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
animation_transform->setDataVariance(osg::Object::DYNAMIC);
osg::AnimationPathCallback* apc = new osg::AnimationPathCallback(animation);
apc->setUseInverseMatrix(true);
animation_transform->setUpdateCallback(apc);
animation_transform->addChild(transform);
osg::MatrixTransform* orientation_transform = new osg::MatrixTransform;
orientation_transform->setDataVariance(osg::Object::STATIC);
orientation_transform->addChild(animation_transform);
//orientation_transform->setMatrix(osg::Matrix::rotate(osg::DegreesToRadians(-00.0f),0.0f,1.0f,0.0f));
orientation_transform->setMatrix(osg::Matrix::inverse(osg::Matrix::lookAt(osg::Vec3(0.0,0.0,0.0),osg::Vec3(0.0,1.0,0.0),osg::Vec3(0.0,0.0,1.0))));
_currentLayer->addChild(orientation_transform);
}
else
{
_currentLayer->addChild(transform);
}
}
}

View File

@@ -71,7 +71,11 @@ public:
void addStereoImagePair(const std::string& filenameLeft,const std::string& filenameRight,float height);
void addModel(const std::string& filename,float scale,float rotation,float position);
enum CoordinateFrame { SLIDE, MODEL };
void addModel(const std::string& filename, CoordinateFrame coordinate_frame, const osg::Vec3& position, float scale, const osg::Vec4& rotate, const osg::Vec4& rotation);
void addModelWithPath(const std::string& filename, CoordinateFrame coordinate_frame, const osg::Vec3& position, float scale, const osg::Vec4& rotate, const std::string& animation_path);
void addModelWithCameraPath(const std::string& filename, CoordinateFrame coordinate_frame, const osg::Vec3& position, float scale, const osg::Vec4& rotate, const std::string& animation_path);
osg::ClearNode* takePresentation() { return _root.release(); }
@@ -88,6 +92,7 @@ protected:
osg::Vec3 _slideOrigin;
float _slideWidth;
float _slideHeight;
float _slideDistance;
osg::Vec4 _backgroundColor;
osg::Vec4 _textColor;