diff --git a/include/IApplication.hpp b/include/IApplication.hpp new file mode 100644 index 0000000..882afe5 --- /dev/null +++ b/include/IApplication.hpp @@ -0,0 +1,85 @@ +#ifndef IRUNLOOP_HPP +#define IRUNLOOP_HPP + +#include +#include + +#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& 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& 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& 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 args; + for (int i=1 ; i - -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 diff --git a/include/IInputWaiter.hpp b/include/IInputWaiter.hpp deleted file mode 100644 index 552a2d8..0000000 --- a/include/IInputWaiter.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef IINPUTWAITER_HPP -#define IINPUTWAITER_HPP - -namespace boo -{ - -class IInputWaiter -{ - -}; - -} - -#endif // IINPUTWAITER_HPP diff --git a/include/IRetraceWaiter.hpp b/include/IRetraceWaiter.hpp deleted file mode 100644 index aacd34f..0000000 --- a/include/IRetraceWaiter.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef IRETRACEWAITER_HPP -#define IRETRACEWAITER_HPP - -namespace boo -{ - -class IRetraceWaiter -{ - -}; - -} - -#endif // IRETRACEWAITER_HPP diff --git a/include/ISurface.hpp b/include/ISurface.hpp deleted file mode 100644 index 6f2f13d..0000000 --- a/include/ISurface.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef ISURFACE_HPP -#define ISURFACE_HPP - -namespace boo -{ - -class ISurface -{ -public: - -}; - -} - -#endif // CSURFACE_HPP diff --git a/include/boo.hpp b/include/boo.hpp index c407f9e..c2a5e6f 100644 --- a/include/boo.hpp +++ b/include/boo.hpp @@ -1,21 +1,8 @@ #ifndef BOO_HPP #define BOO_HPP -#if defined(_WIN32) -#include "win/CWGLContext.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 "IApplication.hpp" +#include "windowsys/IWindow.hpp" #include "inputdev/CDeviceFinder.hpp" #include "inputdev/CDolphinSmashAdapter.hpp" diff --git a/include/graphicsys/CGFXVertexLayoutBase.hpp b/include/graphicsys/CGFXVertexLayoutBase.hpp new file mode 100644 index 0000000..a8ff1c4 --- /dev/null +++ b/include/graphicsys/CGFXVertexLayoutBase.hpp @@ -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 diff --git a/include/graphicsys/IGFXCommandBuffer.hpp b/include/graphicsys/IGFXCommandBuffer.hpp new file mode 100644 index 0000000..fc29bda --- /dev/null +++ b/include/graphicsys/IGFXCommandBuffer.hpp @@ -0,0 +1,5 @@ +#ifndef IGFXCOMMANDBUFFER_HPP +#define IGFXCOMMANDBUFFER_HPP + +#endif // IGFXCOMMANDBUFFER_HPP + diff --git a/include/graphicsys/IGFXContext.hpp b/include/graphicsys/IGFXContext.hpp new file mode 100644 index 0000000..94f3804 --- /dev/null +++ b/include/graphicsys/IGFXContext.hpp @@ -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 diff --git a/include/graphicsys/IGFXPipelineState.hpp b/include/graphicsys/IGFXPipelineState.hpp new file mode 100644 index 0000000..9792d97 --- /dev/null +++ b/include/graphicsys/IGFXPipelineState.hpp @@ -0,0 +1,5 @@ +#ifndef IGFXPIPELINESTATE_HPP +#define IGFXPIPELINESTATE_HPP + +#endif // IGFXPIPELINESTATE_HPP + diff --git a/include/graphicsys/IGFXTransformSet.hpp b/include/graphicsys/IGFXTransformSet.hpp new file mode 100644 index 0000000..ef66cb5 --- /dev/null +++ b/include/graphicsys/IGFXTransformSet.hpp @@ -0,0 +1,5 @@ +#ifndef IGFXTRANSFORMSET_HPP +#define IGFXTRANSFORMSET_HPP + +#endif // IGFXTRANSFORMSET_HPP + diff --git a/include/graphicsys/hecl/CHECLLexer.hpp b/include/graphicsys/hecl/CHECLLexer.hpp new file mode 100644 index 0000000..9c3b0e7 --- /dev/null +++ b/include/graphicsys/hecl/CHECLLexer.hpp @@ -0,0 +1,20 @@ +#ifndef CHECLLEXER_HPP +#define CHECLLEXER_HPP + +#include +#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 diff --git a/include/graphicsys/hecl/HECLExpressions.hpp b/include/graphicsys/hecl/HECLExpressions.hpp new file mode 100644 index 0000000..454d0d7 --- /dev/null +++ b/include/graphicsys/hecl/HECLExpressions.hpp @@ -0,0 +1,46 @@ +#ifndef HECLEXPRESSIONS_HPP +#define HECLEXPRESSIONS_HPP + +#include +#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 diff --git a/include/graphicsys/hecl/IHECLBackend.hpp b/include/graphicsys/hecl/IHECLBackend.hpp new file mode 100644 index 0000000..4585adc --- /dev/null +++ b/include/graphicsys/hecl/IHECLBackend.hpp @@ -0,0 +1,76 @@ +#ifndef IHECLBACKEND_HPP +#define IHECLBACKEND_HPP + +#include +#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 diff --git a/include/inputdev/DeviceBase.hpp b/include/inputdev/DeviceBase.hpp index 392802f..053258e 100644 --- a/include/inputdev/DeviceBase.hpp +++ b/include/inputdev/DeviceBase.hpp @@ -27,15 +27,15 @@ public: virtual void deviceError(const char* error) {fprintf(stderr, "%s\n", error);} /* Low-Level API */ - bool sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length); - size_t receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length); + bool sendUSBInterruptTransfer(const uint8_t* data, size_t length); + size_t receiveUSBInterruptTransfer(uint8_t* data, size_t length); virtual void initialCycle() {} virtual void transferCycle() {} virtual void finalCycle() {} /* High-Level API */ 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;} }; diff --git a/include/inputdev/DeviceFinder.hpp b/include/inputdev/DeviceFinder.hpp index 30b768d..8e328db 100644 --- a/include/inputdev/DeviceFinder.hpp +++ b/include/inputdev/DeviceFinder.hpp @@ -1,7 +1,8 @@ #ifndef CDEVICEFINDER_HPP #define CDEVICEFINDER_HPP -#include +#include +#include #include #include "DeviceToken.hpp" #include "IHIDListener.hpp" @@ -91,7 +92,7 @@ public: }; /* Application must specify its interested device-types */ - CDeviceFinder(std::vector types) + CDeviceFinder(std::unordered_set types) : m_listener(NULL) { if (skDevFinder) @@ -100,12 +101,12 @@ public: abort(); } skDevFinder = this; - for (const char* typeName : types) + for (const std::type_index& typeIdx : types) { const SDeviceSignature* sigIter = BOO_DEVICE_SIGS; while (sigIter->m_name) { - if (!strcmp(sigIter->m_name, typeName)) + if (sigIter->m_typeIdx == typeIdx) m_types.push_back(sigIter); ++sigIter; } diff --git a/include/inputdev/DeviceSignature.hpp b/include/inputdev/DeviceSignature.hpp index 80708b9..7c89d62 100644 --- a/include/inputdev/DeviceSignature.hpp +++ b/include/inputdev/DeviceSignature.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace boo { @@ -15,17 +16,18 @@ struct SDeviceSignature typedef std::vector TDeviceSignatureSet; typedef std::function TFactoryLambda; const char* m_name; + std::type_index m_typeIdx; unsigned m_vid, m_pid; TFactoryLambda m_factory; - SDeviceSignature() : m_name(NULL) {} /* Sentinel constructor */ - SDeviceSignature(const char* name, unsigned vid, unsigned pid, TFactoryLambda&& factory) - : m_name(name), m_vid(vid), m_pid(pid), m_factory(factory) {} + SDeviceSignature() : m_name(NULL), m_typeIdx(typeid(SDeviceSignature)) {} /* Sentinel constructor */ + SDeviceSignature(const char* name, std::type_index&& typeIdx, unsigned vid, unsigned pid, TFactoryLambda&& 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 CDeviceBase* DeviceNew(CDeviceToken& token); }; #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() extern const SDeviceSignature BOO_DEVICE_SIGS[]; diff --git a/include/inputdev/DolphinSmashAdapter.hpp b/include/inputdev/DolphinSmashAdapter.hpp index 4ea14c6..bd6a420 100644 --- a/include/inputdev/DolphinSmashAdapter.hpp +++ b/include/inputdev/DolphinSmashAdapter.hpp @@ -40,10 +40,10 @@ struct SDolphinControllerState struct IDolphinSmashAdapterCallback { - virtual void controllerConnected(unsigned idx, EDolphinControllerType type) {} - virtual void controllerDisconnected(unsigned idx, EDolphinControllerType type) {} + virtual void controllerConnected(unsigned idx, EDolphinControllerType type) {(void)idx;(void)type;} + virtual void controllerDisconnected(unsigned idx, EDolphinControllerType type) {(void)idx;(void)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 diff --git a/include/windowsys/IWindow.hpp b/include/windowsys/IWindow.hpp new file mode 100644 index 0000000..6418f87 --- /dev/null +++ b/include/windowsys/IWindow.hpp @@ -0,0 +1,146 @@ +#ifndef IWINDOW_HPP +#define IWINDOW_HPP + +#include + +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 diff --git a/lib/inputdev/DeviceBase.cpp b/lib/inputdev/DeviceBase.cpp index ef803dc..82132bf 100644 --- a/lib/inputdev/DeviceBase.cpp +++ b/lib/inputdev/DeviceBase.cpp @@ -33,17 +33,17 @@ void CDeviceBase::closeDevice() 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) - return m_hidDev->_sendUSBInterruptTransfer(pipe, data, length); + return m_hidDev->_sendUSBInterruptTransfer(data, length); 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) - return m_hidDev->_receiveUSBInterruptTransfer(pipe, data, length); + return m_hidDev->_receiveUSBInterruptTransfer(data, length); return false; } diff --git a/lib/inputdev/DolphinSmashAdapter.cpp b/lib/inputdev/DolphinSmashAdapter.cpp index 07276f9..06ed00b 100644 --- a/lib/inputdev/DolphinSmashAdapter.cpp +++ b/lib/inputdev/DolphinSmashAdapter.cpp @@ -59,13 +59,13 @@ parseState(SDolphinControllerState* stateOut, uint8_t* payload, bool& rumble) void CDolphinSmashAdapter::initialCycle() { uint8_t handshakePayload[] = {0x13}; - sendUSBInterruptTransfer(0, handshakePayload, sizeof(handshakePayload)); + sendUSBInterruptTransfer(handshakePayload, sizeof(handshakePayload)); } void CDolphinSmashAdapter::transferCycle() { 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) return; //printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]); @@ -108,7 +108,7 @@ void CDolphinSmashAdapter::transferCycle() else rumbleMessage[i+1] = 0; } - sendUSBInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage)); + sendUSBInterruptTransfer(rumbleMessage, sizeof(rumbleMessage)); m_rumbleState = rumbleReq; } } @@ -116,7 +116,7 @@ void CDolphinSmashAdapter::transferCycle() void CDolphinSmashAdapter::finalCycle() { uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0}; - sendUSBInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage)); + sendUSBInterruptTransfer(rumbleMessage, sizeof(rumbleMessage)); } void CDolphinSmashAdapter::deviceDisconnected() diff --git a/lib/inputdev/HIDDeviceIOKit.cpp b/lib/inputdev/HIDDeviceIOKit.cpp index 95b115a..2b7798c 100644 --- a/lib/inputdev/HIDDeviceIOKit.cpp +++ b/lib/inputdev/HIDDeviceIOKit.cpp @@ -24,7 +24,7 @@ class CHIDDeviceIOKit final : public IHIDDevice std::condition_variable m_initCond; 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) { @@ -34,7 +34,7 @@ class CHIDDeviceIOKit final : public IHIDDevice 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) { diff --git a/lib/inputdev/HIDDeviceUdev.cpp b/lib/inputdev/HIDDeviceUdev.cpp index 4978423..c724c81 100644 --- a/lib/inputdev/HIDDeviceUdev.cpp +++ b/lib/inputdev/HIDDeviceUdev.cpp @@ -39,7 +39,7 @@ class CHIDDeviceUdev final : public IHIDDevice std::condition_variable m_initCond; 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) { @@ -58,7 +58,7 @@ class CHIDDeviceUdev final : public IHIDDevice 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) { @@ -94,22 +94,22 @@ class CHIDDeviceUdev final : public IHIDDevice udev_device_unref(udevDev); return; } - usb_device_descriptor devDesc = {0}; + usb_device_descriptor devDesc = {}; read(device->m_devFd, &devDesc, 1); read(device->m_devFd, &devDesc.bDescriptorType, devDesc.bLength-1); if (devDesc.bNumConfigurations) { - usb_config_descriptor confDesc = {0}; + usb_config_descriptor confDesc = {}; read(device->m_devFd, &confDesc, 1); read(device->m_devFd, &confDesc.bDescriptorType, confDesc.bLength-1); if (confDesc.bNumInterfaces) { - usb_interface_descriptor intfDesc = {0}; + usb_interface_descriptor intfDesc = {}; read(device->m_devFd, &intfDesc, 1); read(device->m_devFd, &intfDesc.bDescriptorType, intfDesc.bLength-1); for (i=0 ; im_devFd, &endpDesc, 1); read(device->m_devFd, &endpDesc.bDescriptorType, endpDesc.bLength-1); 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) { + (void)data; + (void)length; return false; } diff --git a/lib/inputdev/HIDDeviceWinUSB.cpp b/lib/inputdev/HIDDeviceWinUSB.cpp index d419140..b17c36a 100644 --- a/lib/inputdev/HIDDeviceWinUSB.cpp +++ b/lib/inputdev/HIDDeviceWinUSB.cpp @@ -33,7 +33,7 @@ class CHIDDeviceWinUSB final : public IHIDDevice std::condition_variable m_initCond; 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) { @@ -47,7 +47,7 @@ class CHIDDeviceWinUSB final : public IHIDDevice 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) { diff --git a/lib/inputdev/HIDListenerUdev.cpp b/lib/inputdev/HIDListenerUdev.cpp index aa4e851..91277ce 100644 --- a/lib/inputdev/HIDListenerUdev.cpp +++ b/lib/inputdev/HIDListenerUdev.cpp @@ -2,7 +2,11 @@ #include "inputdev/DeviceFinder.hpp" #include #include +<<<<<<< HEAD:lib/inputdev/HIDListenerUdev.cpp #include +======= +#include +>>>>>>> 6ce2472b27211a40e1d78f424f09cf26ba5e3281:src/inputdev/CHIDListenerUdev.cpp #include namespace boo @@ -169,6 +173,7 @@ public: ~CHIDListenerUdev() { m_udevRunning = false; + pthread_kill(m_udevThread->native_handle(), SIGINT); m_udevThread->join(); delete m_udevThread; udev_monitor_unref(m_udevMon); diff --git a/lib/inputdev/IHIDDevice.hpp b/lib/inputdev/IHIDDevice.hpp index 82b090a..ca9908c 100644 --- a/lib/inputdev/IHIDDevice.hpp +++ b/lib/inputdev/IHIDDevice.hpp @@ -10,8 +10,8 @@ class IHIDDevice { friend class CDeviceBase; virtual void _deviceDisconnected()=0; - virtual bool _sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length)=0; - virtual size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)=0; + virtual bool _sendUSBInterruptTransfer(const 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; public: inline virtual ~IHIDDevice() {} diff --git a/libBoo.pri b/libBoo.pri new file mode 100644 index 0000000..caf013e --- /dev/null +++ b/libBoo.pri @@ -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 + diff --git a/libBoo.pro b/libBoo.pro new file mode 100644 index 0000000..721b743 --- /dev/null +++ b/libBoo.pro @@ -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) diff --git a/src/CApplicationCocoa.mm b/src/CApplicationCocoa.mm new file mode 100644 index 0000000..9ebaa86 --- /dev/null +++ b/src/CApplicationCocoa.mm @@ -0,0 +1,182 @@ +#include + +#include "IApplication.hpp" + +@interface AppDelegate : NSObject +{ + 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 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& 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& 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& args) +{ + if (!APP) + { + if (platform != IApplication::PLAT_COCOA && + platform != IApplication::PLAT_AUTO) + return NULL; + APP = new CApplicationCocoa(cb, friendlyName, pname, args); + } + return APP; +} + +} diff --git a/src/CApplicationUnix.cpp b/src/CApplicationUnix.cpp new file mode 100644 index 0000000..faa0ab5 --- /dev/null +++ b/src/CApplicationUnix.cpp @@ -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 +#include + +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& 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; +} + +} diff --git a/src/CApplicationWayland.hpp b/src/CApplicationWayland.hpp new file mode 100644 index 0000000..54dd06a --- /dev/null +++ b/src/CApplicationWayland.hpp @@ -0,0 +1,85 @@ +#ifndef CAPPLICATION_UNIX_CPP +#error This file may only be included from CApplicationUnix.cpp +#endif + +#include "IApplication.hpp" + +#include +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 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& 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& getArgs() const + { + return m_args; + } + + IWindow* newWindow(const std::string& title) + { + return _CWindowWaylandNew(title); + } +}; + +} diff --git a/src/CApplicationWin32.cpp b/src/CApplicationWin32.cpp new file mode 100644 index 0000000..ba53335 --- /dev/null +++ b/src/CApplicationWin32.cpp @@ -0,0 +1,166 @@ +#define _CRT_SECURE_NO_WARNINGS 1 /* STFU MSVC */ +#define _WIN32_LEAN_AND_MEAN 1 +#include +#include +#include + +#include + +#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 m_args; + std::unordered_map 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& 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& 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& 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); + +} diff --git a/src/CApplicationXCB.hpp b/src/CApplicationXCB.hpp new file mode 100644 index 0000000..38a0363 --- /dev/null +++ b/src/CApplicationXCB.hpp @@ -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 +#include +#include +#include +#include +#undef explicit + +#include +DBusConnection* registerDBus(const char* appName, bool& isFirst); + +#include + +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 m_args; + + /* DBus single-instance */ + bool m_singleInstance; + DBusConnection* m_dbus = NULL; + + /* All windows */ + std::unordered_map 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& 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 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& 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; + } +}; + +} diff --git a/src/graphicsys/CGraphicsContextCocoa.mm b/src/graphicsys/CGraphicsContextCocoa.mm new file mode 100644 index 0000000..ef61ad1 --- /dev/null +++ b/src/graphicsys/CGraphicsContextCocoa.mm @@ -0,0 +1,639 @@ +#import +#include +#include +#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(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 + diff --git a/src/graphicsys/CGraphicsContextWayland.cpp b/src/graphicsys/CGraphicsContextWayland.cpp new file mode 100644 index 0000000..056faea --- /dev/null +++ b/src/graphicsys/CGraphicsContextWayland.cpp @@ -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); +} + +} diff --git a/src/graphicsys/CGraphicsContextWin32.cpp b/src/graphicsys/CGraphicsContextWin32.cpp new file mode 100644 index 0000000..26436e9 --- /dev/null +++ b/src/graphicsys/CGraphicsContextWin32.cpp @@ -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) +{ + +} + +} diff --git a/src/graphicsys/CGraphicsContextXCB.cpp b/src/graphicsys/CGraphicsContextXCB.cpp new file mode 100644 index 0000000..f18b75f --- /dev/null +++ b/src/graphicsys/CGraphicsContextXCB.cpp @@ -0,0 +1,153 @@ +#include "graphicsys/IGFXContext.hpp" +#include "windowsys/IWindow.hpp" + +#include +#include +#include +#include +#include +#include +#include + +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 ; inum_FB_configs ; ++i) + { + struct conf_prop* configProps = &props[fbconfigs->num_properties * i]; + uint32_t fbconfId, visualId, depthSize, colorSize, doubleBuffer; + for (uint32_t j=0 ; jnum_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); +} + +} diff --git a/src/graphicsys/hecl/CHECLBackendGLSL.cpp b/src/graphicsys/hecl/CHECLBackendGLSL.cpp new file mode 100644 index 0000000..a3ce619 --- /dev/null +++ b/src/graphicsys/hecl/CHECLBackendGLSL.cpp @@ -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); +} + diff --git a/src/graphicsys/hecl/CHECLBackendHLSL.cpp b/src/graphicsys/hecl/CHECLBackendHLSL.cpp new file mode 100644 index 0000000..14c9a4b --- /dev/null +++ b/src/graphicsys/hecl/CHECLBackendHLSL.cpp @@ -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); +} diff --git a/src/graphicsys/hecl/CHECLBackendMetal.cpp b/src/graphicsys/hecl/CHECLBackendMetal.cpp new file mode 100644 index 0000000..cf69b17 --- /dev/null +++ b/src/graphicsys/hecl/CHECLBackendMetal.cpp @@ -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); +} diff --git a/src/graphicsys/hecl/CHECLBackendOutline.cpp b/src/graphicsys/hecl/CHECLBackendOutline.cpp new file mode 100644 index 0000000..ac6536b --- /dev/null +++ b/src/graphicsys/hecl/CHECLBackendOutline.cpp @@ -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); +} + diff --git a/src/graphicsys/hecl/CHECLBackendTEV.cpp b/src/graphicsys/hecl/CHECLBackendTEV.cpp new file mode 100644 index 0000000..f4565df --- /dev/null +++ b/src/graphicsys/hecl/CHECLBackendTEV.cpp @@ -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); +} diff --git a/src/graphicsys/hecl/CHECLLexer.cpp b/src/graphicsys/hecl/CHECLLexer.cpp new file mode 100644 index 0000000..56ba45b --- /dev/null +++ b/src/graphicsys/hecl/CHECLLexer.cpp @@ -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) +{ +} diff --git a/src/windowsys/CWindowCocoa.mm b/src/windowsys/CWindowCocoa.mm new file mode 100644 index 0000000..942d9d2 --- /dev/null +++ b/src/windowsys/CWindowCocoa.mm @@ -0,0 +1,180 @@ +#import +#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 + diff --git a/src/windowsys/CWindowWayland.cpp b/src/windowsys/CWindowWayland.cpp new file mode 100644 index 0000000..c335d36 --- /dev/null +++ b/src/windowsys/CWindowWayland.cpp @@ -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); +} + +} diff --git a/src/windowsys/CWindowWin32.cpp b/src/windowsys/CWindowWin32.cpp new file mode 100644 index 0000000..5617358 --- /dev/null +++ b/src/windowsys/CWindowWin32.cpp @@ -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); +} + +} diff --git a/src/windowsys/CWindowXCB.cpp b/src/windowsys/CWindowXCB.cpp new file mode 100644 index 0000000..9507c9d --- /dev/null +++ b/src/windowsys/CWindowXCB.cpp @@ -0,0 +1,769 @@ +#include "windowsys/IWindow.hpp" +#include "graphicsys/IGFXContext.hpp" +#include "IApplication.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define XK_MISCELLANY +#define XK_XKB_KEYS +#define XK_LATIN1 +#include + +#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 ; ilength/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<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<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<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<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); +} + +} diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 0000000..f00112c --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,147 @@ +#include +#include + +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(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& 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; +} +