ref: ea61a2a8e8601d5b732d2c13257413ad4f864b85
dir: /src/OSPLAN9.c/
#include <u.h> #include <libc.h> #include <stdio.h> #include <draw.h> #include <mouse.h> #include <cursor.h> #include <keyboard.h> #include <thread.h> #include <plumb.h> #define Uint8 u8int #define Uint16 u16int #define Uint32 u32int #include "CNFGRAPI.h" #include "SYSDEPNS.h" #include "ENDIANAC.h" #include "MYOSGLUE.h" #include "STRCONST.h" GLOBALOSGLUPROC MyMoveBytes(anyp srcPtr, anyp destPtr, si5b byteCount) { memmove(destPtr, srcPtr, byteCount); } #define NeedCell2PlainAsciiMap 1 #include "INTLCHAR.h" #if dbglog_HAVE #define dbglog_ToStdErr 0 #if ! dbglog_ToStdErr LOCALVAR FILE *dbglog_File = NULL; #endif LOCALFUNC blnr dbglog_open0(void) { #if dbglog_ToStdErr return trueblnr; #else dbglog_File = fopen("dbglog.txt", "w"); return (NULL != dbglog_File); #endif } LOCALPROC dbglog_write0(char *s, uimr L) { #if dbglog_ToStdErr (void) fwrite(s, 1, L, stderr); #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 "COMOSGLU.h" #include "PBUFSTDC.h" #include "CONTROLM.h" /* --- text translation --- */ LOCALPROC NativeStrFromCStr(char *r, char *s) { ui3b 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 LOCALVAR FILE *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(blnr IsWrite, ui3p Buffer, tDrive Drive_No, ui5r Sony_Start, ui5r Sony_Count, ui5r *Sony_ActCount) { tMacErr err = mnvm_miscErr; FILE *refnum = Drives[Drive_No]; ui5r NewSony_Count = 0; if (0 == fseek(refnum, Sony_Start, SEEK_SET)) { if (IsWrite) { NewSony_Count = fwrite(Buffer, 1, Sony_Count, refnum); } else { NewSony_Count = fread(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, ui5r *Sony_Count) { tMacErr err = mnvm_miscErr; FILE *refnum = Drives[Drive_No]; long v; if (0 == fseek(refnum, 0, SEEK_END)) { v = ftell(refnum); if (v >= 0) { *Sony_Count = v; err = mnvm_noErr; } } return err; /*& figure out what really to return &*/ } LOCALFUNC tMacErr vSonyEject0(tDrive Drive_No, blnr deleteit) { FILE *refnum = Drives[Drive_No]; DiskEjectedNotify(Drive_No); fclose(refnum); Drives[Drive_No] = NotAfileRef; /* not really needed */ return mnvm_noErr; } GLOBALOSGLUFUNC tMacErr vSonyEject(tDrive Drive_No) { return vSonyEject0(Drive_No, falseblnr); } #if IncludeSonyNew GLOBALOSGLUFUNC tMacErr vSonyEjectDelete(tDrive Drive_No) { return vSonyEject0(Drive_No, trueblnr); } #endif #if IncludeSonyGetName GLOBALOSGLUFUNC tMacErr vSonyGetName(tDrive Drive_No, tPbuf *r) { r[0] = 0; return mnvm_noErr; } #endif LOCALPROC UnInitDrives(void) { tDrive i; for (i = 0; i < NumDrives; ++i) { if (vSonyIsInserted(i)) { (void) vSonyEject(i); } } } LOCALFUNC blnr Sony_Insert0(FILE *refnum, blnr locked, char *drivepath) { tDrive Drive_No; blnr IsOk = falseblnr; if (! FirstFreeDisk(&Drive_No)) { MacMsg(kStrTooManyImagesTitle, kStrTooManyImagesMessage, falseblnr); } else { /* printf("Sony_Insert0 %d\n", (int)Drive_No); */ { Drives[Drive_No] = refnum; DiskInsertNotify(Drive_No, locked); IsOk = trueblnr; } } if (! IsOk) { fclose(refnum); } return IsOk; } LOCALFUNC blnr Sony_Insert1(char *drivepath, blnr silentfail) { blnr locked = falseblnr; /* printf("Sony_Insert1 %s\n", drivepath); */ FILE *refnum = fopen(drivepath, "rb+"); if (NULL == refnum) { locked = trueblnr; refnum = fopen(drivepath, "rb"); } if (NULL == refnum) { if (! silentfail) { MacMsg(kStrOpenFailTitle, kStrOpenFailMessage, falseblnr); } } else { return Sony_Insert0(refnum, locked, drivepath); } return falseblnr; } LOCALFUNC tMacErr LoadMacRomFrom(char *path) { tMacErr err; FILE *ROM_File; int File_Size; ROM_File = fopen(path, "rb"); if (NULL == ROM_File) { err = mnvm_fnfErr; } else { File_Size = fread(ROM, 1, kROM_Size, ROM_File); if (File_Size != kROM_Size) { if (feof(ROM_File)) { MacMsgOverride(kStrShortROMTitle, kStrShortROMMessage); err = mnvm_eofErr; } else { MacMsgOverride(kStrNoReadROMTitle, kStrNoReadROMMessage); err = mnvm_miscErr; } } else { err = ROM_IsValid(); } fclose(ROM_File); } return err; } LOCALFUNC blnr Sony_Insert1a(char *drivepath, blnr silentfail) { blnr v; if (! ROM_loaded) { v = (mnvm_noErr == LoadMacRomFrom(drivepath)); } else { v = Sony_Insert1(drivepath, silentfail); } return v; } static void plumbproc(void *) { int f; Plumbmsg *m; char tmp[1024]; threadsetname("plumb"); if ((f = plumbopen("minivmac", OREAD)) >= 0) { while ((m = plumbrecv(f)) != nil) { snprint(tmp, sizeof(tmp), "%s/%s", m->wdir, m->data); Sony_Insert1a(tmp, 0); plumbfree(m); } } threadexits(nil); } LOCALFUNC blnr Sony_Insert2(char *s) { return Sony_Insert1(s, trueblnr); } LOCALFUNC blnr Sony_InsertIth(int i) { blnr v; if ((i > 9) || ! FirstFreeDisk(nullpr)) { v = falseblnr; } else { char s[] = "disk?.dsk"; s[4] = '0' + i; v = Sony_Insert2(s); } return v; } LOCALFUNC blnr LoadInitialImages(void) { if (! AnyDiskInserted()) { int i; for (i = 1; Sony_InsertIth(i); ++i) { /* stop on first error (including file not found) */ } } proccreate(plumbproc, nil, mainstacksize); return trueblnr; } /* --- ROM --- */ LOCALVAR char *rom_path = NULL; LOCALFUNC blnr LoadMacRom(void) { tMacErr err; if ((NULL == rom_path) || (mnvm_fnfErr == (err = LoadMacRomFrom(rom_path)))) if (mnvm_fnfErr == (err = LoadMacRomFrom(RomFileName))) { } return trueblnr; /* keep launching Mini vMac, regardless */ } /* --- video out --- */ #if VarFullScreen LOCALVAR blnr UseFullScreen = (WantInitFullScreen != 0); #endif #if EnableMagnify LOCALVAR blnr UseMagnify = (WantInitMagnify != 0); #endif LOCALVAR blnr gBackgroundFlag = falseblnr; LOCALVAR blnr gTrueBackgroundFlag = falseblnr; LOCALVAR blnr CurSpeedStopped = falseblnr; #if EnableMagnify #define MaxScale MyWindowScale #else #define MaxScale 1 #endif LOCALVAR Image *my_surface = nullpr; LOCALVAR u8int *pixels; LOCALVAR ui3p ScalingBuff = nullpr; LOCALVAR ui3p 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 MyWindowScale 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 "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 "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 "SCRNMAPR.h" #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 MyWindowScale #include "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 MyWindowScale #include "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 MyWindowScale #include "SCRNMAPR.h" #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 "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 "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 "SCRNMAPR.h" #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 MyWindowScale #include "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 MyWindowScale #include "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 MyWindowScale #include "SCRNMAPR.h" #endif LOCALPROC HaveChangedScreenBuff(ui4r top, ui4r left, ui4r bottom, ui4r right) { int i; int j; ui3b *p; Uint32 pixel; #if (0 != vMacScreenDepth) && (vMacScreenDepth < 4) Uint32 CLUT_pixel[CLUT_size]; #endif Uint32 BWLUT_pixel[2]; ui5r top2 = top; ui5r left2 = left; ui5r bottom2 = bottom; ui5r right2 = right; #if EnableMagnify if (UseMagnify) { top2 *= MyWindowScale; left2 *= MyWindowScale; bottom2 *= MyWindowScale; right2 *= MyWindowScale; } #endif /* FIXME image locking here? */ { int bpp = 4; /* FIXME RGB32 for now, make it dynamic though */ ui5r ExpectedPitch = vMacScreenWidth * bpp; #if EnableMagnify if (UseMagnify) { ExpectedPitch *= MyWindowScale; } #endif #if 0 != vMacScreenDepth if (UseColorMode) { #if vMacScreenDepth < 4 for (i = 0; i < CLUT_size; ++i) { CLUT_pixel[i] = (CLUT_blues[i]>>8)<<24 | (CLUT_greens[i]>>8)<<16 | (CLUT_reds[i]>>8)<<8 | 0xff; } #endif } else #endif { BWLUT_pixel[1] = 0x000000ff; /* black */ BWLUT_pixel[0] = 0xffffffff; /* white */ } if ((0 == ((bpp - 1) & bpp)) /* a power of 2 */ #if (vMacScreenDepth > 3) && ! UseColorMode #endif ) { int k; Uint32 v; #if EnableMagnify 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 for (a = UseMagnify ? MyWindowScale : 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 = (ui3p)pixels; #if (0 != vMacScreenDepth) && (vMacScreenDepth < 4) if (UseColorMode) { #if EnableMagnify 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 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 { ui3b *the_data = (ui3b *)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 * Dx(my_surface->r)*bpp + j * bpp; #if EnableMagnify if (UseMagnify) { i0 /= MyWindowScale; j0 /= MyWindowScale; } #endif #if 0 != vMacScreenDepth if (UseColorMode) { #if vMacScreenDepth < 4 p = the_data + ((i0 * vMacScreenWidth + j0) >> (3 - vMacScreenDepth)); { ui3r 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); { ui4r t0 = do_get_mem_word(p); pixel = (((t0 & 0x7C00) >> 7) | ((t0 & 0x7000) >> 12))<<24 | (((t0 & 0x03E0) >> 2) | ((t0 & 0x0380) >> 7))<<16 | (((t0 & 0x001F) << 3) | ((t0 & 0x001C) >> 2))<<8 | 0xff; } #elif 5 == vMacScreenDepth p = the_data + ((i0 * vMacScreenWidth + j0) << 2); pixel = p[1]<<24 | p[2]<<16 | p[3]<<8 | 0xff; #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: bufp[0] = (pixel >> 16) & 0xff; bufp[1] = (pixel >> 8) & 0xff; bufp[2] = pixel & 0xff; break; case 4: /* Probably 32-bpp */ *(Uint32 *)bufp = pixel; break; } } } } } /* FIXME image unlocking? */ lockdisplay(display); if(loadimage(my_surface, my_surface->r, pixels, 4*Dx(my_surface->r)*Dy(my_surface->r)) < 0) sysfatal("%r"); Rectangle r = screen->r; r.min.x += (Dx(r) - Dx(my_surface->r))/2; r.min.y += (Dy(r) - Dy(my_surface->r))/2; draw(screen, r, my_surface, nil, ZP); flushimage(display, 1); unlockdisplay(display); } LOCALPROC MyDrawChangesAndClear(void) { if (ScreenChangedBottom > ScreenChangedTop) { HaveChangedScreenBuff(ScreenChangedTop, ScreenChangedLeft, ScreenChangedBottom, ScreenChangedRight); ScreenClearChanges(); } } GLOBALOSGLUPROC DoneWithDrawingForTick(void) { #if EnableFSMouseMotion if (HaveMouseMotion) { AutoScrollScreen(); } #endif MyDrawChangesAndClear(); } /* --- mouse --- */ /* cursor hiding */ LOCALVAR blnr HaveCursorHidden = falseblnr; LOCALVAR blnr WantCursorHidden = falseblnr; LOCALPROC ForceShowCursor(void) { if (HaveCursorHidden) { HaveCursorHidden = falseblnr; // FIXME pointer toggle //(void) SDL_ShowCursor(SDL_ENABLE); } } /* cursor moving */ LOCALFUNC blnr MyMoveMouse(si4b h, si4b v) { #if EnableMagnify if (UseMagnify) { h *= MyWindowScale; v *= MyWindowScale; } #endif // FIXME pointer warp //SDL_WarpMouse(h, v); return trueblnr; } /* cursor state */ LOCALPROC MousePositionNotify(int NewMousePosh, int NewMousePosv) { blnr ShouldHaveCursorHidden = trueblnr; #if EnableMagnify if (UseMagnify) { NewMousePosh /= MyWindowScale; NewMousePosv /= MyWindowScale; } #endif #if EnableFSMouseMotion if (HaveMouseMotion) { MyMousePositionSetDelta(NewMousePosh - SavedMouseH, NewMousePosv - SavedMouseV); SavedMouseH = NewMousePosh; SavedMouseV = NewMousePosv; } else #endif { if (NewMousePosh < 0) { NewMousePosh = 0; ShouldHaveCursorHidden = falseblnr; } else if (NewMousePosh >= vMacScreenWidth) { NewMousePosh = vMacScreenWidth - 1; ShouldHaveCursorHidden = falseblnr; } if (NewMousePosv < 0) { NewMousePosv = 0; ShouldHaveCursorHidden = falseblnr; } else if (NewMousePosv >= vMacScreenHeight) { NewMousePosv = vMacScreenHeight - 1; ShouldHaveCursorHidden = falseblnr; } #if VarFullScreen if (UseFullScreen) #endif #if MayFullScreen { ShouldHaveCursorHidden = trueblnr; } #endif /* if (ShouldHaveCursorHidden || CurMouseButton) */ /* for a game like arkanoid, would like mouse to still move even when outside window in one direction */ MyMousePositionSet(NewMousePosh, NewMousePosv); } WantCursorHidden = ShouldHaveCursorHidden; } /* --- keyboard input --- */ LOCALFUNC ui3r Rune2MacKeyCode(Rune i) { ui3r v = MKC_None; switch (i) { case Kbs: v = MKC_BackSpace; break; case '\t': v = MKC_Tab; break; //FIXME case clear: v = MKC_Clear; break; case '\n': v = MKC_Return; break; //FIXME case pause: v = MKC_Pause; break; case Kesc: v = MKC_formac_Escape; break; case ' ': v = MKC_Space; break; case '\'': v = MKC_SingleQuote; break; case ',': v = MKC_Comma; break; case '-': v = MKC_Minus; break; case '.': v = MKC_Period; break; case '/': v = MKC_formac_Slash; break; case '0': v = MKC_0; break; case '1': v = MKC_1; break; case '2': v = MKC_2; break; case '3': v = MKC_3; break; case '4': v = MKC_4; break; case '5': v = MKC_5; break; case '6': v = MKC_6; break; case '7': v = MKC_7; break; case '8': v = MKC_8; break; case '9': v = MKC_9; break; case ';': v = MKC_SemiColon; break; case '=': v = MKC_Equal; break; case '[': v = MKC_LeftBracket; break; case '\\': v = MKC_formac_BackSlash; break; case ']': v = MKC_RightBracket; break; case '`': v = MKC_formac_Grave; break; case 'a': v = MKC_A; break; case 'b': v = MKC_B; break; case 'c': v = MKC_C; break; case 'd': v = MKC_D; break; case 'e': v = MKC_E; break; case 'f': v = MKC_F; break; case 'g': v = MKC_G; break; case 'h': v = MKC_H; break; case 'i': v = MKC_I; break; case 'j': v = MKC_J; break; case 'k': v = MKC_K; break; case 'l': v = MKC_L; break; case 'm': v = MKC_M; break; case 'n': v = MKC_N; break; case 'o': v = MKC_O; break; case 'p': v = MKC_P; break; case 'q': v = MKC_Q; break; case 'r': v = MKC_R; break; case 's': v = MKC_S; break; case 't': v = MKC_T; break; case 'u': v = MKC_U; break; case 'v': v = MKC_V; break; case 'w': v = MKC_W; break; case 'x': v = MKC_X; break; case 'y': v = MKC_Y; break; case 'z': v = MKC_Z; break; case Kup: v = MKC_Up; break; case Kdown: v = MKC_Down; break; case Kright: v = MKC_Right; break; case Kleft: v = MKC_Left; break; case Kins: v = MKC_formac_Help; break; case Khome: v = MKC_formac_Home; break; case Kend: v = MKC_formac_End; break; case Kpgup: v = MKC_formac_PageUp; break; case Kpgdown: v = MKC_formac_PageDown; break; //case KF|1: v = MKC_formac_F1; break; //case KF|2: v = MKC_formac_F2; break; //case KF|3: v = MKC_formac_F3; break; case KF|4: v = MKC_formac_F4; break; case KF|5: v = MKC_formac_F5; break; case KF|6: v = MKC_F6; break; case KF|7: v = MKC_F7; break; case KF|8: v = MKC_F8; break; case KF|9: v = MKC_F9; break; case KF|10: v = MKC_F10; break; case KF|11: v = MKC_F11; break; case KF|12: v = MKC_F12; break; case Kshift: v = MKC_formac_Shift; break; case Kctl: v = MKC_formac_Control; break; case Kalt: case KF|1: v = MKC_formac_Command; break; case KF|2: v = MKC_formac_Command; break; case KF|3: v = MKC_formac_Option; break; //FIXME case SDLK_HELP: v = MKC_formac_Help; break; //FIXME case SDLK_PRINT: v = MKC_Print; break; default: break; } return v; } LOCALPROC DoKeyCode(Rune r, blnr down) { ui3r v = Rune2MacKeyCode(r); if (MKC_None != v) { Keyboard_UpdateKeyMap2(v, down); } } LOCALPROC DisableKeyRepeat(void) { } LOCALPROC RestoreKeyRepeat(void) { } LOCALPROC ReconnectKeyCodes3(void) { } LOCALPROC DisconnectKeyCodes3(void) { DisconnectKeyCodes2(); MyMouseButtonSet(falseblnr); } /* --- time, date, location --- */ #define dbglog_TimeStuff (0 && dbglog_HAVE) LOCALVAR ui5b TrueEmulatedTime = 0; #define MyInvTimeDivPow 16 #define MyInvTimeDiv (1 << MyInvTimeDivPow) #define MyInvTimeDivMask (MyInvTimeDiv - 1) #define MyInvTimeStep 1089590 /* 1000 / 60.14742 * MyInvTimeDiv */ LOCALVAR Uint32 LastTime; LOCALVAR Uint32 NextIntTime; LOCALVAR ui5b NextFracTime; LOCALPROC IncrNextTime(void) { NextFracTime += MyInvTimeStep; NextIntTime += (NextFracTime >> MyInvTimeDivPow); NextFracTime &= MyInvTimeDivMask; } LOCALPROC InitNextTime(void) { NextIntTime = LastTime; NextFracTime = 0; IncrNextTime(); } LOCALVAR ui5b NewMacDateInSeconds; static int usensec = 0; /* * nsec() is wallclock and can be adjusted by timesync * so need to use cycles() instead, but fall back to * nsec() in case we can't * * "fasthz" is how many ticks there are in a second * can be read from /dev/time * * perhaps using RDTSCP is even better */ static uvlong nanosec(void) { static uvlong fasthz, xstart; uvlong x, div; int f, n, i; char tmp[128], *e; if (fasthz == ~0ULL) return nsec() - xstart; if (fasthz == 0) { fasthz = ~0ULL; xstart = nsec(); if (usensec) return 0; if ((f = open("/dev/time", OREAD)) >= 0 && (n = read(f, tmp, sizeof(tmp)-1)) > 2) { tmp[n] = 0; e = tmp; for (i = 0; i < 3; i++) strtoll(e, &e, 10); if ((fasthz = strtoll(e, nil, 10)) < 1) fasthz = ~0ULL; else cycles(&xstart); } close(f); if (fasthz == ~0ULL) { fprint(2, "couldn't get fasthz, falling back to nsec()\n"); fprint(2, "you might want to disable aux/timesync\n"); return 0; } } cycles(&x); x -= xstart; for (div = 1000000000ULL; x < 0x1999999999999999ULL && div > 1 ; div /= 10ULL, x *= 10ULL); return x / (fasthz / div); } LOCALFUNC blnr UpdateTrueEmulatedTime(void) { Uint32 LatestTime; si5b TimeDiff; LatestTime = nanosec() / 1000000ULL; 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 trueblnr; } else { if (TimeDiff < -256) { #if dbglog_TimeStuff dbglog_writeln("clock set back"); #endif /* clock goofed if ever get here, reset */ InitNextTime(); } } } return falseblnr; } LOCALFUNC blnr CheckDateTime(void) { if (CurMacDateInSeconds != NewMacDateInSeconds) { CurMacDateInSeconds = NewMacDateInSeconds; return trueblnr; } else { return falseblnr; } } LOCALPROC StartUpTimeAdjust(void) { LastTime = nanosec() / 1000000ULL; InitNextTime(); } LOCALFUNC blnr InitLocationDat(void) { LastTime = nanosec() / 1000000ULL; InitNextTime(); NewMacDateInSeconds = LastTime / 1000; CurMacDateInSeconds = NewMacDateInSeconds; return trueblnr; } /* --- sound --- */ static int audiofd; static u8int *audiobuf; static int audiooff; GLOBALOSGLUFUNC tpSoundSamp MySound_BeginWrite(ui4r n, ui4r *actL) { *actL = n; audiooff += n; return audiobuf + audiooff - n; } LOCALVAR blnr HaveSoundOut = falseblnr; static char audiofmt[32]; static void runpcmconv(void *x) { int *p; p = x; dup(p[0], 0); close(p[0]); close(p[1]); dup(open("/dev/audio", OWRITE), 1); procexecl(nil, "/bin/audio/pcmconv", "pcmconv", "-i", audiofmt, nil); threadexits("exec: %r"); } #define SOUND_SAMPLERATE 22255 LOCALFUNC blnr MySound_Init(void) { int p[2]; sprint( audiofmt, "%c%dc1r%d", 3 == kLn2SoundSampSz ? 'u' : 's', 3 == kLn2SoundSampSz ? 8 : 16, SOUND_SAMPLERATE ); pipe(p); procrfork(runpcmconv, p, 4096, RFFDG); close(p[0]); audiofd = p[1]; HaveSoundOut = trueblnr; audiobuf = malloc(65536); return trueblnr; } GLOBALOSGLUPROC MySound_EndWrite(ui4r actL) { write(audiofd, audiobuf, audiooff); audiooff = 0; } /* --- 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); fprint(2, "%s\n", briefMsg0); fprint(2, "%s\n", longMsg0); SavedBriefMsg = nullpr; } } /* --- main window creation and disposal --- */ LOCALVAR int my_argc; LOCALVAR char **my_argv; enum { Cmouse, Cresize, Numchan, }; static Mousectl *mctl; static Keyboardctl kctl; static Rune rune; static Mouse mouse; static int altdown, ctldown, shiftdown; static Alt a[Numchan+1] = { [Cmouse] = { nil, &mouse, CHANRCV }, [Cresize] = { nil, nil, CHANRCV }, { nil, nil, CHANNOBLK }, }; static void kbdproc(void *) { char buf[128], buf2[128], *s; int kfd, n, kbin; Rune r; threadsetname("kbdproc"); if ((kfd = open("/dev/kbd", OREAD)) < 0) sysfatal("/dev/kbd: %r"); kbin = open("/dev/kbin", OWRITE); buf2[0] = 0; buf2[1] = 0; buf[0] = 0; for (;;) { if (buf[0] != 0) { n = strlen(buf)+1; memmove(buf, buf+n, sizeof(buf)-n); } if (buf[0] == 0) { n = read(kfd, buf, sizeof(buf)-1); if (n <= 0) break; buf[n-1] = 0; buf[n] = 0; } switch (buf[0]) { default: continue; case 'k': s = buf+1; while (*s) { s += chartorune(&r, s); if (utfrune(buf2+1, r) == nil) { DoKeyCode(r, 1); if (r == Kalt) { /* magic trick: write Alt scancode to disable the "compose" mode */ if (kbin >= 0) write(kbin, "\x46", 1); } } } break; case 'K': s = buf2+1; while (*s) { s += chartorune(&r, s); if (utfrune(buf+1, r) == nil) DoKeyCode(r, 0); } break; } strcpy(buf2, buf); } threadexits(nil); } static Cursor emptycursor = { {0, 0}, { 0 }, { 0 } }; LOCALFUNC blnr Screen_Init(void) { InitKeyCodes(); threadsetname(kStrAppName); if(initdraw(nil, nil, kStrAppName) < 0) sysfatal("initdraw: %r"); if ((mctl = initmouse(nil, screen)) == nil) sysfatal("initmouse: %r"); setcursor(mctl, &emptycursor); display->locking = 1; unlockdisplay(display); a[Cmouse].c = mctl->c; a[Cresize].c = mctl->resizec; proccreate(kbdproc, nil, mainstacksize); return trueblnr; } #if MayFullScreen LOCALVAR blnr GrabMachine = falseblnr; #endif #if MayFullScreen LOCALPROC GrabTheMachine(void) { #if GrabKeysFullScreen #endif #if EnableFSMouseMotion /* if magnification changes, need to reset, even if HaveMouseMotion already true */ if (MyMoveMouse(ViewHStart + (ViewHSize / 2), ViewVStart + (ViewVSize / 2))) { SavedMouseH = ViewHStart + (ViewHSize / 2); SavedMouseV = ViewVStart + (ViewVSize / 2); HaveMouseMotion = trueblnr; } #endif } #endif #if MayFullScreen LOCALPROC UngrabMachine(void) { #if EnableFSMouseMotion if (HaveMouseMotion) { (void) MyMoveMouse(CurMouseH, CurMouseV); HaveMouseMotion = falseblnr; } #endif #if GrabKeysFullScreen #endif } #endif #if EnableFSMouseMotion LOCALPROC MyMouseConstrain(void) { si4b shiftdh; si4b 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 (! MyMoveMouse(SavedMouseH, SavedMouseV)) { HaveMouseMotion = falseblnr; } } } #endif LOCALFUNC blnr CreateMainWindow(void) { int NewWindowHeight = vMacScreenHeight; int NewWindowWidth = vMacScreenWidth; blnr v = falseblnr; #if EnableMagnify && 1 if (UseMagnify) { NewWindowHeight *= MyWindowScale; NewWindowWidth *= MyWindowScale; } #endif #if VarFullScreen if (UseFullScreen) #endif #if MayFullScreen { } #endif ViewHStart = 0; ViewVStart = 0; ViewHSize = vMacScreenWidth; ViewVSize = vMacScreenHeight; freeimage(my_surface); my_surface = allocimage( display, Rect(0, 0, NewWindowWidth, NewWindowHeight), CHAN4(CBlue, 8, CGreen, 8, CRed, 8, CIgnore, 8), 0, DWhite); if (NULL == my_surface) { fprint(2, "allocimage: %r\n"); } else { #if 0 != vMacScreenDepth ColorModeWorks = trueblnr; #endif v = trueblnr; pixels = realloc(pixels, 4*NewWindowWidth*NewWindowHeight); } return v; } #if EnableRecreateW LOCALFUNC blnr ReCreateMainWindow(void) { ForceShowCursor(); /* hide/show cursor api is per window */ #if MayFullScreen if (GrabMachine) { GrabMachine = falseblnr; UngrabMachine(); } #endif #if EnableMagnify UseMagnify = WantMagnify; #endif #if VarFullScreen UseFullScreen = WantFullScreen; #endif (void) CreateMainWindow(); if (HaveCursorHidden) { (void) MyMoveMouse(CurMouseH, CurMouseV); } return trueblnr; } #endif LOCALPROC ZapWinStateVars(void) { } #if VarFullScreen LOCALPROC ToggleWantFullScreen(void) { WantFullScreen = ! WantFullScreen; } #endif /* --- SavedTasks --- */ LOCALPROC LeaveBackground(void) { ReconnectKeyCodes3(); DisableKeyRepeat(); } LOCALPROC EnterBackground(void) { RestoreKeyRepeat(); DisconnectKeyCodes3(); ForceShowCursor(); } LOCALPROC LeaveSpeedStopped(void) { StartUpTimeAdjust(); } LOCALPROC EnterSpeedStopped(void) { } LOCALPROC CheckForSavedTasks(void) { if (MyEvtQNeedRecover) { MyEvtQNeedRecover = falseblnr; /* attempt cleanup, MyEvtQNeedRecover may get set again */ MyEvtQTryRecoverFromFull(); } #if EnableFSMouseMotion if (HaveMouseMotion) { MyMouseConstrain(); } #endif if (RequestMacOff) { RequestMacOff = falseblnr; if (AnyDiskInserted()) { MacMsgOverride(kStrQuitWarningTitle, kStrQuitWarningMessage); } else { ForceMacOff = trueblnr; } } if (ForceMacOff) { return; } if (gTrueBackgroundFlag != gBackgroundFlag) { gBackgroundFlag = gTrueBackgroundFlag; if (gTrueBackgroundFlag) { EnterBackground(); } else { LeaveBackground(); } } if (CurSpeedStopped != (SpeedStopped || (gBackgroundFlag && ! RunInBackground #if EnableAutoSlow && 0 && (QuietSubTicks >= 4092) #endif ))) { 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 = falseblnr; ScreenChangedAll(); } #if NeedRequestIthDisk if (0 != RequestIthDisk) { Sony_InsertIth(RequestIthDisk); RequestIthDisk = 0; } #endif if (HaveCursorHidden != (WantCursorHidden && ! (gTrueBackgroundFlag || CurSpeedStopped))) { HaveCursorHidden = ! HaveCursorHidden; //FIXME setcursor(mctl, HaveCursorHidden ? &emptycursor : nil); } } /* --- command line parsing --- */ LOCALFUNC blnr ScanCommandLine(void) { char *pa; int i = 1; label_retry: if (i < my_argc) { pa = my_argv[i++]; if ('-' == pa[0]) { if ((0 == strcmp(pa, "--rom")) || (0 == strcmp(pa, "-r"))) { if (i < my_argc) { rom_path = my_argv[i++]; goto label_retry; } } else { MacMsg(kStrBadArgTitle, kStrBadArgMessage, falseblnr); } } else { (void) Sony_Insert1(pa, falseblnr); goto label_retry; } } return trueblnr; } /* --- main program flow --- */ GLOBALOSGLUFUNC blnr ExtraTimeNotOver(void) { UpdateTrueEmulatedTime(); return TrueEmulatedTime == OnTrueTime; } LOCALPROC WaitForTheNextEvent(void) { switch (alt(a)) { case -1: //threadexitsall(nil); case Cmouse: MousePositionNotify(mouse.xy.x-screen->r.min.x-(Dx(screen->r)-Dx(my_surface->r))/2, mouse.xy.y-screen->r.min.y-(Dx(screen->r)-Dx(my_surface->r))/2); MyMouseButtonSet(mouse.buttons & 1); break; case Cresize: if(getwindow(display, Refnone) < 0) sysfatal("getwindow: %r"); break; } } GLOBALOSGLUPROC WaitForNextTick(void) { label_retry: CheckForSavedTasks(); if (ForceMacOff) { return; } if (1) {//CurSpeedStopped) { DoneWithDrawingForTick(); WaitForTheNextEvent(); if (CurSpeedStopped) goto label_retry; } if (ExtraTimeNotOver()) { sleep(NextIntTime - LastTime); /* FIXME do a better job like in orca */ goto label_retry; } if (CheckDateTime()) { #if EnableDemoMsg DemoModeSecondNotify(); #endif } 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, falseblnr); ReserveAllocOneBlock(&screencomparebuff, vMacScreenNumBytes, 5, trueblnr); #if UseControlKeys ReserveAllocOneBlock(&CntrlDisplayBuff, vMacScreenNumBytes, 5, falseblnr); #endif ReserveAllocOneBlock(&CLUT_final, CLUT_finalsz, 5, falseblnr); EmulationReserveAlloc(); } LOCALFUNC blnr AllocMyMemory(void) { uimr n; blnr IsOk = falseblnr; ReserveAllocOffset = 0; ReserveAllocBigBlock = nullpr; ReserveAllocAll(); n = ReserveAllocOffset; ReserveAllocBigBlock = (ui3p)calloc(1, n); if (NULL == ReserveAllocBigBlock) { MacMsg(kStrOutOfMemTitle, kStrOutOfMemMessage, trueblnr); } else { ReserveAllocOffset = 0; ReserveAllocAll(); if (n != ReserveAllocOffset) { /* oops, program error */ } else { IsOk = trueblnr; } } return IsOk; } LOCALPROC UnallocMyMemory(void) { if (nullpr != ReserveAllocBigBlock) { free((char *)ReserveAllocBigBlock); } } LOCALFUNC blnr InitOSGLU(void) { if (AllocMyMemory()) #if dbglog_HAVE if (dbglog_open()) #endif if (ScanCommandLine()) if (LoadMacRom()) if (LoadInitialImages()) if (InitLocationDat()) if (MySound_Init()) if (Screen_Init()) if (CreateMainWindow()) if (WaitForRom()) { return trueblnr; } return falseblnr; } LOCALPROC UnInitOSGLU(void) { if (MacMsgDisplayed) { MacMsgDisplayOff(); } RestoreKeyRepeat(); #if MayFullScreen UngrabMachine(); #endif #if IncludePbufs UnInitPbufs(); #endif UnInitDrives(); ForceShowCursor(); #if dbglog_HAVE dbglog_close(); #endif UnallocMyMemory(); CheckSavedMacMsg(); } #if IncludeHostTextClipExchange GLOBALOSGLUFUNC tMacErr HTCEexport(tPbuf i) { return mnvm_miscErr; } #endif #if IncludeHostTextClipExchange GLOBALOSGLUFUNC tMacErr HTCEimport(tPbuf *r) { return mnvm_miscErr; } #endif void threadmain(int argc, char **argv) { my_argc = argc; my_argv = argv; ZapOSGLUVars(); if (InitOSGLU()) { ProgramMain(); } UnInitOSGLU(); threadexitsall(nil); }