mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-09-23 06:53:43 +00:00
Redo mouse cursor handling
This commit is contained in:
@@ -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" />
|
||||
|
@@ -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">
|
||||
|
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 <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);
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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 "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;
|
||||
|
@@ -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];
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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();
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
};
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
||||
|
Reference in New Issue
Block a user