devices/deviceopticalhybrid/ordeviceopticalhybrid_device.cxx

devices/deviceopticalhybrid/ordeviceopticalhybrid_device.cxx
/***************************************************************************************
Autodesk(R) Open Reality(R) Samples
(C) 2009 Autodesk, Inc. and/or its licensors
All rights reserved.
AUTODESK SOFTWARE LICENSE AGREEMENT
Autodesk, Inc. licenses this Software to you only upon the condition that
you accept all of the terms contained in the Software License Agreement ("Agreement")
that is embedded in or that is delivered with this Software. By selecting
the "I ACCEPT" button at the end of the Agreement or by copying, installing,
uploading, accessing or using all or any portion of the Software you agree
to enter into the Agreement. A contract is then formed between Autodesk and
either you personally, if you acquire the Software for yourself, or the company
or other legal entity for which you are acquiring the software.
AUTODESK, INC., MAKES NO WARRANTY, EITHER EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
PURPOSE REGARDING THESE MATERIALS, AND MAKES SUCH MATERIALS AVAILABLE SOLELY ON AN
"AS-IS" BASIS.
IN NO EVENT SHALL AUTODESK, INC., BE LIABLE TO ANYONE FOR SPECIAL, COLLATERAL,
INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF PURCHASE
OR USE OF THESE MATERIALS. THE SOLE AND EXCLUSIVE LIABILITY TO AUTODESK, INC.,
REGARDLESS OF THE FORM OF ACTION, SHALL NOT EXCEED THE PURCHASE PRICE OF THE
MATERIALS DESCRIBED HEREIN.
Autodesk, Inc., reserves the right to revise and improve its products as it sees fit.
Autodesk and Open Reality are registered trademarks or trademarks of Autodesk, Inc.,
in the U.S.A. and/or other countries. All other brand names, product names, or
trademarks belong to their respective holders.
GOVERNMENT USE
Use, duplication, or disclosure by the U.S. Government is subject to restrictions as
set forth in FAR 12.212 (Commercial Computer Software-Restricted Rights) and
DFAR 227.7202 (Rights in Technical Data and Computer Software), as applicable.
Manufacturer is Autodesk, Inc., 10 Duke Street, Montreal, Quebec, Canada, H3C 2L7.
***************************************************************************************/
//--- Class declaration
#include "ordeviceopticalhybrid_device.h"
//--- Registration defines
#define ORDEVICEOPTICALHYBRIDTEMPLATE_CLASS ORDEVICEOPTICALHYBRIDTEMPLATE_CLASSNAME
#define ORDEVICEOPTICALHYBRIDTEMPLATE_NAME ORDEVICEOPTICALHYBRIDTEMPLATE_CLASSSTR
#define ORDEVICEOPTICALHYBRIDTEMPLATE_LABEL "OR - Optical Device Hybrid Template"
#define ORDEVICEOPTICALHYBRIDTEMPLATE_DESC "OR - Optical Device Hybrid Template Description"
#define ORDEVICEOPTICALHYBRIDTEMPLATE_PREFIX "OpticalTemplate"
#define ORDEVICEOPTICALHYBRIDTEMPLATE_ICON "processor_optical.png"
//--- FiLMBOX implementation and registration
FBDeviceImplementation ( ORDEVICEOPTICALHYBRIDTEMPLATE_CLASS );
FBRegisterDevice ( ORDEVICEOPTICALHYBRIDTEMPLATE_NAME,
ORDEVICEOPTICALHYBRIDTEMPLATE_CLASS,
ORDEVICEOPTICALHYBRIDTEMPLATE_LABEL,
ORDEVICEOPTICALHYBRIDTEMPLATE_DESC,
ORDEVICEOPTICALHYBRIDTEMPLATE_ICON ); // Icon filename (default=Open Reality icon)
/************************************************
* FiLMBOX Constructor.
************************************************/
bool ORDeviceOpticalHybrid_Template::FBCreate()
{
// Propagate to parent
FBDeviceOptical::FBCreate();
// Add model templates
mRootTemplate = new FBModelTemplate(ORDEVICEOPTICALHYBRIDTEMPLATE_PREFIX, "Reference", kFBModelTemplateRoot);
ModelTemplate.Children.Add(mRootTemplate);
mHierarchyIsDefined = false;
mHasAnimationToTranspose = false;
mPlotting = false;
// Device sampling information
SamplingMode = kFBHardwareTimestamp;
SamplingPeriod = FBTime(0,0,1)/SIM_FPS;
FBPropertyPublish( this, UseReferenceTransformation, "UseReferenceTransformation", NULL, NULL );
UseReferenceTransformation = true;
// Optical device properties
SupportOcclusion = true;
FBSystem().TheOne().OnUIIdle.Add( this,(FBCallback) &ORDeviceOpticalHybrid_Template::EventUIIdle );
return true;
}
/************************************************
* FiLMBOX Destructor.
************************************************/
void ORDeviceOpticalHybrid_Template::FBDestroy()
{
// Propagate to parent
ParentClass::FBDestroy();
FBSystem().TheOne().OnUIIdle.Remove( this,(FBCallback) &ORDeviceOpticalHybrid_Template::EventUIIdle );
}
/************************************************
* Device operation.
************************************************/
bool ORDeviceOpticalHybrid_Template::DeviceOperation( kDeviceOperations pOperation )
{
// Must return the online/offline status of device.
switch (pOperation)
{
case kOpInit: return Init();
case kOpStart: return Start();
case kOpAutoDetect: break;
case kOpStop: return Stop();
case kOpReset: return Reset();
case kOpDone: return Done();
}
return ParentClass::DeviceOperation(pOperation);
}
/************************************************
* Initialize the device.
************************************************/
bool ORDeviceOpticalHybrid_Template::Init()
{
FBProgress lProgress;
lProgress.Caption = "Device";
lProgress.Text = "Initializing device...";
if(!mHardware.GetSetupInfo())
{
Information = "Could not get channel information from device.";
return false;
}
mHierarchyIsDefined = false;
Bind();
return true;
}
/************************************************
* Removal of the device.
************************************************/
bool ORDeviceOpticalHybrid_Template::Done()
{
FBProgress lProgress;
lProgress.Caption = "Device";
lProgress.Text = "Shutting down device...";
UnBind();
/*
* Add device removal code here.
*/
return true;
}
/************************************************
* Reset of the device.
************************************************/
bool ORDeviceOpticalHybrid_Template::Reset()
{
Stop();
return Start();
}
/************************************************
* Device is started (online).
************************************************/
bool ORDeviceOpticalHybrid_Template::Start()
{
FBProgress Progress;
Progress.Caption = "Setting up device";
// Step 1: Open device
if(! mHardware.Open() )
{
Information = "Could not open device";
return false;
}
// Step 2: Ask hardware to get channel information
Progress.Text = "Device found, scanning for channel information...";
Information = "Retrieving channel information";
if(!mHardware.GetSetupInfo())
{
Information = "Cannot connect to server.";
return false;
}
if(mHardware.GetMarkerCount() <= 0)
{
Information = "No markers found.";
return false;
}
// Create Marker Set
DeviceOpticalBeginSetup();
for(int i=0;i<mHardware.GetMarkerCount();i++)
{
Markers.Add(mHardware.GetMarkerName(i));
}
DeviceOpticalEndSetup();
// Step 3: Start data stream
if(! mHardware.StartDataStream() )
{
Information = "Could not start data stream.";
return false;
}
return true; // if true the device is online
}
/************************************************
* Stop the device.
************************************************/
bool ORDeviceOpticalHybrid_Template::Stop()
{
FBProgress lProgress;
lProgress.Caption = "Shutting down device";
if( ! mHardware.StopDataStream() )
{
Information = "Could not stop data stream.";
return false;
}
// Step 2: Close down device
lProgress.Text = "Closing device communication";
Information = "Closing device communication";
if( ! mHardware.Close() )
{
Information = "Could not close device";
return false;
}
return false;
}
/************************************************
* Define model template hierarchy.
************************************************/
void ORDeviceOpticalHybrid_Template::DefineHierarchy()
{
if( !mHierarchyIsDefined && GetChannelCount() > 0 )
{
int lParent;
for(int i=0; i< GetChannelCount(); i++)
{
lParent = GetChannelParent(i);
if(lParent == -1)
{
mRootTemplate->Children.Add(mChannels[i].mModelTemplate);
}
else
{
mChannels[lParent].mModelTemplate->Children.Add(mChannels[i].mModelTemplate);
}
}
mHierarchyIsDefined = true;
}
}
/************************************************
* Test if characterization process can be start
************************************************/
bool ORDeviceOpticalHybrid_Template::ReadyForCharacterize()
{
return mHierarchyIsDefined && GetChannelCount() > 0;
}
/************************************************
* Process global data on template models to local.
************************************************/
void ORDeviceOpticalHybrid_Template::ProcessGlobalToLocal()
{
SetupLocalGlobal(true);
int i;
FBModelList lModels;
FBModel* lModel;
for(i = 0; i < lModels.GetCount(); i++)
lModels[i]->Selected = false;
lModels.Clear();
for(i = 0; i < GetChannelCount(); i++)
{
if(mChannels[i].mModelTemplate && (lModel = mChannels[i].mModelTemplate->Model) != NULL)
{
lModel->Selected = true;
lModels.Add(lModel);
}
}
mPlotting = true;
mSystem.CurrentTake->PlotTakeOnSelected(SamplingPeriod);
mPlotting = false;
for(i = 0; i < lModels.GetCount(); i++)
lModels[i]->Selected = false;
SetupLocalGlobal(false);
bool ApplyReferenceTransformation = UseReferenceTransformation && mRootTemplate->Model;
// Clear Translation and Rotation
if(ApplyReferenceTransformation)
{
mRootTemplate->Model->Translation.SetData(&x);
mRootTemplate->Model->Rotation.SetData(&x);
}
}
void ORDeviceOpticalHybrid_Template::SetupLocalGlobal(bool pGlobal)
{
for( int i = 0; i < GetChannelCount(); i++ )
{
if( mChannels[i].mTAnimNode )
{
mChannels[i].mTAnimNode->SetBufferType(pGlobal);
}
if( mChannels[i].mRAnimNode )
{
mChannels[i].mRAnimNode->SetBufferType(pGlobal);
}
}
}
/************************************************
* Model Template unbinding notification callback
************************************************/
bool ORDeviceOpticalHybrid_Template::ModelTemplateUnBindNotify( int pIndex, FBModelTemplate* pModelTemplate)
{
// Reset skeleton by reevaluating a candidate because of Local/Global animation conversion
bool ObjectInProcess = GetObjectStatus(kFBStatusCreating) || GetObjectStatus(kFBStatusDestroying) || GetObjectStatus(kFBStatusMerging);
if(pModelTemplate->Model && pModelTemplate->Model == mRootTemplate->Model && !ObjectInProcess)
{
FBPlayerControl().TheOne().EvaluationPause();
for( int i = 0; i < GetChannelCount(); i++ )
{
// Create new translation and rotation animation nodes if necessary
if(mChannels[i].mTAnimNode)
{
mChannels[i].mModelTemplate->Model->Translation.SetAnimated(true);
FBAnimationNode* lNode = mChannels[i].mModelTemplate->Model->Translation.GetAnimationNode();
FBVector3d lVector(mChannels[i].mModelTemplate->Model->Translation);
lNode->SetCandidate(lVector.mValue);
}
if(mChannels[i].mRAnimNode)
{
mChannels[i].mModelTemplate->Model->Rotation.SetAnimated(true);
FBAnimationNode* lNode = mChannels[i].mModelTemplate->Model->Rotation.GetAnimationNode();
FBVector3d lVector(mChannels[i].mModelTemplate->Model->Rotation);
lNode->SetCandidate(lVector.mValue);
}
}
FBPlayerControl().TheOne().EvaluationResume();
}
return true;
}
/************************************************
* End the channel set definition.
************************************************/
void ORDeviceOpticalHybrid_Template::Bind()
{
int i;
// Exit edit mode:
// All used channels: if already defined, don't touch, if new: create animation node and model template
// All unused channels: delete animation nodes and associated model template
for( i = 0; i < GetChannelCount(); i++ )
{
// Create new translation and rotation animation nodes if necessary
if( !mChannels[i].mTAnimNode )
{
// We must use a unique name for our connector.
FBString lName( GetChannelName(i), " T" );
mChannels[i].mTAnimNode = AnimationNodeOutCreate( 10000+i, lName, ANIMATIONNODE_TYPE_LOCAL_TRANSLATION );
}
if( !mChannels[i].mRAnimNode )
{
// We must use a unique name for our connector.
FBString lName( GetChannelName(i), " R" );
mChannels[i].mRAnimNode = AnimationNodeOutCreate( 10000+i, lName, ANIMATIONNODE_TYPE_LOCAL_ROTATION );
}
// Create new model templates
if(!mChannels[i].mModelTemplate)
{
mChannels[i].mModelTemplate = new FBModelTemplate(ORDEVICEOPTICALHYBRIDTEMPLATE_PREFIX, GetChannelName(i), kFBModelTemplateSkeleton);
// Bind model template to T and R animation nodes
mChannels[i].mModelTemplate->Bindings.Add(mChannels[i].mTAnimNode);
mChannels[i].mModelTemplate->Bindings.Add(mChannels[i].mRAnimNode);
// Setting global values makes weird value when not live
// mChannels[i].mModelTemplate->DefaultTranslation = mHardware.GetDefaultT(i);
// mChannels[i].mModelTemplate->DefaultRotation = mHardware.GetDefaultR(i);
}
}
//Define hierarchy if needed
DefineHierarchy();
}
void ORDeviceOpticalHybrid_Template::UnBind()
{
int i;
for( i = 0; i < GetChannelCount(); i++ )
{
// Unbind model templates from T and R animation nodes
if( mChannels[i].mTAnimNode )
{
if( mChannels[i].mModelTemplate )
{
mChannels[i].mModelTemplate->Bindings.Remove(mChannels[i].mTAnimNode);
}
}
if( mChannels[i].mRAnimNode )
{
if( mChannels[i].mModelTemplate )
{
mChannels[i].mModelTemplate->Bindings.Remove(mChannels[i].mRAnimNode);
}
}
// Remove as child of root template
if( mRootTemplate->Children.Find(mChannels[i].mModelTemplate) >= 0 )
{
mRootTemplate->Children.Remove(mChannels[i].mModelTemplate);
}
// Destroy unused animation nodes
if( mChannels[i].mTAnimNode )
{
AnimationNodeDestroy(mChannels[i].mTAnimNode);
}
if( mChannels[i].mRAnimNode )
{
AnimationNodeDestroy(mChannels[i].mRAnimNode);
}
mChannels[i].mTAnimNode = NULL;
mChannels[i].mRAnimNode = NULL;
if( mChannels[i].mModelTemplate )
{
mChannels[i].mModelTemplate->Children.RemoveAll();
}
}
for( i = 0; i < GetChannelCount(); i++ )
{
// Delete model template
delete mChannels[i].mModelTemplate;
mChannels[i].mModelTemplate = NULL;
}
}
/************************************************
* Real-time Evaluation Engine.
************************************************/
bool ORDeviceOpticalHybrid_Template::AnimationNodeNotify(FBAnimationNode* pAnimationNode ,FBEvaluateInfo* pEvaluateInfo)
{
kReference lReference = pAnimationNode->Reference;
if (lReference>=10000)
{
FBTVector Pos;
FBRVector Rot;
FBSVector Scal;
FBMatrix GlobalNodeTransformation, GlobalReferenceTransformation;
bool ApplyReferenceTransformation = UseReferenceTransformation && mRootTemplate->Model;
if(ApplyReferenceTransformation)
{
mRootTemplate->Model->GetMatrix(GlobalReferenceTransformation,kModelTransformation,true,pEvaluateInfo);
}
for(int i=0;i<GetChannelCount();i++)
{
if(mChannels[i].mTAnimNode && mChannels[i].mRAnimNode)
{
bool lDontWrite = false;
if ((!pAnimationNode->Live || mPlotting) && mChannels[i].mModelTemplate->Model)
{
mChannels[i].mModelTemplate->Model->Translation.GetAnimationNode()->Evaluate(Pos.mValue,pEvaluateInfo->GetLocalTime(),false);
mChannels[i].mModelTemplate->Model->Rotation.GetAnimationNode()->Evaluate(Rot.mValue,pEvaluateInfo->GetLocalTime(),false);
} else if (pAnimationNode->Live)
{
Pos[0] = mHardware.GetDataTX(i);
Pos[1] = mHardware.GetDataTY(i);
Pos[2] = mHardware.GetDataTZ(i);
Rot[0] = mHardware.GetDataRX(i);
Rot[1] = mHardware.GetDataRY(i);
Rot[2] = mHardware.GetDataRZ(i);
} else
{
lDontWrite = true; // Nothing to do
}
if(ApplyReferenceTransformation)
{
FBTRSToMatrix(GlobalNodeTransformation,Pos,Rot,Scal);
FBGetGlobalMatrix(GlobalNodeTransformation,GlobalReferenceTransformation,GlobalNodeTransformation);
FBMatrixToTranslation(Pos,GlobalNodeTransformation);
FBMatrixToRotation(Rot,GlobalNodeTransformation);
}
if(!lDontWrite)
{
if (!pAnimationNode->Live || mPlotting)
{
mChannels[i].mRAnimNode->WriteData( Rot.mValue, pEvaluateInfo );
mChannels[i].mTAnimNode->WriteData( Pos.mValue, pEvaluateInfo );
} else
{
mChannels[i].mRAnimNode->WriteGlobalData( Rot.mValue, pEvaluateInfo );
mChannels[i].mTAnimNode->WriteGlobalData( Pos.mValue, pEvaluateInfo );
}
}
}
}
}
return FBDeviceOptical::AnimationNodeNotify( pAnimationNode , pEvaluateInfo);
}
/************************************************
* Transport notication.
* Useful to compute time offset between Hardware time and System time
* PreparePlay is called just before play
************************************************/
void ORDeviceOpticalHybrid_Template::DeviceTransportNotify( kTransportMode pMode, FBTime pTime, FBTime pSystem )
{
if(pMode==kPreparePlay)
{
mHardware.ResetPacketTimeOffset(pTime);
}
}
/************************************************
* Real-time Optical Evaluation Engine.
* This is the core of the evaluation for the optical
* device, please read the comment carefully.
************************************************/
void ORDeviceOpticalHybrid_Template::DeviceOpticalEvalAllMarkers(FBDeviceNotifyInfo &pDeviceNotifyInfo)
{
FBTime lEvalTime;
int i;
lEvalTime = pDeviceNotifyInfo.GetLocalTime();
while(mHardware.FetchDataPacket(lEvalTime))
{
for (i=0;i<Markers.GetCount();i ++)
{
Markers[i]->SetData(mHardware.GetDataX(i),
mHardware.GetDataY(i),
mHardware.GetDataZ(i),
mHardware.GetDataO(i));
}
DeviceOpticalRecordFrame(lEvalTime,pDeviceNotifyInfo);
DeviceRecordFrame(lEvalTime,pDeviceNotifyInfo);
}
}
void ORDeviceOpticalHybrid_Template::RecordingDoneAnimation( FBAnimationNode* pAnimationNode )
{
// Parent call
FBDeviceOptical::RecordingDoneAnimation( pAnimationNode );
mHasAnimationToTranspose = true;
}
/************************************************
* Record a frame of the device (recording).
************************************************/
void ORDeviceOpticalHybrid_Template::DeviceRecordFrame(FBTime &pTime,FBDeviceNotifyInfo &pDeviceNotifyInfo)
{
if( mPlayerControl.GetTransportMode() == kFBTransportPlay )
{
int i;
FBAnimationNode* Data;
FBTVector Pos;
FBRVector Rot;
bool ApplyReferenceTransformation = UseReferenceTransformation && mRootTemplate->Model;
FBMatrix GlobalReferenceTransformation;
if(ApplyReferenceTransformation)
mRootTemplate->Model->GetMatrix(GlobalReferenceTransformation,kModelTransformation,true);
for (i=0; i<GetChannelCount(); i++)
{
// Translation information.
if (mChannels[i].mTAnimNode)
{
Data = mChannels[i].mTAnimNode->GetAnimationToRecord();
if (Data)
{
Pos[0] = mHardware.GetDataTX(i);
Pos[1] = mHardware.GetDataTY(i);
Pos[2] = mHardware.GetDataTZ(i);
if(ApplyReferenceTransformation)
FBVectorMatrixMult(Pos,GlobalReferenceTransformation,Pos);
Data->KeyAdd(pTime, Pos);
}
}
// Rotation information.
if (mChannels[i].mRAnimNode)
{
Data = mChannels[i].mRAnimNode->GetAnimationToRecord();
if (Data)
{
Rot[0] = mHardware.GetDataRX(i);
Rot[1] = mHardware.GetDataRY(i);
Rot[2] = mHardware.GetDataRZ(i);
if(ApplyReferenceTransformation)
{
FBMatrix GRM;
FBGetGlobalMatrix(GRM,GlobalReferenceTransformation,GRM);
}
Data->KeyAdd(pTime, Rot);
}
}
}
}
}
/************************************************
* Store data in FBX.
************************************************/
bool ORDeviceOpticalHybrid_Template::FbxStore(FBFbxObject* pFbxObject,kFbxObjectStore pStoreWhat)
{
// Propagate to parent
FBDeviceOptical::FbxStore(pFbxObject, pStoreWhat);
if (pStoreWhat & kAttributes)
{
pFbxObject->FieldWriteC ( "NetworkAddress", mHardware.GetNetworkAddress() );
pFbxObject->FieldWriteI ( "NetworkPort", mHardware.GetNetworkPort() );
}
return true;
}
/************************************************
* Retrieve data from FBX.
************************************************/
bool ORDeviceOpticalHybrid_Template::FbxRetrieve(FBFbxObject* pFbxObject,kFbxObjectStore pStoreWhat)
{
// Propagate to parent
FBDeviceOptical::FbxRetrieve(pFbxObject, pStoreWhat);
if (pStoreWhat & kAttributes)
{
mHardware.SetNetworkAddress ( pFbxObject->FieldReadC( "NetworkAddress") );
mHardware.SetNetworkPort ( pFbxObject->FieldReadI( "NetworkPort") );
}
return true;
}
void ORDeviceOpticalHybrid_Template::EventUIIdle( HISender pSender, HKEvent pEvent )
{
if(mHasAnimationToTranspose)
{
mHasAnimationToTranspose = false;
// Put the animation back on skeleton
ProcessGlobalToLocal();
}
}
/************************************************
* Rigid body setup.
************************************************/
void ORDeviceOpticalHybrid_Template::RigidBodySetup()
{
//---- Steps to create a rigid body
// 1. Establish a snap position
// 2. Create rigid body set with snap positions.
// 3. Add rigid body set to optical model.
double a = 10; // base distance for markers
double lSnapPos[4][3]; // Snap positions (used to calculate relative distances)
int i;
// Set snap positions for markers
lSnapPos[0][0] = 0.0; lSnapPos[0][1] = 0.0; lSnapPos[0][2] = 0.0;
lSnapPos[1][0] = a; lSnapPos[1][1] = 0.0; lSnapPos[1][2] = 0.0;
lSnapPos[2][0] = 0; lSnapPos[2][1] = a; lSnapPos[2][2] = 0.0;
lSnapPos[3][0] = 0; lSnapPos[3][1] = 0.0; lSnapPos[3][2] = a;
// Rigidbody & marker names
FBString lRBName("FBSDK_RigidBody");
FBString lMarkerName;
FBVector3d lPos;
// Get a handle onto the optical model of the device.
FBModelOptical* lModelOptical = (FBModelOptical*) (FBModel*)(this->ModelOptical);
// Affect model optical
if(lModelOptical)
{
FBModelList lList;
FBString lBase(this->Name);
FBString lSep(":");
FBString lModelOpticalName(lModelOptical->Name);
FBString lName;
lBase += lSep;
lBase += lModelOpticalName;
lBase += lSep;
for( i=0;i<mHardware.GetMarkerCount();i++)
{
FBString lMarkerName( mHardware.GetMarkerName(i) );
lName = lBase;
lName += lMarkerName;
FBModel* lModel = FBFindModelByLabelName( lName );
if( lModel )
{
lPos.Set( lSnapPos[i] );
lModel->SetVector( lPos, kModelTranslation, true );
lList.Add( lModel );
}
}
lModelOptical->RigidBodies.Add( lList, lRBName );
lModelOptical->RigidBodies[lModelOptical->RigidBodies.GetCount() - 1].Snap();
}
}