uvmac/src/UI/XPLAT/OSGLUSD2.c
InvisibleUp be71368cf7 WIP: Move screen size to variables
Non-windows systems are probably broken right now. Color display in
general is probably broken. But, soon, you will be able to change the
screen size and color depth without recompiling. That would be nice.
2020-03-05 21:54:02 -05:00

4211 lines
94 KiB
C

/*
OSGLUSD2.c
Copyright (C) 2012 Paul C. Pratt, Manuel Alfayate
You can redistribute this file and/or modify it under the terms
of version 2 of the GNU General Public License as published by
the Free Software Foundation. You should have received a copy
of the license along with this file; see the file COPYING.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
license for more details.
*/
/*
Operating System GLUe for SDl 2.0 library
All operating system dependent code for the
SDL Library should go here.
*/
#include "CNFGRAPI.h"
#include "SYSDEPNS.h"
#include "UTIL/ENDIANAC.h"
#include "UI/MYOSGLUE.h"
#include "STRCONST.h"
/* --- some simple utilities --- */
GLOBALOSGLUPROC MoveBytes(anyp srcPtr, anyp destPtr, int32_t byteCount)
{
(void) memcpy((char *)destPtr, (char *)srcPtr, byteCount);
}
/* --- control mode and internationalization --- */
#define NeedCell2PlainAsciiMap 1
#include "LANG/INTLCHAR.h"
#ifndef CanGetAppPath
#define CanGetAppPath 1
#endif
LOCALVAR char *d_arg = NULL;
LOCALVAR char *n_arg = NULL;
#if CanGetAppPath
LOCALVAR char *app_parent = NULL;
LOCALVAR char *pref_dir = NULL;
#endif
#ifdef _WIN32
#define PathSep '\\'
#else
#define PathSep '/'
#endif
LOCALFUNC tMacErr ChildPath(char *x, char *y, char **r)
{
tMacErr err = mnvm_miscErr;
int nx = strlen(x);
int ny = strlen(y);
{
if ((nx > 0) && (PathSep == x[nx - 1])) {
--nx;
}
{
int nr = nx + 1 + ny;
char *p = malloc(nr + 1);
if (p != NULL) {
char *p2 = p;
(void) memcpy(p2, x, nx);
p2 += nx;
*p2++ = PathSep;
(void) memcpy(p2, y, ny);
p2 += ny;
*p2 = 0;
*r = p;
err = mnvm_noErr;
}
}
}
return err;
}
LOCALPROC MayFree(char *p)
{
if (NULL != p) {
free(p);
}
}
/* --- sending debugging info to file --- */
#if dbglog_HAVE
#ifndef dbglog_ToStdErr
#define dbglog_ToStdErr 0
#endif
#ifndef dbglog_ToSDL_Log
#define dbglog_ToSDL_Log 0
#endif
#if ! dbglog_ToStdErr
LOCALVAR FILE *dbglog_File = NULL;
#endif
LOCALFUNC bool dbglog_open0(void)
{
#if dbglog_ToStdErr || dbglog_ToSDL_Log
return true;
#else
if (NULL == app_parent) {
dbglog_File = fopen("dbglog.txt", "w");
} else {
char *t;
if (mnvm_noErr == ChildPath(app_parent, "dbglog.txt", &t)) {
dbglog_File = fopen(t, "w");
free(t);
}
}
return (NULL != dbglog_File);
#endif
}
LOCALPROC dbglog_write0(char *s, uimr L)
{
#if dbglog_ToStdErr
(void) fwrite(s, 1, L, stderr);
#elif dbglog_ToSDL_Log
char t[256 + 1];
if (L > 256) {
L = 256;
}
(void) memcpy(t, s, L);
t[L] = 1;
SDL_Log("%s", t);
#else
if (dbglog_File != NULL) {
(void) fwrite(s, 1, L, dbglog_File);
}
#endif
}
LOCALPROC dbglog_close0(void)
{
#if ! dbglog_ToStdErr
if (dbglog_File != NULL) {
fclose(dbglog_File);
dbglog_File = NULL;
}
#endif
}
#endif
/* --- information about the environment --- */
#define WantColorTransValid 0
#include "UI/COMOSGLU.h"
#include "UTILS/PBUFSTDC.h"
#include "UI/CONTROLM.h"
/* --- text translation --- */
LOCALPROC NativeStrFromCStr(char *r, char *s)
{
uint8_t ps[ClStrMaxLength];
int i;
int L;
ClStrFromSubstCStr(&L, ps, s);
for (i = 0; i < L; ++i) {
r[i] = Cell2PlainAsciiMap[ps[i]];
}
r[L] = 0;
}
/* --- drives --- */
#define NotAfileRef NULL
#ifndef UseRWops
#define UseRWops 0
#endif
#if UseRWops
#define FilePtr SDL_RWops *
#define Seek SDL_RWseek
#define SeekSet RW_SEEK_SET
#define SeekCur RW_SEEK_CUR
#define SeekEnd RW_SEEK_END
#define FileRead(ptr, size, nmemb, stream) \
SDL_RWread(stream, ptr, size, nmemb)
#define FileWrite(ptr, size, nmemb, stream) \
SDL_RWwrite(stream, ptr, size, nmemb)
#define FileTell SDL_RWtell
#define FileClose SDL_RWclose
#define FileOpen SDL_RWFromFile
#else
#define FilePtr FILE *
#define Seek fseek
#define SeekSet SEEK_SET
#define SeekCur SEEK_CUR
#define SeekEnd SEEK_END
#define FileRead fread
#define FileWrite fwrite
#define FileTell ftell
#define FileClose fclose
#define FileOpen fopen
#define FileEof feof
#endif
LOCALVAR FilePtr Drives[NumDrives]; /* open disk image files */
LOCALPROC InitDrives(void)
{
/*
This isn't really needed, Drives[i] and DriveNames[i]
need not have valid values when not vSonyIsInserted[i].
*/
tDrive i;
for (i = 0; i < NumDrives; ++i) {
Drives[i] = NotAfileRef;
}
}
GLOBALOSGLUFUNC tMacErr vSonyTransfer(bool IsWrite, uint8_t * Buffer,
tDrive Drive_No, uint32_t Sony_Start, uint32_t Sony_Count,
uint32_t *Sony_ActCount)
{
tMacErr err = mnvm_miscErr;
FilePtr refnum = Drives[Drive_No];
uint32_t NewSony_Count = 0;
if (Seek(refnum, Sony_Start, SeekSet) >= 0) {
if (IsWrite) {
NewSony_Count = FileWrite(Buffer, 1, Sony_Count, refnum);
} else {
NewSony_Count = FileRead(Buffer, 1, Sony_Count, refnum);
}
if (NewSony_Count == Sony_Count) {
err = mnvm_noErr;
}
}
if (nullpr != Sony_ActCount) {
*Sony_ActCount = NewSony_Count;
}
return err; /*& figure out what really to return &*/
}
GLOBALOSGLUFUNC tMacErr vSonyGetSize(tDrive Drive_No, uint32_t *Sony_Count)
{
tMacErr err = mnvm_miscErr;
FilePtr refnum = Drives[Drive_No];
long v;
if (Seek(refnum, 0, SeekEnd) >= 0) {
v = FileTell(refnum);
if (v >= 0) {
*Sony_Count = v;
err = mnvm_noErr;
}
}
return err; /*& figure out what really to return &*/
}
LOCALFUNC tMacErr vSonyEject0(tDrive Drive_No, bool deleteit)
{
FilePtr refnum = Drives[Drive_No];
DiskEjectedNotify(Drive_No);
FileClose(refnum);
Drives[Drive_No] = NotAfileRef; /* not really needed */
return mnvm_noErr;
}
GLOBALOSGLUFUNC tMacErr vSonyEject(tDrive Drive_No)
{
return vSonyEject0(Drive_No, false);
}
LOCALPROC UnInitDrives(void)
{
tDrive i;
for (i = 0; i < NumDrives; ++i) {
if (vSonyIsInserted(i)) {
(void) vSonyEject(i);
}
}
}
LOCALFUNC bool Sony_Insert0(FilePtr refnum, bool locked,
char *drivepath)
{
tDrive Drive_No;
bool IsOk = false;
if (! FirstFreeDisk(&Drive_No)) {
MacMsg(kStrTooManyImagesTitle, kStrTooManyImagesMessage,
false);
} else {
/* printf("Sony_Insert0 %d\n", (int)Drive_No); */
{
Drives[Drive_No] = refnum;
DiskInsertNotify(Drive_No, locked);
IsOk = true;
}
}
if (! IsOk) {
FileClose(refnum);
}
return IsOk;
}
LOCALFUNC bool Sony_Insert1(char *drivepath, bool silentfail)
{
bool locked = false;
/* printf("Sony_Insert1 %s\n", drivepath); */
FilePtr refnum = FileOpen(drivepath, "rb+");
if (NULL == refnum) {
locked = true;
refnum = FileOpen(drivepath, "rb");
}
if (NULL == refnum) {
if (! silentfail) {
MacMsg(kStrOpenFailTitle, kStrOpenFailMessage, false);
}
} else {
return Sony_Insert0(refnum, locked, drivepath);
}
return false;
}
LOCALFUNC tMacErr LoadMacRomFrom(char *path)
{
tMacErr err;
FilePtr ROM_File;
int File_Size;
ROM_File = FileOpen(path, "rb");
if (NULL == ROM_File) {
err = mnvm_fnfErr;
} else {
File_Size = FileRead(ROM, 1, kROM_Size, ROM_File);
if (File_Size != kROM_Size) {
#ifdef FileEof
if (FileEof(ROM_File))
#else
if (File_Size > 0)
#endif
{
MacMsgOverride(kStrShortROMTitle,
kStrShortROMMessage);
err = mnvm_eofErr;
} else {
MacMsgOverride(kStrNoReadROMTitle,
kStrNoReadROMMessage);
err = mnvm_miscErr;
}
} else {
err = ROM_IsValid();
}
FileClose(ROM_File);
}
return err;
}
LOCALFUNC bool Sony_Insert1a(char *drivepath, bool silentfail)
{
bool v;
if (! ROM_loaded) {
v = (mnvm_noErr == LoadMacRomFrom(drivepath));
} else {
v = Sony_Insert1(drivepath, silentfail);
}
return v;
}
LOCALFUNC bool Sony_Insert2(char *s)
{
char *d =
#if CanGetAppPath
(NULL == d_arg) ? app_parent :
#endif
d_arg;
bool IsOk = false;
if (NULL == d) {
IsOk = Sony_Insert1(s, true);
} else {
char *t;
if (mnvm_noErr == ChildPath(d, s, &t)) {
IsOk = Sony_Insert1(t, true);
free(t);
}
}
return IsOk;
}
LOCALFUNC bool Sony_InsertIth(int i)
{
bool v;
if ((i > 9) || ! FirstFreeDisk(nullpr)) {
v = false;
} else {
char s[] = "disk?.dsk";
s[4] = '0' + i;
v = Sony_Insert2(s);
}
return v;
}
LOCALFUNC bool LoadInitialImages(void)
{
if (! AnyDiskInserted()) {
int i;
for (i = 1; Sony_InsertIth(i); ++i) {
/* stop on first error (including file not found) */
}
}
return true;
}
/* --- ROM --- */
LOCALVAR char *rom_path = NULL;
#if CanGetAppPath
LOCALFUNC tMacErr LoadMacRomFromPrefDir(void)
{
tMacErr err;
char *t = NULL;
char *t2 = NULL;
if (NULL == pref_dir) {
err = mnvm_fnfErr;
} else
if (mnvm_noErr != (err =
ChildPath(pref_dir, "mnvm_rom", &t)))
{
/* fail */
} else
if (mnvm_noErr != (err =
ChildPath(t, RomFileName, &t2)))
{
/* fail */
} else
{
err = LoadMacRomFrom(t2);
}
MayFree(t2);
MayFree(t);
return err;
}
#endif
#if CanGetAppPath
LOCALFUNC tMacErr LoadMacRomFromAppPar(void)
{
tMacErr err;
char *d = (NULL == d_arg) ? app_parent : d_arg;
char *t = NULL;
if (NULL == d) {
err = mnvm_fnfErr;
} else
if (mnvm_noErr != (err =
ChildPath(d, RomFileName, &t)))
{
/* fail */
} else
{
err = LoadMacRomFrom(t);
}
MayFree(t);
return err;
}
#endif
LOCALFUNC bool LoadMacRom(void)
{
tMacErr err;
if ((NULL == rom_path)
|| (mnvm_fnfErr == (err = LoadMacRomFrom(rom_path))))
#if CanGetAppPath
if (mnvm_fnfErr == (err = LoadMacRomFromAppPar()))
if (mnvm_fnfErr == (err = LoadMacRomFromPrefDir()))
#endif
if (mnvm_fnfErr == (err = LoadMacRomFrom(RomFileName)))
{
}
return true; /* keep launching Mini vMac, regardless */
}
/* --- video out --- */
#if MayFullScreen
LOCALVAR int hOffset;
LOCALVAR int vOffset;
#endif
#if VarFullScreen
LOCALVAR bool UseFullScreen = (WantInitFullScreen != 0);
#endif
#if EnableMagnify
LOCALVAR bool UseMagnify = (WantInitMagnify != 0);
#endif
#ifndef UseSDLscaling
#define UseSDLscaling 0
#endif
LOCALVAR bool gBackgroundFlag = false;
LOCALVAR bool gTrueBackgroundFlag = false;
LOCALVAR bool CurSpeedStopped = true;
#if EnableMagnify && ! UseSDLscaling
#define MaxScale WindowScale
#else
#define MaxScale 1
#endif
LOCALVAR SDL_Window *main_wind = NULL;
LOCALVAR SDL_Renderer *renderer = NULL;
LOCALVAR SDL_Texture *texture = NULL;
LOCALVAR SDL_PixelFormat *format = NULL;
LOCALVAR uint8_t * ScalingBuff = nullpr;
LOCALVAR uint8_t * CLUT_final;
#define CLUT_finalsz (256 * 8 * 4 * MaxScale)
/*
256 possible values of one byte
8 pixels per byte maximum (when black and white)
4 bytes per destination pixel maximum
multiplied by WindowScale if EnableMagnify
*/
#define ScrnMapr_DoMap UpdateBWDepth3Copy
#define ScrnMapr_Src GetCurDrawBuff()
#define ScrnMapr_Dst ScalingBuff
#define ScrnMapr_SrcDepth 0
#define ScrnMapr_DstDepth 3
#define ScrnMapr_Map CLUT_final
#include "HW/SCREEN/SCRNMAPR.h"
#define ScrnMapr_DoMap UpdateBWDepth4Copy
#define ScrnMapr_Src GetCurDrawBuff()
#define ScrnMapr_Dst ScalingBuff
#define ScrnMapr_SrcDepth 0
#define ScrnMapr_DstDepth 4
#define ScrnMapr_Map CLUT_final
#include "HW/SCREEN/SCRNMAPR.h"
#define ScrnMapr_DoMap UpdateBWDepth5Copy
#define ScrnMapr_Src GetCurDrawBuff()
#define ScrnMapr_Dst ScalingBuff
#define ScrnMapr_SrcDepth 0
#define ScrnMapr_DstDepth 5
#define ScrnMapr_Map CLUT_final
#include "HW/SCREEN/SCRNMAPR.h"
#if EnableMagnify && ! UseSDLscaling
#define ScrnMapr_DoMap UpdateBWDepth3ScaledCopy
#define ScrnMapr_Src GetCurDrawBuff()
#define ScrnMapr_Dst ScalingBuff
#define ScrnMapr_SrcDepth 0
#define ScrnMapr_DstDepth 3
#define ScrnMapr_Map CLUT_final
#define ScrnMapr_Scale WindowScale
#include "HW/SCREEN/SCRNMAPR.h"
#define ScrnMapr_DoMap UpdateBWDepth4ScaledCopy
#define ScrnMapr_Src GetCurDrawBuff()
#define ScrnMapr_Dst ScalingBuff
#define ScrnMapr_SrcDepth 0
#define ScrnMapr_DstDepth 4
#define ScrnMapr_Map CLUT_final
#define ScrnMapr_Scale WindowScale
#include "HW/SCREEN/SCRNMAPR.h"
#define ScrnMapr_DoMap UpdateBWDepth5ScaledCopy
#define ScrnMapr_Src GetCurDrawBuff()
#define ScrnMapr_Dst ScalingBuff
#define ScrnMapr_SrcDepth 0
#define ScrnMapr_DstDepth 5
#define ScrnMapr_Map CLUT_final
#define ScrnMapr_Scale WindowScale
#include "HW/SCREEN/SCRNMAPR.h"
#endif /* EnableMagnify && ! UseSDLscaling */
#if (0 != vMacScreenDepth) && (vMacScreenDepth < 4)
#define ScrnMapr_DoMap UpdateColorDepth3Copy
#define ScrnMapr_Src GetCurDrawBuff()
#define ScrnMapr_Dst ScalingBuff
#define ScrnMapr_SrcDepth vMacScreenDepth
#define ScrnMapr_DstDepth 3
#define ScrnMapr_Map CLUT_final
#include "HW/SCREEN/SCRNMAPR.h"
#define ScrnMapr_DoMap UpdateColorDepth4Copy
#define ScrnMapr_Src GetCurDrawBuff()
#define ScrnMapr_Dst ScalingBuff
#define ScrnMapr_SrcDepth vMacScreenDepth
#define ScrnMapr_DstDepth 4
#define ScrnMapr_Map CLUT_final
#include "HW/SCREEN/SCRNMAPR.h"
#define ScrnMapr_DoMap UpdateColorDepth5Copy
#define ScrnMapr_Src GetCurDrawBuff()
#define ScrnMapr_Dst ScalingBuff
#define ScrnMapr_SrcDepth vMacScreenDepth
#define ScrnMapr_DstDepth 5
#define ScrnMapr_Map CLUT_final
#include "HW/SCREEN/SCRNMAPR.h"
#if EnableMagnify && ! UseSDLscaling
#define ScrnMapr_DoMap UpdateColorDepth3ScaledCopy
#define ScrnMapr_Src GetCurDrawBuff()
#define ScrnMapr_Dst ScalingBuff
#define ScrnMapr_SrcDepth vMacScreenDepth
#define ScrnMapr_DstDepth 3
#define ScrnMapr_Map CLUT_final
#define ScrnMapr_Scale WindowScale
#include "HW/SCREEN/SCRNMAPR.h"
#define ScrnMapr_DoMap UpdateColorDepth4ScaledCopy
#define ScrnMapr_Src GetCurDrawBuff()
#define ScrnMapr_Dst ScalingBuff
#define ScrnMapr_SrcDepth vMacScreenDepth
#define ScrnMapr_DstDepth 4
#define ScrnMapr_Map CLUT_final
#define ScrnMapr_Scale WindowScale
#include "HW/SCREEN/SCRNMAPR.h"
#define ScrnMapr_DoMap UpdateColorDepth5ScaledCopy
#define ScrnMapr_Src GetCurDrawBuff()
#define ScrnMapr_Dst ScalingBuff
#define ScrnMapr_SrcDepth vMacScreenDepth
#define ScrnMapr_DstDepth 5
#define ScrnMapr_Map CLUT_final
#define ScrnMapr_Scale WindowScale
#include "HW/SCREEN/SCRNMAPR.h"
#endif /* EnableMagnify && ! UseSDLscaling */
#endif
LOCALPROC HaveChangedScreenBuff(uint16_t top, uint16_t left,
uint16_t bottom, uint16_t right)
{
int i;
int j;
uint8_t *p;
Uint32 pixel;
#if (0 != vMacScreenDepth) && (vMacScreenDepth < 4)
Uint32 CLUT_pixel[CLUT_size];
#endif
Uint32 BWLUT_pixel[2];
uint32_t top2;
uint32_t left2;
uint32_t bottom2;
uint32_t right2;
void *pixels;
int pitch;
SDL_Rect src_rect;
SDL_Rect dst_rect;
int XDest;
int YDest;
int DestWidth;
int DestHeight;
#if VarFullScreen
if (UseFullScreen)
#endif
#if MayFullScreen
{
if (top < ViewVStart) {
top = ViewVStart;
}
if (left < ViewHStart) {
left = ViewHStart;
}
if (bottom > ViewVStart + ViewVSize) {
bottom = ViewVStart + ViewVSize;
}
if (right > ViewHStart + ViewHSize) {
right = ViewHStart + ViewHSize;
}
if ((top >= bottom) || (left >= right)) {
goto label_exit;
}
}
#endif
XDest = left;
YDest = top;
DestWidth = (right - left);
DestHeight = (bottom - top);
#if VarFullScreen
if (UseFullScreen)
#endif
#if MayFullScreen
{
XDest -= ViewHStart;
YDest -= ViewVStart;
}
#endif
#if EnableMagnify
if (UseMagnify) {
XDest *= WindowScale;
YDest *= WindowScale;
DestWidth *= WindowScale;
DestHeight *= WindowScale;
}
#endif
#if VarFullScreen
if (UseFullScreen)
#endif
#if MayFullScreen
{
XDest += hOffset;
YDest += vOffset;
}
#endif
top2 = top;
left2 = left;
bottom2 = bottom;
right2 = right;
#if EnableMagnify && ! UseSDLscaling
if (UseMagnify) {
top2 *= WindowScale;
left2 *= WindowScale;
bottom2 *= WindowScale;
right2 *= WindowScale;
}
#endif
if (0 != SDL_LockTexture(texture, NULL, &pixels, &pitch)) {
return;
}
{
int bpp = format->BytesPerPixel;
uint32_t ExpectedPitch = vMacScreenWidth * bpp;
#if EnableMagnify && ! UseSDLscaling
if (UseMagnify) {
ExpectedPitch *= WindowScale;
}
#endif
#if 0 != vMacScreenDepth
if (UseColorMode) {
#if vMacScreenDepth < 4
for (i = 0; i < CLUT_size; ++i) {
CLUT_pixel[i] = SDL_MapRGB(format,
CLUT_reds[i] >> 8,
CLUT_greens[i] >> 8,
CLUT_blues[i] >> 8);
}
#endif
} else
#endif
{
BWLUT_pixel[1] = SDL_MapRGB(format, 0, 0, 0);
/* black */
BWLUT_pixel[0] = SDL_MapRGB(format, 255, 255, 255);
/* white */
}
if ((0 == ((bpp - 1) & bpp)) /* a power of 2 */
&& (pitch == ExpectedPitch)
#if (vMacScreenDepth > 3)
&& ! UseColorMode
#endif
)
{
int k;
Uint32 v;
#if EnableMagnify && ! UseSDLscaling
int a;
#endif
int PixPerByte =
#if (0 != vMacScreenDepth) && (vMacScreenDepth < 4)
UseColorMode ? (1 << (3 - vMacScreenDepth)) :
#endif
8;
Uint8 *p4 = (Uint8 *)CLUT_final;
for (i = 0; i < 256; ++i) {
for (k = PixPerByte; --k >= 0; ) {
#if (0 != vMacScreenDepth) && (vMacScreenDepth < 4)
if (UseColorMode) {
v = CLUT_pixel[
#if 3 == vMacScreenDepth
i
#else
(i >> (k << vMacScreenDepth))
& (CLUT_size - 1)
#endif
];
} else
#endif
{
v = BWLUT_pixel[(i >> k) & 1];
}
#if EnableMagnify && ! UseSDLscaling
for (a = UseMagnify ? WindowScale : 1; --a >= 0; )
#endif
{
switch (bpp) {
case 1: /* Assuming 8-bpp */
*p4++ = v;
break;
case 2: /* Probably 15-bpp or 16-bpp */
*(Uint16 *)p4 = v;
p4 += 2;
break;
case 4: /* Probably 32-bpp */
*(Uint32 *)p4 = v;
p4 += 4;
break;
}
}
}
}
ScalingBuff = (uint8_t *)pixels;
#if (0 != vMacScreenDepth) && (vMacScreenDepth < 4)
if (UseColorMode) {
#if EnableMagnify && ! UseSDLscaling
if (UseMagnify) {
switch (bpp) {
case 1:
UpdateColorDepth3ScaledCopy(
top, left, bottom, right);
break;
case 2:
UpdateColorDepth4ScaledCopy(
top, left, bottom, right);
break;
case 4:
UpdateColorDepth5ScaledCopy(
top, left, bottom, right);
break;
}
} else
#endif
{
switch (bpp) {
case 1:
UpdateColorDepth3Copy(top, left, bottom, right);
break;
case 2:
UpdateColorDepth4Copy(top, left, bottom, right);
break;
case 4:
UpdateColorDepth5Copy(top, left, bottom, right);
break;
}
}
} else
#endif
{
#if EnableMagnify && ! UseSDLscaling
if (UseMagnify) {
switch (bpp) {
case 1:
UpdateBWDepth3ScaledCopy(
top, left, bottom, right);
break;
case 2:
UpdateBWDepth4ScaledCopy(
top, left, bottom, right);
break;
case 4:
UpdateBWDepth5ScaledCopy(
top, left, bottom, right);
break;
}
} else
#endif
{
switch (bpp) {
case 1:
UpdateBWDepth3Copy(top, left, bottom, right);
break;
case 2:
UpdateBWDepth4Copy(top, left, bottom, right);
break;
case 4:
UpdateBWDepth5Copy(top, left, bottom, right);
break;
}
}
}
} else {
uint8_t *the_data = (uint8_t *)GetCurDrawBuff();
/* adapted from putpixel in SDL documentation */
for (i = top2; i < bottom2; ++i) {
for (j = left2; j < right2; ++j) {
int i0 = i;
int j0 = j;
Uint8 *bufp = (Uint8 *)pixels
+ i * pitch + j * bpp;
#if EnableMagnify && ! UseSDLscaling
if (UseMagnify) {
i0 /= WindowScale;
j0 /= WindowScale;
}
#endif
#if 0 != vMacScreenDepth
if (UseColorMode) {
#if vMacScreenDepth < 4
p = the_data + ((i0 * vMacScreenWidth + j0)
>> (3 - vMacScreenDepth));
{
uint8_t k = (*p >> (((~ j0)
& ((1 << (3 - vMacScreenDepth)) - 1))
<< vMacScreenDepth))
& (CLUT_size - 1);
pixel = CLUT_pixel[k];
}
#elif 4 == vMacScreenDepth
p = the_data + ((i0 * vMacScreenWidth + j0) << 1);
{
uint16_t t0 = do_get_mem_word(p);
pixel = SDL_MapRGB(format,
((t0 & 0x7C00) >> 7)
| ((t0 & 0x7000) >> 12),
((t0 & 0x03E0) >> 2)
| ((t0 & 0x0380) >> 7),
((t0 & 0x001F) << 3)
| ((t0 & 0x001C) >> 2));
}
#elif 5 == vMacScreenDepth
p = the_data + ((i0 * vMacScreenWidth + j0) << 2);
pixel = SDL_MapRGB(format,
p[1],
p[2],
p[3]);
#endif
} else
#endif
{
p = the_data + ((i0 * vMacScreenWidth + j0) / 8);
pixel = BWLUT_pixel[(*p >> ((~ j0) & 0x7)) & 1];
}
switch (bpp) {
case 1: /* Assuming 8-bpp */
*bufp = pixel;
break;
case 2: /* Probably 15-bpp or 16-bpp */
*(Uint16 *)bufp = pixel;
break;
case 3:
/* Slow 24-bpp mode, usually not used */
if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
bufp[0] = (pixel >> 16) & 0xff;
bufp[1] = (pixel >> 8) & 0xff;
bufp[2] = pixel & 0xff;
} else {
bufp[0] = pixel & 0xff;
bufp[1] = (pixel >> 8) & 0xff;
bufp[2] = (pixel >> 16) & 0xff;
}
break;
case 4: /* Probably 32-bpp */
*(Uint32 *)bufp = pixel;
break;
}
}
}
}
}
SDL_UnlockTexture(texture);
src_rect.x = left2;
src_rect.y = top2;
src_rect.w = right2 - left2;
src_rect.h = bottom2 - top2;
dst_rect.x = XDest;
dst_rect.y = YDest;
dst_rect.w = DestWidth;
dst_rect.h = DestHeight;
/* SDL_RenderClear(renderer); */
SDL_RenderCopy(renderer, texture, &src_rect, &dst_rect);
SDL_RenderPresent(renderer);
#if MayFullScreen
label_exit:
;
#endif
}
LOCALPROC DrawChangesAndClear(void)
{
if (ScreenChangedBottom > ScreenChangedTop) {
HaveChangedScreenBuff(ScreenChangedTop, ScreenChangedLeft,
ScreenChangedBottom, ScreenChangedRight);
ScreenClearChanges();
}
}
GLOBALOSGLUPROC DoneWithDrawingForTick(void)
{
#if EnableFSMouseMotion
if (HaveMouseMotion) {
AutoScrollScreen();
}
#endif
DrawChangesAndClear();
}
/* --- mouse --- */
/* cursor hiding */
LOCALVAR bool HaveCursorHidden = false;
LOCALVAR bool WantCursorHidden = false;
LOCALPROC ForceShowCursor(void)
{
if (HaveCursorHidden) {
HaveCursorHidden = false;
(void) SDL_ShowCursor(SDL_ENABLE);
}
}
/* cursor moving */
#ifndef HaveWorkingWarp
#define HaveWorkingWarp 1
#endif
#if EnableMoveMouse && HaveWorkingWarp
LOCALFUNC bool MoveMouse(int16_t h, int16_t v)
{
#if VarFullScreen
if (UseFullScreen)
#endif
#if MayFullScreen
{
h -= ViewHStart;
v -= ViewVStart;
}
#endif
#if EnableMagnify
if (UseMagnify) {
h *= WindowScale;
v *= WindowScale;
}
#endif
#if VarFullScreen
if (UseFullScreen)
#endif
#if MayFullScreen
{
h += hOffset;
v += vOffset;
}
#endif
SDL_WarpMouseInWindow(main_wind, h, v);
return true;
}
#endif
/* cursor state */
LOCALPROC MousePositionNotify(int NewMousePosh, int NewMousePosv)
{
bool ShouldHaveCursorHidden = true;
#if VarFullScreen
if (UseFullScreen)
#endif
#if MayFullScreen
{
NewMousePosh -= hOffset;
NewMousePosv -= vOffset;
}
#endif
#if EnableMagnify
if (UseMagnify) {
NewMousePosh /= WindowScale;
NewMousePosv /= WindowScale;
}
#endif
#if VarFullScreen
if (UseFullScreen)
#endif
#if MayFullScreen
{
NewMousePosh += ViewHStart;
NewMousePosv += ViewVStart;
}
#endif
#if EnableFSMouseMotion
if (HaveMouseMotion) {
MousePositionSetDelta(NewMousePosh - SavedMouseH,
NewMousePosv - SavedMouseV);
SavedMouseH = NewMousePosh;
SavedMouseV = NewMousePosv;
} else
#endif
{
if (NewMousePosh < 0) {
NewMousePosh = 0;
ShouldHaveCursorHidden = false;
} else if (NewMousePosh >= vMacScreenWidth) {
NewMousePosh = vMacScreenWidth - 1;
ShouldHaveCursorHidden = false;
}
if (NewMousePosv < 0) {
NewMousePosv = 0;
ShouldHaveCursorHidden = false;
} else if (NewMousePosv >= vMacScreenHeight) {
NewMousePosv = vMacScreenHeight - 1;
ShouldHaveCursorHidden = false;
}
#if VarFullScreen
if (UseFullScreen)
#endif
#if MayFullScreen
{
ShouldHaveCursorHidden = true;
}
#endif
/* if (ShouldHaveCursorHidden || CurMouseButton) */
/*
for a game like arkanoid, would like mouse to still
move even when outside window in one direction
*/
MousePositionSet(NewMousePosh, NewMousePosv);
}
WantCursorHidden = ShouldHaveCursorHidden;
}
#if EnableFSMouseMotion && ! HaveWorkingWarp
LOCALPROC MousePositionNotifyRelative(int deltah, int deltav)
{
bool ShouldHaveCursorHidden = true;
#if EnableMagnify
if (UseMagnify) {
/*
This is not really right. If only move one pixel
each time, emulated mouse doesn't move at all.
*/
deltah /= WindowScale;
deltav /= WindowScale;
}
#endif
MousePositionSetDelta(deltah,
deltav);
WantCursorHidden = ShouldHaveCursorHidden;
}
#endif
LOCALPROC CheckMouseState(void)
{
/*
this doesn't work as desired, doesn't get mouse movements
when outside of our window.
*/
int x;
int y;
(void) SDL_GetMouseState(&x, &y);
MousePositionNotify(x, y);
}
/* --- keyboard input --- */
LOCALFUNC uint8_t SDLScan2MacKeyCode(SDL_Scancode i)
{
uint8_t v = MKC_None;
switch (i) {
case SDL_SCANCODE_BACKSPACE: v = MKC_BackSpace; break;
case SDL_SCANCODE_TAB: v = MKC_Tab; break;
case SDL_SCANCODE_CLEAR: v = MKC_Clear; break;
case SDL_SCANCODE_RETURN: v = MKC_Return; break;
case SDL_SCANCODE_PAUSE: v = MKC_Pause; break;
case SDL_SCANCODE_ESCAPE: v = MKC_formac_Escape; break;
case SDL_SCANCODE_SPACE: v = MKC_Space; break;
case SDL_SCANCODE_APOSTROPHE: v = MKC_SingleQuote; break;
case SDL_SCANCODE_COMMA: v = MKC_Comma; break;
case SDL_SCANCODE_MINUS: v = MKC_Minus; break;
case SDL_SCANCODE_PERIOD: v = MKC_Period; break;
case SDL_SCANCODE_SLASH: v = MKC_formac_Slash; break;
case SDL_SCANCODE_0: v = MKC_0; break;
case SDL_SCANCODE_1: v = MKC_1; break;
case SDL_SCANCODE_2: v = MKC_2; break;
case SDL_SCANCODE_3: v = MKC_3; break;
case SDL_SCANCODE_4: v = MKC_4; break;
case SDL_SCANCODE_5: v = MKC_5; break;
case SDL_SCANCODE_6: v = MKC_6; break;
case SDL_SCANCODE_7: v = MKC_7; break;
case SDL_SCANCODE_8: v = MKC_8; break;
case SDL_SCANCODE_9: v = MKC_9; break;
case SDL_SCANCODE_SEMICOLON: v = MKC_SemiColon; break;
case SDL_SCANCODE_EQUALS: v = MKC_Equal; break;
case SDL_SCANCODE_LEFTBRACKET: v = MKC_LeftBracket; break;
case SDL_SCANCODE_BACKSLASH: v = MKC_formac_BackSlash; break;
case SDL_SCANCODE_RIGHTBRACKET: v = MKC_RightBracket; break;
case SDL_SCANCODE_GRAVE: v = MKC_formac_Grave; break;
case SDL_SCANCODE_A: v = MKC_A; break;
case SDL_SCANCODE_B: v = MKC_B; break;
case SDL_SCANCODE_C: v = MKC_C; break;
case SDL_SCANCODE_D: v = MKC_D; break;
case SDL_SCANCODE_E: v = MKC_E; break;
case SDL_SCANCODE_F: v = MKC_F; break;
case SDL_SCANCODE_G: v = MKC_G; break;
case SDL_SCANCODE_H: v = MKC_H; break;
case SDL_SCANCODE_I: v = MKC_I; break;
case SDL_SCANCODE_J: v = MKC_J; break;
case SDL_SCANCODE_K: v = MKC_K; break;
case SDL_SCANCODE_L: v = MKC_L; break;
case SDL_SCANCODE_M: v = MKC_M; break;
case SDL_SCANCODE_N: v = MKC_N; break;
case SDL_SCANCODE_O: v = MKC_O; break;
case SDL_SCANCODE_P: v = MKC_P; break;
case SDL_SCANCODE_Q: v = MKC_Q; break;
case SDL_SCANCODE_R: v = MKC_R; break;
case SDL_SCANCODE_S: v = MKC_S; break;
case SDL_SCANCODE_T: v = MKC_T; break;
case SDL_SCANCODE_U: v = MKC_U; break;
case SDL_SCANCODE_V: v = MKC_V; break;
case SDL_SCANCODE_W: v = MKC_W; break;
case SDL_SCANCODE_X: v = MKC_X; break;
case SDL_SCANCODE_Y: v = MKC_Y; break;
case SDL_SCANCODE_Z: v = MKC_Z; break;
case SDL_SCANCODE_KP_0: v = MKC_KP0; break;
case SDL_SCANCODE_KP_1: v = MKC_KP1; break;
case SDL_SCANCODE_KP_2: v = MKC_KP2; break;
case SDL_SCANCODE_KP_3: v = MKC_KP3; break;
case SDL_SCANCODE_KP_4: v = MKC_KP4; break;
case SDL_SCANCODE_KP_5: v = MKC_KP5; break;
case SDL_SCANCODE_KP_6: v = MKC_KP6; break;
case SDL_SCANCODE_KP_7: v = MKC_KP7; break;
case SDL_SCANCODE_KP_8: v = MKC_KP8; break;
case SDL_SCANCODE_KP_9: v = MKC_KP9; break;
case SDL_SCANCODE_KP_PERIOD: v = MKC_Decimal; break;
case SDL_SCANCODE_KP_DIVIDE: v = MKC_KPDevide; break;
case SDL_SCANCODE_KP_MULTIPLY: v = MKC_KPMultiply; break;
case SDL_SCANCODE_KP_MINUS: v = MKC_KPSubtract; break;
case SDL_SCANCODE_KP_PLUS: v = MKC_KPAdd; break;
case SDL_SCANCODE_KP_ENTER: v = MKC_formac_Enter; break;
case SDL_SCANCODE_KP_EQUALS: v = MKC_KPEqual; break;
case SDL_SCANCODE_UP: v = MKC_Up; break;
case SDL_SCANCODE_DOWN: v = MKC_Down; break;
case SDL_SCANCODE_RIGHT: v = MKC_Right; break;
case SDL_SCANCODE_LEFT: v = MKC_Left; break;
case SDL_SCANCODE_INSERT: v = MKC_formac_Help; break;
case SDL_SCANCODE_HOME: v = MKC_formac_Home; break;
case SDL_SCANCODE_END: v = MKC_formac_End; break;
case SDL_SCANCODE_PAGEUP: v = MKC_formac_PageUp; break;
case SDL_SCANCODE_PAGEDOWN: v = MKC_formac_PageDown; break;
case SDL_SCANCODE_F1: v = MKC_formac_F1; break;
case SDL_SCANCODE_F2: v = MKC_formac_F2; break;
case SDL_SCANCODE_F3: v = MKC_formac_F3; break;
case SDL_SCANCODE_F4: v = MKC_formac_F4; break;
case SDL_SCANCODE_F5: v = MKC_formac_F5; break;
case SDL_SCANCODE_F6: v = MKC_F6; break;
case SDL_SCANCODE_F7: v = MKC_F7; break;
case SDL_SCANCODE_F8: v = MKC_F8; break;
case SDL_SCANCODE_F9: v = MKC_F9; break;
case SDL_SCANCODE_F10: v = MKC_F10; break;
case SDL_SCANCODE_F11: v = MKC_F11; break;
case SDL_SCANCODE_F12: v = MKC_F12; break;
case SDL_SCANCODE_NUMLOCKCLEAR:
v = MKC_formac_ForwardDel; break;
case SDL_SCANCODE_CAPSLOCK: v = MKC_formac_CapsLock; break;
case SDL_SCANCODE_SCROLLLOCK: v = MKC_ScrollLock; break;
case SDL_SCANCODE_RSHIFT: v = MKC_formac_RShift; break;
case SDL_SCANCODE_LSHIFT: v = MKC_formac_Shift; break;
case SDL_SCANCODE_RCTRL: v = MKC_formac_RControl; break;
case SDL_SCANCODE_LCTRL: v = MKC_formac_Control; break;
case SDL_SCANCODE_RALT: v = MKC_formac_ROption; break;
case SDL_SCANCODE_LALT: v = MKC_formac_Option; break;
case SDL_SCANCODE_RGUI: v = MKC_formac_RCommand; break;
case SDL_SCANCODE_LGUI: v = MKC_formac_Command; break;
/* case SDLK_LSUPER: v = MKC_formac_Option; break; */
/* case SDLK_RSUPER: v = MKC_formac_ROption; break; */
case SDL_SCANCODE_HELP: v = MKC_formac_Help; break;
case SDL_SCANCODE_PRINTSCREEN: v = MKC_Print; break;
case SDL_SCANCODE_UNDO: v = MKC_formac_F1; break;
case SDL_SCANCODE_CUT: v = MKC_formac_F2; break;
case SDL_SCANCODE_COPY: v = MKC_formac_F3; break;
case SDL_SCANCODE_PASTE: v = MKC_formac_F4; break;
case SDL_SCANCODE_AC_HOME: v = MKC_formac_Home; break;
case SDL_SCANCODE_KP_A: v = MKC_A; break;
case SDL_SCANCODE_KP_B: v = MKC_B; break;
case SDL_SCANCODE_KP_C: v = MKC_C; break;
case SDL_SCANCODE_KP_D: v = MKC_D; break;
case SDL_SCANCODE_KP_E: v = MKC_E; break;
case SDL_SCANCODE_KP_F: v = MKC_F; break;
case SDL_SCANCODE_KP_BACKSPACE: v = MKC_BackSpace; break;
case SDL_SCANCODE_KP_CLEAR: v = MKC_Clear; break;
case SDL_SCANCODE_KP_COMMA: v = MKC_Comma; break;
case SDL_SCANCODE_KP_DECIMAL: v = MKC_Decimal; break;
default:
break;
}
return v;
}
LOCALPROC DoKeyCode(SDL_Keysym *r, bool down)
{
uint8_t v = SDLScan2MacKeyCode(r->scancode);
if (MKC_None != v) {
Keyboard_UpdateKeyMap2(v, down);
}
}
LOCALPROC DisableKeyRepeat(void)
{
}
LOCALPROC RestoreKeyRepeat(void)
{
}
LOCALPROC ReconnectKeyCodes3(void)
{
}
LOCALPROC DisconnectKeyCodes3(void)
{
DisconnectKeyCodes2();
MouseButtonSet(false);
}
/* --- time, date, location --- */
#define dbglog_TimeStuff (0 && dbglog_HAVE)
LOCALVAR uint32_t TrueEmulatedTime = 0;
#define InvTimeDivPow 16
#define InvTimeDiv (1 << InvTimeDivPow)
#define InvTimeDivMask (InvTimeDiv - 1)
#define InvTimeStep 1089590 /* 1000 / 60.14742 * InvTimeDiv */
LOCALVAR Uint32 LastTime;
LOCALVAR Uint32 NextIntTime;
LOCALVAR uint32_t NextFracTime;
LOCALPROC IncrNextTime(void)
{
NextFracTime += InvTimeStep;
NextIntTime += (NextFracTime >> InvTimeDivPow);
NextFracTime &= InvTimeDivMask;
}
LOCALPROC InitNextTime(void)
{
NextIntTime = LastTime;
NextFracTime = 0;
IncrNextTime();
}
LOCALVAR uint32_t NewMacDateInSeconds;
LOCALFUNC bool UpdateTrueEmulatedTime(void)
{
Uint32 LatestTime;
int32_t TimeDiff;
LatestTime = SDL_GetTicks();
if (LatestTime != LastTime) {
NewMacDateInSeconds = LatestTime / 1000;
/* no date and time api in SDL */
LastTime = LatestTime;
TimeDiff = (LatestTime - NextIntTime);
/* this should work even when time wraps */
if (TimeDiff >= 0) {
if (TimeDiff > 256) {
/* emulation interrupted, forget it */
++TrueEmulatedTime;
InitNextTime();
#if dbglog_TimeStuff
dbglog_writelnNum("emulation interrupted",
TrueEmulatedTime);
#endif
} else {
do {
++TrueEmulatedTime;
IncrNextTime();
TimeDiff = (LatestTime - NextIntTime);
} while (TimeDiff >= 0);
}
return true;
} else {
if (TimeDiff < -256) {
#if dbglog_TimeStuff
dbglog_writeln("clock set back");
#endif
/* clock goofed if ever get here, reset */
InitNextTime();
}
}
}
return false;
}
LOCALFUNC bool CheckDateTime(void)
{
if (CurMacDateInSeconds != NewMacDateInSeconds) {
CurMacDateInSeconds = NewMacDateInSeconds;
return true;
} else {
return false;
}
}
LOCALPROC StartUpTimeAdjust(void)
{
LastTime = SDL_GetTicks();
InitNextTime();
}
LOCALFUNC bool InitLocationDat(void)
{
LastTime = SDL_GetTicks();
InitNextTime();
NewMacDateInSeconds = LastTime / 1000;
CurMacDateInSeconds = NewMacDateInSeconds;
return true;
}
/* --- sound --- */
#if SoundEnabled
#define kLn2SoundBuffers 4 /* kSoundBuffers must be a power of two */
#define kSoundBuffers (1 << kLn2SoundBuffers)
#define kSoundBuffMask (kSoundBuffers - 1)
#define DesiredMinFilledSoundBuffs 3
/*
if too big then sound lags behind emulation.
if too small then sound will have pauses.
*/
#define kLnOneBuffLen 9
#define kLnAllBuffLen (kLn2SoundBuffers + kLnOneBuffLen)
#define kOneBuffLen (1UL << kLnOneBuffLen)
#define kAllBuffLen (1UL << kLnAllBuffLen)
#define kLnOneBuffSz (kLnOneBuffLen + kLn2SoundSampSz - 3)
#define kLnAllBuffSz (kLnAllBuffLen + kLn2SoundSampSz - 3)
#define kOneBuffSz (1UL << kLnOneBuffSz)
#define kAllBuffSz (1UL << kLnAllBuffSz)
#define kOneBuffMask (kOneBuffLen - 1)
#define kAllBuffMask (kAllBuffLen - 1)
#define dbhBufferSize (kAllBuffSz + kOneBuffSz)
#define dbglog_SoundStuff (0 && dbglog_HAVE)
#define dbglog_SoundBuffStats (0 && dbglog_HAVE)
LOCALVAR tpSoundSamp TheSoundBuffer = nullpr;
volatile static uint16_t ThePlayOffset;
volatile static uint16_t TheFillOffset;
volatile static uint16_t MinFilledSoundBuffs;
#if dbglog_SoundBuffStats
LOCALVAR uint16_t MaxFilledSoundBuffs;
#endif
LOCALVAR uint16_t TheWriteOffset;
LOCALPROC Sound_Init0(void)
{
ThePlayOffset = 0;
TheFillOffset = 0;
TheWriteOffset = 0;
}
LOCALPROC Sound_Start0(void)
{
/* Reset variables */
MinFilledSoundBuffs = kSoundBuffers + 1;
#if dbglog_SoundBuffStats
MaxFilledSoundBuffs = 0;
#endif
}
GLOBALOSGLUFUNC tpSoundSamp Sound_BeginWrite(uint16_t n, uint16_t *actL)
{
uint16_t ToFillLen = kAllBuffLen - (TheWriteOffset - ThePlayOffset);
uint16_t WriteBuffContig =
kOneBuffLen - (TheWriteOffset & kOneBuffMask);
if (WriteBuffContig < n) {
n = WriteBuffContig;
}
if (ToFillLen < n) {
/* overwrite previous buffer */
#if dbglog_SoundStuff
dbglog_writeln("sound buffer over flow");
#endif
TheWriteOffset -= kOneBuffLen;
}
*actL = n;
return TheSoundBuffer + (TheWriteOffset & kAllBuffMask);
}
#if 4 == kLn2SoundSampSz
LOCALPROC ConvertSoundBlockToNative(tpSoundSamp p)
{
int i;
for (i = kOneBuffLen; --i >= 0; ) {
*p++ -= 0x8000;
}
}
#else
#define ConvertSoundBlockToNative(p)
#endif
LOCALPROC Sound_WroteABlock(void)
{
#if (4 == kLn2SoundSampSz)
uint16_t PrevWriteOffset = TheWriteOffset - kOneBuffLen;
tpSoundSamp p = TheSoundBuffer + (PrevWriteOffset & kAllBuffMask);
#endif
#if dbglog_SoundStuff
dbglog_writeln("enter Sound_WroteABlock");
#endif
ConvertSoundBlockToNative(p);
TheFillOffset = TheWriteOffset;
#if dbglog_SoundBuffStats
{
uint16_t ToPlayLen = TheFillOffset
- ThePlayOffset;
uint16_t ToPlayBuffs = ToPlayLen >> kLnOneBuffLen;
if (ToPlayBuffs > MaxFilledSoundBuffs) {
MaxFilledSoundBuffs = ToPlayBuffs;
}
}
#endif
}
LOCALFUNC bool Sound_EndWrite0(uint16_t actL)
{
bool v;
TheWriteOffset += actL;
if (0 != (TheWriteOffset & kOneBuffMask)) {
v = false;
} else {
/* just finished a block */
Sound_WroteABlock();
v = true;
}
return v;
}
LOCALPROC Sound_SecondNotify0(void)
{
if (MinFilledSoundBuffs <= kSoundBuffers) {
if (MinFilledSoundBuffs > DesiredMinFilledSoundBuffs) {
#if dbglog_SoundStuff
dbglog_writeln("MinFilledSoundBuffs too high");
#endif
IncrNextTime();
} else if (MinFilledSoundBuffs < DesiredMinFilledSoundBuffs) {
#if dbglog_SoundStuff
dbglog_writeln("MinFilledSoundBuffs too low");
#endif
++TrueEmulatedTime;
}
#if dbglog_SoundBuffStats
dbglog_writelnNum("MinFilledSoundBuffs",
MinFilledSoundBuffs);
dbglog_writelnNum("MaxFilledSoundBuffs",
MaxFilledSoundBuffs);
MaxFilledSoundBuffs = 0;
#endif
MinFilledSoundBuffs = kSoundBuffers + 1;
}
}
typedef uint16_t trSoundTemp;
#define kCenterTempSound 0x8000
#define AudioStepVal 0x0040
#if 3 == kLn2SoundSampSz
#define ConvertTempSoundSampleFromNative(v) ((v) << 8)
#elif 4 == kLn2SoundSampSz
#define ConvertTempSoundSampleFromNative(v) ((v) + kCenterSound)
#else
#error "unsupported kLn2SoundSampSz"
#endif
#if 3 == kLn2SoundSampSz
#define ConvertTempSoundSampleToNative(v) ((v) >> 8)
#elif 4 == kLn2SoundSampSz
#define ConvertTempSoundSampleToNative(v) ((v) - kCenterSound)
#else
#error "unsupported kLn2SoundSampSz"
#endif
LOCALPROC SoundRampTo(trSoundTemp *last_val, trSoundTemp dst_val,
tpSoundSamp *stream, int *len)
{
trSoundTemp diff;
tpSoundSamp p = *stream;
int n = *len;
trSoundTemp v1 = *last_val;
while ((v1 != dst_val) && (0 != n)) {
if (v1 > dst_val) {
diff = v1 - dst_val;
if (diff > AudioStepVal) {
v1 -= AudioStepVal;
} else {
v1 = dst_val;
}
} else {
diff = dst_val - v1;
if (diff > AudioStepVal) {
v1 += AudioStepVal;
} else {
v1 = dst_val;
}
}
--n;
*p++ = ConvertTempSoundSampleToNative(v1);
}
*stream = p;
*len = n;
*last_val = v1;
}
struct SoundR {
tpSoundSamp fTheSoundBuffer;
volatile uint16_t (*fPlayOffset);
volatile uint16_t (*fFillOffset);
volatile uint16_t (*fMinFilledSoundBuffs);
volatile trSoundTemp lastv;
bool wantplaying;
bool HaveStartedPlaying;
};
typedef struct SoundR SoundR;
static void audio_callback(void *udata, Uint8 *stream, int len)
{
uint16_t ToPlayLen;
uint16_t FilledSoundBuffs;
int i;
SoundR *datp = (SoundR *)udata;
tpSoundSamp CurSoundBuffer = datp->fTheSoundBuffer;
uint16_t CurPlayOffset = *datp->fPlayOffset;
trSoundTemp v0 = datp->lastv;
trSoundTemp v1 = v0;
tpSoundSamp dst = (tpSoundSamp)stream;
#if kLn2SoundSampSz > 3
len >>= (kLn2SoundSampSz - 3);
#endif
#if dbglog_SoundStuff
dbglog_writeln("Enter audio_callback");
dbglog_writelnNum("len", len);
#endif
label_retry:
ToPlayLen = *datp->fFillOffset - CurPlayOffset;
FilledSoundBuffs = ToPlayLen >> kLnOneBuffLen;
if (! datp->wantplaying) {
#if dbglog_SoundStuff
dbglog_writeln("playing end transistion");
#endif
SoundRampTo(&v1, kCenterTempSound, &dst, &len);
ToPlayLen = 0;
} else if (! datp->HaveStartedPlaying) {
#if dbglog_SoundStuff
dbglog_writeln("playing start block");
#endif
if ((ToPlayLen >> kLnOneBuffLen) < 8) {
ToPlayLen = 0;
} else {
tpSoundSamp p = datp->fTheSoundBuffer
+ (CurPlayOffset & kAllBuffMask);
trSoundTemp v2 = ConvertTempSoundSampleFromNative(*p);
#if dbglog_SoundStuff
dbglog_writeln("have enough samples to start");
#endif
SoundRampTo(&v1, v2, &dst, &len);
if (v1 == v2) {
#if dbglog_SoundStuff
dbglog_writeln("finished start transition");
#endif
datp->HaveStartedPlaying = true;
}
}
}
if (0 == len) {
/* done */
if (FilledSoundBuffs < *datp->fMinFilledSoundBuffs) {
*datp->fMinFilledSoundBuffs = FilledSoundBuffs;
}
} else if (0 == ToPlayLen) {
#if dbglog_SoundStuff
dbglog_writeln("under run");
#endif
for (i = 0; i < len; ++i) {
*dst++ = ConvertTempSoundSampleToNative(v1);
}
*datp->fMinFilledSoundBuffs = 0;
} else {
uint16_t PlayBuffContig = kAllBuffLen
- (CurPlayOffset & kAllBuffMask);
tpSoundSamp p = CurSoundBuffer
+ (CurPlayOffset & kAllBuffMask);
if (ToPlayLen > PlayBuffContig) {
ToPlayLen = PlayBuffContig;
}
if (ToPlayLen > len) {
ToPlayLen = len;
}
for (i = 0; i < ToPlayLen; ++i) {
*dst++ = *p++;
}
v1 = ConvertTempSoundSampleFromNative(p[-1]);
CurPlayOffset += ToPlayLen;
len -= ToPlayLen;
*datp->fPlayOffset = CurPlayOffset;
goto label_retry;
}
datp->lastv = v1;
}
LOCALVAR SoundR cur_audio;
LOCALVAR bool HaveSoundOut = false;
LOCALPROC Sound_Stop(void)
{
#if dbglog_SoundStuff
dbglog_writeln("enter Sound_Stop");
#endif
if (cur_audio.wantplaying && HaveSoundOut) {
uint16_t retry_limit = 50; /* half of a second */
cur_audio.wantplaying = false;
label_retry:
if (kCenterTempSound == cur_audio.lastv) {
#if dbglog_SoundStuff
dbglog_writeln("reached kCenterTempSound");
#endif
/* done */
} else if (0 == --retry_limit) {
#if dbglog_SoundStuff
dbglog_writeln("retry limit reached");
#endif
/* done */
} else
{
/*
give time back, particularly important
if got here on a suspend event.
*/
#if dbglog_SoundStuff
dbglog_writeln("busy, so sleep");
#endif
(void) SDL_Delay(10);
goto label_retry;
}
SDL_PauseAudio(1);
}
#if dbglog_SoundStuff
dbglog_writeln("leave Sound_Stop");
#endif
}
LOCALPROC Sound_Start(void)
{
if ((! cur_audio.wantplaying) && HaveSoundOut) {
Sound_Start0();
cur_audio.lastv = kCenterTempSound;
cur_audio.HaveStartedPlaying = false;
cur_audio.wantplaying = true;
SDL_PauseAudio(0);
}
}
LOCALPROC Sound_UnInit(void)
{
if (HaveSoundOut) {
SDL_CloseAudio();
}
}
#define SOUND_SAMPLERATE 22255 /* = round(7833600 * 2 / 704) */
LOCALFUNC bool Sound_Init(void)
{
SDL_AudioSpec desired;
Sound_Init0();
cur_audio.fTheSoundBuffer = TheSoundBuffer;
cur_audio.fPlayOffset = &ThePlayOffset;
cur_audio.fFillOffset = &TheFillOffset;
cur_audio.fMinFilledSoundBuffs = &MinFilledSoundBuffs;
cur_audio.wantplaying = false;
desired.freq = SOUND_SAMPLERATE;
#if 3 == kLn2SoundSampSz
desired.format = AUDIO_U8;
#elif 4 == kLn2SoundSampSz
desired.format = AUDIO_S16SYS;
#else
#error "unsupported audio format"
#endif
desired.channels = 1;
desired.samples = 1024;
desired.callback = audio_callback;
desired.userdata = (void *)&cur_audio;
/* Open the audio device */
if (SDL_OpenAudio(&desired, NULL) < 0) {
fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
} else {
HaveSoundOut = true;
Sound_Start();
/*
This should be taken care of by LeaveSpeedStopped,
but since takes a while to get going properly,
start early.
*/
}
return true; /* keep going, even if no sound */
}
GLOBALOSGLUPROC Sound_EndWrite(uint16_t actL)
{
if (Sound_EndWrite0(actL)) {
}
}
LOCALPROC Sound_SecondNotify(void)
{
if (HaveSoundOut) {
Sound_SecondNotify0();
}
}
#endif
/* --- basic dialogs --- */
LOCALPROC CheckSavedMacMsg(void)
{
/* called only on quit, if error saved but not yet reported */
if (nullpr != SavedBriefMsg) {
char briefMsg0[ClStrMaxLength + 1];
char longMsg0[ClStrMaxLength + 1];
NativeStrFromCStr(briefMsg0, SavedBriefMsg);
NativeStrFromCStr(longMsg0, SavedLongMsg);
if (0 != SDL_ShowSimpleMessageBox(
SDL_MESSAGEBOX_ERROR,
SavedBriefMsg,
SavedLongMsg,
main_wind
))
{
fprintf(stderr, "%s\n", briefMsg0);
fprintf(stderr, "%s\n", longMsg0);
}
SavedBriefMsg = nullpr;
}
}
/* --- clipboard --- */
#if IncludeHostTextClipExchange
LOCALFUNC uimr MacRoman2UniCodeSize(uint8_t *s, uimr L)
{
uimr i;
uint8_t x;
uimr n;
uimr v = 0;
for (i = 0; i < L; ++i) {
x = *s++;
if (x < 128) {
n = 1;
} else {
switch (x) {
case 0x80: n = 2; break;
/* LATIN CAPITAL LETTER A WITH DIAERESIS */
case 0x81: n = 2; break;
/* LATIN CAPITAL LETTER A WITH RING ABOVE */
case 0x82: n = 2; break;
/* LATIN CAPITAL LETTER C WITH CEDILLA */
case 0x83: n = 2; break;
/* LATIN CAPITAL LETTER E WITH ACUTE */
case 0x84: n = 2; break;
/* LATIN CAPITAL LETTER N WITH TILDE */
case 0x85: n = 2; break;
/* LATIN CAPITAL LETTER O WITH DIAERESIS */
case 0x86: n = 2; break;
/* LATIN CAPITAL LETTER U WITH DIAERESIS */
case 0x87: n = 2; break;
/* LATIN SMALL LETTER A WITH ACUTE */
case 0x88: n = 2; break;
/* LATIN SMALL LETTER A WITH GRAVE */
case 0x89: n = 2; break;
/* LATIN SMALL LETTER A WITH CIRCUMFLEX */
case 0x8A: n = 2; break;
/* LATIN SMALL LETTER A WITH DIAERESIS */
case 0x8B: n = 2; break;
/* LATIN SMALL LETTER A WITH TILDE */
case 0x8C: n = 2; break;
/* LATIN SMALL LETTER A WITH RING ABOVE */
case 0x8D: n = 2; break;
/* LATIN SMALL LETTER C WITH CEDILLA */
case 0x8E: n = 2; break;
/* LATIN SMALL LETTER E WITH ACUTE */
case 0x8F: n = 2; break;
/* LATIN SMALL LETTER E WITH GRAVE */
case 0x90: n = 2; break;
/* LATIN SMALL LETTER E WITH CIRCUMFLEX */
case 0x91: n = 2; break;
/* LATIN SMALL LETTER E WITH DIAERESIS */
case 0x92: n = 2; break;
/* LATIN SMALL LETTER I WITH ACUTE */
case 0x93: n = 2; break;
/* LATIN SMALL LETTER I WITH GRAVE */
case 0x94: n = 2; break;
/* LATIN SMALL LETTER I WITH CIRCUMFLEX */
case 0x95: n = 2; break;
/* LATIN SMALL LETTER I WITH DIAERESIS */
case 0x96: n = 2; break;
/* LATIN SMALL LETTER N WITH TILDE */
case 0x97: n = 2; break;
/* LATIN SMALL LETTER O WITH ACUTE */
case 0x98: n = 2; break;
/* LATIN SMALL LETTER O WITH GRAVE */
case 0x99: n = 2; break;
/* LATIN SMALL LETTER O WITH CIRCUMFLEX */
case 0x9A: n = 2; break;
/* LATIN SMALL LETTER O WITH DIAERESIS */
case 0x9B: n = 2; break;
/* LATIN SMALL LETTER O WITH TILDE */
case 0x9C: n = 2; break;
/* LATIN SMALL LETTER U WITH ACUTE */
case 0x9D: n = 2; break;
/* LATIN SMALL LETTER U WITH GRAVE */
case 0x9E: n = 2; break;
/* LATIN SMALL LETTER U WITH CIRCUMFLEX */
case 0x9F: n = 2; break;
/* LATIN SMALL LETTER U WITH DIAERESIS */
case 0xA0: n = 3; break;
/* DAGGER */
case 0xA1: n = 2; break;
/* DEGREE SIGN */
case 0xA2: n = 2; break;
/* CENT SIGN */
case 0xA3: n = 2; break;
/* POUND SIGN */
case 0xA4: n = 2; break;
/* SECTION SIGN */
case 0xA5: n = 3; break;
/* BULLET */
case 0xA6: n = 2; break;
/* PILCROW SIGN */
case 0xA7: n = 2; break;
/* LATIN SMALL LETTER SHARP S */
case 0xA8: n = 2; break;
/* REGISTERED SIGN */
case 0xA9: n = 2; break;
/* COPYRIGHT SIGN */
case 0xAA: n = 3; break;
/* TRADE MARK SIGN */
case 0xAB: n = 2; break;
/* ACUTE ACCENT */
case 0xAC: n = 2; break;
/* DIAERESIS */
case 0xAD: n = 3; break;
/* NOT EQUAL TO */
case 0xAE: n = 2; break;
/* LATIN CAPITAL LETTER AE */
case 0xAF: n = 2; break;
/* LATIN CAPITAL LETTER O WITH STROKE */
case 0xB0: n = 3; break;
/* INFINITY */
case 0xB1: n = 2; break;
/* PLUS-MINUS SIGN */
case 0xB2: n = 3; break;
/* LESS-THAN OR EQUAL TO */
case 0xB3: n = 3; break;
/* GREATER-THAN OR EQUAL TO */
case 0xB4: n = 2; break;
/* YEN SIGN */
case 0xB5: n = 2; break;
/* MICRO SIGN */
case 0xB6: n = 3; break;
/* PARTIAL DIFFERENTIAL */
case 0xB7: n = 3; break;
/* N-ARY SUMMATION */
case 0xB8: n = 3; break;
/* N-ARY PRODUCT */
case 0xB9: n = 2; break;
/* GREEK SMALL LETTER PI */
case 0xBA: n = 3; break;
/* INTEGRAL */
case 0xBB: n = 2; break;
/* FEMININE ORDINAL INDICATOR */
case 0xBC: n = 2; break;
/* MASCULINE ORDINAL INDICATOR */
case 0xBD: n = 2; break;
/* GREEK CAPITAL LETTER OMEGA */
case 0xBE: n = 2; break;
/* LATIN SMALL LETTER AE */
case 0xBF: n = 2; break;
/* LATIN SMALL LETTER O WITH STROKE */
case 0xC0: n = 2; break;
/* INVERTED QUESTION MARK */
case 0xC1: n = 2; break;
/* INVERTED EXCLAMATION MARK */
case 0xC2: n = 2; break;
/* NOT SIGN */
case 0xC3: n = 3; break;
/* SQUARE ROOT */
case 0xC4: n = 2; break;
/* LATIN SMALL LETTER F WITH HOOK */
case 0xC5: n = 3; break;
/* ALMOST EQUAL TO */
case 0xC6: n = 3; break;
/* INCREMENT */
case 0xC7: n = 2; break;
/* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
case 0xC8: n = 2; break;
/* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
case 0xC9: n = 3; break;
/* HORIZONTAL ELLIPSIS */
case 0xCA: n = 2; break;
/* NO-BREAK SPACE */
case 0xCB: n = 2; break;
/* LATIN CAPITAL LETTER A WITH GRAVE */
case 0xCC: n = 2; break;
/* LATIN CAPITAL LETTER A WITH TILDE */
case 0xCD: n = 2; break;
/* LATIN CAPITAL LETTER O WITH TILDE */
case 0xCE: n = 2; break;
/* LATIN CAPITAL LIGATURE OE */
case 0xCF: n = 2; break;
/* LATIN SMALL LIGATURE OE */
case 0xD0: n = 3; break;
/* EN DASH */
case 0xD1: n = 3; break;
/* EM DASH */
case 0xD2: n = 3; break;
/* LEFT DOUBLE QUOTATION MARK */
case 0xD3: n = 3; break;
/* RIGHT DOUBLE QUOTATION MARK */
case 0xD4: n = 3; break;
/* LEFT SINGLE QUOTATION MARK */
case 0xD5: n = 3; break;
/* RIGHT SINGLE QUOTATION MARK */
case 0xD6: n = 2; break;
/* DIVISION SIGN */
case 0xD7: n = 3; break;
/* LOZENGE */
case 0xD8: n = 2; break;
/* LATIN SMALL LETTER Y WITH DIAERESIS */
case 0xD9: n = 2; break;
/* LATIN CAPITAL LETTER Y WITH DIAERESIS */
case 0xDA: n = 3; break;
/* FRACTION SLASH */
case 0xDB: n = 3; break;
/* EURO SIGN */
case 0xDC: n = 3; break;
/* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
case 0xDD: n = 3; break;
/* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
case 0xDE: n = 3; break;
/* LATIN SMALL LIGATURE FI */
case 0xDF: n = 3; break;
/* LATIN SMALL LIGATURE FL */
case 0xE0: n = 3; break;
/* DOUBLE DAGGER */
case 0xE1: n = 2; break;
/* MIDDLE DOT */
case 0xE2: n = 3; break;
/* SINGLE LOW-9 QUOTATION MARK */
case 0xE3: n = 3; break;
/* DOUBLE LOW-9 QUOTATION MARK */
case 0xE4: n = 3; break;
/* PER MILLE SIGN */
case 0xE5: n = 2; break;
/* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
case 0xE6: n = 2; break;
/* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
case 0xE7: n = 2; break;
/* LATIN CAPITAL LETTER A WITH ACUTE */
case 0xE8: n = 2; break;
/* LATIN CAPITAL LETTER E WITH DIAERESIS */
case 0xE9: n = 2; break;
/* LATIN CAPITAL LETTER E WITH GRAVE */
case 0xEA: n = 2; break;
/* LATIN CAPITAL LETTER I WITH ACUTE */
case 0xEB: n = 2; break;
/* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
case 0xEC: n = 2; break;
/* LATIN CAPITAL LETTER I WITH DIAERESIS */
case 0xED: n = 2; break;
/* LATIN CAPITAL LETTER I WITH GRAVE */
case 0xEE: n = 2; break;
/* LATIN CAPITAL LETTER O WITH ACUTE */
case 0xEF: n = 2; break;
/* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
case 0xF0: n = 3; break;
/* Apple logo */
case 0xF1: n = 2; break;
/* LATIN CAPITAL LETTER O WITH GRAVE */
case 0xF2: n = 2; break;
/* LATIN CAPITAL LETTER U WITH ACUTE */
case 0xF3: n = 2; break;
/* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
case 0xF4: n = 2; break;
/* LATIN CAPITAL LETTER U WITH GRAVE */
case 0xF5: n = 2; break;
/* LATIN SMALL LETTER DOTLESS I */
case 0xF6: n = 2; break;
/* MODIFIER LETTER CIRCUMFLEX ACCENT */
case 0xF7: n = 2; break;
/* SMALL TILDE */
case 0xF8: n = 2; break;
/* MACRON */
case 0xF9: n = 2; break;
/* BREVE */
case 0xFA: n = 2; break;
/* DOT ABOVE */
case 0xFB: n = 2; break;
/* RING ABOVE */
case 0xFC: n = 2; break;
/* CEDILLA */
case 0xFD: n = 2; break;
/* DOUBLE ACUTE ACCENT */
case 0xFE: n = 2; break;
/* OGONEK */
case 0xFF: n = 2; break;
/* CARON */
default: n = 1; break;
/* shouldn't get here */
}
}
v += n;
}
return v;
}
#endif
#if IncludeHostTextClipExchange
LOCALPROC MacRoman2UniCodeData(uint8_t *s, uimr L, char *t)
{
uimr i;
uint8_t x;
for (i = 0; i < L; ++i) {
x = *s++;
if (x < 128) {
*t++ = x;
} else {
switch (x) {
case 0x80: *t++ = 0xC3; *t++ = 0x84; break;
/* LATIN CAPITAL LETTER A WITH DIAERESIS */
case 0x81: *t++ = 0xC3; *t++ = 0x85; break;
/* LATIN CAPITAL LETTER A WITH RING ABOVE */
case 0x82: *t++ = 0xC3; *t++ = 0x87; break;
/* LATIN CAPITAL LETTER C WITH CEDILLA */
case 0x83: *t++ = 0xC3; *t++ = 0x89; break;
/* LATIN CAPITAL LETTER E WITH ACUTE */
case 0x84: *t++ = 0xC3; *t++ = 0x91; break;
/* LATIN CAPITAL LETTER N WITH TILDE */
case 0x85: *t++ = 0xC3; *t++ = 0x96; break;
/* LATIN CAPITAL LETTER O WITH DIAERESIS */
case 0x86: *t++ = 0xC3; *t++ = 0x9C; break;
/* LATIN CAPITAL LETTER U WITH DIAERESIS */
case 0x87: *t++ = 0xC3; *t++ = 0xA1; break;
/* LATIN SMALL LETTER A WITH ACUTE */
case 0x88: *t++ = 0xC3; *t++ = 0xA0; break;
/* LATIN SMALL LETTER A WITH GRAVE */
case 0x89: *t++ = 0xC3; *t++ = 0xA2; break;
/* LATIN SMALL LETTER A WITH CIRCUMFLEX */
case 0x8A: *t++ = 0xC3; *t++ = 0xA4; break;
/* LATIN SMALL LETTER A WITH DIAERESIS */
case 0x8B: *t++ = 0xC3; *t++ = 0xA3; break;
/* LATIN SMALL LETTER A WITH TILDE */
case 0x8C: *t++ = 0xC3; *t++ = 0xA5; break;
/* LATIN SMALL LETTER A WITH RING ABOVE */
case 0x8D: *t++ = 0xC3; *t++ = 0xA7; break;
/* LATIN SMALL LETTER C WITH CEDILLA */
case 0x8E: *t++ = 0xC3; *t++ = 0xA9; break;
/* LATIN SMALL LETTER E WITH ACUTE */
case 0x8F: *t++ = 0xC3; *t++ = 0xA8; break;
/* LATIN SMALL LETTER E WITH GRAVE */
case 0x90: *t++ = 0xC3; *t++ = 0xAA; break;
/* LATIN SMALL LETTER E WITH CIRCUMFLEX */
case 0x91: *t++ = 0xC3; *t++ = 0xAB; break;
/* LATIN SMALL LETTER E WITH DIAERESIS */
case 0x92: *t++ = 0xC3; *t++ = 0xAD; break;
/* LATIN SMALL LETTER I WITH ACUTE */
case 0x93: *t++ = 0xC3; *t++ = 0xAC; break;
/* LATIN SMALL LETTER I WITH GRAVE */
case 0x94: *t++ = 0xC3; *t++ = 0xAE; break;
/* LATIN SMALL LETTER I WITH CIRCUMFLEX */
case 0x95: *t++ = 0xC3; *t++ = 0xAF; break;
/* LATIN SMALL LETTER I WITH DIAERESIS */
case 0x96: *t++ = 0xC3; *t++ = 0xB1; break;
/* LATIN SMALL LETTER N WITH TILDE */
case 0x97: *t++ = 0xC3; *t++ = 0xB3; break;
/* LATIN SMALL LETTER O WITH ACUTE */
case 0x98: *t++ = 0xC3; *t++ = 0xB2; break;
/* LATIN SMALL LETTER O WITH GRAVE */
case 0x99: *t++ = 0xC3; *t++ = 0xB4; break;
/* LATIN SMALL LETTER O WITH CIRCUMFLEX */
case 0x9A: *t++ = 0xC3; *t++ = 0xB6; break;
/* LATIN SMALL LETTER O WITH DIAERESIS */
case 0x9B: *t++ = 0xC3; *t++ = 0xB5; break;
/* LATIN SMALL LETTER O WITH TILDE */
case 0x9C: *t++ = 0xC3; *t++ = 0xBA; break;
/* LATIN SMALL LETTER U WITH ACUTE */
case 0x9D: *t++ = 0xC3; *t++ = 0xB9; break;
/* LATIN SMALL LETTER U WITH GRAVE */
case 0x9E: *t++ = 0xC3; *t++ = 0xBB; break;
/* LATIN SMALL LETTER U WITH CIRCUMFLEX */
case 0x9F: *t++ = 0xC3; *t++ = 0xBC; break;
/* LATIN SMALL LETTER U WITH DIAERESIS */
case 0xA0: *t++ = 0xE2; *t++ = 0x80; *t++ = 0xA0; break;
/* DAGGER */
case 0xA1: *t++ = 0xC2; *t++ = 0xB0; break;
/* DEGREE SIGN */
case 0xA2: *t++ = 0xC2; *t++ = 0xA2; break;
/* CENT SIGN */
case 0xA3: *t++ = 0xC2; *t++ = 0xA3; break;
/* POUND SIGN */
case 0xA4: *t++ = 0xC2; *t++ = 0xA7; break;
/* SECTION SIGN */
case 0xA5: *t++ = 0xE2; *t++ = 0x80; *t++ = 0xA2; break;
/* BULLET */
case 0xA6: *t++ = 0xC2; *t++ = 0xB6; break;
/* PILCROW SIGN */
case 0xA7: *t++ = 0xC3; *t++ = 0x9F; break;
/* LATIN SMALL LETTER SHARP S */
case 0xA8: *t++ = 0xC2; *t++ = 0xAE; break;
/* REGISTERED SIGN */
case 0xA9: *t++ = 0xC2; *t++ = 0xA9; break;
/* COPYRIGHT SIGN */
case 0xAA: *t++ = 0xE2; *t++ = 0x84; *t++ = 0xA2; break;
/* TRADE MARK SIGN */
case 0xAB: *t++ = 0xC2; *t++ = 0xB4; break;
/* ACUTE ACCENT */
case 0xAC: *t++ = 0xC2; *t++ = 0xA8; break;
/* DIAERESIS */
case 0xAD: *t++ = 0xE2; *t++ = 0x89; *t++ = 0xA0; break;
/* NOT EQUAL TO */
case 0xAE: *t++ = 0xC3; *t++ = 0x86; break;
/* LATIN CAPITAL LETTER AE */
case 0xAF: *t++ = 0xC3; *t++ = 0x98; break;
/* LATIN CAPITAL LETTER O WITH STROKE */
case 0xB0: *t++ = 0xE2; *t++ = 0x88; *t++ = 0x9E; break;
/* INFINITY */
case 0xB1: *t++ = 0xC2; *t++ = 0xB1; break;
/* PLUS-MINUS SIGN */
case 0xB2: *t++ = 0xE2; *t++ = 0x89; *t++ = 0xA4; break;
/* LESS-THAN OR EQUAL TO */
case 0xB3: *t++ = 0xE2; *t++ = 0x89; *t++ = 0xA5; break;
/* GREATER-THAN OR EQUAL TO */
case 0xB4: *t++ = 0xC2; *t++ = 0xA5; break;
/* YEN SIGN */
case 0xB5: *t++ = 0xC2; *t++ = 0xB5; break;
/* MICRO SIGN */
case 0xB6: *t++ = 0xE2; *t++ = 0x88; *t++ = 0x82; break;
/* PARTIAL DIFFERENTIAL */
case 0xB7: *t++ = 0xE2; *t++ = 0x88; *t++ = 0x91; break;
/* N-ARY SUMMATION */
case 0xB8: *t++ = 0xE2; *t++ = 0x88; *t++ = 0x8F; break;
/* N-ARY PRODUCT */
case 0xB9: *t++ = 0xCF; *t++ = 0x80; break;
/* GREEK SMALL LETTER PI */
case 0xBA: *t++ = 0xE2; *t++ = 0x88; *t++ = 0xAB; break;
/* INTEGRAL */
case 0xBB: *t++ = 0xC2; *t++ = 0xAA; break;
/* FEMININE ORDINAL INDICATOR */
case 0xBC: *t++ = 0xC2; *t++ = 0xBA; break;
/* MASCULINE ORDINAL INDICATOR */
case 0xBD: *t++ = 0xCE; *t++ = 0xA9; break;
/* GREEK CAPITAL LETTER OMEGA */
case 0xBE: *t++ = 0xC3; *t++ = 0xA6; break;
/* LATIN SMALL LETTER AE */
case 0xBF: *t++ = 0xC3; *t++ = 0xB8; break;
/* LATIN SMALL LETTER O WITH STROKE */
case 0xC0: *t++ = 0xC2; *t++ = 0xBF; break;
/* INVERTED QUESTION MARK */
case 0xC1: *t++ = 0xC2; *t++ = 0xA1; break;
/* INVERTED EXCLAMATION MARK */
case 0xC2: *t++ = 0xC2; *t++ = 0xAC; break;
/* NOT SIGN */
case 0xC3: *t++ = 0xE2; *t++ = 0x88; *t++ = 0x9A; break;
/* SQUARE ROOT */
case 0xC4: *t++ = 0xC6; *t++ = 0x92; break;
/* LATIN SMALL LETTER F WITH HOOK */
case 0xC5: *t++ = 0xE2; *t++ = 0x89; *t++ = 0x88; break;
/* ALMOST EQUAL TO */
case 0xC6: *t++ = 0xE2; *t++ = 0x88; *t++ = 0x86; break;
/* INCREMENT */
case 0xC7: *t++ = 0xC2; *t++ = 0xAB; break;
/* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
case 0xC8: *t++ = 0xC2; *t++ = 0xBB; break;
/* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
case 0xC9: *t++ = 0xE2; *t++ = 0x80; *t++ = 0xA6; break;
/* HORIZONTAL ELLIPSIS */
case 0xCA: *t++ = 0xC2; *t++ = 0xA0; break;
/* NO-BREAK SPACE */
case 0xCB: *t++ = 0xC3; *t++ = 0x80; break;
/* LATIN CAPITAL LETTER A WITH GRAVE */
case 0xCC: *t++ = 0xC3; *t++ = 0x83; break;
/* LATIN CAPITAL LETTER A WITH TILDE */
case 0xCD: *t++ = 0xC3; *t++ = 0x95; break;
/* LATIN CAPITAL LETTER O WITH TILDE */
case 0xCE: *t++ = 0xC5; *t++ = 0x92; break;
/* LATIN CAPITAL LIGATURE OE */
case 0xCF: *t++ = 0xC5; *t++ = 0x93; break;
/* LATIN SMALL LIGATURE OE */
case 0xD0: *t++ = 0xE2; *t++ = 0x80; *t++ = 0x93; break;
/* EN DASH */
case 0xD1: *t++ = 0xE2; *t++ = 0x80; *t++ = 0x94; break;
/* EM DASH */
case 0xD2: *t++ = 0xE2; *t++ = 0x80; *t++ = 0x9C; break;
/* LEFT DOUBLE QUOTATION MARK */
case 0xD3: *t++ = 0xE2; *t++ = 0x80; *t++ = 0x9D; break;
/* RIGHT DOUBLE QUOTATION MARK */
case 0xD4: *t++ = 0xE2; *t++ = 0x80; *t++ = 0x98; break;
/* LEFT SINGLE QUOTATION MARK */
case 0xD5: *t++ = 0xE2; *t++ = 0x80; *t++ = 0x99; break;
/* RIGHT SINGLE QUOTATION MARK */
case 0xD6: *t++ = 0xC3; *t++ = 0xB7; break;
/* DIVISION SIGN */
case 0xD7: *t++ = 0xE2; *t++ = 0x97; *t++ = 0x8A; break;
/* LOZENGE */
case 0xD8: *t++ = 0xC3; *t++ = 0xBF; break;
/* LATIN SMALL LETTER Y WITH DIAERESIS */
case 0xD9: *t++ = 0xC5; *t++ = 0xB8; break;
/* LATIN CAPITAL LETTER Y WITH DIAERESIS */
case 0xDA: *t++ = 0xE2; *t++ = 0x81; *t++ = 0x84; break;
/* FRACTION SLASH */
case 0xDB: *t++ = 0xE2; *t++ = 0x82; *t++ = 0xAC; break;
/* EURO SIGN */
case 0xDC: *t++ = 0xE2; *t++ = 0x80; *t++ = 0xB9; break;
/* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
case 0xDD: *t++ = 0xE2; *t++ = 0x80; *t++ = 0xBA; break;
/* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
case 0xDE: *t++ = 0xEF; *t++ = 0xAC; *t++ = 0x81; break;
/* LATIN SMALL LIGATURE FI */
case 0xDF: *t++ = 0xEF; *t++ = 0xAC; *t++ = 0x82; break;
/* LATIN SMALL LIGATURE FL */
case 0xE0: *t++ = 0xE2; *t++ = 0x80; *t++ = 0xA1; break;
/* DOUBLE DAGGER */
case 0xE1: *t++ = 0xC2; *t++ = 0xB7; break;
/* MIDDLE DOT */
case 0xE2: *t++ = 0xE2; *t++ = 0x80; *t++ = 0x9A; break;
/* SINGLE LOW-9 QUOTATION MARK */
case 0xE3: *t++ = 0xE2; *t++ = 0x80; *t++ = 0x9E; break;
/* DOUBLE LOW-9 QUOTATION MARK */
case 0xE4: *t++ = 0xE2; *t++ = 0x80; *t++ = 0xB0; break;
/* PER MILLE SIGN */
case 0xE5: *t++ = 0xC3; *t++ = 0x82; break;
/* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
case 0xE6: *t++ = 0xC3; *t++ = 0x8A; break;
/* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
case 0xE7: *t++ = 0xC3; *t++ = 0x81; break;
/* LATIN CAPITAL LETTER A WITH ACUTE */
case 0xE8: *t++ = 0xC3; *t++ = 0x8B; break;
/* LATIN CAPITAL LETTER E WITH DIAERESIS */
case 0xE9: *t++ = 0xC3; *t++ = 0x88; break;
/* LATIN CAPITAL LETTER E WITH GRAVE */
case 0xEA: *t++ = 0xC3; *t++ = 0x8D; break;
/* LATIN CAPITAL LETTER I WITH ACUTE */
case 0xEB: *t++ = 0xC3; *t++ = 0x8E; break;
/* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
case 0xEC: *t++ = 0xC3; *t++ = 0x8F; break;
/* LATIN CAPITAL LETTER I WITH DIAERESIS */
case 0xED: *t++ = 0xC3; *t++ = 0x8C; break;
/* LATIN CAPITAL LETTER I WITH GRAVE */
case 0xEE: *t++ = 0xC3; *t++ = 0x93; break;
/* LATIN CAPITAL LETTER O WITH ACUTE */
case 0xEF: *t++ = 0xC3; *t++ = 0x94; break;
/* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
case 0xF0: *t++ = 0xEF; *t++ = 0xA3; *t++ = 0xBF; break;
/* Apple logo */
case 0xF1: *t++ = 0xC3; *t++ = 0x92; break;
/* LATIN CAPITAL LETTER O WITH GRAVE */
case 0xF2: *t++ = 0xC3; *t++ = 0x9A; break;
/* LATIN CAPITAL LETTER U WITH ACUTE */
case 0xF3: *t++ = 0xC3; *t++ = 0x9B; break;
/* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
case 0xF4: *t++ = 0xC3; *t++ = 0x99; break;
/* LATIN CAPITAL LETTER U WITH GRAVE */
case 0xF5: *t++ = 0xC4; *t++ = 0xB1; break;
/* LATIN SMALL LETTER DOTLESS I */
case 0xF6: *t++ = 0xCB; *t++ = 0x86; break;
/* MODIFIER LETTER CIRCUMFLEX ACCENT */
case 0xF7: *t++ = 0xCB; *t++ = 0x9C; break;
/* SMALL TILDE */
case 0xF8: *t++ = 0xC2; *t++ = 0xAF; break;
/* MACRON */
case 0xF9: *t++ = 0xCB; *t++ = 0x98; break;
/* BREVE */
case 0xFA: *t++ = 0xCB; *t++ = 0x99; break;
/* DOT ABOVE */
case 0xFB: *t++ = 0xCB; *t++ = 0x9A; break;
/* RING ABOVE */
case 0xFC: *t++ = 0xC2; *t++ = 0xB8; break;
/* CEDILLA */
case 0xFD: *t++ = 0xCB; *t++ = 0x9D; break;
/* DOUBLE ACUTE ACCENT */
case 0xFE: *t++ = 0xCB; *t++ = 0x9B; break;
/* OGONEK */
case 0xFF: *t++ = 0xCB; *t++ = 0x87; break;
/* CARON */
default: *t++ = '?'; break;
/* shouldn't get here */
}
}
}
}
#endif
#if IncludeHostTextClipExchange
GLOBALOSGLUFUNC tMacErr HTCEexport(tPbuf i)
{
tMacErr err;
char *p;
uint8_t * s = PbufDat[i];
uimr L = PbufSize[i];
uimr sz = MacRoman2UniCodeSize(s, L);
if (NULL == (p = malloc(sz + 1))) {
err = mnvm_miscErr;
} else {
MacRoman2UniCodeData(s, L, p);
p[sz] = 0;
if (0 != SDL_SetClipboardText(p)) {
err = mnvm_miscErr;
} else {
err = mnvm_noErr;
}
free(p);
}
return err;
}
#endif
#if IncludeHostTextClipExchange
LOCALFUNC tMacErr UniCodeStrLength(char *s, uimr *r)
{
tMacErr err;
uint8_t t;
uint8_t t2;
char *p = s;
uimr L = 0;
label_retry:
if (0 == (t = *p++)) {
err = mnvm_noErr;
/* done */
} else
if (0 == (0x80 & t)) {
/* One-byte code */
L += 1;
goto label_retry;
} else
if (0 == (0x40 & t)) {
/* continuation code, error */
err = mnvm_miscErr;
} else
if (0 == (t2 = *p++)) {
err = mnvm_miscErr;
} else
if (0x80 != (0xC0 & t2)) {
/* not a continuation code, error */
err = mnvm_miscErr;
} else
if (0 == (0x20 & t)) {
/* two bytes */
L += 2;
goto label_retry;
} else
if (0 == (t2 = *p++)) {
err = mnvm_miscErr;
} else
if (0x80 != (0xC0 & t2)) {
/* not a continuation code, error */
err = mnvm_miscErr;
} else
if (0 == (0x10 & t)) {
/* three bytes */
L += 3;
goto label_retry;
} else
if (0 == (t2 = *p++)) {
err = mnvm_miscErr;
} else
if (0x80 != (0xC0 & t2)) {
/* not a continuation code, error */
err = mnvm_miscErr;
} else
if (0 == (0x08 & t)) {
/* four bytes */
L += 5;
goto label_retry;
} else
{
err = mnvm_miscErr;
/* longer code not supported yet */
}
*r = L;
return err;
}
#endif
#if IncludeHostTextClipExchange
LOCALFUNC uint8_t UniCodePoint2MacRoman(uint32_t x)
{
/*
adapted from
http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/ROMAN.TXT
*/
uint8_t y;
if (x < 128) {
y = x;
} else {
switch (x) {
case 0x00C4: y = 0x80; break;
/* LATIN CAPITAL LETTER A WITH DIAERESIS */
case 0x00C5: y = 0x81; break;
/* LATIN CAPITAL LETTER A WITH RING ABOVE */
case 0x00C7: y = 0x82; break;
/* LATIN CAPITAL LETTER C WITH CEDILLA */
case 0x00C9: y = 0x83; break;
/* LATIN CAPITAL LETTER E WITH ACUTE */
case 0x00D1: y = 0x84; break;
/* LATIN CAPITAL LETTER N WITH TILDE */
case 0x00D6: y = 0x85; break;
/* LATIN CAPITAL LETTER O WITH DIAERESIS */
case 0x00DC: y = 0x86; break;
/* LATIN CAPITAL LETTER U WITH DIAERESIS */
case 0x00E1: y = 0x87; break;
/* LATIN SMALL LETTER A WITH ACUTE */
case 0x00E0: y = 0x88; break;
/* LATIN SMALL LETTER A WITH GRAVE */
case 0x00E2: y = 0x89; break;
/* LATIN SMALL LETTER A WITH CIRCUMFLEX */
case 0x00E4: y = 0x8A; break;
/* LATIN SMALL LETTER A WITH DIAERESIS */
case 0x00E3: y = 0x8B; break;
/* LATIN SMALL LETTER A WITH TILDE */
case 0x00E5: y = 0x8C; break;
/* LATIN SMALL LETTER A WITH RING ABOVE */
case 0x00E7: y = 0x8D; break;
/* LATIN SMALL LETTER C WITH CEDILLA */
case 0x00E9: y = 0x8E; break;
/* LATIN SMALL LETTER E WITH ACUTE */
case 0x00E8: y = 0x8F; break;
/* LATIN SMALL LETTER E WITH GRAVE */
case 0x00EA: y = 0x90; break;
/* LATIN SMALL LETTER E WITH CIRCUMFLEX */
case 0x00EB: y = 0x91; break;
/* LATIN SMALL LETTER E WITH DIAERESIS */
case 0x00ED: y = 0x92; break;
/* LATIN SMALL LETTER I WITH ACUTE */
case 0x00EC: y = 0x93; break;
/* LATIN SMALL LETTER I WITH GRAVE */
case 0x00EE: y = 0x94; break;
/* LATIN SMALL LETTER I WITH CIRCUMFLEX */
case 0x00EF: y = 0x95; break;
/* LATIN SMALL LETTER I WITH DIAERESIS */
case 0x00F1: y = 0x96; break;
/* LATIN SMALL LETTER N WITH TILDE */
case 0x00F3: y = 0x97; break;
/* LATIN SMALL LETTER O WITH ACUTE */
case 0x00F2: y = 0x98; break;
/* LATIN SMALL LETTER O WITH GRAVE */
case 0x00F4: y = 0x99; break;
/* LATIN SMALL LETTER O WITH CIRCUMFLEX */
case 0x00F6: y = 0x9A; break;
/* LATIN SMALL LETTER O WITH DIAERESIS */
case 0x00F5: y = 0x9B; break;
/* LATIN SMALL LETTER O WITH TILDE */
case 0x00FA: y = 0x9C; break;
/* LATIN SMALL LETTER U WITH ACUTE */
case 0x00F9: y = 0x9D; break;
/* LATIN SMALL LETTER U WITH GRAVE */
case 0x00FB: y = 0x9E; break;
/* LATIN SMALL LETTER U WITH CIRCUMFLEX */
case 0x00FC: y = 0x9F; break;
/* LATIN SMALL LETTER U WITH DIAERESIS */
case 0x2020: y = 0xA0; break;
/* DAGGER */
case 0x00B0: y = 0xA1; break;
/* DEGREE SIGN */
case 0x00A2: y = 0xA2; break;
/* CENT SIGN */
case 0x00A3: y = 0xA3; break;
/* POUND SIGN */
case 0x00A7: y = 0xA4; break;
/* SECTION SIGN */
case 0x2022: y = 0xA5; break;
/* BULLET */
case 0x00B6: y = 0xA6; break;
/* PILCROW SIGN */
case 0x00DF: y = 0xA7; break;
/* LATIN SMALL LETTER SHARP S */
case 0x00AE: y = 0xA8; break;
/* REGISTERED SIGN */
case 0x00A9: y = 0xA9; break;
/* COPYRIGHT SIGN */
case 0x2122: y = 0xAA; break;
/* TRADE MARK SIGN */
case 0x00B4: y = 0xAB; break;
/* ACUTE ACCENT */
case 0x00A8: y = 0xAC; break;
/* DIAERESIS */
case 0x2260: y = 0xAD; break;
/* NOT EQUAL TO */
case 0x00C6: y = 0xAE; break;
/* LATIN CAPITAL LETTER AE */
case 0x00D8: y = 0xAF; break;
/* LATIN CAPITAL LETTER O WITH STROKE */
case 0x221E: y = 0xB0; break;
/* INFINITY */
case 0x00B1: y = 0xB1; break;
/* PLUS-MINUS SIGN */
case 0x2264: y = 0xB2; break;
/* LESS-THAN OR EQUAL TO */
case 0x2265: y = 0xB3; break;
/* GREATER-THAN OR EQUAL TO */
case 0x00A5: y = 0xB4; break;
/* YEN SIGN */
case 0x00B5: y = 0xB5; break;
/* MICRO SIGN */
case 0x2202: y = 0xB6; break;
/* PARTIAL DIFFERENTIAL */
case 0x2211: y = 0xB7; break;
/* N-ARY SUMMATION */
case 0x220F: y = 0xB8; break;
/* N-ARY PRODUCT */
case 0x03C0: y = 0xB9; break;
/* GREEK SMALL LETTER PI */
case 0x222B: y = 0xBA; break;
/* INTEGRAL */
case 0x00AA: y = 0xBB; break;
/* FEMININE ORDINAL INDICATOR */
case 0x00BA: y = 0xBC; break;
/* MASCULINE ORDINAL INDICATOR */
case 0x03A9: y = 0xBD; break;
/* GREEK CAPITAL LETTER OMEGA */
case 0x00E6: y = 0xBE; break;
/* LATIN SMALL LETTER AE */
case 0x00F8: y = 0xBF; break;
/* LATIN SMALL LETTER O WITH STROKE */
case 0x00BF: y = 0xC0; break;
/* INVERTED QUESTION MARK */
case 0x00A1: y = 0xC1; break;
/* INVERTED EXCLAMATION MARK */
case 0x00AC: y = 0xC2; break;
/* NOT SIGN */
case 0x221A: y = 0xC3; break;
/* SQUARE ROOT */
case 0x0192: y = 0xC4; break;
/* LATIN SMALL LETTER F WITH HOOK */
case 0x2248: y = 0xC5; break;
/* ALMOST EQUAL TO */
case 0x2206: y = 0xC6; break;
/* INCREMENT */
case 0x00AB: y = 0xC7; break;
/* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
case 0x00BB: y = 0xC8; break;
/* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
case 0x2026: y = 0xC9; break;
/* HORIZONTAL ELLIPSIS */
case 0x00A0: y = 0xCA; break;
/* NO-BREAK SPACE */
case 0x00C0: y = 0xCB; break;
/* LATIN CAPITAL LETTER A WITH GRAVE */
case 0x00C3: y = 0xCC; break;
/* LATIN CAPITAL LETTER A WITH TILDE */
case 0x00D5: y = 0xCD; break;
/* LATIN CAPITAL LETTER O WITH TILDE */
case 0x0152: y = 0xCE; break;
/* LATIN CAPITAL LIGATURE OE */
case 0x0153: y = 0xCF; break;
/* LATIN SMALL LIGATURE OE */
case 0x2013: y = 0xD0; break;
/* EN DASH */
case 0x2014: y = 0xD1; break;
/* EM DASH */
case 0x201C: y = 0xD2; break;
/* LEFT DOUBLE QUOTATION MARK */
case 0x201D: y = 0xD3; break;
/* RIGHT DOUBLE QUOTATION MARK */
case 0x2018: y = 0xD4; break;
/* LEFT SINGLE QUOTATION MARK */
case 0x2019: y = 0xD5; break;
/* RIGHT SINGLE QUOTATION MARK */
case 0x00F7: y = 0xD6; break;
/* DIVISION SIGN */
case 0x25CA: y = 0xD7; break;
/* LOZENGE */
case 0x00FF: y = 0xD8; break;
/* LATIN SMALL LETTER Y WITH DIAERESIS */
case 0x0178: y = 0xD9; break;
/* LATIN CAPITAL LETTER Y WITH DIAERESIS */
case 0x2044: y = 0xDA; break;
/* FRACTION SLASH */
case 0x20AC: y = 0xDB; break;
/* EURO SIGN */
case 0x2039: y = 0xDC; break;
/* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
case 0x203A: y = 0xDD; break;
/* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
case 0xFB01: y = 0xDE; break;
/* LATIN SMALL LIGATURE FI */
case 0xFB02: y = 0xDF; break;
/* LATIN SMALL LIGATURE FL */
case 0x2021: y = 0xE0; break;
/* DOUBLE DAGGER */
case 0x00B7: y = 0xE1; break;
/* MIDDLE DOT */
case 0x201A: y = 0xE2; break;
/* SINGLE LOW-9 QUOTATION MARK */
case 0x201E: y = 0xE3; break;
/* DOUBLE LOW-9 QUOTATION MARK */
case 0x2030: y = 0xE4; break;
/* PER MILLE SIGN */
case 0x00C2: y = 0xE5; break;
/* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
case 0x00CA: y = 0xE6; break;
/* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
case 0x00C1: y = 0xE7; break;
/* LATIN CAPITAL LETTER A WITH ACUTE */
case 0x00CB: y = 0xE8; break;
/* LATIN CAPITAL LETTER E WITH DIAERESIS */
case 0x00C8: y = 0xE9; break;
/* LATIN CAPITAL LETTER E WITH GRAVE */
case 0x00CD: y = 0xEA; break;
/* LATIN CAPITAL LETTER I WITH ACUTE */
case 0x00CE: y = 0xEB; break;
/* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
case 0x00CF: y = 0xEC; break;
/* LATIN CAPITAL LETTER I WITH DIAERESIS */
case 0x00CC: y = 0xED; break;
/* LATIN CAPITAL LETTER I WITH GRAVE */
case 0x00D3: y = 0xEE; break;
/* LATIN CAPITAL LETTER O WITH ACUTE */
case 0x00D4: y = 0xEF; break;
/* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
case 0xF8FF: y = 0xF0; break;
/* Apple logo */
case 0x00D2: y = 0xF1; break;
/* LATIN CAPITAL LETTER O WITH GRAVE */
case 0x00DA: y = 0xF2; break;
/* LATIN CAPITAL LETTER U WITH ACUTE */
case 0x00DB: y = 0xF3; break;
/* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
case 0x00D9: y = 0xF4; break;
/* LATIN CAPITAL LETTER U WITH GRAVE */
case 0x0131: y = 0xF5; break;
/* LATIN SMALL LETTER DOTLESS I */
case 0x02C6: y = 0xF6; break;
/* MODIFIER LETTER CIRCUMFLEX ACCENT */
case 0x02DC: y = 0xF7; break;
/* SMALL TILDE */
case 0x00AF: y = 0xF8; break;
/* MACRON */
case 0x02D8: y = 0xF9; break;
/* BREVE */
case 0x02D9: y = 0xFA; break;
/* DOT ABOVE */
case 0x02DA: y = 0xFB; break;
/* RING ABOVE */
case 0x00B8: y = 0xFC; break;
/* CEDILLA */
case 0x02DD: y = 0xFD; break;
/* DOUBLE ACUTE ACCENT */
case 0x02DB: y = 0xFE; break;
/* OGONEK */
case 0x02C7: y = 0xFF; break;
/* CARON */
default: y = '?'; break;
/* unrecognized */
}
}
return y;
}
#endif
#if IncludeHostTextClipExchange
LOCALPROC UniCodeStr2MacRoman(char *s, char *r)
{
tMacErr err;
uint8_t t;
uint8_t t2;
uint8_t t3;
uint8_t t4;
uint32_t v;
char *p = s;
char *q = r;
label_retry:
if (0 == (t = *p++)) {
err = mnvm_noErr;
/* done */
} else
if (0 == (0x80 & t)) {
*q++ = t;
goto label_retry;
} else
if (0 == (0x40 & t)) {
/* continuation code, error */
err = mnvm_miscErr;
} else
if (0 == (t2 = *p++)) {
err = mnvm_miscErr;
} else
if (0x80 != (0xC0 & t2)) {
/* not a continuation code, error */
err = mnvm_miscErr;
} else
if (0 == (0x20 & t)) {
/* two bytes */
v = t & 0x1F;
v = (v << 6) | (t2 & 0x3F);
*q++ = UniCodePoint2MacRoman(v);
goto label_retry;
} else
if (0 == (t3 = *p++)) {
err = mnvm_miscErr;
} else
if (0x80 != (0xC0 & t3)) {
/* not a continuation code, error */
err = mnvm_miscErr;
} else
if (0 == (0x10 & t)) {
/* three bytes */
v = t & 0x0F;
v = (v << 6) | (t3 & 0x3F);
v = (v << 6) | (t2 & 0x3F);
*q++ = UniCodePoint2MacRoman(v);
goto label_retry;
} else
if (0 == (t4 = *p++)) {
err = mnvm_miscErr;
} else
if (0x80 != (0xC0 & t4)) {
/* not a continuation code, error */
err = mnvm_miscErr;
} else
if (0 == (0x08 & t)) {
/* four bytes */
v = t & 0x07;
v = (v << 6) | (t4 & 0x3F);
v = (v << 6) | (t3 & 0x3F);
v = (v << 6) | (t2 & 0x3F);
*q++ = UniCodePoint2MacRoman(v);
goto label_retry;
} else
{
err = mnvm_miscErr;
/* longer code not supported yet */
}
}
#endif
#if IncludeHostTextClipExchange
GLOBALOSGLUFUNC tMacErr HTCEimport(tPbuf *r)
{
tMacErr err;
uimr L;
char *s = NULL;
tPbuf t = NotAPbuf;
if (NULL == (s = SDL_GetClipboardText())) {
err = mnvm_miscErr;
} else
if (mnvm_noErr != (err =
UniCodeStrLength(s, &L)))
{
/* fail */
} else
if (mnvm_noErr != (err =
PbufNew(L, &t)))
{
/* fail */
} else
{
err = mnvm_noErr;
UniCodeStr2MacRoman(s, PbufDat[t]);
*r = t;
t = NotAPbuf;
}
if (NotAPbuf != t) {
PbufDispose(t);
}
if (NULL != s) {
SDL_free(s);
}
return err;
}
#endif
/* --- event handling for main window --- */
#define UseMotionEvents 1
#if UseMotionEvents
LOCALVAR bool CaughtMouse = false;
#endif
LOCALPROC HandleTheEvent(SDL_Event *event)
{
switch (event->type) {
case SDL_QUIT:
RequestMacOff = true;
break;
case SDL_WINDOWEVENT:
switch (event->window.event) {
case SDL_WINDOWEVENT_FOCUS_GAINED:
gTrueBackgroundFlag = 0;
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
gTrueBackgroundFlag = 1;
break;
case SDL_WINDOWEVENT_ENTER:
CaughtMouse = 1;
break;
case SDL_WINDOWEVENT_LEAVE:
CaughtMouse = 0;
break;
}
break;
case SDL_MOUSEMOTION:
#if EnableFSMouseMotion && ! HaveWorkingWarp
if (HaveMouseMotion) {
MousePositionNotifyRelative(
event->motion.xrel, event->motion.yrel);
} else
#endif
{
MousePositionNotify(
event->motion.x, event->motion.y);
}
break;
case SDL_MOUSEBUTTONDOWN:
/* any mouse button, we don't care which */
#if EnableFSMouseMotion && ! HaveWorkingWarp
if (HaveMouseMotion) {
/* ignore position */
} else
#endif
{
MousePositionNotify(
event->button.x, event->button.y);
}
MouseButtonSet(true);
break;
case SDL_MOUSEBUTTONUP:
#if EnableFSMouseMotion && ! HaveWorkingWarp
if (HaveMouseMotion) {
/* ignore position */
} else
#endif
{
MousePositionNotify(
event->button.x, event->button.y);
}
MouseButtonSet(false);
break;
case SDL_KEYDOWN:
DoKeyCode(&event->key.keysym, true);
break;
case SDL_KEYUP:
DoKeyCode(&event->key.keysym, false);
break;
case SDL_MOUSEWHEEL:
if (event->wheel.x < 0) {
Keyboard_UpdateKeyMap2(MKC_Left, true);
Keyboard_UpdateKeyMap2(MKC_Left, false);
} else if (event->wheel.x > 0) {
Keyboard_UpdateKeyMap2(MKC_Right, true);
Keyboard_UpdateKeyMap2(MKC_Right, false);
}
if (event->wheel.y < 0) {
Keyboard_UpdateKeyMap2(MKC_Down, true);
Keyboard_UpdateKeyMap2(MKC_Down, false);
} else if(event->wheel.y > 0) {
Keyboard_UpdateKeyMap2(MKC_Up, true);
Keyboard_UpdateKeyMap2(MKC_Up, false);
}
break;
case SDL_DROPFILE:
{
char *s = event->drop.file;
(void) Sony_Insert1a(s, false);
SDL_RaiseWindow(main_wind);
SDL_free(s);
}
break;
#if 0
case Expose: /* SDL doesn't have an expose event */
int x0 = event->expose.x;
int y0 = event->expose.y;
int x1 = x0 + event->expose.width;
int y1 = y0 + event->expose.height;
if (x0 < 0) {
x0 = 0;
}
if (x1 > vMacScreenWidth) {
x1 = vMacScreenWidth;
}
if (y0 < 0) {
y0 = 0;
}
if (y1 > vMacScreenHeight) {
y1 = vMacScreenHeight;
}
if ((x0 < x1) && (y0 < y1)) {
HaveChangedScreenBuff(y0, x0, y1, x1);
}
break;
#endif
}
}
/* --- main window creation and disposal --- */
LOCALVAR int argc;
LOCALVAR char **argv;
LOCALFUNC bool Screen_Init(void)
{
bool v = false;
InitKeyCodes();
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
{
fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
} else {
v = true;
}
return v;
}
#if MayFullScreen
LOCALVAR bool GrabMachine = false;
#endif
#if MayFullScreen
LOCALPROC GrabTheMachine(void)
{
#if GrabKeysFullScreen
SDL_SetWindowGrab(main_wind, SDL_TRUE);
#endif
#if EnableFSMouseMotion
#if HaveWorkingWarp
/*
if magnification changes, need to reset,
even if HaveMouseMotion already true
*/
if (MoveMouse(ViewHStart + (ViewHSize / 2),
ViewVStart + (ViewVSize / 2)))
{
SavedMouseH = ViewHStart + (ViewHSize / 2);
SavedMouseV = ViewVStart + (ViewVSize / 2);
HaveMouseMotion = true;
}
#else
if (0 == SDL_SetRelativeMouseMode(SDL_ENABLE)) {
HaveMouseMotion = true;
}
#endif
#endif /* EnableFSMouseMotion */
}
#endif
#if MayFullScreen
LOCALPROC UngrabMachine(void)
{
#if EnableFSMouseMotion
if (HaveMouseMotion) {
#if HaveWorkingWarp
(void) MoveMouse(CurMouseH, CurMouseV);
#else
SDL_SetRelativeMouseMode(SDL_DISABLE);
#endif
HaveMouseMotion = false;
}
#endif /* EnableFSMouseMotion */
#if GrabKeysFullScreen
SDL_SetWindowGrab(main_wind, SDL_FALSE);
#endif
}
#endif
#if EnableFSMouseMotion && HaveWorkingWarp
LOCALPROC MouseConstrain(void)
{
int16_t shiftdh;
int16_t shiftdv;
if (SavedMouseH < ViewHStart + (ViewHSize / 4)) {
shiftdh = ViewHSize / 2;
} else if (SavedMouseH > ViewHStart + ViewHSize - (ViewHSize / 4)) {
shiftdh = - ViewHSize / 2;
} else {
shiftdh = 0;
}
if (SavedMouseV < ViewVStart + (ViewVSize / 4)) {
shiftdv = ViewVSize / 2;
} else if (SavedMouseV > ViewVStart + ViewVSize - (ViewVSize / 4)) {
shiftdv = - ViewVSize / 2;
} else {
shiftdv = 0;
}
if ((shiftdh != 0) || (shiftdv != 0)) {
SavedMouseH += shiftdh;
SavedMouseV += shiftdv;
if (! MoveMouse(SavedMouseH, SavedMouseV)) {
HaveMouseMotion = false;
}
}
}
#endif
enum {
kMagStateNormal,
#if EnableMagnify
kMagStateMagnifgy,
#endif
kNumMagStates
};
#define kMagStateAuto kNumMagStates
#if MayNotFullScreen
LOCALVAR int CurWinIndx;
LOCALVAR bool HavePositionWins[kNumMagStates];
LOCALVAR int WinPositionsX[kNumMagStates];
LOCALVAR int WinPositionsY[kNumMagStates];
#endif
LOCALFUNC bool CreateMainWindow(void)
{
int NewWindowX;
int NewWindowY;
int NewWindowHeight = vMacScreenHeight;
int NewWindowWidth = vMacScreenWidth;
Uint32 flags = 0 /* SDL_WINDOW_HIDDEN */;
bool v = false;
#if EnableMagnify && 1
if (UseMagnify) {
NewWindowHeight *= WindowScale;
NewWindowWidth *= WindowScale;
}
#endif
#if VarFullScreen
if (UseFullScreen)
#endif
#if MayFullScreen
{
/*
We don't want physical screen mode to be changed in modern
displays, so we pass this _DESKTOP flag.
*/
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
NewWindowX = SDL_WINDOWPOS_UNDEFINED;
NewWindowY = SDL_WINDOWPOS_UNDEFINED;
}
#endif
#if VarFullScreen
else
#endif
#if MayNotFullScreen
{
int WinIndx;
#if EnableMagnify
if (UseMagnify) {
WinIndx = kMagStateMagnifgy;
} else
#endif
{
WinIndx = kMagStateNormal;
}
if (! HavePositionWins[WinIndx]) {
NewWindowX = SDL_WINDOWPOS_CENTERED;
NewWindowY = SDL_WINDOWPOS_CENTERED;
} else {
NewWindowX = WinPositionsX[WinIndx];
NewWindowY = WinPositionsY[WinIndx];
}
CurWinIndx = WinIndx;
}
#endif
#if 0
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
#endif
if (NULL == (main_wind = SDL_CreateWindow(
(NULL != n_arg) ? n_arg : kStrAppName,
NewWindowX, NewWindowY,
NewWindowWidth, NewWindowHeight,
flags)))
{
fprintf(stderr, "SDL_CreateWindow fails: %s\n",
SDL_GetError());
} else
if (NULL == (renderer = SDL_CreateRenderer(
main_wind, -1,
0 /* SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC */
/*
SDL_RENDERER_ACCELERATED not needed
"no flags gives priority to available
SDL_RENDERER_ACCELERATED renderers"
*/
/* would rather not require vsync */
)))
{
fprintf(stderr, "SDL_CreateRenderer fails: %s\n",
SDL_GetError());
} else
if (NULL == (texture = SDL_CreateTexture(
renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
#if UseSDLscaling
vMacScreenWidth, vMacScreenHeight
#else
NewWindowWidth, NewWindowHeight
#endif
)))
{
fprintf(stderr, "SDL_CreateTexture fails: %s\n",
SDL_GetError());
} else
if (NULL == (format = SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888)))
{
fprintf(stderr, "SDL_AllocFormat fails: %s\n",
SDL_GetError());
} else
{
/* SDL_ShowWindow(main_wind); */
SDL_RenderClear(renderer);
#if 0
SDL_DisplayMode info;
if (0 != SDL_GetCurrentDisplayMode(0, &info)) {
fprintf(stderr, "SDL_GetCurrentDisplayMode fails: %s\n",
SDL_GetError());
return false;
}
#endif
#if VarFullScreen
if (UseFullScreen)
#endif
#if MayFullScreen
{
int wr;
int hr;
SDL_GL_GetDrawableSize(main_wind, &wr, &hr);
ViewHSize = wr;
ViewVSize = hr;
#if EnableMagnify
if (UseMagnify) {
ViewHSize /= WindowScale;
ViewVSize /= WindowScale;
}
#endif
if (ViewHSize >= vMacScreenWidth) {
ViewHStart = 0;
ViewHSize = vMacScreenWidth;
} else {
ViewHSize &= ~ 1;
}
if (ViewVSize >= vMacScreenHeight) {
ViewVStart = 0;
ViewVSize = vMacScreenHeight;
} else {
ViewVSize &= ~ 1;
}
if (wr > NewWindowWidth) {
hOffset = (wr - NewWindowWidth) / 2;
} else {
hOffset = 0;
}
if (hr > NewWindowHeight) {
vOffset = (hr - NewWindowHeight) / 2;
} else {
vOffset = 0;
}
}
#endif
#if 0 != vMacScreenDepth
ColorModeWorks = true;
#endif
v = true;
}
return v;
}
LOCALPROC CloseMainWindow(void)
{
if (NULL != format) {
SDL_FreeFormat(format);
format = NULL;
}
if (NULL != texture) {
SDL_DestroyTexture(texture);
texture = NULL;
}
if (NULL != renderer) {
SDL_DestroyRenderer(renderer);
renderer = NULL;
}
if (NULL != main_wind) {
SDL_DestroyWindow(main_wind);
main_wind = NULL;
}
}
#if EnableRecreateW
LOCALPROC ZapWState(void)
{
main_wind = NULL;
renderer = NULL;
texture = NULL;
format = NULL;
}
#endif
#if EnableRecreateW
struct WState {
#if MayFullScreen
uint16_t f_ViewHSize;
uint16_t f_ViewVSize;
uint16_t f_ViewHStart;
uint16_t f_ViewVStart;
int f_hOffset;
int f_vOffset;
#endif
#if VarFullScreen
bool f_UseFullScreen;
#endif
#if EnableMagnify
bool f_UseMagnify;
#endif
#if MayNotFullScreen
int f_CurWinIndx;
#endif
SDL_Window *f_main_wind;
SDL_Renderer *f_renderer;
SDL_Texture *f_texture;
SDL_PixelFormat *f_format;
};
typedef struct WState WState;
#endif
#if EnableRecreateW
LOCALPROC GetWState(WState *r)
{
#if MayFullScreen
r->f_ViewHSize = ViewHSize;
r->f_ViewVSize = ViewVSize;
r->f_ViewHStart = ViewHStart;
r->f_ViewVStart = ViewVStart;
r->f_hOffset = hOffset;
r->f_vOffset = vOffset;
#endif
#if VarFullScreen
r->f_UseFullScreen = UseFullScreen;
#endif
#if EnableMagnify
r->f_UseMagnify = UseMagnify;
#endif
#if MayNotFullScreen
r->f_CurWinIndx = CurWinIndx;
#endif
r->f_main_wind = main_wind;
r->f_renderer = renderer;
r->f_texture = texture;
r->f_format = format;
}
#endif
#if EnableRecreateW
LOCALPROC SetWState(WState *r)
{
#if MayFullScreen
ViewHSize = r->f_ViewHSize;
ViewVSize = r->f_ViewVSize;
ViewHStart = r->f_ViewHStart;
ViewVStart = r->f_ViewVStart;
hOffset = r->f_hOffset;
vOffset = r->f_vOffset;
#endif
#if VarFullScreen
UseFullScreen = r->f_UseFullScreen;
#endif
#if EnableMagnify
UseMagnify = r->f_UseMagnify;
#endif
#if MayNotFullScreen
CurWinIndx = r->f_CurWinIndx;
#endif
main_wind = r->f_main_wind;
renderer = r->f_renderer;
texture = r->f_texture;
format = r->f_format;
}
#endif
#if VarFullScreen && EnableMagnify
enum {
kWinStateWindowed,
#if EnableMagnify
kWinStateFullScreen,
#endif
kNumWinStates
};
#endif
#if VarFullScreen && EnableMagnify
LOCALVAR int WinMagStates[kNumWinStates];
#endif
#if EnableRecreateW
LOCALFUNC bool ReCreateMainWindow(void)
{
WState old_state;
WState new_state;
#if HaveWorkingWarp
bool HadCursorHidden = HaveCursorHidden;
#endif
#if VarFullScreen && EnableMagnify
int OldWinState =
UseFullScreen ? kWinStateFullScreen : kWinStateWindowed;
int OldMagState =
UseMagnify ? kMagStateMagnifgy : kMagStateNormal;
WinMagStates[OldWinState] =
OldMagState;
#endif
#if VarFullScreen
if (! UseFullScreen)
#endif
#if MayNotFullScreen
{
SDL_GetWindowPosition(main_wind,
&WinPositionsX[CurWinIndx],
&WinPositionsY[CurWinIndx]);
HavePositionWins[CurWinIndx] = true;
}
#endif
ForceShowCursor(); /* hide/show cursor api is per window */
#if MayFullScreen
if (GrabMachine) {
GrabMachine = false;
UngrabMachine();
}
#endif
GetWState(&old_state);
ZapWState();
#if EnableMagnify
UseMagnify = WantMagnify;
#endif
#if VarFullScreen
UseFullScreen = WantFullScreen;
#endif
if (! CreateMainWindow()) {
CloseMainWindow();
SetWState(&old_state);
/* avoid retry */
#if VarFullScreen
WantFullScreen = UseFullScreen;
#endif
#if EnableMagnify
WantMagnify = UseMagnify;
#endif
} else {
GetWState(&new_state);
SetWState(&old_state);
CloseMainWindow();
SetWState(&new_state);
#if HaveWorkingWarp
if (HadCursorHidden) {
(void) MoveMouse(CurMouseH, CurMouseV);
}
#endif
}
return true;
}
#endif
LOCALPROC ZapWinStateVars(void)
{
#if MayNotFullScreen
{
int i;
for (i = 0; i < kNumMagStates; ++i) {
HavePositionWins[i] = false;
}
}
#endif
#if VarFullScreen && EnableMagnify
{
int i;
for (i = 0; i < kNumWinStates; ++i) {
WinMagStates[i] = kMagStateAuto;
}
}
#endif
}
#if VarFullScreen
LOCALPROC ToggleWantFullScreen(void)
{
WantFullScreen = ! WantFullScreen;
#if EnableMagnify
{
int OldWinState =
UseFullScreen ? kWinStateFullScreen : kWinStateWindowed;
int OldMagState =
UseMagnify ? kMagStateMagnifgy : kMagStateNormal;
int NewWinState =
WantFullScreen ? kWinStateFullScreen : kWinStateWindowed;
int NewMagState = WinMagStates[NewWinState];
WinMagStates[OldWinState] = OldMagState;
if (kMagStateAuto != NewMagState) {
WantMagnify = (kMagStateMagnifgy == NewMagState);
} else {
WantMagnify = false;
if (WantFullScreen) {
SDL_Rect r;
if (0 == SDL_GetDisplayBounds(0, &r)) {
if ((r.w >= vMacScreenWidth * WindowScale)
&& (r.h >= vMacScreenHeight * WindowScale)
)
{
WantMagnify = true;
}
}
}
}
}
#endif
}
#endif
/* --- SavedTasks --- */
LOCALPROC LeaveBackground(void)
{
ReconnectKeyCodes3();
DisableKeyRepeat();
}
LOCALPROC EnterBackground(void)
{
RestoreKeyRepeat();
DisconnectKeyCodes3();
ForceShowCursor();
}
LOCALPROC LeaveSpeedStopped(void)
{
#if SoundEnabled
Sound_Start();
#endif
StartUpTimeAdjust();
}
LOCALPROC EnterSpeedStopped(void)
{
#if SoundEnabled
Sound_Stop();
#endif
}
LOCALPROC CheckForSavedTasks(void)
{
if (EvtQNeedRecover) {
EvtQNeedRecover = false;
/* attempt cleanup, EvtQNeedRecover may get set again */
EvtQTryRecoverFromFull();
}
#if EnableFSMouseMotion && HaveWorkingWarp
if (HaveMouseMotion) {
MouseConstrain();
}
#endif
if (RequestMacOff) {
RequestMacOff = false;
if (AnyDiskInserted()) {
MacMsgOverride(kStrQuitWarningTitle,
kStrQuitWarningMessage);
} else {
ForceMacOff = true;
}
}
if (ForceMacOff) {
return;
}
if (gTrueBackgroundFlag != gBackgroundFlag) {
gBackgroundFlag = gTrueBackgroundFlag;
if (gTrueBackgroundFlag) {
EnterBackground();
} else {
LeaveBackground();
}
}
if (CurSpeedStopped != (SpeedStopped ||
(gBackgroundFlag && ! RunInBackground)))
{
CurSpeedStopped = ! CurSpeedStopped;
if (CurSpeedStopped) {
EnterSpeedStopped();
} else {
LeaveSpeedStopped();
}
}
if ((nullpr != SavedBriefMsg) & ! MacMsgDisplayed) {
MacMsgDisplayOn();
}
#if EnableRecreateW
if (0
#if EnableMagnify
|| (UseMagnify != WantMagnify)
#endif
#if VarFullScreen
|| (UseFullScreen != WantFullScreen)
#endif
)
{
(void) ReCreateMainWindow();
}
#endif
#if MayFullScreen
if (GrabMachine != (
#if VarFullScreen
UseFullScreen &&
#endif
! (gTrueBackgroundFlag || CurSpeedStopped)))
{
GrabMachine = ! GrabMachine;
if (GrabMachine) {
GrabTheMachine();
} else {
UngrabMachine();
}
}
#endif
if (NeedWholeScreenDraw) {
NeedWholeScreenDraw = false;
ScreenChangedAll();
}
#if NeedRequestIthDisk
if (0 != RequestIthDisk) {
Sony_InsertIth(RequestIthDisk);
RequestIthDisk = 0;
}
#endif
if (HaveCursorHidden != (WantCursorHidden
&& ! (gTrueBackgroundFlag || CurSpeedStopped)))
{
HaveCursorHidden = ! HaveCursorHidden;
(void) SDL_ShowCursor(
HaveCursorHidden ? SDL_DISABLE : SDL_ENABLE);
}
}
/* --- command line parsing --- */
LOCALFUNC bool ScanCommandLine(void)
{
char *pa;
int i = 1;
label_retry:
if (i < argc) {
pa = argv[i++];
if ('-' == pa[0]) {
if ((0 == strcmp(pa, "--rom"))
|| (0 == strcmp(pa, "-r")))
{
if (i < argc) {
rom_path = argv[i++];
goto label_retry;
}
} else
if (0 == strcmp(pa, "-n"))
{
if (i < argc) {
n_arg = argv[i++];
goto label_retry;
}
} else
if (0 == strcmp(pa, "-d"))
{
if (i < argc) {
d_arg = argv[i++];
goto label_retry;
}
} else
if (('p' == pa[1]) && ('s' == pa[2]) && ('n' == pa[3]))
{
/* seen in OS X. ignore */
goto label_retry;
} else
{
MacMsg(kStrBadArgTitle, kStrBadArgMessage, false);
#if dbglog_HAVE
dbglog_writeln("bad command line argument");
dbglog_writeln(pa);
#endif
}
} else {
(void) Sony_Insert1(pa, false);
goto label_retry;
}
}
return true;
}
/* --- main program flow --- */
GLOBALOSGLUFUNC bool ExtraTimeNotOver(void)
{
UpdateTrueEmulatedTime();
return TrueEmulatedTime == OnTrueTime;
}
LOCALPROC WaitForTheNextEvent(void)
{
SDL_Event event;
if (SDL_WaitEvent(&event)) {
HandleTheEvent(&event);
}
}
LOCALPROC CheckForSystemEvents(void)
{
SDL_Event event;
int i = 10;
while ((--i >= 0) && SDL_PollEvent(&event)) {
HandleTheEvent(&event);
}
}
GLOBALOSGLUPROC WaitForNextTick(void)
{
label_retry:
CheckForSystemEvents();
CheckForSavedTasks();
if (ForceMacOff) {
return;
}
if (CurSpeedStopped) {
DoneWithDrawingForTick();
WaitForTheNextEvent();
goto label_retry;
}
if (ExtraTimeNotOver()) {
(void) SDL_Delay(NextIntTime - LastTime);
goto label_retry;
}
if (CheckDateTime()) {
#if SoundEnabled
Sound_SecondNotify();
#endif
}
if ((! gBackgroundFlag)
#if UseMotionEvents
&& (! CaughtMouse)
#endif
)
{
CheckMouseState();
}
OnTrueTime = TrueEmulatedTime;
#if dbglog_TimeStuff
dbglog_writelnNum("WaitForNextTick, OnTrueTime", OnTrueTime);
#endif
}
/* --- platform independent code can be thought of as going here --- */
#include "PROGMAIN.h"
LOCALPROC ZapOSGLUVars(void)
{
InitDrives();
ZapWinStateVars();
}
LOCALPROC ReserveAllocAll(void)
{
#if dbglog_HAVE
dbglog_ReserveAlloc();
#endif
ReserveAllocOneBlock(&ROM, kROM_Size, 5, false);
ReserveAllocOneBlock(&screencomparebuff,
vMacScreenNumBytes, 5, true);
#if UseControlKeys
ReserveAllocOneBlock(&CntrlDisplayBuff,
vMacScreenNumBytes, 5, false);
#endif
ReserveAllocOneBlock(&CLUT_final, CLUT_finalsz, 5, false);
#if SoundEnabled
ReserveAllocOneBlock((uint8_t * *)&TheSoundBuffer,
dbhBufferSize, 5, false);
#endif
EmulationReserveAlloc();
}
LOCALFUNC bool AllocMemory(void)
{
uimr n;
bool IsOk = false;
ReserveAllocOffset = 0;
ReserveAllocBigBlock = nullpr;
ReserveAllocAll();
n = ReserveAllocOffset;
ReserveAllocBigBlock = (uint8_t *)calloc(1, n);
if (NULL == ReserveAllocBigBlock) {
MacMsg(kStrOutOfMemTitle, kStrOutOfMemMessage, true);
} else {
ReserveAllocOffset = 0;
ReserveAllocAll();
if (n != ReserveAllocOffset) {
/* oops, program error */
} else {
IsOk = true;
}
}
return IsOk;
}
LOCALPROC UnallocMemory(void)
{
if (nullpr != ReserveAllocBigBlock) {
free((char *)ReserveAllocBigBlock);
}
}
#if CanGetAppPath
LOCALFUNC bool InitWhereAmI(void)
{
app_parent = SDL_GetBasePath();
pref_dir = SDL_GetPrefPath("gryphel", "minivmac");
return true; /* keep going regardless */
}
#endif
#if CanGetAppPath
LOCALPROC UninitWhereAmI(void)
{
SDL_free(pref_dir);
SDL_free(app_parent);
}
#endif
LOCALFUNC bool InitOSGLU(void)
{
if (AllocMemory())
#if CanGetAppPath
if (InitWhereAmI())
#endif
#if dbglog_HAVE
if (dbglog_open())
#endif
if (ScanCommandLine())
if (LoadMacRom())
if (LoadInitialImages())
if (InitLocationDat())
#if SoundEnabled
if (Sound_Init())
#endif
if (Screen_Init())
if (CreateMainWindow())
if (WaitForRom())
{
return true;
}
return false;
}
LOCALPROC UnInitOSGLU(void)
{
if (MacMsgDisplayed) {
MacMsgDisplayOff();
}
RestoreKeyRepeat();
#if MayFullScreen
UngrabMachine();
#endif
#if SoundEnabled
Sound_Stop();
#endif
#if SoundEnabled
Sound_UnInit();
#endif
#if IncludePbufs
UnInitPbufs();
#endif
UnInitDrives();
ForceShowCursor();
#if dbglog_HAVE
dbglog_close();
#endif
#if CanGetAppPath
UninitWhereAmI();
#endif
UnallocMemory();
CheckSavedMacMsg();
CloseMainWindow();
SDL_Quit();
}
int main(int argc, char **argv)
{
argc = argc;
argv = argv;
ZapOSGLUVars();
if (InitOSGLU()) {
ProgramMain();
}
UnInitOSGLU();
return 0;
}