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;