Redo mouse cursor handling

This commit is contained in:
elasota
2020-09-26 21:15:43 -04:00
parent db54e92425
commit e88c9e7112
17 changed files with 654 additions and 397 deletions

View File

@@ -82,6 +82,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="GpBWCursor_Win32.cpp" />
<ClCompile Include="GpColorCursor_Win32.cpp" />
<ClCompile Include="GpFiber_Win32.cpp" />
<ClCompile Include="GpFileStream_Win32.cpp" />
@@ -106,10 +107,10 @@
<ClInclude Include="..\GpCommon\IGpDisplayDriverSurface.h" />
<ClInclude Include="..\GpCommon\IGpLogDriver.h" />
<ClInclude Include="..\GpCommon\IGpPrefsHandler.h" />
<ClInclude Include="GpBWCursor_Win32.h" />
<ClInclude Include="GpFiber_Win32.h" />
<ClInclude Include="GpFileStream_Win32.h" />
<ClInclude Include="GpFileSystem_Win32.h" />
<ClInclude Include="GpFontHandler_FreeType2.h" />
<ClInclude Include="GpLogDriver_Win32.h" />
<ClInclude Include="GpMutex_Win32.h" />
<ClInclude Include="GpSystemServices_Win32.h" />

View File

@@ -31,6 +31,9 @@
<ClCompile Include="GpLogDriver_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpBWCursor_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\GpCommon\EGpInputDriverType.h">
@@ -57,9 +60,6 @@
<ClInclude Include="GpFileSystem_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpFontHandler_FreeType2.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\GpInputDriverProperties.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -96,6 +96,9 @@
<ClInclude Include="..\GpCommon\GpBuildVersion.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpBWCursor_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="ConvertedResources\Large128.ico">

View File

@@ -0,0 +1,110 @@
/*
Portions of this file based on Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
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 <stdint.h>
#include <stdlib.h>
#include <new>
#include <algorithm>
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<uint8_t*>(malloc(numBytes));
uint8_t *convertedXorData = static_cast<uint8_t*>(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<const uint8_t*>(maskData)[i] ^ 0xff;
convertedXorData[i] = static_cast<const uint8_t*>(maskData)[i] ^ static_cast<const uint8_t*>(pixelData)[i];
}
HCURSOR hcursor = CreateCursor(g_gpWindowsGlobals.m_hInstance, static_cast<int>(hotSpotX), static_cast<int>(hotSpotY), static_cast<int>(width), static_cast<int>(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);
}
}

View File

@@ -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;
};

View File

@@ -1,58 +1,132 @@
#include "GpCursor_Win32.h"
/*
Portions of this file based on Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
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 <stdint.h>
#include <stdlib.h>
#include <new>
#include <algorithm>
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<LONG>(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<HCURSOR>(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<uint8_t*>(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<HCURSOR>(cursor));
return new (storage) GpColorCursor_Win32(reinterpret_cast<HCURSOR>(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);
}
}

View File

@@ -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);

View File

@@ -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;
};

View File

@@ -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;

View File

@@ -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<GpWindowsGlobals*>(properties.m_osGlobals))
, m_properties(properties)
, m_syncTimeBase(std::chrono::time_point<std::chrono::high_resolution_clock>::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<intmax_t>(properties.m_frameTimeLockNumerator) / static_cast<intmax_t>(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<class T>
@@ -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<const Uint8*>(pixelData), static_cast<const Uint8*>(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<uint8_t*>(&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<uint8_t*>(surface->pixels);
for (size_t y = 0; y < height; y++)
memcpy(destPixels + y * surfacePitch, static_cast<const uint8_t*>(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<GpCursor_SDL2*>(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];

View File

@@ -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;

View File

@@ -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<const uint8_t*>(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<void> resHdl = resFile->LoadResource('CURS', resID);
const void *cursorDataBase = *resHdl;
const BWCursor *cursorData = static_cast<const BWCursor *>(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<uint32_t>(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<void> resHdl = resFile->LoadResource('crsr', resID);
const void *cursorDataBase = *resHdl;
const void *cursorData = cursorDataBase;
const CursorHeader *cursorHeader = static_cast<const CursorHeader *>(cursorData);
cursorData = cursorHeader + 1;
cursorData = static_cast<const void*>(reinterpret_cast<const uint8_t*>(cursorDataBase) + cursorHeader->m_pixMapOffset);
const CursorPixMapPrefix *cursorPixMapPrefix = static_cast<const CursorPixMapPrefix *>(cursorData);
cursorData = cursorPixMapPrefix + 1;
const BEPixMap *pixMap = reinterpret_cast<const BEPixMap*>(reinterpret_cast<const uint8_t*>(cursorData));
cursorData = pixMap + 1;
cursorData = static_cast<const void*>(reinterpret_cast<const uint8_t*>(cursorDataBase) + cursorHeader->m_pixDataOffset);
const uint8_t *pixMapDataBytes = static_cast<const uint8_t*>(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<int>(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<const void*>(pixMapDataBytes + bytesRequired);
const BEColorTableHeader *colorTableHeader = static_cast<const BEColorTableHeader *>(cursorData);
cursorData = colorTableHeader + 1;
const BEColorTableItem *ctabItems = static_cast<const BEColorTableItem *>(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<uint8_t*>(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<uint32_t>(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);

View File

@@ -13,8 +13,11 @@
#include "HostDisplayDriver.h"
#include "IGpCursor.h"
#include "IGpDisplayDriver.h"
#include "MemoryManager.h"
#include "ResourceManager.h"
#include <assert.h>
#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<void> 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<const CursorHeader *>(cursorData);
cursorData = cursorHeader + 1;
cursorData = static_cast<const void*>(reinterpret_cast<const uint8_t*>(cursorDataBase) + cursorHeader->m_pixMapOffset);
const CursorPixMapPrefix *cursorPixMapPrefix = static_cast<const CursorPixMapPrefix *>(cursorData);
cursorData = cursorPixMapPrefix + 1;
const BEPixMap *pixMap = reinterpret_cast<const BEPixMap*>(reinterpret_cast<const uint8_t*>(cursorData));
cursorData = pixMap + 1;
cursorData = static_cast<const void*>(reinterpret_cast<const uint8_t*>(cursorDataBase) + cursorHeader->m_pixDataOffset);
const uint8_t *pixMapDataBytes = static_cast<const uint8_t*>(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<int>(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<uint8_t*>(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<const void*>(pixMapDataBytes + bytesRequired);
const BEColorTableHeader *colorTableHeader = static_cast<const BEColorTableHeader *>(cursorData);
cursorData = colorTableHeader + 1;
const BEColorTableItem *ctabItems = static_cast<const BEColorTableItem *>(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<uint32_t*>(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<uint8_t*>(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();

View File

@@ -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<6F>
// editing cursors are loaded up.
IGpCursor *LoadBWCursor(int resID)
{
const THandle<void> 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<const BWCursor *>(*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);
}

View File

@@ -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);
};

View File

@@ -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;

View File

@@ -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<size_t>(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

View File

@@ -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;