this repo has no description
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 */