You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/3rd/VTK7.1/source/VTK-7.1.1/Rendering/OpenGL/vtkTDxMacDevice.cxx

336 lines
10 KiB
C++

/*=========================================================================
Program: Visualization Toolkit
Module: vtkTDxMacDevice.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkTDxMacDevice.h"
#include <cassert>
#include "vtkTDxMotionEventInfo.h"
#include "vtkCommand.h"
#include "vtkObjectFactory.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkMath.h"
#include <map>
#include <cstring> // for strlen()
vtkStandardNewMacro(vtkTDxMacDevice);
void vtkTDxMacDeviceMessageHandler(io_connect_t connection,
natural_t messageType,
void *messageArgument);
class vtkLessThanClientID
{
public:
bool operator()(const UInt16 &id1, const UInt16 &id2) const
{
return id1<id2;
}
};
// It would be better to have the following variables as member of variable
// but the message handle registration through the 3DConnexion SDK is a piece
// of crap: it only takes a callback pointer but no callback data!
std::map<UInt16,vtkTDxMacDevice *,vtkLessThanClientID> vtkClientIDToDeviceObject;
// ----------------------------------------------------------------------------
// Description:
// Default constructor.
vtkTDxMacDevice::vtkTDxMacDevice()
{
this->ClientApplicationName=0;
this->SetClientApplicationName("3DxClientTest");
this->ClientID=0;
this->LastButtonState=0; // all buttons released.
// this->DebugOn();
}
// ----------------------------------------------------------------------------
// Description:
// Destructor. If the device is not initialized, do nothing. If the device
// is initialized, close the device.
vtkTDxMacDevice::~vtkTDxMacDevice()
{
if(this->Initialized)
{
this->Close();
}
this->SetClientApplicationName(0);
}
// ----------------------------------------------------------------------------
// Description:
// Initialize the device with the current display and window ids.
// It updates the value of GetInitialized().
// Initialization can fail. You must look for the value of
// GetInitialized() before processing further.
// \pre not_yet_initialized: !GetInitialized()
// \pre valid_name: GetClientApplicationName()!=0
void vtkTDxMacDevice::Initialize()
{
assert("pre: not_yet_initialized" && !this->GetInitialized());
assert("pre: valid_name" && this->GetClientApplicationName()!=0);
if(vtkClientIDToDeviceObject.empty())
{
OSErr result=InstallConnexionHandlers(vtkTDxMacDeviceMessageHandler,0L,0L);
this->Initialized=result==noErr; // 0
}
else
{
this->Initialized=true;
}
this->LastButtonState=0; // all buttons released.
unsigned char *pString=
this->CStringToPascalString(this->ClientApplicationName);
// this does not work, we have to use kConnexionClientWildcard and '\0'
// this->ClientID=RegisterConnexionClient('MCTt',pString,kConnexionClientModeTakeOver,kConnexionMaskAll);
this->ClientID=RegisterConnexionClient(kConnexionClientWildcard,'\0',
kConnexionClientModeTakeOver,
kConnexionMaskAll);
vtkDebugMacro(<< "Registered with ClientID=" << this->ClientID);
delete[] pString;
vtkClientIDToDeviceObject.insert(std::pair<const UInt16,vtkTDxMacDevice *>(this->ClientID,this));
}
// ----------------------------------------------------------------------------
// Description:
// Close the device. This is called by the destructor.
// You don't have to close the device explicitly, as the destructor do it
// automatically, but you can.
// \pre initialized: GetInitialized().
// \post restored: !GetInitialized()
void vtkTDxMacDevice::Close()
{
assert("pre: initialized" && this->GetInitialized());
vtkDebugMacro(<< "Close()" );
UnregisterConnexionClient(this->ClientID);
// remove it from map
std::map<UInt16,vtkTDxMacDevice *,vtkLessThanClientID>::iterator it=
vtkClientIDToDeviceObject.find(this->ClientID);
if(it==vtkClientIDToDeviceObject.end())
{
vtkErrorMacro(<< "No matching vtkTDxMacDevice object for clientID=" << this->ClientID);
}
else
{
vtkClientIDToDeviceObject.erase(it);
}
// only if the map is empty.
if(vtkClientIDToDeviceObject.empty())
{
CleanupConnexionHandlers();
}
this->ClientID=0;
this->LastButtonState=0; // all buttons released.
this->Initialized=false;
assert("post: restored" && !this->GetInitialized());
}
// ----------------------------------------------------------------------------
// Description:
// Translate the X11 event by invoking a VTK event, if the event came from
// the device.
// Return true if the event passed in argument was effectively an event from
// the device, return false otherwise.
// \pre initialized: GetInitialized()
// \pre s_exists: s!=0
// \pre client_matches: s->client==this->ClientID
void vtkTDxMacDevice::ProcessEvent(const ConnexionDeviceState *s)
{
assert("pre: initialized" && this->GetInitialized());
assert("pre: s_exists" && s!=0);
assert("pre: client_matches" && s->client==this->ClientID);
vtkTDxMotionEventInfo motionInfo;
int buttonInfo;
double axis[3];
UInt16 mask;
bool pressed;
switch(s->command)
{
case kConnexionCmdHandleAxis:
vtkDebugMacro(<< "it is kConnexionCmdHandleAxis");
motionInfo.X=s->axis[0]; // Tx: SInt16 between -1024 and 1024
// On Mac, the Y and Z axes are reversed (wrong). We want to have a
// right-handed coordinate system, so positive Y has to go from bottom to
// top and positive Z has to come towards us, as on Windows.
motionInfo.Y=-s->axis[1]; // Ty: SInt16 between -1024 and 1024
motionInfo.Z=-s->axis[2]; // Tz: SInt16 between -1024 and 1014
axis[0]=s->axis[3]; // Rx: SInt16 between -1024 and 1024
// On Mac, the Y and Z axes are reversed (wrong).
axis[1]=-s->axis[4]; // Ry: SInt16 between -1024 and 1024
axis[2]=-s->axis[5]; // Rz: SInt16 between -1024 and 1024
motionInfo.Angle=vtkMath::Norm(axis);
if(motionInfo.Angle==0.0)
{
motionInfo.AxisX=0.0;
motionInfo.AxisY=0.0;
motionInfo.AxisZ=1.0;
}
else
{
motionInfo.AxisX=axis[0]/motionInfo.Angle;
motionInfo.AxisY=axis[1]/motionInfo.Angle;
motionInfo.AxisZ=axis[2]/motionInfo.Angle;
}
this->Interactor->InvokeEvent(vtkCommand::TDxMotionEvent,&motionInfo);
break;
case kConnexionCmdHandleButtons:
// find which button changed
// (from release to press or from press to release)
// mask shoud have only one bit at 1, the one of the button that changed.
vtkDebugMacro("lastbuttons=" << hex << this->LastButtonState << dec);
vtkDebugMacro("buttons=" << hex << s->buttons << dec);
mask=s->buttons^this->LastButtonState;
vtkDebugMacro("mask=" << hex << mask << dec);
this->LastButtonState=s->buttons;
pressed=(s->buttons&mask)!=0;
// find the button number (starting at 0).
buttonInfo=0;
mask=mask>>1;
while(mask!=0)
{
mask=mask>>1;
++buttonInfo;
}
if(pressed)
{
vtkDebugMacro(<< "it is kConnexionCmdHandleButtons (press) event");
this->Interactor->InvokeEvent(vtkCommand::TDxButtonPressEvent,
&buttonInfo);
}
else
{
vtkDebugMacro(<< "it is kConnexionCmdHandleButtons (release) event");
this->Interactor->InvokeEvent(vtkCommand::TDxButtonReleaseEvent,
&buttonInfo);
}
break;
default:
// ignore kConnexionCmd(None|HandleRawData|AppSpecific)
break;
}
}
// ----------------------------------------------------------------------------
void vtkTDxMacDevice::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "ClientApplicationName=";
if(this->ClientApplicationName!=0)
{
os << this->ClientApplicationName << endl;
}
else
{
os << "(none)" << endl;
}
}
// ----------------------------------------------------------------------------
// Description:
// Convert a C string to a Pascal String. Allocation happens with new[].
// It is the responsibility of the user to call delete[].
//
// Apple specific. String literal starting with \p are pascal strings: it is
// an unsigned char array starting with the length and terminated by \0. The
// length does not include the length value neither the \0.
// Pascal strings literal are allowed with apple specific gcc option
// -fpascal-strings. Pascal literal are writable is -fwritable-strings is
// set. -Wwrite-strings is a related warning flag.
// \pre s_exists: s!=0
// \pre s_small_enough: strlen(s)<=255
// \post result_exists: result!=0
unsigned char *vtkTDxMacDevice::CStringToPascalString(const char *s)
{
assert("pre: s_exists" && s!=0);
assert("pre: s_small_enough" && strlen(s)<=255);
size_t l=strlen(s);
unsigned char *result=new unsigned char[l+2];
result[0]=static_cast<unsigned char>(l);
result[l+1]=0;
size_t i=0;
while(i<l)
{
result[i+1]=static_cast<unsigned char>(s[i]);
++i;
}
assert("post result_exists" && result!=0);
return result;
}
// ----------------------------------------------------------------------------
// The timer callback is used to poll the 3d input device for change of
// keystates and the cap displacement values.
void vtkTDxMacDeviceMessageHandler(io_connect_t connection,
natural_t messageType,
void *messageArgument)
{
ConnexionDeviceState *s;
std::map<UInt16,vtkTDxMacDevice *,vtkLessThanClientID>::iterator it;
vtkTDxMacDevice *device;
switch(messageType)
{
case kConnexionMsgDeviceState:
s=static_cast<ConnexionDeviceState *>(messageArgument);
it=vtkClientIDToDeviceObject.find(s->client);
if(it==vtkClientIDToDeviceObject.end())
{
// it can happen during initialization phase because of a race condition:
// clientID is registered with the system, events can happen but the
// line that records the clientID is the map is not executed yet.
// No worries.
return;
}
device=(*it).second;
device->ProcessEvent(s);
break;
default:
// other messageTypes can happen and should be ignored.
break;
}
}