mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-12-14 12:09:36 +00:00
Redo mouse cursor handling
This commit is contained in:
@@ -82,6 +82,7 @@
|
|||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="GpBWCursor_Win32.cpp" />
|
||||||
<ClCompile Include="GpColorCursor_Win32.cpp" />
|
<ClCompile Include="GpColorCursor_Win32.cpp" />
|
||||||
<ClCompile Include="GpFiber_Win32.cpp" />
|
<ClCompile Include="GpFiber_Win32.cpp" />
|
||||||
<ClCompile Include="GpFileStream_Win32.cpp" />
|
<ClCompile Include="GpFileStream_Win32.cpp" />
|
||||||
@@ -106,10 +107,10 @@
|
|||||||
<ClInclude Include="..\GpCommon\IGpDisplayDriverSurface.h" />
|
<ClInclude Include="..\GpCommon\IGpDisplayDriverSurface.h" />
|
||||||
<ClInclude Include="..\GpCommon\IGpLogDriver.h" />
|
<ClInclude Include="..\GpCommon\IGpLogDriver.h" />
|
||||||
<ClInclude Include="..\GpCommon\IGpPrefsHandler.h" />
|
<ClInclude Include="..\GpCommon\IGpPrefsHandler.h" />
|
||||||
|
<ClInclude Include="GpBWCursor_Win32.h" />
|
||||||
<ClInclude Include="GpFiber_Win32.h" />
|
<ClInclude Include="GpFiber_Win32.h" />
|
||||||
<ClInclude Include="GpFileStream_Win32.h" />
|
<ClInclude Include="GpFileStream_Win32.h" />
|
||||||
<ClInclude Include="GpFileSystem_Win32.h" />
|
<ClInclude Include="GpFileSystem_Win32.h" />
|
||||||
<ClInclude Include="GpFontHandler_FreeType2.h" />
|
|
||||||
<ClInclude Include="GpLogDriver_Win32.h" />
|
<ClInclude Include="GpLogDriver_Win32.h" />
|
||||||
<ClInclude Include="GpMutex_Win32.h" />
|
<ClInclude Include="GpMutex_Win32.h" />
|
||||||
<ClInclude Include="GpSystemServices_Win32.h" />
|
<ClInclude Include="GpSystemServices_Win32.h" />
|
||||||
|
|||||||
@@ -31,6 +31,9 @@
|
|||||||
<ClCompile Include="GpLogDriver_Win32.cpp">
|
<ClCompile Include="GpLogDriver_Win32.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="GpBWCursor_Win32.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\GpCommon\EGpInputDriverType.h">
|
<ClInclude Include="..\GpCommon\EGpInputDriverType.h">
|
||||||
@@ -57,9 +60,6 @@
|
|||||||
<ClInclude Include="GpFileSystem_Win32.h">
|
<ClInclude Include="GpFileSystem_Win32.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="GpFontHandler_FreeType2.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\GpCommon\GpInputDriverProperties.h">
|
<ClInclude Include="..\GpCommon\GpInputDriverProperties.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -96,6 +96,9 @@
|
|||||||
<ClInclude Include="..\GpCommon\GpBuildVersion.h">
|
<ClInclude Include="..\GpCommon\GpBuildVersion.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="GpBWCursor_Win32.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Image Include="ConvertedResources\Large128.ico">
|
<Image Include="ConvertedResources\Large128.ico">
|
||||||
|
|||||||
110
Aerofoil/GpBWCursor_Win32.cpp
Normal file
110
Aerofoil/GpBWCursor_Win32.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
24
Aerofoil/GpBWCursor_Win32.h
Normal file
24
Aerofoil/GpBWCursor_Win32.h
Normal 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;
|
||||||
|
};
|
||||||
@@ -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 <stdlib.h>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
void GpCursor_Win32::Destroy()
|
void GpColorCursor_Win32::Destroy()
|
||||||
{
|
{
|
||||||
this->DecRef();
|
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;
|
return nullptr;
|
||||||
|
|
||||||
HCURSOR cursor = reinterpret_cast<HCURSOR>(imageH);
|
memset(maskBits, 0xff, maskPitch * height);
|
||||||
void *storage = malloc(sizeof(GpCursor_Win32));
|
|
||||||
|
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)
|
if (!storage)
|
||||||
{
|
{
|
||||||
DestroyCursor(cursor);
|
DestroyIcon(hicon);
|
||||||
return nullptr;
|
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_cursor(cursor)
|
||||||
, m_refCount(1)
|
, 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;
|
return m_cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpCursor_Win32::IncRef()
|
void GpColorCursor_Win32::IncRef()
|
||||||
{
|
{
|
||||||
m_refCount++;
|
m_refCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GpCursor_Win32::DecRef()
|
void GpColorCursor_Win32::DecRef()
|
||||||
{
|
{
|
||||||
m_refCount--;
|
m_refCount--;
|
||||||
if (m_refCount == 0)
|
if (m_refCount == 0)
|
||||||
{
|
{
|
||||||
this->~GpCursor_Win32();
|
this->~GpColorCursor_Win32();
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "IGpColorCursor.h"
|
#include "IGpCursor_Win32.h"
|
||||||
#include "GpWindows.h"
|
#include "GpWindows.h"
|
||||||
|
|
||||||
struct IGpColorCursor_Win32 : public IGpColorCursor
|
|
||||||
{
|
|
||||||
virtual const HCURSOR &GetHCursor() const = 0;
|
|
||||||
|
|
||||||
virtual void IncRef() = 0;
|
class GpColorCursor_Win32 final : public IGpCursor_Win32
|
||||||
virtual void DecRef() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class GpColorCursor_Win32 final : public IGpColorCursor_Win32
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void Destroy() override;
|
void Destroy() override;
|
||||||
@@ -22,7 +14,7 @@ public:
|
|||||||
void IncRef() override;
|
void IncRef() override;
|
||||||
void DecRef() 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:
|
private:
|
||||||
GpColorCursor_Win32(HCURSOR cursor);
|
GpColorCursor_Win32(HCURSOR cursor);
|
||||||
|
|||||||
@@ -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;
|
|
||||||
};
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "GpMain.h"
|
#include "GpMain.h"
|
||||||
#include "GpAudioDriverFactory.h"
|
#include "GpAudioDriverFactory.h"
|
||||||
#include "GpCursor_Win32.h"
|
#include "GpBWCursor_Win32.h"
|
||||||
|
#include "GpColorCursor_Win32.h"
|
||||||
#include "GpDisplayDriverFactory.h"
|
#include "GpDisplayDriverFactory.h"
|
||||||
#include "GpGlobalConfig.h"
|
#include "GpGlobalConfig.h"
|
||||||
#include "GpFiber_Win32.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_hIconSm = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_ICON2));
|
||||||
|
|
||||||
g_gpWindowsGlobals.m_createFiberFunc = GpFiber_Win32::Create;
|
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_gpWindowsGlobals.m_translateWindowsMessageFunc = TranslateWindowsMessage;
|
||||||
|
|
||||||
g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_D3D11;
|
g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_D3D11;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "IGpPrefsHandler.h"
|
#include "IGpPrefsHandler.h"
|
||||||
#include "IGpVOSEventQueue.h"
|
#include "IGpVOSEventQueue.h"
|
||||||
|
|
||||||
|
#include "SDL_mouse.h"
|
||||||
#include "SDL_opengl.h"
|
#include "SDL_opengl.h"
|
||||||
#include "SDL_video.h"
|
#include "SDL_video.h"
|
||||||
|
|
||||||
@@ -588,9 +589,45 @@ private:
|
|||||||
class GpCursor_SDL2 final : public IGpCursor
|
class GpCursor_SDL2 final : public IGpCursor
|
||||||
{
|
{
|
||||||
public:
|
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
|
class GpDisplayDriver_SDL_GL2 final : public IGpDisplayDriver, public IGpPrefsHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -604,7 +641,8 @@ public:
|
|||||||
void GetDisplayResolution(unsigned int *width, unsigned int *height) override;
|
void GetDisplayResolution(unsigned int *width, unsigned int *height) override;
|
||||||
IGpDisplayDriverSurface *CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat) 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;
|
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 SetCursor(IGpCursor *cursor) override;
|
||||||
void SetStandardCursor(EGpStandardCursor_t standardCursor) override;
|
void SetStandardCursor(EGpStandardCursor_t standardCursor) override;
|
||||||
void UpdatePalette(const void *paletteData) override;
|
void UpdatePalette(const void *paletteData) override;
|
||||||
@@ -649,6 +687,10 @@ private:
|
|||||||
void BecomeFullScreen();
|
void BecomeFullScreen();
|
||||||
void BecomeWindowed();
|
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 ResizeOpenGLWindow(uint32_t &windowWidth, uint32_t &windowHeight, uint32_t desiredWidth, uint32_t desiredHeight, IGpLogDriver *logger);
|
||||||
bool InitBackBuffer(uint32_t width, uint32_t height);
|
bool InitBackBuffer(uint32_t width, uint32_t height);
|
||||||
|
|
||||||
@@ -710,6 +752,12 @@ private:
|
|||||||
SDL_Window *m_window;
|
SDL_Window *m_window;
|
||||||
SDL_GLContext m_glContext;
|
SDL_GLContext m_glContext;
|
||||||
|
|
||||||
|
SDL_Cursor *m_waitCursor;
|
||||||
|
SDL_Cursor *m_iBeamCursor;
|
||||||
|
SDL_Cursor *m_arrowCursor;
|
||||||
|
bool m_cursorIsHidden;
|
||||||
|
|
||||||
|
|
||||||
UINT m_expectedSyncDelta;
|
UINT m_expectedSyncDelta;
|
||||||
bool m_isResettingSwapChain;
|
bool m_isResettingSwapChain;
|
||||||
|
|
||||||
@@ -732,8 +780,8 @@ private:
|
|||||||
float m_pixelScaleX;
|
float m_pixelScaleX;
|
||||||
float m_pixelScaleY;
|
float m_pixelScaleY;
|
||||||
|
|
||||||
IGpCursor *m_activeCursor;
|
GpCursor_SDL2 *m_activeCursor;
|
||||||
IGpCursor *m_pendingCursor;
|
GpCursor_SDL2 *m_pendingCursor;
|
||||||
EGpStandardCursor_t m_currentStandardCursor;
|
EGpStandardCursor_t m_currentStandardCursor;
|
||||||
EGpStandardCursor_t m_pendingStandardCursor;
|
EGpStandardCursor_t m_pendingStandardCursor;
|
||||||
bool m_mouseIsInClientArea;
|
bool m_mouseIsInClientArea;
|
||||||
@@ -742,10 +790,6 @@ private:
|
|||||||
PortabilityLayer::HostThreadEvent *m_vosEvent;
|
PortabilityLayer::HostThreadEvent *m_vosEvent;
|
||||||
GpWindowsGlobals *m_osGlobals;
|
GpWindowsGlobals *m_osGlobals;
|
||||||
|
|
||||||
HCURSOR m_arrowCursor;
|
|
||||||
HCURSOR m_waitCursor;
|
|
||||||
HCURSOR m_ibeamCursor;
|
|
||||||
|
|
||||||
float m_bgColor[4];
|
float m_bgColor[4];
|
||||||
bool m_bgIsDark;
|
bool m_bgIsDark;
|
||||||
|
|
||||||
@@ -975,6 +1019,10 @@ GpDisplayDriver_SDL_GL2::GpDisplayDriver_SDL_GL2(const GpDisplayDriverProperties
|
|||||||
, m_osGlobals(static_cast<GpWindowsGlobals*>(properties.m_osGlobals))
|
, m_osGlobals(static_cast<GpWindowsGlobals*>(properties.m_osGlobals))
|
||||||
, m_properties(properties)
|
, m_properties(properties)
|
||||||
, m_syncTimeBase(std::chrono::time_point<std::chrono::high_resolution_clock>::duration::zero())
|
, 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[0] = 0.f;
|
||||||
m_bgColor[1] = 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;
|
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_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>
|
template<class T>
|
||||||
@@ -1347,17 +1399,62 @@ void GpDisplayDriver_SDL_GL2::DrawSurface(IGpDisplayDriverSurface *surface, int3
|
|||||||
m_gl.Disable(GL_ALPHA_TEST);
|
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)
|
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)
|
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)
|
void GpDisplayDriver_SDL_GL2::UpdatePalette(const void *paletteData)
|
||||||
@@ -1619,6 +1716,93 @@ void GpDisplayDriver_SDL_GL2::BecomeWindowed()
|
|||||||
m_isFullScreen = false;
|
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)
|
bool GpDisplayDriver_SDL_GL2::ResizeOpenGLWindow(uint32_t &windowWidth, uint32_t &windowHeight, uint32_t desiredWidth, uint32_t desiredHeight, IGpLogDriver *logger)
|
||||||
{
|
{
|
||||||
if (logger)
|
if (logger)
|
||||||
@@ -1850,7 +2034,7 @@ bool GpDisplayDriver_SDL_GL2::ScaleQuadProgram::Link(GpDisplayDriver_SDL_GL2 *dr
|
|||||||
|
|
||||||
GpDisplayDriverTickStatus_t GpDisplayDriver_SDL_GL2::PresentFrameAndSync()
|
GpDisplayDriverTickStatus_t GpDisplayDriver_SDL_GL2::PresentFrameAndSync()
|
||||||
{
|
{
|
||||||
//SynchronizeCursors();
|
SynchronizeCursors();
|
||||||
|
|
||||||
float bgColor[4];
|
float bgColor[4];
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "GpMain.h"
|
#include "GpMain.h"
|
||||||
#include "GpAudioDriverFactory.h"
|
#include "GpAudioDriverFactory.h"
|
||||||
#include "GpCursor_Win32.h"
|
|
||||||
#include "GpDisplayDriverFactory.h"
|
#include "GpDisplayDriverFactory.h"
|
||||||
#include "GpGlobalConfig.h"
|
#include "GpGlobalConfig.h"
|
||||||
#include "GpFiber_Win32.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_hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_ICON1));
|
||||||
//g_gpWindowsGlobals.m_hIconSm = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_ICON2));
|
//g_gpWindowsGlobals.m_hIconSm = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_ICON2));
|
||||||
|
|
||||||
g_gpWindowsGlobals.m_loadCursorFunc = GpCursor_Win32::Load;
|
|
||||||
g_gpWindowsGlobals.m_translateWindowsMessageFunc = TranslateWindowsMessage;
|
g_gpWindowsGlobals.m_translateWindowsMessageFunc = TranslateWindowsMessage;
|
||||||
|
|
||||||
g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_SDL_GL2;
|
g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_SDL_GL2;
|
||||||
|
|||||||
@@ -13,56 +13,6 @@
|
|||||||
|
|
||||||
#include "stb_image_write.h"
|
#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
|
struct IconDir
|
||||||
{
|
{
|
||||||
uint16_t m_reserved;
|
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]);
|
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)
|
void ConvertIconFamily(PortabilityLayer::ResourceFile *resFile, int32_t iconBitmapType, int32_t iconColorType, const char *prefix, unsigned int dimension)
|
||||||
{
|
{
|
||||||
const PortabilityLayer::ResourceCompiledTypeList *typeList = resFile->GetResourceTypeList(iconBitmapType);
|
const PortabilityLayer::ResourceCompiledTypeList *typeList = resFile->GetResourceTypeList(iconBitmapType);
|
||||||
@@ -446,8 +147,6 @@ int main(int argc, const char **argv)
|
|||||||
|
|
||||||
stream.Close();
|
stream.Close();
|
||||||
|
|
||||||
ConvertCursors(resFile);
|
|
||||||
ConvertBWCursors(resFile);
|
|
||||||
ConvertIconFamily(resFile, 'ics#', 'ics8', "Small", 16);
|
ConvertIconFamily(resFile, 'ics#', 'ics8', "Small", 16);
|
||||||
ConvertIconFamily(resFile, 'ICN#', 'icl8', "Large", 32);
|
ConvertIconFamily(resFile, 'ICN#', 'icl8', "Large", 32);
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,11 @@
|
|||||||
#include "HostDisplayDriver.h"
|
#include "HostDisplayDriver.h"
|
||||||
#include "IGpCursor.h"
|
#include "IGpCursor.h"
|
||||||
#include "IGpDisplayDriver.h"
|
#include "IGpDisplayDriver.h"
|
||||||
|
#include "MemoryManager.h"
|
||||||
#include "ResourceManager.h"
|
#include "ResourceManager.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
|
||||||
#define rAcurID 128
|
#define rAcurID 128
|
||||||
#define rHandCursorID 1000
|
#define rHandCursorID 1000
|
||||||
@@ -58,6 +61,173 @@ compiledAcurHandle compiledAnimCursorH = nil;
|
|||||||
|
|
||||||
// Loads color cursors (for animated beach ball).
|
// 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)
|
Boolean GetColorCursors (acurHandle ballCursH, compiledAcurHandle compiledBallCursH)
|
||||||
{
|
{
|
||||||
short i, j;
|
short i, j;
|
||||||
@@ -70,8 +240,8 @@ Boolean GetColorCursors (acurHandle ballCursH, compiledAcurHandle compiledBallCu
|
|||||||
HideCursor(); // Hide the cursor
|
HideCursor(); // Hide the cursor
|
||||||
for (i = 0; i < j; i++) // Walk through the acur resource
|
for (i = 0; i < j; i++) // Walk through the acur resource
|
||||||
{
|
{
|
||||||
hwCursor = PortabilityLayer::HostDisplayDriver::GetInstance()->LoadCursor(true, (*ballCursH)->frame[i].resID); // Get the cursor
|
hwCursor = LoadColorCursor((*ballCursH)->frame[i].resID); // Get the cursor
|
||||||
if (hwCursor == nil) // Make sure a real cursor was returned
|
if (hwCursor == nil) // Make sure a real cursor was returned
|
||||||
{ // If not, trash all cursors loaded
|
{ // If not, trash all cursors loaded
|
||||||
for (j = 0; j < i; j++)
|
for (j = 0; j < i; j++)
|
||||||
(*compiledBallCursH)->frame[j].hwCursor->Destroy();
|
(*compiledBallCursH)->frame[j].hwCursor->Destroy();
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "PLKeyEncoding.h"
|
#include "PLKeyEncoding.h"
|
||||||
#include "PLPasStr.h"
|
#include "PLPasStr.h"
|
||||||
#include "RectUtils.h"
|
#include "RectUtils.h"
|
||||||
|
#include "ResourceManager.h"
|
||||||
#include "Tools.h"
|
#include "Tools.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -81,21 +82,51 @@ void InitializeMenus (void)
|
|||||||
// Extra cursors (custom cursors) like the "hand" and various room<6F>
|
// Extra cursors (custom cursors) like the "hand" and various room<6F>
|
||||||
// editing cursors are loaded up.
|
// 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)
|
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)
|
if (handCursor == nil)
|
||||||
RedAlert(kErrFailedResourceLoad);
|
RedAlert(kErrFailedResourceLoad);
|
||||||
|
|
||||||
vertCursor = PortabilityLayer::HostDisplayDriver::GetInstance()->LoadCursor(false, kVertCursorID);
|
vertCursor = LoadBWCursor(kVertCursorID);
|
||||||
if (vertCursor == nil)
|
if (vertCursor == nil)
|
||||||
RedAlert(kErrFailedResourceLoad);
|
RedAlert(kErrFailedResourceLoad);
|
||||||
|
|
||||||
horiCursor = PortabilityLayer::HostDisplayDriver::GetInstance()->LoadCursor(false, kHoriCursorID);
|
horiCursor = LoadBWCursor(kHoriCursorID);
|
||||||
if (horiCursor == nil)
|
if (horiCursor == nil)
|
||||||
RedAlert(kErrFailedResourceLoad);
|
RedAlert(kErrFailedResourceLoad);
|
||||||
|
|
||||||
diagCursor = PortabilityLayer::HostDisplayDriver::GetInstance()->LoadCursor(false, kDiagCursorID);
|
diagCursor = LoadBWCursor(kDiagCursorID);
|
||||||
if (diagCursor == nil)
|
if (diagCursor == nil)
|
||||||
RedAlert(kErrFailedResourceLoad);
|
RedAlert(kErrFailedResourceLoad);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ struct GpWindowsGlobals
|
|||||||
int m_nCmdShow;
|
int m_nCmdShow;
|
||||||
|
|
||||||
IGpFiber *(*m_createFiberFunc)(LPVOID fiber);
|
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);
|
void (*m_translateWindowsMessageFunc)(const MSG *msg, IGpVOSEventQueue *eventQueue, float pixelScaleX, float pixelScaleY);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ public:
|
|||||||
virtual IGpDisplayDriverSurface *CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat) = 0;
|
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 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 SetCursor(IGpCursor *cursor) = 0;
|
||||||
virtual void SetStandardCursor(EGpStandardCursor_t standardCursor) = 0;
|
virtual void SetStandardCursor(EGpStandardCursor_t standardCursor) = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -877,8 +877,6 @@ void GpDisplayDriverD3D11::ScaleVirtualScreen()
|
|||||||
|
|
||||||
void GpDisplayDriverD3D11::SynchronizeCursors()
|
void GpDisplayDriverD3D11::SynchronizeCursors()
|
||||||
{
|
{
|
||||||
HCURSOR replacementCursor = nullptr;
|
|
||||||
|
|
||||||
if (m_activeCursor)
|
if (m_activeCursor)
|
||||||
{
|
{
|
||||||
if (m_pendingCursor != m_activeCursor)
|
if (m_pendingCursor != m_activeCursor)
|
||||||
@@ -1373,23 +1371,15 @@ void GpDisplayDriverD3D11::DrawSurface(IGpDisplayDriverSurface *surface, int32_t
|
|||||||
m_deviceContext->DrawIndexed(6, 0, 0);
|
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;
|
return m_osGlobals->m_createColorCursorFunc(width, height, pixelDataRGBA, hotSpotX, hotSpotY);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// 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
|
// to the game window area, but depending on the fiber implementation, this may not be
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ public:
|
|||||||
IGpDisplayDriverSurface *CreateSurface(size_t width, size_t height, size_t pitch, GpPixelFormat_t pixelFormat) 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;
|
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 SetCursor(IGpCursor *cursor) override;
|
||||||
void SetStandardCursor(EGpStandardCursor_t standardCursor) override;
|
void SetStandardCursor(EGpStandardCursor_t standardCursor) override;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user