comparison src/win32/System.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
comparison
equal deleted inserted replaced
0:8ced16adf2e1 1:f9f4f1b99eed
1 // System.cpp : Defines the system behaviors for the emulator.
2 //
3 #include "stdafx.h"
4 #include "Sound.h"
5 #include "Input.h"
6 #include "IUpdate.h"
7 #include "ram_search.h"
8 #include "WinMiscUtil.h"
9 #include "WinResUtil.h"
10 #include "resource.h"
11 #include "VBA.h"
12 #include "../gba/GBA.h"
13 #include "../gba/GBAGlobals.h"
14 #include "../gba/GBASound.h"
15 #include "../gb/GB.h"
16 #include "../gb/gbGlobals.h"
17 //#include "../common/System.h"
18 #include "../common/movie.h"
19 #include "../common/vbalua.h"
20 #include "../common/Text.h"
21 #include "../common/Util.h"
22 #include "../common/nesvideos-piece.h"
23 #include "../version.h"
24 #include <cassert>
25
26 struct EmulatedSystem theEmulator;
27
28 u32 RGB_LOW_BITS_MASK = 0;
29 int emulating = 0;
30 int systemCartridgeType = 0;
31 int systemSpeed = 0;
32 bool systemSoundOn = false;
33 u32 systemColorMap32[0x10000];
34 u16 systemColorMap16[0x10000];
35 u16 systemGbPalette[24];
36 int systemRedShift = 0;
37 int systemBlueShift = 0;
38 int systemGreenShift = 0;
39 int systemColorDepth = 16;
40 int systemDebug = 0;
41 int systemVerbose = 0;
42 int systemFrameSkip = 0;
43 int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
44
45 const int32 INITIAL_SENSOR_VALUE = 2047;
46
47 int32 sensorX = INITIAL_SENSOR_VALUE;
48 int32 sensorY = INITIAL_SENSOR_VALUE;
49 u16 currentButtons [4] = { 0, 0, 0, 0 }; // constrain: never contains hacked buttons, only the lower 16 bits of each are used
50 u16 lastKeys = 0;
51
52 // static_assertion that BUTTON_REGULAR_RECORDING_MASK should be an u16 constant
53 namespace { const void * const s_STATIC_ASSERTION_(static_cast<void *>(BUTTON_REGULAR_RECORDING_MASK & 0xFFFF0000)); }
54
55 #define BMP_BUFFER_MAX_WIDTH (256)
56 #define BMP_BUFFER_MAX_HEIGHT (224)
57 #define BMP_BUFFER_MAX_DEPTH (4)
58 static u8 bmpBuffer[BMP_BUFFER_MAX_WIDTH * BMP_BUFFER_MAX_HEIGHT * BMP_BUFFER_MAX_DEPTH];
59
60 static int s_stockThrottleValues[] = {
61 6, 15, 25, 25, 37, 50, 75, 87, 100, 112, 125, 150, 200, 300, 400, 600, 800, 1000
62 };
63
64 // systemXYZ: Win32 stuff
65
66 // input
67
68 void systemSetSensorX(int32 x)
69 {
70 sensorX = x;
71 }
72
73 void systemSetSensorY(int32 y)
74 {
75 sensorY = y;
76 }
77
78 void systemResetSensor()
79 {
80 sensorX = sensorY = INITIAL_SENSOR_VALUE;
81 }
82
83 int32 systemGetSensorX()
84 {
85 return sensorX;
86 }
87
88 int32 systemGetSensorY()
89 {
90 return sensorY;
91 }
92
93 // handles motion sensor input
94 void systemUpdateMotionSensor(int i)
95 {
96 if (i < 0 || i > 3)
97 i = 0;
98
99 if (currentButtons[i] & BUTTON_MASK_LEFT_MOTION)
100 {
101 sensorX += 3;
102 if (sensorX > 2197)
103 sensorX = 2197;
104 if (sensorX < 2047)
105 sensorX = 2057;
106 }
107 else if (currentButtons[i] & BUTTON_MASK_RIGHT_MOTION)
108 {
109 sensorX -= 3;
110 if (sensorX < 1897)
111 sensorX = 1897;
112 if (sensorX > 2047)
113 sensorX = 2037;
114 }
115 else if (sensorX > 2047)
116 {
117 sensorX -= 2;
118 if (sensorX < 2047)
119 sensorX = 2047;
120 }
121 else
122 {
123 sensorX += 2;
124 if (sensorX > 2047)
125 sensorX = 2047;
126 }
127
128 if (currentButtons[i] & BUTTON_MASK_UP_MOTION)
129 {
130 sensorY += 3;
131 if (sensorY > 2197)
132 sensorY = 2197;
133 if (sensorY < 2047)
134 sensorY = 2057;
135 }
136 else if (currentButtons[i] & BUTTON_MASK_DOWN_MOTION)
137 {
138 sensorY -= 3;
139 if (sensorY < 1897)
140 sensorY = 1897;
141 if (sensorY > 2047)
142 sensorY = 2037;
143 }
144 else if (sensorY > 2047)
145 {
146 sensorY -= 2;
147 if (sensorY < 2047)
148 sensorY = 2047;
149 }
150 else
151 {
152 sensorY += 2;
153 if (sensorY > 2047)
154 sensorY = 2047;
155 }
156 }
157
158 int systemGetDefaultJoypad()
159 {
160 return theApp.joypadDefault;
161 }
162
163 void systemSetDefaultJoypad(int which)
164 {
165 theApp.joypadDefault = which;
166 }
167
168 bool systemReadJoypads()
169 {
170 // this function is called at every frame, even if vba is fast-forwarded.
171 // so we try to limit the input frequency here just in case.
172 static u32 lastTime = systemGetClock();
173 if ((u32)(systemGetClock() - lastTime) < 10)
174 return false;
175 lastTime = systemGetClock();
176
177 if (theApp.input)
178 return theApp.input->readDevices();
179 return false;
180 }
181
182 u32 systemGetOriginalJoypad(int i, bool sensor)
183 {
184 if (i < 0 || i > 3)
185 i = 0;
186
187 u32 res = 0;
188 if (theApp.input)
189 res = theApp.input->readDevice(i, sensor);
190
191 // +auto input, XOR
192 // maybe these should be moved into DirectInput.cpp
193 if (theApp.autoFire || theApp.autoFire2)
194 {
195 res ^= (theApp.autoFireToggle ? theApp.autoFire : theApp.autoFire2);
196 if (!theApp.autofireAccountForLag || !systemCounters.laggedLast)
197 {
198 theApp.autoFireToggle = !theApp.autoFireToggle;
199 }
200 }
201 if (theApp.autoHold)
202 {
203 res ^= theApp.autoHold;
204 }
205
206 // filter buttons
207 // maybe better elsewhere?
208 if (!theApp.allowLeftRight)
209 {
210 // disallow L+R or U+D to being pressed at the same time
211 if ((res & (BUTTON_MASK_RIGHT | BUTTON_MASK_LEFT)) == (BUTTON_MASK_RIGHT | BUTTON_MASK_LEFT))
212 res &= ~BUTTON_MASK_RIGHT; // leave only LEFT on
213 if ((res & (BUTTON_MASK_DOWN | BUTTON_MASK_UP)) == (BUTTON_MASK_DOWN | BUTTON_MASK_UP))
214 res &= ~BUTTON_MASK_DOWN; // leave only UP on
215 }
216
217 if (!sensor)
218 {
219 if (res & BUTTON_MOTION_MASK)
220 res &= ~BUTTON_MOTION_MASK;
221 }
222
223 if (systemCartridgeType != 0 && !gbSgbMode) // regular GB has no L/R buttons
224 {
225 if (res & (BUTTON_GBA_ONLY))
226 res &= ~BUTTON_GBA_ONLY;
227 }
228
229 currentButtons[i] = res & BUTTON_REGULAR_RECORDING_MASK;
230
231 return res;
232 }
233
234 u32 systemGetJoypad(int i, bool sensor)
235 {
236 if (i < 0 || i > 3)
237 i = 0;
238
239 // input priority: original+auto < Lua < frame search < movie, correct this if wrong
240
241 // get original+auto input
242 u32 hackedButtons = systemGetOriginalJoypad(i, sensor) & BUTTON_NONRECORDINGONLY_MASK;
243 u32 res = currentButtons[i];
244
245 // since movie input has the highest priority, there's no point to read from other input
246 if (VBAMoviePlaying())
247 {
248 // VBAMovieRead() overwrites currentButtons[i]
249 VBAMovieRead(i, sensor);
250 res = currentButtons[i];
251 }
252 else
253 {
254 // Lua input, shouldn't have any side effect within them
255 if (VBALuaUsingJoypad(i))
256 res = VBALuaReadJoypad(i);
257
258 // override input above
259 if (theApp.frameSearchSkipping)
260 res = theApp.frameSearchOldInput[i];
261
262 // flush non-hack buttons into the "current buttons" input buffer, which will be read by the movie routine
263 currentButtons[i] = res & BUTTON_REGULAR_RECORDING_MASK;
264 VBAMovieWrite(i, sensor);
265 }
266
267 return res | hackedButtons;
268 }
269
270 void systemSetJoypad(int which, u32 buttons)
271 {
272 if (which < 0 || which > 3)
273 which = 0;
274
275 currentButtons[which] = buttons;
276
277 lastKeys = 0;
278 }
279
280 void systemClearJoypads()
281 {
282 for (int i = 0; i < 3; ++i)
283 currentButtons[i] = 0;
284
285 lastKeys = 0;
286 }
287
288 // screen
289
290 // delayed repaint
291 void systemRefreshScreen()
292 {
293 if (theApp.m_pMainWnd)
294 {
295 theApp.m_pMainWnd->PostMessage(WM_PAINT, NULL, NULL);
296 }
297 }
298
299 extern bool vbaShuttingDown;
300
301 void systemRenderFrame()
302 {
303 extern long linearSoundFrameCount;
304 extern long linearFrameCount;
305
306 if (vbaShuttingDown)
307 return;
308
309 ++theApp.renderedFrames;
310
311 VBAUpdateFrameCountDisplay();
312 VBAUpdateButtonPressDisplay();
313
314 // "in-game" text rendering
315 if (textMethod == 0) // transparent text can only be painted once, so timed messages will not be updated
316 {
317 extern void DrawLuaGui();
318 DrawLuaGui();
319
320 int copyX = 240, copyY = 160;
321 if (systemCartridgeType == 1)
322 if (gbBorderOn)
323 copyX = 256, copyY = 224;
324 else
325 copyX = 160, copyY = 144;
326 int pitch = copyX * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4); // FIXME: sure?
327
328 DrawTextMessages((u8 *)pix, pitch, 0, copyY);
329 }
330
331 ++linearFrameCount;
332 if (!theApp.sound)
333 {
334 if (linearFrameCount > 10000)
335 linearFrameCount -= 10000;
336 linearSoundFrameCount = linearFrameCount;
337 }
338
339 // record avi
340 int width = 240;
341 int height = 160;
342 switch (systemCartridgeType)
343 {
344 case 0:
345 width = 240;
346 height = 160;
347 break;
348 case 1:
349 if (gbBorderOn)
350 {
351 width = 256;
352 height = 224;
353 }
354 else
355 {
356 width = 160;
357 height = 144;
358 }
359 break;
360 }
361
362 bool firstFrameLogged = false;
363 --linearFrameCount;
364 do
365 {
366 ++linearFrameCount;
367
368 if (theApp.aviRecording && (!theApp.altAviRecordMethod || (theApp.altAviRecordMethod && !firstFrameLogged)))
369 {
370 // usually aviRecorder is created when vba starts avi recording, though
371 if (theApp.aviRecorder == NULL)
372 {
373 theApp.aviRecorder = new AVIWrite();
374
375 theApp.aviRecorder->SetFPS(60);
376
377 BITMAPINFOHEADER bi;
378 memset(&bi, 0, sizeof(bi));
379 bi.biSize = 0x28;
380 bi.biPlanes = 1;
381 bi.biBitCount = 24;
382 bi.biWidth = width;
383 bi.biHeight = height;
384 bi.biSizeImage = 3 * width * height;
385 theApp.aviRecorder->SetVideoFormat(&bi);
386 if (!theApp.aviRecorder->Open(theApp.aviRecordName))
387 {
388 delete theApp.aviRecorder;
389 theApp.aviRecorder = NULL;
390 theApp.aviRecording = false;
391 }
392 }
393
394 if (theApp.aviRecorder != NULL && !theApp.aviRecorder->IsPaused())
395 {
396 assert(
397 width <= BMP_BUFFER_MAX_WIDTH && height <= BMP_BUFFER_MAX_HEIGHT && systemColorDepth <=
398 BMP_BUFFER_MAX_DEPTH * 8);
399 utilWriteBMP(bmpBuffer, width, height, systemColorDepth, pix);
400 theApp.aviRecorder->AddFrame(bmpBuffer);
401 }
402 }
403
404 if (theApp.nvVideoLog)
405 {
406 // convert from whatever bit depth to 16-bit, while stripping away extra pixels
407 assert(width <= BMP_BUFFER_MAX_WIDTH && height <= BMP_BUFFER_MAX_HEIGHT && 16 <= BMP_BUFFER_MAX_DEPTH * 8);
408 utilWriteBMP(bmpBuffer, width, -height, 16, pix);
409 NESVideoLoggingVideo((u8 *)bmpBuffer, width, height, 0x1000000 * 60);
410 }
411
412 firstFrameLogged = true;
413 }
414 while (linearFrameCount < linearSoundFrameCount); // compensate for frames lost due to frame skip being nonzero, etc.
415
416 if (textMethod != 0) // do not draw Lua HUD to a video dump
417 {
418 extern void DrawLuaGui();
419 DrawLuaGui();
420 }
421
422 // interframe blending
423 if (theApp.ifbFunction)
424 {
425 if (systemColorDepth == 16)
426 theApp.ifbFunction(pix + theApp.filterWidth * 2 + 4, theApp.filterWidth * 2 + 4,
427 theApp.filterWidth, theApp.filterHeight);
428 else
429 theApp.ifbFunction(pix + theApp.filterWidth * 4 + 4, theApp.filterWidth * 4 + 4,
430 theApp.filterWidth, theApp.filterHeight);
431 }
432
433 systemRedrawScreen();
434 }
435
436 void systemRedrawScreen()
437 {
438 if (vbaShuttingDown)
439 return;
440
441 if (theApp.display)
442 theApp.display->render();
443
444 systemUpdateListeners();
445 }
446
447 void systemUpdateListeners()
448 {
449 if (vbaShuttingDown)
450 return;
451
452 Update_RAM_Search(); // updates RAM search and RAM watch
453
454 // update viewers etc.
455 if (theApp.updateCount)
456 {
457 POSITION pos = theApp.updateList.GetHeadPosition();
458 while (pos)
459 {
460 IUpdateListener *up = theApp.updateList.GetNext(pos);
461 if (up)
462 up->update();
463 }
464 }
465 }
466
467 int systemScreenCapture(int captureNumber)
468 {
469 return winScreenCapture(captureNumber);
470 }
471
472 void systemMessage(int number, const char *defaultMsg, ...)
473 {
474 CString buffer;
475 va_list valist;
476 CString msg = defaultMsg;
477 if (number)
478 msg = winResLoadString(number);
479
480 va_start(valist, defaultMsg);
481 buffer.FormatV(msg, valist);
482
483 theApp.winCheckFullscreen();
484 systemSoundClearBuffer();
485 AfxGetApp()->m_pMainWnd->MessageBox(buffer, winResLoadString(IDS_ERROR), MB_OK | MB_ICONERROR);
486
487 va_end(valist);
488 }
489
490 void systemScreenMessage(const char *msg, int slot, int duration, const char *colorList)
491 {
492 if (slot < 0 || slot > SCREEN_MESSAGE_SLOTS)
493 return;
494
495 theApp.screenMessage[slot] = true;
496 theApp.screenMessageTime[slot] = GetTickCount();
497 theApp.screenMessageDuration[slot] = duration;
498 theApp.screenMessageBuffer[slot] = msg;
499 theApp.screenMessageColorBuffer[slot] = colorList ? colorList : "";
500
501 if (theApp.screenMessageBuffer[slot].GetLength() > 40)
502 theApp.screenMessageBuffer[slot] = theApp.screenMessageBuffer[slot].Left(40);
503
504 // update the display when a main slot message appears while the game is paused
505 if (slot == 0 && (theApp.paused || (theApp.frameSearching)))
506 systemRefreshScreen();
507 }
508
509 void systemShowSpeed(int speed)
510 {
511 systemSpeed = speed;
512 theApp.showRenderedFrames = theApp.renderedFrames;
513 theApp.renderedFrames = 0;
514 if (theApp.videoOption <= VIDEO_4X && theApp.showSpeed)
515 {
516 CString buffer;
517 if (theApp.showSpeed == 1)
518 buffer.Format(VBA_NAME_AND_VERSION " %3d%%", systemSpeed);
519 else
520 buffer.Format(VBA_NAME_AND_VERSION " %3d%% (%d fps | %d skipped)",
521 systemSpeed,
522 theApp.showRenderedFrames,
523 systemFrameSkip);
524
525 systemSetTitle(buffer);
526 }
527 }
528
529 void systemSetTitle(const char *title)
530 {
531 if (theApp.m_pMainWnd != NULL)
532 {
533 AfxGetApp()->m_pMainWnd->SetWindowText(title);
534 }
535 }
536
537 // timing/speed
538
539 u32 systemGetClock()
540 {
541 return timeGetTime();
542 }
543
544 void systemIncreaseThrottle()
545 {
546 int throttle = theApp.throttle;
547
548 if (throttle < 6)
549 ++throttle;
550 else if (throttle < s_stockThrottleValues[_countof(s_stockThrottleValues) - 1])
551 {
552 int i = 0;
553 while (throttle >= s_stockThrottleValues[i])
554 {
555 ++i;
556 }
557 throttle = s_stockThrottleValues[i];
558 }
559
560 systemSetThrottle(throttle);
561 }
562
563 void systemDecreaseThrottle()
564 {
565 int throttle = theApp.throttle;
566
567 if (throttle > 6)
568 {
569 int i = _countof(s_stockThrottleValues) - 1;
570 while (throttle <= s_stockThrottleValues[i])
571 {
572 --i;
573 }
574 throttle = s_stockThrottleValues[i];
575 }
576 else if (throttle > 1)
577 --throttle;
578
579 systemSetThrottle(throttle);
580 }
581
582 void systemSetThrottle(int throttle)
583 {
584 theApp.throttle = throttle;
585 char str[256];
586 sprintf(str, "%d%% throttle speed", theApp.throttle);
587 systemScreenMessage(str);
588 }
589
590 int systemGetThrottle()
591 {
592 return theApp.throttle;
593 }
594
595 void systemFrame()
596 {
597 if (theApp.altAviRecordMethod && theApp.aviRecording)
598 {
599 if (theApp.aviRecorder)
600 {
601 if (!theApp.aviRecorder->IsSoundAdded())
602 {
603 WAVEFORMATEX wfx;
604 memset(&wfx, 0, sizeof(wfx));
605 wfx.wFormatTag = WAVE_FORMAT_PCM;
606 wfx.nChannels = 2;
607 wfx.nSamplesPerSec = 44100 / soundQuality;
608 wfx.wBitsPerSample = 16;
609 wfx.nBlockAlign = (wfx.wBitsPerSample / 8) * wfx.nChannels;
610 wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
611 wfx.cbSize = 0;
612 theApp.aviRecorder->SetSoundFormat(&wfx);
613 }
614 theApp.aviRecorder->AddSound((u8 *)soundFrameSound, soundFrameSoundWritten * 2);
615 }
616 }
617
618 soundFrameSoundWritten = 0;
619
620 // no more stupid updates :)
621
622 extern int quitAfterTime; // from VBA.cpp
623 void VBAMovieStop(bool8 suppress_message); // from ../movie.cpp
624 if (quitAfterTime >= 0 && systemCounters.frameCount == quitAfterTime)
625 {
626 VBAMovieStop(true);
627 AfxPostQuitMessage(0);
628 }
629
630 // change the sound speed, or set it to normal - must always do this or it won't get reset after a change, but that's OK
631 // because it's inexpensive
632 if (theApp.sound)
633 {
634 theApp.sound->setSpeed(
635 speedup || theApp.winPauseNextFrame || !synchronize || theApp.accuratePitchThrottle || theApp.useOldSync
636 ? 1.0f : (float)theApp.throttle / 100.0f);
637 }
638
639 // if a throttle speed is set and we're not allowed to change the sound frequency to achieve it,
640 // sleep for a certain amount each time we get here to approximate the necessary slowdown
641 if (synchronize && (theApp.accuratePitchThrottle || !theApp.sound || theApp.throttle < 6) /*&& !theApp.winPauseNextFrame*/)
642 {
643 /// FIXME: this is still a horrible way of achieving a certain frame time
644 /// (look at what Snes9x does - it's complicated but much much better)
645
646 static float sleepAmt = 0.0f; // variable to smooth out the sleeping amount so it doesn't oscillate so fast
647 // if(!theApp.wasPaused) {
648 if (!speedup)
649 {
650 u32 time = systemGetClock();
651 u32 diff = time - theApp.throttleLastTime;
652 if (theApp.wasPaused)
653 diff = 0;
654
655 int target = (100000 / (60 * theApp.throttle));
656 int d = (target - diff);
657
658 if (d > 1000) // added to avoid 500-day waits for vba to start emulating.
659 d = 1000; // I suspect most users aren't that patient, and would find 1 second to be a more reasonable delay.
660
661 sleepAmt = 0.8f * sleepAmt + 0.2f * (float)d;
662 if (d - sleepAmt <= 1.5f && d - sleepAmt >= -1.5f)
663 d = (int)(sleepAmt);
664
665 if (d > 0)
666 {
667 Sleep(d);
668 }
669 }
670 theApp.throttleLastTime = systemGetClock();
671 //}
672 //else
673 //{
674 // Sleep(100);
675 //}
676 }
677
678 if (systemCounters.frameCount % 10 == 0)
679 {
680 if (theApp.rewindMemory)
681 {
682 if (++theApp.rewindCounter >= (theApp.rewindTimer))
683 {
684 theApp.rewindSaveNeeded = true;
685 theApp.rewindCounter = 0;
686 }
687 }
688 if (systemSaveUpdateCounter)
689 {
690 if (--systemSaveUpdateCounter <= SYSTEM_SAVE_NOT_UPDATED)
691 {
692 winWriteBatteryFile();
693 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
694 }
695 }
696 }
697
698 theApp.wasPaused = false;
699 /// theApp.autoFrameSkipLastTime = time;
700 }
701
702 int systemFramesToSkip()
703 {
704 int framesToSkip = systemFrameSkip;
705
706 bool fastForward = speedup;
707
708 #if (defined(WIN32) && !defined(SDL))
709 fastForward = (fastForward || theApp.frameSearchSkipping);
710 int throttle = theApp.throttle;
711 if (theApp.frameSearching && throttle < 100)
712 throttle = 100;
713 #else
714 extern int throttle;
715 #endif
716
717 #if (defined(WIN32) && !defined(SDL))
718 if (theApp.aviRecording || theApp.nvVideoLog)
719 {
720 framesToSkip = 0; // render all frames
721 }
722 else
723 {
724 if (fastForward)
725 framesToSkip = 9; // try 6 FPS during speedup
726 else if (throttle != 100)
727 framesToSkip = (framesToSkip * throttle) / 100;
728 }
729 #endif
730
731 return framesToSkip;
732 }
733
734 // sound
735
736 bool systemSoundInit()
737 {
738 if (theApp.sound)
739 delete theApp.sound;
740
741 extern ISound *newDirectSound();
742 theApp.sound = newDirectSound();
743 return theApp.sound->init();
744 }
745
746 void systemSoundShutdown()
747 {
748 if (theApp.sound)
749 delete theApp.sound;
750 theApp.sound = NULL;
751 }
752
753 void systemSoundPause()
754 {
755 if (theApp.sound)
756 theApp.sound->pause();
757 soundPaused = 1;
758 }
759
760 void systemSoundResume()
761 {
762 if (theApp.sound)
763 theApp.sound->resume();
764 soundPaused = 0;
765 }
766
767 bool systemSoundIsPaused()
768 {
769 // return soundPaused;
770 return !(theApp.sound && theApp.sound->isPlaying());
771 }
772
773 void systemSoundClearBuffer()
774 {
775 if (theApp.sound)
776 theApp.sound->clearAudioBuffer();
777 }
778
779 void systemSoundReset()
780 {
781 if (theApp.sound)
782 theApp.sound->reset();
783 }
784
785 void systemSoundWriteToBuffer()
786 {
787 if (theApp.sound)
788 theApp.sound->write();
789 }
790
791 bool systemSoundCanChangeQuality()
792 {
793 return true;
794 }
795
796 bool systemSoundSetQuality(int quality)
797 {
798 if (systemCartridgeType == 0)
799 soundSetQuality(quality);
800 else
801 gbSoundSetQuality(quality);
802
803 return true;
804 }
805
806 // emulation
807
808 bool systemIsEmulating()
809 {
810 return emulating != 0;
811 }
812
813 void systemGbBorderOn()
814 {
815 if (vbaShuttingDown)
816 return;
817
818 if (emulating && systemCartridgeType == 1)
819 {
820 theApp.updateWindowSize(theApp.videoOption);
821 }
822 }
823
824 bool systemIsRunningGBA()
825 {
826 return (systemCartridgeType == 0);
827 }
828
829 bool systemIsSpedUp()
830 {
831 return theApp.speedupToggle;
832 }
833
834 bool systemIsPaused()
835 {
836 return theApp.paused;
837 }
838
839 void systemSetPause(bool pause)
840 {
841 if (pause)
842 {
843 capturePrevious = false;
844 theApp.wasPaused = true;
845 theApp.paused = true;
846 theApp.speedupToggle = false;
847 theApp.winPauseNextFrame = false;
848 systemSoundPause();
849 systemRefreshScreen();;
850 }
851 else
852 {
853 theApp.paused = false;
854 systemSoundResume();
855 }
856 }
857
858 // aka. frame advance
859 bool systemPauseOnFrame()
860 {
861 if (theApp.winPauseNextFrame)
862 {
863 if (!theApp.nextframeAccountForLag || !systemCounters.laggedLast)
864 {
865 theApp.winPauseNextFrame = false;
866 return true;
867 }
868 }
869
870 return false;
871 }
872
873 bool systemLoadBIOS(const char *biosFileName, bool useBiosFile)
874 {
875 bool use = false;
876 if (systemCartridgeType == 0)
877 use = CPULoadBios(biosFileName, useBiosFile);
878 else
879 use = false;
880 return use;
881 }
882
883 // FIXME: now platform-independant stuff
884 // it should be admitted that the naming schema/code organization is a whole mess
885 // these things should be moved somewhere else
886
887 EmulatedSystemCounters systemCounters =
888 {
889 // frameCount
890 0,
891 // lagCount
892 0,
893 // extraCount
894 0,
895 // lagged
896 true,
897 // laggedLast
898 true,
899 };
900
901 // VBAxyz stuff are not part of the core.
902
903 void VBAOnEnteringFrameBoundary()
904 {
905 CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION);
906
907 if (VBALuaRunning())
908 {
909 VBALuaFrameBoundary();
910 }
911
912 VBAMovieUpdateState();
913 }
914
915 void VBAOnExitingFrameBoundary()
916 {
917 ;
918 }
919
920 //////////////////////////////////////////////
921 // ultility
922
923 extern void toolsLog(const char *);
924
925 void log(const char *msg, ...)
926 {
927 CString buffer;
928 va_list valist;
929
930 va_start(valist, msg);
931 buffer.FormatV(msg, valist);
932
933 toolsLog(buffer);
934
935 va_end(valist);
936 }