From 311160953632d7fb19571684a0457031d5df80fd Mon Sep 17 00:00:00 2001 From: elasota Date: Tue, 24 Dec 2019 02:35:24 -0500 Subject: [PATCH] Menu work, move VOS queue interface --- GpApp/GpAppInterface.cpp | 2 + GpCommon/GpDisplayDriverProperties.h | 3 + GpCommon/GpVOSEvent.h | 80 +++- GpCommon/GpWindows.h | 2 + GpCommon/IGpVOSEventQueue.h | 11 + .../{HostVOSEventQueue.h => SimpleGraphic.h} | 0 GpD3D/GpAppEnvironment.cpp | 8 +- GpD3D/GpAppEnvironment.h | 3 +- GpD3D/GpD3D.rc | Bin 3484 -> 5270 bytes GpD3D/GpMain.cpp | 3 + GpD3D/GpMain_Win32.cpp | 66 ++++ GpD3D/GpPLGlueDisplayDriver.cpp | 64 ++-- GpD3D/GpVOSEventQueue.h | 6 +- .../GpDisplayDriverD3D11.cpp | 27 +- PortabilityLayer/FontManager.cpp | 12 + PortabilityLayer/FontManager.h | 1 + PortabilityLayer/FontRenderer.cpp | 15 + PortabilityLayer/HostVOSEventQueue.h | 7 +- PortabilityLayer/MenuManager.cpp | 348 +++++++++++++++++- PortabilityLayer/MenuManager.h | 10 +- PortabilityLayer/PLCore.cpp | 7 + PortabilityLayer/PLEventQueue.cpp | 4 +- PortabilityLayer/PLMenus.cpp | 3 +- PortabilityLayer/PLQDOffscreen.cpp | 2 +- PortabilityLayer/PortabilityLayer.vcxproj | 2 + .../PortabilityLayer.vcxproj.filters | 6 + PortabilityLayer/QDGraf.cpp | 30 ++ PortabilityLayer/QDGraf.h | 5 +- PortabilityLayer/QDManager.cpp | 7 + PortabilityLayer/QDManager.h | 1 + PortabilityLayer/RenderedFont.h | 5 +- PortabilityLayer/SimpleGraphic.cpp | 100 +++++ PortabilityLayer/SimpleGraphic.h | 56 +++ PortabilityLayer/WindowManager.cpp | 24 +- 34 files changed, 828 insertions(+), 92 deletions(-) create mode 100644 GpCommon/IGpVOSEventQueue.h rename GpCommon/{HostVOSEventQueue.h => SimpleGraphic.h} (100%) create mode 100644 PortabilityLayer/SimpleGraphic.cpp create mode 100644 PortabilityLayer/SimpleGraphic.h diff --git a/GpApp/GpAppInterface.cpp b/GpApp/GpAppInterface.cpp index 37392a5..34ea0ca 100644 --- a/GpApp/GpAppInterface.cpp +++ b/GpApp/GpAppInterface.cpp @@ -7,6 +7,7 @@ #include "HostDisplayDriver.h" #include "HostSystemServices.h" #include "HostVOSEventQueue.h" +#include "MenuManager.h" #include "WindowManager.h" int gpAppMain(); @@ -40,6 +41,7 @@ void GpAppInterfaceImpl::PL_IncrementTickCounter(uint32_t count) void GpAppInterfaceImpl::PL_Render(IGpDisplayDriver *displayDriver) { PortabilityLayer::WindowManager::GetInstance()->RenderFrame(displayDriver); + PortabilityLayer::MenuManager::GetInstance()->RenderFrame(displayDriver); } void GpAppInterfaceImpl::PL_HostFileSystem_SetInstance(PortabilityLayer::HostFileSystem *instance) diff --git a/GpCommon/GpDisplayDriverProperties.h b/GpCommon/GpDisplayDriverProperties.h index 474c2d0..19efbee 100644 --- a/GpCommon/GpDisplayDriverProperties.h +++ b/GpCommon/GpDisplayDriverProperties.h @@ -4,6 +4,7 @@ struct IGpDisplayDriver; struct IGpFiber; +struct IGpVOSEventQueue; struct GpDisplayDriverProperties { @@ -29,4 +30,6 @@ struct GpDisplayDriverProperties RenderFunc_t m_renderFunc; void *m_renderFuncContext; + + IGpVOSEventQueue *m_eventQueue; }; diff --git a/GpCommon/GpVOSEvent.h b/GpCommon/GpVOSEvent.h index e732d27..3e76993 100644 --- a/GpCommon/GpVOSEvent.h +++ b/GpCommon/GpVOSEvent.h @@ -1,5 +1,14 @@ #pragma once +namespace GpKeyModifiers +{ + enum GpKeyModifier + { + kShift, + kCtrl, + }; +} + namespace GpKeyIDSubsets { enum GpKeyIDSubset @@ -43,9 +52,9 @@ namespace GpKeySpecials typedef GpKeySpecials::GpKeySpecial GpKeySpecial_t; -namespace GpInputEventTypes +namespace GpKeyboardInputEventTypes { - enum GpInputEventType + enum GpKeyboardInputEventType { kDown, kUp, @@ -53,19 +62,9 @@ namespace GpInputEventTypes }; } -typedef GpInputEventTypes::GpInputEventType GpInputEventType_t; +typedef GpKeyboardInputEventTypes::GpKeyboardInputEventType GpKeyboardInputEventType_t; -namespace GpVOSEventTypes -{ - enum GpVOSEventType - { - kInput, - }; -} - -typedef GpVOSEventTypes::GpVOSEventType GpVOSEventType_t; - -struct GpInputEvent +struct GpKeyboardInputEvent { union KeyUnion { @@ -73,17 +72,66 @@ struct GpInputEvent char m_asciiChar; }; - GpInputEventType_t m_eventType; + GpKeyboardInputEventType_t m_eventType; GpKeyIDSubset_t m_keyIDSubset; KeyUnion m_key; }; +namespace GpMouseEventTypes +{ + enum GpMouseEventType + { + kUp, + kDown, + kMove, + kLeave, + }; +} + +typedef GpMouseEventTypes::GpMouseEventType GpMouseEventType_t; + +namespace GpMouseButtons +{ + enum GpMouseButton + { + kNone, + kLeft, + kMiddle, + kRight, + kX1, + kX2, + }; +} + +typedef GpMouseButtons::GpMouseButton GpMouseButton_t; + +struct GpMouseInputEvent +{ + int32_t m_x; + int32_t m_y; + GpMouseEventType_t m_eventType; + GpMouseButton_t m_button; +}; + +namespace GpVOSEventTypes +{ + enum GpVOSEventType + { + kKeyboardInput, + kMouseInput, + }; +} + +typedef GpVOSEventTypes::GpVOSEventType GpVOSEventType_t; + struct GpVOSEvent { union EventUnion { - GpInputEvent m_inputEvent; + GpKeyboardInputEvent m_keyboardInputEvent; + GpMouseInputEvent m_mouseInputEvent; }; + EventUnion m_event; GpVOSEventType_t m_eventType; }; diff --git a/GpCommon/GpWindows.h b/GpCommon/GpWindows.h index 8e559f0..b9213a6 100644 --- a/GpCommon/GpWindows.h +++ b/GpCommon/GpWindows.h @@ -10,6 +10,7 @@ struct IGpFiber; struct IGpColorCursor_Win32; +struct IGpVOSEventQueue; struct GpWindowsGlobals { @@ -21,5 +22,6 @@ struct GpWindowsGlobals IGpFiber *(*m_createFiberFunc)(LPVOID fiber); IGpColorCursor_Win32 *(*m_loadColorCursorFunc)(const wchar_t *path); + void (*m_translateWindowsMessageFunc)(const MSG *msg, IGpVOSEventQueue *eventQueue); }; diff --git a/GpCommon/IGpVOSEventQueue.h b/GpCommon/IGpVOSEventQueue.h new file mode 100644 index 0000000..7d1d56d --- /dev/null +++ b/GpCommon/IGpVOSEventQueue.h @@ -0,0 +1,11 @@ +#pragma once + +struct GpVOSEvent; + +struct IGpVOSEventQueue +{ + virtual const GpVOSEvent *GetNext() = 0; + virtual void DischargeOne() = 0; + + virtual GpVOSEvent *QueueEvent() = 0; +}; diff --git a/GpCommon/HostVOSEventQueue.h b/GpCommon/SimpleGraphic.h similarity index 100% rename from GpCommon/HostVOSEventQueue.h rename to GpCommon/SimpleGraphic.h diff --git a/GpD3D/GpAppEnvironment.cpp b/GpD3D/GpAppEnvironment.cpp index 89a8c11..cebd152 100644 --- a/GpD3D/GpAppEnvironment.cpp +++ b/GpD3D/GpAppEnvironment.cpp @@ -14,6 +14,7 @@ GpAppEnvironment::GpAppEnvironment() , m_displayDriver(nullptr) , m_audioDriver(nullptr) , m_fontHandler(nullptr) + , m_vosEventQueue(nullptr) , m_applicationFiber(nullptr) , m_vosFiber(nullptr) , m_suspendCallID(PortabilityLayer::HostSuspendCallID_Unknown) @@ -100,6 +101,11 @@ void GpAppEnvironment::SetFontHandler(PortabilityLayer::HostFontHandler *fontHan m_fontHandler = fontHandler; } +void GpAppEnvironment::SetVOSEventQueue(GpVOSEventQueue *eventQueue) +{ + m_vosEventQueue = eventQueue; +} + void GpAppEnvironment::StaticAppThreadFunc(void *context) { static_cast(context)->AppThreadFunc(); @@ -117,7 +123,7 @@ void GpAppEnvironment::InitializeApplicationState() GpAppInterface_Get()->PL_InstallHostSuspendHook(GpAppEnvironment::StaticSuspendHookFunc, this); GpAppInterface_Get()->PL_HostFontHandler_SetInstance(m_fontHandler); - GpAppInterface_Get()->PL_HostVOSEventQueue_SetInstance(&m_vosEventQueue); + GpAppInterface_Get()->PL_HostVOSEventQueue_SetInstance(m_vosEventQueue); SynchronizeState(); } diff --git a/GpD3D/GpAppEnvironment.h b/GpD3D/GpAppEnvironment.h index f358836..417927f 100644 --- a/GpD3D/GpAppEnvironment.h +++ b/GpD3D/GpAppEnvironment.h @@ -30,6 +30,7 @@ public: void SetDisplayDriver(IGpDisplayDriver *displayDriver); void SetAudioDriver(IGpAudioDriver *audioDriver); void SetFontHandler(PortabilityLayer::HostFontHandler *fontHandler); + void SetVOSEventQueue(GpVOSEventQueue *eventQueue); private: enum ApplicationState @@ -54,7 +55,7 @@ private: IGpDisplayDriver *m_displayDriver; IGpAudioDriver *m_audioDriver; PortabilityLayer::HostFontHandler *m_fontHandler; - GpVOSEventQueue m_vosEventQueue; + GpVOSEventQueue *m_vosEventQueue; IGpFiber *m_applicationFiber; IGpFiber *m_vosFiber; diff --git a/GpD3D/GpD3D.rc b/GpD3D/GpD3D.rc index 1abaef50607be0d31bde6df0961d6bb31281a142..3adbcb0f9439782f3c754e2ec3cce5abacff92a4 100644 GIT binary patch literal 5270 zcmdUzU2hsk6o$`rrT&NM`leB%*d)1VFJmAS6@z6kY9&j^0oz5g!D1n4rT+G|&pX4g zA1pL>Q;BM{%+Ac2Gw+=5<*z@F?bw{1+0@3iu(_o?x3*+%$XseGyS95qb^DIy?9Og% z#m$Hm+ zk<#2Axc?IANDc#T{WHI9Ze8b|l1G#I*F0s7{Id=|dHIHYMfo3|#3G_#9V=udOSf=9`cvqd1M_5;fCcb~r+|Hc?cwAt^BX)J!|H7ZzVYbWcC4I}=X`BgkEqJ%_ z)gSF8y!+6dG86WcDMqXYuMQTVyX>|A`Nxo({KTn^|6MGo_VQ>G>h;u+Sv95e>!;kk zsh zZk&DewZqD1t4AoVeRZIULD_t=sXF<6z4|~Oa-$HpiCJx;o$3gA)V>z!_R-|m68H+mM=&is zvI$YLSU06u{}oa18Vc1}HGJ-S@JR~uTt!sID$m^4{yVIFDv}`8U09<{i?x!DbRnt?TXT=cAJZrN&{t8Q{)KlmGc;J293vOQHn&_N+DBd{xfTv1pyP|6~#{DRY-V#qgA!fy= zw&U*Ad?k5B?FGH!N|)aU#*uT2tkA%g8=P>1Rcj^KRODCei?ZuLf9Lrs7C({&r1?AY z*K%{h_KNE4y03d*bE_I!RVA*SW8M_4_3f+5`zcs@>$7Efx@ojMjlSHC&pBm|9jw5* ztdM5eN}h6qBJXNTsC|YdWL0L=-S$k;XNSmWv60wwytQZ-1GrtIhZH^N`zh~Bik-oi z^SetDisplayDriver(displayDriver); appEnvironment->SetAudioDriver(audioDriver); appEnvironment->SetFontHandler(fontHandler); + appEnvironment->SetVOSEventQueue(eventQueue); // Start the display loop displayDriver->Run(); diff --git a/GpD3D/GpMain_Win32.cpp b/GpD3D/GpMain_Win32.cpp index 0000839..70f3457 100644 --- a/GpD3D/GpMain_Win32.cpp +++ b/GpD3D/GpMain_Win32.cpp @@ -7,18 +7,83 @@ #include "GpFileSystem_Win32.h" #include "GpAppInterface.h" #include "GpSystemServices_Win32.h" +#include "GpVOSEvent.h" +#include "IGpVOSEventQueue.h" #include "HostFileSystem.h" #include "GpWindows.h" #include +#include GpWindowsGlobals g_gpWindowsGlobals; extern "C" __declspec(dllimport) IGpAudioDriver *GpDriver_CreateAudioDriver_XAudio2(const GpAudioDriverProperties &properties); extern "C" __declspec(dllimport) IGpDisplayDriver *GpDriver_CreateDisplayDriver_D3D11(const GpDisplayDriverProperties &properties); +static void PostMouseEvent(IGpVOSEventQueue *eventQueue, GpMouseEventType_t eventType, GpMouseButton_t button, int32_t x, int32_t y) +{ + if (GpVOSEvent *evt = eventQueue->QueueEvent()) + { + evt->m_eventType = GpVOSEventTypes::kMouseInput; + + GpMouseInputEvent &mEvent = evt->m_event.m_mouseInputEvent; + mEvent.m_button = button; + mEvent.m_x = x; + mEvent.m_y = y; + mEvent.m_eventType = eventType; + } +} + +static void TranslateWindowsMessage(const MSG *msg, IGpVOSEventQueue *eventQueue) +{ + WPARAM wParam = msg->wParam; + LPARAM lParam = msg->lParam; + + switch (msg->message) + { + case WM_LBUTTONDOWN: + PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kLeft, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + break; + case WM_LBUTTONUP: + PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kLeft, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + break; + case WM_MBUTTONDOWN: + PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kMiddle, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + break; + case WM_MBUTTONUP: + PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kMiddle, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + break; + case WM_RBUTTONDOWN: + PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kRight, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + break; + case WM_RBUTTONUP: + PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kRight, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + break; + case WM_XBUTTONDOWN: + if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) + PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kX1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2) + PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kX2, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + break; + case WM_XBUTTONUP: + if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) + PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kX1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2) + PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kX2, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + break; + case WM_MOUSEMOVE: + PostMouseEvent(eventQueue, GpMouseEventTypes::kMove, GpMouseButtons::kNone, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + break; + case WM_MOUSELEAVE: + PostMouseEvent(eventQueue, GpMouseEventTypes::kLeave, GpMouseButtons::kNone, 0, 0); + break; + default: + break; + } +} + int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { GpAppInterface_Get()->PL_HostFileSystem_SetInstance(GpFileSystem_Win32::GetInstance()); @@ -32,6 +97,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine g_gpWindowsGlobals.m_createFiberFunc = GpFiber_Win32::Create; g_gpWindowsGlobals.m_loadColorCursorFunc = GpColorCursor_Win32::Load; + g_gpWindowsGlobals.m_translateWindowsMessageFunc = TranslateWindowsMessage; g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_D3D11; g_gpGlobalConfig.m_osGlobals = &g_gpWindowsGlobals; diff --git a/GpD3D/GpPLGlueDisplayDriver.cpp b/GpD3D/GpPLGlueDisplayDriver.cpp index 51ac94d..5c3d2a6 100644 --- a/GpD3D/GpPLGlueDisplayDriver.cpp +++ b/GpD3D/GpPLGlueDisplayDriver.cpp @@ -1,40 +1,40 @@ #include "GpPLGlueDisplayDriver.h" -#include "VirtualDirectory.h" -#include "IGpDisplayDriver.h" - -GpPLGlueDisplayDriver::GpPLGlueDisplayDriver() - : m_displayDriver(nullptr) -{ -} - -void GpPLGlueDisplayDriver::GetDisplayResolution(unsigned int *width, unsigned int *height, GpPixelFormat_t *bpp) -{ - m_displayDriver->GetDisplayResolution(width, height, bpp); +#include "VirtualDirectory.h" +#include "IGpDisplayDriver.h" + +GpPLGlueDisplayDriver::GpPLGlueDisplayDriver() + : m_displayDriver(nullptr) +{ +} + +void GpPLGlueDisplayDriver::GetDisplayResolution(unsigned int *width, unsigned int *height, GpPixelFormat_t *bpp) +{ + m_displayDriver->GetDisplayResolution(width, height, bpp); } IGpColorCursor *GpPLGlueDisplayDriver::LoadColorCursor(int cursorID) { - return m_displayDriver->LoadColorCursor(cursorID); -} - -void GpPLGlueDisplayDriver::SetColorCursor(IGpColorCursor *colorCursor) -{ - m_displayDriver->SetColorCursor(colorCursor); + return m_displayDriver->LoadColorCursor(cursorID); } - + +void GpPLGlueDisplayDriver::SetColorCursor(IGpColorCursor *colorCursor) +{ + m_displayDriver->SetColorCursor(colorCursor); +} + void GpPLGlueDisplayDriver::SetStandardCursor(EGpStandardCursor_t standardCursor) { - m_displayDriver->SetStandardCursor(standardCursor); -} - -GpPLGlueDisplayDriver *GpPLGlueDisplayDriver::GetInstance() -{ - return &ms_instance; -} - -void GpPLGlueDisplayDriver::SetGpDisplayDriver(IGpDisplayDriver *displayDriver) -{ - m_displayDriver = displayDriver; -} - -GpPLGlueDisplayDriver GpPLGlueDisplayDriver::ms_instance; + m_displayDriver->SetStandardCursor(standardCursor); +} + +GpPLGlueDisplayDriver *GpPLGlueDisplayDriver::GetInstance() +{ + return &ms_instance; +} + +void GpPLGlueDisplayDriver::SetGpDisplayDriver(IGpDisplayDriver *displayDriver) +{ + m_displayDriver = displayDriver; +} + +GpPLGlueDisplayDriver GpPLGlueDisplayDriver::ms_instance; diff --git a/GpD3D/GpVOSEventQueue.h b/GpD3D/GpVOSEventQueue.h index e125e80..7a7c021 100644 --- a/GpD3D/GpVOSEventQueue.h +++ b/GpD3D/GpVOSEventQueue.h @@ -3,10 +3,10 @@ #include #include "HostVOSEventQueue.h" -#include "GpVOSEvent.h" +#include "GpVOSEvent.h" class GpVOSEventQueue final : public PortabilityLayer::HostVOSEventQueue -{ +{ public: GpVOSEventQueue(); ~GpVOSEventQueue(); @@ -14,7 +14,7 @@ public: const GpVOSEvent *GetNext() override; void DischargeOne() override; - GpVOSEvent *QueueEvent(); + GpVOSEvent *QueueEvent() override; private: static const size_t kMaxEvents = 10000; diff --git a/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp b/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp index ba385ad..5b24b0f 100644 --- a/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp +++ b/GpDisplayDriver_D3D11/GpDisplayDriverD3D11.cpp @@ -565,10 +565,29 @@ void GpDisplayDriverD3D11::Run() if (msg.message == WM_QUIT) break; - else if (msg.message == WM_MOUSEMOVE) - m_mouseIsInClientArea = true; - else if (msg.message == WM_MOUSELEAVE) - m_mouseIsInClientArea = false; + else + { + if (msg.message == WM_MOUSEMOVE) + { + if (!m_mouseIsInClientArea) + { + m_mouseIsInClientArea = true; + + TRACKMOUSEEVENT tme; + ZeroMemory(&tme, sizeof(tme)); + + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = m_hwnd; + tme.dwHoverTime = HOVER_DEFAULT; + TrackMouseEvent(&tme); + } + } + else if (msg.message == WM_MOUSELEAVE) + m_mouseIsInClientArea = false; + + m_osGlobals->m_translateWindowsMessageFunc(&msg, m_properties.m_eventQueue); + } } else { diff --git a/PortabilityLayer/FontManager.cpp b/PortabilityLayer/FontManager.cpp index d810746..a42b691 100644 --- a/PortabilityLayer/FontManager.cpp +++ b/PortabilityLayer/FontManager.cpp @@ -25,6 +25,7 @@ namespace PortabilityLayer FontFamily *GetApplicationFont(int textSize, int variationFlags) const override; RenderedFont *GetRenderedFont(HostFont *font, int size, FontHacks fontHacks) override; + RenderedFont *GetRenderedFontFromFamily(FontFamily *font, int size, int flags) override; static FontManagerImpl *GetInstance(); @@ -157,6 +158,17 @@ namespace PortabilityLayer return rfont; } + RenderedFont *FontManagerImpl::GetRenderedFontFromFamily(FontFamily *fontFamily, int size, int flags) + { + const int variation = fontFamily->GetVariationForFlags(flags); + + PortabilityLayer::HostFont *hostFont = fontFamily->GetFontForVariation(variation); + if (!hostFont) + return nullptr; + + return PortabilityLayer::FontManager::GetInstance()->GetRenderedFont(hostFont, size, fontFamily->GetHacksForVariation(variation)); + } + FontManagerImpl *FontManagerImpl::GetInstance() { return &ms_instance; diff --git a/PortabilityLayer/FontManager.h b/PortabilityLayer/FontManager.h index 97175cb..2a39c6e 100644 --- a/PortabilityLayer/FontManager.h +++ b/PortabilityLayer/FontManager.h @@ -18,6 +18,7 @@ namespace PortabilityLayer virtual FontFamily *GetApplicationFont(int fontSize, int variationFlags) const = 0; virtual RenderedFont *GetRenderedFont(HostFont *font, int size, FontHacks fontHacks) = 0; + virtual RenderedFont *GetRenderedFontFromFamily(FontFamily *fontFamily, int fontSize, int flags) = 0; static FontManager *GetInstance(); }; diff --git a/PortabilityLayer/FontRenderer.cpp b/PortabilityLayer/FontRenderer.cpp index e1d1590..1a21913 100644 --- a/PortabilityLayer/FontRenderer.cpp +++ b/PortabilityLayer/FontRenderer.cpp @@ -5,6 +5,7 @@ #include "HostFontHandler.h" #include "HostFontRenderedGlyph.h" #include "MacRoman.h" +#include "PLPasStr.h" #include "RenderedFont.h" #include "RenderedGlyphMetrics.h" @@ -19,6 +20,7 @@ namespace PortabilityLayer { public: bool GetGlyph(unsigned int character, const RenderedGlyphMetrics **outMetricsPtr, const void **outData) const override; + size_t MeasureString(const uint8_t *chars, size_t len) const override; void Destroy() override; @@ -59,6 +61,19 @@ namespace PortabilityLayer return true; } + size_t RenderedFontImpl::MeasureString(const uint8_t *chars, size_t len) const + { + size_t measure = 0; + + for (size_t i = 0; i < len; i++) + { + const RenderedGlyphMetrics &metrics = m_metrics[chars[i]]; + measure += metrics.m_advanceX; + } + + return measure; + } + void RenderedFontImpl::Destroy() { this->~RenderedFontImpl(); diff --git a/PortabilityLayer/HostVOSEventQueue.h b/PortabilityLayer/HostVOSEventQueue.h index 282f964..232d67e 100644 --- a/PortabilityLayer/HostVOSEventQueue.h +++ b/PortabilityLayer/HostVOSEventQueue.h @@ -1,15 +1,12 @@ #pragma once -struct GpVOSEvent; +#include "IGpVOSEventQueue.h" namespace PortabilityLayer { - class HostVOSEventQueue + class HostVOSEventQueue : public IGpVOSEventQueue { public: - virtual const GpVOSEvent *GetNext() = 0; - virtual void DischargeOne() = 0; - static void SetInstance(HostVOSEventQueue *instance); static HostVOSEventQueue *GetInstance(); diff --git a/PortabilityLayer/MenuManager.cpp b/PortabilityLayer/MenuManager.cpp index 850c875..2d2fa5b 100644 --- a/PortabilityLayer/MenuManager.cpp +++ b/PortabilityLayer/MenuManager.cpp @@ -1,7 +1,60 @@ #include "MenuManager.h" -#include "PLBigEndian.h" +#include "DisplayDeviceManager.h" +#include "FontFamily.h" +#include "FontManager.h" +#include "HostDisplayDriver.h" +#include "HostFont.h" +#include "IGpDisplayDriver.h" #include "MemoryManager.h" +#include "ResourceManager.h" +#include "SimpleGraphic.h" +#include "PLBigEndian.h" +#include "PLCore.h" +#include "PLPasStr.h" +#include "PLResources.h" +#include "PLQDOffscreen.h" +#include "RenderedFont.h" +#include "QDGraf.h" +#include "QDManager.h" +#include "QDPixMap.h" +#include "RGBAColor.h" + #include +#include + +namespace +{ + 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 }, + }; + + 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 }, + }; + + const PortabilityLayer::RGBAColor gs_barBrightColor = { 255, 255, 255, 255 }; + const PortabilityLayer::RGBAColor gs_barMidColor = { 221, 221, 221, 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_barHighlightBrightColor = { 153, 153, 255, 255 }; + const PortabilityLayer::RGBAColor gs_barHighlightMidColor = { 102, 102, 204, 255 }; + const PortabilityLayer::RGBAColor gs_barHighlightDarkColor = { 51, 51, 102, 255 }; + + PortabilityLayer::SimpleGraphicInstanceRGBA<5, 5> gs_barTopLeftCornerGraphic(gs_barTopLeftCornerGraphicPixels); + PortabilityLayer::SimpleGraphicInstanceRGBA<5, 5> gs_barTopRightCornerGraphic(gs_barTopRightCornerGraphicPixels); +} struct MenuItem { @@ -21,13 +74,20 @@ struct Menu uint16_t height; uint16_t commandID; bool enabled; + bool isIcon; PortabilityLayer::MMHandleBlock *stringBlobHandle; Menu **prevMenu; Menu **nextMenu; + // Refreshed on layout + size_t cumulativeOffset; + unsigned int menuIndex; + size_t numMenuItems; + + // This must be the last item MenuItem menuItems[1]; }; @@ -39,6 +99,9 @@ namespace PortabilityLayer MenuManagerImpl(); ~MenuManagerImpl(); + virtual void Init() override; + virtual void Shutdown() override; + Menu **DeserializeMenu(const void *resData) const override; Menu **GetMenuByID(int id) const override; void InsertMenuBefore(Menu **insertingMenu, Menu **existingMenu) override; @@ -49,18 +112,46 @@ namespace PortabilityLayer void SetItemEnabled(Menu **menu, unsigned int index, bool enabled) override; void SetItemChecked(Menu **menu, unsigned int index, bool checked) override; + void DrawMenuBar() override; + + void RenderFrame(IGpDisplayDriver *displayDriver) override; + static MenuManagerImpl *GetInstance(); private: + void RefreshMenuLayout(); + + static const unsigned int kIconResID = 128; + static const unsigned int kMenuFontSize = 12; + static const unsigned int kMenuBarIconYOffset = 2; + static const unsigned int kMenuBarTextYOffset = 14; + static const unsigned int kMenuBarHeight = 20; + static const unsigned int kMenuBarItemPadding = 6; + static const unsigned int kMenuBarInitialPadding = 16; + static const int kMenuFontFlags = PortabilityLayer::FontFamilyFlag_Bold; + + CGraf *m_menuBarGraf; + Menu **m_firstMenu; Menu **m_lastMenu; + bool m_haveMenuLayout; + bool m_haveIcon; + + uint8_t m_iconColors[16 * 16]; + uint8_t m_iconMask[32]; + + SimpleGraphic *m_iconGraphic; static MenuManagerImpl ms_instance; }; MenuManagerImpl::MenuManagerImpl() - : m_firstMenu(nullptr) + : m_menuBarGraf(nullptr) + , m_firstMenu(nullptr) , m_lastMenu(nullptr) + , m_haveMenuLayout(false) + , m_haveIcon(false) + , m_iconGraphic(nullptr) { } @@ -68,6 +159,26 @@ namespace PortabilityLayer { } + void MenuManagerImpl::Init() + { + } + + void MenuManagerImpl::Shutdown() + { + PortabilityLayer::QDManager *qdManager = PortabilityLayer::QDManager::GetInstance(); + + if (m_menuBarGraf) + qdManager->DisposeGWorld(m_menuBarGraf); + + if (m_iconGraphic) + { + m_iconGraphic->~SimpleGraphic(); + free(m_iconGraphic); + } + + // GP TODO: Dispose of menus properly + } + Menu **MenuManagerImpl::DeserializeMenu(const void *resData) const { PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance(); @@ -122,6 +233,9 @@ namespace PortabilityLayer menu->height = header.height; menu->commandID = header.commandID; menu->enabled = ((enableFlags & 1) != 0); + menu->menuIndex = 0; + menu->cumulativeOffset = 0; + menu->isIcon = false; uint8_t *stringDataStart = static_cast(stringData->m_contents); uint8_t *stringDest = stringDataStart; @@ -172,6 +286,8 @@ namespace PortabilityLayer void MenuManagerImpl::InsertMenuBefore(Menu **insertingMenu, Menu **existingMenu) { + m_haveMenuLayout = false; + Menu *insertingMenuPtr = *insertingMenu; Menu *existingMenuPtr = *existingMenu; @@ -188,6 +304,8 @@ namespace PortabilityLayer void MenuManagerImpl::InsertMenuAfter(Menu **insertingMenu, Menu **existingMenu) { + m_haveMenuLayout = false; + Menu *insertingMenuPtr = *insertingMenu; Menu *existingMenuPtr = *existingMenu; @@ -204,6 +322,8 @@ namespace PortabilityLayer void MenuManagerImpl::InsertMenuAtEnd(Menu **insertingMenu) { + m_haveMenuLayout = false; + if (m_firstMenu == nullptr) { m_firstMenu = m_lastMenu = insertingMenu; @@ -217,6 +337,8 @@ namespace PortabilityLayer void MenuManagerImpl::InsertMenuAtBeginning(Menu **insertingMenu) { + m_haveMenuLayout = false; + if (m_firstMenu == nullptr) { m_firstMenu = m_lastMenu = insertingMenu; @@ -255,6 +377,228 @@ namespace PortabilityLayer menu->menuItems[index].checked = checked; } + void MenuManagerImpl::DrawMenuBar() + { + if (!m_haveIcon) + { + ResourceManager *resManager = ResourceManager::GetInstance(); + + Handle icsHandle = GetResource('ics#', kIconResID); + Handle ics8Handle = GetResource('ics8', kIconResID); + + if (icsHandle && ics8Handle) + { + typedef SimpleGraphicInstanceStandardPalette<16, 16> GraphicType_t; + + void *storage = static_cast(malloc(sizeof(GraphicType_t))); + if (storage) + { + memcpy(m_iconMask, static_cast(*icsHandle) + 32, 32); + memcpy(m_iconColors, static_cast(*ics8Handle), 16 * 16); + + GraphicType_t *graphic = new (storage) GraphicType_t(m_iconColors); + + m_iconGraphic = graphic; + + } + } + + if (icsHandle) + ReleaseResource(icsHandle); + + if (ics8Handle) + ReleaseResource(ics8Handle); + + m_haveIcon = true; + } + + unsigned int width; + GpPixelFormat_t pixelFormat; + PortabilityLayer::HostDisplayDriver::GetInstance()->GetDisplayResolution(&width, nullptr, &pixelFormat); + + PortabilityLayer::QDManager *qdManager = PortabilityLayer::QDManager::GetInstance(); + + const Rect menuRect = Rect::Create(0, 0, kMenuBarHeight, width); + + if (m_menuBarGraf == nullptr) + { + int depth = 0; + + switch (pixelFormat) + { + case GpPixelFormats::k8BitStandard: + depth = 8; + break; + default: + PL_NotYetImplemented(); + return; + } + + if (qdManager->NewGWorld(&m_menuBarGraf, depth, menuRect, nullptr, nullptr, 0) != 0) + return; + } + + CGraf *graf = m_menuBarGraf; + + assert(graf); + + if (static_cast(graf->m_port.GetRect().right) != width) + { + if (!graf->m_port.Resize(menuRect)) + return; + } + + + RefreshMenuLayout(); + + CGraf *oldGraf; + GDHandle oldDevice; + GetGWorld(&oldGraf, &oldDevice); + + SetGWorld(m_menuBarGraf, nullptr); + + PortabilityLayer::QDState *qdState = qdManager->GetState(); + + qdState->SetForeColor(gs_barMidColor); + PaintRect(&menuRect); + + qdState->SetForeColor(gs_barBrightColor); + + // Top stripe + { + const Rect rect = Rect::Create(0, 0, 1, static_cast(width) - 1); + PaintRect(&rect); + } + + // Left stripe + { + const Rect rect = Rect::Create(0, 0, kMenuBarHeight - 1, 1); + PaintRect(&rect); + } + + qdState->SetForeColor(gs_barDarkColor); + + // Bottom stripe + { + const Rect rect = Rect::Create(kMenuBarHeight - 2, 1, kMenuBarHeight - 1, width); + PaintRect(&rect); + } + + // Right stripe + { + const Rect rect = Rect::Create(0, width - 1, kMenuBarHeight - 1, width); + PaintRect(&rect); + } + + qdState->SetForeColor(gs_barBottomEdgeColor); + + // Bottom edge + { + const Rect rect = Rect::Create(kMenuBarHeight - 1, 0, kMenuBarHeight, width); + PaintRect(&rect); + } + + PixMapHandle pixMap = m_menuBarGraf->m_port.GetPixMap(); + + // Round corners + gs_barTopLeftCornerGraphic.DrawToPixMap(pixMap, 0, 0); + gs_barTopRightCornerGraphic.DrawToPixMap(pixMap, static_cast(width) - static_cast(gs_barTopRightCornerGraphic.m_width), 0); + + qdState->SetForeColor(gs_barNormalTextColor); + TextFont(systemFont); + TextSize(kMenuFontSize); + + // Text items + { + Menu **menuHdl = m_firstMenu; + while (menuHdl) + { + Menu *menu = *menuHdl; + + if (menu->stringBlobHandle) + { + size_t xCoordinate = menu->cumulativeOffset + (menu->menuIndex * 2) * kMenuBarItemPadding + kMenuBarInitialPadding; + + if (menu->isIcon) + { + if (m_iconGraphic) + m_iconGraphic->DrawToPixMapWithMask(pixMap, m_iconMask, xCoordinate, kMenuBarIconYOffset); + } + else + { + qdState->m_penPos.h = xCoordinate; + qdState->m_penPos.v = kMenuBarTextYOffset; + DrawString(PLPasStr(static_cast(menu->stringBlobHandle->m_contents))); + } + } + + menuHdl = menu->nextMenu; + } + } + + SetGWorld(oldGraf, oldDevice); + + m_menuBarGraf->m_port.SetDirty(QDPortDirtyFlag_Contents); + } + + void MenuManagerImpl::RenderFrame(IGpDisplayDriver *displayDriver) + { + if (m_menuBarGraf) + { + m_menuBarGraf->PushToDDSurface(displayDriver); + + if (m_menuBarGraf->m_ddSurface) + { + const PixMap *pixMap = *m_menuBarGraf->m_port.GetPixMap(); + const size_t width = pixMap->m_rect.right - pixMap->m_rect.left; + const size_t height = pixMap->m_rect.bottom - pixMap->m_rect.top; + displayDriver->DrawSurface(m_menuBarGraf->m_ddSurface, 0, 0, width, height); + } + } + } + + void MenuManagerImpl::RefreshMenuLayout() + { + if (m_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; + + unsigned int index = 0; + size_t measuredWidth = 0; + + Menu **menuHdl = m_firstMenu; + while (menuHdl) + { + Menu *menu = *menuHdl; + + menu->menuIndex = index++; + menu->cumulativeOffset = measuredWidth; + + const PLPasStr pascalStr = PLPasStr(static_cast(menu->stringBlobHandle->m_contents)); + + if (pascalStr.Length() == 1 && pascalStr.UChars()[0] == 0x14) + { + measuredWidth += 16; + menu->isIcon = true; + } + else + measuredWidth += rfont->MeasureString(pascalStr.UChars(), pascalStr.Length()); + + menuHdl = menu->nextMenu; + } + + m_haveMenuLayout = true; + } + MenuManagerImpl *MenuManagerImpl::GetInstance() { return &ms_instance; diff --git a/PortabilityLayer/MenuManager.h b/PortabilityLayer/MenuManager.h index c5306fc..8627554 100644 --- a/PortabilityLayer/MenuManager.h +++ b/PortabilityLayer/MenuManager.h @@ -1,12 +1,16 @@ #pragma once -struct Menu; +struct Menu; +struct IGpDisplayDriver; namespace PortabilityLayer { class MenuManager { public: + virtual void Init() = 0; + virtual void Shutdown() = 0; + virtual Menu **DeserializeMenu(const void *resData) const = 0; virtual Menu **GetMenuByID(int id) const = 0; virtual void InsertMenuBefore(Menu **insertingMenu, Menu **existingMenu) = 0; @@ -17,6 +21,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 void DrawMenuBar() = 0; + + virtual void RenderFrame(IGpDisplayDriver *displayDriver) = 0; + static MenuManager *GetInstance(); }; } diff --git a/PortabilityLayer/PLCore.cpp b/PortabilityLayer/PLCore.cpp index 9b32e59..0f63ec2 100644 --- a/PortabilityLayer/PLCore.cpp +++ b/PortabilityLayer/PLCore.cpp @@ -19,6 +19,7 @@ #include "ResourceManager.h" #include "MacFileInfo.h" #include "MemoryManager.h" +#include "MenuManager.h" #include "MemReaderStream.h" #include "MMHandleBlock.h" #include "ResTypeID.h" @@ -61,6 +62,11 @@ static void TranslateVOSEvent(const GpVOSEvent *vosEvent, EventRecord *evt) static void ImportVOSEvents() { + PortabilityLayer::HostVOSEventQueue *evtQueue = PortabilityLayer::HostVOSEventQueue::GetInstance(); + while (const GpVOSEvent *evt = evtQueue->GetNext()) + { + evtQueue->DischargeOne(); + } } void InitCursor() @@ -864,6 +870,7 @@ void PL_Init() PortabilityLayer::DisplayDeviceManager::GetInstance()->Init(); PortabilityLayer::AEManager::GetInstance()->Init(); PortabilityLayer::QDManager::GetInstance()->Init(); + PortabilityLayer::MenuManager::GetInstance()->Init(); } WindowPtr PL_GetPutInFrontWindowPtr() diff --git a/PortabilityLayer/PLEventQueue.cpp b/PortabilityLayer/PLEventQueue.cpp index ad84cb9..3eaac96 100644 --- a/PortabilityLayer/PLEventQueue.cpp +++ b/PortabilityLayer/PLEventQueue.cpp @@ -1,9 +1,9 @@ #include "PLEventQueue.h" -#include +#include namespace PortabilityLayer -{ +{ class EventQueueImpl final : public EventQueue { public: diff --git a/PortabilityLayer/PLMenus.cpp b/PortabilityLayer/PLMenus.cpp index 0300aa1..fcbe4a7 100644 --- a/PortabilityLayer/PLMenus.cpp +++ b/PortabilityLayer/PLMenus.cpp @@ -2,6 +2,7 @@ #include "PLResources.h" #include "MenuManager.h" +#include "QDManager.h" // Menu resource structure: // uint16 menu ID @@ -54,7 +55,7 @@ void DeleteMenu(int menuID) void DrawMenuBar() { - PL_NotYetImplemented_TODO("Menus"); + PortabilityLayer::MenuManager::GetInstance()->DrawMenuBar(); } void HiliteMenu(int menu) diff --git a/PortabilityLayer/PLQDOffscreen.cpp b/PortabilityLayer/PLQDOffscreen.cpp index 4399243..794c07c 100644 --- a/PortabilityLayer/PLQDOffscreen.cpp +++ b/PortabilityLayer/PLQDOffscreen.cpp @@ -239,7 +239,7 @@ OSErr NewGWorld(GWorldPtr *gworld, int depth, Rect *bounds, CTabHandle colorTabl void DisposeGWorld(GWorldPtr gworld) { - PL_NotYetImplemented(); + return PortabilityLayer::QDManager::GetInstance()->DisposeGWorld(gworld); } PixMapHandle GetGWorldPixMap(GWorldPtr gworld) diff --git a/PortabilityLayer/PortabilityLayer.vcxproj b/PortabilityLayer/PortabilityLayer.vcxproj index 6834ed0..2e78b00 100644 --- a/PortabilityLayer/PortabilityLayer.vcxproj +++ b/PortabilityLayer/PortabilityLayer.vcxproj @@ -227,6 +227,7 @@ + @@ -296,6 +297,7 @@ + diff --git a/PortabilityLayer/PortabilityLayer.vcxproj.filters b/PortabilityLayer/PortabilityLayer.vcxproj.filters index e7b73d7..e50e1cb 100644 --- a/PortabilityLayer/PortabilityLayer.vcxproj.filters +++ b/PortabilityLayer/PortabilityLayer.vcxproj.filters @@ -360,6 +360,9 @@ Header Files + + Source Files + @@ -539,5 +542,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/PortabilityLayer/QDGraf.cpp b/PortabilityLayer/QDGraf.cpp index e69de29..5696324 100644 --- a/PortabilityLayer/QDGraf.cpp +++ b/PortabilityLayer/QDGraf.cpp @@ -0,0 +1,30 @@ +#include "QDGraf.h" +#include "QDPixMap.h" +#include "QDPort.h" +#include "IGpDisplayDriver.h" +#include "IGpDisplayDriverSurface.h" + +void CGraf::PushToDDSurface(IGpDisplayDriver *displayDriver) +{ + const PixMap *pixMap = *m_port.GetPixMap(); + const size_t width = pixMap->m_rect.right - pixMap->m_rect.left; + const size_t height = pixMap->m_rect.bottom - pixMap->m_rect.top; + + if (m_port.IsDirty(PortabilityLayer::QDPortDirtyFlag_Size)) + { + if (m_ddSurface != nullptr) + m_ddSurface->Destroy(); + + m_ddSurface = nullptr; + m_port.ClearDirty(PortabilityLayer::QDPortDirtyFlag_Size); + } + + if (m_ddSurface == nullptr) + m_ddSurface = displayDriver->CreateSurface(pixMap->m_rect.right - pixMap->m_rect.left, pixMap->m_rect.bottom - pixMap->m_rect.top, pixMap->m_pixelFormat); + + if (m_port.IsDirty(PortabilityLayer::QDPortDirtyFlag_Contents) && m_ddSurface != nullptr) + { + m_ddSurface->UploadEntire(pixMap->m_data, pixMap->m_pitch); + m_port.ClearDirty(PortabilityLayer::QDPortDirtyFlag_Contents); + } +} diff --git a/PortabilityLayer/QDGraf.h b/PortabilityLayer/QDGraf.h index d9e8672..bcfd21b 100644 --- a/PortabilityLayer/QDGraf.h +++ b/PortabilityLayer/QDGraf.h @@ -8,9 +8,10 @@ struct PixMap; struct Rect; +struct IGpDisplayDriver; struct IGpDisplayDriverSurface; -struct CGraf +struct CGraf final { CGraf() : m_port(PortabilityLayer::QDPortType_CGraf) @@ -37,6 +38,8 @@ struct CGraf return m_port.Resize(rect); } + void PushToDDSurface(IGpDisplayDriver *displayDriver); + // Must be the first item PortabilityLayer::QDPort m_port; diff --git a/PortabilityLayer/QDManager.cpp b/PortabilityLayer/QDManager.cpp index c6c64b2..6cc50f5 100644 --- a/PortabilityLayer/QDManager.cpp +++ b/PortabilityLayer/QDManager.cpp @@ -17,6 +17,7 @@ namespace PortabilityLayer void GetPort(QDPort **port, GDevice ***gdHandle) override; void SetPort(QDPort *gw, GDevice **gdHandle) override; int NewGWorld(CGraf **gw, int depth, const Rect &bounds, ColorTable **colorTable, GDevice **device, int flags) override; + void DisposeGWorld(CGraf *gw) override; QDState *GetState() override; static QDManagerImpl *GetInstance(); @@ -93,6 +94,12 @@ namespace PortabilityLayer return noErr; } + void QDManagerImpl::DisposeGWorld(CGraf *gw) + { + gw->~CGraf(); + MemoryManager::GetInstance()->Release(gw); + } + QDState *QDManagerImpl::GetState() { return m_port->GetState(); diff --git a/PortabilityLayer/QDManager.h b/PortabilityLayer/QDManager.h index cd691a0..3535cb3 100644 --- a/PortabilityLayer/QDManager.h +++ b/PortabilityLayer/QDManager.h @@ -17,6 +17,7 @@ namespace PortabilityLayer virtual void GetPort(QDPort **gw, GDevice ***gdHandle) = 0; virtual void SetPort(QDPort *gw, GDevice **gdHandle) = 0; virtual int NewGWorld(CGraf **gw, int depth, const Rect &bounds, ColorTable **colorTable, GDevice **device, int flags) = 0; + virtual void DisposeGWorld(CGraf *gw) = 0; virtual QDState *GetState() = 0; diff --git a/PortabilityLayer/RenderedFont.h b/PortabilityLayer/RenderedFont.h index a742a8a..5ff4643 100644 --- a/PortabilityLayer/RenderedFont.h +++ b/PortabilityLayer/RenderedFont.h @@ -1,4 +1,6 @@ -#pragma once +#pragma once + +#include namespace PortabilityLayer { @@ -8,6 +10,7 @@ namespace PortabilityLayer { public: virtual bool GetGlyph(unsigned int character, const RenderedGlyphMetrics **outMetricsPtr, const void **outData) const = 0; + virtual size_t MeasureString(const uint8_t *chars, size_t len) const = 0; virtual void Destroy() = 0; }; diff --git a/PortabilityLayer/SimpleGraphic.cpp b/PortabilityLayer/SimpleGraphic.cpp new file mode 100644 index 0000000..153c6b0 --- /dev/null +++ b/PortabilityLayer/SimpleGraphic.cpp @@ -0,0 +1,100 @@ +#include "SimpleGraphic.h" +#include "QDStandardPalette.h" +#include "QDPixMap.h" +#include "SharedTypes.h" + +namespace PortabilityLayer +{ + SimpleGraphic::SimpleGraphic(unsigned int width, unsigned int height, const RGBAColor *pixelData, uint8_t *standardPaletteData) + : m_width(width) + , m_height(height) + , m_pixelData(pixelData) + , m_standardPaletteData(standardPaletteData) + { + const unsigned int numPixels = width * height; + + for (unsigned int i = 0; i < numPixels; i++) + standardPaletteData[i] = PortabilityLayer::StandardPalette::MapColorAnalytic(pixelData[i]); + } + + SimpleGraphic::SimpleGraphic(unsigned int width, unsigned int height, const uint8_t *standardPaletteData, RGBAColor *pixelData) + : m_width(width) + , m_height(height) + , m_pixelData(pixelData) + , m_standardPaletteData(standardPaletteData) + { + const unsigned int numPixels = width * height; + + for (unsigned int i = 0; i < numPixels; i++) + pixelData[i] = PortabilityLayer::StandardPalette::GetInstance()->GetColors()[standardPaletteData[i]]; + } + + void SimpleGraphic::DrawToPixMap(PixMap **pixMapH, int16_t x, int16_t y) + { + DrawToPixMapWithMask(pixMapH, nullptr, x, y); + } + + void SimpleGraphic::DrawToPixMapWithMask(PixMap **pixMapH, const uint8_t *maskData, int16_t x, int16_t y) + { + if (!pixMapH) + return; + + PixMap *pixMap = *pixMapH; + + void *pixMapData = pixMap->m_data; + const size_t destPitch = pixMap->m_pitch; + + const Rect pixMapRect = pixMap->m_rect; + const int32_t right = x + static_cast(m_width); + const int32_t bottom = y + static_cast(m_height); + + // Simple graphics must be entirely in bounds + if (x < 0 || y < 0 || right > pixMapRect.right || bottom > pixMapRect.bottom) + return; + + const size_t destXOffset = (x - pixMapRect.left); + const size_t destYOffset = (y - pixMapRect.top); + + const size_t srcHeight = m_height; + const size_t srcWidth = m_width; + + size_t maskOffset = 0; + + switch (pixMap->m_pixelFormat) + { + case GpPixelFormats::k8BitStandard: + { + uint8_t *destFirstPixel = static_cast(pixMapData) + destXOffset + destYOffset * destPitch; + const uint8_t *srcPixel = m_standardPaletteData; + + for (size_t row = 0; row < srcHeight; row++) + { + uint8_t *destRowFirstPixel = destFirstPixel + row * destPitch; + + if (maskData) + { + for (size_t col = 0; col < srcWidth; col++) + { + if (maskData[maskOffset / 8] & (0x80 >> (maskOffset & 7))) + destRowFirstPixel[col] = *srcPixel; + srcPixel++; + maskOffset++; + } + } + else + { + for (size_t col = 0; col < srcWidth; col++) + { + destRowFirstPixel[col] = *srcPixel; + srcPixel++; + } + } + } + } + break; + default: + PL_NotYetImplemented(); + break; + } + } +} diff --git a/PortabilityLayer/SimpleGraphic.h b/PortabilityLayer/SimpleGraphic.h new file mode 100644 index 0000000..24683e7 --- /dev/null +++ b/PortabilityLayer/SimpleGraphic.h @@ -0,0 +1,56 @@ +#pragma once + +#include "RGBAColor.h" + +struct PixMap; + +namespace PortabilityLayer +{ + struct SimpleGraphic + { + unsigned int m_width; + unsigned int m_height; + + const RGBAColor *m_pixelData; + const uint8_t *m_standardPaletteData; + + void DrawToPixMap(PixMap **pixMap, int16_t x, int16_t y); + void DrawToPixMapWithMask(PixMap **pixMap, const uint8_t *maskData, int16_t x, int16_t y); + + protected: + SimpleGraphic(unsigned int width, unsigned int height, const RGBAColor *pixelData, uint8_t *standardPaletteData); + SimpleGraphic(unsigned int width, unsigned int height, const uint8_t *pixelData, RGBAColor *standardPaletteData); + }; + + template + struct SimpleGraphicInstanceRGBA final : public SimpleGraphic + { + uint8_t m_standardPaletteDataInstance[TWidth * THeight]; + + explicit SimpleGraphicInstanceRGBA(const RGBAColor *data); + }; + + template + struct SimpleGraphicInstanceStandardPalette final : public SimpleGraphic + { + RGBAColor m_pixelDataInstance[TWidth * THeight]; + + explicit SimpleGraphicInstanceStandardPalette(const uint8_t *data); + }; +} + + +namespace PortabilityLayer +{ + template + inline SimpleGraphicInstanceRGBA::SimpleGraphicInstanceRGBA(const RGBAColor *data) + : SimpleGraphic(TWidth, THeight, data, m_standardPaletteDataInstance) + { + } + + template + inline SimpleGraphicInstanceStandardPalette::SimpleGraphicInstanceStandardPalette(const uint8_t *data) + : SimpleGraphic(TWidth, THeight, data, m_pixelDataInstance) + { + } +} diff --git a/PortabilityLayer/WindowManager.cpp b/PortabilityLayer/WindowManager.cpp index 5d64221..1b7c311 100644 --- a/PortabilityLayer/WindowManager.cpp +++ b/PortabilityLayer/WindowManager.cpp @@ -311,31 +311,13 @@ namespace PortabilityLayer void WindowManagerImpl::RenderWindow(WindowImpl *window, IGpDisplayDriver *displayDriver) { - GDevice *device = *window->GetDevice(); - CGraf &graf = window->m_graf; + + graf.PushToDDSurface(displayDriver); + const PixMap *pixMap = *graf.m_port.GetPixMap(); const size_t width = pixMap->m_rect.right - pixMap->m_rect.left; const size_t height = pixMap->m_rect.bottom - pixMap->m_rect.top; - - if (graf.m_port.IsDirty(QDPortDirtyFlag_Size)) - { - if (graf.m_ddSurface != nullptr) - graf.m_ddSurface->Destroy(); - - graf.m_ddSurface = nullptr; - graf.m_port.ClearDirty(QDPortDirtyFlag_Size); - } - - if (graf.m_ddSurface == nullptr) - graf.m_ddSurface = displayDriver->CreateSurface(pixMap->m_rect.right - pixMap->m_rect.left, pixMap->m_rect.bottom - pixMap->m_rect.top, pixMap->m_pixelFormat); - - if (graf.m_port.IsDirty(QDPortDirtyFlag_Contents) && graf.m_ddSurface != nullptr) - { - graf.m_ddSurface->UploadEntire(pixMap->m_data, pixMap->m_pitch); - graf.m_port.ClearDirty(QDPortDirtyFlag_Contents); - } - displayDriver->DrawSurface(graf.m_ddSurface, window->m_wmX, window->m_wmY, width, height); }