Merge branch 'gl' of ../../libBoo

This commit is contained in:
Jack Andersen 2015-08-18 08:02:21 -10:00
commit 3007714b5a
48 changed files with 3772 additions and 119 deletions

85
include/IApplication.hpp Normal file
View File

@ -0,0 +1,85 @@
#ifndef IRUNLOOP_HPP
#define IRUNLOOP_HPP
#include <string>
#include <vector>
#include "windowsys/IWindow.hpp"
#include "inputdev/CDeviceFinder.hpp"
namespace boo
{
class IApplication;
struct IApplicationCallback
{
virtual void appLaunched(IApplication* app) {(void)app;}
virtual void appQuitting(IApplication* app) {(void)app;}
virtual void appFilesOpen(IApplication* app, const std::vector<const std::string>& paths) {(void)app;(void)paths;}
};
class IApplication
{
friend class CWindowCocoa;
friend class CWindowWayland;
friend class CWindowXCB;
friend class CWindowWin32;
virtual void _deletedWindow(IWindow* window)=0;
public:
virtual ~IApplication() {}
enum EPlatformType
{
PLAT_AUTO = 0,
PLAT_WAYLAND = 1,
PLAT_XCB = 2,
PLAT_ANDROID = 3,
PLAT_COCOA = 4,
PLAT_COCOA_TOUCH = 5,
PLAT_WIN32 = 6,
PLAT_WINRT = 7,
PLAT_REVOLUTION = 8,
PLAT_CAFE = 9
};
virtual EPlatformType getPlatformType() const=0;
virtual void run()=0;
virtual void quit()=0;
virtual const std::string& getUniqueName() const=0;
virtual const std::string& getFriendlyName() const=0;
virtual const std::string& getProcessName() const=0;
virtual const std::vector<std::string>& getArgs() const=0;
/* Constructors/initializers for sub-objects */
virtual IWindow* newWindow(const std::string& title)=0;
};
IApplication* IApplicationBootstrap(IApplication::EPlatformType platform,
IApplicationCallback& cb,
const std::string& uniqueName,
const std::string& friendlyName,
const std::string& pname,
const std::vector<std::string>& args,
bool singleInstance=true);
extern IApplication* APP;
#define IApplicationInstance() APP
static inline IApplication* IApplicationBootstrap(IApplication::EPlatformType platform,
IApplicationCallback& cb,
const std::string& uniqueName,
const std::string& friendlyName,
int argc, char** argv,
bool singleInstance=true)
{
if (APP)
return APP;
std::vector<std::string> args;
for (int i=1 ; i<argc ; ++i)
args.push_back(argv[i]);
return IApplicationBootstrap(platform, cb, uniqueName, friendlyName, argv[0], args, singleInstance);
}
}
#endif // IRUNLOOP_HPP

View File

@ -1,27 +0,0 @@
#ifndef IGRAPHICSCONTEXT_HPP
#define IGRAPHICSCONTEXT_HPP
#include <string>
namespace boo
{
class IGraphicsContext
{
public:
virtual ~IGraphicsContext() {}
virtual void setMinVersion (const int& min)=0;
virtual void setMajorVersion(const int& maj)=0;
virtual bool create()=0;
virtual const std::string version() const=0;
virtual const std::string name() const=0;
virtual int depthSize() const=0;
virtual int redDepth() const=0;
virtual int greenDepth() const=0;
virtual int blueDepth() const=0;
};
}
#endif // IGRAPHICSCONTEXT_HPP

View File

@ -1,14 +0,0 @@
#ifndef IINPUTWAITER_HPP
#define IINPUTWAITER_HPP
namespace boo
{
class IInputWaiter
{
};
}
#endif // IINPUTWAITER_HPP

View File

@ -1,14 +0,0 @@
#ifndef IRETRACEWAITER_HPP
#define IRETRACEWAITER_HPP
namespace boo
{
class IRetraceWaiter
{
};
}
#endif // IRETRACEWAITER_HPP

View File

@ -1,15 +0,0 @@
#ifndef ISURFACE_HPP
#define ISURFACE_HPP
namespace boo
{
class ISurface
{
public:
};
}
#endif // CSURFACE_HPP

View File

@ -1,21 +1,8 @@
#ifndef BOO_HPP #ifndef BOO_HPP
#define BOO_HPP #define BOO_HPP
#if defined(_WIN32) #include "IApplication.hpp"
#include "win/CWGLContext.hpp" #include "windowsys/IWindow.hpp"
namespace boo {typedef CWGLContext CGraphicsContext;}
#elif defined(__APPLE__)
#include "mac/CCGLContext.hpp"
namespace boo {typedef CCGLContext CGraphicsContext;}
#elif defined(__GNUC__) || defined(__clang__)
#include "x11/CGLXContext.hpp"
namespace boo {typedef CGLXContext CGraphicsContext;}
#endif
#include "IGraphicsContext.hpp"
#include "inputdev/CDeviceFinder.hpp" #include "inputdev/CDeviceFinder.hpp"
#include "inputdev/CDolphinSmashAdapter.hpp" #include "inputdev/CDolphinSmashAdapter.hpp"

View File

@ -0,0 +1,20 @@
#ifndef CGFXVERTEXLAYOUTBASE_HPP
#define CGFXVERTEXLAYOUTBASE_HPP
class CGFXVertexLayoutBase
{
unsigned m_uvCount;
unsigned m_weightCount;
public:
CGFXVertexLayoutBase(unsigned uvCount=0, unsigned weightCount=0)
: m_uvCount(uvCount),
m_weightCount(weightCount) {}
virtual ~CGFXVertexLayoutBase() {}
inline unsigned uvCount() {return m_uvCount;}
inline unsigned weightCount() {return m_weightCount;}
inline bool isSkinned() {return m_weightCount > 0;}
};
#endif // CGFXVERTEXLAYOUTBASE_HPP

View File

@ -0,0 +1,5 @@
#ifndef IGFXCOMMANDBUFFER_HPP
#define IGFXCOMMANDBUFFER_HPP
#endif // IGFXCOMMANDBUFFER_HPP

View File

@ -0,0 +1,48 @@
#ifndef IGFXCONTEXT_HPP
#define IGFXCONTEXT_HPP
namespace boo
{
class IGFXContext
{
friend class CWindowCocoa;
friend class CWindowXCB;
virtual void _setCallback(class IWindowCallback* cb) {(void)cb;}
public:
enum EGraphicsAPI
{
API_NONE = 0,
API_OPENGL_3_3 = 1,
API_OPENGL_4_2 = 2,
API_OPENGLES_3 = 3,
API_VULKAN = 4,
API_D3D11 = 5,
API_METAL = 6,
API_GX = 7,
API_GX2 = 8
};
enum EPixelFormat
{
PF_NONE = 0,
PF_RGBA8 = 1, /* Default */
PF_RGBA8_Z24 = 2,
PF_RGBAF32 = 3,
PF_RGBAF32_Z24 = 4
};
virtual ~IGFXContext() {}
virtual EGraphicsAPI getAPI() const=0;
virtual EPixelFormat getPixelFormat() const=0;
virtual void setPixelFormat(EPixelFormat pf)=0;
virtual void initializeContext()=0;
};
}
#endif // IGFXCONTEXT_HPP

View File

@ -0,0 +1,5 @@
#ifndef IGFXPIPELINESTATE_HPP
#define IGFXPIPELINESTATE_HPP
#endif // IGFXPIPELINESTATE_HPP

View File

@ -0,0 +1,5 @@
#ifndef IGFXTRANSFORMSET_HPP
#define IGFXTRANSFORMSET_HPP
#endif // IGFXTRANSFORMSET_HPP

View File

@ -0,0 +1,20 @@
#ifndef CHECLLEXER_HPP
#define CHECLLEXER_HPP
#include <string>
#include "graphicsys/CGFXVertexLayoutBase.hpp"
class CHECLLexer
{
const CGFXVertexLayoutBase& m_vertLayout;
public:
CHECLLexer(const CGFXVertexLayoutBase& vertLayout,
const std::string& colorHECL);
CHECLLexer(const CGFXVertexLayoutBase& vertLayout,
const std::string& colorHECL,
const std::string& alphaHECL);
inline const CGFXVertexLayoutBase& getVertLayout() const {return m_vertLayout;}
};
#endif // CHECLLEXER_HPP

View File

@ -0,0 +1,46 @@
#ifndef HECLEXPRESSIONS_HPP
#define HECLEXPRESSIONS_HPP
#include <string>
#include "IHECLBackend.hpp"
class IHECLExpression
{
/* Traverse expression tree and assemble
* backend-specific stage objects */
virtual IHECLBackendStage* recursiveStages(IHECLBackend& backend) const=0;
};
class CHECLNumberLiteral final : IHECLExpression
{
};
class CHECLVector final : IHECLExpression
{
};
class CHECLTextureSample final : IHECLExpression
{
};
class CHECLTextureGatherSample final : IHECLExpression
{
};
class CHECLMulOperation final : IHECLExpression
{
};
class CHECLAddOperation final : IHECLExpression
{
};
class CHECLSubOperation final : IHECLExpression
{
};
class CHECLRoot final : IHECLExpression
{
};
#endif // HECLEXPRESSIONS_HPP

View File

@ -0,0 +1,76 @@
#ifndef IHECLBACKEND_HPP
#define IHECLBACKEND_HPP
#include <string>
#include "CHECLLexer.hpp"
class IHECLBackend;
IHECLBackend* NewHECLBackendOutline(const CHECLLexer& lexer);
IHECLBackend* NewHECLBackendGLSL(const CHECLLexer& lexer);
IHECLBackend* NewHECLBackendHLSL(const CHECLLexer& lexer);
IHECLBackend* NewHECLBackendMetal(const CHECLLexer& lexer);
IHECLBackend* NewHECLBackendTEV(const CHECLLexer& lexer);
IHECLBackend* NewHECLBackendGLSLCafe(const CHECLLexer& lexer);
class IHECLBackend
{
public:
enum Type
{
AUTO = 0,
OUTLINE = 1,
GLSL = 2,
HLSL = 3,
METAL = 4,
TEV = 5,
GLSL_CAFE = 6
};
virtual Type getType() const=0;
virtual bool hasVertexSourceForm() const {return false;}
virtual bool hasFragmentSourceForm() const {return false;}
virtual bool hasVertexBinaryForm() const {return false;}
virtual bool hasFragmentBinaryForm() const {return false;}
virtual bool hasBinaryForm() const {return false;}
virtual std::string* emitNewVertexSource() {return NULL;}
virtual std::string* emitNewFragmentSource() {return NULL;}
virtual void* emitNewVertexBinary(size_t& szOut) {szOut = 0;return NULL;}
virtual void* emitNewFragmentBinary(size_t& szOut) {szOut = 0;return NULL;}
virtual void* emitNewBinary(size_t& szOut) {szOut = 0;return NULL;}
static inline IHECLBackend* NewHECLBackend(Type backendType, const CHECLLexer& lexer)
{
switch (backendType)
{
case AUTO:
#if HW_RVL
return NewHECLBackendTEV(lexer);
#elif HW_CAFE
return NewHECLBackendGLSLCafe(lexer);
#elif _WIN32
return NewHECLBackendHLSL(lexer);
#else
return NewHECLBackendGLSL(lexer);
#endif
case OUTLINE:
return NewHECLBackendOutline(lexer);
case GLSL:
return NewHECLBackendGLSL(lexer);
case HLSL:
return NewHECLBackendHLSL(lexer);
case METAL:
return NewHECLBackendMetal(lexer);
case TEV:
return NewHECLBackendTEV(lexer);
case GLSL_CAFE:
return NewHECLBackendGLSLCafe(lexer);
}
return NULL;
}
};
#endif // IHECLBACKEND_HPP

View File

@ -27,15 +27,15 @@ public:
virtual void deviceError(const char* error) {fprintf(stderr, "%s\n", error);} virtual void deviceError(const char* error) {fprintf(stderr, "%s\n", error);}
/* Low-Level API */ /* Low-Level API */
bool sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length); bool sendUSBInterruptTransfer(const uint8_t* data, size_t length);
size_t receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length); size_t receiveUSBInterruptTransfer(uint8_t* data, size_t length);
virtual void initialCycle() {} virtual void initialCycle() {}
virtual void transferCycle() {} virtual void transferCycle() {}
virtual void finalCycle() {} virtual void finalCycle() {}
/* High-Level API */ /* High-Level API */
bool sendHIDReport(const uint8_t* data, size_t length); bool sendHIDReport(const uint8_t* data, size_t length);
virtual size_t receiveReport(uint8_t* data, size_t length) {return 0;} virtual size_t receiveReport(uint8_t* data, size_t length) {(void)data;(void)length;return 0;}
}; };

View File

