Extended GHOST to support WinTab, in order to better support graphic tablets on Windows

Basic support for normal pressure sensitivity is implemented, adding other features like tilt etc. shouldn't be too difficult, now that basic support is there.
Tested with WACOM Volito on Windows XP using the pressure sensitivity with texture paint to change size of the brush .

Added additional include dir to scons, and MSVC 7 project files - other build systems might have to be updated.
This commit is contained in:
2006-11-05 21:55:28 +00:00
parent 8b77d4241b
commit 6feb2cc4f6
6 changed files with 158 additions and 5 deletions

View File

@@ -27,4 +27,6 @@ else:
Exit()
incs = '. ../string ' + env['BF_OPENGL_INC']
if window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross'):
incs = '../../../../lib/windows/wintab/INCLUDE ' + incs
env.BlenderLib ('bf_ghost', sources, Split(incs), [], libtype=['core','player'], priority = [25,15] )

View File

@@ -627,7 +627,16 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
* a dead key that is pressed while holding down the alt key.
*/
break;
////////////////////////////////////////////////////////////////////////
// Tablet events, processed
////////////////////////////////////////////////////////////////////////
case WT_PACKET:
((GHOST_WindowWin32*)window)->processWin32TabletEvent(wParam, lParam);
break;
case WT_CSRCHANGE:
case WT_PROXIMITY:
((GHOST_WindowWin32*)window)->processWin32TabletInitEvent();
break;
////////////////////////////////////////////////////////////////////////
// Mouse events, processed
////////////////////////////////////////////////////////////////////////

View File

@@ -274,6 +274,7 @@ protected:
bool m_seperateLeftRight;
/** Stores the initialization state of the member m_leftRightDistinguishable. */
bool m_seperateLeftRightInitialized;
};
inline void GHOST_SystemWin32::retrieveModifierKeys(GHOST_ModifierKeys& keys) const

View File

@@ -99,7 +99,11 @@ GHOST_WindowWin32::GHOST_WindowWin32(
m_hGlRc(0),
m_hasMouseCaptured(false),
m_nPressedButtons(0),
m_customCursor(0)
m_customCursor(0),
m_tabletData(NULL),
m_tablet(0),
m_wintab(NULL),
m_maxPressure(0)
{
if (state != GHOST_kWindowStateFullScreen) {
/* Convert client size into window size */
@@ -159,11 +163,67 @@ GHOST_WindowWin32::GHOST_WindowWin32(
// Force an initial paint of the window
::UpdateWindow(m_hWnd);
}
m_wintab = ::LoadLibrary("Wintab32.dll");
if (m_wintab) {
GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" );
GHOST_WIN32_WTOpen fpWTOpen = ( GHOST_WIN32_WTOpen ) ::GetProcAddress( m_wintab, "WTOpenA" );
// let's see if we can initialize tablet here
/* check if WinTab available. */
if (fpWTInfo && fpWTInfo(0, 0, NULL)) {
// Now init the tablet
LOGCONTEXT lc;
AXIS TabletX, TabletY, Pressure; /* The maximum tablet size */
// Open a Wintab context
// Get default context information
fpWTInfo( WTI_DEFCONTEXT, 0, &lc );
// Open the context
lc.lcPktData = PACKETDATA;
lc.lcPktMode = PACKETMODE;
lc.lcOptions |= CXO_MESSAGES | CXO_SYSTEM;
/* Set the entire tablet as active */
fpWTInfo(WTI_DEVICES,DVC_X,&TabletX);
fpWTInfo(WTI_DEVICES,DVC_Y,&TabletY);
BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure);
if (pressureSupport)
m_maxPressure = Pressure.axMax;
else
m_maxPressure = 0;
lc.lcInOrgX = 0;
lc.lcInOrgY = 0;
lc.lcInExtX = TabletX.axMax;
lc.lcInExtY = TabletY.axMax;
if (fpWTOpen) {
m_tablet = fpWTOpen( m_hWnd, &lc, TRUE );
if (m_tablet) {
m_tabletData = new GHOST_TabletData();
m_tabletData->Active = 0;
}
}
}
}
}
GHOST_WindowWin32::~GHOST_WindowWin32()
{
if (m_wintab) {
GHOST_WIN32_WTClose fpWTClose = ( GHOST_WIN32_WTClose ) ::GetProcAddress( m_wintab, "WTClose" );
if (fpWTClose) {
if (m_tablet)
fpWTClose(m_tablet);
if (m_tabletData)
delete m_tabletData;
m_tabletData = NULL;
}
}
if (m_customCursor) {
DestroyCursor(m_customCursor);
m_customCursor = NULL;
@@ -563,6 +623,61 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cur
return GHOST_kSuccess;
}
void GHOST_WindowWin32::processWin32TabletInitEvent()
{
if (m_wintab) {
GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" );
// let's see if we can initialize tablet here
/* check if WinTab available. */
if (fpWTInfo) {
AXIS TabletX, TabletY, Pressure; /* The maximum tablet size */
BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure);
if (pressureSupport)
m_maxPressure = Pressure.axMax;
else
m_maxPressure = 0;
m_tabletData->Active = 0;
}
}
}
void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
{
PACKET pkt;
if (m_wintab) {
GHOST_WIN32_WTPacket fpWTPacket = ( GHOST_WIN32_WTPacket ) ::GetProcAddress( m_wintab, "WTPacket" );
if (fpWTPacket) {
if (fpWTPacket((HCTX)lParam, wParam, &pkt)) {
if (m_tabletData) {
switch (pkt.pkCursor) {
case 0: /* first device */
case 3: /* second device */
m_tabletData->Active = 0; /* puck - not yet supported */
break;
case 1:
case 4:
m_tabletData->Active = 1; /* stylus */
break;
case 2:
case 5:
m_tabletData->Active = 2; /* eraser */
break;
}
if (m_maxPressure > 0) {
m_tabletData->Pressure = (float)pkt.pkNormalPressure / (float)m_maxPressure;
} else {
m_tabletData->Pressure = 1.0f;
}
// tilt data not yet supported
m_tabletData->Xtilt = 0;
m_tabletData->Ytilt = 0;
}
}
}
}
}
/** Reverse the bits in a GHOST_TUns8 */
static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)

