summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbustico2011-01-26 16:28:13 +0000
committerbustico2011-01-26 16:28:13 +0000
commit0cabd03d3f5ef640ca49e6555cbcaaf01e7138f0 (patch)
tree3f17e8f051f272c7ac0f1046d0cd9be2e54072a9
parent90a72f5d635f4ad62cdf4a586d26e787f2418c93 (diff)
downloadivy-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.cxx196
-rw-r--r--src/FieldConnector.h70
-rw-r--r--src/InventorUtil.cxx109
-rw-r--r--src/InventorUtil.h64
-rw-r--r--src/IvyEngine.cxx135
-rw-r--r--src/IvyEngine.h83
-rw-r--r--src/IvyExpression.cxx172
-rw-r--r--src/IvyExpression.h71
-rw-r--r--src/IvyField.h45
-rw-r--r--src/IvyMessage.cxx283
-rw-r--r--src/IvyMessage.h75
-rw-r--r--src/Makefile61
-rw-r--r--src/example.iv72
-rw-r--r--src/readme.txt38
-rw-r--r--src/simpleView.cxx53
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;
+}