@ -1,7 +1,8 @@
#ifndef CDEVICEFINDER_HPP #ifndef CDEVICEFINDER_HPP
#define CDEVICEFINDER_HPP #define CDEVICEFINDER_HPP
#include <set> #include <unordered_set>
#include <typeindex>
#include <mutex> #include <mutex>
#include "DeviceToken.hpp" #include "DeviceToken.hpp"
#include "IHIDListener.hpp" #include "IHIDListener.hpp"
@ -91,7 +92,7 @@ public:
}; };
/* Application must specify its interested device-types */ /* Application must specify its interested device-types */
CDeviceFinder(std::vector<const char*> types) CDeviceFinder(std::unordered_set<std::type_index> types)
: m_listener(NULL) : m_listener(NULL)
{ {
if (skDevFinder) if (skDevFinder)
@ -100,12 +101,12 @@ public:
abort(); abort();
} }
skDevFinder = this; skDevFinder = this;
for (const char* typeName : types) for (const std::type_index& typeIdx : types)
{ {
const SDeviceSignature* sigIter = BOO_DEVICE_SIGS; const SDeviceSignature* sigIter = BOO_DEVICE_SIGS;
while (sigIter->m_name) while (sigIter->m_name)
{ {
if (!strcmp(sigIter->m_name, typeName)) if (sigIter->m_typeIdx == typeIdx)
m_types.push_back(sigIter); m_types.push_back(sigIter);
++sigIter; ++sigIter;
} }

View File

@ -3,6 +3,7 @@
#include <vector> #include <vector>
#include <functional> #include <functional>
#include <typeindex>
namespace boo namespace boo
{ {
@ -15,17 +16,18 @@ struct SDeviceSignature
typedef std::vector<const SDeviceSignature*> TDeviceSignatureSet; typedef std::vector<const SDeviceSignature*> TDeviceSignatureSet;
typedef std::function<CDeviceBase*(CDeviceToken*)> TFactoryLambda; typedef std::function<CDeviceBase*(CDeviceToken*)> TFactoryLambda;
const char* m_name; const char* m_name;
std::type_index m_typeIdx;
unsigned m_vid, m_pid; unsigned m_vid, m_pid;
TFactoryLambda m_factory; TFactoryLambda m_factory;
SDeviceSignature() : m_name(NULL) {} /* Sentinel constructor */ SDeviceSignature() : m_name(NULL), m_typeIdx(typeid(SDeviceSignature)) {} /* Sentinel constructor */
SDeviceSignature(const char* name, unsigned vid, unsigned pid, TFactoryLambda&& factory) SDeviceSignature(const char* name, std::type_index&& typeIdx, unsigned vid, unsigned pid, TFactoryLambda&& factory)
: m_name(name), m_vid(vid), m_pid(pid), m_factory(factory) {} : m_name(name), m_typeIdx(typeIdx), m_vid(vid), m_pid(pid), m_factory(factory) {}
static bool DeviceMatchToken(const CDeviceToken& token, const TDeviceSignatureSet& sigSet); static bool DeviceMatchToken(const CDeviceToken& token, const TDeviceSignatureSet& sigSet);
static CDeviceBase* DeviceNew(CDeviceToken& token); static CDeviceBase* DeviceNew(CDeviceToken& token);
}; };
#define DEVICE_SIG(name, vid, pid) \ #define DEVICE_SIG(name, vid, pid) \
SDeviceSignature(#name, vid, pid, [](CDeviceToken* tok) -> CDeviceBase* {return new name(tok);}) SDeviceSignature(#name, typeid(name), vid, pid, [](CDeviceToken* tok) -> CDeviceBase* {return new name(tok);})
#define DEVICE_SIG_SENTINEL() SDeviceSignature() #define DEVICE_SIG_SENTINEL() SDeviceSignature()
extern const SDeviceSignature BOO_DEVICE_SIGS[]; extern const SDeviceSignature BOO_DEVICE_SIGS[];

View File

@ -40,10 +40,10 @@ struct SDolphinControllerState
struct IDolphinSmashAdapterCallback struct IDolphinSmashAdapterCallback
{ {
virtual void controllerConnected(unsigned idx, EDolphinControllerType type) {} virtual void controllerConnected(unsigned idx, EDolphinControllerType type) {(void)idx;(void)type;}
virtual void controllerDisconnected(unsigned idx, EDolphinControllerType type) {} virtual void controllerDisconnected(unsigned idx, EDolphinControllerType type) {(void)idx;(void)type;}
virtual void controllerUpdate(unsigned idx, EDolphinControllerType type, virtual void controllerUpdate(unsigned idx, EDolphinControllerType type,
const SDolphinControllerState& state) {} const SDolphinControllerState& state) {(void)idx;(void)type;(void)state;}
}; };
class CDolphinSmashAdapter final : public CDeviceBase class CDolphinSmashAdapter final : public CDeviceBase

View File

@ -0,0 +1,146 @@
#ifndef IWINDOW_HPP
#define IWINDOW_HPP
#include <string>
namespace boo
{
class IWindowCallback
{
public:
enum EMouseButton
{
BUTTON_NONE = 0,
BUTTON_PRIMARY = 1,
BUTTON_SECONDARY = 2,
BUTTON_MIDDLE = 3,
BUTTON_AUX1 = 4,
BUTTON_AUX2 = 5
};
struct SWindowCoord
{
unsigned pixel[2];
unsigned virtualPixel[2];
float norm[2];
};
struct STouchCoord
{
double coord[2];
};
struct SScrollDelta
{
double delta[2];
bool isFine; /* Use system-scale fine-scroll (for scrollable-trackpads) */
};
enum ESpecialKey
{
KEY_NONE = 0,
KEY_F1 = 1,
KEY_F2 = 2,
KEY_F3 = 3,
KEY_F4 = 4,
KEY_F5 = 5,
KEY_F6 = 6,
KEY_F7 = 7,
KEY_F8 = 8,
KEY_F9 = 9,
KEY_F10 = 10,
KEY_F11 = 11,
KEY_F12 = 12,
KEY_ESC = 13,
KEY_ENTER = 14,
KEY_BACKSPACE = 15,
KEY_INSERT = 16,
KEY_DELETE = 17,
KEY_HOME = 18,
KEY_END = 19,
KEY_PGUP = 20,
KEY_PGDOWN = 21,
KEY_LEFT = 22,
KEY_RIGHT = 23,
KEY_UP = 24,
KEY_DOWN = 25
};
enum EModifierKey
{
MKEY_NONE = 0,
MKEY_CTRL = 1<<0,
MKEY_ALT = 1<<2,
MKEY_SHIFT = 1<<3,
MKEY_COMMAND = 1<<4
};
virtual void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods)
{(void)coord;(void)button;(void)mods;}
virtual void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods)
{(void)coord;(void)button;(void)mods;}
virtual void mouseMove(const SWindowCoord& coord)
{(void)coord;}
virtual void scroll(const SWindowCoord& coord, const SScrollDelta& scroll)
{(void)coord;(void)scroll;}
virtual void touchDown(const STouchCoord& coord, uintptr_t tid)
{(void)coord;(void)tid;}
virtual void touchUp(const STouchCoord& coord, uintptr_t tid)
{(void)coord;(void)tid;}
virtual void touchMove(const STouchCoord& coord, uintptr_t tid)
{(void)coord;(void)tid;}
virtual void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat)
{(void)charCode;(void)mods;(void)isRepeat;}
virtual void charKeyUp(unsigned long charCode, EModifierKey mods)
{(void)charCode;(void)mods;}
virtual void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat)
{(void)key;(void)mods;(void)isRepeat;}
virtual void specialKeyUp(ESpecialKey key, EModifierKey mods)
{(void)key;(void)mods;}
virtual void modKeyDown(EModifierKey mod, bool isRepeat)
{(void)mod;(void)isRepeat;}
virtual void modKeyUp(EModifierKey mod) {(void)mod;}
};
class IWindow
{
public:
virtual ~IWindow() {}
virtual void setCallback(IWindowCallback* cb)=0;
virtual void showWindow()=0;
virtual void hideWindow()=0;
virtual std::string getTitle()=0;
virtual void setTitle(const std::string& title)=0;
virtual void setWindowFrameDefault()=0;
virtual void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const=0;
virtual void setWindowFrame(float x, float y, float w, float h)=0;
virtual float getVirtualPixelFactor() const=0;
virtual bool isFullscreen() const=0;
virtual void setFullscreen(bool fs)=0;
virtual uintptr_t getPlatformHandle() const=0;
virtual void _incomingEvent(void* event) {(void)event;}
enum ETouchType
{
TOUCH_NONE = 0,
TOUCH_DISPLAY = 1,
TOUCH_TRACKPAD = 2
};
virtual ETouchType getTouchType() const=0;
};
}
#endif // IWINDOW_HPP

View File

@ -33,17 +33,17 @@ void CDeviceBase::closeDevice()
m_token->_deviceClose(); m_token->_deviceClose();
} }
bool CDeviceBase::sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length) bool CDeviceBase::sendUSBInterruptTransfer(const uint8_t* data, size_t length)
{ {
if (m_hidDev) if (m_hidDev)
return m_hidDev->_sendUSBInterruptTransfer(pipe, data, length); return m_hidDev->_sendUSBInterruptTransfer(data, length);
return false; return false;
} }
size_t CDeviceBase::receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length) size_t CDeviceBase::receiveUSBInterruptTransfer(uint8_t* data, size_t length)
{ {
if (m_hidDev) if (m_hidDev)
return m_hidDev->_receiveUSBInterruptTransfer(pipe, data, length); return m_hidDev->_receiveUSBInterruptTransfer(data, length);
return false; return false;
} }

View File

@ -59,13 +59,13 @@ parseState(SDolphinControllerState* stateOut, uint8_t* payload, bool& rumble)
void CDolphinSmashAdapter::initialCycle() void CDolphinSmashAdapter::initialCycle()
{ {
uint8_t handshakePayload[] = {0x13}; uint8_t handshakePayload[] = {0x13};
sendUSBInterruptTransfer(0, handshakePayload, sizeof(handshakePayload)); sendUSBInterruptTransfer(handshakePayload, sizeof(handshakePayload));
} }
void CDolphinSmashAdapter::transferCycle() void CDolphinSmashAdapter::transferCycle()
{ {
uint8_t payload[37]; uint8_t payload[37];
size_t recvSz = receiveUSBInterruptTransfer(0, payload, sizeof(payload)); size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload));
if (recvSz != 37 || payload[0] != 0x21) if (recvSz != 37 || payload[0] != 0x21)
return; return;
//printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]); //printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]);
@ -108,7 +108,7 @@ void CDolphinSmashAdapter::transferCycle()
else else
rumbleMessage[i+1] = 0; rumbleMessage[i+1] = 0;
} }
sendUSBInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage)); sendUSBInterruptTransfer(rumbleMessage, sizeof(rumbleMessage));
m_rumbleState = rumbleReq; m_rumbleState = rumbleReq;
} }
} }
@ -116,7 +116,7 @@ void CDolphinSmashAdapter::transferCycle()
void CDolphinSmashAdapter::finalCycle() void CDolphinSmashAdapter::finalCycle()
{ {
uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0}; uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0};
sendUSBInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage)); sendUSBInterruptTransfer(rumbleMessage, sizeof(rumbleMessage));
} }
void CDolphinSmashAdapter::deviceDisconnected() void CDolphinSmashAdapter::deviceDisconnected()

View File

