Fix house data corruption, progress to first screen

This commit is contained in:
elasota
2019-12-24 18:39:30 -05:00
parent 3111609536
commit 5cb9b85396
30 changed files with 896 additions and 113 deletions

1
.gitignore vendored
View File

@@ -22,3 +22,4 @@
*.res
.vs/*
Packaged/*
DebugData/*

View File

@@ -72,13 +72,13 @@ void DrawBanner (Point *topLeft)
theErr = CreateOffScreenGWorld(&tempMask, &mapBounds, 1);
SetGWorld(tempMask, nil);
LoadGraphic(kBannerPageBottomMask);
CopyMask((BitMap *)*GetGWorldPixMap(tempMap),
(BitMap *)*GetGWorldPixMap(tempMask),
(BitMap *)*GetGWorldPixMap(workSrcMap),
&mapBounds, &mapBounds, &partPage);
SetPort((GrafPtr)workSrcMap);
SetGWorld(wasCPort, wasWorld);
DisposeGWorld(tempMap);
DisposeGWorld(tempMask);
@@ -176,6 +176,9 @@ void BringUpBanner (void)
DrawBanner(&topLeft);
DrawBannerMessage(topLeft);
DumpScreenOn(&justRoomsRect);
// if (quickerTransitions)
// DissBitsChunky(&justRoomsRect); // was workSrcRect
// else
@@ -186,6 +189,7 @@ void BringUpBanner (void)
CopyBits((BitMap *)*GetGWorldPixMap(backSrcMap),
(BitMap *)*GetGWorldPixMap(workSrcMap),
&wholePage, &wholePage, srcCopy, nil);
if (demoGoing)
WaitForInputEvent(4);

View File

@@ -474,6 +474,8 @@ void DoDiedGameOver (void)
pagesStuck = 8;
userAborted = true;
}
Delay(1, nullptr);
}
while (TickCount() < nextLoop);
nextLoop = TickCount() + 2;

View File

@@ -194,7 +194,11 @@ typedef struct
Boolean unusedBoolean; // 1
int16_t firstRoom; // 2
int16_t nRooms; // 2
int16_t padding;
roomType rooms[1]; // 348 * nRooms
static const size_t kBinaryDataSize = 866;
} houseType, *housePtr, **houseHand; // total = 866 +
typedef struct

View File

@@ -598,7 +598,7 @@ bool ByteSwapHouse(housePtr house, size_t sizeInBytes)
PortabilityLayer::ByteSwap::BigInt16(house->firstRoom);
PortabilityLayer::ByteSwap::BigInt16(house->nRooms);
const size_t roomDataSize = sizeInBytes + sizeof(roomType) - sizeof(houseType);
const size_t roomDataSize = sizeInBytes - houseType::kBinaryDataSize;
if (house->nRooms < 1 || roomDataSize / sizeof(roomType) < static_cast<size_t>(house->nRooms))
return false;
@@ -614,6 +614,9 @@ Boolean ReadHouse (void)
long byteCount;
OSErr theErr;
short whichRoom;
// There should be no padding remaining the house type
PL_STATIC_ASSERT(sizeof(houseType) - sizeof(roomType) == houseType::kBinaryDataSize + 2);
if (!houseOpen)
{
@@ -649,8 +652,11 @@ Boolean ReadHouse (void)
if (thisHouse != nil)
DisposeHandle((Handle)thisHouse);
// GP: Correct for padding
const size_t alignmentPadding = sizeof(houseType) - sizeof(roomType) - houseType::kBinaryDataSize;
thisHouse = (houseHand)NewHandle(byteCount);
thisHouse = (houseHand)NewHandle(byteCount + alignmentPadding);
if (thisHouse == nil)
{
YellowAlert(kYellowNoMemory, 10);
@@ -666,14 +672,24 @@ Boolean ReadHouse (void)
}
HLock((Handle)thisHouse);
theErr = FSRead(houseRefNum, &byteCount, *thisHouse);
if (theErr != noErr)
long readByteCount = byteCount;
theErr = FSRead(houseRefNum, &readByteCount, *thisHouse);
if (theErr != noErr || readByteCount != byteCount || byteCount < static_cast<long>(houseType::kBinaryDataSize))
{
CheckFileError(theErr, thisHouseName);
HUnlock((Handle)thisHouse);
return(false);
}
if (alignmentPadding != 0)
{
// GP: Correct for padding
const size_t roomDataSize = byteCount - houseType::kBinaryDataSize;
uint8_t *houseDataBytes = reinterpret_cast<uint8_t*>(*thisHouse);
memmove((*thisHouse)->rooms, houseDataBytes + houseType::kBinaryDataSize, roomDataSize);
}
ByteSwapHouse(*thisHouse, static_cast<size_t>(byteCount));
numberRooms = (*thisHouse)->nRooms;
@@ -791,14 +807,27 @@ Boolean WriteHouse (Boolean checkIt)
ByteSwapHouse(*thisHouse, static_cast<size_t>(byteCount));
theErr = FSWrite(houseRefNum, &byteCount, *thisHouse);
long headerSize = houseType::kBinaryDataSize;
long roomsSize = sizeof(roomType) * (*thisHouse)->nRooms;
theErr = FSWrite(houseRefNum, &headerSize, *thisHouse);
if (theErr != noErr)
{
CheckFileError(theErr, thisHouseName);
ByteSwapHouse(*thisHouse, static_cast<size_t>(byteCount));
HUnlock((Handle)thisHouse);
return(false);
}
theErr = FSWrite(houseRefNum, &roomsSize, (*thisHouse)->rooms);
if (theErr != noErr)
{
CheckFileError(theErr, thisHouseName);
ByteSwapHouse(*thisHouse, static_cast<size_t>(byteCount));
HUnlock((Handle)thisHouse);
return(false);
}
ByteSwapHouse(*thisHouse, static_cast<size_t>(byteCount));
theErr = SetEOF(houseRefNum, byteCount);

View File

@@ -74,7 +74,6 @@ extern Boolean switchedOut;
void NewGame (short mode)
{
Rect tempRect;
Size freeBytes, growBytes;
OSErr theErr;
Boolean wasPlayMusicPref;
@@ -192,8 +191,6 @@ void NewGame (short mode)
InitTelephone();
wasPlayMusicPref = isPlayMusicGame;
freeBytes = MaxMem(&growBytes);
#ifdef CREATEDEMODATA
SysBeep(1);
#endif

View File

@@ -616,14 +616,18 @@ void RenderShreds (void)
void CopyRectsQD (void)
{
short i;
CGrafPtr mainWindowGraf = GetWindowPort(mainWindow);
for (i = 0; i < numWork2Main; i++)
{
CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap),
GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
GetPortBitMapForCopyBits(mainWindowGraf),
&work2MainRects[i], &work2MainRects[i],
srcCopy, nil);
}
mainWindowGraf->m_port.SetDirty(PortabilityLayer::QDPortDirtyFlag_Contents);
for (i = 0; i < numBack2Work; i++)
{
@@ -661,6 +665,7 @@ void RenderFrame (void)
while (TickCount() < nextFrame)
{
Delay(1, nullptr);
}
nextFrame = TickCount() + kTicksPerFrame;

View File

@@ -138,8 +138,12 @@ void WipeScreenOn (short direction, Rect *theRect)
void DumpScreenOn (Rect *theRect)
{
CGrafPtr graf = GetWindowPort(mainWindow);
CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap),
GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
GetPortBitMapForCopyBits(graf),
theRect, theRect, srcCopy, nil);
graf->m_port.SetDirty(PortabilityLayer::QDPortDirtyFlag_Contents);
}

View File

@@ -248,8 +248,9 @@ OSErr CreateOffScreenGWorld (GWorldPtr *theGWorld, Rect *bounds, short depth)
if (theErr)
theErr = NewGWorld(theGWorld, depth, bounds, nil, nil, 0);
LockPixels(GetGWorldPixMap(*theGWorld));
if (!theErr)
LockPixels(GetGWorldPixMap(*theGWorld));
return theErr;
}
@@ -450,6 +451,8 @@ Boolean WaitForInputEvent (short seconds)
}
if ((seconds != -1) && (TickCount() >= timeToBail))
waiting = false;
Delay(1, nullptr);
}
FlushEvents(everyEvent, 0);
return (didResume);

View File

@@ -6,6 +6,7 @@ namespace GpPixelFormats
{
kInvalid,
kBW1,
k8BitStandard,
k8BitCustom,
kRGB555,

View File

@@ -18,39 +18,44 @@
#include "QDManager.h"
#include "QDPixMap.h"
#include "RGBAColor.h"
#include "Vec2i.h"
#include <stdint.h>
#include <assert.h>
#include <algorithm>
namespace
{
static const int kMidGray = 187;
const PortabilityLayer::RGBAColor gs_barTopLeftCornerGraphicPixels[] =
{
{ 0, 0, 0, 255 }, { 0, 0, 0, 255 }, { 0, 0, 0, 255 }, { 85, 85, 85, 255 }, { 170, 170, 170, 255 },
{ 0, 0, 0, 255 }, { 0, 0, 0, 255 }, { 85, 85, 85, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 },
{ 0, 0, 0, 255 }, { 85, 85, 85, 255 }, { 255, 255, 255, 255 }, { 221, 221, 221, 255 }, { 221, 221, 221, 255 },
{ 85, 85, 85, 255 }, { 255, 255, 255, 255 }, { 221, 221, 221, 255 }, { 221, 221, 221, 255 }, { 221, 221, 221, 255 },
{ 170, 170, 170, 255 }, { 255, 255, 255, 255 }, { 221, 221, 221, 255 }, { 221, 221, 221, 255 }, { 221, 221, 221, 255 },
{ 0, 0, 0, 255 }, { 85, 85, 85, 255 }, { 255, 255, 255, 255 }, { kMidGray, kMidGray, kMidGray, 255 }, { kMidGray, kMidGray, kMidGray, 255 },
{ 85, 85, 85, 255 }, { 255, 255, 255, 255 }, { kMidGray, kMidGray, kMidGray, 255 }, { kMidGray, kMidGray, kMidGray, 255 }, { kMidGray, kMidGray, kMidGray, 255 },
{ 170, 170, 170, 255 }, { 255, 255, 255, 255 }, { kMidGray, kMidGray, kMidGray, 255 }, { kMidGray, kMidGray, kMidGray, 255 }, { kMidGray, kMidGray, kMidGray, 255 },
};
const PortabilityLayer::RGBAColor gs_barTopRightCornerGraphicPixels[] =
{
{ 170, 170, 170, 255 }, { 85, 85, 85, 255 }, { 0, 0, 0, 255 }, { 0, 0, 0, 255 }, { 0, 0, 0, 255 },
{ 255, 255, 255, 255 }, { 255, 255, 255, 255 }, { 85, 85, 85, 255 }, { 0, 0, 0, 255 }, { 0, 0, 0, 255 },
{ 221, 221, 221, 255 }, { 221, 221, 221, 255 }, { 255, 255, 255, 255 }, { 85, 85, 85, 255 }, { 0, 0, 0, 255 },
{ 221, 221, 221, 255 }, { 221, 221, 221, 255 }, { 221, 221, 221, 255 }, { 255, 255, 255, 255 }, { 85, 85, 85, 255 },
{ 221, 221, 221, 255 }, { 221, 221, 221, 255 }, { 221, 221, 221, 255 }, { 255, 255, 255, 255 }, { 85, 85, 85, 255 },
{ kMidGray, kMidGray, kMidGray, 255 }, { kMidGray, kMidGray, kMidGray, 255 }, { 255, 255, 255, 255 }, { 85, 85, 85, 255 }, { 0, 0, 0, 255 },
{ kMidGray, kMidGray, kMidGray, 255 }, { kMidGray, kMidGray, kMidGray, 255 }, { kMidGray, kMidGray, kMidGray, 255 }, { 255, 255, 255, 255 }, { 85, 85, 85, 255 },
{ kMidGray, kMidGray, kMidGray, 255 }, { kMidGray, kMidGray, kMidGray, 255 }, { kMidGray, kMidGray, kMidGray, 255 }, { 255, 255, 255, 255 }, { 85, 85, 85, 255 },
};
const PortabilityLayer::RGBAColor gs_barBrightColor = { 255, 255, 255, 255 };
const PortabilityLayer::RGBAColor gs_barMidColor = { 221, 221, 221, 255 };
const PortabilityLayer::RGBAColor gs_barMidColor = { kMidGray, kMidGray, kMidGray, 255 };
const PortabilityLayer::RGBAColor gs_barDarkColor = { 102, 102, 102, 255 };
const PortabilityLayer::RGBAColor gs_barBottomEdgeColor = { 0, 0, 0, 255 };
const PortabilityLayer::RGBAColor gs_barNormalTextColor = { 0, 0, 0, 255 };
const PortabilityLayer::RGBAColor gs_barHighlightTextColor = { 255, 255, 255, 255 };
const PortabilityLayer::RGBAColor gs_barHighlightBrightColor = { 153, 153, 255, 255 };
const PortabilityLayer::RGBAColor gs_barHighlightMidColor = { 102, 102, 204, 255 };
const PortabilityLayer::RGBAColor gs_barHighlightDarkColor = { 51, 51, 102, 255 };
const PortabilityLayer::RGBAColor gs_barHighlightBrightColor = { 153, 204, 255, 255 };
const PortabilityLayer::RGBAColor gs_barHighlightMidColor = { 51, 102, 204, 255 };
const PortabilityLayer::RGBAColor gs_barHighlightDarkColor = { 0, 51, 102, 255 };
PortabilityLayer::SimpleGraphicInstanceRGBA<5, 5> gs_barTopLeftCornerGraphic(gs_barTopLeftCornerGraphicPixels);
PortabilityLayer::SimpleGraphicInstanceRGBA<5, 5> gs_barTopRightCornerGraphic(gs_barTopRightCornerGraphicPixels);
@@ -65,6 +70,9 @@ struct MenuItem
uint8_t textStyle;
bool enabled;
bool checked;
uint16_t layoutYOffset;
uint16_t layoutHeight;
};
struct Menu
@@ -75,6 +83,10 @@ struct Menu
uint16_t commandID;
bool enabled;
bool isIcon;
bool haveMenuLayout;
size_t layoutWidth;
size_t layoutHeight;
PortabilityLayer::MMHandleBlock *stringBlobHandle;
@@ -83,6 +95,7 @@ struct Menu
// Refreshed on layout
size_t cumulativeOffset;
size_t unpaddedTitleWidth;
unsigned int menuIndex;
size_t numMenuItems;
@@ -112,6 +125,9 @@ namespace PortabilityLayer
void SetItemEnabled(Menu **menu, unsigned int index, bool enabled) override;
void SetItemChecked(Menu **menu, unsigned int index, bool checked) override;
bool IsPointInMenuBar(const Vec2i &point) const override;
void MenuSelect(const Vec2i &initialPoint, int16_t *outMenu, uint16_t *outItem) override;
void DrawMenuBar() override;
void RenderFrame(IGpDisplayDriver *displayDriver) override;
@@ -119,7 +135,36 @@ namespace PortabilityLayer
static MenuManagerImpl *GetInstance();
private:
void RefreshMenuLayout();
class MenuSelectionState
{
public:
MenuSelectionState();
~MenuSelectionState();
void HandleSelectionOfMenu(MenuManagerImpl *mm, Menu **menuHdl, bool &outNeedRedraw);
void Dismiss();
Menu **GetSelectedMenu() const;
CGraf *GetRenderedMenu() const;
const unsigned int *GetSelectedItem() const;
void SelectItem(size_t item);
void ClearSelection();
private:
void RenderMenu(Menu *menu);
Menu **m_currentMenu;
CGraf *m_menuGraf;
unsigned int m_itemIndex;
bool m_haveItem;
};
void RefreshMenuBarLayout();
void RefreshMenuLayout(Menu *menu);
void ProcessMouseMoveTo(const Vec2i &point);
void ProcessMouseMoveToMenuBar(const Vec2i &point);
void ProcessMouseMoveToMenu(const Vec2i &point);
static const unsigned int kIconResID = 128;
static const unsigned int kMenuFontSize = 12;
@@ -128,13 +173,21 @@ namespace PortabilityLayer
static const unsigned int kMenuBarHeight = 20;
static const unsigned int kMenuBarItemPadding = 6;
static const unsigned int kMenuBarInitialPadding = 16;
static const unsigned int kMenuItemHeight = 18;
static const unsigned int kMenuItemTextYOffset = 13;
static const unsigned int kMenuSeparatorHeight = 6;
static const unsigned int kMenuItemRightPadding = 8;
static const unsigned int kMenuItemLeftPadding = 16 + 2 + 2; // 2 for left border, 16 for icon, 2 for spacing
static const int kMenuFontFlags = PortabilityLayer::FontFamilyFlag_Bold;
CGraf *m_menuBarGraf;
Menu **m_firstMenu;
Menu **m_lastMenu;
bool m_haveMenuLayout;
bool m_haveMenuBarLayout;
bool m_haveIcon;
uint8_t m_iconColors[16 * 16];
@@ -142,6 +195,8 @@ namespace PortabilityLayer
SimpleGraphic *m_iconGraphic;
MenuSelectionState m_menuSelectionState;
static MenuManagerImpl ms_instance;
};
@@ -149,7 +204,7 @@ namespace PortabilityLayer
: m_menuBarGraf(nullptr)
, m_firstMenu(nullptr)
, m_lastMenu(nullptr)
, m_haveMenuLayout(false)
, m_haveMenuBarLayout(false)
, m_haveIcon(false)
, m_iconGraphic(nullptr)
{
@@ -235,7 +290,9 @@ namespace PortabilityLayer
menu->enabled = ((enableFlags & 1) != 0);
menu->menuIndex = 0;
menu->cumulativeOffset = 0;
menu->unpaddedTitleWidth = 0;
menu->isIcon = false;
menu->haveMenuLayout = false;
uint8_t *stringDataStart = static_cast<uint8_t*>(stringData->m_contents);
uint8_t *stringDest = stringDataStart;
@@ -258,6 +315,7 @@ namespace PortabilityLayer
currentItem->nameOffsetInStringBlob = static_cast<uint32_t>(stringDest - stringDataStart);
currentItem->enabled = ((enableFlags & 1) != 0);
currentItem->checked = false;
currentItem->layoutYOffset = 0;
enableFlags >>= 1;
@@ -269,6 +327,8 @@ namespace PortabilityLayer
menu->stringBlobHandle = stringData;
menu->prevMenu = nullptr;
menu->nextMenu = nullptr;
menu->layoutWidth = 0;
menu->layoutHeight = 0;
return reinterpret_cast<Menu**>(&menuData->m_contents);
}
@@ -286,7 +346,7 @@ namespace PortabilityLayer
void MenuManagerImpl::InsertMenuBefore(Menu **insertingMenu, Menu **existingMenu)
{
m_haveMenuLayout = false;
m_haveMenuBarLayout = false;
Menu *insertingMenuPtr = *insertingMenu;
Menu *existingMenuPtr = *existingMenu;
@@ -304,7 +364,7 @@ namespace PortabilityLayer
void MenuManagerImpl::InsertMenuAfter(Menu **insertingMenu, Menu **existingMenu)
{
m_haveMenuLayout = false;
m_haveMenuBarLayout = false;
Menu *insertingMenuPtr = *insertingMenu;
Menu *existingMenuPtr = *existingMenu;
@@ -322,7 +382,7 @@ namespace PortabilityLayer
void MenuManagerImpl::InsertMenuAtEnd(Menu **insertingMenu)
{
m_haveMenuLayout = false;
m_haveMenuBarLayout = false;
if (m_firstMenu == nullptr)
{
@@ -337,7 +397,7 @@ namespace PortabilityLayer
void MenuManagerImpl::InsertMenuAtBeginning(Menu **insertingMenu)
{
m_haveMenuLayout = false;
m_haveMenuBarLayout = false;
if (m_firstMenu == nullptr)
{
@@ -377,6 +437,72 @@ namespace PortabilityLayer
menu->menuItems[index].checked = checked;
}
bool MenuManagerImpl::IsPointInMenuBar(const Vec2i &point) const
{
return point.m_y >= 0 && static_cast<uint32_t>(point.m_y) < kMenuBarHeight;
}
void MenuManagerImpl::MenuSelect(const Vec2i &initialPoint, int16_t *outMenu, uint16_t *outItem)
{
RefreshMenuBarLayout();
ProcessMouseMoveTo(initialPoint);
if (m_menuSelectionState.GetSelectedMenu() == nullptr)
{
if (outMenu)
*outMenu = 0;
if (outItem)
*outItem = 0;
return;
}
EventRecord evt;
bool canDismiss = false;
while (!canDismiss)
{
if (WaitNextEvent(everyEvent, &evt, 1, nullptr))
{
const EventCode eventCode = static_cast<EventCode>(evt.what);
switch (eventCode)
{
case mouseMove:
case mouseDown: // It's possible to get a mouse down event again if the mouse leaves the window and is downed again inside
ProcessMouseMoveTo(PortabilityLayer::Vec2i(evt.where.h, evt.where.v));
break;
case mouseUp:
canDismiss = true;
break;
}
}
}
if (outMenu)
*outMenu = 0;
if (outItem)
*outItem = 0;
if (Menu **menuHdl = m_menuSelectionState.GetSelectedMenu())
{
if (const unsigned int *selectedItem = m_menuSelectionState.GetSelectedItem())
{
if (outMenu)
*outMenu = (*menuHdl)->menuID;
if (outItem)
*outItem = (*selectedItem) + 1;
}
}
m_menuSelectionState.Dismiss();
this->DrawMenuBar();
}
void MenuManagerImpl::DrawMenuBar()
{
if (!m_haveIcon)
@@ -422,17 +548,7 @@ namespace PortabilityLayer
if (m_menuBarGraf == nullptr)
{
int depth = 0;
switch (pixelFormat)
{
case GpPixelFormats::k8BitStandard:
depth = 8;
break;
default:
PL_NotYetImplemented();
return;
}
int depth = PortabilityLayer::QDManager::GetInstance()->DepthForPixelFormat(pixelFormat);
if (qdManager->NewGWorld(&m_menuBarGraf, depth, menuRect, nullptr, nullptr, 0) != 0)
return;
@@ -448,8 +564,7 @@ namespace PortabilityLayer
return;
}
RefreshMenuLayout();
RefreshMenuBarLayout();
CGraf *oldGraf;
GDHandle oldDevice;
@@ -504,11 +619,44 @@ namespace PortabilityLayer
gs_barTopLeftCornerGraphic.DrawToPixMap(pixMap, 0, 0);
gs_barTopRightCornerGraphic.DrawToPixMap(pixMap, static_cast<int16_t>(width) - static_cast<int16_t>(gs_barTopRightCornerGraphic.m_width), 0);
Menu **selectedMenuHdl = m_menuSelectionState.GetSelectedMenu();
if (selectedMenuHdl)
{
Menu *menu = *selectedMenuHdl;
const size_t xCoordinate = menu->cumulativeOffset + (menu->menuIndex * 2) * kMenuBarItemPadding + kMenuBarInitialPadding - kMenuBarItemPadding;
const size_t width = menu->unpaddedTitleWidth + kMenuBarItemPadding * 2;
const int16_t left = static_cast<int16_t>(xCoordinate);
const int16_t right = static_cast<int16_t>(xCoordinate + width);
// Top edge
qdState->SetForeColor(gs_barHighlightBrightColor);
{
const Rect rect = Rect::Create(0, left, 1, right);
PaintRect(&rect);
}
// Middle
qdState->SetForeColor(gs_barHighlightMidColor);
{
const Rect rect = Rect::Create(1, left, kMenuBarHeight - 2, right);
PaintRect(&rect);
}
qdState->SetForeColor(gs_barHighlightDarkColor);
{
const Rect rect = Rect::Create(kMenuBarHeight - 2, left, kMenuBarHeight - 1, right);
PaintRect(&rect);
}
}
// Text items
qdState->SetForeColor(gs_barNormalTextColor);
TextFont(systemFont);
TextSize(kMenuFontSize);
// Text items
{
Menu **menuHdl = m_firstMenu;
while (menuHdl)
@@ -522,13 +670,16 @@ namespace PortabilityLayer
if (menu->isIcon)
{
if (m_iconGraphic)
m_iconGraphic->DrawToPixMapWithMask(pixMap, m_iconMask, xCoordinate, kMenuBarIconYOffset);
m_iconGraphic->DrawToPixMapWithMask(pixMap, m_iconMask, static_cast<int16_t>(xCoordinate), kMenuBarIconYOffset);
}
else
{
qdState->m_penPos.h = xCoordinate;
qdState->m_penPos.v = kMenuBarTextYOffset;
DrawString(PLPasStr(static_cast<const uint8_t*>(menu->stringBlobHandle->m_contents)));
if (menuHdl != selectedMenuHdl)
{
qdState->m_penPos.h = static_cast<int16_t>(xCoordinate);
qdState->m_penPos.v = kMenuBarTextYOffset;
DrawString(PLPasStr(static_cast<const uint8_t*>(menu->stringBlobHandle->m_contents)));
}
}
}
@@ -536,6 +687,21 @@ namespace PortabilityLayer
}
}
if (selectedMenuHdl)
{
Menu *menu = *selectedMenuHdl;
if (menu->stringBlobHandle && !menu->isIcon)
{
qdState->SetForeColor(gs_barHighlightTextColor);
size_t xCoordinate = menu->cumulativeOffset + (menu->menuIndex * 2) * kMenuBarItemPadding + kMenuBarInitialPadding;
qdState->m_penPos.h = static_cast<int16_t>(xCoordinate);
qdState->m_penPos.v = kMenuBarTextYOffset;
DrawString(PLPasStr(static_cast<const uint8_t*>(menu->stringBlobHandle->m_contents)));
}
}
SetGWorld(oldGraf, oldDevice);
m_menuBarGraf->m_port.SetDirty(QDPortDirtyFlag_Contents);
@@ -555,11 +721,23 @@ namespace PortabilityLayer
displayDriver->DrawSurface(m_menuBarGraf->m_ddSurface, 0, 0, width, height);
}
}
if (CGraf *renderedMenu = m_menuSelectionState.GetRenderedMenu())
{
renderedMenu->PushToDDSurface(displayDriver);
Menu *selectedMenu = *m_menuSelectionState.GetSelectedMenu();
const PixMap *pixMap = *renderedMenu->m_port.GetPixMap();
const size_t xCoordinate = kMenuBarInitialPadding + selectedMenu->menuIndex * kMenuBarItemPadding * 2 + selectedMenu->cumulativeOffset - kMenuBarItemPadding;
displayDriver->DrawSurface(renderedMenu->m_ddSurface, xCoordinate, kMenuBarHeight, pixMap->m_rect.right, pixMap->m_rect.bottom);
}
}
void MenuManagerImpl::RefreshMenuLayout()
void MenuManagerImpl::RefreshMenuBarLayout()
{
if (m_haveMenuLayout)
if (m_haveMenuBarLayout)
return;
PortabilityLayer::FontManager *fontManager = PortabilityLayer::FontManager::GetInstance();
@@ -587,16 +765,141 @@ namespace PortabilityLayer
if (pascalStr.Length() == 1 && pascalStr.UChars()[0] == 0x14)
{
measuredWidth += 16;
menu->unpaddedTitleWidth = 16;
menu->isIcon = true;
}
else
measuredWidth += rfont->MeasureString(pascalStr.UChars(), pascalStr.Length());
menu->unpaddedTitleWidth = rfont->MeasureString(pascalStr.UChars(), pascalStr.Length());
measuredWidth += menu->unpaddedTitleWidth;
menuHdl = menu->nextMenu;
}
m_haveMenuLayout = true;
m_haveMenuBarLayout = true;
}
void MenuManagerImpl::RefreshMenuLayout(Menu *menu)
{
if (menu->haveMenuLayout)
return;
PortabilityLayer::FontManager *fontManager = PortabilityLayer::FontManager::GetInstance();
PortabilityLayer::FontFamily *fontFamily = PortabilityLayer::FontManager::GetInstance()->GetSystemFont(kMenuFontSize, kMenuFontFlags);
if (!fontFamily)
return;
PortabilityLayer::RenderedFont *rfont = PortabilityLayer::FontManager::GetInstance()->GetRenderedFontFromFamily(fontFamily, kMenuFontSize, kMenuFontFlags);
if (!rfont)
return;
const uint8_t *strBlob = static_cast<const uint8_t*>(menu->stringBlobHandle->m_contents);
size_t cumulativeHeight = 0;
size_t width = menu->width;
const size_t numItems = menu->numMenuItems;
for (size_t i = 0; i < numItems; i++)
{
MenuItem &item = menu->menuItems[i];
item.layoutYOffset = cumulativeHeight;
item.layoutHeight = kMenuItemHeight;
const uint8_t *itemName = strBlob + item.nameOffsetInStringBlob;
const PLPasStr itemNamePStr = PLPasStr(itemName);
const size_t nameWidth = rfont->MeasureString(itemNamePStr.UChars(), itemNamePStr.Length());
const size_t paddedWidth = nameWidth + kMenuItemLeftPadding + kMenuItemRightPadding;
width = std::max<size_t>(width, paddedWidth);
cumulativeHeight += item.layoutHeight;
}
menu->haveMenuLayout = true;
menu->layoutWidth = width;
menu->layoutHeight = cumulativeHeight;
}
void MenuManagerImpl::ProcessMouseMoveTo(const Vec2i &point)
{
if (point.m_y < 0)
return;
if (point.m_y < static_cast<int>(kMenuBarHeight))
ProcessMouseMoveToMenuBar(point);
else
ProcessMouseMoveToMenu(point);
}
void MenuManagerImpl::ProcessMouseMoveToMenuBar(const Vec2i &point)
{
if (point.m_x < 0)
return;
const uint32_t mouseXCoordinate = static_cast<uint32_t>(point.m_x);
Menu **selectedMenu = nullptr;
Menu **menuHdl = m_firstMenu;
while (menuHdl)
{
Menu *menu = *menuHdl;
uint32_t menuLeftXCoordinate = kMenuBarInitialPadding + menu->cumulativeOffset + menu->menuIndex * kMenuBarItemPadding * 2 - kMenuBarItemPadding;
uint32_t menuRightXCoordinate = menuLeftXCoordinate + menu->unpaddedTitleWidth + kMenuBarItemPadding * 2;
if (mouseXCoordinate >= menuLeftXCoordinate && mouseXCoordinate < menuRightXCoordinate)
{
selectedMenu = menuHdl;
break;
}
menuHdl = menu->nextMenu;
}
if (selectedMenu)
{
bool needRedraw = false;
m_menuSelectionState.HandleSelectionOfMenu(this, menuHdl, needRedraw);
if (needRedraw)
DrawMenuBar();
}
}
void MenuManagerImpl::ProcessMouseMoveToMenu(const Vec2i &point)
{
Menu **selectedMenuHandle = m_menuSelectionState.GetSelectedMenu();
if (selectedMenuHandle)
{
Menu *menu = *selectedMenuHandle;
const int32_t xCoordinate = kMenuBarInitialPadding + menu->menuIndex * kMenuBarItemPadding * 2 + menu->cumulativeOffset - kMenuBarItemPadding;
const Vec2i localPoint = point - Vec2i(xCoordinate, kMenuBarHeight);
if (localPoint.m_x < 0 || localPoint.m_y < 0 || static_cast<size_t>(localPoint.m_x) >= menu->layoutWidth || static_cast<size_t>(localPoint.m_y) >= menu->layoutHeight)
return;
const size_t localY = localPoint.m_y;
for (size_t i = 0; i < menu->numMenuItems; i++)
{
const MenuItem &item = menu->menuItems[i];
if (localY >= item.layoutYOffset && localY - item.layoutYOffset < item.layoutHeight)
{
m_menuSelectionState.SelectItem(i);
return;
}
}
}
m_menuSelectionState.ClearSelection();
}
MenuManagerImpl *MenuManagerImpl::GetInstance()
@@ -606,6 +909,166 @@ namespace PortabilityLayer
MenuManagerImpl MenuManagerImpl::ms_instance;
MenuManagerImpl::MenuSelectionState::MenuSelectionState()
: m_currentMenu(nullptr)
, m_menuGraf(nullptr)
, m_haveItem(false)
, m_itemIndex(0)
{
}
MenuManagerImpl::MenuSelectionState::~MenuSelectionState()
{
Dismiss();
}
void MenuManagerImpl::MenuSelectionState::HandleSelectionOfMenu(MenuManagerImpl *mm, Menu **menuHdl, bool &outNeedRedraw)
{
outNeedRedraw = false;
if (!menuHdl)
return;
if (menuHdl != m_currentMenu)
{
Dismiss();
m_currentMenu = menuHdl;
Menu *menu = *menuHdl;
outNeedRedraw = true;
mm->RefreshMenuLayout(menu);
RenderMenu(menu);
}
}
void MenuManagerImpl::MenuSelectionState::Dismiss()
{
if (m_menuGraf)
{
DisposeGWorld(m_menuGraf);
m_menuGraf = nullptr;
}
m_currentMenu = nullptr;
m_haveItem = false;
}
Menu **MenuManagerImpl::MenuSelectionState::GetSelectedMenu() const
{
return m_currentMenu;
}
CGraf *MenuManagerImpl::MenuSelectionState::GetRenderedMenu() const
{
return m_menuGraf;
}
const unsigned int *MenuManagerImpl::MenuSelectionState::GetSelectedItem() const
{
if (!m_haveItem)
return nullptr;
return &m_itemIndex;
}
void MenuManagerImpl::MenuSelectionState::SelectItem(size_t item)
{
if (m_haveItem && m_itemIndex == item)
return;
m_haveItem = true;
m_itemIndex = item;
if (m_currentMenu)
RenderMenu(*m_currentMenu);
}
void MenuManagerImpl::MenuSelectionState::ClearSelection()
{
if (!m_haveItem)
return;
m_haveItem = false;
if (m_currentMenu)
RenderMenu(*m_currentMenu);
}
void MenuManagerImpl::MenuSelectionState::RenderMenu(Menu *menu)
{
PortabilityLayer::QDManager *qdManager = PortabilityLayer::QDManager::GetInstance();
const Rect menuRect = Rect::Create(0, 0, menu->layoutHeight, menu->layoutWidth);
if (m_menuGraf == nullptr)
{
GpPixelFormat_t pixelFormat;
PortabilityLayer::HostDisplayDriver::GetInstance()->GetDisplayResolution(nullptr, nullptr, &pixelFormat);
if (qdManager->NewGWorld(&m_menuGraf, qdManager->DepthForPixelFormat(pixelFormat), menuRect, nullptr, nullptr, 0) != 0)
return;
}
CGrafPtr oldGraf = nullptr;
GDHandle oldDevice = nullptr;
GetGWorld(&oldGraf, &oldDevice);
SetGWorld(m_menuGraf, nullptr);
QDState *qdState = qdManager->GetState();
qdState->SetForeColor(gs_barMidColor);
{
const Rect rect = Rect::Create(0, 0, menu->layoutHeight, menu->layoutWidth);
PaintRect(&rect);
}
TextFont(systemFont);
TextSize(kMenuFontSize);
const uint8_t *strBlob = static_cast<const uint8_t*>(menu->stringBlobHandle->m_contents);
qdState->m_penPos.h = kMenuItemLeftPadding;
qdState->SetForeColor(gs_barNormalTextColor);
for (size_t i = 0; i < menu->numMenuItems; i++)
{
if (m_haveItem && i == m_itemIndex)
continue;
const MenuItem &item = menu->menuItems[i];
qdState->m_penPos.v = item.layoutYOffset + kMenuItemTextYOffset;
DrawString(PLPasStr(strBlob + item.nameOffsetInStringBlob));
}
if (m_haveItem)
{
const MenuItem &selectedItem = menu->menuItems[m_itemIndex];
qdState->SetForeColor(gs_barHighlightMidColor);
const Rect itemRect = Rect::Create(selectedItem.layoutYOffset, 0, selectedItem.layoutYOffset + selectedItem.layoutHeight, menu->layoutWidth);
PaintRect(&itemRect);
qdState->SetForeColor(gs_barHighlightTextColor);
const MenuItem &item = menu->menuItems[m_itemIndex];
qdState->m_penPos.v = item.layoutYOffset + kMenuItemTextYOffset;
DrawString(PLPasStr(strBlob + item.nameOffsetInStringBlob));
}
m_menuGraf->m_port.SetDirty(QDPortDirtyFlag_Contents);
SetGWorld(oldGraf, oldDevice);
}
MenuManager *MenuManager::GetInstance()
{
return MenuManagerImpl::GetInstance();

View File

@@ -1,10 +1,14 @@
#pragma once
#include <stdint.h>
struct IGpDisplayDriver;
struct Menu;
struct IGpDisplayDriver;
namespace PortabilityLayer
{
struct Vec2i;
class MenuManager
{
public:
@@ -21,6 +25,10 @@ namespace PortabilityLayer
virtual void SetItemEnabled(Menu **menu, unsigned int index, bool enabled) = 0;
virtual void SetItemChecked(Menu **menu, unsigned int index, bool checked) = 0;
virtual bool IsPointInMenuBar(const Vec2i &point) const = 0;
virtual void MenuSelect(const Vec2i &initialPoint, int16_t *outMenu, uint16_t *outItem) = 0;
virtual void DrawMenuBar() = 0;
virtual void RenderFrame(IGpDisplayDriver *displayDriver) = 0;

View File

@@ -7,6 +7,7 @@
#include "FileManager.h"
#include "FilePermission.h"
#include "FontManager.h"
#include "GpVOSEvent.h"
#include "HostDirectoryCursor.h"
#include "HostFileSystem.h"
#include "HostSuspendCallArgument.h"
@@ -27,10 +28,12 @@
#include "PLBigEndian.h"
#include "PLEventQueue.h"
#include "QDManager.h"
#include "Vec2i.h"
#include "WindowDef.h"
#include "WindowManager.h"
#include <assert.h>
#include <algorithm>
static bool ConvertFilenameToSafePStr(const char *str, uint8_t *pstr)
{
@@ -55,16 +58,65 @@ static bool ConvertFilenameToSafePStr(const char *str, uint8_t *pstr)
return true;
}
static void TranslateVOSEvent(const GpVOSEvent *vosEvent, EventRecord *evt)
static void TranslateMouseInputEvent(const GpMouseInputEvent &vosEvent, PortabilityLayer::EventQueue *queue)
{
PL_NotYetImplemented();
if (vosEvent.m_button == GpMouseButtons::kLeft)
{
if (vosEvent.m_eventType == GpMouseEventTypes::kDown)
{
if (EventRecord *evt = queue->Enqueue())
{
evt->what = mouseDown;
evt->where.h = std::min<int32_t>(INT16_MAX, std::max<int32_t>(INT16_MIN, vosEvent.m_x));
evt->where.v = std::min<int32_t>(INT16_MAX, std::max<int32_t>(INT16_MIN, vosEvent.m_y));
}
}
else if (vosEvent.m_eventType == GpMouseEventTypes::kUp)
{
if (EventRecord *evt = queue->Enqueue())
{
evt->what = mouseUp;
evt->where.h = std::min<int32_t>(INT16_MAX, std::max<int32_t>(INT16_MIN, vosEvent.m_x));
evt->where.v = std::min<int32_t>(INT16_MAX, std::max<int32_t>(INT16_MIN, vosEvent.m_y));
}
}
}
else if (vosEvent.m_eventType == GpMouseEventTypes::kMove)
{
if (EventRecord *evt = queue->Enqueue())
{
evt->what = mouseMove;
evt->where.h = std::min<int32_t>(INT16_MAX, std::max<int32_t>(INT16_MIN, vosEvent.m_x));
evt->where.v = std::min<int32_t>(INT16_MAX, std::max<int32_t>(INT16_MIN, vosEvent.m_y));
}
}
}
static void TranslateKeyboardInputEvent(const GpKeyboardInputEvent &vosEvent, PortabilityLayer::EventQueue *queue)
{
}
static void TranslateVOSEvent(const GpVOSEvent *vosEvent, PortabilityLayer::EventQueue *queue)
{
switch (vosEvent->m_eventType)
{
case GpVOSEventTypes::kMouseInput:
TranslateMouseInputEvent(vosEvent->m_event.m_mouseInputEvent, queue);
break;
case GpVOSEventTypes::kKeyboardInput:
TranslateKeyboardInputEvent(vosEvent->m_event.m_keyboardInputEvent, queue);
break;
}
}
static void ImportVOSEvents()
{
PortabilityLayer::EventQueue *plQueue = PortabilityLayer::EventQueue::GetInstance();
PortabilityLayer::HostVOSEventQueue *evtQueue = PortabilityLayer::HostVOSEventQueue::GetInstance();
while (const GpVOSEvent *evt = evtQueue->GetNext())
{
TranslateVOSEvent(evt, plQueue);
evtQueue->DischargeOne();
}
}
@@ -184,8 +236,10 @@ Handle GetResource(const char(&resTypeLiteral)[5], int id)
short FindWindow(Point point, WindowPtr *window)
{
PL_NotYetImplemented();
return 0;
short part = 0;
PortabilityLayer::WindowManager::GetInstance()->FindWindow(point, window, &part);
return part;
}
void DragWindow(WindowPtr window, Point start, Rect *bounds)
@@ -309,6 +363,22 @@ void SetWTitle(WindowPtr window, const PLPasStr &title)
PL_NotYetImplemented();
}
bool PeekNextEvent(int32_t eventMask, EventRecord *event)
{
assert(eventMask == everyEvent); // We don't support other use cases
PortabilityLayer::EventQueue *queue = PortabilityLayer::EventQueue::GetInstance();
const EventRecord *record = queue->Peek();
if (record)
{
*event = *record;
return PL_TRUE;
}
else
return PL_FALSE;
}
bool GetNextEvent(int32_t eventMask, EventRecord *event)
{
assert(eventMask == everyEvent); // We don't support other use cases
@@ -319,8 +389,12 @@ bool GetNextEvent(int32_t eventMask, EventRecord *event)
long MenuSelect(Point point)
{
PL_NotYetImplemented();
return noErr;
int16_t menuID = 0;
uint16_t menuItem = 0;
PortabilityLayer::MenuManager::GetInstance()->MenuSelect(PortabilityLayer::Vec2i(point.h, point.v), &menuID, &menuItem);
return (static_cast<int32_t>(menuID) << 16) | (static_cast<int32_t>(menuItem));
}
long MenuKey(int charCode)
@@ -357,7 +431,8 @@ bool BitTst(const KeyMap *keyMap, int bit)
void NumToString(long number, unsigned char *str)
{
PL_NotYetImplemented();
PL_NotYetImplemented_TODO("Strings");
str[0] = 0;
}
void ParamText(const PLPasStr &title, const PLPasStr &a, const PLPasStr &b, const PLPasStr &c)
@@ -701,7 +776,11 @@ UInt32 GetDblTime()
void FlushEvents(int mask, int unknown)
{
PL_NotYetImplemented();
PortabilityLayer::EventQueue *queue = PortabilityLayer::EventQueue::GetInstance();
while (queue->Dequeue(nullptr))
{
}
}
void ExitToShell()
@@ -783,12 +862,6 @@ void DisposePtr(void *ptr)
PL_NotYetImplemented();
}
Size MaxMem(Size *growBytes)
{
PL_NotYetImplemented();
return 0;
}
void PurgeSpace(long *totalFree, long *contiguousFree)
{
PL_NotYetImplemented();

View File

@@ -186,8 +186,7 @@ typedef unsigned char KeyMap[16];
enum RegionID
{
inDesk,
inMenuBar,
inMenuBar = 1,
inSysWindow,
inContent,
inDrag,
@@ -206,6 +205,7 @@ enum EventCode
{
mouseDown,
mouseUp,
mouseMove,
keyDown,
autoKey,
updateEvt,
@@ -307,6 +307,7 @@ void MoveWindow(WindowPtr window, int x, int y, Boolean moveToFront);
void ShowWindow(WindowPtr window);
void SetWTitle(WindowPtr window, const PLPasStr &title);
bool PeekNextEvent(int32_t eventMask, EventRecord *event);
bool GetNextEvent(int32_t eventMask, EventRecord *event);
long MenuSelect(Point point); // Breaks into menu select routine (in practice we'll just forward one from the queue?)

View File

@@ -11,6 +11,7 @@ namespace PortabilityLayer
~EventQueueImpl();
bool Dequeue(EventRecord *evt) override;
const EventRecord *Peek() const override;
EventRecord *Enqueue() override;
static EventQueueImpl *GetInstance();
@@ -40,7 +41,8 @@ namespace PortabilityLayer
if (m_numQueuedEvents == 0)
return false;
*evt = m_events[m_firstEvent];
if (evt)
*evt = m_events[m_firstEvent];
m_firstEvent++;
if (m_firstEvent == kMaxEvents)
@@ -51,6 +53,15 @@ namespace PortabilityLayer
return true;
}
const EventRecord *EventQueueImpl::Peek() const
{
if (m_numQueuedEvents == 0)
return nullptr;
return m_events + m_firstEvent;
}
EventRecord *EventQueueImpl::Enqueue()
{
if (m_numQueuedEvents == kMaxEvents)

View File

@@ -2,14 +2,15 @@
#include "PLCore.h"
#include <stdint.h>
#include <stdint.h>
namespace PortabilityLayer
{
{
class EventQueue
{
public:
virtual bool Dequeue(EventRecord *evt) = 0;
virtual const EventRecord *Peek() const = 0;
virtual EventRecord *Enqueue() = 0;
static EventQueue *GetInstance();

View File

@@ -60,7 +60,7 @@ void DrawMenuBar()
void HiliteMenu(int menu)
{
PL_NotYetImplemented();
// Don't know what this does
}
void EnableMenuItem(MenuHandle menu, int index)

View File

@@ -232,7 +232,7 @@ namespace PortabilityLayer
}
}
OSErr NewGWorld(GWorldPtr *gworld, int depth, Rect *bounds, CTabHandle colorTable, GDHandle device, int flags)
OSErr NewGWorld(GWorldPtr *gworld, int depth, const Rect *bounds, CTabHandle colorTable, GDHandle device, int flags)
{
return PortabilityLayer::QDManager::GetInstance()->NewGWorld(gworld, depth, *bounds, colorTable, device, flags);
}
@@ -301,6 +301,7 @@ void DrawPicture(PicHandle pict, Rect *bounds)
switch (pixMap->GetPixelFormat())
{
case GpPixelFormats::kBW1:
case GpPixelFormats::k8BitStandard:
{
PortabilityLayer::PixMapBlitEmitter blitEmitter(PortabilityLayer::Vec2i(bounds->left, bounds->top), pixMap);

View File

@@ -25,7 +25,7 @@ enum QDFlags
useTempMem = 1,
};
OSErr NewGWorld(GWorldPtr *gworld, int depth, Rect *bounds, CTabHandle colorTable, GDHandle device, int flags);
OSErr NewGWorld(GWorldPtr *gworld, int depth, const Rect *bounds, CTabHandle colorTable, GDHandle device, int flags);
void DisposeGWorld(GWorldPtr gworld);
PixMapHandle GetGWorldPixMap(GWorldPtr gworld);

View File

@@ -534,9 +534,7 @@ void GetIndPattern(Pattern *pattern, int patListID, int index)
memcpy(pattern, patternRes + 2 + (index - 1) * 8, 8);
}
void CopyBits(const BitMap *srcBitmap, BitMap *destBitmap, const Rect *srcRect, const Rect *destRect, CopyBitsMode copyMode, RgnHandle maskRegion)
static void CopyBitsComplete(const BitMap *srcBitmap, const BitMap *maskBitmap, BitMap *destBitmap, const Rect *srcRectBase, const Rect *maskRectBase, const Rect *destRectBase, RgnHandle maskRegion)
{
assert(srcBitmap->m_pixelFormat == destBitmap->m_pixelFormat);
@@ -546,30 +544,84 @@ void CopyBits(const BitMap *srcBitmap, BitMap *destBitmap, const Rect *srcRect,
const size_t srcPitch = srcBitmap->m_pitch;
const size_t destPitch = destBitmap->m_pitch;
assert(srcRect->top >= srcBounds.top);
assert(srcRect->bottom <= srcBounds.bottom);
assert(srcRect->left >= srcBounds.left);
assert(srcRect->right <= srcBounds.right);
assert(srcRectBase->right - srcRectBase->left == destRectBase->right - destRectBase->left);
assert(srcRectBase->bottom - srcRectBase->top == destRectBase->bottom - destRectBase->top);
assert(destRect->top >= destBounds.top);
assert(destRect->bottom <= destBounds.bottom);
assert(destRect->left >= destBounds.left);
assert(destRect->right <= destBounds.right);
if (maskBitmap)
{
assert(maskRectBase);
assert(maskRectBase->right - maskRectBase->left == destRectBase->right - destRectBase->left);
}
assert(srcRect->right - srcRect->left == destRect->right - destRect->left);
assert(srcRect->bottom - srcRect->top == destRect->bottom - destRect->top);
assert((maskBitmap == nullptr) == (maskRectBase == nullptr));
const Region *mask = *maskRegion;
Rect srcRect;
Rect destRect;
Rect maskRect;
const Rect constrainedDestRect = destRect->Intersect(mask->rect);
{
const Rect constrainedSrcRect = srcRectBase->Intersect(srcBounds);
const Rect constrainedDestRect = destRectBase->Intersect(destBounds);
const int32_t leftNudge = std::max(constrainedSrcRect.left - srcRectBase->left, constrainedDestRect.left - destRectBase->left);
const int32_t topNudge = std::max(constrainedSrcRect.top - srcRectBase->top, constrainedDestRect.top - destRectBase->top);
const int32_t bottomNudge = std::min(constrainedSrcRect.bottom - srcRectBase->bottom, constrainedDestRect.bottom - destRectBase->bottom);
const int32_t rightNudge = std::min(constrainedSrcRect.right - srcRectBase->right, constrainedDestRect.right - destRectBase->right);
const int32_t srcLeft = srcRectBase->left + leftNudge;
const int32_t srcRight = srcRectBase->right + rightNudge;
const int32_t srcTop = srcRectBase->top + topNudge;
const int32_t srcBottom = srcRectBase->bottom + bottomNudge;
if (srcTop >= srcBottom)
return;
if (srcLeft >= srcRight)
return;
srcRect.left = srcLeft;
srcRect.right = srcRight;
srcRect.top = srcTop;
srcRect.bottom = srcBottom;
destRect.left = destRectBase->left + leftNudge;
destRect.right = destRectBase->right + rightNudge;
destRect.top = destRectBase->top + topNudge;
destRect.bottom = destRectBase->bottom + bottomNudge;
if (maskRectBase)
{
maskRect.left = maskRectBase->left + leftNudge;
maskRect.right = maskRectBase->right + rightNudge;
maskRect.top = maskRectBase->top + topNudge;
maskRect.bottom = maskRectBase->bottom + bottomNudge;
}
}
assert(srcRect.top >= srcBounds.top);
assert(srcRect.bottom <= srcBounds.bottom);
assert(srcRect.left >= srcBounds.left);
assert(srcRect.right <= srcBounds.right);
assert(destRect.top >= destBounds.top);
assert(destRect.bottom <= destBounds.bottom);
assert(destRect.left >= destBounds.left);
assert(destRect.right <= destBounds.right);
const Region *mask = nullptr;
if (maskRegion)
mask = *maskRegion;
const Rect constrainedDestRect = mask ? destRect.Intersect(mask->rect) : destRect;
if (!constrainedDestRect.IsValid())
return;
Rect constrainedSrcRect = *srcRect;
constrainedSrcRect.left += constrainedDestRect.left - destRect->left;
constrainedSrcRect.right += constrainedDestRect.right - destRect->right;
constrainedSrcRect.top += constrainedDestRect.top - destRect->top;
constrainedSrcRect.bottom += constrainedDestRect.bottom - destRect->bottom;
Rect constrainedSrcRect = srcRect;
constrainedSrcRect.left += constrainedDestRect.left - destRect.left;
constrainedSrcRect.right += constrainedDestRect.right - destRect.right;
constrainedSrcRect.top += constrainedDestRect.top - destRect.top;
constrainedSrcRect.bottom += constrainedDestRect.bottom - destRect.bottom;
const size_t srcFirstCol = constrainedSrcRect.left - srcBitmap->m_rect.left;
const size_t srcFirstRow = constrainedSrcRect.top - srcBitmap->m_rect.top;
@@ -577,7 +629,7 @@ void CopyBits(const BitMap *srcBitmap, BitMap *destBitmap, const Rect *srcRect,
const size_t destFirstCol = constrainedDestRect.left - destBitmap->m_rect.left;
const size_t destFirstRow = constrainedDestRect.top - destBitmap->m_rect.top;
if (mask->size != sizeof(Region))
if (mask && mask->size != sizeof(Region))
{
PL_NotYetImplemented();
}
@@ -608,8 +660,8 @@ void CopyBits(const BitMap *srcBitmap, BitMap *destBitmap, const Rect *srcRect,
const size_t firstSrcByte = srcFirstRow * srcPitch + srcFirstCol * pixelSizeBytes;
const size_t firstDestByte = destFirstRow * destPitch + destFirstCol * pixelSizeBytes;
const size_t numCopiedRows = srcRect->bottom - srcRect->top;
const size_t numCopiedCols = srcRect->right - srcRect->left;
const size_t numCopiedRows = srcRect.bottom - srcRect.top;
const size_t numCopiedCols = srcRect.right - srcRect.left;
const size_t numCopiedBytesPerScanline = numCopiedCols * pixelSizeBytes;
for (size_t i = 0; i < numCopiedRows; i++)
@@ -617,11 +669,15 @@ void CopyBits(const BitMap *srcBitmap, BitMap *destBitmap, const Rect *srcRect,
}
}
void CopyMask(const BitMap *srcBitmap, const BitMap *maskBitmap, BitMap *destBitmap, const Rect *srcRect, const Rect *maskRect, const Rect *destRect)
void CopyBits(const BitMap *srcBitmap, BitMap *destBitmap, const Rect *srcRectBase, const Rect *destRectBase, CopyBitsMode copyMode, RgnHandle maskRegion)
{
PL_NotYetImplemented();
CopyBitsComplete(srcBitmap, nullptr, destBitmap, srcRectBase, nullptr, destRectBase, maskRegion);
}
void CopyMask(const BitMap *srcBitmap, const BitMap *maskBitmap, BitMap *destBitmap, const Rect *srcRectBase, const Rect *maskRectBase, const Rect *destRectBase)
{
CopyBitsComplete(srcBitmap, maskBitmap, destBitmap, srcRectBase, maskRectBase, destRectBase, nullptr);
}
RgnHandle NewRgn()
{
@@ -725,8 +781,9 @@ void SubPt(Point srcPoint, Point *destPoint)
Boolean SectRect(const Rect *rectA, const Rect *rectB, Rect *outIntersection)
{
PL_NotYetImplemented();
return false;
*outIntersection = rectA->Intersect(*rectB);
return outIntersection->IsValid() ? PL_TRUE : PL_FALSE;
}
@@ -760,3 +817,15 @@ void BitMap::Init(const Rect &rect, GpPixelFormat_t pixelFormat, size_t pitch, v
m_pitch = pitch;
m_data = dataPtr;
}
#include "stb_image_write.h"
void DebugPixMap(PixMap **pixMapH, const char *outName)
{
PixMap *pixMap = *pixMapH;
char outPath[1024];
strcpy_s(outPath, outName);
strcat_s(outPath, ".png");
stbi_write_png(outPath, pixMap->m_rect.right - pixMap->m_rect.left, pixMap->m_rect.bottom - pixMap->m_rect.top, 1, pixMap->m_data, pixMap->m_pitch);
}

View File

@@ -148,6 +148,7 @@ Pattern *GetQDGlobalsBlack(Pattern *pattern);
// Index is 1-based
void GetIndPattern(Pattern *pattern, int patListID, int index);
void DebugPixMap(PixMap **pixMap, const char *outName);
void CopyBits(const BitMap *srcBitmap, BitMap *destBitmap, const Rect *srcRect, const Rect *destRect, CopyBitsMode copyMode, RgnHandle maskRegion);
void CopyMask(const BitMap *srcBitmap, const BitMap *maskBitmap, BitMap *destBitmap, const Rect *srcRect, const Rect *maskRect, const Rect *destRect);

View File

@@ -60,21 +60,25 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\Common.props" />
<Import Project="..\GpCommon.props" />
<Import Project="..\stb.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\Common.props" />
<Import Project="..\GpCommon.props" />
<Import Project="..\stb.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\Common.props" />
<Import Project="..\GpCommon.props" />
<Import Project="..\stb.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\Common.props" />
<Import Project="..\GpCommon.props" />
<Import Project="..\stb.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
@@ -241,6 +245,7 @@
<ClInclude Include="XModemCRC.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\stb\stb_image_write.c" />
<ClCompile Include="AEManager.cpp" />
<ClCompile Include="BinHex4.cpp" />
<ClCompile Include="ByteSwap.cpp" />

View File

@@ -361,7 +361,7 @@
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="SimpleGraphic.h">
<Filter>Source Files</Filter>
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
@@ -545,5 +545,8 @@
<ClCompile Include="SimpleGraphic.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\stb\stb_image_write.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -6,6 +6,8 @@
#include "QDGraf.h"
#include "QDState.h"
#include <assert.h>
namespace PortabilityLayer
{
class QDManagerImpl final : public QDManager
@@ -20,6 +22,8 @@ namespace PortabilityLayer
void DisposeGWorld(CGraf *gw) override;
QDState *GetState() override;
int DepthForPixelFormat(GpPixelFormat_t pixelFormat) const override;
static QDManagerImpl *GetInstance();
private:
@@ -59,6 +63,9 @@ namespace PortabilityLayer
switch (depth)
{
case 1:
pixelFormat = GpPixelFormats::kBW1;
break;
case 8:
pixelFormat = (colorTable == nullptr) ? GpPixelFormats::k8BitStandard : GpPixelFormats::k8BitCustom;
break;
@@ -72,9 +79,6 @@ namespace PortabilityLayer
return genericErr;
}
if (depth != 8)
return genericErr;
void *grafStorage = MemoryManager::GetInstance()->Alloc(sizeof(CGraf));
if (!grafStorage)
return mFulErr;
@@ -105,6 +109,25 @@ namespace PortabilityLayer
return m_port->GetState();
}
int QDManagerImpl::DepthForPixelFormat(GpPixelFormat_t pixelFormat) const
{
switch (pixelFormat)
{
case GpPixelFormats::k8BitStandard:
case GpPixelFormats::k8BitCustom:
return 8;
case GpPixelFormats::kRGB555:
return 16;
case GpPixelFormats::kRGB24:
return 24;
case GpPixelFormats::kRGB32:
return 32;
default:
assert(false);
return 0;
}
}
QDManagerImpl *QDManagerImpl::GetInstance()
{
return &ms_instance;

View File

@@ -1,5 +1,7 @@
#pragma once
#include "GpPixelFormat.h"
struct ColorTable;
struct CGraf;
struct GDevice;
@@ -21,6 +23,8 @@ namespace PortabilityLayer
virtual QDState *GetState() = 0;
virtual int DepthForPixelFormat(GpPixelFormat_t pixelFormat) const = 0;
static QDManager *GetInstance();
};
}

View File

@@ -42,7 +42,8 @@ namespace PortabilityLayer
switch (pixelFormat)
{
case GpPixelFormats::k8BitCustom:
case GpPixelFormats::k8BitStandard:
case GpPixelFormats::k8BitStandard:
case GpPixelFormats::kBW1:
rowByteCount = width;
break;
case GpPixelFormats::kRGB555:
@@ -53,7 +54,7 @@ namespace PortabilityLayer
break;
case GpPixelFormats::kRGB32:
rowByteCount = width * 4;
break;
break;
default:
assert(false);
return 0;

View File

@@ -150,7 +150,7 @@ namespace PortabilityLayer
const int gGrayDelta = static_cast<int>(g * 3) - static_cast<int>(grayscaleTimes3);
const int bGrayDelta = static_cast<int>(b * 3) - static_cast<int>(grayscaleTimes3);
if (rGrayDelta >= -3 && rGrayDelta <= 3 && gGrayDelta >= -3 && gGrayDelta <= -3 && bGrayDelta >= -3 && bGrayDelta <= -3)
if (rGrayDelta >= -3 && rGrayDelta <= 3 && gGrayDelta >= -3 && gGrayDelta <= 3 && bGrayDelta >= -3 && bGrayDelta <= 3)
{
// Divide down to 0..15 range
const unsigned int grayscaleValue = (grayscaleTimes3 * 21 + 36) >> 6;
@@ -167,7 +167,7 @@ namespace PortabilityLayer
else if (grayscale6Step == 5)
return 0;
else
return 180 - 36 * grayscale6Step;
return 215 - 43 * grayscale6Step;
}
else
return 255 - grayscale6Step * 2 - grayscale6StepRemainder;

View File

@@ -7,9 +7,11 @@
#include "PLCore.h"
#include "PLEventQueue.h"
#include "MemoryManager.h"
#include "MenuManager.h"
#include "QDGraf.h"
#include "QDManager.h"
#include "QDPixMap.h"
#include "Vec2i.h"
#include "WindowDef.h"
struct GDevice;
@@ -58,6 +60,7 @@ namespace PortabilityLayer
void ShowWindow(Window *window) override;
void HideWindow(Window *window) override;
GDevice **GetWindowDevice(Window *window) override;
void FindWindow(const Point &point, Window **outWindow, short *outRegion) const override;
void RenderFrame(IGpDisplayDriver *displayDriver) override;
@@ -245,6 +248,60 @@ namespace PortabilityLayer
return static_cast<WindowImpl*>(window)->GetDevice();
}
void WindowManagerImpl::FindWindow(const Point &point, Window **outWindow, short *outRegion) const
{
// outRegion = One of:
/*
inMenuBar,
inSysWindow,
inContent,
inDrag,
inGrow,
inGoAway,
inZoomIn,
inZoomOut,
*/
if (PortabilityLayer::MenuManager::GetInstance()->IsPointInMenuBar(PortabilityLayer::Vec2i(point.h, point.v)))
{
if (outWindow)
*outWindow = nullptr;
if (outRegion)
*outRegion = inMenuBar;
return;
}
WindowImpl *window = m_windowStackTop;
while (window)
{
const Rect windowRect = window->m_graf.m_port.GetRect();
const int32_t localX = point.h - window->m_wmX;
const int32_t localY = point.v - window->m_wmY;
if (localX >= 0 && localY >= 0 && localX < windowRect.right && localY < windowRect.bottom)
{
if (outWindow)
*outWindow = window;
if (outRegion)
*outRegion = inContent;
return;
}
window = window->GetWindowBelow();
}
if (outWindow)
*outWindow = nullptr;
if (outRegion)
*outRegion = 0;
}
void WindowManagerImpl::RenderFrame(IGpDisplayDriver *displayDriver)
{
GDevice **mainDeviceHdl = PortabilityLayer::DisplayDeviceManager::GetInstance()->GetMainDevice();

View File

@@ -4,6 +4,8 @@ struct Window;
struct CGraf;
struct GDevice;
struct IGpDisplayDriver;
struct Point;
struct Window;
namespace PortabilityLayer
{
@@ -20,6 +22,7 @@ namespace PortabilityLayer
virtual void ShowWindow(Window *window) = 0;
virtual void HideWindow(Window *window) = 0;
virtual GDevice **GetWindowDevice(Window *window) = 0;
virtual void FindWindow(const Point &point, Window **outWindow, short *outRegion) const = 0;
virtual void RenderFrame(IGpDisplayDriver *displayDriver) = 0;

View File

@@ -17,3 +17,12 @@ Other parts:
- FTagData: Copies a data-only file to a .gpd and creates a .gpf for it
- ImportCharSet: Imports the Unicode MacRoman description into a code page table.
- PictChecker: Experimental app that extracts all of the PICT resources from all of the houses and dumps them to PNG. Used to verify that the PICT loader works.
GlidePort is intended to be primarily a straight port, retaining most of the look and feel of the original.
Planned additions:
- 32-bit color support (mainly matters for houses that have higher-resolution PICT resources)
- Resolution changes while the game is running
- Bring back the gray-to-color intro fade that was removed in later versions
- Gamepad support