View File

@@ -45,6 +45,17 @@
#include <windows.h>
#include <wintab.h>
#define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_CURSOR)
#define PACKETMODE PK_BUTTONS
#include <pktdef.h>
// typedefs for WinTab functions to allow dynamic loading
typedef UINT (API * GHOST_WIN32_WTInfo) ( UINT, UINT, LPVOID );
typedef HCTX (API * GHOST_WIN32_WTOpen) (HWND, LPLOGCONTEXTA, BOOL);
typedef BOOL (API * GHOST_WIN32_WTClose) (HCTX);
typedef BOOL (API * GHOST_WIN32_WTPacket) (HCTX, UINT, LPVOID);
/**
* GHOST window on M$ Windows OSs.
* @author Maarten Gribnau
@@ -217,7 +228,11 @@ public:
void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const;
const GHOST_TabletData* GetTabletData()
{ return NULL; }
{ return m_tabletData; }
void processWin32TabletInitEvent();
void processWin32TabletEvent(WPARAM wParam, LPARAM lParam);
protected:
/**
* Tries to install a rendering context in this window.
@@ -278,6 +293,17 @@ protected:
static LPCSTR s_windowClassName;
static const int s_maxTitleLength;
/** WinTab dll handle */
HMODULE m_wintab;
/** Tablet data for GHOST */
GHOST_TabletData* m_tabletData;
/** Stores the Tablet context if detected Tablet features using WinTab.dll */
HCTX m_tablet;
LONG m_maxPressure;
};
#endif // _GHOST_WINDOW_WIN32_H_

View File

@@ -21,7 +21,7 @@
<Tool
Name="VCCLCompilerTool"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="..\..;..\..\..\..\..\build\msvc_7\intern\string\include"
AdditionalIncludeDirectories="..\..;..\..\..\..\..\build\msvc_7\intern\string\include;..\..\..\..\..\lib\windows\wintab\INCLUDE"
PreprocessorDefinitions="WIN32,NDEBUG,_LIB"
StringPooling="TRUE"
RuntimeLibrary="0"
@@ -78,7 +78,7 @@ ECHO Done
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..;..\..\..\..\..\build\msvc_7\intern\string\include"
AdditionalIncludeDirectories="..\..;..\..\..\..\..\build\msvc_7\intern\string\include;..\..\..\..\..\lib\windows\wintab\INCLUDE"
PreprocessorDefinitions="WIN32,_DEBUG,_LIB"
BasicRuntimeChecks="3"
RuntimeLibrary="1"