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:
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user