From 7aaa3174df022fea7b7caefc4437743a0303af69 Mon Sep 17 00:00:00 2001 From: Wolfgang Thaller Date: Sat, 18 Jul 2015 01:14:43 +0200 Subject: [PATCH] One more example: a System Extension (INIT) --- CMakeLists.txt | 1 + Samples/SystemExtension/CMakeLists.txt | 16 +++ Samples/SystemExtension/Icons.rsrc.bin | Bin 0 -> 5248 bytes Samples/SystemExtension/ShowInitIcon.c | 161 ++++++++++++++++++++++ Samples/SystemExtension/ShowInitIcon.h | 21 +++ Samples/SystemExtension/SystemExtension.c | 16 +++ Samples/SystemExtension/SystemExtension.r | 13 ++ libretro/CMakeLists.txt | 2 +- libretro/Retro68Runtime.h | 1 + libretro/relocate.c | 22 ++- libretro/start.c | 1 - 11 files changed, 248 insertions(+), 6 deletions(-) create mode 100644 Samples/SystemExtension/CMakeLists.txt create mode 100644 Samples/SystemExtension/Icons.rsrc.bin create mode 100644 Samples/SystemExtension/ShowInitIcon.c create mode 100644 Samples/SystemExtension/ShowInitIcon.h create mode 100644 Samples/SystemExtension/SystemExtension.c create mode 100644 Samples/SystemExtension/SystemExtension.r diff --git a/CMakeLists.txt b/CMakeLists.txt index c45771fe17..7771287309 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ add_subdirectory(Samples/HelloWorld) add_subdirectory(Samples/Raytracer) add_subdirectory(Samples/Launcher) add_subdirectory(Samples/Dialog) +add_subdirectory(Samples/SystemExtension) else() configure_file(cmake/retro68.toolchain.cmake.in cmake/retro68.toolchain.cmake @ONLY) diff --git a/Samples/SystemExtension/CMakeLists.txt b/Samples/SystemExtension/CMakeLists.txt new file mode 100644 index 0000000000..60303e4679 --- /dev/null +++ b/Samples/SystemExtension/CMakeLists.txt @@ -0,0 +1,16 @@ +add_executable(SystemExtension + SystemExtension.c + SystemExtension.r + ShowInitIcon.c + ShowInitIcon.h) + +set_target_properties(SystemExtension PROPERTIES OUTPUT_NAME SystemExtension.flt) + +add_custom_command( + OUTPUT SystemExtension.dsk + COMMAND ${REZ} ${CMAKE_CURRENT_SOURCE_DIR}/SystemExtension.r + --copy ${CMAKE_CURRENT_SOURCE_DIR}/Icons.rsrc.bin + -o SystemExtension.dsk + -t INIT + DEPENDS SystemExtension SystemExtension.r Icons.rsrc.bin) +add_custom_target(SystemExtension_INIT ALL DEPENDS SystemExtension.dsk) diff --git a/Samples/SystemExtension/Icons.rsrc.bin b/Samples/SystemExtension/Icons.rsrc.bin new file mode 100644 index 0000000000000000000000000000000000000000..ebe670db314fe1ebc82b34a44cada558832be4f7 GIT binary patch literal 5248 zcmd^DF^?NX6n@?d=>*}LXL`?mG6+xZ%9Enb_O*7~ny?L_OpzrchS*K9oZ1Ul%J+C9YDoCDlDpQ`%%h)*d7 zP(m!0wXJ)I7wfQYl}#t(wYljPzMh$F34mzRq>)^+u)|G_qS^FW@3pe7pYwZKS+HQ}4 zkJUtp{h(v)>j^x@x}%P)KUN@K*WrjCv0pjP@n!$J#(xw4e19f>{{B~=&)6rmaNa~` zk^=~hCF>(%W6A8n!H5y5vBS7mlw~=ZFuqO>6c$Vlcoz7Ked06rV99~=!^autfJc%8 z#rh@(JX~_X$E&`vN5lOTKz!%Fd7=wMMG;sSaYfKxS(qE9jA=^iXtq9%rPKMAdip@| zfbcS7418SlEzV<}Xz>|~MbF{JhQl=`h=!e%kBz>r-6C*)mf!+gdu||$EVT@mz~*7k2SxDBgvIl7!57?}U-|s&lLty=ePhLc8$6xW5`TZI zzV9ce2KZac$LqylWewsQP)XK4*MLegxa3$Jeu^5fXae@nXp4)st>iy#->U(Y8}w>G z4W8G4I^5NOWq2jV!Y3oRk6Z)jnts>|___PXPhY(|yz%?qaBukYpGMXT^h58_hxy~A zhZ!nOZlf0@8`m1t zi<@}_9>jbX6h_+2*G_-lp5xuR*vA?^$h8bU2*C&8v8E7wDD&Fzr|_XMU$&9O9^vLy zx_2Q97x)?RokALCDSjvAM^%1d`DfMVWr8=~@z9X@6};Fh?1S}+aFstEEapl%%l?%J zn?0Ktxr&td#WV5X^W{=s&!^eq2|^Ex+jhsO?A#pDW~-o-gE= YKJeuC3wiW%A&, Jim Walker +// and François Pottier , with thanks to previous ShowINIT authors. +// Send comments and bug reports to François Pottier. + +// This version features: +// - Short and readable code. +// - Correctly wraps around when more than one row of icons has been displayed. +// - works with System 6 +// - Built with Universal Headers & CodeWarrior. Should work with other headers/compilers. + +#include +#include +#include +#include +#include "ShowInitIcon.h" + +// You should set SystemSixOrLater in your headers to avoid including glue for SysEnvirons. + +// --------------------------------------------------------------------------------------------------------------------- +// Set this flag to 1 if you want to compile this file into a stand-alone resource (see note below). +// Set it to 0 if you want to include this source file into your INIT project. + +#if 0 +#define ShowInitIcon main +#endif + +// --------------------------------------------------------------------------------------------------------------------- +// The ShowINIT mechanism works by having each INIT read/write data from these globals. +// The MPW C compiler doesn't accept variables declared at an absolute address, so I use these macros instead. +// Only one macro is defined per variable; there is no need to define a Set and a Get accessor like in . + +#define LMVCheckSum (* (unsigned short*) 0x928) +#define LMVCoord (* ( short*) 0x92A) +#define LMHCoord (* ( short*) 0x92C) +#define LMHCheckSum (* (unsigned short*) 0x92E) + +// --------------------------------------------------------------------------------------------------------------------- +// Prototypes for the subroutines. The main routine comes first; this is necessary to make THINK C's "Custom Header" option work. + +static unsigned short CheckSum (short x); +static void ComputeIconRect (Rect* iconRect, Rect* screenBounds); +static void AdvanceIconPosition (Rect* iconRect); +static void DrawBWIcon (short iconID, Rect *iconRect); + +// --------------------------------------------------------------------------------------------------------------------- +// Main routine. + +typedef struct { + QDGlobals qd; // Storage for the QuickDraw globals + long qdGlobalsPtr; // A5 points to this place; it will contain a pointer to qd +} QDStorage; + +pascal void ShowInitIcon (short iconFamilyID, Boolean advance) +{ + long oldA5; // Original value of register A5 + QDStorage qds; // Fake QD globals + CGrafPort colorPort; + GrafPort bwPort; + Rect destRect; + SysEnvRec environment; // Machine configuration. + + oldA5 = SetA5((long) &qds.qdGlobalsPtr); // Tell A5 to point to the end of the fake QD Globals + InitGraf(&qds.qd.thePort); // Initialize the fake QD Globals + + SysEnvirons(curSysEnvVers, &environment); // Find out what kind of machine this is + + ComputeIconRect(&destRect, &qds.qd.screenBits.bounds); // Compute where the icon should be drawn + + if (environment.systemVersion >= 0x0700 && environment.hasColorQD) { + OpenCPort(&colorPort); + PlotIconID(&destRect, atNone, ttNone, iconFamilyID); + CloseCPort(&colorPort); + } + else { + OpenPort(&bwPort); + DrawBWIcon(iconFamilyID, &destRect); + ClosePort(&bwPort); + } + + if (advance) + AdvanceIconPosition (&destRect); + + SetA5(oldA5); // Restore A5 to its previous value +} + +// --------------------------------------------------------------------------------------------------------------------- +// A checksum is used to make sure that the data in there was left by another ShowINIT-aware INIT. + +static unsigned short CheckSum (short x) +{ + return (unsigned short)(((x << 1) | (x >> 15)) ^ 0x1021); +} + +// --------------------------------------------------------------------------------------------------------------------- +// ComputeIconRect computes where the icon should be displayed. + +static void ComputeIconRect (Rect* iconRect, Rect* screenBounds) +{ + if (CheckSum(LMHCoord) != LMHCheckSum) // If we are first, we need to initialize the shared data. + LMHCoord = 8; + if (CheckSum(LMVCoord) != LMVCheckSum) + LMVCoord = (short)(screenBounds->bottom - 40); + + if (LMHCoord + 34 > screenBounds->right) { // Check whether we must wrap + iconRect->left = 8; + iconRect->top = (short)(LMVCoord - 40); + } + else { + iconRect->left = LMHCoord; + iconRect->top = LMVCoord; + } + iconRect->right = (short)(iconRect->left + 32); + iconRect->bottom = (short)(iconRect->top + 32); +} + +// AdvanceIconPosition updates the shared global variables so that the next extension will draw its icon beside ours. + +static void AdvanceIconPosition (Rect* iconRect) +{ + LMHCoord = (short)(iconRect->left + 40); // Update the shared data + LMVCoord = iconRect->top; + LMHCheckSum = CheckSum(LMHCoord); + LMVCheckSum = CheckSum(LMVCoord); +} + +// DrawBWIcon draws the 'ICN#' member of the icon family. It works under System 6. + +static void DrawBWIcon (short iconID, Rect *iconRect) +{ + Handle icon; + BitMap source, destination; + GrafPtr port; + + icon = Get1Resource('ICN#', iconID); + if (icon != NULL) { + HLock(icon); + // Prepare the source and destination bitmaps. + source.baseAddr = *icon + 128; // Mask address. + source.rowBytes = 4; + SetRect(&source.bounds, 0, 0, 32, 32); + GetPort(&port); + destination = port->portBits; + // Transfer the mask. + CopyBits(&source, &destination, &source.bounds, iconRect, srcBic, nil); + // Then the icon. + source.baseAddr = *icon; + CopyBits(&source, &destination, &source.bounds, iconRect, srcOr, nil); + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// Notes + +// Checking for PlotIconID: +// We (PNL) now check for system 7 and colour QD, and use colour graf ports and PlotIconID only if both are true +// Otherwise we use B&W grafport and draw using PlotBWIcon. + diff --git a/Samples/SystemExtension/ShowInitIcon.h b/Samples/SystemExtension/ShowInitIcon.h new file mode 100644 index 0000000000..0d5290959a --- /dev/null +++ b/Samples/SystemExtension/ShowInitIcon.h @@ -0,0 +1,21 @@ +#ifndef __ShowInitIcon__ +#define __ShowInitIcon__ + +#include + +// Usage: pass the ID of your icon family (ICN#/icl4/icl8) to have it drawn in the right spot. +// If 'advance' is true, the next INIT icon will be drawn to the right of your icon. If it is false, the next INIT icon will overwrite +// yours. You can use it to create animation effects by calling ShowInitIcon several times with 'advance' set to false. + +#ifdef __cplusplus +extern "C" { +#endif + +pascal void ShowInitIcon (short iconFamilyID, Boolean advance); + +#ifdef __cplusplus +} +#endif + +#endif /* __ShowInitIcon__ */ + diff --git a/Samples/SystemExtension/SystemExtension.c b/Samples/SystemExtension/SystemExtension.c new file mode 100644 index 0000000000..2b0f81caa9 --- /dev/null +++ b/Samples/SystemExtension/SystemExtension.c @@ -0,0 +1,16 @@ +#include +#include "ShowInitIcon.h" +#include "Retro68Runtime.h" + +void _start() +{ + RETRO68_RELOCATE(); + Retro68CallConstructors(); + + ShowInitIcon(130, false); + Delay(20, NULL); + ShowInitIcon(128, true); + Delay(40, NULL); + + Retro68FreeGlobals(); +} diff --git a/Samples/SystemExtension/SystemExtension.r b/Samples/SystemExtension/SystemExtension.r new file mode 100644 index 0000000000..a595c40546 --- /dev/null +++ b/Samples/SystemExtension/SystemExtension.r @@ -0,0 +1,13 @@ +type 'INIT' (0) { + hex string dontBreakAtEntry = $"", breakAtEntry = $"A9FF"; + longint = 0x61000002; // bsr *+2 + integer = 0x0697; // addi.l #_, (a7) + longint = $$long(fltfile + 8*8) + 8; + integer = 0x4e75; // rts +fltfile: + hex string; +}; + +resource 'INIT' (0) { + dontBreakAtEntry, $$read("SystemExtension.flt"); +}; diff --git a/libretro/CMakeLists.txt b/libretro/CMakeLists.txt index 428a65d493..437825e488 100644 --- a/libretro/CMakeLists.txt +++ b/libretro/CMakeLists.txt @@ -33,4 +33,4 @@ add_library(retrocrt consolehooks.c) install(TARGETS retrocrt DESTINATION lib) - +install(FILES Retro68Runtime.h DESTINATION include) diff --git a/libretro/Retro68Runtime.h b/libretro/Retro68Runtime.h index c2e1366dc8..a9a83996e1 100644 --- a/libretro/Retro68Runtime.h +++ b/libretro/Retro68Runtime.h @@ -42,5 +42,6 @@ void Retro68Relocate(); void Retro68CallConstructors(); +void Retro68FreeGlobals(); #define RETRO68_RELOCATE() RETRO68_CALL_UNRELOCATED(Retro68Relocate,()) diff --git a/libretro/relocate.c b/libretro/relocate.c index 08e727e679..97343b9210 100644 --- a/libretro/relocate.c +++ b/libretro/relocate.c @@ -66,7 +66,7 @@ extern void __fini_section_end(void); static long headerVirtualAddress = -0x40; -static Ptr savedBSS = (Ptr) -1; +static Ptr bssPtr = (Ptr) -1; #define ACCESS_DISPLACED(VAR) \ ( * (typeof(&VAR)) ((char*)(&VAR) + displacement) ) @@ -92,10 +92,14 @@ void Retro68Relocate() long data_end = header->data_end - 0x40; long bss_displacement = 0; - Ptr bss = ACCESS_DISPLACED(savedBSS); + Ptr bss = ACCESS_DISPLACED(bssPtr); if(bss == (Ptr)-1) { - bss = NewPtrClear(bss_size); + THz zone = ApplicationZone(); + if(!zone || (char*)header < (char*)zone) + bss = NewPtrSysClear(bss_size); + else + bss = NewPtrClear(bss_size); bss_displacement = (long)bss - data_end; } @@ -121,7 +125,7 @@ void Retro68Relocate() // accessing globals and calling functions is OK below here. headerVirtualAddress += displacement; - savedBSS = bss; + bssPtr = bss; } void Retro68CallConstructors() @@ -135,3 +139,13 @@ void Retro68CallConstructors() p += 6; } } + +void Retro68FreeGlobals() +{ + if(bssPtr != (Ptr) -1) + { + DisposePtr(bssPtr); + bssPtr = (Ptr) -1; + } +} + diff --git a/libretro/start.c b/libretro/start.c index 52b8893dbb..f4d514c57a 100644 --- a/libretro/start.c +++ b/libretro/start.c @@ -25,7 +25,6 @@ #include #include -#include #include "Retro68Runtime.h"