diff --git a/Aerofoil/Aerofoil.vcxproj b/Aerofoil/Aerofoil.vcxproj index 39256f0..2392627 100644 --- a/Aerofoil/Aerofoil.vcxproj +++ b/Aerofoil/Aerofoil.vcxproj @@ -82,6 +82,7 @@ + @@ -106,10 +107,10 @@ + - diff --git a/Aerofoil/Aerofoil.vcxproj.filters b/Aerofoil/Aerofoil.vcxproj.filters index 3570943..1648a84 100644 --- a/Aerofoil/Aerofoil.vcxproj.filters +++ b/Aerofoil/Aerofoil.vcxproj.filters @@ -31,6 +31,9 @@ Source Files + + Source Files + @@ -57,9 +60,6 @@ Header Files - - Header Files - Header Files @@ -96,6 +96,9 @@ Header Files + + Header Files + diff --git a/Aerofoil/GpBWCursor_Win32.cpp b/Aerofoil/GpBWCursor_Win32.cpp new file mode 100644 index 0000000..da4a07e --- /dev/null +++ b/Aerofoil/GpBWCursor_Win32.cpp @@ -0,0 +1,110 @@ +/* + Portions of this file based on Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "GpBWCursor_Win32.h" +#include "GpWindows.h" + +#include +#include +#include +#include + +extern GpWindowsGlobals g_gpWindowsGlobals; + +void GpBWCursor_Win32::Destroy() +{ + this->DecRef(); +} + +IGpCursor_Win32 *GpBWCursor_Win32::Create(size_t width, size_t height, const void *pixelData, const void *maskData, size_t hotSpotX, size_t hotSpotY) +{ + size_t numBits = width * height; + size_t numBytes = (width * height + 7) / 8; + uint8_t *convertedAndData = static_cast(malloc(numBytes)); + uint8_t *convertedXorData = static_cast(malloc(numBytes)); + + if (!convertedAndData || !convertedXorData) + { + if (convertedAndData) + free(convertedAndData); + if (convertedXorData) + free(convertedXorData); + + return nullptr; + } + + for (size_t i = 0; i < numBytes; i++) + { + // MacPx0 MacPx1 + // MacMask0 1a 0x 1a 1x + // MacMask1 0a 1x 0a 0x + convertedAndData[i] = static_cast(maskData)[i] ^ 0xff; + convertedXorData[i] = static_cast(maskData)[i] ^ static_cast(pixelData)[i]; + } + + HCURSOR hcursor = CreateCursor(g_gpWindowsGlobals.m_hInstance, static_cast(hotSpotX), static_cast(hotSpotY), static_cast(width), static_cast(height), convertedAndData, convertedXorData); + + free(convertedAndData); + free(convertedXorData); + + if (!hcursor) + return nullptr; + + void *storage = malloc(sizeof(GpBWCursor_Win32)); + if (!storage) + { + DestroyCursor(hcursor); + return nullptr; + } + + return new (storage) GpBWCursor_Win32(hcursor); +} + +GpBWCursor_Win32::GpBWCursor_Win32(HCURSOR cursor) + : m_cursor(cursor) + , m_refCount(1) +{ +} + +GpBWCursor_Win32::~GpBWCursor_Win32() +{ + DestroyCursor(m_cursor); +} + +const HCURSOR &GpBWCursor_Win32::GetHCursor() const +{ + return m_cursor; +} + +void GpBWCursor_Win32::IncRef() +{ + m_refCount++; +} + +void GpBWCursor_Win32::DecRef() +{ + m_refCount--; + if (m_refCount == 0) + { + this->~GpBWCursor_Win32(); + free(this); + } +} diff --git a/Aerofoil/GpBWCursor_Win32.h b/Aerofoil/GpBWCursor_Win32.h new file mode 100644 index 0000000..070bb7b --- /dev/null +++ b/Aerofoil/GpBWCursor_Win32.h @@ -0,0 +1,24 @@ +#pragma once + +#include "IGpCursor_Win32.h" +#include "GpWindows.h" + +class GpBWCursor_Win32 final : public IGpCursor_Win32 +{ +public: + void Destroy() override; + + const HCURSOR &GetHCursor() const override; + + void IncRef() override; + void DecRef() override; + + static IGpCursor_Win32 *Create(size_t width, size_t height, const void *pixelData, const void *maskData, size_t hotSpotX, size_t hotSpotY); + +private: + GpBWCursor_Win32(HCURSOR cursor); + ~GpBWCursor_Win32(); + + HCURSOR m_cursor; + int m_refCount; +}; diff --git a/Aerofoil/GpColorCursor_Win32.cpp b/Aerofoil/GpColorCursor_Win32.cpp index 59972e7..5dbfd84 100644 --- a/Aerofoil/GpColorCursor_Win32.cpp +++ b/Aerofoil/GpColorCursor_Win32.cpp @@ -1,58 +1,132 @@ -#include "GpCursor_Win32.h" +/* + Portions of this file based on Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "GpColorCursor_Win32.h" + +#include #include #include +#include -void GpCursor_Win32::Destroy() +void GpColorCursor_Win32::Destroy() { this->DecRef(); } -IGpCursor_Win32 *GpCursor_Win32::Load(const wchar_t *path) +IGpCursor_Win32 *GpColorCursor_Win32::Create(size_t width, size_t height, const void *pixelDataRGBA, size_t hotSpotX, size_t hotSpotY) { - HANDLE imageH = LoadImageW(nullptr, path, IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE); + const size_t paddingBits = (sizeof(void*) * 8); - if (imageH == nullptr) + BITMAPV4HEADER bmp; + + memset(&bmp, 0, sizeof(bmp)); + bmp.bV4Size = sizeof(bmp); + bmp.bV4Width = width; + bmp.bV4Height = -static_cast(height); + bmp.bV4Planes = 1; + bmp.bV4BitCount = 32; + bmp.bV4V4Compression = BI_BITFIELDS; + bmp.bV4AlphaMask = 0xFF000000; + bmp.bV4RedMask = 0x00FF0000; + bmp.bV4GreenMask = 0x0000FF00; + bmp.bV4BlueMask = 0x000000FF; + + size_t maskPitch = width + paddingBits - 1; + maskPitch -= maskPitch % paddingBits; + + LPVOID maskBits = malloc(maskPitch * height); + if (!maskBits) return nullptr; - HCURSOR cursor = reinterpret_cast(imageH); - void *storage = malloc(sizeof(GpCursor_Win32)); + memset(maskBits, 0xff, maskPitch * height); + + HDC hdc = GetDC(NULL); + + LPVOID pixels; + + ICONINFO ii; + memset(&ii, 0, sizeof(ii)); + ii.fIcon = FALSE; + ii.xHotspot = (DWORD)hotSpotX; + ii.yHotspot = (DWORD)hotSpotY; + ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO*)&bmp, DIB_RGB_COLORS, &pixels, NULL, 0); + ii.hbmMask = CreateBitmap(width, height, 1, 1, maskBits); + ReleaseDC(NULL, hdc); + + size_t cursorPitch = width * 4; + + size_t numPixels = width * height; + memcpy(pixels, pixelDataRGBA, numPixels * 4); + + for (size_t i = 0; i < numPixels; i++) + { + uint8_t *pixel = static_cast(pixels) + i * 4; + std::swap(pixel[0], pixel[2]); + } + + HICON hicon = CreateIconIndirect(&ii); + + DeleteObject(ii.hbmColor); + DeleteObject(ii.hbmMask); + + if (!hicon) + return nullptr; + + void *storage = malloc(sizeof(GpColorCursor_Win32)); if (!storage) { - DestroyCursor(cursor); + DestroyIcon(hicon); return nullptr; } - return new (storage) GpCursor_Win32(reinterpret_cast(cursor)); + return new (storage) GpColorCursor_Win32(reinterpret_cast(hicon)); } -GpCursor_Win32::GpCursor_Win32(HCURSOR cursor) +GpColorCursor_Win32::GpColorCursor_Win32(HCURSOR cursor) : m_cursor(cursor) , m_refCount(1) { } -GpCursor_Win32::~GpCursor_Win32() +GpColorCursor_Win32::~GpColorCursor_Win32() { - DestroyCursor(m_cursor); + DestroyIcon(m_cursor); } -const HCURSOR &GpCursor_Win32::GetHCursor() const +const HCURSOR &GpColorCursor_Win32::GetHCursor() const { return m_cursor; } -void GpCursor_Win32::IncRef() +void GpColorCursor_Win32::IncRef() { m_refCount++; } -void GpCursor_Win32::DecRef() +void GpColorCursor_Win32::DecRef() { m_refCount--; if (m_refCount == 0) { - this->~GpCursor_Win32(); + this->~GpColorCursor_Win32(); free(this); } } diff --git a/Aerofoil/GpColorCursor_Win32.h b/Aerofoil/GpColorCursor_Win32.h index 378e2b1..a451ea2 100644 --- a/Aerofoil/GpColorCursor_Win32.h +++ b/Aerofoil/GpColorCursor_Win32.h @@ -1,18 +1,10 @@ #pragma once -#include "IGpColorCursor.h" +#include "IGpCursor_Win32.h" #include "GpWindows.h" -struct IGpColorCursor_Win32 : public IGpColorCursor -{ - virtual const HCURSOR &GetHCursor() const = 0; - virtual void IncRef() = 0; - virtual void DecRef() = 0; -}; - - -class GpColorCursor_Win32 final : public IGpColorCursor_Win32 +class GpColorCursor_Win32 final : public IGpCursor_Win32 { public: void Destroy() override; @@ -22,7 +14,7 @@ public: void IncRef() override; void DecRef() override; - static IGpColorCursor_Win32 *Load(const wchar_t *path); + static IGpCursor_Win32 *Create(size_t width, size_t height, const void *pixelDataRGBA, size_t hotSpotX, size_t hotSpotY); private: GpColorCursor_Win32(HCURSOR cursor); diff --git a/Aerofoil/GpCursor_Win32.h b/Aerofoil/GpCursor_Win32.h deleted file mode 100644 index da45656..0000000 --- a/Aerofoil/GpCursor_Win32.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "IGpCursor_Win32.h" -#include "GpWindows.h" - - -class GpCursor_Win32 final : public IGpCursor_Win32 -{ -public: - void Destroy() override; - - const HCURSOR &GetHCursor() const override; - - void IncRef() override; - void DecRef() override; - - static IGpCursor_Win32 *Load(const wchar_t *path); - -private: - GpCursor_Win32(HCURSOR cursor); - ~GpCursor_Win32(); - - HCURSOR m_cursor; - int m_refCount; -}; diff --git a/Aerofoil/GpMain_Win32.cpp b/Aerofoil/GpMain_Win32.cpp index 3f7c04b..3ae45b3 100644 --- a/Aerofoil/GpMain_Win32.cpp +++ b/Aerofoil/GpMain_Win32.cpp @@ -1,6 +1,7 @@ #include "GpMain.h" #include "GpAudioDriverFactory.h" -#include "GpCursor_Win32.h" +#include "GpBWCursor_Win32.h" +#include "GpColorCursor_Win32.h" #include "GpDisplayDriverFactory.h" #include "GpGlobalConfig.h" #include "GpFiber_Win32.h" @@ -427,7 +428,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine g_gpWindowsGlobals.m_hIconSm = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_ICON2)); g_gpWindowsGlobals.m_createFiberFunc = GpFiber_Win32::Create; - g_gpWindowsGlobals.m_loadCursorFunc = GpCursor_Win32::Load; + g_gpWindowsGlobals.m_createBWCursorFunc = GpBWCursor_Win32::Create; + g_gpWindowsGlobals.m_createColorCursorFunc = GpColorCursor_Win32::Create; g_gpWindowsGlobals.m_translateWindowsMessageFunc = TranslateWindowsMessage; g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_D3D11; diff --git a/AerofoilSDL/GpDisplayDriver_SDL_GL2.cpp b/AerofoilSDL/GpDisplayDriver_SDL_GL2.cpp index 4490c40..79afb38 100644 --- a/AerofoilSDL/GpDisplayDriver_SDL_GL2.cpp +++ b/AerofoilSDL/GpDisplayDriver_SDL_GL2.cpp @@ -14,6 +14,7 @@ #include "IGpPrefsHandler.h" #include "IGpVOSEventQueue.h" +#include "SDL_mouse.h" #include "SDL_opengl.h" #include "SDL_video.h" @@ -588,9 +589,45 @@ private: class GpCursor_SDL2 final : public IGpCursor { public: - void Destroy() override { delete this; } + explicit GpCursor_SDL2(SDL_Cursor *cursor); + + SDL_Cursor* GetCursor() const; + + void IncRef(); + void DecRef(); + + void Destroy() override { this->DecRef(); } + +private: + SDL_Cursor *m_cursor; + unsigned int m_count; }; +GpCursor_SDL2::GpCursor_SDL2(SDL_Cursor *cursor) + : m_cursor(cursor) + , m_count(1) +{ +} + +SDL_Cursor* GpCursor_SDL2::GetCursor() const +{ + return m_cursor; +} + +void GpCursor_SDL2::IncRef() +{ + ++m_count; +} + +void GpCursor_SDL2::DecRef() +{ + if (m_count == 1) + delete this; + else + --m_count; +} + + class GpDisplayDriver_SDL_GL2 final : public IGpDisplayDriver, public IGpPrefsHandler { public: @@ -604,7 +641,8 @@ public: void GetDisplayResolution(unsigned int *width, unsigned int *height) override; IGpDisplayDriverSurface *CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat) override; void DrawSurface(IGpDisplayDriverSurface *surface, int32_t x, int32_t y, size_t width, size_t height, const GpDisplayDriverSurfaceEffects *effects) override; - IGpCursor *LoadCursor(bool isColor, int cursorID) override; + IGpCursor *CreateBWCursor(size_t width, size_t height, const void *pixelData, const void *maskData, size_t hotSpotX, size_t hotSpotY) override; + IGpCursor *CreateColorCursor(size_t width, size_t height, const void *pixelDataRGBA, size_t hotSpotX, size_t hotSpotY) override; void SetCursor(IGpCursor *cursor) override; void SetStandardCursor(EGpStandardCursor_t standardCursor) override; void UpdatePalette(const void *paletteData) override; @@ -649,6 +687,10 @@ private: void BecomeFullScreen(); void BecomeWindowed(); + void SynchronizeCursors(); + void ChangeToCursor(SDL_Cursor *cursor); + void ChangeToStandardCursor(EGpStandardCursor_t cursor); + bool ResizeOpenGLWindow(uint32_t &windowWidth, uint32_t &windowHeight, uint32_t desiredWidth, uint32_t desiredHeight, IGpLogDriver *logger); bool InitBackBuffer(uint32_t width, uint32_t height); @@ -710,6 +752,12 @@ private: SDL_Window *m_window; SDL_GLContext m_glContext; + SDL_Cursor *m_waitCursor; + SDL_Cursor *m_iBeamCursor; + SDL_Cursor *m_arrowCursor; + bool m_cursorIsHidden; + + UINT m_expectedSyncDelta; bool m_isResettingSwapChain; @@ -732,8 +780,8 @@ private: float m_pixelScaleX; float m_pixelScaleY; - IGpCursor *m_activeCursor; - IGpCursor *m_pendingCursor; + GpCursor_SDL2 *m_activeCursor; + GpCursor_SDL2 *m_pendingCursor; EGpStandardCursor_t m_currentStandardCursor; EGpStandardCursor_t m_pendingStandardCursor; bool m_mouseIsInClientArea; @@ -742,10 +790,6 @@ private: PortabilityLayer::HostThreadEvent *m_vosEvent; GpWindowsGlobals *m_osGlobals; - HCURSOR m_arrowCursor; - HCURSOR m_waitCursor; - HCURSOR m_ibeamCursor; - float m_bgColor[4]; bool m_bgIsDark; @@ -975,6 +1019,10 @@ GpDisplayDriver_SDL_GL2::GpDisplayDriver_SDL_GL2(const GpDisplayDriverProperties , m_osGlobals(static_cast(properties.m_osGlobals)) , m_properties(properties) , m_syncTimeBase(std::chrono::time_point::duration::zero()) + , m_waitCursor(nullptr) + , m_iBeamCursor(nullptr) + , m_arrowCursor(nullptr) + , m_cursorIsHidden(false) { m_bgColor[0] = 0.f; m_bgColor[1] = 0.f; @@ -985,6 +1033,10 @@ GpDisplayDriver_SDL_GL2::GpDisplayDriver_SDL_GL2(const GpDisplayDriverProperties const intmax_t periodDen = std::chrono::high_resolution_clock::period::den; m_frameTimeSliceSize = std::chrono::high_resolution_clock::duration(periodDen * static_cast(properties.m_frameTimeLockNumerator) / static_cast(properties.m_frameTimeLockDenominator) / periodNum); + + m_waitCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT); + m_iBeamCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); + m_arrowCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); } template @@ -1347,17 +1399,62 @@ void GpDisplayDriver_SDL_GL2::DrawSurface(IGpDisplayDriverSurface *surface, int3 m_gl.Disable(GL_ALPHA_TEST); } -IGpCursor *GpDisplayDriver_SDL_GL2::LoadCursor(bool isColor, int cursorID) + +IGpCursor *GpDisplayDriver_SDL_GL2::CreateBWCursor(size_t width, size_t height, const void *pixelData, const void *maskData, size_t hotSpotX, size_t hotSpotY) { - return new GpCursor_SDL2(); + SDL_Cursor *cursor = SDL_CreateCursor(static_cast(pixelData), static_cast(maskData), width, height, hotSpotX, hotSpotY); + return new GpCursor_SDL2(cursor); +} + +IGpCursor *GpDisplayDriver_SDL_GL2::CreateColorCursor(size_t width, size_t height, const void *pixelDataRGBA, size_t hotSpotX, size_t hotSpotY) +{ + uint32_t channelMasks[4]; + + for (int i = 0; i < 4; i++) + { + channelMasks[i] = 0; + reinterpret_cast(&channelMasks[i])[i] = 0xff; + } + + SDL_Surface *surface = SDL_CreateRGBSurface(0, width, height, 32, channelMasks[0], channelMasks[1], channelMasks[2], channelMasks[3]); + if (!surface) + return nullptr; + + size_t surfacePitch = surface->pitch; + uint8_t *destPixels = reinterpret_cast(surface->pixels); + for (size_t y = 0; y < height; y++) + memcpy(destPixels + y * surfacePitch, static_cast(pixelDataRGBA) + y * width * 4, width * 4); + + SDL_Cursor *cursor = SDL_CreateColorCursor(surface, hotSpotX, hotSpotY); + SDL_FreeSurface(surface); + + if (!cursor) + return nullptr; + + return new GpCursor_SDL2(cursor); } void GpDisplayDriver_SDL_GL2::SetCursor(IGpCursor *cursor) { + GpCursor_SDL2 *sdlCursor = static_cast(cursor); + + sdlCursor->IncRef(); + + if (m_pendingCursor) + m_pendingCursor->DecRef(); + + m_pendingCursor = sdlCursor; } void GpDisplayDriver_SDL_GL2::SetStandardCursor(EGpStandardCursor_t standardCursor) { + if (m_pendingCursor) + { + m_pendingCursor->DecRef(); + m_pendingCursor = nullptr; + } + + m_pendingStandardCursor = standardCursor; } void GpDisplayDriver_SDL_GL2::UpdatePalette(const void *paletteData) @@ -1619,6 +1716,93 @@ void GpDisplayDriver_SDL_GL2::BecomeWindowed() m_isFullScreen = false; } +void GpDisplayDriver_SDL_GL2::SynchronizeCursors() +{ + if (m_activeCursor) + { + if (m_pendingCursor != m_activeCursor) + { + if (m_pendingCursor == nullptr) + { + m_currentStandardCursor = m_pendingStandardCursor; + ChangeToStandardCursor(m_currentStandardCursor); + + m_activeCursor->DecRef(); + m_activeCursor = nullptr; + } + else + { + ChangeToCursor(m_pendingCursor->GetCursor()); + + m_pendingCursor->IncRef(); + m_activeCursor->DecRef(); + m_activeCursor = m_pendingCursor; + } + } + } + else + { + if (m_pendingCursor) + { + m_pendingCursor->IncRef(); + m_activeCursor = m_pendingCursor; + + ChangeToCursor(m_activeCursor->GetCursor()); + } + else + { + if (m_pendingStandardCursor != m_currentStandardCursor) + { + ChangeToStandardCursor(m_pendingStandardCursor); + m_currentStandardCursor = m_pendingStandardCursor; + } + } + } +} + +void GpDisplayDriver_SDL_GL2::ChangeToCursor(SDL_Cursor *cursor) +{ + if (cursor == nullptr) + { + if (!m_cursorIsHidden) + { + m_cursorIsHidden = true; + SDL_ShowCursor(0); + } + } + else + { + if (m_cursorIsHidden) + { + m_cursorIsHidden = false; + SDL_ShowCursor(1); + } + SDL_SetCursor(cursor); + } +} + +void GpDisplayDriver_SDL_GL2::ChangeToStandardCursor(EGpStandardCursor_t cursor) +{ + switch (cursor) + { + case EGpStandardCursors::kArrow: + SDL_SetCursor(m_arrowCursor); + break; + case EGpStandardCursors::kHidden: + SDL_SetCursor(nullptr); + break; + case EGpStandardCursors::kIBeam: + SDL_SetCursor(m_iBeamCursor); + break; + case EGpStandardCursors::kWait: + SDL_SetCursor(m_waitCursor); + break; + default: + break; + } +} + + bool GpDisplayDriver_SDL_GL2::ResizeOpenGLWindow(uint32_t &windowWidth, uint32_t &windowHeight, uint32_t desiredWidth, uint32_t desiredHeight, IGpLogDriver *logger) { if (logger) @@ -1850,7 +2034,7 @@ bool GpDisplayDriver_SDL_GL2::ScaleQuadProgram::Link(GpDisplayDriver_SDL_GL2 *dr GpDisplayDriverTickStatus_t GpDisplayDriver_SDL_GL2::PresentFrameAndSync() { - //SynchronizeCursors(); + SynchronizeCursors(); float bgColor[4]; diff --git a/AerofoilSDL/GpMain_SDL_Win32.cpp b/AerofoilSDL/GpMain_SDL_Win32.cpp index f447478..1491b2e 100644 --- a/AerofoilSDL/GpMain_SDL_Win32.cpp +++ b/AerofoilSDL/GpMain_SDL_Win32.cpp @@ -2,7 +2,6 @@ #include "GpMain.h" #include "GpAudioDriverFactory.h" -#include "GpCursor_Win32.h" #include "GpDisplayDriverFactory.h" #include "GpGlobalConfig.h" #include "GpFiber_Win32.h" @@ -435,7 +434,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine //g_gpWindowsGlobals.m_hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_ICON1)); //g_gpWindowsGlobals.m_hIconSm = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_ICON2)); - g_gpWindowsGlobals.m_loadCursorFunc = GpCursor_Win32::Load; g_gpWindowsGlobals.m_translateWindowsMessageFunc = TranslateWindowsMessage; g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_SDL_GL2; diff --git a/ConvertColorCursors/ConvertColorCursors.cpp b/ConvertColorCursors/ConvertColorCursors.cpp index a0ded11..a35b39e 100644 --- a/ConvertColorCursors/ConvertColorCursors.cpp +++ b/ConvertColorCursors/ConvertColorCursors.cpp @@ -13,56 +13,6 @@ #include "stb_image_write.h" -// This extracts all of the color cursors from a resource file and converts them to -// Windows cursor format. -// -// Windows only supports loading color cursors by loading them from an executable or DLL resource, -// or by loading them from a file, so we can't just do the conversion/construction at runtime. -// -// Also, classic Mac cursor features are not fully supported by newer operating systems. -// The classic Mac cursor function is basically (existing ^ color) where the mask bit isn't set, -// so it supports inversion masking and colors with the same cursor. -// -// Fortunately, none of the Glider PRO cursors use this combination. -// -// The color cursor format is not fully documented. Appears to be: -// Header -// CursorPixMapPrefix (at pixMapOffset) -// BEPixMap -// Pixel data -// BEColorTableHeader -// BEColorTableItem[...] - -struct CursorPixMapPrefix -{ - BEUInt32_t m_unknown; // Seems to always be zero - BEUInt16_t m_subFormat; // 0x8002 = 2 colors, 0x8004 = 4 colors, 0x8008 = 16 colors, 0x8010 = 256 colors -}; - -struct CursorHeader -{ - BEUInt16_t m_cursorType; - BEUInt32_t m_pixMapOffset; - BEUInt32_t m_pixDataOffset; - BEUInt32_t m_expandedData; - BEUInt16_t m_expandedDataDepth; - BEUInt32_t m_unused; - uint8_t m_bwCursor[32]; - uint8_t m_mask[32]; - BEUInt16_t m_hotSpotY; - BEUInt16_t m_hotSpotX; - BEUInt32_t m_colorTableResourceID; - BEUInt32_t m_cursorResourceID; -}; - -struct BWCursor -{ - uint8_t m_pixels[32]; - uint8_t m_mask[32]; - BEUInt16_t m_hotSpotX; - BEUInt16_t m_hotSpotY; -}; - struct IconDir { uint16_t m_reserved; @@ -101,255 +51,6 @@ void WriteToVectorCallback(void *context, void *data, int size) vec->push_back(static_cast(data)[i]); } -void ConvertBWCursors(PortabilityLayer::ResourceFile *resFile) -{ - const PortabilityLayer::ResourceCompiledTypeList *typeList = resFile->GetResourceTypeList('CURS'); - if (!typeList) - return; - - const size_t numRefs = typeList->m_numRefs; - for (size_t i = 0; i < numRefs; i++) - { - const int resID = typeList->m_firstRef[i].m_resID; - const THandle resHdl = resFile->LoadResource('CURS', resID); - const void *cursorDataBase = *resHdl; - const BWCursor *cursorData = static_cast(cursorDataBase); - - char outPathDebug[64]; - sprintf_s(outPathDebug, "Packaged\\WinCursors\\b%i.bmp", resID); - - char outPath[64]; - sprintf_s(outPath, "Packaged\\WinCursors\\b%i.cur", resID); - - FILE *outF = nullptr; - errno_t outErr = fopen_s(&outF, outPath, "wb"); - - if (!outErr) - { - IconDir iconDir; - iconDir.m_reserved = 0; - iconDir.m_type = 2; - iconDir.m_numImages = 1; - - IconDirEntry iconDirEntry; - iconDirEntry.m_width = 16; - iconDirEntry.m_height = 16; - iconDirEntry.m_numColors = 0; - iconDirEntry.m_reserved = 0; - iconDirEntry.m_numPlanes_HotSpotX = cursorData->m_hotSpotX; - iconDirEntry.m_bpp_HotSpotY = cursorData->m_hotSpotY; - iconDirEntry.m_imageDataSize = 0; - iconDirEntry.m_imageDataOffset = sizeof(IconDir) + sizeof(IconDirEntry); - - fwrite(&iconDir, 1, sizeof(IconDir), outF); - fwrite(&iconDirEntry, 1, sizeof(IconDirEntry), outF); - - long imageDataStart = ftell(outF); - - PortabilityLayer::BitmapInfoHeader bmpHeader; - bmpHeader.m_thisStructureSize = sizeof(bmpHeader); - bmpHeader.m_width = 16; - bmpHeader.m_height = 32; - bmpHeader.m_planes = 1; - bmpHeader.m_bitsPerPixel = 1; - bmpHeader.m_compression = 0; - bmpHeader.m_imageSize = (16 * 16 / 8); - bmpHeader.m_xPixelsPerMeter = 0; - bmpHeader.m_yPixelsPerMeter = 0; - bmpHeader.m_numColors = 2; - bmpHeader.m_importantColorCount = 2; - - fwrite(&bmpHeader, 1, sizeof(bmpHeader), outF); - - const uint8_t paletteData[] = { - 0, 0, 0, 0, - 255, 255, 255, 0 }; - - fwrite(paletteData, 1, sizeof(paletteData), outF); - uint8_t padding[2] = { 0, 0 }; - - for (int y = 0; y < 16; y++) - { - const uint8_t *maskRow = cursorData->m_mask + (15 - y) * 2; - const uint8_t *row = cursorData->m_pixels + (15 - y) * 2; - const uint8_t modifiedRow[] = { row[0] ^ maskRow[0], row[1] ^ maskRow[1] }; - fwrite(modifiedRow, 1, 2, outF); - fwrite(padding, 1, 2, outF); - } - - for (int y = 0; y < 16; y++) - { - const uint8_t *row = cursorData->m_mask + (15 - y) * 2; - const uint8_t modifiedRow[] = { row[0] ^ 255, row[1] ^ 255 }; - fwrite(modifiedRow, 1, 2, outF); - fwrite(padding, 1, 2, outF); - } - - long imageDataEnd = ftell(outF); - - fseek(outF, sizeof(IconDir), SEEK_SET); - - iconDirEntry.m_imageDataSize = static_cast(imageDataEnd - imageDataStart); - fwrite(&iconDirEntry, 1, sizeof(IconDirEntry), outF); - fclose(outF); - } - } -} - -void ConvertCursors(PortabilityLayer::ResourceFile *resFile) -{ - const PortabilityLayer::ResourceCompiledTypeList *typeList = resFile->GetResourceTypeList('crsr'); - if (!typeList) - return; - - const size_t numRefs = typeList->m_numRefs; - for (size_t i = 0; i < numRefs; i++) - { - const int resID = typeList->m_firstRef[i].m_resID; - const THandle resHdl = resFile->LoadResource('crsr', resID); - const void *cursorDataBase = *resHdl; - const void *cursorData = cursorDataBase; - - const CursorHeader *cursorHeader = static_cast(cursorData); - cursorData = cursorHeader + 1; - cursorData = static_cast(reinterpret_cast(cursorDataBase) + cursorHeader->m_pixMapOffset); - - const CursorPixMapPrefix *cursorPixMapPrefix = static_cast(cursorData); - - cursorData = cursorPixMapPrefix + 1; - - const BEPixMap *pixMap = reinterpret_cast(reinterpret_cast(cursorData)); - cursorData = pixMap + 1; - - cursorData = static_cast(reinterpret_cast(cursorDataBase) + cursorHeader->m_pixDataOffset); - const uint8_t *pixMapDataBytes = static_cast(cursorData); - - const Rect rect = pixMap->m_bounds.ToRect(); - const int width = rect.right - rect.left; - const int height = rect.bottom - rect.top; - const int componentSize = static_cast(pixMap->m_componentSize); - - switch (componentSize) - { - case 1: - case 2: - case 4: - case 8: - break; - default: - assert(false); - break; - } - - const int bitsRequired = width * height * componentSize; - const int bytesRequired = (bitsRequired + 7) / 8; - - uint8_t *colorValues = new uint8_t[width * height]; - - const int numPixels = width * height; - - switch (componentSize) - { - case 1: - for (int i = 0; i < numPixels; i++) - colorValues[i] = (pixMapDataBytes[i / 8] >> (7 - (i & 7) * 1)) & 0x1; - break; - case 2: - for (int i = 0; i < numPixels; i++) - colorValues[i] = (pixMapDataBytes[i / 4] >> (6 - (i & 3) * 2)) & 0x3; - break; - case 4: - for (int i = 0; i < numPixels; i++) - colorValues[i] = (pixMapDataBytes[i / 2] >> (4 - (i & 1) * 4)) & 0xf; - break; - case 8: - for (int i = 0; i < numPixels; i++) - colorValues[i] = pixMapDataBytes[i]; - break; - default: - assert(false); - break; - } - - cursorData = static_cast(pixMapDataBytes + bytesRequired); - const BEColorTableHeader *colorTableHeader = static_cast(cursorData); - - cursorData = colorTableHeader + 1; - - const BEColorTableItem *ctabItems = static_cast(cursorData); - - uint32_t decodedCTabItems[256]; - const int numCTabItems = colorTableHeader->m_numItemsMinusOne + 1; - - for (int i = 0; i < numCTabItems; i++) - { - const BEColorTableItem &item = ctabItems[i]; - unsigned char rgba[4]; - rgba[0] = CompactChannel(item.m_red); - rgba[1] = CompactChannel(item.m_green); - rgba[2] = CompactChannel(item.m_blue); - rgba[3] = 255; - - int index = item.m_index; - assert(index >= 0 && index < 256); - - memcpy(decodedCTabItems + index, rgba, 4); - } - - uint32_t *pixelDataRGBA = new uint32_t[width * height * 4]; - - for (int i = 0; i < numPixels; i++) - { - const uint8_t ctabIndex = colorValues[i]; - pixelDataRGBA[i] = decodedCTabItems[ctabIndex]; - - if (((cursorHeader->m_mask[i / 8] >> (7 - (i & 7))) & 1) == 0) - reinterpret_cast(pixelDataRGBA + i)[3] = 0; - } - - char outPath[64]; - sprintf_s(outPath, "Packaged\\WinCursors\\c%i.cur", resID); - - FILE *outF = nullptr; - errno_t outErr = fopen_s(&outF, outPath, "wb"); - - if (!outErr) - { - IconDir iconDir; - iconDir.m_reserved = 0; - iconDir.m_type = 2; - iconDir.m_numImages = 1; - - IconDirEntry iconDirEntry; - iconDirEntry.m_width = width; - iconDirEntry.m_height = height; - iconDirEntry.m_numColors = 0; - iconDirEntry.m_reserved = 0; - iconDirEntry.m_numPlanes_HotSpotX = cursorHeader->m_hotSpotX; - iconDirEntry.m_bpp_HotSpotY = cursorHeader->m_hotSpotY; - iconDirEntry.m_imageDataSize = 0; - iconDirEntry.m_imageDataOffset = sizeof(IconDir) + sizeof(IconDirEntry); - - fwrite(&iconDir, 1, sizeof(IconDir), outF); - fwrite(&iconDirEntry, 1, sizeof(IconDirEntry), outF); - - long imageDataStart = ftell(outF); - stbi_write_png_to_func(WriteToFileCallback, outF, width, height, 4, pixelDataRGBA, width * 4); - long imageDataEnd = ftell(outF); - - fseek(outF, sizeof(IconDir), SEEK_SET); - - iconDirEntry.m_imageDataSize = static_cast(imageDataEnd - imageDataStart); - fwrite(&iconDirEntry, 1, sizeof(IconDirEntry), outF); - fclose(outF); - } - - delete[] colorValues; - delete[] pixelDataRGBA; - resHdl.Dispose(); - } -} - void ConvertIconFamily(PortabilityLayer::ResourceFile *resFile, int32_t iconBitmapType, int32_t iconColorType, const char *prefix, unsigned int dimension) { const PortabilityLayer::ResourceCompiledTypeList *typeList = resFile->GetResourceTypeList(iconBitmapType); @@ -446,8 +147,6 @@ int main(int argc, const char **argv) stream.Close(); - ConvertCursors(resFile); - ConvertBWCursors(resFile); ConvertIconFamily(resFile, 'ics#', 'ics8', "Small", 16); ConvertIconFamily(resFile, 'ICN#', 'icl8', "Large", 32); diff --git a/GpApp/AnimCursor.cpp b/GpApp/AnimCursor.cpp index f97cbdc..8a785fa 100644 --- a/GpApp/AnimCursor.cpp +++ b/GpApp/AnimCursor.cpp @@ -13,8 +13,11 @@ #include "HostDisplayDriver.h" #include "IGpCursor.h" #include "IGpDisplayDriver.h" +#include "MemoryManager.h" #include "ResourceManager.h" +#include + #define rAcurID 128 #define rHandCursorID 1000 @@ -58,6 +61,173 @@ compiledAcurHandle compiledAnimCursorH = nil; // Loads color cursors (for animated beach ball). +static uint8_t CompactChannel(const uint8_t *doublet) +{ + unsigned int doubletValue = (doublet[0] << 8) + doublet[1]; + + return (doubletValue * 2 + 0x101) / 0x202; +} + +IGpCursor *LoadColorCursor(int16_t resID) +{ + const THandle resHdl = PortabilityLayer::ResourceManager::GetInstance()->GetAppResource('crsr', resID); + if (!resHdl) + return nullptr; + + // The color cursor format is not fully documented. Appears to be: + // Header + // CursorPixMapPrefix (at pixMapOffset) + // BEPixMap + // Pixel data + // BEColorTableHeader + // BEColorTableItem[...] + + struct CursorPixMapPrefix + { + BEUInt32_t m_unknown; // Seems to always be zero + BEUInt16_t m_subFormat; // 0x8002 = 2 colors, 0x8004 = 4 colors, 0x8008 = 16 colors, 0x8010 = 256 colors + }; + + struct CursorHeader + { + BEUInt16_t m_cursorType; + BEUInt32_t m_pixMapOffset; + BEUInt32_t m_pixDataOffset; + BEUInt32_t m_expandedData; + BEUInt16_t m_expandedDataDepth; + BEUInt32_t m_unused; + uint8_t m_bwCursor[32]; + uint8_t m_mask[32]; + BEUInt16_t m_hotSpotY; + BEUInt16_t m_hotSpotX; + BEUInt32_t m_colorTableResourceID; + BEUInt32_t m_cursorResourceID; + }; + + const void *cursorDataBase = *resHdl; + const void *cursorData = cursorDataBase; + + const CursorHeader *cursorHeader = static_cast(cursorData); + cursorData = cursorHeader + 1; + cursorData = static_cast(reinterpret_cast(cursorDataBase) + cursorHeader->m_pixMapOffset); + + const CursorPixMapPrefix *cursorPixMapPrefix = static_cast(cursorData); + + cursorData = cursorPixMapPrefix + 1; + + const BEPixMap *pixMap = reinterpret_cast(reinterpret_cast(cursorData)); + cursorData = pixMap + 1; + + cursorData = static_cast(reinterpret_cast(cursorDataBase) + cursorHeader->m_pixDataOffset); + const uint8_t *pixMapDataBytes = static_cast(cursorData); + + const Rect rect = pixMap->m_bounds.ToRect(); + const int width = rect.right - rect.left; + const int height = rect.bottom - rect.top; + const int componentSize = static_cast(pixMap->m_componentSize); + + switch (componentSize) + { + case 1: + case 2: + case 4: + case 8: + break; + default: + assert(false); + break; + } + + const int bitsRequired = width * height * componentSize; + const int bytesRequired = (bitsRequired + 7) / 8; + + PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance(); + + uint8_t *colorValues = static_cast(mm->Alloc(width * height)); + if (!colorValues) + { + resHdl.Dispose(); + return nullptr; + } + + const int numPixels = width * height; + + switch (componentSize) + { + case 1: + for (int i = 0; i < numPixels; i++) + colorValues[i] = (pixMapDataBytes[i / 8] >> (7 - (i & 7) * 1)) & 0x1; + break; + case 2: + for (int i = 0; i < numPixels; i++) + colorValues[i] = (pixMapDataBytes[i / 4] >> (6 - (i & 3) * 2)) & 0x3; + break; + case 4: + for (int i = 0; i < numPixels; i++) + colorValues[i] = (pixMapDataBytes[i / 2] >> (4 - (i & 1) * 4)) & 0xf; + break; + case 8: + for (int i = 0; i < numPixels; i++) + colorValues[i] = pixMapDataBytes[i]; + break; + default: + assert(false); + break; + } + + cursorData = static_cast(pixMapDataBytes + bytesRequired); + const BEColorTableHeader *colorTableHeader = static_cast(cursorData); + + cursorData = colorTableHeader + 1; + + const BEColorTableItem *ctabItems = static_cast(cursorData); + + uint32_t decodedCTabItems[256]; + const int numCTabItems = colorTableHeader->m_numItemsMinusOne + 1; + + for (int i = 0; i < numCTabItems; i++) + { + const BEColorTableItem &item = ctabItems[i]; + unsigned char rgba[4]; + rgba[0] = CompactChannel(item.m_red); + rgba[1] = CompactChannel(item.m_green); + rgba[2] = CompactChannel(item.m_blue); + rgba[3] = 255; + + int index = item.m_index; + assert(index >= 0 && index < 256); + + memcpy(decodedCTabItems + index, rgba, 4); + } + + uint32_t *pixelDataRGBA = static_cast(mm->Alloc(width * height * 4)); + if (!pixelDataRGBA) + { + mm->Release(colorValues); + resHdl.Dispose(); + return nullptr; + } + + for (int i = 0; i < numPixels; i++) + { + const uint8_t ctabIndex = colorValues[i]; + pixelDataRGBA[i] = decodedCTabItems[ctabIndex]; + + if (((cursorHeader->m_mask[i / 8] >> (7 - (i & 7))) & 1) == 0) + reinterpret_cast(pixelDataRGBA + i)[3] = 0; + } + + mm->Release(colorValues); + + IGpCursor *cursor = PortabilityLayer::HostDisplayDriver::GetInstance()->CreateColorCursor(width, height, pixelDataRGBA, cursorHeader->m_hotSpotX, cursorHeader->m_hotSpotY); + + mm->Release(pixelDataRGBA); + + resHdl.Dispose(); + + return cursor; +} + Boolean GetColorCursors (acurHandle ballCursH, compiledAcurHandle compiledBallCursH) { short i, j; @@ -70,8 +240,8 @@ Boolean GetColorCursors (acurHandle ballCursH, compiledAcurHandle compiledBallCu HideCursor(); // Hide the cursor for (i = 0; i < j; i++) // Walk through the acur resource { - hwCursor = PortabilityLayer::HostDisplayDriver::GetInstance()->LoadCursor(true, (*ballCursH)->frame[i].resID); // Get the cursor - if (hwCursor == nil) // Make sure a real cursor was returned + hwCursor = LoadColorCursor((*ballCursH)->frame[i].resID); // Get the cursor + if (hwCursor == nil) // Make sure a real cursor was returned { // If not, trash all cursors loaded for (j = 0; j < i; j++) (*compiledBallCursH)->frame[j].hwCursor->Destroy(); diff --git a/GpApp/InterfaceInit.cpp b/GpApp/InterfaceInit.cpp index fa8b679..9bba98f 100644 --- a/GpApp/InterfaceInit.cpp +++ b/GpApp/InterfaceInit.cpp @@ -16,6 +16,7 @@ #include "PLKeyEncoding.h" #include "PLPasStr.h" #include "RectUtils.h" +#include "ResourceManager.h" #include "Tools.h" @@ -81,21 +82,51 @@ void InitializeMenus (void) // Extra cursors (custom cursors) like the "hand" and various roomÉ // editing cursors are loaded up. +IGpCursor *LoadBWCursor(int resID) +{ + const THandle resHdl = PortabilityLayer::ResourceManager::GetInstance()->GetAppResource('CURS', resID); + if (!resHdl) + return nullptr; + + struct BWCursor + { + uint8_t m_pixels[32]; + uint8_t m_mask[32]; + BEUInt16_t m_hotSpotX; + BEUInt16_t m_hotSpotY; + }; + + const BWCursor *cursorData = static_cast(*resHdl); + + IGpCursor *cursor = PortabilityLayer::HostDisplayDriver::GetInstance()->CreateBWCursor(16, 16, cursorData->m_pixels, cursorData->m_mask, cursorData->m_hotSpotX, cursorData->m_hotSpotY); + resHdl.Dispose(); + + return cursor; +} + void GetExtraCursors (void) { - handCursor = PortabilityLayer::HostDisplayDriver::GetInstance()->LoadCursor(false, kHandCursorID); + struct BWCursor + { + uint8_t m_pixels[32]; + uint8_t m_mask[32]; + BEUInt16_t m_hotSpotX; + BEUInt16_t m_hotSpotY; + }; + + handCursor = LoadBWCursor(kHandCursorID); if (handCursor == nil) RedAlert(kErrFailedResourceLoad); - vertCursor = PortabilityLayer::HostDisplayDriver::GetInstance()->LoadCursor(false, kVertCursorID); + vertCursor = LoadBWCursor(kVertCursorID); if (vertCursor == nil) RedAlert(kErrFailedResourceLoad); - horiCursor = PortabilityLayer::HostDisplayDriver::GetInstance()->LoadCursor(false, kHoriCursorID); + horiCursor = LoadBWCursor(kHoriCursorID); if (horiCursor == nil) RedAlert(kErrFailedResourceLoad); - diagCursor = PortabilityLayer::HostDisplayDriver::GetInstance()->LoadCursor(false, kDiagCursorID); + diagCursor = LoadBWCursor(kDiagCursorID); if (diagCursor == nil) RedAlert(kErrFailedResourceLoad); } diff --git a/GpCommon/GpWindows.h b/GpCommon/GpWindows.h index 6250ff9..237bd7b 100644 --- a/GpCommon/GpWindows.h +++ b/GpCommon/GpWindows.h @@ -30,6 +30,7 @@ struct GpWindowsGlobals int m_nCmdShow; IGpFiber *(*m_createFiberFunc)(LPVOID fiber); - IGpCursor_Win32 *(*m_loadCursorFunc)(const wchar_t *path); + IGpCursor_Win32 *(*m_createColorCursorFunc)(size_t width, size_t height, const void *pixelDataRGBA, size_t hotSpotX, size_t hotSpotY); + IGpCursor_Win32 *(*m_createBWCursorFunc)(size_t width, size_t height, const void *pixelData, const void *maskData, size_t hotSpotX, size_t hotSpotY); void (*m_translateWindowsMessageFunc)(const MSG *msg, IGpVOSEventQueue *eventQueue, float pixelScaleX, float pixelScaleY); }; diff --git a/GpCommon/IGpDisplayDriver.h b/GpCommon/IGpDisplayDriver.h index 156fbc4..a8cc3c2 100644 --- a/GpCommon/IGpDisplayDriver.h +++ b/GpCommon/IGpDisplayDriver.h @@ -35,7 +35,9 @@ public: virtual IGpDisplayDriverSurface *CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat) = 0; virtual void DrawSurface(IGpDisplayDriverSurface *surface, int32_t x, int32_t y, size_t width, size_t height, const GpDisplayDriverSurfaceEffects *effects) = 0; - virtual IGpCursor *LoadCursor(bool isColor, int cursorID) = 0; + virtual IGpCursor *CreateBWCursor(size_t width, size_t height, const void *pixelData, const void *maskData, size_t hotSpotX, size_t hotSpotY) = 0; + virtual IGpCursor *CreateColorCursor(size_t width, size_t height, const void *pixelDataRGBA, size_t hotSpotX, size_t hotSpotY) = 0; + virtual void SetCursor(IGpCursor *cursor) = 0; virtual void SetStandardCursor(EGpStandardCursor_t standardCursor) = 0; diff --git a/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp b/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp index 55b7fb7..9a776f6 100644 --- a/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp +++ b/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp @@ -877,8 +877,6 @@ void GpDisplayDriverD3D11::ScaleVirtualScreen() void GpDisplayDriverD3D11::SynchronizeCursors() { - HCURSOR replacementCursor = nullptr; - if (m_activeCursor) { if (m_pendingCursor != m_activeCursor) @@ -1373,23 +1371,15 @@ void GpDisplayDriverD3D11::DrawSurface(IGpDisplayDriverSurface *surface, int32_t m_deviceContext->DrawIndexed(6, 0, 0); } -IGpCursor *GpDisplayDriverD3D11::LoadCursor(bool isColor, int cursorID) +IGpCursor *GpDisplayDriverD3D11::CreateColorCursor(size_t width, size_t height, const void *pixelDataRGBA, size_t hotSpotX, size_t hotSpotY) { - const size_t bufSize = MAX_PATH; - wchar_t path[bufSize]; - - int sz = 0; - if (isColor) - sz = _snwprintf(path, bufSize, L"%sPackaged\\WinCursors\\c%i.cur", m_osGlobals->m_baseDir, cursorID); - else - sz = _snwprintf(path, bufSize, L"%sPackaged\\WinCursors\\b%i.cur", m_osGlobals->m_baseDir, cursorID); - - if (sz < 0 || static_cast(sz) >= bufSize) - return nullptr; - - return m_osGlobals->m_loadCursorFunc(path); + return m_osGlobals->m_createColorCursorFunc(width, height, pixelDataRGBA, hotSpotX, hotSpotY); } +IGpCursor *GpDisplayDriverD3D11::CreateBWCursor(size_t width, size_t height, const void *pixelData, const void *maskData, size_t hotSpotX, size_t hotSpotY) +{ + return m_osGlobals->m_createBWCursorFunc(width, height, pixelData, maskData, hotSpotX, hotSpotY); +} // We can't just set the cursor because we want to post WM_SETCURSOR to keep it limited // to the game window area, but depending on the fiber implementation, this may not be diff --git a/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.h b/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.h index 26ca06c..5305ed5 100644 --- a/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.h +++ b/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.h @@ -44,7 +44,8 @@ public: IGpDisplayDriverSurface *CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat) override; void DrawSurface(IGpDisplayDriverSurface *surface, int32_t x, int32_t y, size_t width, size_t height, const GpDisplayDriverSurfaceEffects *effects) override; - IGpCursor *LoadCursor(bool isColor, int cursorID) override; + IGpCursor *CreateColorCursor(size_t width, size_t height, const void *pixelDataRGBA, size_t hotSpotX, size_t hotSpotY) override; + IGpCursor *CreateBWCursor(size_t width, size_t height, const void *pixelData, const void *maskData, size_t hotSpotX, size_t hotSpotY) override; void SetCursor(IGpCursor *cursor) override; void SetStandardCursor(EGpStandardCursor_t standardCursor) override;