diff options
author | bustico | 2011-01-26 16:28:13 +0000 |
---|---|---|
committer | bustico | 2011-01-26 16:28:13 +0000 |
commit | 0cabd03d3f5ef640ca49e6555cbcaaf01e7138f0 (patch) | |
tree | 3f17e8f051f272c7ac0f1046d0cd9be2e54072a9 | |
parent | 90a72f5d635f4ad62cdf4a586d26e787f2418c93 (diff) | |
download | ivy-inventor-0cabd03d3f5ef640ca49e6555cbcaaf01e7138f0.zip ivy-inventor-0cabd03d3f5ef640ca49e6555cbcaaf01e7138f0.tar.gz ivy-inventor-0cabd03d3f5ef640ca49e6555cbcaaf01e7138f0.tar.bz2 ivy-inventor-0cabd03d3f5ef640ca49e6555cbcaaf01e7138f0.tar.xz |
initial add of files
-rw-r--r-- | src/FieldConnector.cxx | 196 | ||||
-rw-r--r-- | src/FieldConnector.h | 70 | ||||
-rw-r--r-- | src/InventorUtil.cxx | 109 | ||||
-rw-r--r-- | src/InventorUtil.h | 64 | ||||
-rw-r--r-- | src/IvyEngine.cxx | 135 | ||||
-rw-r--r-- | src/IvyEngine.h | 83 | ||||
-rw-r--r-- | src/IvyExpression.cxx | 172 | ||||
-rw-r--r-- | src/IvyExpression.h | 71 | ||||
-rw-r--r-- | src/IvyField.h | 45 | ||||
-rw-r--r-- | src/IvyMessage.cxx | 283 | ||||
-rw-r--r-- | src/IvyMessage.h | 75 | ||||
-rw-r--r-- | src/Makefile | 61 | ||||
-rw-r--r-- | src/example.iv | 72 | ||||
-rw-r--r-- | src/readme.txt | 38 | ||||
-rw-r--r-- | src/simpleView.cxx | 53 |
15 files changed, 1527 insertions, 0 deletions
diff --git a/src/FieldConnector.cxx b/src/FieldConnector.cxx new file mode 100644 index 0000000..f5b9355 --- /dev/null +++ b/src/FieldConnector.cxx @@ -0,0 +1,196 @@ +/////////////////////////////////////////////////////// +// class FieldConnector +// +// Copyright 1998 Francois-Regis COLIN , CENA/PII +// All rights reserved. + +#ifdef WIN32 +#include <afx.h> + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +#endif +#include <Inventor/engines/SoEngine.h> +#include <Inventor/errors/SoDebugError.h> +#include "FieldConnector.h" + +// +// +// +SO_NODE_SOURCE(FieldConnector); + +// +// Initializes the FieldConnector class. This is a one-time thing that is +// done after database initialization and before any instance of +// this class is constructed. +// + +void +FieldConnector::initClass() +{ + // Initialize type id variables. The arguments to the macro + // are: the name of the node class, the class this is derived + // from, and the name registered with the type of the parent + // class. + SO_NODE_INIT_CLASS(FieldConnector, SoLabel, "Label"); +} + +// +// Constructor +// + +FieldConnector::FieldConnector() +{ + SO_NODE_CONSTRUCTOR(FieldConnector); +} +FieldConnector::~FieldConnector() +{ +} + + + +/* + _ _ _ __ . _ ___ _ _ _ + |_| |_ |_| | | | |\| |_ | |_| |\| | |_ + |\ |_ | | ]_| | | | _| | | | | | |_ |_ +*/ + + +enum FromMode {FROM, TO, UNDEF}; + +SbBool FieldConnector::readInstance (SoInput *in, unsigned short flags) +{ + SbString str, from; + enum FromMode fromMode = UNDEF; + + while ( in->read(str) && !((str == "}")|| !str.getLength())) { + // printf ("DBG> FieldConnector::readInstance str = %s\n", str.getString()); + if (str == "ROUTE") { + fromMode = FROM; + } else if (str == "TO") { + fromMode = TO; + } else { + if (fromMode == UNDEF) { + SoDebugError::post ("FieldConnector::readInstance", + "syntaxe : ROUTE container.field TO container.field") ; + return FALSE; + } + if (fromMode == FROM) { + from = str; + } else { + if (!connectFieldOrEngineOutputToField (from, str)) { + return FALSE; + } + } + } + } + + if ( str.getLength() ) + in->putBack ('}'); + return TRUE; +} + + +bool FieldConnector::connectFieldOrEngineOutputToField (const SbString &from, + const SbString &to) +{ + ConnectionPoint fromCp, toCp ; + + getFromString (from, fromCp); + getFromString (to, toCp); + + + + if ((toCp.type == ERROR) || (fromCp.type == ERROR)) { + return false; + } + + if (toCp.type == ENGINE_OUTPUT) { + SoDebugError::post ("FieldConnector::readInstance", + "impossible d'avoir un engine output %s en champ TO ", + to.getString()) ; + return false; + } + + if (fromCp.type == ENGINE_OUTPUT) { + toCp.value.field->connectFrom (fromCp.value.engineOutput); + } else { + toCp.value.field->connectFrom (fromCp.value.field); + } + + return true; +} + + + +void FieldConnector::getFromString (const SbString &string, + ConnectionPoint &cp) +{ + char buff [256]; + char *nodeOrEngine = buff; + char *fieldOrEngOut; + SoFieldContainer *fieldContainer; + SoField *globalField; + + cp.type = ERROR; + cp.value.field = NULL; + strcpy (buff, string.getString()); + fieldOrEngOut = strchr (buff, '.'); + if (!fieldOrEngOut) { + SoDebugError::post ("FieldConnector::getFromString", + "%s n'est pas un ensemble containerName.fieldName", + buff) ; + return ; + } + *fieldOrEngOut++ = '\000'; + + if (!(fieldContainer = SoNode::getByName (SbName (nodeOrEngine)))) { + fieldContainer = SoEngine::getByName (SbName (nodeOrEngine)); + } + + if (fieldContainer == NULL) { + if (globalField = SoDB::getGlobalField (SbName (nodeOrEngine))) { + cp.type = GLOBAL_FIELD; + cp.value.field = globalField; + return; + } else { + SoDebugError::post ("FieldConnector::getFromString", + "%s n'est pas un nom de node d'engine" + "ou de globalField", nodeOrEngine) ; + return ; + } + } + + if (fieldContainer->isOfType (SoNode::getClassTypeId())) { + if (cp.value.field = fieldContainer->getField (SbName (fieldOrEngOut))) { + cp.type = FIELD; + } else { + SoDebugError::post ("FieldConnector::getFromString", + "%s n'est pas un nom de champ " + "de %s\n", fieldOrEngOut, nodeOrEngine); + cp.type = ERROR; + return; + } + } else { + SoEngine *engine = (SoEngine *) fieldContainer; + if (cp.value.field = engine->getField (SbName (fieldOrEngOut))) { + cp.type = FIELD; + return; + } + if (cp.value.engineOutput = engine->getOutput(SbName (fieldOrEngOut))) { + cp.type = ENGINE_OUTPUT ; + } else { + SoDebugError::post ("FieldConnector::getFromString", + "%s n'est pas un nom de champ ou d'engine output " + "de %s\n", fieldOrEngOut, nodeOrEngine); + cp.type = ERROR; + return; + } + } +} + + diff --git a/src/FieldConnector.h b/src/FieldConnector.h new file mode 100644 index 0000000..47d685e --- /dev/null +++ b/src/FieldConnector.h @@ -0,0 +1,70 @@ +// #pragma once + +#include <Inventor/nodes/SoLabel.h> + + +#ifdef WIN32 +#ifdef FIELDCONNECTOR_EXPORTS +class _declspec(dllexport) FieldConnector; +#else +#pragma comment(lib,"FieldConnector.LIB" ) +#endif +#include <SoWinLeaveScope.h> +#endif +////////////////////////////////////////////////////////////////////////////// +// +// Class: FieldConnector +// +// +////////////////////////////////////////////////////////////////////////////// + +enum ConnectionPointType { + ENGINE_OUTPUT, FIELD, GLOBAL_FIELD, ERROR +}; + +union ConnectionPointValue { + SoField *field; + SoEngineOutput *engineOutput; +}; + +struct ConnectionPoint { + enum ConnectionPointType type; + ConnectionPointValue value; +}; + + +class FieldConnector : public SoLabel { + + SO_NODE_HEADER(FieldConnector); + + public: + // ExposedFields + FieldConnector(); + + // Overrides default method on SoNode + + SoEXTENDER public: + // Implement actions: + + SoINTERNAL public: + static void initClass(); + + protected: + virtual ~FieldConnector(); + + + // reimplementing this methos permits to know when + // parsing of node id done, so after calling + // SoEngine::readInstance we know that the field + // are filled + SbBool readInstance (SoInput *in, unsigned short flags); + bool connectFieldOrEngineOutputToField (const SbString &from, + const SbString &str); + void getFromString (const SbString &from, ConnectionPoint &cp); +}; +#ifdef WIN32 +#include <SoWinEnterScope.h> +#endif + + + diff --git a/src/InventorUtil.cxx b/src/InventorUtil.cxx new file mode 100644 index 0000000..d3711d0 --- /dev/null +++ b/src/InventorUtil.cxx @@ -0,0 +1,109 @@ +//#pragma once +#include "InventorUtil.h" + +#include <Inventor/nodes/SoGroup.h> +#include <Inventor/nodes/SoSwitch.h> +#include <Inventor/actions/SoSearchAction.h> + +#ifndef WIN32 +void UnixTrace( const char *fmt, ... ) +{ + va_list ap; + + va_start( ap, fmt ); + vfprintf( stderr, fmt, ap ); + va_end ( ap ); +} +#endif +//////////////////////////////////////////////////////////////////////////////////////// +// Utility function // +//////////////////////////////////////////////////////////////////////////////////////// + +// +// Remplace toutes les occurences d'un noeud de nom "name" ayant le +// meme type que le nouveau noeud +// +void ReplaceAllNode (SoNode *parent, const char *name, SoNode *newNode) +{ + SoSearchAction find; + find.setType( newNode->getTypeId() ); + find.setInterest( SoSearchAction::ALL ); + find.setSearchingAll( TRUE ); // absolutly all even in SoSwitch + find.setName( name ); + find.setFind( SoSearchAction::TYPE | SoSearchAction::NAME ); + + find.apply( parent ); + SoPathList &pathList = find.getPaths(); + for( int i = 0; i < pathList.getLength(); i++ ) + { + SoNode *kid = pathList[i]->getTail(); + pathList[i]->pop(); + SoGroup *parent = (SoGroup *)pathList[i]->getTail(); + parent->replaceChild(kid,newNode); + } + +} +// +// Met tous les noeud de type SoWitch a SO_SOWITCH_NONE +// +void SwitchOffAllNode (SoNode *parent) +{ + SoSearchAction find; + find.setType( SoSwitch::getClassTypeId() ); + find.setInterest( SoSearchAction::ALL ); + find.setSearchingAll( TRUE ); // absolutly all even in SoSwitch + find.setFind( SoSearchAction::TYPE ); + + find.apply( parent ); + SoPathList &pathList = find.getPaths(); + for( int i = 0; i < pathList.getLength(); i++ ) + { + SoSwitch *sw = (SoSwitch *)pathList[i]->getTail(); + sw->whichChild.setValue( SO_SWITCH_NONE ); + } + +} +// +// trouve le premier noeud de type et de nom donne +// +SoNode *findNodeType (SoNode *node, const char *name, SoType type) +{ + SoSearchAction find; + SoPath *path; + find.setType( type ); + find.setInterest( SoSearchAction::FIRST ); + find.setName( name ); + find.setFind( SoSearchAction::TYPE | SoSearchAction::NAME ); + + find.apply( node ); + path = find.getPath(); + if ( path ) + return path->getTail(); + else return NULL; +} + + + + +SoNode *deepFindNode (SoNode *node, const char *name, + const char *type) +{ + return (findNodeType (node, name, SoType::fromName (SbName (type)))); +} + +SoField *deepFindNodeField (SoNode *node, const char *name, + const char *type, const char *fieldName) +{ + SoNode *foundNode = deepFindNode (node, name, type); + + if (foundNode != (SoNode *) NULL) { + /* + printf ("DBG> %s.%s found &%s = %x\n", node->getName().getString(), name, + fieldName, foundNode->getField (SbName (fieldName))); + */ + return (foundNode->getField (SbName (fieldName))); + } else { + printf ("DBG> %s.%s *NOT* found\n", node->getName().getString(), name); + return ((SoField *) NULL); + } +} diff --git a/src/InventorUtil.h b/src/InventorUtil.h new file mode 100644 index 0000000..96772d5 --- /dev/null +++ b/src/InventorUtil.h @@ -0,0 +1,64 @@ +// // #pragma once + +#include <assert.h> +#define ASSERT assert +#define TRACE UnixTrace +#define UTILEXPORTS /**/ +void UnixTrace( const char *fmt, ... ); + + + +#include <stdarg.h> +#include <Inventor/SoDB.h> + +#define loadANode(node, type, name) \ + name = (type *) node->getByName (# name);\ + if (name == NULL) {\ + TRACE ("erreur de chargement fichier %s : DEF " # name " \ + non trouvee\n", ivFile);\ + exit (-1); \ + } \ +if (!name->isOfType (type::getClassTypeId())) { \ + TRACE ("erreur de chargement fichier %s : DEF " # name " \ + n'est pas du type " # type " voulu\n", ivFile);\ +} + +#define loadAField(type, name) \ + name = (type *) SoDB::getGlobalField(SbName (# name));\ + if (name == NULL) {\ + TRACE ("erreur de chargement fichier %s : globalField " # name " \ + non trouve\n", ivFile);\ + exit (-1); \ + } \ +if (!name->isOfType (type::getClassTypeId())) { \ + TRACE ("erreur de chargement fichier %s : globalField " # name " \ + n'est pas du type " # type " voulu\n", ivFile);\ +} +#define GET_TYPE( node, name, type ) (type*)(findNodeType (node, name, type::getClassTypeId ())) + +#ifndef MIN +#define MIN(v1, v2) ((v1) < (v2)? (v1) : (v2)) +#endif +#ifndef MAX +#define MAX(v1, v2) ((v1) > (v2)? (v1) : (v2)) +#endif +// +// Remplace toutes les occurences d'un noeud de nom "name" ayant le +// meme type que le nouveau noeud +// +UTILEXPORTS void ReplaceAllNode (SoNode *parent, const char *name, SoNode *newNode); +// +// Met tous les noeud de type SoWitch a SO_SOWITCH_NONE +// +UTILEXPORTS void SwitchOffAllNode (SoNode *parent); +// +// trouve le premier noeud de type et de nom donne +// +UTILEXPORTS SoNode *findNodeType (SoNode *node, const char *name, SoType type); + +UTILEXPORTS SoNode *deepFindNode (SoNode *node, const char *name, + const char *type); + +UTILEXPORTS SoField *deepFindNodeField (SoNode *node, const char *name, + const char *type, const char *fieldName); + diff --git a/src/IvyEngine.cxx b/src/IvyEngine.cxx new file mode 100644 index 0000000..1201e0f --- /dev/null +++ b/src/IvyEngine.cxx @@ -0,0 +1,135 @@ +/////////////////////////////////////////////////////// +// class IvyEngine +// +// Copyright 1998 Francois-Regis COLIN , CENA/PII +// All rights reserved. + +#include <iostream> + +#include <Inventor/SoDB.h> +#include <Inventor/engines/SoSubEngine.h> +#include <Inventor/fields/SoSFEnum.h> + +#include "IvyEngine.h" +// my friend classes +#include "IvyExpression.h" +#include "IvyMessage.h" + +#include "InventorUtil.h" +// + +SO_ENGINE_SOURCE(IvyEngine); + + + +void IvyEngine::initClass() +{ + SO_ENGINE_INIT_CLASS(IvyEngine, SoEngine, "Engine"); + //Also Init my friend classes because there is no DLL for those classes + // so there is no automatic call for initClass + IvyExpression::initClass(); + IvyMessage::initClass(); + + // Need to deffer Ivy Init to the first instance creation + // to wait for Params to be read in the Iv file +} +void IvyEngine::IvyInit() +{ + bus = new Ivy( + applicationName.getValue().getString(), + readyMessage.getValue().getString(), + BUS_APPLICATION_CALLBACK( ivyAppConnCb, ivyAppDiscConnCb ),false); + bus->SetFilter( classes_nb, classes_list ); + bus->start(domain.getValue().getString()); + +} +IvyEngine::IvyEngine() +{ + SO_ENGINE_CONSTRUCTOR(IvyEngine); + + SO_ENGINE_ADD_INPUT( applicationName, ("IvyEngineDefaultApplicationName") ); // nom de l'application passe a IvyInit + SO_ENGINE_ADD_INPUT( readyMessage, ("") ); // ready message emis + SO_ENGINE_ADD_INPUT( classes, ("") ); // classes de message emis + SO_ENGINE_ADD_INPUT( domain, ("") ); // numero de bus + + SO_ENGINE_ADD_OUTPUT( Connectedname , SoSFString ); + SO_ENGINE_ADD_OUTPUT( Disconnectedname , SoSFString ); + + bus = NULL; + classes_nb = 0; + classes_list = NULL; +} + + +IvyEngine::~IvyEngine() +{ +#ifdef TRACE_EXPRESSION + TRACE ("Destructeur IvyEngine on object %0x\n", this); +#endif + + if ( classes_list ) delete classes_list; + if ( bus ) + { + bus->stop(); + delete bus; + bus = NULL; + } +} + +void IvyEngine::evaluate() +{ + if ( !bus ) + { + IvyInit(); + } +} + +void IvyEngine::inputChanged( SoField* whichField ) +{ + // skip bus param + if ( ( whichField == & applicationName ) || ( whichField == & readyMessage ) || ( whichField == & domain ) ) + { + return; + } + else if ( whichField == & classes ) + { + classes_nb = classes.getNum(); + if ( classes_list ) delete classes_list; + classes_list = new const char *[classes_nb]; + for ( int i = 0 ; i < classes_nb; i++ ) + { + classes_list[i] = classes[i].getString(); + } + } + else TRACE("Unkonwn IvyEngine Field\n"); +} +void IvyEngine::OnApplicationConnected(IvyApplication *app) +{ + + SO_ENGINE_OUTPUT( Connectedname, SoSFString, setValue( app->GetName()) ); + +} +void IvyEngine::OnApplicationDisconnected(IvyApplication *app) +{ + + SO_ENGINE_OUTPUT( Disconnectedname, SoSFString, setValue( app->GetName()) ); + +} + +void IvyEngine::OnApplicationCongestion(IvyApplication *app) +{ + std::cerr << "Ivy Congestion notififation\n"; +} +void IvyEngine::OnApplicationDecongestion(IvyApplication *app) +{ + std::cerr << "Ivy Decongestion notififation\n"; +} +void IvyEngine::OnApplicationFifoFull(IvyApplication *app) +{ + std::cerr << "Ivy FIFO Full notififation : MESSAGE WILL BE LOST\n"; +} + +void IvyEngine::sendMsg (const char* msg) +{ + if (bus) bus->SendMsg (msg); +} diff --git a/src/IvyEngine.h b/src/IvyEngine.h new file mode 100644 index 0000000..1c039bd --- /dev/null +++ b/src/IvyEngine.h @@ -0,0 +1,83 @@ +/////////////////////////////////////////////////////// +// class IvyEngine +// +// Copyright 1998 Francois-Regis COLIN , CENA/PII +// All rights reserved. + +#ifndef __IVYENGINE_H__ +#define __IVYENGINE_H__ + +#include <Inventor/engines/SoEngine.h> +#include <Inventor/fields/SoSFString.h> +#include <Inventor/fields/SoMFString.h> +#include <Inventor/fields/SoSFInt32.h> + + +#include "IvyApplication.h" +#include "Ivycpp.h" + + +class IvyEngine : public SoEngine, public IvyApplicationCallback +{ + SO_ENGINE_HEADER(IvyEngine); + +// Constructor/destructor +public: + IvyEngine(); + static void initClass(); + virtual ~IvyEngine(); + +// Inputs + SoSFString applicationName; // nom de l'application passe a IvyInit + SoSFString readyMessage; // ready message emis + SoMFString classes; // classes de message a emettre + SoSFString domain; // numero de bus +// Outputs + SoEngineOutput Connectedname; // application name + SoEngineOutput Disconnectedname; // application name + +// Methods +public: + virtual void evaluate(); + virtual void inputChanged( SoField* whichField ); + + enum ApplicationEvent { + CONNECTED, + DISCONNECTED + }; + + + Ivy* getIvy() + { + if ( !bus ) + IvyInit(); + return bus; + }; +protected: +// implementation Methods + void OnApplicationConnected(IvyApplication *app); + void OnApplicationDisconnected(IvyApplication *app); + void OnApplicationCongestion (IvyApplication *app) ; + void OnApplicationDecongestion (IvyApplication *app) ; + void OnApplicationFifoFull (IvyApplication *app) ; + void IvyInit(); + void sendMsg (const char* msg) ; +protected: +// implementation Variables + Ivy *bus; + int classes_nb; + const char **classes_list; + + +private: + static void ivyAppConnCb( IvyApplication *app ) {}; + static void ivyAppDiscConnCb( IvyApplication *app ) {}; + +}; +#ifdef WIN32 +#include <SoWinEnterScope.h> +#endif + +#endif + + diff --git a/src/IvyExpression.cxx b/src/IvyExpression.cxx new file mode 100644 index 0000000..e53e624 --- /dev/null +++ b/src/IvyExpression.cxx @@ -0,0 +1,172 @@ +/////////////////////////////////////////////////////// +// class IvyExpression +// +// Copyright 1998 Francois-Regis COLIN , CENA/PII +// All rights reserved. + +#include <stdio.h> +#include <string.h> + +#include <string> +#include <Inventor/SoDB.h> + +#include <Inventor/engines/SoSubEngine.h> +#include <Inventor/errors/SoDebugError.h> +#include <Inventor/fields/SoSFString.h> +#include <Inventor/fields/SoSFInt32.h> +#include <Inventor/fields/SoMFString.h> +#include <Inventor/fields/SoMFFloat.h> + +#include "InventorUtil.h" + +#include "IvyExpression.h" +#include "IvyEngine.h" + +using namespace std; + +SO_ENGINE_SOURCE(IvyExpression); + + +void IvyExpression::initClass() +{ + SO_ENGINE_INIT_CLASS(IvyExpression, SoEngine, "Engine"); +} + +IvyExpression::IvyExpression() +{ + + SO_ENGINE_CONSTRUCTOR(IvyExpression); + + SO_ENGINE_ADD_INPUT( ivy , (0) ); + SO_ENGINE_ADD_INPUT( params, ("") ); + SO_ENGINE_ADD_INPUT( expression, ("") ); + SO_ENGINE_ADD_INPUT( cumulate, (FALSE) ); + + SO_ENGINE_ADD_OUTPUT(arguments, SoMFString ); + SO_ENGINE_ADD_OUTPUT(argnum, SoMFUInt32 ); + + bind_id = -1; + bus = 0; + current_msg_index = 0; + current_num_index = 0; + cumulate_msg = 0; + inOnMessage = FALSE; +} + + +IvyExpression::~IvyExpression() +{ +#ifdef TRACE_EXPRESSION + TRACE ("Destructeur IvyExpression on object %0x\n", this); +#endif +} + + +void IvyExpression::inputChanged( SoField* whichField ) +{ + if ( (whichField == & expression) || (whichField == & params) ) + { + SbString regexp = "";; + int start = 0; + unsigned int i; + string concatExpr; + for (i=0; i<expression.getNum(); i++) { + concatExpr += expression[i].getString(); + } + + + const char *expr = concatExpr.c_str(); + unsigned int len = strlen(expr); + if ( !len ) return; + if ( !bus ) + { + SoDebugError::post ("IvyExpression::::inputChanged", "ivy field Not Initialised !!!!\n"); + return; + } + // remove old bind if any + if ( bind_id >= 0 ) + bus->UnbindMsg( bind_id ); + // subsitution des $0 $N parametres avec les parametres + for ( i = 0; i < len ; i++ ) + { + // regexp.getString(); + + if ( expr[i] == '$' ) + { + int index = atoi( &expr[i+1]); + regexp += SbString(expr, start, i-1); + regexp += params[ index ]; + start = i+2; /// Attention gros BUG si n > 10 ou blanc etc + } + } + regexp += SbString(expr, start, i-1); + //TRACE( "New Ivy Expression %s\n", regexp.getString() ); + + // Bind to a new bus message + bind_id = bus->BindMsg( regexp.getString(), this ); + } + else if ( whichField == & ivy ) + { + IvyEngine* eng = (IvyEngine*)ivy.getValue(); // check engine type + if ( ! eng->isOfType( IvyEngine::getClassTypeId()) ) + { + SoDebugError::post ("IvyExpression::::inputChanged", "ivy field Not an IvyEngine !!!!\n"); + return; + } + if ( eng ) bus = eng->getIvy(); + } + else if ( whichField == & cumulate ) + { + cumulate_msg = cumulate.getValue(); + } + +} +// Copies an instance that is encountered through a field connection +SoFieldContainer *IvyExpression::copyThroughConnection() const +{ +// return SoEngine::copyThroughConnection(); + return (SoFieldContainer *)this; +} + +void IvyExpression::OnMessage( IvyApplication *app, int argc, const char **argv ) +{ +// CTime t = CTime::GetCurrentTime(); +// CString time = t.Format("%X" ); +// TRACE("*** %s Ivy Message Receive %d args\n",(LPCSTR)time,argc); + + inOnMessage = TRUE; + + + SO_ENGINE_OUTPUT( arguments, SoMFString, setNum( current_msg_index+argc ) ); + SO_ENGINE_OUTPUT( arguments, SoMFString, setValues( current_msg_index, argc, argv ) ); + SO_ENGINE_OUTPUT( argnum, SoMFUInt32, setNum( current_num_index+1 ) ); + SO_ENGINE_OUTPUT( argnum, SoMFUInt32, set1Value( current_num_index, argc ) ); + + if ( cumulate_msg ) + { + current_num_index++; + current_msg_index +=argc; + } + //touch(); + + inOnMessage = FALSE; + + //TRACE("IvyExpression::OnMessage(%lx) argc=%d totalarg=%d nbmsg=%d\n",this,argc, current_msg_index ,current_num_index ); +} + +void IvyExpression::evaluate() +{ +// CTime t = CTime::GetCurrentTime(); +// CString time = t.Format("%X" ); +// TRACE("*** %s Ivy Message Evaluate \n",(LPCSTR)time); + //TRACE("IvyExpression::evaluate(%lx) totalarg=%d nbmsg=%d\n",this,current_msg_index ,current_num_index ); + // on redemarre a zero a la prochaine reception de message + + if ( ! inOnMessage ) + { + //if ( cumulate_msg ) TRACE(" IvyExpression::evaluate current_msg_index = %d current_num_index = %d\n", current_msg_index ,current_num_index ); + current_msg_index = 0; + current_num_index = 0; + } +} + diff --git a/src/IvyExpression.h b/src/IvyExpression.h new file mode 100644 index 0000000..94c8a54 --- /dev/null +++ b/src/IvyExpression.h @@ -0,0 +1,71 @@ +/////////////////////////////////////////////////////// +// class IvyExpression +// +// Copyright 1998 Francois-Regis COLIN , CENA/PII +// All rights reserved. + +#ifndef __IVYEXPRESSION_H__ +#define __IVYEXPRESSION_H__ + + +#include <Inventor/engines/SoEngine.h> +#include <Inventor/fields/SoSFEngine.h> +#include <Inventor/fields/SoSFTrigger.h> +#include <Inventor/fields/SoSFString.h> +#include <Inventor/fields/SoMFString.h> +#include <Inventor/fields/SoMFUInt32.h> +#include <Inventor/fields/SoSFBool.h> + +#include "Ivycpp.h" + +class IvyExpression : public SoEngine, public IvyMessageCallback +{ + SO_ENGINE_HEADER(IvyExpression); + +// Constructor/destructor +public: + IvyExpression(); + static void initClass(); + virtual ~IvyExpression(); + +// Inputs + SoSFEngine ivy; // ivy bus used to send the message + SoMFString params; // parametres dans l'expression reguliere ($0 $n) + SoMFString expression; // expression reguliere passe a Ivy + SoSFBool cumulate; // indicate to cummuled all the message comming between each evaluate + +// Outputs + SoEngineOutput arguments; // arguments des messages recu + SoEngineOutput argnum; // nb d'argument de chaque message + + // other output are generated dynamicly using bindings input + + +// Methods +public: + virtual void evaluate(); + virtual void inputChanged( SoField* whichField ); + // Copies an instance that is encountered through a field connection + virtual SoFieldContainer * copyThroughConnection() const; + +protected: +// implementation Methods + void OnMessage( IvyApplication *app, int argc, const char **argv ); + void IvyInit(); + +protected: +// implementation Variables + Ivy* bus; + int bind_id; + int inOnMessage; + int cumulate_msg; + int current_msg_index; + int current_num_index; +}; +#ifdef WIN32 +#include <SoWinEnterScope.h> +#endif + +#endif + + diff --git a/src/IvyField.h b/src/IvyField.h new file mode 100644 index 0000000..ad7470f --- /dev/null +++ b/src/IvyField.h @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////// +// class IvyField +// +// Copyright 1998 Francois-Regis COLIN , CENA/PII +// All rights reserved. +// ivyField.h: interface for the ivyField class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_IVYFIELD_H__66F74AB2_9021_11D2_8966_00A0245B298A__INCLUDED_) +#define AFX_IVYFIELD_H__66F74AB2_9021_11D2_8966_00A0245B298A__INCLUDED_ + +#if _MSC_VER > 1000 +// #pragma once +#endif // _MSC_VER > 1000 + +#include <Inventor/fields/SoSubField.h> + +#ifdef WIN32 +#ifdef IVYENGINE_EXPORTS +class _declspec(dllexport) IvyField; +#endif +#include <SoWinLeaveScope.h> +#endif + +class Bus; + +class IvyField : public SoSField +{ + SO_SFIELD_HEADER( IvyField, Bus* , Bus* ); +public: +// IvyField(); +// virtual ~IvyField(); + + static void initClass(); + +}; +#ifdef WIN32 +#include <SoWinEnterScope.h> +#endif + +#endif // !defined(AFX_IVYFIELD_H__66F74AB2_9021_11D2_8966_00A0245B298A__INCLUDED_) + + + diff --git a/src/IvyMessage.cxx b/src/IvyMessage.cxx new file mode 100644 index 0000000..c83ab80 --- /dev/null +++ b/src/IvyMessage.cxx @@ -0,0 +1,283 @@ +/////////////////////////////////////////////////////// +// class IvyMessage +// +// Copyright 1998 Francois-Regis COLIN , CENA/PII +// All rights reserved. + + +// Pour avoir des traces remettre define +//#define TRACE_EXPRESSION + +#ifdef WIN32 + +#include "stdafx.h" + +#endif + + +#include <Inventor/SoDB.h> +#include <Inventor/engines/SoSubEngine.h> +#include <Inventor/errors/SoDebugError.h> + +#include <Inventor/fields/SoSFString.h> +#include <Inventor/fields/SoMFString.h> + +#include "IvyEngine.h" +#include "IvyMessage.h" +#include "InventorUtil.h" +#include <stdlib.h> + +// The OneShotSensor is needed the force the call to the evaluate method +// since there is no output. +// we can't call directly from inputChanged because not all +// input can have been set and so we can produce incomplete message + +static void doSendCallback(void *userData, SoSensor *send ) +{ + IvyMessage *msg = (IvyMessage *)userData; + msg->evaluate(); +#ifdef TRACE_EXPRESSION + TRACE("doSendCallback\n"); +#endif +} + +SO_ENGINE_SOURCE(IvyMessage); + +void IvyMessage::initClass() +{ + SO_ENGINE_INIT_CLASS(IvyMessage, SoEngine, "Engine"); +} + +IvyMessage::IvyMessage() +{ + SO_ENGINE_CONSTRUCTOR(IvyMessage); + + SO_ENGINE_ADD_INPUT( ivy , (0) ); + + SO_ENGINE_ADD_INPUT( SendOnParamChange, (TRUE) ); + SO_ENGINE_ADD_INPUT( trigger, () ); + + SO_ENGINE_ADD_INPUT(message, ("") ); + SO_ENGINE_ADD_INPUT(params, ("") ); + + bus = 0; + argc = 0; + argv = NULL; + inputChangedSinceEvaluate=false; + // Init One shotsensor to send message + // this is needed to call the evaluate method since thereis no output + send = new SoOneShotSensor( doSendCallback, this ); +} + + +IvyMessage::~IvyMessage() +{ +#ifdef TRACE_EXPRESSION + TRACE ("Destructeur IvyMessage on object %0x\n", this); +#endif + Empty(); +} +void IvyMessage::Empty() +{ + // Free old segment format + for ( int i = 0 ; i < segment.getLength(); i++ ) + { + SbPList *listSeg = (SbPList *)segment[i]; + for ( int j = 0; j != listSeg->getLength(); j++ ) + { + MsgSegment *seg = (MsgSegment *)(*listSeg)[j]; + delete seg; + } + delete listSeg; + } + segment.truncate( 0 ); +} +void IvyMessage::evaluate() +{ + // Send the message now + if ( !bus ) + { + SoDebugError::post ("IvyExpression::::inputChanged", "ivy field Not Initialised !!!!\n"); + return; + } + + bool allArgsAreNull = true; + for ( int i = 0 ; i < segment.getLength(); i++ ) { + SbPList *listSeg = (SbPList *)segment[i]; + SbString msg; + for ( int j = 0; j != listSeg->getLength(); j++ ) { + MsgSegment *seg = (MsgSegment *)(*listSeg)[j]; + + if ( seg->start < 0 ) { + if (*argv[seg->end]) { + allArgsAreNull=false; + msg += argv[seg->end]; + } + } else { + // AB 13/3/02 ajouté cette ligne sinon ça n'envoie jamais de message + allArgsAreNull=false; + msg += message[i].getSubString( seg->start, seg->end ); + } + } + + if ((allArgsAreNull) || (!inputChangedSinceEvaluate )) { +#ifdef TRACE_EXPRESSION + TRACE("IvyMessage::evaluate *NOT SENT* '%s' allargnul=%d change=%d\n", + msg.getString(), allArgsAreNull, inputChangedSinceEvaluate); +#endif //TRACE_EXPRESSION + return; + } + inputChangedSinceEvaluate = false; +#ifdef TRACE_EXPRESSION + TRACE("IvyMessage::evaluate Send Message '%s'\n", msg.getString()); +#endif //TRACE_EXPRESSION + bus->SendMsg( msg.getString()); + } +} + +void IvyMessage::inputChanged( SoField* whichField ) +{ + SbName fieldName; + + whichField->getContainer()->getFieldName(whichField, fieldName); +#ifdef TRACE_EXPRESSION + TRACE ("IvyMessage::inputChanged on field %s\n", fieldName.getString()); +#endif //TRACE_EXPRESSION + if ( whichField == & ivy ) + { + IvyEngine* eng = (IvyEngine*)ivy.getValue(); // check engine type + if ( ! eng->isOfType( IvyEngine::getClassTypeId()) ) + { + SoDebugError::post ("IvyExpression::::inputChanged", "ivy field Not an IvyEngine !!!!\n"); + return; + } + if ( eng ) bus = eng->getIvy(); + } + else if ( whichField == & message ) + { + // Free old segment format + Empty(); + // Parse new messages formats + for ( int i = 0 ; i < message.getNum(); i++ ) + { + int len = message[i].getLength(); + const char *msg = message[i].getString(); + MsgSegment *seg = NULL; + int last_index = 0; + if ( len ) + { + SbPList *list = new SbPList; + segment.append(list); + // find $ occurence + for ( int j = 0; j < len ; j++ ) + if ( msg[j] == '$' ) + { + // Add beginning segment if one + if ( last_index != j ) + { + seg = new MsgSegment; + seg->start = last_index; + seg->end = j-1; + list->append( seg ); + +#ifdef TRACE_EXPRESSION + TRACE( "Add Segment String start %d end %d\n", + seg->start, seg->end); +#endif //TRACE_EXPRESSION + + } + // Add Argument segment. assume args are $0 form no check ( TODO ) + seg = new MsgSegment; + seg->start = -1; + seg->end = atoi( &msg[j+1] ); + list->append( seg ); + +#ifdef TRACE_EXPRESSION + TRACE( "Add Segment Arg %d \n", seg->end); +#endif //TRACE_EXPRESSION + + last_index = j+2; + //seg->end = -1; + } + // check for last segment + if ( last_index < len ) + { + +#ifdef TRACE_EXPRESSION + if (seg) TRACE( "Add Segment start %d end %d\n", seg->start, seg->end); +#endif //TRACE_EXPRESSION + seg = new MsgSegment; + seg->start = last_index; + seg->end = -1; + list->append( seg ); + } + + } + else { + TRACE("Empty Message ???\n"); + } + } + } + else if ( whichField == & params ) { + inputChangedSinceEvaluate = true; + if ( argv ) delete [] argv; + argc = params.getNum(); + argv = new const char *[argc]; + for ( int i = 0; i < argc ; i++ ) + { + argv[i] = params[i].getString(); + } + if ( SendOnParamChange.getValue() == true ) { + // schedule to the send the new message + // +#ifdef TRACE_EXPRESSION + TRACE("param change : send->schedule ()\n"); +#endif + if (SendWhenParamChange.getValue() == true) { + if (params.getNum() != lastParams.getNum()) { + send->schedule(); + } else { + bool shouldSend = false; + for (int i = 0; i < params.getNum(); i++) { + if (params[i] == lastParams[i]) { + shouldSend = true; + break; + } + } + if (shouldSend) send->schedule(); + } + } else { + send->schedule(); + } + } + } else if ( (whichField == & trigger) ) { + inputChangedSinceEvaluate = true; + trigger.getValue (); + static int i = 0; + + //if (i++ > 12) abort (); + + // schedule to the send the new message + // + if (SendOnParamChange.getValue() == true) { + if (params.getNum() != lastParams.getNum()) { + send->schedule(); + } else { + bool shouldSend = false; + for (int i = 0; i < params.getNum(); i++) { + if (params[i] == lastParams[i]) { + shouldSend = true; + break; + } + } + if (shouldSend) send->schedule(); + } + + } else { + send->schedule(); + } +#ifdef TRACE_EXPRESSION + TRACE("trigger change : send->schedule ()\n"); +#endif + } +} diff --git a/src/IvyMessage.h b/src/IvyMessage.h new file mode 100644 index 0000000..731ed67 --- /dev/null +++ b/src/IvyMessage.h @@ -0,0 +1,75 @@ +/////////////////////////////////////////////////////// +// class IvyMessage +// +// Copyright 1998-2011 Francois-Regis COLIN , CENA/PII +// All rights reserved. + +#ifndef __IVYMESSAGE_H__ +#define __IVYMESSAGE_H__ + + + +#include <Inventor/engines/SoEngine.h> +#include <Inventor/fields/SoSFEngine.h> +#include <Inventor/fields/SoSFString.h> +#include <Inventor/fields/SoSFTrigger.h> +#include <Inventor/fields/SoSFBool.h> +#include <Inventor/sensors/SoOneShotSensor.h> + + +#include "Ivycpp.h" + + + +class IvyMessage : public SoEngine +{ + SO_ENGINE_HEADER(IvyMessage); + +// Constructor/destructor +public: + IvyMessage(); + static void initClass(); + virtual ~IvyMessage(); + +// Inputs + SoSFEngine ivy; // ivy bus used to send the message + // indique si le message doit etre emis suite a un changement de param + SoSFBool SendOnParamChange; + SoSFBool SendWhenParamChange; + SoSFTrigger trigger; // declenche l'emission du message + SoMFString params; // parametres du message + SoMFString message; // format general du message + +// Outputs + // no output +protected: +// implementation Variables + SoMFString lastParams; + Ivy* bus; + int argc; + const char **argv; + bool inputChangedSinceEvaluate; + + typedef struct { + int start; // start of substring in message of -1 if segment is an argument + int end; // end of substring in mesage of arg index if start = -1 + }MsgSegment; + + SbPList segment; + void Empty(); + SoOneShotSensor *send; + +// Methods +public: + virtual void evaluate(); + virtual void inputChanged( SoField* whichField ); + + +}; +#ifdef WIN32 +#include <SoWinEnterScope.h> +#endif + +#endif + + diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..9f233e0 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,61 @@ +DSO= libIvyEngine.so +OBJECTS= IvyEngine.o IvyExpression.o IvyMessage.o InventorUtil.o +C++FILES= IvyEngine.cxx IvyExpression.cxx IvyMessage.cxx InventorUtil.cxx +HFILES= IvyEngine.h IvyExpression.h IvyField.h IvyMessage.h InventorUtil.h + +DSO_FC= libFieldConnector.so +OBJECTS_FC= FieldConnector.o +C++FILES_FC= FieldConnector.cxx +HFILES_FC= FieldConnector.cxx +NODE_LIB:= . +OBJECTS_EXAMPLE= simpleView.o +TARGETS_EXAMPLE= simpleView + + + +LC++INCS= -I/usr/local/include -I/usr/local/include/Ivy \ + -I/usr/local/include -I/usr/local/include/Inventor/annex \ + -I/usr/lib/qt4/include -I/usr/lib/qt4/include/QtCore \ + -I/usr/lib/qt4/include/QtGui -I/usr/lib/qt4/include/QtOpenGL + +QTDEF= -D_REENTRANT -DQT_SHARED + + +LLDLIBS = -L/usr/X11R6/lib \ + -Wl,-rpath,/usr/local/lib -L. -Wl,-rpath,. \ + -L$(NODE_LIB) -Wl,-rpath,$(NODE_LIB) \ + -lSoQt -lXmu -lQtOpenGL -lQtGui -lQtCore \ + -lXi -lCoin -lGL -lXext -lSM -lICE -lX11 -ldl -lpthread + +.SUFFIXES: +.SUFFIXES: .cxx .o + +.cxx.o : + g++ -fPIC $(QTDEF) $(LC++INCS) $(OPTIMIZER) -c $< + + + + +$(TARGETS_EXAMPLE) : $(OBJECTS_EXAMPLE) $(DSO) $(DSO_FC) + g++ -g $(OPTIMIZER) $(QTDEF) -o $(TARGETS_EXAMPLE) $(OBJECTS_EXAMPLE) \ + -L$(NODE_LIB) \ + -Wl,-rpath,$(NODE_LIB) $(LLDLIBS) \ + -lIvyQt -livy + +$(DSO) : $(OBJECTS) + g++ -fPIC $(OPTIMIZER) -shared -o $(DSO) $(OBJECTS) \ + -L$(NODE_LIB) \ + -Wl,-rpath,$(NODE_LIB) $(LLDLIBS) \ + -lIvyQt + +$(DSO_FC) : $(OBJECTS_FC) + g++ -fPIC $(OPTIMIZER) -shared -o $(DSO_FC) $(OBJECTS_FC) \ + -L$(NODE_LIB) \ + -Wl,-rpath,$(NODE_LIB) $(LLDLIBS) \ + -lIvyQt + + +clean: + /bin/rm $(OBJECTS) $(OBJECTS_FC) $(TARGETS) $(OBJECTS_EXAMPLE) $(TARGETS_EXAMPLE) + + diff --git a/src/example.iv b/src/example.iv new file mode 100644 index 0000000..cffd149 --- /dev/null +++ b/src/example.iv @@ -0,0 +1,72 @@ +#Inventor V2.1 ascii + +DEF realTime ElapsedTime { } + + +DEF ivy IvyEngine { + applicationName "COIN_IVY" + readyMessage "COIN_IVY READY" +} + +DEF ivyprobe_ready IvyExpression { + ivy USE ivy + expression "^IVYPROBE Ready" +} + +DEF ivyStart IvyMessage { + ivy USE ivy + trigger = USE ivyprobe_ready.arguments + message "DEBUG Message Ready received from ivyprobe" +} + + +DEF ivyDrag IvyMessage { + ivy USE ivy + SendOnParamChange TRUE + message "DragVal x=$0 y=$1" + params = DEF messageIn Concatenate { + type MFString + input0 "" + input1 "" + }.output +} + +DEF ivyGetServoVal IvyExpression { + ivy USE ivy + expression "^val=(.*)" +} + +DEF decomp DecomposeVec3f { +} + + +Separator { + Transform { + translation 0 0 0 + scaleFactor 0.05 0.05 0.05 + } + Group { + NormalBinding { + value PER_FACE + } + LightModel { + model PHONG + } + Group { + Font { size 1 } + DEF test Text3 { + string "TEst" = USE ivyGetServoVal.arguments + } + } + DEF drag Translate2Dragger { + } + + FieldConnector { + ROUTE drag.translation TO decomp.vector + ROUTE decomp.x TO messageIn.input0 + ROUTE decomp.y TO messageIn.input1 + } + + + } +} diff --git a/src/readme.txt b/src/readme.txt new file mode 100644 index 0000000..01c0b5f --- /dev/null +++ b/src/readme.txt @@ -0,0 +1,38 @@ +this the code to connect coind3d (a gpl sgi open inventor compliant livrary) +http://www.coin3d.org/ + +with ivy (a gpl multiplatform, multilanguage lightweight software bus) +http://www2.tls.cena.fr/products/ivy/ + +the idea is to have a SoEngine node which can receive and emit messages +to enable .iv scene to be easily drivable by externals events. + +° PREREQUISITE + +Of course, since it is an Engine Node, you will need to install Coind3D + +IvyEngine need IVY-c++, which itself is a wrapper over ivy-c + +So you need to get, compile and install ivy-c +mkdir ivy-c ivy-c++ ivyengine ; cd ivy-c +svn co http://svn.tls.cena.fr/svn/ivy/ivy-c/trunk ; +cd /trunk/src +make ; sudo make install + +then Ivy-c++ +cd ../../../ivy-c++ +svn co http://svn.tls.cena.fr/svn/ivy/ivy-c++/trunk/ +cd /trunk/src +make ; sudo make install + + +° INSTALL + +and at last ivyengine +cd ../../../ivy-c++ +svn co http://svn.tls.cena.fr/svn/ivy/ivy-c++/trunk/ +cd /trunk/src +make + + + diff --git a/src/simpleView.cxx b/src/simpleView.cxx new file mode 100644 index 0000000..396eeeb --- /dev/null +++ b/src/simpleView.cxx @@ -0,0 +1,53 @@ +#include <Inventor/Qt/SoQt.h> +#include <Inventor/Qt/viewers/SoQtExaminerViewer.h> + +#include <Inventor/nodes/SoBaseColor.h> +#include <Inventor/nodes/SoCone.h> +#include <Inventor/nodes/SoSeparator.h> + +int +main(int argc, char ** argv) +{ + if (argc < 2) { + (void)fprintf(stderr, "\n\n\tUsage: %s <modelfilename>\n\n", + argc > 0 ? argv[0] : "viewerapp"); + exit(1); + } + + + // Initialize SoQt and Inventor API libraries. This returns a main + // window to use. + QWidget *mainwin = SoQt::init(argc, argv, argv[0]); + + // Open the argument file.. + SoInput in; + SbBool ok = in.openFile(argv[1]); + if (!ok) { exit(1); } + + // ..and import it. + SoSeparator * root = SoDB::readAll(&in); + if (root == NULL) { exit(1); } + root->ref(); + + // Use the ExaminerViewer, for a nice interface for 3D model + // inspection. + SoQtExaminerViewer * viewer = new SoQtExaminerViewer(mainwin); + viewer->setDoubleBuffer(TRUE); + viewer->setAlphaChannel(TRUE); + viewer->setStencilBuffer(TRUE); + + // visual = glXChooseVisual (viewer->getDisplay(), 0, attribList); + viewer->setSceneGraph(root); + viewer->show(); + + // Pop up the main window. + SoQt::show(mainwin); + // Loop until exit. + SoQt::mainLoop(); + + // Clean up resources. + delete viewer; + root->unref(); + + return 0; +} |