this repo has no description
at main 1384 lines 26 kB view raw
1/* 2 OSGLUNDS.c 3 4 Copyright (C) 2012 Lazyone, Paul C. Pratt 5 6 You can redistribute this file and/or modify it under the terms 7 of version 2 of the GNU General Public License as published by 8 the Free Software Foundation. You should have received a copy 9 of the license along with this file; see the file COPYING. 10 11 This file is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 license for more details. 15*/ 16 17/* 18 Operating System GLUe for Nintendo DS 19*/ 20 21#include "OSGCOMUI.h" 22#include "OSGCOMUD.h" 23 24#ifdef WantOSGLUNDS 25 26#include "FB1BPP2I.h" 27 28#define CONSOLE_TRACE() \ 29 fprintf(stderr, "%s() at line %d\n", __FUNCTION__, __LINE__) 30 31/* --- some simple utilities --- */ 32 33GLOBALOSGLUPROC MyMoveBytes(anyp srcPtr, anyp destPtr, si5b byteCount) 34{ 35 (void) memcpy((char *)destPtr, (char *)srcPtr, byteCount); 36} 37 38/* 39 Nintendo DS port globals 40*/ 41#define DS_ScreenWidth 256 42#define DS_ScreenHeight 192 43 44LOCALVAR volatile int VBlankCounter = 0; 45LOCALVAR volatile int HBlankCounter = 0; 46LOCALVAR volatile unsigned int TimerBaseMSec = 0; 47LOCALVAR Keyboard* DSKeyboard = NULL; 48LOCALVAR volatile int LastKeyboardKey = NOKEY; 49LOCALVAR volatile int KeyboardKey = NOKEY; 50LOCALVAR volatile int KeysHeld = 0; 51LOCALVAR volatile int CursorX = 0; 52LOCALVAR volatile int CursorY = 0; 53LOCALVAR int Display_bg2_Main = 0; 54 55/* --- control mode and internationalization --- */ 56 57#define NeedCell2PlainAsciiMap 1 58 59#include "INTLCHAR.h" 60 61/* --- sending debugging info to file --- */ 62 63#if dbglog_HAVE 64 65#define dbglog_ToStdErr 1 66 67#if ! dbglog_ToStdErr 68LOCALVAR FILE *dbglog_File = NULL; 69#endif 70 71LOCALFUNC blnr dbglog_open0(void) 72{ 73#if dbglog_ToStdErr 74 return trueblnr; 75#else 76 dbglog_File = fopen("dbglog.txt", "w"); 77 return (NULL != dbglog_File); 78#endif 79} 80 81LOCALPROC dbglog_write0(char *s, uimr L) 82{ 83#if dbglog_ToStdErr 84 (void) fwrite(s, 1, L, stderr); 85#else 86 if (dbglog_File != NULL) { 87 (void) fwrite(s, 1, L, dbglog_File); 88 } 89#endif 90} 91 92LOCALPROC dbglog_close0(void) 93{ 94#if ! dbglog_ToStdErr 95 if (dbglog_File != NULL) { 96 fclose(dbglog_File); 97 dbglog_File = NULL; 98 } 99#endif 100} 101 102#endif 103 104/* --- debug settings and utilities --- */ 105 106#if ! dbglog_HAVE 107#define WriteExtraErr(s) 108#else 109LOCALPROC WriteExtraErr(char *s) 110{ 111 dbglog_writeCStr("*** error: "); 112 dbglog_writeCStr(s); 113 dbglog_writeReturn(); 114} 115#endif 116 117/* --- information about the environment --- */ 118 119#define WantColorTransValid 0 120 121#include "COMOSGLU.h" 122#include "CONTROLM.h" 123 124LOCALPROC NativeStrFromCStr(char *r, char *s) 125{ 126 ui3b ps[ClStrMaxLength]; 127 int i; 128 int L; 129 130 ClStrFromSubstCStr(&L, ps, s); 131 132 for (i = 0; i < L; ++i) { 133 r[i] = Cell2PlainAsciiMap[ps[i]]; 134 } 135 136 r[L] = 0; 137} 138 139/* --- drives --- */ 140 141#define NotAfileRef NULL 142 143LOCALVAR FILE *Drives[NumDrives]; /* open disk image files */ 144#if IncludeSonyGetName || IncludeSonyNew 145LOCALVAR char *DriveNames[NumDrives]; 146#endif 147 148LOCALPROC InitDrives(void) 149{ 150 /* 151 This isn't really needed, Drives[i] and DriveNames[i] 152 need not have valid values when not vSonyIsInserted[i]. 153 */ 154 tDrive i; 155 156 for (i = 0; i < NumDrives; ++i) { 157 Drives[i] = NotAfileRef; 158#if IncludeSonyGetName || IncludeSonyNew 159 DriveNames[i] = NULL; 160#endif 161 } 162} 163 164GLOBALOSGLUFUNC tMacErr vSonyTransfer(blnr IsWrite, ui3p Buffer, 165 tDrive Drive_No, ui5r Sony_Start, ui5r Sony_Count, 166 ui5r *Sony_ActCount) 167{ 168 tMacErr err = mnvm_miscErr; 169 FILE *refnum = Drives[Drive_No]; 170 ui5r NewSony_Count = 0; 171 172 if (0 == fseek(refnum, Sony_Start, SEEK_SET)) { 173 if (IsWrite) { 174 NewSony_Count = fwrite(Buffer, 1, Sony_Count, refnum); 175 } else { 176 NewSony_Count = fread(Buffer, 1, Sony_Count, refnum); 177 } 178 179 if (NewSony_Count == Sony_Count) { 180 err = mnvm_noErr; 181 } 182 } 183 184 if (nullpr != Sony_ActCount) { 185 *Sony_ActCount = NewSony_Count; 186 } 187 188 return err; /*& figure out what really to return &*/ 189} 190 191GLOBALOSGLUFUNC tMacErr vSonyGetSize(tDrive Drive_No, ui5r *Sony_Count) 192{ 193 tMacErr err = mnvm_miscErr; 194 FILE *refnum = Drives[Drive_No]; 195 long v; 196 197 if (0 == fseek(refnum, 0, SEEK_END)) { 198 v = ftell(refnum); 199 if (v >= 0) { 200 *Sony_Count = v; 201 err = mnvm_noErr; 202 } 203 } 204 205 return err; /*& figure out what really to return &*/ 206} 207 208LOCALFUNC tMacErr vSonyEject0(tDrive Drive_No, blnr deleteit) 209{ 210 FILE *refnum = Drives[Drive_No]; 211 212 DiskEjectedNotify(Drive_No); 213 214 fclose(refnum); 215 Drives[Drive_No] = NotAfileRef; /* not really needed */ 216 217#if IncludeSonyGetName || IncludeSonyNew 218 { 219 char *s = DriveNames[Drive_No]; 220 if (NULL != s) { 221 if (deleteit) { 222 remove(s); 223 } 224 free(s); 225 DriveNames[Drive_No] = NULL; /* not really needed */ 226 } 227 } 228#endif 229 230 return mnvm_noErr; 231} 232 233GLOBALOSGLUFUNC tMacErr vSonyEject(tDrive Drive_No) 234{ 235 return vSonyEject0(Drive_No, falseblnr); 236} 237 238#if IncludeSonyNew 239GLOBALOSGLUFUNC tMacErr vSonyEjectDelete(tDrive Drive_No) 240{ 241 return vSonyEject0(Drive_No, trueblnr); 242} 243#endif 244 245LOCALPROC UnInitDrives(void) 246{ 247 tDrive i; 248 249 for (i = 0; i < NumDrives; ++i) { 250 if (vSonyIsInserted(i)) { 251 (void) vSonyEject(i); 252 } 253 } 254} 255 256#if IncludeSonyGetName 257GLOBALOSGLUFUNC tMacErr vSonyGetName(tDrive Drive_No, tPbuf *r) 258{ 259 char *drivepath = DriveNames[Drive_No]; 260 if (NULL == drivepath) { 261 return mnvm_miscErr; 262 } else { 263 char *s = strrchr(drivepath, '/'); 264 if (NULL == s) { 265 s = drivepath; 266 } else { 267 ++s; 268 } 269 return NativeTextToMacRomanPbuf(s, r); 270 } 271} 272#endif 273 274LOCALFUNC blnr Sony_Insert0(FILE *refnum, blnr locked, 275 char *drivepath) 276{ 277 tDrive Drive_No; 278 blnr IsOk = falseblnr; 279 280 if (! FirstFreeDisk(&Drive_No)) { 281 MacMsg(kStrTooManyImagesTitle, kStrTooManyImagesMessage, 282 falseblnr); 283 } else { 284 /* printf("Sony_Insert0 %d\n", (int)Drive_No); */ 285 286 { 287 Drives[Drive_No] = refnum; 288 DiskInsertNotify(Drive_No, locked); 289 290#if IncludeSonyGetName || IncludeSonyNew 291 { 292 ui5b L = strlen(drivepath); 293 char *p = malloc(L + 1); 294 if (p != NULL) { 295 (void) memcpy(p, drivepath, L + 1); 296 } 297 DriveNames[Drive_No] = p; 298 } 299#endif 300 301 IsOk = trueblnr; 302 } 303 } 304 305 if (! IsOk) { 306 fclose(refnum); 307 } 308 309 return IsOk; 310} 311 312LOCALFUNC blnr Sony_Insert1(char *drivepath, blnr silentfail) 313{ 314 blnr locked = falseblnr; 315 /* printf("Sony_Insert1 %s\n", drivepath); */ 316 FILE *refnum = fopen(drivepath, "rb+"); 317 if (NULL == refnum) { 318 locked = trueblnr; 319 refnum = fopen(drivepath, "rb"); 320 CONSOLE_TRACE(); 321 } 322 if (NULL == refnum) { 323 if (! silentfail) { 324 MacMsg(kStrOpenFailTitle, kStrOpenFailMessage, falseblnr); 325 CONSOLE_TRACE(); 326 } 327 } else { 328 CONSOLE_TRACE(); 329 return Sony_Insert0(refnum, locked, drivepath); 330 } 331 332 return falseblnr; 333} 334 335#define Sony_Insert2(s) Sony_Insert1(s, trueblnr) 336 337LOCALFUNC blnr Sony_InsertIth(int i) 338{ 339 blnr v; 340 341 if ((i > 9) || ! FirstFreeDisk(nullpr)) { 342 v = falseblnr; 343 } else { 344 char s[] = "disk?.dsk"; 345 346 s[4] = '0' + i; 347 348 v = Sony_Insert2(s); 349 } 350 351 return v; 352} 353 354LOCALFUNC blnr LoadInitialImages(void) 355{ 356 int i; 357 358 CONSOLE_TRACE(); 359 360 for (i = 1; Sony_InsertIth(i); ++i) { 361 /* stop on first error (including file not found) */ 362 } 363 364 return trueblnr; 365} 366 367#if IncludeSonyNew 368LOCALFUNC blnr WriteZero(FILE *refnum, ui5b L) 369{ 370#define ZeroBufferSize 2048 371 ui5b i; 372 ui3b buffer[ZeroBufferSize]; 373 374 memset(&buffer, 0, ZeroBufferSize); 375 376 while (L > 0) { 377 i = (L > ZeroBufferSize) ? ZeroBufferSize : L; 378 if (fwrite(buffer, 1, i, refnum) != i) { 379 return falseblnr; 380 } 381 L -= i; 382 } 383 return trueblnr; 384} 385#endif 386 387#if IncludeSonyNew 388LOCALPROC MakeNewDisk(ui5b L, char *drivepath) 389{ 390 blnr IsOk = falseblnr; 391 FILE *refnum = fopen(drivepath, "wb+"); 392 if (NULL == refnum) { 393 MacMsg(kStrOpenFailTitle, kStrOpenFailMessage, falseblnr); 394 } else { 395 if (WriteZero(refnum, L)) { 396 IsOk = Sony_Insert0(refnum, falseblnr, drivepath); 397 refnum = NULL; 398 } 399 if (refnum != NULL) { 400 fclose(refnum); 401 } 402 if (! IsOk) { 403 (void) remove(drivepath); 404 } 405 } 406} 407#endif 408 409#if IncludeSonyNew 410LOCALPROC MakeNewDiskAtDefault(ui5b L) 411{ 412 char s[ClStrMaxLength + 1]; 413 414 NativeStrFromCStr(s, "untitled.dsk"); 415 MakeNewDisk(L, s); 416} 417#endif 418 419/* --- ROM --- */ 420 421LOCALFUNC tMacErr LoadMacRomFrom(char *path) 422{ 423 tMacErr err; 424 FILE *ROM_File; 425 int File_Size; 426 427 ROM_File = fopen(path, "rb"); 428 if (NULL == ROM_File) { 429 err = mnvm_fnfErr; 430 } else { 431 File_Size = fread(ROM, 1, kROM_Size, ROM_File); 432 if (kROM_Size != File_Size) { 433 if (feof(ROM_File)) { 434 MacMsgOverride(kStrShortROMTitle, 435 kStrShortROMMessage); 436 err = mnvm_eofErr; 437 } else { 438 MacMsgOverride(kStrNoReadROMTitle, 439 kStrNoReadROMMessage); 440 err = mnvm_miscErr; 441 } 442 } else { 443 err = ROM_IsValid(); 444 } 445 fclose(ROM_File); 446 } 447 448 return err; 449} 450 451LOCALFUNC blnr LoadMacRom(void) 452{ 453 tMacErr err; 454 455 if (mnvm_fnfErr == (err = LoadMacRomFrom(RomFileName))) 456 { 457 } 458 459 return trueblnr; /* keep launching Mini vMac, regardless */ 460} 461 462/* --- video out --- */ 463 464#if MayFullScreen 465LOCALVAR short hOffset; 466LOCALVAR short vOffset; 467#endif 468 469#if VarFullScreen 470LOCALVAR blnr UseFullScreen = (WantInitFullScreen != 0); 471#endif 472 473#if EnableMagnify 474LOCALVAR blnr UseMagnify = (WantInitMagnify != 0); 475#endif 476 477LOCALVAR blnr CurSpeedStopped = trueblnr; 478 479#if EnableMagnify 480#define MaxScale MyWindowScale 481#else 482#define MaxScale 1 483#endif 484 485LOCALPROC HaveChangedScreenBuff(ui4r top, ui4r left, 486 ui4r bottom, ui4r right) 487{ 488 /* 489 Oh god, clean this up. 490 */ 491 u8 *octpix = NULL; 492 u32 *vram = NULL; 493 494 octpix = (u8 *)GetCurDrawBuff(); 495 vram = (u32 *)BG_BMP_RAM(0); 496 497 octpix += ((top * vMacScreenWidth ) >> 3); 498 vram += ((top * vMacScreenWidth ) >> 2); 499 500 FB1BPPtoIndexed(vram, octpix, 501 ((bottom - top) * vMacScreenWidth) >> 3); 502} 503 504LOCALPROC MyDrawChangesAndClear(void) 505{ 506 if (ScreenChangedBottom > ScreenChangedTop) { 507 HaveChangedScreenBuff(ScreenChangedTop, ScreenChangedLeft, 508 ScreenChangedBottom, ScreenChangedRight); 509 ScreenClearChanges(); 510 } 511} 512 513GLOBALOSGLUPROC DoneWithDrawingForTick(void) 514{ 515#if 0 && EnableFSMouseMotion 516 if (HaveMouseMotion) { 517 AutoScrollScreen(); 518 } 519#endif 520 MyDrawChangesAndClear(); 521} 522 523/* --- mouse --- */ 524 525/* cursor state */ 526 527LOCALPROC CheckMouseState(void) 528{ 529 si5b MotionX; 530 si5b MotionY; 531 532 /* 533 TODO: 534 535 - Don't hardcode motion values 536 - Acceleration? 537 - Allow key remapping 538 - Handle touchscreen input (non-mouse motion) 539 - Handle touchscreen input (trackpad style mouse motion) 540 */ 541 542 if (0 != (KeysHeld & KEY_LEFT)) { 543 MotionX = -4; 544 } else if (0 != (KeysHeld & KEY_RIGHT)) { 545 MotionX = 4; 546 } 547 548 if (0 != (KeysHeld & KEY_UP)) { 549 MotionY = -4; 550 } else if (0 != (KeysHeld & KEY_DOWN)) { 551 MotionY = 4; 552 } 553 554 HaveMouseMotion = trueblnr; 555 556 MyMousePositionSetDelta(MotionX, MotionY); 557 MyMouseButtonSet(0 != (KeysHeld & KEY_A)); 558} 559 560/* --- keyboard input --- */ 561 562LOCALVAR ui3b KC2MKC[256]; 563 564/* 565 AHA! 566 GCC Was turning this into a macro of some sort which of course 567 broke horribly with libnds's keyboard having some negative values. 568*/ 569LOCALPROC AssignKeyToMKC(int UKey, int LKey, ui3r MKC) 570{ 571 if (UKey != NOKEY) { 572 KC2MKC[UKey] = MKC; 573 } 574 575 if (LKey != NOKEY) { 576 KC2MKC[LKey] = MKC; 577 } 578} 579 580LOCALFUNC blnr KC2MKCInit(void) 581{ 582 int i; 583 584 for (i = 0; i < 256; ++i) { 585 KC2MKC[i] = MKC_None; 586 } 587 588 AssignKeyToMKC('A', 'a', MKC_A); 589 AssignKeyToMKC('B', 'b', MKC_B); 590 AssignKeyToMKC('C', 'c', MKC_C); 591 AssignKeyToMKC('D', 'd', MKC_D); 592 AssignKeyToMKC('E', 'e', MKC_E); 593 AssignKeyToMKC('F', 'f', MKC_F); 594 AssignKeyToMKC('G', 'g', MKC_G); 595 AssignKeyToMKC('H', 'h', MKC_H); 596 AssignKeyToMKC('I', 'i', MKC_I); 597 AssignKeyToMKC('J', 'j', MKC_J); 598 AssignKeyToMKC('K', 'k', MKC_K); 599 AssignKeyToMKC('L', 'l', MKC_L); 600 AssignKeyToMKC('M', 'm', MKC_M); 601 AssignKeyToMKC('N', 'n', MKC_N); 602 AssignKeyToMKC('O', 'o', MKC_O); 603 AssignKeyToMKC('P', 'p', MKC_P); 604 AssignKeyToMKC('Q', 'q', MKC_Q); 605 AssignKeyToMKC('R', 'r', MKC_R); 606 AssignKeyToMKC('S', 's', MKC_S); 607 AssignKeyToMKC('T', 't', MKC_T); 608 AssignKeyToMKC('U', 'u', MKC_U); 609 AssignKeyToMKC('V', 'v', MKC_V); 610 AssignKeyToMKC('W', 'w', MKC_W); 611 AssignKeyToMKC('X', 'x', MKC_X); 612 AssignKeyToMKC('Y', 'y', MKC_Y); 613 AssignKeyToMKC('Z', 'z', MKC_Z); 614 615 AssignKeyToMKC(')', '0', MKC_0); 616 AssignKeyToMKC('!', '1', MKC_1); 617 AssignKeyToMKC('@', '2', MKC_2); 618 AssignKeyToMKC('#', '3', MKC_3); 619 AssignKeyToMKC('$', '4', MKC_4); 620 AssignKeyToMKC('%', '5', MKC_5); 621 AssignKeyToMKC('^', '6', MKC_6); 622 AssignKeyToMKC('&', '7', MKC_7); 623 AssignKeyToMKC('*', '8', MKC_8); 624 AssignKeyToMKC('(', '9', MKC_9); 625 626 AssignKeyToMKC('~', '`', MKC_formac_Grave); 627 AssignKeyToMKC('_', '-', MKC_Minus); 628 AssignKeyToMKC('+', '=', MKC_Equal); 629 AssignKeyToMKC(':', ';', MKC_SemiColon); 630 AssignKeyToMKC('\"', '\'', MKC_SingleQuote); 631 AssignKeyToMKC('{', '[', MKC_LeftBracket); 632 AssignKeyToMKC('}', ']', MKC_RightBracket); 633 AssignKeyToMKC('|', '\\', MKC_formac_BackSlash); 634 AssignKeyToMKC('<', ',', MKC_Comma); 635 AssignKeyToMKC('>', '.', MKC_Period); 636 AssignKeyToMKC('?', '/', MKC_formac_Slash); 637 638 AssignKeyToMKC(NOKEY, DVK_SPACE, MKC_Space); 639 AssignKeyToMKC(NOKEY, DVK_BACKSPACE, MKC_BackSpace); 640 AssignKeyToMKC(NOKEY, DVK_ENTER, MKC_formac_Enter); 641 AssignKeyToMKC(NOKEY, DVK_TAB, MKC_Tab); 642 643 InitKeyCodes(); 644 645 return trueblnr; 646} 647 648LOCALPROC DoKeyCode0(int i, blnr down) 649{ 650 ui3r key = KC2MKC[i]; 651 if (MKC_None != key) { 652 fprintf(stderr, "%s() :: %c (%d) == %d\n", 653 __FUNCTION__, (char) i, key, down); 654 Keyboard_UpdateKeyMap2(key, down); 655 } 656} 657 658LOCALPROC DoKeyCode(int i, blnr down) 659{ 660 if ((i >= 0) && (i < 256)) { 661 DoKeyCode0(i, down); 662 } 663} 664 665/* 666 TODO: 667 668 Rethink keyboard input... 669 Especially shift and capslock, the libnds keyboard 670 is weird about those. 671*/ 672 673LOCALVAR blnr DS_Keystate_Menu = falseblnr; 674LOCALVAR blnr DS_Keystate_Shift = falseblnr; 675 676LOCALPROC DS_HandleKey(si5b Key, blnr Down) 677{ 678 if (Key == NOKEY) { 679 return; 680 } 681 682 switch (Key) { 683 case DVK_UP: 684 Keyboard_UpdateKeyMap2(MKC_Up, Down); 685 break; 686 687 case DVK_DOWN: 688 Keyboard_UpdateKeyMap2(MKC_Down, Down); 689 break; 690 691 case DVK_LEFT: 692 Keyboard_UpdateKeyMap2(MKC_Left, Down); 693 break; 694 695 case DVK_RIGHT: 696 Keyboard_UpdateKeyMap2(MKC_Right, Down); 697 break; 698 699 case DVK_SHIFT: 700 Keyboard_UpdateKeyMap2(MKC_formac_Shift, trueblnr); 701 break; 702 703 default: 704 if (Key > 0) { 705 DoKeyCode(Key, Down); 706 Keyboard_UpdateKeyMap2(MKC_formac_Shift, falseblnr); 707 } 708 break; 709 } 710} 711 712LOCALPROC DS_HandleKeyboard(void) 713{ 714 LastKeyboardKey = KeyboardKey; 715 KeyboardKey = keyboardUpdate(); 716 717 if ((KeyboardKey == NOKEY) && (LastKeyboardKey != NOKEY)) { 718 DS_HandleKey(LastKeyboardKey, falseblnr); 719 LastKeyboardKey = NOKEY; 720 } else { 721 DS_HandleKey(KeyboardKey, trueblnr); 722 LastKeyboardKey = KeyboardKey; 723 } 724} 725 726/* --- time, date, location --- */ 727 728LOCALVAR ui5b TrueEmulatedTime = 0; 729 730#include "DATE2SEC.h" 731 732#define TicksPerSecond 1000000 733/* #define TicksPerSecond 1000 */ 734 735LOCALVAR blnr HaveTimeDelta = falseblnr; 736LOCALVAR ui5b TimeDelta; 737 738LOCALVAR ui5b NewMacDateInSeconds; 739 740LOCALVAR ui5b LastTimeSec; 741LOCALVAR ui5b LastTimeUsec; 742 743LOCALPROC GetCurrentTicks(void) 744{ 745 struct timeval t; 746 747 gettimeofday(&t, NULL); 748 749 /* 750 HACKHACKHACK 751 */ 752 t.tv_usec = TimerBaseMSec + TIMER1_DATA; 753 t.tv_usec = t.tv_usec * 1000; 754 755 if (! HaveTimeDelta) { 756 time_t Current_Time; 757 struct tm *s; 758 759 (void) time(&Current_Time); 760 s = localtime(&Current_Time); 761 TimeDelta = Date2MacSeconds(s->tm_sec, s->tm_min, s->tm_hour, 762 s->tm_mday, 1 + s->tm_mon, 1900 + s->tm_year) - t.tv_sec; 763#if 0 && AutoTimeZone /* how portable is this ? */ 764 CurMacDelta = ((ui5b)(s->tm_gmtoff) & 0x00FFFFFF) 765 | ((s->tm_isdst ? 0x80 : 0) << 24); 766#endif 767 HaveTimeDelta = trueblnr; 768 } 769 770 NewMacDateInSeconds = t.tv_sec + TimeDelta; 771 LastTimeSec = (ui5b)t.tv_sec; 772 LastTimeUsec = (ui5b)t.tv_usec; 773} 774 775/* #define MyInvTimeStep 16626 */ /* TicksPerSecond / 60.14742 */ 776#define MyInvTimeStep 17 777 778LOCALVAR ui5b NextTimeSec; 779LOCALVAR ui5b NextTimeUsec; 780 781LOCALPROC IncrNextTime(void) 782{ 783 NextTimeUsec += MyInvTimeStep; 784 if (NextTimeUsec >= TicksPerSecond) { 785 NextTimeUsec -= TicksPerSecond; 786 NextTimeSec += 1; 787 } 788} 789 790LOCALPROC InitNextTime(void) 791{ 792 NextTimeSec = LastTimeSec; 793 NextTimeUsec = LastTimeUsec; 794 IncrNextTime(); 795} 796 797LOCALPROC StartUpTimeAdjust(void) 798{ 799 GetCurrentTicks(); 800 InitNextTime(); 801} 802 803LOCALFUNC si5b GetTimeDiff(void) 804{ 805 return ((si5b)(LastTimeSec - NextTimeSec)) * TicksPerSecond 806 + ((si5b)(LastTimeUsec - NextTimeUsec)); 807} 808 809LOCALPROC UpdateTrueEmulatedTime(void) 810{ 811 si5b TimeDiff; 812 813 GetCurrentTicks(); 814 815 TimeDiff = GetTimeDiff(); 816 if (TimeDiff >= 0) { 817 if (TimeDiff > 4 * MyInvTimeStep) { 818 /* emulation interrupted, forget it */ 819 ++TrueEmulatedTime; 820 InitNextTime(); 821 } else { 822 do { 823 ++TrueEmulatedTime; 824 IncrNextTime(); 825 TimeDiff -= TicksPerSecond; 826 } while (TimeDiff >= 0); 827 } 828 } else if (TimeDiff < - 2 * MyInvTimeStep) { 829 /* clock goofed if ever get here, reset */ 830 InitNextTime(); 831 } 832} 833 834LOCALFUNC blnr CheckDateTime(void) 835{ 836 if (CurMacDateInSeconds != NewMacDateInSeconds) { 837 CurMacDateInSeconds = NewMacDateInSeconds; 838 return trueblnr; 839 } else { 840 return falseblnr; 841 } 842} 843 844LOCALFUNC blnr InitLocationDat(void) 845{ 846 GetCurrentTicks(); 847 CurMacDateInSeconds = NewMacDateInSeconds; 848 849 return trueblnr; 850} 851 852/* --- basic dialogs --- */ 853 854LOCALPROC CheckSavedMacMsg(void) 855{ 856 if (nullpr != SavedBriefMsg) { 857 char briefMsg0[ClStrMaxLength + 1]; 858 char longMsg0[ClStrMaxLength + 1]; 859 860 NativeStrFromCStr(briefMsg0, SavedBriefMsg); 861 NativeStrFromCStr(longMsg0, SavedLongMsg); 862 863 fprintf(stderr, "%s\n", briefMsg0); 864 fprintf(stderr, "%s\n", longMsg0); 865 866 SavedBriefMsg = nullpr; 867 } 868} 869 870/* --- main window creation and disposal --- */ 871 872/* 873 Screen_Init 874 875 Mode 5 gives us 2 text backgrounds 0-1 (tiled mode) and 876 2 extended rotation backgrounds 2-3. (linear fb) 877 878 Also we need to map 2 banks of vram so we have enough space for 879 our 512x512 surface. 880*/ 881LOCALFUNC blnr Screen_Init(void) 882{ 883 videoSetMode(MODE_5_2D); 884 vramSetBankA(VRAM_A_MAIN_BG_0x06000000); 885 vramSetBankB(VRAM_B_MAIN_BG_0x06020000); 886 887 Display_bg2_Main = bgInit(2, BgType_Bmp8, BgSize_B8_512x512, 0, 0); 888 889 BG_PALETTE[0] = RGB15(31, 31, 31); 890 BG_PALETTE[1] = RGB15(0, 0, 0); 891 892 return trueblnr; 893} 894 895#if VarFullScreen 896LOCALPROC ToggleWantFullScreen(void) 897{ 898 WantFullScreen = ! WantFullScreen; 899} 900#endif 901 902/* --- SavedTasks --- */ 903 904LOCALPROC LeaveSpeedStopped(void) 905{ 906#if MySoundEnabled 907 MySound_Start(); 908#endif 909 910 StartUpTimeAdjust(); 911} 912 913LOCALPROC EnterSpeedStopped(void) 914{ 915#if MySoundEnabled 916 MySound_Stop(); 917#endif 918} 919 920LOCALPROC CheckForSavedTasks(void) 921{ 922 if (MyEvtQNeedRecover) { 923 MyEvtQNeedRecover = falseblnr; 924 925 /* attempt cleanup, MyEvtQNeedRecover may get set again */ 926 MyEvtQTryRecoverFromFull(); 927 } 928 929 if (RequestMacOff) { 930 RequestMacOff = falseblnr; 931 if (AnyDiskInserted()) { 932 MacMsgOverride(kStrQuitWarningTitle, 933 kStrQuitWarningMessage); 934 } else { 935 ForceMacOff = trueblnr; 936 } 937 } 938 939 if (ForceMacOff) { 940 return; 941 } 942 943 if (CurSpeedStopped != SpeedStopped) { 944 CurSpeedStopped = ! CurSpeedStopped; 945 if (CurSpeedStopped) { 946 EnterSpeedStopped(); 947 } else { 948 LeaveSpeedStopped(); 949 } 950 } 951 952#if IncludeSonyNew 953 if (vSonyNewDiskWanted) { 954#if IncludeSonyNameNew 955 if (vSonyNewDiskName != NotAPbuf) { 956 ui3p NewDiskNameDat; 957 if (MacRomanTextToNativePtr(vSonyNewDiskName, trueblnr, 958 &NewDiskNameDat)) 959 { 960 MakeNewDisk(vSonyNewDiskSize, (char *)NewDiskNameDat); 961 free(NewDiskNameDat); 962 } 963 PbufDispose(vSonyNewDiskName); 964 vSonyNewDiskName = NotAPbuf; 965 } else 966#endif 967 { 968 MakeNewDiskAtDefault(vSonyNewDiskSize); 969 } 970 vSonyNewDiskWanted = falseblnr; 971 /* must be done after may have gotten disk */ 972 } 973#endif 974 975 if ((nullpr != SavedBriefMsg) & ! MacMsgDisplayed) { 976 MacMsgDisplayOn(); 977 } 978 979 if (NeedWholeScreenDraw) { 980 NeedWholeScreenDraw = falseblnr; 981 ScreenChangedAll(); 982 } 983 984#if NeedRequestIthDisk 985 if (0 != RequestIthDisk) { 986 Sony_InsertIth(RequestIthDisk); 987 RequestIthDisk = 0; 988 } 989#endif 990} 991 992/* --- main program flow --- */ 993 994GLOBALOSGLUFUNC blnr ExtraTimeNotOver(void) 995{ 996 UpdateTrueEmulatedTime(); 997 return TrueEmulatedTime == OnTrueTime; 998} 999 1000LOCALPROC WaitForTheNextEvent(void) 1001{ 1002} 1003 1004LOCALPROC CheckForSystemEvents(void) 1005{ 1006 DS_HandleKeyboard(); 1007} 1008 1009GLOBALOSGLUPROC WaitForNextTick(void) 1010{ 1011label_retry: 1012 CheckForSystemEvents(); 1013 CheckForSavedTasks(); 1014 if (ForceMacOff) { 1015 return; 1016 } 1017 1018 if (CurSpeedStopped) { 1019 MyDrawChangesAndClear(); 1020 WaitForTheNextEvent(); 1021 goto label_retry; 1022 } 1023 1024 if (ExtraTimeNotOver()) { 1025 si5b TimeDiff = GetTimeDiff(); 1026 if (TimeDiff < 0) { 1027 /* 1028 FIXME: 1029 1030 Implement this? 1031 1032 struct timespec rqt; 1033 struct timespec rmt; 1034 1035 rqt.tv_sec = 0; 1036 rqt.tv_nsec = (- TimeDiff) * 1000; 1037 1038 (void) nanosleep(&rqt, &rmt); 1039 */ 1040 } 1041 goto label_retry; 1042 } 1043 1044 if (CheckDateTime()) { 1045#if MySoundEnabled 1046 MySound_SecondNotify(); 1047#endif 1048#if EnableDemoMsg 1049 DemoModeSecondNotify(); 1050#endif 1051 } 1052 1053 CheckMouseState(); 1054 1055 OnTrueTime = TrueEmulatedTime; 1056} 1057 1058/* 1059 DS_ScrollBackground: 1060 1061 Positions the screen as to center it over the emulated cursor. 1062*/ 1063LOCALPROC DS_ScrollBackground(void) 1064{ 1065 int ScrollX = 0; 1066 int ScrollY = 0; 1067 int Scale = 0; 1068 1069 /* 1070 TODO: 1071 Lots of magic numbers here. 1072 */ 1073#if EnableMagnify 1074 if (WantMagnify) { 1075 ScrollX = ((int) CurMouseH) - (DS_ScreenWidth / 4); 1076 ScrollY = ((int) CurMouseV) - (DS_ScreenHeight / 4); 1077 Scale = 128; 1078 1079 ScrollX = ScrollX > vMacScreenWidth - (DS_ScreenWidth / 2) 1080 ? vMacScreenWidth - (DS_ScreenWidth / 2) 1081 : ScrollX; 1082 ScrollY = ScrollY > vMacScreenHeight - (DS_ScreenHeight / 2) 1083 ? vMacScreenHeight - (DS_ScreenHeight / 2) 1084 : ScrollY; 1085 } else 1086#endif 1087 { 1088 ScrollX = ((int) CurMouseH) - (DS_ScreenWidth / 2); 1089 ScrollY = ((int) CurMouseV) - (DS_ScreenHeight / 2); 1090 Scale = 256; 1091 1092 ScrollX = ScrollX > vMacScreenWidth - DS_ScreenWidth 1093 ? vMacScreenWidth - DS_ScreenWidth 1094 : ScrollX; 1095 ScrollY = ScrollY > vMacScreenHeight - DS_ScreenHeight 1096 ? vMacScreenHeight - DS_ScreenHeight 1097 : ScrollY; 1098 } 1099 1100 ScrollX = ScrollX < 0 ? 0 : ScrollX; 1101 ScrollY = ScrollY < 0 ? 0 : ScrollY; 1102 1103 if (Display_bg2_Main) { 1104 bgSetScale(Display_bg2_Main, Scale, Scale); 1105 bgSetScroll(Display_bg2_Main, ScrollX, ScrollY); 1106 } 1107} 1108 1109/* 1110 DS_Timer1_IRQ 1111 1112 Called when TIMER0_DATA overflows. 1113*/ 1114LOCALPROC DS_Timer1_IRQ(void) 1115{ 1116 TimerBaseMSec += 65536; 1117} 1118 1119/* 1120 DS_VBlank_IRQ 1121 1122 Vertical blank interrupt callback. 1123*/ 1124LOCALPROC DS_VBlank_IRQ(void) 1125{ 1126 scanKeys(); 1127 1128 KeysHeld = keysHeld(); 1129 1130 if (++VBlankCounter == 60) { 1131 VBlankCounter = 0; 1132 } 1133 1134 /* 1135 TODO: 1136 Rewrite this at some point, I'm not sure I like it. 1137 */ 1138 if (0 != (KeysHeld & KEY_LEFT)) { 1139 --CursorX; 1140 } else if (0 != (KeysHeld & KEY_RIGHT)) { 1141 ++CursorX; 1142 } 1143 1144 if (0 != (KeysHeld & KEY_UP)) { 1145 --CursorY; 1146 } else if (0 != (KeysHeld & KEY_DOWN)) { 1147 ++CursorY; 1148 } 1149 1150 CursorX = CursorX < 0 ? 0 : CursorX; 1151 CursorX = CursorX > vMacScreenWidth ? vMacScreenWidth : CursorX; 1152 1153 CursorY = CursorY < 0 ? 0 : CursorY; 1154 CursorY = CursorY > vMacScreenHeight ? vMacScreenHeight : CursorY; 1155 1156 DS_ScrollBackground(); 1157 bgUpdate(); 1158} 1159 1160/* 1161 DS_HBlank_IRQ 1162 1163 Called at the start of the horizontal blanking period. 1164 This is here mainly as a simple performance test. 1165*/ 1166LOCALPROC DS_HBlank_IRQ(void) 1167{ 1168 ++HBlankCounter; 1169} 1170 1171/* 1172 DS_SysInit 1173 1174 Initializes DS specific system hardware and interrupts. 1175*/ 1176LOCALPROC DS_SysInit(void) 1177{ 1178 defaultExceptionHandler(); 1179 powerOn(POWER_ALL_2D); 1180 lcdMainOnTop(); 1181 1182 irqSet(IRQ_VBLANK, DS_VBlank_IRQ); 1183 irqSet(IRQ_HBLANK, DS_HBlank_IRQ); 1184 irqSet(IRQ_TIMER1, DS_Timer1_IRQ); 1185 1186 irqEnable(IRQ_VBLANK); 1187 irqEnable(IRQ_HBLANK); 1188 irqEnable(IRQ_TIMER1); 1189 1190 /* 1191 This sets up 2 timers as a milisecond counter. 1192 TIMER0_DATA Will overflow roughly every 1 msec into TIMER1_DATA. 1193 When TIMER1_DATA overflows an interrupt will be generated 1194 and DS_Timer1_IRQ will be called. 1195 */ 1196 TIMER0_DATA = 32768; 1197 1198 TIMER0_CR = TIMER_DIV_1 | TIMER_ENABLE; 1199 1200 1201 1202 TIMER1_DATA = 0; 1203 1204 TIMER1_CR = TIMER_ENABLE | TIMER_CASCADE | TIMER_IRQ_REQ; 1205 1206 /* 1207 Testing. 1208 */ 1209 consoleDemoInit(); 1210 consoleDebugInit(DebugDevice_NOCASH); 1211 1212 /* 1213 Use the default keyboard until I design a (good) UI... 1214 */ 1215 DSKeyboard = keyboardDemoInit(); 1216 keyboardShow(); 1217 1218 /* 1219 Drop back to a read only filesystem embedded in the 1220 Mini vMac binary if we cannot open a media device. 1221 */ 1222 if (! fatInitDefault()) { 1223 nitroFSInit(); 1224 } 1225} 1226 1227/* 1228 DS_ClearVRAM: 1229 1230 Make sure all of the video memory and background/object palettes 1231 are zeroed out just in-case the loader doesn't do it for us. 1232*/ 1233LOCALPROC DS_ClearVRAM(void) 1234{ 1235 vramSetPrimaryBanks(VRAM_A_LCD, VRAM_B_LCD, VRAM_C_LCD, VRAM_D_LCD); 1236 1237 dmaFillWords(0, (void *) VRAM_A, 128 * 1024 * 4); 1238 dmaFillWords(0, (void *) BG_PALETTE, 256 * 2); 1239 dmaFillWords(0, (void *) BG_PALETTE_SUB, 256 * 2); 1240 dmaFillWords(0, (void *) SPRITE_PALETTE, 256 * 2); 1241 dmaFillWords(0, (void *) SPRITE_PALETTE_SUB, 256 * 2); 1242 1243 vramDefault(); 1244} 1245 1246/* --- platform independent code can be thought of as going here --- */ 1247 1248#include "PROGMAIN.h" 1249 1250LOCALPROC ReserveAllocAll(void) 1251{ 1252#if dbglog_HAVE 1253 dbglog_ReserveAlloc(); 1254#endif 1255 ReserveAllocOneBlock(&ROM, kROM_Size, 5, falseblnr); 1256 1257 ReserveAllocOneBlock(&screencomparebuff, 1258 vMacScreenNumBytes, 5, trueblnr); 1259#if UseControlKeys 1260 ReserveAllocOneBlock(&CntrlDisplayBuff, 1261 vMacScreenNumBytes, 5, falseblnr); 1262#endif 1263 1264#if MySoundEnabled 1265 ReserveAllocOneBlock((ui3p *)&TheSoundBuffer, 1266 dbhBufferSize, 5, falseblnr); 1267#endif 1268 1269 EmulationReserveAlloc(); 1270} 1271 1272LOCALFUNC blnr AllocMyMemory(void) 1273{ 1274 uimr n; 1275 blnr IsOk = falseblnr; 1276 1277 ReserveAllocOffset = 0; 1278 ReserveAllocBigBlock = nullpr; 1279 ReserveAllocAll(); 1280 n = ReserveAllocOffset; 1281 ReserveAllocBigBlock = (ui3p)calloc(1, n); 1282 if (NULL == ReserveAllocBigBlock) { 1283 MacMsg(kStrOutOfMemTitle, kStrOutOfMemMessage, trueblnr); 1284 } else { 1285 ReserveAllocOffset = 0; 1286 ReserveAllocAll(); 1287 if (n != ReserveAllocOffset) { 1288 /* oops, program error */ 1289 } else { 1290 IsOk = trueblnr; 1291 } 1292 } 1293 1294 return IsOk; 1295} 1296 1297LOCALPROC UnallocMyMemory(void) 1298{ 1299 if (nullpr != ReserveAllocBigBlock) { 1300 free((char *)ReserveAllocBigBlock); 1301 } 1302} 1303 1304LOCALPROC ZapOSGLUVars(void) 1305{ 1306 InitDrives(); 1307 DS_ClearVRAM(); 1308} 1309 1310LOCALFUNC blnr InitOSGLU(void) 1311{ 1312 DS_SysInit(); 1313 1314 if (AllocMyMemory()) 1315#if dbglog_HAVE 1316 if (dbglog_open()) 1317#endif 1318 if (LoadMacRom()) 1319 if (LoadInitialImages()) 1320 if (InitLocationDat()) 1321#if MySoundEnabled 1322 if (MySound_Init()) 1323#endif 1324 if (Screen_Init()) 1325 if (KC2MKCInit()) 1326 if (WaitForRom()) 1327 { 1328 return trueblnr; 1329 } 1330 1331 return falseblnr; 1332} 1333 1334LOCALPROC UnInitOSGLU(void) 1335{ 1336 if (MacMsgDisplayed) { 1337 MacMsgDisplayOff(); 1338 } 1339 1340#if MySoundEnabled 1341 MySound_Stop(); 1342#endif 1343#if MySoundEnabled 1344 MySound_UnInit(); 1345#endif 1346 1347 UnInitDrives(); 1348 1349#if dbglog_HAVE 1350 dbglog_close(); 1351#endif 1352 1353 UnallocMyMemory(); 1354 CheckSavedMacMsg(); 1355} 1356 1357int main(int argc, char **argv) 1358{ 1359 ZapOSGLUVars(); 1360 1361 if (InitOSGLU()) { 1362 iprintf("Entering ProgramMain...\n"); 1363 1364 ProgramMain(); 1365 1366 iprintf("Leaving ProgramMain...\n"); 1367 } 1368 1369 UnInitOSGLU(); 1370 1371 /* 1372 On some homebrew launchers this could return to 1373 the menu by default. 1374 */ 1375 exit(1); 1376 1377 while (1) { 1378 swiWaitForVBlank(); 1379 } 1380 1381 return 0; 1382} 1383 1384#endif /* WantOSGLUNDS */