@ -24,7 +24,7 @@ class CHIDDeviceIOKit final : public IHIDDevice
std::condition_variable m_initCond; std::condition_variable m_initCond;
std::thread* m_thread; std::thread* m_thread;
bool _sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length) bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length)
{ {
if (m_usbIntf) if (m_usbIntf)
{ {
@ -34,7 +34,7 @@ class CHIDDeviceIOKit final : public IHIDDevice
return false; return false;
} }
size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length) size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length)
{ {
if (m_usbIntf) if (m_usbIntf)
{ {

View File

@ -39,7 +39,7 @@ class CHIDDeviceUdev final : public IHIDDevice
std::condition_variable m_initCond; std::condition_variable m_initCond;
std::thread* m_thread; std::thread* m_thread;
bool _sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length) bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length)
{ {
if (m_devFd) if (m_devFd)
{ {
@ -58,7 +58,7 @@ class CHIDDeviceUdev final : public IHIDDevice
return false; return false;
} }
size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length) size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length)
{ {
if (m_devFd) if (m_devFd)
{ {
@ -94,22 +94,22 @@ class CHIDDeviceUdev final : public IHIDDevice
udev_device_unref(udevDev); udev_device_unref(udevDev);
return; return;
} }
usb_device_descriptor devDesc = {0}; usb_device_descriptor devDesc = {};
read(device->m_devFd, &devDesc, 1); read(device->m_devFd, &devDesc, 1);
read(device->m_devFd, &devDesc.bDescriptorType, devDesc.bLength-1); read(device->m_devFd, &devDesc.bDescriptorType, devDesc.bLength-1);
if (devDesc.bNumConfigurations) if (devDesc.bNumConfigurations)
{ {
usb_config_descriptor confDesc = {0}; usb_config_descriptor confDesc = {};
read(device->m_devFd, &confDesc, 1); read(device->m_devFd, &confDesc, 1);
read(device->m_devFd, &confDesc.bDescriptorType, confDesc.bLength-1); read(device->m_devFd, &confDesc.bDescriptorType, confDesc.bLength-1);
if (confDesc.bNumInterfaces) if (confDesc.bNumInterfaces)
{ {
usb_interface_descriptor intfDesc = {0}; usb_interface_descriptor intfDesc = {};
read(device->m_devFd, &intfDesc, 1); read(device->m_devFd, &intfDesc, 1);
read(device->m_devFd, &intfDesc.bDescriptorType, intfDesc.bLength-1); read(device->m_devFd, &intfDesc.bDescriptorType, intfDesc.bLength-1);
for (i=0 ; i<intfDesc.bNumEndpoints+1 ; ++i) for (i=0 ; i<intfDesc.bNumEndpoints+1 ; ++i)
{ {
usb_endpoint_descriptor endpDesc = {0}; usb_endpoint_descriptor endpDesc = {};
read(device->m_devFd, &endpDesc, 1); read(device->m_devFd, &endpDesc, 1);
read(device->m_devFd, &endpDesc.bDescriptorType, endpDesc.bLength-1); read(device->m_devFd, &endpDesc.bDescriptorType, endpDesc.bLength-1);
if ((endpDesc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) if ((endpDesc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
@ -194,6 +194,8 @@ class CHIDDeviceUdev final : public IHIDDevice
bool _sendHIDReport(const uint8_t* data, size_t length) bool _sendHIDReport(const uint8_t* data, size_t length)
{ {
(void)data;
(void)length;
return false; return false;
} }

View File

@ -33,7 +33,7 @@ class CHIDDeviceWinUSB final : public IHIDDevice
std::condition_variable m_initCond; std::condition_variable m_initCond;
std::thread* m_thread; std::thread* m_thread;
bool _sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length) bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length)
{ {
if (m_usbHandle) if (m_usbHandle)
{ {
@ -47,7 +47,7 @@ class CHIDDeviceWinUSB final : public IHIDDevice
return false; return false;
} }
size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length) size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length)
{ {
if (m_usbHandle) if (m_usbHandle)
{ {

View File

@ -2,7 +2,11 @@
#include "inputdev/DeviceFinder.hpp" #include "inputdev/DeviceFinder.hpp"
#include <libudev.h> #include <libudev.h>
#include <string.h> #include <string.h>
<<<<<<< HEAD:lib/inputdev/HIDListenerUdev.cpp
#include <stdio.h> #include <stdio.h>
=======
#include <signal.h>
>>>>>>> 6ce2472b27211a40e1d78f424f09cf26ba5e3281:src/inputdev/CHIDListenerUdev.cpp
#include <thread> #include <thread>
namespace boo namespace boo
@ -169,6 +173,7 @@ public:
~CHIDListenerUdev() ~CHIDListenerUdev()
{ {
m_udevRunning = false; m_udevRunning = false;
pthread_kill(m_udevThread->native_handle(), SIGINT);
m_udevThread->join(); m_udevThread->join();
delete m_udevThread; delete m_udevThread;
udev_monitor_unref(m_udevMon); udev_monitor_unref(m_udevMon);

View File

@ -10,8 +10,8 @@ class IHIDDevice
{ {
friend class CDeviceBase; friend class CDeviceBase;
virtual void _deviceDisconnected()=0; virtual void _deviceDisconnected()=0;
virtual bool _sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length)=0; virtual bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length)=0;
virtual size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)=0; virtual size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length)=0;
virtual bool _sendHIDReport(const uint8_t* data, size_t length)=0; virtual bool _sendHIDReport(const uint8_t* data, size_t length)=0;
public: public:
inline virtual ~IHIDDevice() {} inline virtual ~IHIDDevice() {}

84
libBoo.pri Normal file
View File

@ -0,0 +1,84 @@
HEADERS += \
$$PWD/include/boo.hpp \
$$PWD/include/IApplication.hpp \
$$PWD/include/windowsys/IWindow.hpp \
$$PWD/include/inputdev/CDolphinSmashAdapter.hpp \
$$PWD/include/inputdev/CRevolutionPad.hpp \
$$PWD/include/inputdev/CCafeProPad.hpp \
$$PWD/include/inputdev/CDualshockPad.hpp \
$$PWD/include/inputdev/CGenericPad.hpp \
$$PWD/include/inputdev/CDeviceFinder.hpp \
$$PWD/include/inputdev/CDeviceToken.hpp \
$$PWD/include/inputdev/CDeviceBase.hpp \
$$PWD/include/inputdev/IHIDListener.hpp \
$$PWD/src/inputdev/IHIDDevice.hpp \
$$PWD/include/inputdev/SDeviceSignature.hpp \
$$PWD/include/windowsys/IGFXCommandBuffer.hpp \
$$PWD/include/graphicsys/IGFXCommandBuffer.hpp \
$$PWD/include/graphicsys/IGFXContext.hpp \
$$PWD/include/graphicsys/IGFXPipelineState.hpp \
$$PWD/include/graphicsys/IGFXTransformSet.hpp \
$$PWD/include/graphicsys/hecl/CHECLLexer.hpp \
$$PWD/src/graphicsys/hecl/IHECLBackend.hpp \
$$PWD/src/graphicsys/hecl/HECLExpressions.hpp \
$$PWD/include/graphicsys/CGFXVertexLayoutBase.hpp \
$$PWD/include/graphicsys/hecl/HECLExpressions.hpp \
$$PWD/include/graphicsys/hecl/IHECLBackend.hpp
SOURCES += \
$$PWD/InputDeviceClasses.cpp \
$$PWD/src/inputdev/CDolphinSmashAdapter.cpp \
$$PWD/src/inputdev/CRevolutionPad.cpp \
$$PWD/src/inputdev/CCafeProPad.cpp \
$$PWD/src/inputdev/CDualshockPad.cpp \
$$PWD/src/inputdev/CGenericPad.cpp \
$$PWD/src/inputdev/CDeviceBase.cpp \
$$PWD/src/inputdev/SDeviceSignature.cpp \
$$PWD/src/graphicsys/hecl/CHECLBackendGLSL.cpp \
$$PWD/src/graphicsys/hecl/CHECLBackendHLSL.cpp \
$$PWD/src/graphicsys/hecl/CHECLBackendMetal.cpp \
$$PWD/src/graphicsys/hecl/CHECLLexer.cpp \
$$PWD/src/graphicsys/hecl/CHECLBackendOutline.cpp \
$$PWD/src/graphicsys/hecl/CHECLBackendTEV.cpp
unix:!macx {
HEADERS += \
$$PWD/src/CApplicationXCB.hpp \
$$PWD/src/CApplicationWayland.hpp
SOURCES += \
$$PWD/src/CApplicationUnix.cpp \
$$PWD/src/windowsys/CWindowXCB.cpp \
$$PWD/src/windowsys/CWindowWayland.cpp \
$$PWD/src/graphicsys/CGraphicsContextXCB.cpp \
$$PWD/src/graphicsys/CGraphicsContextWayland.cpp
}
linux {
SOURCES += \
$$PWD/src/inputdev/CHIDListenerUdev.cpp \
$$PWD/src/inputdev/CHIDDeviceUdev.cpp
LIBS += -ludev
}
macx {
SOURCES += \
$$PWD/src/inputdev/CHIDDeviceIOKit.cpp \
$$PWD/src/inputdev/CHIDListenerIOKit.cpp
OBJECTIVE_SOURCES += \
$$PWD/src/CApplicationCocoa.mm \
$$PWD/src/windowsys/CWindowCocoa.mm \
$$PWD/src/windowsys/CGraphicsContextCocoa.mm
LIBS += -framework AppKit
}
win32 {
SOURCES += \
$$PWD/src/CApplicationWin32.cpp \
$$PWD/src/inputdev/CHIDListenerWinUSB.cpp \
$$PWD/src/inputdev/CHIDDeviceWinUSB.cpp \
$$PWD/src/windowsys/CWindowWin32.cpp \
$$PWD/src/graphicsys/CGraphicsContextWin32.cpp
}
INCLUDEPATH += $$PWD/include

13
libBoo.pro Normal file
View File

@ -0,0 +1,13 @@
CONFIG -= Qt
QT =
LIBS -= -lQtGui -lQtCore
unix:QMAKE_CXXFLAGS += -std=c++11 -stdlib=libc++
unix:!macx:LIBS += -std=c++11 -stdlib=libc++ -lc++abi
unix:!macx:CONFIG += link_pkgconfig
unix:!macx:PKGCONFIG += xcb xcb-glx xcb-xinput xcb-xkb xcb-keysyms xkbcommon xkbcommon-x11 dbus-1
win32:LIBS += Setupapi.lib winusb.lib User32.lib /SUBSYSTEM:Windows
include(libBoo.pri)
include(test/test.pri)

182
src/CApplicationCocoa.mm Normal file
View File

@ -0,0 +1,182 @@
#include <AppKit/AppKit.h>
#include "IApplication.hpp"
@interface AppDelegate : NSObject <NSApplicationDelegate>
{
boo::IApplicationCallback* callback;
@public
NSPanel* aboutPanel;
}
- (id)initWithCallback:(boo::IApplicationCallback*)cb;
@end
@implementation AppDelegate
- (id)initWithCallback:(boo::IApplicationCallback*)cb
{
self = [super init];
callback = cb;
return self;
}
- (void)applicationDidFinishLaunching:(NSNotification*)notification
{
(void)notification;
callback->appLaunched(boo::IApplicationInstance());
}
- (void)applicationWillTerminate:(NSNotification*)notification
{
(void)notification;
callback->appQuitting(boo::IApplicationInstance());
}
- (BOOL)application:(NSApplication*)sender openFile:(NSString*)filename
{
(void)sender;
return callback->appFileOpen(boo::IApplicationInstance(), [filename UTF8String]);
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender {
(void)sender;
return YES;
}
- (IBAction)aboutApp:(id)sender
{
(void)sender;
NSRect screenFrame = [[aboutPanel screen] frame];
CGFloat xPos = NSWidth(screenFrame)/2 - 300/2;
CGFloat yPos = NSHeight(screenFrame)/2 - 220/2;
NSRect aboutCr = NSMakeRect(xPos, yPos, 300, 220);
[aboutPanel setFrame:aboutCr display:NO];
[aboutPanel makeKeyAndOrderFront:self];
}
- (IBAction)toggleFs:(id)sender
{
(void)sender;
[[NSApp keyWindow] toggleFullScreen:nil];
}
- (IBAction)quitApp:(id)sender
{
(void)sender;
[NSApp terminate:nil];
}
@end
namespace boo
{
IWindow* _CWindowCocoaNew(const std::string& title);
class CApplicationCocoa final : public IApplication
{
IApplicationCallback& m_callback;
const std::string m_friendlyName;
const std::string m_pname;
const std::vector<std::string> m_args;
NSPanel* aboutPanel;
void _deletedWindow(IWindow* window)
{
(void)window;
}
public:
CApplicationCocoa(IApplicationCallback& callback,
const std::string& friendlyName,
const std::string& pname,
const std::vector<std::string>& args)
: m_callback(callback),
m_friendlyName(friendlyName),
m_pname(pname),
m_args(args)
{}
EPlatformType getPlatformType() const
{
return PLAT_COCOA;
}
void run()
{
@autoreleasepool
{
NSApplication* app = [NSApplication sharedApplication];
[app setActivationPolicy:NSApplicationActivationPolicyRegular];
/* Delegate (OS X callbacks) */
AppDelegate* appDelegate = [[AppDelegate alloc] initWithCallback:&m_callback];
[app setDelegate:appDelegate];
/* App menu */
NSMenu* appMenu = [[NSMenu alloc] initWithTitle:@"main"];
NSMenu* rwkMenu = [[NSMenu alloc] initWithTitle:[[NSString stringWithUTF8String:m_friendlyName.c_str()] autorelease]];
[rwkMenu addItemWithTitle:[[NSString stringWithFormat:@"About %s", m_friendlyName.c_str()] autorelease]
action:@selector(aboutApp:)
keyEquivalent:@""];
NSMenuItem* fsItem = [rwkMenu addItemWithTitle:@"Toggle Full Screen"
action:@selector(toggleFs:)
keyEquivalent:@"f"];
[fsItem setKeyEquivalentModifierMask:NSCommandKeyMask];
[rwkMenu addItem:[NSMenuItem separatorItem]];
NSMenuItem* quit_item = [rwkMenu addItemWithTitle:[[NSString stringWithFormat:@"Quit %s", m_friendlyName.c_str()] autorelease]
action:@selector(quitApp:)
keyEquivalent:@"q"];
[quit_item setKeyEquivalentModifierMask:NSCommandKeyMask];
[[appMenu addItemWithTitle:[[NSString stringWithUTF8String:m_friendlyName.c_str()] autorelease]
action:nil keyEquivalent:@""] setSubmenu:rwkMenu];
[[NSApplication sharedApplication] setMainMenu:appMenu];
/* About panel */
NSRect aboutCr = NSMakeRect(0, 0, 300, 220);
aboutPanel = [[NSPanel alloc] initWithContentRect:aboutCr
styleMask:NSUtilityWindowMask|NSTitledWindowMask|NSClosableWindowMask
backing:NSBackingStoreBuffered defer:YES];
[aboutPanel setTitle:[[NSString stringWithFormat:@"About %s", m_friendlyName.c_str()] autorelease]];
NSText* aboutText = [[NSText alloc] initWithFrame:aboutCr];
[aboutText setEditable:NO];
[aboutText setAlignment:NSCenterTextAlignment];
[aboutText setString:@"\nRWK Authors\n\nJackoalan\nAntidote\n"];
[aboutPanel setContentView:aboutText];
appDelegate->aboutPanel = aboutPanel;
[app run];
}
}
void quit()
{
[NSApp terminate:nil];
}
const std::string& getProcessName() const
{
return m_pname;
}
const std::vector<std::string>& getArgs() const
{
return m_args;
}
IWindow* newWindow(const std::string& title)
{
return _CWindowCocoaNew(title);
}
};
IApplication* APP = NULL;
IApplication* IApplicationBootstrap(IApplication::EPlatformType platform,
IApplicationCallback& cb,
const std::string& friendlyName,
const std::string& pname,
const std::vector<std::string>& args)
{
if (!APP)
{
if (platform != IApplication::PLAT_COCOA &&
platform != IApplication::PLAT_AUTO)
return NULL;
APP = new CApplicationCocoa(cb, friendlyName, pname, args);
}
return APP;
}
}

71
src/CApplicationUnix.cpp Normal file
View File

@ -0,0 +1,71 @@
/* Meta-implementation for dynamically-constructing user's preferred
* platform interface
*/
#define CAPPLICATION_UNIX_CPP
#include "CApplicationXCB.hpp"
#include "CApplicationWayland.hpp"
#include <dbus/dbus.h>
#include <stdio.h>
DBusConnection* registerDBus(const char* appName, bool& isFirst)
{
isFirst = true;
DBusError err = {};
dbus_error_init(&err);
/* connect to the bus and check for errors */
DBusConnection* conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
if (dbus_error_is_set(&err))
{
fprintf(stderr, "DBus Connection Error (%s)\n", err.message);
dbus_error_free(&err);
}
if (NULL == conn)
return NULL;
/* request our name on the bus and check for errors */
char busName[256];
snprintf(busName, 256, "boo.%s.unique", appName);
int ret = dbus_bus_request_name(conn, busName, DBUS_NAME_FLAG_DO_NOT_QUEUE , &err);
if (dbus_error_is_set(&err))
{
fprintf(stderr, "DBus Name Error (%s)\n", err.message);
dbus_error_free(&err);
dbus_connection_close(conn);
return NULL;
}
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret)
isFirst = false;
return conn;
}
namespace boo
{
IApplication* APP = NULL;
IApplication* IApplicationBootstrap(IApplication::EPlatformType platform,
IApplicationCallback& cb,
const std::string& uniqueName,
const std::string& friendlyName,
const std::string& pname,
const std::vector<std::string>& args,
bool singleInstance)
{
if (!APP)
{
if (platform == IApplication::PLAT_WAYLAND)
APP = new CApplicationWayland(cb, uniqueName, friendlyName, pname, args, singleInstance);
else if (platform == IApplication::PLAT_XCB ||
platform == IApplication::PLAT_AUTO)
APP = new CApplicationXCB(cb, uniqueName, friendlyName, pname, args, singleInstance);
else
return NULL;
}
return APP;
}
}

View File

@ -0,0 +1,85 @@
#ifndef CAPPLICATION_UNIX_CPP
#error This file may only be included from CApplicationUnix.cpp
#endif
#include "IApplication.hpp"
#include <dbus/dbus.h>
DBusConnection* registerDBus(const char* appName, bool& isFirst);
namespace boo
{
IWindow* _CWindowWaylandNew(const std::string& title);
class CApplicationWayland final : public IApplication
{
IApplicationCallback& m_callback;
const std::string m_uniqueName;
const std::string m_friendlyName;
const std::string m_pname;
const std::vector<std::string> m_args;
bool m_singleInstance;
void _deletedWindow(IWindow* window)
{
(void)window;
}
public:
CApplicationWayland(IApplicationCallback& callback,
const std::string& uniqueName,
const std::string& friendlyName,
const std::string& pname,
const std::vector<std::string>& args,
bool singleInstance)
: m_callback(callback),
m_uniqueName(uniqueName),
m_friendlyName(friendlyName),
m_pname(pname),
m_args(args),
m_singleInstance(singleInstance)
{}
EPlatformType getPlatformType() const
{
return PLAT_WAYLAND;
}
void run()
{
}
void quit()
{
}
const std::string& getUniqueName() const
{
return m_uniqueName;
}
const std::string& getFriendlyName() const
{
return m_friendlyName;
}
const std::string& getProcessName() const
{
return m_pname;
}
const std::vector<std::string>& getArgs() const
{
return m_args;
}
IWindow* newWindow(const std::string& title)
{
return _CWindowWaylandNew(title);
}
};
}

166
src/CApplicationWin32.cpp Normal file
View File

@ -0,0 +1,166 @@
#define _CRT_SECURE_NO_WARNINGS 1 /* STFU MSVC */
#define _WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#include <initguid.h>
#include <Usbiodef.h>
#include <unordered_map>
#include "IRunLoop.hpp"
#include "inputdev/CDeviceFinder.hpp"
namespace boo
{
IWindow* _CWindowWin32New(const std::string& title);
class CApplicationWin32 final : public IApplication
{
const IApplicationCallback& m_callback;
const std::string m_friendlyName;
const std::string m_pname;
const std::vector<std::string> m_args;
std::unordered_map<HWND, IWindow*> m_allWindows;
bool m_singleInstance;
void _deletedWindow(IWindow* window)
{
m_allWindows.erase(window);
}
public:
CApplicationWin32(const IApplicationCallback& callback,
const std::string& friendlyName,
const std::string& pname,
const std::vector<std::string>& args,
bool singleInstance)
: m_callback(callback),
m_friendlyName(friendlyName),
m_pname(pname),
m_args(args),
m_singleInstance(singleInstance)
{}
EPlatformType getPlatformType() const
{
return PLAT_WIN32;
}
LRESULT winHwndHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
/* Lookup boo window instance */
IWindow* window = m_allWindows[hwnd];
switch (uMsg)
{
case WM_CREATE:
return 0;
case WM_DEVICECHANGE:
return CDeviceFinder::winDevChangedHandler(wParam, lParam);
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
void run()
{
/* Pump messages */
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
const std::string& getProcessName() const
{
return m_pname;
}
const std::vector<std::string>& getArgs() const
{
return m_args;
}
IWindow* newWindow(const std::string& title)
{
IWindow* window = _CWindowWin32New(title);
HWND hwnd = window->getPlatformHandle();
m_allWindows[hwnd] = window;
}
};
IApplication* APP = NULL;
IApplication* IApplicationBootstrap(IApplication::EPlatformType platform,
IApplicationCallback& cb,
const std::string& friendlyName,
const std::string& pname,
const std::vector<std::string>& args,
bool singleInstance)
{
if (!APP)
{
if (platform != IApplication::PLAT_WIN32 &&
platform != IApplication::PLAT_AUTO)
return NULL;
APP = new CApplicationWin32(cb, friendlyName, pname, args, singleInstance);
}
return APP;
}
}
static const DEV_BROADCAST_DEVICEINTERFACE_A HOTPLUG_CONF =
{
sizeof(DEV_BROADCAST_DEVICEINTERFACE_A),
DBT_DEVTYP_DEVICEINTERFACE,
0,
GUID_DEVINTERFACE_USB_DEVICE
};
static bool HOTPLUG_REGISTERED = false;
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (!HOTPLUG_REGISTERED && hwnd == WM_CREATE)
{
/* Register hotplug notification with windows */
RegisterDeviceNotificationA(hwnd, (LPVOID)&HOTPLUG_CONF, DEVICE_NOTIFY_WINDOW_HANDLE);
HOTPLUG_REGISTERED = true;
}
return IRunLoopInstance()->winHwndHandler(hwnd, uMsg, wParam, lParam);
}
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPCWSTR lpCmdLine, int)
{
#if DEBUG
/* Debug console */
AllocConsole();
freopen("CONOUT$", "w", stdout);
#endif
/* One class for *all* boo windows */
WNDCLASS wndClass =
{
0,
WindowProc,
0,
0,
hInstance,
0,
0,
0,
0,
L"BooWindow"
};
RegisterClassW(&wndClass);
int argc = 0;
LPWSTR* argv = CommandLineToArgvW(lpCmdLine, &argc);
/* Call into the 'proper' entry point */
return main(argc, argv);
}

334
src/CApplicationXCB.hpp Normal file
View File

@ -0,0 +1,334 @@
#ifndef CAPPLICATION_UNIX_CPP
#error This file may only be included from CApplicationUnix.cpp
#endif
#include "IApplication.hpp"
#define explicit explicit_c
#include <xcb/xcb.h>
#include <xcb/xcb_event.h>
#include <xkbcommon/xkbcommon-x11.h>
#include <xcb/xkb.h>
#include <xcb/xinput.h>
#undef explicit
#include <dbus/dbus.h>
DBusConnection* registerDBus(const char* appName, bool& isFirst);
#include <sys/param.h>
namespace boo
{
int XINPUT_OPCODE = 0;
static xcb_window_t getWindowOfEvent(xcb_generic_event_t* event, bool& windowEvent)
{
switch (XCB_EVENT_RESPONSE_TYPE(event))
{
case XCB_CLIENT_MESSAGE:
{
xcb_client_message_event_t* ev = (xcb_client_message_event_t*)event;
windowEvent = true;
return ev->window;
}
case XCB_EXPOSE:
{
xcb_expose_event_t* ev = (xcb_expose_event_t*)event;
windowEvent = true;
return ev->window;
}
case XCB_CONFIGURE_NOTIFY:
{
xcb_configure_notify_event_t* ev = (xcb_configure_notify_event_t*)event;
windowEvent = true;
return ev->window;
}
case XCB_KEY_PRESS:
{
xcb_key_press_event_t* ev = (xcb_key_press_event_t*)event;
windowEvent = true;
return ev->event;
}
case XCB_KEY_RELEASE:
{
xcb_key_release_event_t* ev = (xcb_key_release_event_t*)event;
windowEvent = true;
return ev->event;
}
case XCB_BUTTON_PRESS:
{
xcb_button_press_event_t* ev = (xcb_button_press_event_t*)event;
windowEvent = true;
return ev->event;
}
case XCB_BUTTON_RELEASE:
{
xcb_button_release_event_t* ev = (xcb_button_release_event_t*)event;
windowEvent = true;
return ev->event;
}
case XCB_MOTION_NOTIFY:
{
xcb_motion_notify_event_t* ev = (xcb_motion_notify_event_t*)event;
windowEvent = true;
return ev->event;
}
case XCB_GE_GENERIC:
{
xcb_ge_event_t* gev = (xcb_ge_event_t*)event;
if (gev->pad0 == XINPUT_OPCODE)
{
switch (gev->event_type)
{
case XCB_INPUT_MOTION:
{
xcb_input_motion_event_t* ev = (xcb_input_motion_event_t*)event;
windowEvent = true;
return ev->event;
}
case XCB_INPUT_TOUCH_BEGIN:
{
xcb_input_touch_begin_event_t* ev = (xcb_input_touch_begin_event_t*)event;
windowEvent = true;
return ev->event;
}
case XCB_INPUT_TOUCH_UPDATE:
{
xcb_input_touch_update_event_t* ev = (xcb_input_touch_update_event_t*)event;
windowEvent = true;
return ev->event;
}
case XCB_INPUT_TOUCH_END:
{
xcb_input_touch_end_event_t* ev = (xcb_input_touch_end_event_t*)event;
windowEvent = true;
return ev->event;
}
}
}
}
}
windowEvent = false;
return 0;
}
IWindow* _CWindowXCBNew(const std::string& title, xcb_connection_t* conn);
class CApplicationXCB final : public IApplication
{
IApplicationCallback& m_callback;
const std::string m_uniqueName;
const std::string m_friendlyName;
const std::string m_pname;
const std::vector<std::string> m_args;
/* DBus single-instance */
bool m_singleInstance;
DBusConnection* m_dbus = NULL;
/* All windows */
std::unordered_map<xcb_window_t, IWindow*> m_windows;
xcb_connection_t* m_xcbConn = NULL;
bool m_running;
void _deletedWindow(IWindow* window)
{
m_windows.erase((xcb_window_t)window->getPlatformHandle());
}
public:
CApplicationXCB(IApplicationCallback& callback,
const std::string& uniqueName,
const std::string& friendlyName,
const std::string& pname,
const std::vector<std::string>& args,
bool singleInstance)
: m_callback(callback),
m_uniqueName(uniqueName),
m_friendlyName(friendlyName),
m_pname(pname),
m_args(args),
m_singleInstance(singleInstance)
{
/* DBus single instance registration */
bool isFirst;
m_dbus = registerDBus(uniqueName.c_str(), isFirst);
if (m_singleInstance)
{
if (!isFirst)
{
/* This is a duplicate instance, send signal and return */
if (args.size())
{
/* create a signal & check for errors */
DBusMessage*
msg = dbus_message_new_signal("/boo/signal/FileHandler",
"boo.signal.FileHandling",
"Open");
/* append arguments onto signal */
DBusMessageIter argsIter;
dbus_message_iter_init_append(msg, &argsIter);
for (const std::string& arg : args)
{
const char* sigvalue = arg.c_str();
dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, &sigvalue);
}
/* send the message and flush the connection */
dbus_uint32_t serial;
dbus_connection_send(m_dbus, msg, &serial);
dbus_connection_flush(m_dbus);
dbus_message_unref(msg);
}
return;
}
else
{
/* This is the first instance, register for signal */
// add a rule for which messages we want to see
DBusError err = {};
dbus_bus_add_match(m_dbus, "type='signal',interface='boo.signal.FileHandling'", &err);
dbus_connection_flush(m_dbus);
}
}
/* Open X connection */
m_xcbConn = xcb_connect(NULL, NULL);
/* The xkb extension requests that the X server does not
* send repeated keydown events when a key is held */
xkb_x11_setup_xkb_extension(m_xcbConn,
XKB_X11_MIN_MAJOR_XKB_VERSION,
XKB_X11_MIN_MINOR_XKB_VERSION,
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS,
NULL, NULL, NULL, NULL);
xcb_xkb_per_client_flags(m_xcbConn, XCB_XKB_ID_USE_CORE_KBD,
XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT, 0, 0, 0);
/* Xinput major opcode */
const xcb_query_extension_reply_t* xiReply =
xcb_get_extension_data(m_xcbConn, &xcb_input_id);
if (xiReply)
XINPUT_OPCODE = xiReply->major_opcode;
}
~CApplicationXCB()
{
xcb_disconnect(m_xcbConn);
}
EPlatformType getPlatformType() const
{
return PLAT_XCB;
}
void run()
{
if (!m_xcbConn)
return;
xcb_generic_event_t* event;
m_running = true;
m_callback.appLaunched(this);
xcb_flush(m_xcbConn);
int xcbFd = xcb_get_file_descriptor(m_xcbConn);
int dbusFd;
dbus_connection_get_unix_fd(m_dbus, &dbusFd);
int maxFd = MAX(xcbFd, dbusFd);
while (m_running)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(xcbFd, &fds);
FD_SET(dbusFd, &fds);
select(maxFd+1, &fds, NULL, NULL, NULL);
if (FD_ISSET(xcbFd, &fds))
{
event = xcb_poll_for_event(m_xcbConn);
if (!event)
break;
bool windowEvent;
xcb_window_t evWindow = getWindowOfEvent(event, windowEvent);
//fprintf(stderr, "EVENT %d\n", XCB_EVENT_RESPONSE_TYPE(event));
if (windowEvent)
{
auto window = m_windows.find(evWindow);
if (window != m_windows.end())
window->second->_incomingEvent(event);
}
free(event);
}
if (FD_ISSET(dbusFd, &fds))
{
DBusMessage* msg;
dbus_connection_read_write(m_dbus, 0);
while ((msg = dbus_connection_pop_message(m_dbus)))
{
/* check if the message is a signal from the correct interface and with the correct name */
if (dbus_message_is_signal(msg, "boo.signal.FileHandling", "Open"))
{
/* read the parameters */
std::vector<const std::string> paths;
DBusMessageIter iter;
dbus_message_iter_init(msg, &iter);
while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID)
{
const char* argVal;
dbus_message_iter_get_basic(&iter, &argVal);
paths.push_back(argVal);
dbus_message_iter_next(&iter);
}
m_callback.appFilesOpen(this, paths);
}
dbus_message_unref(msg);
}
}
}
m_callback.appQuitting(this);
}
void quit()
{
m_running = false;
}
const std::string& getUniqueName() const
{
return m_uniqueName;
}
const std::string& getFriendlyName() const
{
return m_friendlyName;
}
const std::string& getProcessName() const
{
return m_pname;
}
const std::vector<std::string>& getArgs() const
{
return m_args;
}
IWindow* newWindow(const std::string& title)
{
IWindow* newWindow = _CWindowXCBNew(title, m_xcbConn);
m_windows[(xcb_window_t)newWindow->getPlatformHandle()] = newWindow;
return newWindow;
}
};
}

View File

@ -0,0 +1,639 @@
#import <AppKit/AppKit.h>
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl3.h>
#include "windowsys/IGraphicsContext.hpp"
#include "windowsys/IWindow.hpp"
/* AppKit applies OpenGL much differently than other platforms
* the NSOpenGLView class composes together all necessary
* OGL context members and provides the necessary event hooks
* for KB/Mouse/Touch events
*/
static const NSOpenGLPixelFormatAttribute PF_RGBA8_ATTRS[] =
{
NSOpenGLPFAAccelerated,
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAColorSize, 24,
NSOpenGLPFAAlphaSize, 8,
};
static const NSOpenGLPixelFormatAttribute PF_RGBA8_Z24_ATTRS[] =
{
NSOpenGLPFAAccelerated,
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAColorSize, 24,
NSOpenGLPFAAlphaSize, 8,
NSOpenGLPFADepthSize, 24,
};
static const NSOpenGLPixelFormatAttribute PF_RGBAF32_ATTRS[] =
{
NSOpenGLPFAAccelerated,
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAColorFloat,
NSOpenGLPFAColorSize, 96,
NSOpenGLPFAAlphaSize, 32,
};
static const NSOpenGLPixelFormatAttribute PF_RGBAF32_Z24_ATTRS[] =
{
NSOpenGLPFAAccelerated,
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAColorFloat,
NSOpenGLPFAColorSize, 96,
NSOpenGLPFAAlphaSize, 32,
NSOpenGLPFADepthSize, 24,
};
static const NSOpenGLPixelFormatAttribute* PF_TABLE[] =
{
NULL,
PF_RGBA8_ATTRS,
PF_RGBA8_Z24_ATTRS,
PF_RGBAF32_ATTRS,
PF_RGBAF32_Z24_ATTRS
};
namespace boo {class CGraphicsContextCocoa;}
@interface CGraphicsContextCocoaInternal : NSOpenGLView
{
NSUInteger lastModifiers;
boo::CGraphicsContextCocoa* booContext;
}
- (id)initWithBooContext:(boo::CGraphicsContextCocoa*)bctx;
@end
namespace boo
{
class CGraphicsContextCocoa final : public IGraphicsContext
{
EGraphicsAPI m_api;
EPixelFormat m_pf;
IWindow* m_parentWindow;
CGraphicsContextCocoaInternal* m_nsContext;
NSOpenGLContext* m_nsShareContext;
public:
IWindowCallback* m_callback;
CGraphicsContextCocoa(EGraphicsAPI api, IWindow* parentWindow)
: m_api(api),
m_pf(PF_RGBA8),
m_parentWindow(parentWindow),
m_nsContext(NULL),
m_nsShareContext(NULL),
m_callback(NULL)
{}
~CGraphicsContextCocoa()
{
[m_nsContext release];
[m_nsShareContext release];
}
void _setCallback(IWindowCallback* cb)
{
m_callback = cb;
}
EGraphicsAPI getAPI() const
{
return m_api;
}
EPixelFormat getPixelFormat() const
{
return m_pf;
}
void setPixelFormat(EPixelFormat pf)
{
if (pf > PF_RGBAF32_Z24)
return;
m_pf = pf;
}
void initializeContext()
{
if (m_nsShareContext)
return;
m_nsContext = [[CGraphicsContextCocoaInternal alloc] initWithBooContext:this];
[(NSWindow*)m_parentWindow->getPlatformHandle() setContentView:m_nsContext];
}
IGraphicsContext* makeShareContext() const
{
NSOpenGLContext* nsctx;
if (m_nsContext)
{
nsctx = [[NSOpenGLContext alloc] initWithFormat:[m_nsContext pixelFormat]
shareContext:[m_nsContext openGLContext]];
}
else if (m_nsShareContext)
{
nsctx = [[NSOpenGLContext alloc] initWithFormat:[m_nsShareContext pixelFormat]
shareContext:m_nsShareContext];
}
else
return NULL;
if (!nsctx)
return NULL;
CGraphicsContextCocoa* newCtx = new CGraphicsContextCocoa(m_api, NULL);
newCtx->m_nsShareContext = nsctx;
return newCtx;
}
void makeCurrent()
{
if (m_nsContext)
[[m_nsContext openGLContext] makeCurrentContext];
else if (m_nsShareContext)
[m_nsShareContext makeCurrentContext];
}
void clearCurrent()
{
[NSOpenGLContext clearCurrentContext];
}
void swapBuffer()
{
[[m_nsContext openGLContext] flushBuffer];
}
};
IGraphicsContext* _CGraphicsContextCocoaNew(IGraphicsContext::EGraphicsAPI api,
IWindow* parentWindow)
{
if (api != IGraphicsContext::API_OPENGL_3_3 && api != IGraphicsContext::API_OPENGL_4_2)
return NULL;
/* Create temporary context to query GL version */
NSOpenGLPixelFormat* nspf = [[NSOpenGLPixelFormat alloc] initWithAttributes:PF_RGBA8_ATTRS];
if (!nspf)
return NULL;
NSOpenGLContext* nsctx = [[NSOpenGLContext alloc] initWithFormat:nspf shareContext:nil];
[nspf release];
if (!nsctx)
return NULL;
[nsctx makeCurrentContext];
const char* glVersion = (char*)glGetString(GL_VERSION);
unsigned major = 0;
unsigned minor = 0;
if (glVersion)
{
major = glVersion[0] - '0';
minor = glVersion[2] - '0';
}
[NSOpenGLContext clearCurrentContext];
[nsctx release];
if (!glVersion)
return NULL;
if (major > 4 || (major == 4 && minor >= 2))
api = IGraphicsContext::API_OPENGL_4_2;
else if (major == 3 && minor >= 3)
if (api == IGraphicsContext::API_OPENGL_4_2)
return NULL;
return new CGraphicsContextCocoa(api, parentWindow);
}
}
@implementation CGraphicsContextCocoaInternal
- (id)initWithBooContext:(boo::CGraphicsContextCocoa*)bctx
{
lastModifiers = 0;
booContext = bctx;
boo::IGraphicsContext::EPixelFormat pf = bctx->getPixelFormat();
NSOpenGLPixelFormat* nspf = [[NSOpenGLPixelFormat alloc] initWithAttributes:PF_TABLE[pf]];
self = [self initWithFrame:NSMakeRect(0, 0, 100, 100) pixelFormat:nspf];
[nspf release];
return self;
}
- (BOOL)acceptsTouchEvents
{
return YES;
}
static inline boo::IWindowCallback::EModifierKey getMod(NSEventModifierFlags flags)
{
int ret = boo::IWindowCallback::MKEY_NONE;
if (flags & NSControlKeyMask)
ret |= boo::IWindowCallback::MKEY_CTRL;
if (flags & NSAlternateKeyMask)
ret |= boo::IWindowCallback::MKEY_ALT;
if (flags & NSShiftKeyMask)
ret |= boo::IWindowCallback::MKEY_SHIFT;
if (flags & NSCommandKeyMask)
ret |= boo::IWindowCallback::MKEY_COMMAND;
return static_cast<boo::IWindowCallback::EModifierKey>(ret);
}
static inline boo::IWindowCallback::EMouseButton getButton(NSEvent* event)
{
NSInteger buttonNumber = event.buttonNumber;
if (buttonNumber == 3)
return boo::IWindowCallback::BUTTON_MIDDLE;
else if (buttonNumber == 4)
return boo::IWindowCallback::BUTTON_AUX1;
else if (buttonNumber == 5)
return boo::IWindowCallback::BUTTON_AUX2;
return boo::IWindowCallback::BUTTON_NONE;
}
- (void)mouseDown:(NSEvent*)theEvent
{
if (!booContext->m_callback)
return;
NSPoint liw = [self convertPoint:[theEvent locationInWindow] fromView:nil];
float pixelFactor = [[self window] backingScaleFactor];
NSRect frame = [self frame];
boo::IWindowCallback::SWindowCoord coord =
{
{(unsigned)(liw.x * pixelFactor), (unsigned)(liw.y * pixelFactor)},
{(unsigned)liw.x, (unsigned)liw.y},
{(float)(liw.x / frame.size.width), (float)(liw.y / frame.size.height)}
};
booContext->m_callback->mouseDown(coord, boo::IWindowCallback::BUTTON_PRIMARY,
getMod([theEvent modifierFlags]));
}
- (void)mouseUp:(NSEvent*)theEvent
{
if (!booContext->m_callback)
return;
NSPoint liw = [self convertPoint:[theEvent locationInWindow] fromView:nil];
float pixelFactor = [[self window] backingScaleFactor];
NSRect frame = [self frame];
boo::IWindowCallback::SWindowCoord coord =
{
{(unsigned)(liw.x * pixelFactor), (unsigned)(liw.y * pixelFactor)},
{(unsigned)liw.x, (unsigned)liw.y},
{(float)(liw.x / frame.size.width), (float)(liw.y / frame.size.height)}
};
booContext->m_callback->mouseUp(coord, boo::IWindowCallback::BUTTON_PRIMARY,
getMod([theEvent modifierFlags]));
}
- (void)rightMouseDown:(NSEvent*)theEvent
{
if (!booContext->m_callback)
return;
NSPoint liw = [self convertPoint:[theEvent locationInWindow] fromView:nil];
float pixelFactor = [[self window] backingScaleFactor];
NSRect frame = [self frame];
boo::IWindowCallback::SWindowCoord coord =
{
{(unsigned)(liw.x * pixelFactor), (unsigned)(liw.y * pixelFactor)},
{(unsigned)liw.x, (unsigned)liw.y},
{(float)(liw.x / frame.size.width), (float)(liw.y / frame.size.height)}
};
booContext->m_callback->mouseDown(coord, boo::IWindowCallback::BUTTON_SECONDARY,
getMod([theEvent modifierFlags]));
}
- (void)rightMouseUp:(NSEvent*)theEvent
{
if (!booContext->m_callback)
return;
NSPoint liw = [self convertPoint:[theEvent locationInWindow] fromView:nil];
float pixelFactor = [[self window] backingScaleFactor];
NSRect frame = [self frame];
boo::IWindowCallback::SWindowCoord coord =
{
{(unsigned)(liw.x * pixelFactor), (unsigned)(liw.y * pixelFactor)},
{(unsigned)liw.x, (unsigned)liw.y},
{(float)(liw.x / frame.size.width), (float)(liw.y / frame.size.height)}
};
booContext->m_callback->mouseUp(coord, boo::IWindowCallback::BUTTON_SECONDARY,
getMod([theEvent modifierFlags]));
}
- (void)otherMouseDown:(NSEvent*)theEvent
{
if (!booContext->m_callback)
return;
boo::IWindowCallback::EMouseButton button = getButton(theEvent);
if (!button)
return;
NSPoint liw = [self convertPoint:[theEvent locationInWindow] fromView:nil];
float pixelFactor = [[self window] backingScaleFactor];
NSRect frame = [self frame];
boo::IWindowCallback::SWindowCoord coord =
{
{(unsigned)(liw.x * pixelFactor), (unsigned)(liw.y * pixelFactor)},
{(unsigned)liw.x, (unsigned)liw.y},
{(float)(liw.x / frame.size.width), (float)(liw.y / frame.size.height)}
};
booContext->m_callback->mouseDown(coord, button, getMod([theEvent modifierFlags]));
}
- (void)otherMouseUp:(NSEvent*)theEvent
{
if (!booContext->m_callback)
return;
boo::IWindowCallback::EMouseButton button = getButton(theEvent);
if (!button)
return;
NSPoint liw = [self convertPoint:[theEvent locationInWindow] fromView:nil];
float pixelFactor = [[self window] backingScaleFactor];
NSRect frame = [self frame];
boo::IWindowCallback::SWindowCoord coord =
{
{(unsigned)(liw.x * pixelFactor), (unsigned)(liw.y * pixelFactor)},
{(unsigned)liw.x, (unsigned)liw.y},
{(float)(liw.x / frame.size.width), (float)(liw.y / frame.size.height)}
};
booContext->m_callback->mouseUp(coord, button, getMod([theEvent modifierFlags]));
}
- (void)mouseMoved:(NSEvent*)theEvent
{
if (!booContext->m_callback)
return;
NSPoint liw = [self convertPoint:[theEvent locationInWindow] fromView:nil];
float pixelFactor = [[self window] backingScaleFactor];
NSRect frame = [self frame];
boo::IWindowCallback::SWindowCoord coord =
{
{(unsigned)(liw.x * pixelFactor), (unsigned)(liw.y * pixelFactor)},
{(unsigned)liw.x, (unsigned)liw.y},
{(float)(liw.x / frame.size.width), (float)(liw.y / frame.size.height)}
};
booContext->m_callback->mouseMove(coord);
}
- (void)mouseDragged:(NSEvent*)theEvent
{
[self mouseMoved:theEvent];
}
- (void)rightMouseDragged:(NSEvent*)theEvent
{
[self mouseMoved:theEvent];
}
- (void)otherMouseDragged:(NSEvent*)theEvent
{
[self mouseMoved:theEvent];
}
- (void)scrollWheel:(NSEvent*)theEvent
{
if (!booContext->m_callback)
return;
boo::IWindowCallback::SScrollDelta scroll =
{
{(float)[theEvent scrollingDeltaX], (float)[theEvent scrollingDeltaY]},
(bool)[theEvent hasPreciseScrollingDeltas]
};
booContext->m_callback->scroll(scroll);
}
- (void)touchesBeganWithEvent:(NSEvent*)event
{
if (!booContext->m_callback)
return;
for (NSTouch* touch in [event touchesMatchingPhase:NSTouchPhaseBegan inView:nil])
{
NSPoint pos = touch.normalizedPosition;
boo::IWindowCallback::SWindowCoord coord =
{
{0, 0},
{0, 0},
{(float)pos.x, (float)pos.y}
};
booContext->m_callback->touchDown(coord, (uintptr_t)touch.identity);
}
}
- (void)touchesEndedWithEvent:(NSEvent*)event
{
if (!booContext->m_callback)
return;
for (NSTouch* touch in [event touchesMatchingPhase:NSTouchPhaseEnded inView:nil])
{
NSPoint pos = touch.normalizedPosition;
boo::IWindowCallback::SWindowCoord coord =
{
{0, 0},
{0, 0},
{(float)pos.x, (float)pos.y}
};
booContext->m_callback->touchUp(coord, (uintptr_t)touch.identity);
}
}
- (void)touchesMovedWithEvent:(NSEvent*)event
{
if (!booContext->m_callback)
return;
for (NSTouch* touch in [event touchesMatchingPhase:NSTouchPhaseMoved inView:nil])
{
NSPoint pos = touch.normalizedPosition;
boo::IWindowCallback::SWindowCoord coord =
{
{0, 0},
{0, 0},
{(float)pos.x, (float)pos.y}
};
booContext->m_callback->touchMove(coord, (uintptr_t)touch.identity);
}
}
- (void)touchesCancelledWithEvent:(NSEvent*)event
{
if (!booContext->m_callback)
return;
for (NSTouch* touch in [event touchesMatchingPhase:NSTouchPhaseCancelled inView:nil])
{
NSPoint pos = touch.normalizedPosition;
boo::IWindowCallback::SWindowCoord coord =
{
{0, 0},
{0, 0},
{(float)pos.x, (float)pos.y}
};
booContext->m_callback->touchUp(coord, (uintptr_t)touch.identity);
}
}
/* keycodes for keys that are independent of keyboard layout*/
enum
{
kVK_Return = 0x24,
kVK_Tab = 0x30,
kVK_Space = 0x31,
kVK_Delete = 0x33,
kVK_Escape = 0x35,
kVK_Command = 0x37,
kVK_Shift = 0x38,
kVK_CapsLock = 0x39,
kVK_Option = 0x3A,
kVK_Control = 0x3B,
kVK_RightShift = 0x3C,
kVK_RightOption = 0x3D,
kVK_RightControl = 0x3E,
kVK_Function = 0x3F,
kVK_F17 = 0x40,
kVK_VolumeUp = 0x48,
kVK_VolumeDown = 0x49,
kVK_Mute = 0x4A,
kVK_F18 = 0x4F,
kVK_F19 = 0x50,
kVK_F20 = 0x5A,
kVK_F5 = 0x60,
kVK_F6 = 0x61,
kVK_F7 = 0x62,
kVK_F3 = 0x63,
kVK_F8 = 0x64,
kVK_F9 = 0x65,
kVK_F11 = 0x67,
kVK_F13 = 0x69,
kVK_F16 = 0x6A,
kVK_F14 = 0x6B,
kVK_F10 = 0x6D,
kVK_F12 = 0x6F,
kVK_F15 = 0x71,
kVK_Help = 0x72,
kVK_Home = 0x73,
kVK_PageUp = 0x74,
kVK_ForwardDelete = 0x75,
kVK_F4 = 0x76,
kVK_End = 0x77,
kVK_F2 = 0x78,
kVK_PageDown = 0x79,
kVK_F1 = 0x7A,
kVK_LeftArrow = 0x7B,
kVK_RightArrow = 0x7C,
kVK_DownArrow = 0x7D,
kVK_UpArrow = 0x7E
};
static boo::IWindowCallback::ESpecialKey translateKeycode(short code)
{
switch (code) {
case kVK_F1:
return boo::IWindowCallback::KEY_F1;
case kVK_F2:
return boo::IWindowCallback::KEY_F2;
case kVK_F3:
return boo::IWindowCallback::KEY_F3;
case kVK_F4:
return boo::IWindowCallback::KEY_F4;
case kVK_F5:
return boo::IWindowCallback::KEY_F5;
case kVK_F6:
return boo::IWindowCallback::KEY_F6;
case kVK_F7:
return boo::IWindowCallback::KEY_F7;
case kVK_F8:
return boo::IWindowCallback::KEY_F8;
case kVK_F9:
return boo::IWindowCallback::KEY_F9;
case kVK_F10:
return boo::IWindowCallback::KEY_F10;
case kVK_F11:
return boo::IWindowCallback::KEY_F11;
case kVK_F12:
return boo::IWindowCallback::KEY_F12;
case kVK_Escape:
return boo::IWindowCallback::KEY_ESC;
case kVK_Return:
return boo::IWindowCallback::KEY_ENTER;
case kVK_Delete:
return boo::IWindowCallback::KEY_BACKSPACE;
case kVK_ForwardDelete:
return boo::IWindowCallback::KEY_DELETE;
case kVK_Home:
return boo::IWindowCallback::KEY_HOME;
case kVK_End:
return boo::IWindowCallback::KEY_END;
case kVK_PageUp:
return boo::IWindowCallback::KEY_PGUP;
case kVK_PageDown:
return boo::IWindowCallback::KEY_PGDOWN;
case kVK_LeftArrow:
return boo::IWindowCallback::KEY_LEFT;
case kVK_RightArrow:
return boo::IWindowCallback::KEY_RIGHT;
case kVK_UpArrow:
return boo::IWindowCallback::KEY_UP;
case kVK_DownArrow:
return boo::IWindowCallback::KEY_DOWN;
default:
return boo::IWindowCallback::KEY_NONE;
}
}
- (void)keyDown:(NSEvent*)theEvent
{
if (!booContext->m_callback)
return;
NSString* chars = theEvent.characters;
if ([chars length] == 0)
booContext->m_callback->specialKeyDown(translateKeycode(theEvent.keyCode),
getMod(theEvent.modifierFlags),
theEvent.isARepeat);
else
booContext->m_callback->charKeyDown([chars characterAtIndex:0],
getMod(theEvent.modifierFlags),
theEvent.isARepeat);
}
- (void)keyUp:(NSEvent*)theEvent
{
if (!booContext->m_callback)
return;
NSString* chars = theEvent.characters;
if ([chars length] == 0)
booContext->m_callback->specialKeyUp(translateKeycode(theEvent.keyCode),
getMod(theEvent.modifierFlags));
else
booContext->m_callback->charKeyUp([chars characterAtIndex:0],
getMod(theEvent.modifierFlags));
}
- (void)flagsChanged:(NSEvent*)theEvent
{
if (!booContext->m_callback)
return;
NSUInteger modFlags = theEvent.modifierFlags;
bool isRepeat = theEvent.isARepeat;
if (modFlags != lastModifiers)
{
NSUInteger changedFlags = modFlags ^ lastModifiers;
NSUInteger downFlags = changedFlags & modFlags;
if (downFlags & NSControlKeyMask)
booContext->m_callback->modKeyDown(boo::IWindowCallback::MKEY_CTRL, isRepeat);
if (downFlags & NSAlternateKeyMask)
booContext->m_callback->modKeyDown(boo::IWindowCallback::MKEY_ALT, isRepeat);
if (downFlags & NSShiftKeyMask)
booContext->m_callback->modKeyDown(boo::IWindowCallback::MKEY_SHIFT, isRepeat);
if (downFlags & NSCommandKeyMask)
booContext->m_callback->modKeyDown(boo::IWindowCallback::MKEY_COMMAND, isRepeat);
NSUInteger upFlags = changedFlags & ~modFlags;
if (upFlags & NSControlKeyMask)
booContext->m_callback->modKeyUp(boo::IWindowCallback::MKEY_CTRL);
if (upFlags & NSAlternateKeyMask)
booContext->m_callback->modKeyUp(boo::IWindowCallback::MKEY_ALT);
if (upFlags & NSShiftKeyMask)
booContext->m_callback->modKeyUp(boo::IWindowCallback::MKEY_SHIFT);
if (upFlags & NSCommandKeyMask)
booContext->m_callback->modKeyUp(boo::IWindowCallback::MKEY_COMMAND);
lastModifiers = modFlags;
}
}
@end

View File

@ -0,0 +1,63 @@
#include "graphicsys/IGFXContext.hpp"
#include "windowsys/IWindow.hpp"
namespace boo
{
class CGraphicsContextWayland final : public IGFXContext
{
EGraphicsAPI m_api;
EPixelFormat m_pf;
IWindow* m_parentWindow;
public:
IWindowCallback* m_callback;
CGraphicsContextWayland(EGraphicsAPI api, IWindow* parentWindow)
: m_api(api),
m_pf(PF_RGBA8),
m_parentWindow(parentWindow)
{}
~CGraphicsContextWayland()
{
}
void _setCallback(IWindowCallback* cb)
{
m_callback = cb;
}
EGraphicsAPI getAPI() const
{
return m_api;
}
EPixelFormat getPixelFormat() const
{
return m_pf;
}
void setPixelFormat(EPixelFormat pf)
{
if (pf > PF_RGBAF32_Z24)
return;
m_pf = pf;
}
void initializeContext()
{
}
};
IGFXContext* _CGraphicsContextWaylandNew(IGFXContext::EGraphicsAPI api,
IWindow* parentWindow)
{
return new CGraphicsContextWayland(api, parentWindow);
}
}

View File

@ -0,0 +1,83 @@
#include "windowsys/IGraphicsContext.hpp"
#include "windowsys/IWindow.hpp"
namespace boo
{
class CGraphicsContextWin32 final : public IGraphicsContext
{
EGraphicsAPI m_api;
EPixelFormat m_pf;
IWindow* m_parentWindow;
public:
IWindowCallback* m_callback;
CGraphicsContextWin32(EGraphicsAPI api, IWindow* parentWindow)
: m_api(api),
m_pf(PF_RGBA8),
m_parentWindow(parentWindow)
{}
~CGraphicsContextWin32()
{
}
void _setCallback(IWindowCallback* cb)
{
m_callback = cb;
}
EGraphicsAPI getAPI() const
{
return m_api;
}
EPixelFormat getPixelFormat() const
{
return m_pf;
}
void setPixelFormat(EPixelFormat pf)
{
if (pf > PF_RGBAF32_Z24)
return;
m_pf = pf;
}
void initializeContext()
{
}
IGraphicsContext* makeShareContext() const
{
}
void makeCurrent()
{
}
void clearCurrent()
{
}
void swapBuffer()
{
}
};
IGraphicsContext* _CGraphicsContextWin32New(IGraphicsContext::EGraphicsAPI api,
IWindow* parentWindow)
{
}
}

View File

@ -0,0 +1,153 @@
#include "graphicsys/IGFXContext.hpp"
#include "windowsys/IWindow.hpp"
#include <xcb/xcb.h>
#include <xcb/glx.h>
#include <GL/glx.h>
#include <GL/glcorearb.h>
#include <stdio.h>
#include <stdlib.h>
#include <thread>
namespace boo
{
class CGraphicsContextXCB final : public IGFXContext
{
EGraphicsAPI m_api;
EPixelFormat m_pf;
IWindow* m_parentWindow;
xcb_connection_t* m_xcbConn;
xcb_glx_fbconfig_t m_fbconfig = 0;
xcb_visualid_t m_visualid = 0;
xcb_glx_window_t m_glxWindow = 0;
xcb_glx_context_t m_glxCtx = 0;
xcb_glx_context_tag_t m_glxCtxTag = 0;
std::thread* m_commandThread = NULL;
public:
IWindowCallback* m_callback;
CGraphicsContextXCB(EGraphicsAPI api, IWindow* parentWindow, xcb_connection_t* conn, uint32_t& visualIdOut)
: m_api(api),
m_pf(PF_RGBA8),
m_parentWindow(parentWindow),
m_xcbConn(conn)
{
/* WTF freedesktop?? Fix this awful API and your nonexistant docs */
xcb_glx_get_fb_configs_reply_t* fbconfigs =
xcb_glx_get_fb_configs_reply(m_xcbConn, xcb_glx_get_fb_configs(m_xcbConn, 0), NULL);
struct conf_prop
{
uint32_t key;
uint32_t val;
}* props = (struct conf_prop*)xcb_glx_get_fb_configs_property_list(fbconfigs);
for (uint32_t i=0 ; i<fbconfigs->num_FB_configs ; ++i)
{
struct conf_prop* configProps = &props[fbconfigs->num_properties * i];
uint32_t fbconfId, visualId, depthSize, colorSize, doubleBuffer;
for (uint32_t j=0 ; j<fbconfigs->num_properties ; ++j)
{
struct conf_prop* prop = &configProps[j];
if (prop->key == GLX_FBCONFIG_ID)
fbconfId = prop->val;
if (prop->key == GLX_VISUAL_ID)
visualId = prop->val;
else if (prop->key == GLX_DEPTH_SIZE)
depthSize = prop->val;
else if (prop->key == GLX_BUFFER_SIZE)
colorSize = prop->val;
else if (prop->key == GLX_DOUBLEBUFFER)
doubleBuffer = prop->val;
}
/* Double-buffer only */
if (!doubleBuffer)
continue;
if (m_pf == PF_RGBA8 && colorSize >= 32)
{
m_fbconfig = fbconfId;
m_visualid = visualId;
break;
}
else if (m_pf == PF_RGBA8_Z24 && colorSize >= 32 && depthSize >= 24)
{
m_fbconfig = fbconfId;
m_visualid = visualId;
break;
}
else if (m_pf == PF_RGBAF32 && colorSize >= 128)
{
m_fbconfig = fbconfId;
m_visualid = visualId;
break;
}
else if (m_pf == PF_RGBAF32_Z24 && colorSize >= 128 && depthSize >= 24)
{
m_fbconfig = fbconfId;
m_visualid = visualId;
break;
}
}
free(fbconfigs);
if (!m_fbconfig)
{
throw std::runtime_error("unable to find suitable pixel format");
return;
}
visualIdOut = m_visualid;
}
~CGraphicsContextXCB()
{
}
void _setCallback(IWindowCallback* cb)
{
m_callback = cb;
}
EGraphicsAPI getAPI() const
{
return m_api;
}
EPixelFormat getPixelFormat() const
{
return m_pf;
}
void setPixelFormat(EPixelFormat pf)
{
if (pf > PF_RGBAF32_Z24)
return;
m_pf = pf;
}
void initializeContext()
{
m_glxWindow = xcb_generate_id(m_xcbConn);
xcb_glx_create_window(m_xcbConn, 0, m_fbconfig,
m_parentWindow->getPlatformHandle(),
m_glxWindow, 0, NULL);
}
};
IGFXContext* _CGraphicsContextXCBNew(IGFXContext::EGraphicsAPI api,
IWindow* parentWindow, xcb_connection_t* conn,
uint32_t& visualIdOut)
{
return new CGraphicsContextXCB(api, parentWindow, conn, visualIdOut);
}
}

View File

@ -0,0 +1,32 @@
#include "graphicsys/hecl/IHECLBackend.hpp"
class CHECLBackendGLSL : public IHECLBackend
{
public:
CHECLBackendGLSL(const CHECLLexer& lexer)
{
}
Type getType() const {return GLSL;}
};
IHECLBackend* NewHECLBackendGLSL(const CHECLLexer& lexer)
{
return new CHECLBackendGLSL(lexer);
}
class CHECLBackendGLSLCafe final : public CHECLBackendGLSL
{
public:
CHECLBackendGLSLCafe(const CHECLLexer& lexer)
: CHECLBackendGLSL(lexer)
{
}
Type getType() const {return GLSL_CAFE;}
};
IHECLBackend* NewHECLBackendGLSLCafe(const CHECLLexer& lexer)
{
return new CHECLBackendGLSLCafe(lexer);
}

View File

@ -0,0 +1,15 @@
#include "graphicsys/hecl/IHECLBackend.hpp"
class CHECLBackendHLSL final : public IHECLBackend
{
public:
CHECLBackendHLSL(const CHECLLexer& lexer)
{
}
Type getType() const {return HLSL;}
};
IHECLBackend* NewHECLBackendHLSL(const CHECLLexer& lexer)
{
return new CHECLBackendHLSL(lexer);
}

View File

@ -0,0 +1,15 @@
#include "graphicsys/hecl/IHECLBackend.hpp"
class CHECLBackendMetal final : public IHECLBackend
{
public:
CHECLBackendMetal(const CHECLLexer& lexer)
{
}
Type getType() const {return METAL;}
};
IHECLBackend* NewHECLBackendMetal(const CHECLLexer& lexer)
{
return new CHECLBackendMetal(lexer);
}

View File

@ -0,0 +1,16 @@
#include "graphicsys/hecl/IHECLBackend.hpp"
class CHECLBackendOutline final : public IHECLBackend
{
public:
CHECLBackendOutline(const CHECLLexer& lexer)
{
}
Type getType() const {return OUTLINE;}
};
IHECLBackend* NewHECLBackendOutline(const CHECLLexer& lexer)
{
return new CHECLBackendOutline(lexer);
}

View File

@ -0,0 +1,15 @@
#include "graphicsys/hecl/IHECLBackend.hpp"
class CHECLBackendTEV final : public IHECLBackend
{
public:
CHECLBackendTEV(const CHECLLexer& lexer)
{
}
Type getType() const {return TEV;}
};
IHECLBackend* NewHECLBackendTEV(const CHECLLexer& lexer)
{
return new CHECLBackendTEV(lexer);
}

View File

@ -0,0 +1,14 @@
#include "graphicsys/hecl/CHECLLexer.hpp"
CHECLLexer::CHECLLexer(const CGFXVertexLayoutBase& vertLayout,
const std::string& colorHECL)
: m_vertLayout(vertLayout)
{
}
CHECLLexer::CHECLLexer(const CGFXVertexLayoutBase& vertLayout,
const std::string& colorHECL,
const std::string& alphaHECL)
: m_vertLayout(vertLayout)
{
}

View File

@ -0,0 +1,180 @@
#import <AppKit/AppKit.h>
#include "IApplication.hpp"
#include "windowsys/IWindow.hpp"
#include "windowsys/IGraphicsContext.hpp"
namespace boo {class CWindowCocoa;}
@interface CWindowCocoaInternal : NSWindow
{
boo::CWindowCocoa* booWindow;
}
- (id)initWithBooWindow:(boo::CWindowCocoa*)bw title:(const std::string&)title;
- (void)setFrameDefault;
- (NSRect)genFrameDefault;
@end
namespace boo
{
IGraphicsContext* _CGraphicsContextCocoaNew(IGraphicsContext::EGraphicsAPI api,
IWindow* parentWindow);
class CWindowCocoa final : public IWindow
{
CWindowCocoaInternal* m_nsWindow;
IGraphicsContext* m_gfxCtx;
public:
CWindowCocoa(const std::string& title)
{
m_nsWindow = [[CWindowCocoaInternal alloc] initWithBooWindow:this title:title];
m_gfxCtx = _CGraphicsContextCocoaNew(IGraphicsContext::API_OPENGL_3_3, this);
m_gfxCtx->initializeContext();
}
void _clearWindow()
{
m_nsWindow = NULL;
}
~CWindowCocoa()
{
[m_nsWindow orderOut:nil];
[m_nsWindow release];
delete m_gfxCtx;
IApplicationInstance()->_deletedWindow(this);
}
void setCallback(IWindowCallback* cb)
{
m_gfxCtx->_setCallback(cb);
}
void showWindow()
{
[m_nsWindow makeKeyAndOrderFront:nil];
}
void hideWindow()
{
[m_nsWindow orderOut:nil];
}
std::string getTitle()
{
return [[m_nsWindow title] UTF8String];
}
void setTitle(const std::string& title)
{
[m_nsWindow setTitle:[[NSString stringWithUTF8String:title.c_str()] autorelease]];
}
void setWindowFrameDefault()
{
NSScreen* mainScreen = [NSScreen mainScreen];
NSRect scrFrame = mainScreen.frame;
float x_off = scrFrame.size.width / 3.0;
float y_off = scrFrame.size.height / 3.0;
[m_nsWindow setFrame:NSMakeRect(x_off, y_off, x_off * 2.0, y_off * 2.0) display:NO];
}
void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const
{
NSRect wFrame = m_nsWindow.frame;
xOut = wFrame.origin.x;
yOut = wFrame.origin.y;
wOut = wFrame.size.width;
hOut = wFrame.size.height;
}
void setWindowFrame(float x, float y, float w, float h)
{
NSRect wFrame = NSMakeRect(x, y, w, h);
[m_nsWindow setFrame:wFrame display:NO];
}
float getVirtualPixelFactor() const
{
return [m_nsWindow backingScaleFactor];
}
bool isFullscreen() const
{
return ([m_nsWindow styleMask] & NSFullScreenWindowMask) == NSFullScreenWindowMask;
}
void setFullscreen(bool fs)
{
if ((fs && !isFullscreen()) || (!fs && isFullscreen()))
[m_nsWindow toggleFullScreen:nil];
}
ETouchType getTouchType() const
{
return TOUCH_TRACKPAD;
}
uintptr_t getPlatformHandle() const
{
return (uintptr_t)m_nsWindow;
}
};
IWindow* _CWindowCocoaNew(const std::string& title)
{
return new CWindowCocoa(title);
}
}
@implementation CWindowCocoaInternal
- (id)initWithBooWindow:(boo::CWindowCocoa *)bw title:(const std::string&)title
{
self = [self initWithContentRect:[self genFrameDefault]
styleMask:NSTitledWindowMask|
NSClosableWindowMask|
NSMiniaturizableWindowMask|
NSResizableWindowMask
backing:NSBackingStoreBuffered
defer:YES];
self.title = [[NSString stringWithUTF8String:title.c_str()] autorelease];
booWindow = bw;
return self;
}
- (void)setFrameDefault
{
[self setFrame:[self genFrameDefault] display:NO];
}
- (NSRect)genFrameDefault
{
NSScreen* mainScreen = [NSScreen mainScreen];
NSRect scrFrame = mainScreen.frame;
float width = scrFrame.size.width * 2.0 / 3.0;
float height = scrFrame.size.height * 2.0 / 3.0;
return NSMakeRect((scrFrame.size.width - width) / 2.0,
(scrFrame.size.height - height) / 2.0,
width, height);
}
- (void)close
{
booWindow->_clearWindow();
[super close];
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (BOOL)acceptsMouseMovedEvents
{
return YES;
}
- (NSWindowCollectionBehavior)collectionBehavior
{
return NSWindowCollectionBehaviorFullScreenPrimary;
}
@end

View File

@ -0,0 +1,98 @@
#include "windowsys/IWindow.hpp"
#include "windowsys/IGraphicsContext.hpp"
namespace boo
{
IGraphicsContext* _CGraphicsContextWaylandNew(IGraphicsContext::EGraphicsAPI api,
IWindow* parentWindow);
class CWindowWayland final : public IWindow
{
public:
CWindowWayland(const std::string& title)
{
}
~CWindowWayland()
{
}
void setCallback(IWindowCallback* cb)
{
}
void showWindow()
{
}
void hideWindow()
{
}
std::string getTitle()
{
}
void setTitle(const std::string& title)
{
}
void setWindowFrameDefault()
{
}
void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const
{
}
void setWindowFrame(float x, float y, float w, float h)
{
}
float getVirtualPixelFactor() const
{
}
bool isFullscreen() const
{
}
void setFullscreen(bool fs)
{
}
uintptr_t getPlatformHandle() const
{
}
ETouchType getTouchType() const
{
}
};
IWindow* _CWindowWaylandNew(const std::string& title)
{
return new CWindowWayland(title);
}
}

View File

@ -0,0 +1,96 @@
#include "windowsys/IWindow.hpp"
#include "windowsys/IGraphicsContext.hpp"
namespace boo
{
IGraphicsContext* _CGraphicsContextWin32New(IGraphicsContext::EGraphicsAPI api,
IWindow* parentWindow);
class CWindowWin32 final : public IWindow
{
HWND m_hwnd;
public:
CWindowWin32(const std::string& title)
{
m_hwnd = CreateWindowW(L"BooWindow", L"BooTest", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
}
~CWindowWin32()
{
}
void setCallback(IWindowCallback* cb)
{
}
void showWindow()
{
}
void hideWindow()
{
}
std::string getTitle()
{
}
void setTitle(const std::string& title)
{
}
void setWindowFrameDefault()
{
}
void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const
{
}
void setWindowFrame(float x, float y, float w, float h)
{
}
float getVirtualPixelFactor() const
{
}
bool isFullscreen() const
{
}
void setFullscreen(bool fs)
{
}
ETouchType getTouchType() const
{
}
};
IWindow* _CWindowWin32New(const std::string& title)
{
return new CWindowWin32(title);
}
}

View File

@ -0,0 +1,769 @@
#include "windowsys/IWindow.hpp"
#include "graphicsys/IGFXContext.hpp"
#include "IApplication.hpp"
#include <xcb/xcb.h>
#include <xcb/xcb_event.h>
#include <xcb/xproto.h>
#include <xcb/xcb_keysyms.h>
#include <xkbcommon/xkbcommon.h>
#include <xcb/xinput.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#define XK_MISCELLANY
#define XK_XKB_KEYS
#define XK_LATIN1
#include <X11/keysymdef.h>
#define REF_DPMM 3.7824 /* 96 DPI */
#define FS_ATOM "_NET_WM_STATE_FULLSCREEN"
namespace boo
{
extern int XINPUT_OPCODE;
static inline double fp3232val(xcb_input_fp3232_t* val)
{
return val->integral + val->frac / (double)UINT_MAX;
}
static uint32_t translateKeysym(xcb_keysym_t sym, int& specialSym, int& modifierSym)
{
specialSym = IWindowCallback::KEY_NONE;
modifierSym = IWindowCallback::MKEY_NONE;
if (sym >= XK_F1 && sym <= XK_F12)
specialSym = IWindowCallback::KEY_F1 + sym - XK_F1;
else if (sym == XK_Escape)
specialSym = IWindowCallback::KEY_ESC;
else if (sym == XK_Return)
specialSym = IWindowCallback::KEY_ENTER;
else if (sym == XK_BackSpace)
specialSym = IWindowCallback::KEY_BACKSPACE;
else if (sym == XK_Insert)
specialSym = IWindowCallback::KEY_INSERT;
else if (sym == XK_Delete)
specialSym = IWindowCallback::KEY_DELETE;
else if (sym == XK_Home)
specialSym = IWindowCallback::KEY_HOME;
else if (sym == XK_End)
specialSym = IWindowCallback::KEY_END;
else if (sym == XK_Page_Up)
specialSym = IWindowCallback::KEY_PGUP;
else if (sym == XK_Page_Down)
specialSym = IWindowCallback::KEY_PGDOWN;
else if (sym == XK_Left)
specialSym = IWindowCallback::KEY_LEFT;
else if (sym == XK_Right)
specialSym = IWindowCallback::KEY_RIGHT;
else if (sym == XK_Up)
specialSym = IWindowCallback::KEY_UP;
else if (sym == XK_Down)
specialSym = IWindowCallback::KEY_DOWN;
else if (sym == XK_Shift_L || sym == XK_Shift_R)
modifierSym = IWindowCallback::MKEY_SHIFT;
else if (sym == XK_Control_L || sym == XK_Control_R)
modifierSym = IWindowCallback::MKEY_CTRL;
else if (sym == XK_Alt_L || sym == XK_Alt_R)
modifierSym = IWindowCallback::MKEY_ALT;
else
return xkb_keysym_to_utf32(sym);
return 0;
}
static int translateModifiers(unsigned state)
{
int retval = 0;
if (state & XCB_MOD_MASK_SHIFT)
retval |= IWindowCallback::MKEY_SHIFT;
if (state & XCB_MOD_MASK_CONTROL)
retval |= IWindowCallback::MKEY_CTRL;
if (state & XCB_MOD_MASK_1)
retval |= IWindowCallback::MKEY_ALT;
return retval;
}
static int translateButton(unsigned detail)
{
int retval = 0;
if (detail == 1)
retval = IWindowCallback::BUTTON_PRIMARY;
else if (detail == 3)
retval = IWindowCallback::BUTTON_SECONDARY;
else if (detail == 2)
retval = IWindowCallback::BUTTON_MIDDLE;
else if (detail == 8)
retval = IWindowCallback::BUTTON_AUX1;
else if (detail == 9)
retval =
IWindowCallback::BUTTON_AUX2;
return retval;
}
#define INTERN_ATOM(var, conn, name, if_exists) \
do {\
xcb_intern_atom_cookie_t cookie = \
xcb_intern_atom(conn, if_exists, sizeof(#name), #name); \
xcb_intern_atom_reply_t* reply = \
xcb_intern_atom_reply(conn, cookie, NULL); \
var = reply->atom; \
free(reply); \
} while(0)
struct SXCBAtoms
{
xcb_atom_t m_wmProtocols = 0;
xcb_atom_t m_wmDeleteWindow = 0;
xcb_atom_t m_netwmState = 0;
xcb_atom_t m_netwmStateFullscreen = 0;
xcb_atom_t m_netwmStateAdd = 0;
xcb_atom_t m_netwmStateRemove = 0;
xcb_key_symbols_t* m_keySyms = NULL;
SXCBAtoms(xcb_connection_t* conn)
{
INTERN_ATOM(m_wmProtocols, conn, WM_PROTOCOLS, 1);
INTERN_ATOM(m_wmDeleteWindow, conn, WM_DELETE_WINDOW, 1);
INTERN_ATOM(m_netwmState, conn, _NET_WM_STATE, 0);
INTERN_ATOM(m_netwmStateFullscreen, conn, _NET_WM_STATE_FULLSCREEN, 0);
INTERN_ATOM(m_netwmStateAdd, conn, _NET_WM_STATE_ADD, 0);
INTERN_ATOM(m_netwmStateRemove, conn, _NET_WM_STATE_REMOVE, 0);
m_keySyms = xcb_key_symbols_alloc(conn);
}
};
static SXCBAtoms* S_ATOMS = NULL;
static void genFrameDefault(xcb_screen_t* screen, int* xOut, int* yOut, int* wOut, int* hOut)
{
float width = screen->width_in_pixels * 2.0 / 3.0;
float height = screen->height_in_pixels * 2.0 / 3.0;
*xOut = (screen->width_in_pixels - width) / 2.0;
*yOut = (screen->height_in_pixels - height) / 2.0;
*wOut = width;
*hOut = height;
}
IGFXContext* _CGraphicsContextXCBNew(IGFXContext::EGraphicsAPI api,
IWindow* parentWindow, xcb_connection_t* conn,
uint32_t& visualIdOut);
class CWindowXCB final : public IWindow
{
xcb_connection_t* m_xcbConn;
xcb_window_t m_windowId;
IGFXContext* m_gfxCtx;
IWindowCallback* m_callback;
/* Last known input device id (0xffff if not yet set) */
xcb_input_device_id_t m_lastInputID = 0xffff;
ETouchType m_touchType = TOUCH_NONE;
/* Scroll valuators */
int m_hScrollValuator = -1;
int m_vScrollValuator = -1;
double m_hScrollLast = 0.0;
double m_vScrollLast = 0.0;
/* Cached window rectangle (to avoid repeated X queries) */
int m_wx, m_wy, m_ww, m_wh;
float m_pixelFactor;
public:
CWindowXCB(const std::string& title, xcb_connection_t* conn)
: m_xcbConn(conn), m_callback(NULL)
{
if (!S_ATOMS)
S_ATOMS = new SXCBAtoms(conn);
/* Default screen */
xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(m_xcbConn)).data;
m_pixelFactor = screen->width_in_pixels / (float)screen->width_in_millimeters / REF_DPMM;
/* Construct graphics context */
uint32_t visualId;
m_gfxCtx = _CGraphicsContextXCBNew(IGFXContext::API_OPENGL_3_3, this, m_xcbConn, visualId);
/* Create colormap */
xcb_colormap_t colormap = xcb_generate_id(m_xcbConn);
xcb_create_colormap(m_xcbConn, XCB_COLORMAP_ALLOC_NONE,
colormap, screen->root, visualId);
/* Create window */
int x, y, w, h;
genFrameDefault(screen, &x, &y, &w, &h);
uint32_t valueMasks[] =
{
XCB_NONE,
XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE |
XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE |
XCB_EVENT_MASK_STRUCTURE_NOTIFY,
colormap,
XCB_NONE
};
m_windowId = xcb_generate_id(conn);
xcb_create_window(m_xcbConn, XCB_COPY_FROM_PARENT, m_windowId, screen->root,
x, y, w, h, 10,
XCB_WINDOW_CLASS_INPUT_OUTPUT, visualId,
XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP,
valueMasks);
/* The XInput 2.1 extension enables per-pixel smooth scrolling trackpads */
xcb_generic_error_t* xiErr = NULL;
xcb_input_xi_query_version_reply_t* xiReply =
xcb_input_xi_query_version_reply(m_xcbConn,
xcb_input_xi_query_version(m_xcbConn, 2, 1), &xiErr);
if (!xiErr)
{
struct
{
xcb_input_event_mask_t mask;
uint32_t maskVal;
} masks =
{
{XCB_INPUT_DEVICE_ALL_MASTER, 1},
XCB_INPUT_XI_EVENT_MASK_MOTION |
XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN |
XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE |
XCB_INPUT_XI_EVENT_MASK_TOUCH_END
};
xcb_input_xi_select_events(m_xcbConn, m_windowId, 1, &masks.mask);
}
free(xiReply);
/* Register netwm extension atom for window closing */
#if 0
xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId, S_ATOMS->m_wmProtocols,
XCB_ATOM_ATOM, 32, 1, &S_ATOMS->m_wmDeleteWindow);
const xcb_atom_t wm_protocols[1] = {
S_ATOMS->m_wmDeleteWindow,
};
xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId,
S_ATOMS->m_wmProtocols, 4,
32, 1, wm_protocols);
#endif
/* Set the title of the window */
const char* c_title = title.c_str();
xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId,
XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
strlen(c_title), c_title);
/* Set the title of the window icon */
xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId,
XCB_ATOM_WM_ICON_NAME, XCB_ATOM_STRING, 8,
strlen(c_title), c_title);
/* Initialize context */
xcb_map_window(m_xcbConn, m_windowId);
xcb_flush(m_xcbConn);
m_gfxCtx->initializeContext();
}
~CWindowXCB()
{
IApplicationInstance()->_deletedWindow(this);
}
void setCallback(IWindowCallback* cb)
{
m_callback = cb;
}
void showWindow()
{
xcb_map_window(m_xcbConn, m_windowId);
xcb_flush(m_xcbConn);
}
void hideWindow()
{
xcb_unmap_window(m_xcbConn, m_windowId);
xcb_flush(m_xcbConn);
}
std::string getTitle()
{
xcb_get_property_cookie_t cookie =
xcb_get_property(m_xcbConn, 0, m_windowId, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 64);
xcb_get_property_reply_t* reply =
xcb_get_property_reply(m_xcbConn, cookie, NULL);
std::string retval((const char*)xcb_get_property_value(reply));
free(reply);
return retval;
}
void setTitle(const std::string& title)
{
const char* c_title = title.c_str();
xcb_change_property(m_xcbConn, XCB_PROP_MODE_REPLACE, m_windowId,
XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
strlen(c_title), c_title);
}
void setWindowFrameDefault()
{
int x, y, w, h;
xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(m_xcbConn)).data;
genFrameDefault(screen, &x, &y, &w, &h);
uint32_t values[] = {(uint32_t)x, (uint32_t)y, (uint32_t)w, (uint32_t)h};
xcb_configure_window(m_xcbConn, m_windowId,
XCB_CONFIG_WINDOW_X |
XCB_CONFIG_WINDOW_Y |
XCB_CONFIG_WINDOW_WIDTH |
XCB_CONFIG_WINDOW_HEIGHT,
values);
}
void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const
{
xOut = m_wx;
yOut = m_wy;
wOut = m_ww;
hOut = m_wh;
}
void setWindowFrame(float x, float y, float w, float h)
{
uint32_t values[] = {(uint32_t)x, (uint32_t)y, (uint32_t)w, (uint32_t)h};
xcb_configure_window(m_xcbConn, m_windowId,
XCB_CONFIG_WINDOW_X |
XCB_CONFIG_WINDOW_Y |
XCB_CONFIG_WINDOW_WIDTH |
XCB_CONFIG_WINDOW_HEIGHT,
values);
}
float getVirtualPixelFactor() const
{
return m_pixelFactor;
}
bool isFullscreen() const
{
xcb_get_property_cookie_t cookie =
xcb_get_property(m_xcbConn, 0, m_windowId, S_ATOMS->m_netwmState, XCB_ATOM_ATOM, 0, 32);
xcb_get_property_reply_t* reply =
xcb_get_property_reply(m_xcbConn, cookie, NULL);
char* props = (char*)xcb_get_property_value(reply);
char fullscreen = false;
for (unsigned i=0 ; i<reply->length/4 ; ++i)
{
if ((xcb_atom_t)props[i] == S_ATOMS->m_netwmStateFullscreen)
{
fullscreen = true;
break;
}
}
free(reply);
return fullscreen;
}
void setFullscreen(bool fs)
{
xcb_client_message_event_t fsEvent =
{
XCB_CLIENT_MESSAGE,
32,
0,
m_windowId,
S_ATOMS->m_netwmState,
{}
};
fsEvent.data.data32[0] = fs ? S_ATOMS->m_netwmStateAdd : S_ATOMS->m_netwmStateRemove;
fsEvent.data.data32[1] = S_ATOMS->m_netwmStateFullscreen;
xcb_send_event(m_xcbConn, 0, m_windowId,
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
(const char*)&fsEvent);
}
uintptr_t getPlatformHandle() const
{
return (uintptr_t)m_windowId;
}
void _pointingDeviceChanged(xcb_input_device_id_t deviceId)
{
xcb_input_xi_query_device_reply_t* reply =
xcb_input_xi_query_device_reply(m_xcbConn, xcb_input_xi_query_device(m_xcbConn, deviceId), NULL);
xcb_input_xi_device_info_iterator_t infoIter = xcb_input_xi_query_device_infos_iterator(reply);
while (infoIter.rem)
{
/* First iterate classes for scrollables */
xcb_input_device_class_iterator_t classIter =
xcb_input_xi_device_info_classes_iterator(infoIter.data);
int hScroll = -1;
int vScroll = -1;
m_hScrollLast = 0.0;
m_vScrollLast = 0.0;
m_hScrollValuator = -1;
m_vScrollValuator = -1;
while (classIter.rem)
{
if (classIter.data->type == XCB_INPUT_DEVICE_CLASS_TYPE_SCROLL)
{
xcb_input_scroll_class_t* scrollClass = (xcb_input_scroll_class_t*)classIter.data;
if (scrollClass->scroll_type == XCB_INPUT_SCROLL_TYPE_VERTICAL)
vScroll = scrollClass->number;
else if (scrollClass->scroll_type == XCB_INPUT_SCROLL_TYPE_HORIZONTAL)
hScroll = scrollClass->number;
}
xcb_input_device_class_next(&classIter);
}
/* Next iterate for touch and scroll valuators */
classIter = xcb_input_xi_device_info_classes_iterator(infoIter.data);
while (classIter.rem)
{
if (classIter.data->type == XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR)
{
xcb_input_valuator_class_t* valClass = (xcb_input_valuator_class_t*)classIter.data;
if (valClass->number == vScroll)
{
m_vScrollLast = fp3232val(&valClass->value);
m_vScrollValuator = vScroll;
}
else if (valClass->number == hScroll)
{
m_hScrollLast = fp3232val(&valClass->value);
m_hScrollValuator = hScroll;
}
}
else if (classIter.data->type == XCB_INPUT_DEVICE_CLASS_TYPE_TOUCH)
{
xcb_input_touch_class_t* touchClass = (xcb_input_touch_class_t*)classIter.data;
if (touchClass->mode == XCB_INPUT_TOUCH_MODE_DIRECT)
m_touchType = TOUCH_DISPLAY;
else if (touchClass->mode == XCB_INPUT_TOUCH_MODE_DEPENDENT)
m_touchType = TOUCH_TRACKPAD;
else
m_touchType = TOUCH_NONE;
}
xcb_input_device_class_next(&classIter);
}
xcb_input_xi_device_info_next(&infoIter);
}
free(reply);
m_lastInputID = deviceId;
}
void _incomingEvent(void* e)
{
xcb_generic_event_t* event = (xcb_generic_event_t*)e;
switch (XCB_EVENT_RESPONSE_TYPE(event))
{
case XCB_EXPOSE:
{
xcb_expose_event_t* ev = (xcb_expose_event_t*)event;
m_wx = ev->x;
m_wy = ev->y;
m_ww = ev->width;
m_wh = ev->height;
return;
}
case XCB_CONFIGURE_NOTIFY:
{
xcb_configure_notify_event_t* ev = (xcb_configure_notify_event_t*)event;
if (ev->width && ev->height)
{
m_wx = ev->x;
m_wy = ev->y;
m_ww = ev->width;
m_wh = ev->height;
}
return;
}
case XCB_KEY_PRESS:
{
xcb_key_press_event_t* ev = (xcb_key_press_event_t*)event;
if (m_callback)
{
int specialKey;
int modifierKey;
wchar_t charCode = translateKeysym(xcb_key_press_lookup_keysym(S_ATOMS->m_keySyms, ev, 0),
specialKey, modifierKey);
int modifierMask = translateModifiers(ev->state);
if (charCode)
m_callback->charKeyDown(charCode,
(IWindowCallback::EModifierKey)modifierMask, false);
else if (specialKey)
m_callback->specialKeyDown((IWindowCallback::ESpecialKey)specialKey,
(IWindowCallback::EModifierKey)modifierMask, false);
else if (modifierKey)
m_callback->modKeyDown((IWindowCallback::EModifierKey)modifierKey, false);
}
return;
}
case XCB_KEY_RELEASE:
{
xcb_key_release_event_t* ev = (xcb_key_release_event_t*)event;
if (m_callback)
{
int specialKey;
int modifierKey;
wchar_t charCode = translateKeysym(xcb_key_release_lookup_keysym(S_ATOMS->m_keySyms, ev, 0),
specialKey, modifierKey);
int modifierMask = translateModifiers(ev->state);
if (charCode)
m_callback->charKeyUp(charCode,
(IWindowCallback::EModifierKey)modifierMask);
else if (specialKey)
m_callback->specialKeyUp((IWindowCallback::ESpecialKey)specialKey,
(IWindowCallback::EModifierKey)modifierMask);
else if (modifierKey)
m_callback->modKeyUp((IWindowCallback::EModifierKey)modifierKey);
}
return;
}
case XCB_BUTTON_PRESS:
{
xcb_button_press_event_t* ev = (xcb_button_press_event_t*)event;
if (m_callback)
{
int button = translateButton(ev->detail);
if (button)
{
int modifierMask = translateModifiers(ev->state);
IWindowCallback::SWindowCoord coord =
{
{(unsigned)ev->event_x, (unsigned)ev->event_y},
{(unsigned)(ev->event_x / m_pixelFactor), (unsigned)(ev->event_y / m_pixelFactor)},
{ev->event_x / (float)m_ww, ev->event_y / (float)m_wh}
};
m_callback->mouseDown(coord, (IWindowCallback::EMouseButton)button,
(IWindowCallback::EModifierKey)modifierMask);
}
/* Also handle legacy scroll events here */
if (ev->detail >= 4 && ev->detail <= 7 &&
m_hScrollValuator == -1 && m_vScrollValuator == -1)
{
IWindowCallback::SWindowCoord coord =
{
{(unsigned)ev->event_x, (unsigned)ev->event_y},
{(unsigned)(ev->event_x / m_pixelFactor), (unsigned)(ev->event_y / m_pixelFactor)},
{ev->event_x / (float)m_ww, ev->event_y / (float)m_wh}
};
IWindowCallback::SScrollDelta scrollDelta =
{
{0.0, 0.0},
false
};
if (ev->detail == 4)
scrollDelta.delta[1] = 1.0;
else if (ev->detail == 5)
scrollDelta.delta[1] = -1.0;
else if (ev->detail == 6)
scrollDelta.delta[0] = 1.0;
else if (ev->detail == 7)
scrollDelta.delta[0] = -1.0;
m_callback->scroll(coord, scrollDelta);
}
}
return;
}
case XCB_BUTTON_RELEASE:
{
xcb_button_release_event_t* ev = (xcb_button_release_event_t*)event;
if (m_callback)
{
int button = translateButton(ev->detail);
if (button)
{
int modifierMask = translateModifiers(ev->state);
IWindowCallback::SWindowCoord coord =
{
{(unsigned)ev->event_x, (unsigned)ev->event_y},
{(unsigned)(ev->event_x / m_pixelFactor), (unsigned)(ev->event_y / m_pixelFactor)},
{ev->event_x / (float)m_ww, ev->event_y / (float)m_wh}
};
m_callback->mouseUp(coord, (IWindowCallback::EMouseButton)button,
(IWindowCallback::EModifierKey)modifierMask);
}
}
return;
}
case XCB_MOTION_NOTIFY:
{
xcb_motion_notify_event_t* ev = (xcb_motion_notify_event_t*)event;
if (m_callback)
{
IWindowCallback::SWindowCoord coord =
{
{(unsigned)ev->event_x, (unsigned)ev->event_y},
{(unsigned)(ev->event_x / m_pixelFactor), (unsigned)(ev->event_y / m_pixelFactor)},
{ev->event_x / (float)m_ww, ev->event_y / (float)m_wh}
};
m_callback->mouseMove(coord);
}
return;
}
case XCB_GE_GENERIC:
{
xcb_ge_event_t* gev = (xcb_ge_event_t*)event;
if (gev->pad0 == XINPUT_OPCODE)
{
switch (gev->event_type)
{
case XCB_INPUT_MOTION:
{
xcb_input_motion_event_t* ev = (xcb_input_motion_event_t*)event;
if (m_lastInputID != ev->deviceid)
_pointingDeviceChanged(ev->deviceid);
uint32_t* valuators = (uint32_t*)(((char*)ev) + sizeof(xcb_input_motion_event_t) + sizeof(uint32_t) * ev->buttons_len);
xcb_input_fp3232_t* valuatorVals = (xcb_input_fp3232_t*)(((char*)valuators) + sizeof(uint32_t) * ev->valuators_len);
int cv = 0;
double newScroll[2] = {m_hScrollLast, m_vScrollLast};
bool didScroll = false;
for (int i=0 ; i<32 ; ++i)
{
if (valuators[0] & (1<<i))
{
if (i == m_hScrollValuator)
{
newScroll[0] = fp3232val(&valuatorVals[cv]);
didScroll = true;
}
else if (i == m_vScrollValuator)
{
newScroll[1] = fp3232val(&valuatorVals[cv]);
didScroll = true;
}
++cv;
}
}
IWindowCallback::SScrollDelta scrollDelta =
{
{newScroll[0] - m_hScrollLast, newScroll[1] - m_vScrollLast},
true
};
m_hScrollLast = newScroll[0];
m_vScrollLast = newScroll[1];
if (m_callback && didScroll)
{
unsigned event_x = ev->event_x >> 16;
unsigned event_y = ev->event_y >> 16;
IWindowCallback::SWindowCoord coord =
{
{event_x, event_y},
{(unsigned)(event_x / m_pixelFactor), (unsigned)(event_y / m_pixelFactor)},
{event_x / (float)m_ww, event_y / (float)m_wh}
};
m_callback->scroll(coord, scrollDelta);
}
return;
}
case XCB_INPUT_TOUCH_BEGIN:
{
xcb_input_touch_begin_event_t* ev = (xcb_input_touch_begin_event_t*)event;
if (m_lastInputID != ev->deviceid)
_pointingDeviceChanged(ev->deviceid);
uint32_t* valuators = (uint32_t*)(((char*)ev) + sizeof(xcb_input_motion_event_t) + sizeof(uint32_t) * ev->buttons_len);
xcb_input_fp3232_t* valuatorVals = (xcb_input_fp3232_t*)(((char*)valuators) + sizeof(uint32_t) * ev->valuators_len);
int cv = 0;
double vals[32] = {};
for (int i=0 ; i<32 ; ++i)
{
if (valuators[0] & (1<<i))
{
vals[i] = fp3232val(&valuatorVals[cv]);
++cv;
}
}
IWindowCallback::STouchCoord coord =
{
{vals[0], vals[1]}
};
if (m_callback)
m_callback->touchDown(coord, ev->detail);
return;
}
case XCB_INPUT_TOUCH_UPDATE:
{
xcb_input_touch_update_event_t* ev = (xcb_input_touch_update_event_t*)event;
if (m_lastInputID != ev->deviceid)
_pointingDeviceChanged(ev->deviceid);
uint32_t* valuators = (uint32_t*)(((char*)ev) + sizeof(xcb_input_motion_event_t) + sizeof(uint32_t) * ev->buttons_len);
xcb_input_fp3232_t* valuatorVals = (xcb_input_fp3232_t*)(((char*)valuators) + sizeof(uint32_t) * ev->valuators_len);
int cv = 0;
double vals[32] = {};
for (int i=0 ; i<32 ; ++i)
{
if (valuators[0] & (1<<i))
{
vals[i] = fp3232val(&valuatorVals[cv]);
++cv;
}
}
IWindowCallback::STouchCoord coord =
{
{vals[0], vals[1]}
};
if (m_callback)
m_callback->touchMove(coord, ev->detail);
return;
}
case XCB_INPUT_TOUCH_END:
{
xcb_input_touch_end_event_t* ev = (xcb_input_touch_end_event_t*)event;
if (m_lastInputID != ev->deviceid)
_pointingDeviceChanged(ev->deviceid);
uint32_t* valuators = (uint32_t*)(((char*)ev) + sizeof(xcb_input_motion_event_t) + sizeof(uint32_t) * ev->buttons_len);
xcb_input_fp3232_t* valuatorVals = (xcb_input_fp3232_t*)(((char*)valuators) + sizeof(uint32_t) * ev->valuators_len);
int cv = 0;
double vals[32] = {};
for (int i=0 ; i<32 ; ++i)
{
if (valuators[0] & (1<<i))
{
vals[i] = fp3232val(&valuatorVals[cv]);
++cv;
}
}
IWindowCallback::STouchCoord coord =
{
{vals[0], vals[1]}
};
if (m_callback)
m_callback->touchUp(coord, ev->detail);
return;
}
}
}
}
}
}
ETouchType getTouchType() const
{
return m_touchType;
}
};
IWindow* _CWindowXCBNew(const std::string& title, xcb_connection_t* conn)
{
return new CWindowXCB(title, conn);
}
}

147
test/main.cpp Normal file
View File

@ -0,0 +1,147 @@
#include <stdio.h>
#include <boo.hpp>
namespace boo
{
class CDolphinSmashAdapterCallback : public IDolphinSmashAdapterCallback
{
void controllerConnected(unsigned idx, EDolphinControllerType)
{
printf("CONTROLLER %u CONNECTED\n", idx);
}
void controllerDisconnected(unsigned idx, EDolphinControllerType)
{
printf("CONTROLLER %u DISCONNECTED\n", idx);
}
void controllerUpdate(unsigned idx, EDolphinControllerType,
const SDolphinControllerState& state)
{
printf("CONTROLLER %u UPDATE %d %d\n", idx, state.m_leftStick[0], state.m_leftStick[1]);
}
};
class CTestDeviceFinder : public CDeviceFinder
{
CDolphinSmashAdapter* smashAdapter = NULL;
CDolphinSmashAdapterCallback m_cb;
public:
CTestDeviceFinder()
: CDeviceFinder({typeid(CDolphinSmashAdapter)})
{}
void deviceConnected(CDeviceToken& tok)
{
smashAdapter = dynamic_cast<CDolphinSmashAdapter*>(tok.openAndGetDevice());
smashAdapter->setCallback(&m_cb);
smashAdapter->startRumble(0);
}
void deviceDisconnected(CDeviceToken&, CDeviceBase* device)
{
if (smashAdapter == device)
{
delete smashAdapter;
smashAdapter = NULL;
}
}
};
struct CTestWindowCallback : public IWindowCallback
{
void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods)
{
fprintf(stderr, "Mouse Down %d (%f,%f)\n", button, coord.norm[0], coord.norm[1]);
}
void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods)
{
fprintf(stderr, "Mouse Up %d (%f,%f)\n", button, coord.norm[0], coord.norm[1]);
}
void mouseMove(const SWindowCoord& coord)
{
//fprintf(stderr, "Mouse Move (%f,%f)\n", coord.norm[0], coord.norm[1]);
}
void scroll(const SWindowCoord& coord, const SScrollDelta& scroll)
{
fprintf(stderr, "Mouse Scroll (%f,%f) (%f,%f)\n", coord.norm[0], coord.norm[1], scroll.delta[0], scroll.delta[1]);
}
void touchDown(const STouchCoord& coord, uintptr_t tid)
{
//fprintf(stderr, "Touch Down %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]);
}
void touchUp(const STouchCoord& coord, uintptr_t tid)
{
//fprintf(stderr, "Touch Up %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]);
}
void touchMove(const STouchCoord& coord, uintptr_t tid)
{
//fprintf(stderr, "Touch Move %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]);
}
void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat)
{
}
void charKeyUp(unsigned long charCode, EModifierKey mods)
{
}
void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat)
{
}
void specialKeyUp(ESpecialKey key, EModifierKey mods)
{
}
void modKeyDown(EModifierKey mod, bool isRepeat)
{
}
void modKeyUp(EModifierKey mod)
{
}
};
struct CTestApplicationCallback : public IApplicationCallback
{
IWindow* mainWindow = NULL;
boo::CTestDeviceFinder devFinder;
CTestWindowCallback windowCallback;
void appLaunched(IApplication* app)
{
mainWindow = app->newWindow("YAY!");
mainWindow->setCallback(&windowCallback);
mainWindow->showWindow();
devFinder.startScanning();
}
void appQuitting(IApplication*)
{
delete mainWindow;
}
void appFilesOpen(IApplication*, const std::vector<const std::string>& paths)
{
fprintf(stderr, "OPENING: ");
for (const std::string& path : paths)
fprintf(stderr, "%s ", path.c_str());
fprintf(stderr, "\n");
}
};
}
int main(int argc, char** argv)
{
boo::CTestApplicationCallback appCb;
boo::IApplication* app = IApplicationBootstrap(boo::IApplication::PLAT_AUTO,
appCb, "rwk", "RWK", argc, argv);
app->run();
delete app;
printf("IM DYING!!\n");
return 0;
}