Mercurial > vba-clojure
diff 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 |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/win32/System.cpp Sat Mar 03 10:31:27 2012 -0600 1.3 @@ -0,0 +1,936 @@ 1.4 +// System.cpp : Defines the system behaviors for the emulator. 1.5 +// 1.6 +#include "stdafx.h" 1.7 +#include "Sound.h" 1.8 +#include "Input.h" 1.9 +#include "IUpdate.h" 1.10 +#include "ram_search.h" 1.11 +#include "WinMiscUtil.h" 1.12 +#include "WinResUtil.h" 1.13 +#include "resource.h" 1.14 +#include "VBA.h" 1.15 +#include "../gba/GBA.h" 1.16 +#include "../gba/GBAGlobals.h" 1.17 +#include "../gba/GBASound.h" 1.18 +#include "../gb/GB.h" 1.19 +#include "../gb/gbGlobals.h" 1.20 +//#include "../common/System.h" 1.21 +#include "../common/movie.h" 1.22 +#include "../common/vbalua.h" 1.23 +#include "../common/Text.h" 1.24 +#include "../common/Util.h" 1.25 +#include "../common/nesvideos-piece.h" 1.26 +#include "../version.h" 1.27 +#include <cassert> 1.28 + 1.29 +struct EmulatedSystem theEmulator; 1.30 + 1.31 +u32 RGB_LOW_BITS_MASK = 0; 1.32 +int emulating = 0; 1.33 +int systemCartridgeType = 0; 1.34 +int systemSpeed = 0; 1.35 +bool systemSoundOn = false; 1.36 +u32 systemColorMap32[0x10000]; 1.37 +u16 systemColorMap16[0x10000]; 1.38 +u16 systemGbPalette[24]; 1.39 +int systemRedShift = 0; 1.40 +int systemBlueShift = 0; 1.41 +int systemGreenShift = 0; 1.42 +int systemColorDepth = 16; 1.43 +int systemDebug = 0; 1.44 +int systemVerbose = 0; 1.45 +int systemFrameSkip = 0; 1.46 +int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 1.47 + 1.48 +const int32 INITIAL_SENSOR_VALUE = 2047; 1.49 + 1.50 +int32 sensorX = INITIAL_SENSOR_VALUE; 1.51 +int32 sensorY = INITIAL_SENSOR_VALUE; 1.52 +u16 currentButtons [4] = { 0, 0, 0, 0 }; // constrain: never contains hacked buttons, only the lower 16 bits of each are used 1.53 +u16 lastKeys = 0; 1.54 + 1.55 +// static_assertion that BUTTON_REGULAR_RECORDING_MASK should be an u16 constant 1.56 +namespace { const void * const s_STATIC_ASSERTION_(static_cast<void *>(BUTTON_REGULAR_RECORDING_MASK & 0xFFFF0000)); } 1.57 + 1.58 +#define BMP_BUFFER_MAX_WIDTH (256) 1.59 +#define BMP_BUFFER_MAX_HEIGHT (224) 1.60 +#define BMP_BUFFER_MAX_DEPTH (4) 1.61 +static u8 bmpBuffer[BMP_BUFFER_MAX_WIDTH * BMP_BUFFER_MAX_HEIGHT * BMP_BUFFER_MAX_DEPTH]; 1.62 + 1.63 +static int s_stockThrottleValues[] = { 1.64 + 6, 15, 25, 25, 37, 50, 75, 87, 100, 112, 125, 150, 200, 300, 400, 600, 800, 1000 1.65 +}; 1.66 + 1.67 +// systemXYZ: Win32 stuff 1.68 + 1.69 +// input 1.70 + 1.71 +void systemSetSensorX(int32 x) 1.72 +{ 1.73 + sensorX = x; 1.74 +} 1.75 + 1.76 +void systemSetSensorY(int32 y) 1.77 +{ 1.78 + sensorY = y; 1.79 +} 1.80 + 1.81 +void systemResetSensor() 1.82 +{ 1.83 + sensorX = sensorY = INITIAL_SENSOR_VALUE; 1.84 +} 1.85 + 1.86 +int32 systemGetSensorX() 1.87 +{ 1.88 + return sensorX; 1.89 +} 1.90 + 1.91 +int32 systemGetSensorY() 1.92 +{ 1.93 + return sensorY; 1.94 +} 1.95 + 1.96 +// handles motion sensor input 1.97 +void systemUpdateMotionSensor(int i) 1.98 +{ 1.99 + if (i < 0 || i > 3) 1.100 + i = 0; 1.101 + 1.102 + if (currentButtons[i] & BUTTON_MASK_LEFT_MOTION) 1.103 + { 1.104 + sensorX += 3; 1.105 + if (sensorX > 2197) 1.106 + sensorX = 2197; 1.107 + if (sensorX < 2047) 1.108 + sensorX = 2057; 1.109 + } 1.110 + else if (currentButtons[i] & BUTTON_MASK_RIGHT_MOTION) 1.111 + { 1.112 + sensorX -= 3; 1.113 + if (sensorX < 1897) 1.114 + sensorX = 1897; 1.115 + if (sensorX > 2047) 1.116 + sensorX = 2037; 1.117 + } 1.118 + else if (sensorX > 2047) 1.119 + { 1.120 + sensorX -= 2; 1.121 + if (sensorX < 2047) 1.122 + sensorX = 2047; 1.123 + } 1.124 + else 1.125 + { 1.126 + sensorX += 2; 1.127 + if (sensorX > 2047) 1.128 + sensorX = 2047; 1.129 + } 1.130 + 1.131 + if (currentButtons[i] & BUTTON_MASK_UP_MOTION) 1.132 + { 1.133 + sensorY += 3; 1.134 + if (sensorY > 2197) 1.135 + sensorY = 2197; 1.136 + if (sensorY < 2047) 1.137 + sensorY = 2057; 1.138 + } 1.139 + else if (currentButtons[i] & BUTTON_MASK_DOWN_MOTION) 1.140 + { 1.141 + sensorY -= 3; 1.142 + if (sensorY < 1897) 1.143 + sensorY = 1897; 1.144 + if (sensorY > 2047) 1.145 + sensorY = 2037; 1.146 + } 1.147 + else if (sensorY > 2047) 1.148 + { 1.149 + sensorY -= 2; 1.150 + if (sensorY < 2047) 1.151 + sensorY = 2047; 1.152 + } 1.153 + else 1.154 + { 1.155 + sensorY += 2; 1.156 + if (sensorY > 2047) 1.157 + sensorY = 2047; 1.158 + } 1.159 +} 1.160 + 1.161 +int systemGetDefaultJoypad() 1.162 +{ 1.163 + return theApp.joypadDefault; 1.164 +} 1.165 + 1.166 +void systemSetDefaultJoypad(int which) 1.167 +{ 1.168 + theApp.joypadDefault = which; 1.169 +} 1.170 + 1.171 +bool systemReadJoypads() 1.172 +{ 1.173 + // this function is called at every frame, even if vba is fast-forwarded. 1.174 + // so we try to limit the input frequency here just in case. 1.175 + static u32 lastTime = systemGetClock(); 1.176 + if ((u32)(systemGetClock() - lastTime) < 10) 1.177 + return false; 1.178 + lastTime = systemGetClock(); 1.179 + 1.180 + if (theApp.input) 1.181 + return theApp.input->readDevices(); 1.182 + return false; 1.183 +} 1.184 + 1.185 +u32 systemGetOriginalJoypad(int i, bool sensor) 1.186 +{ 1.187 + if (i < 0 || i > 3) 1.188 + i = 0; 1.189 + 1.190 + u32 res = 0; 1.191 + if (theApp.input) 1.192 + res = theApp.input->readDevice(i, sensor); 1.193 + 1.194 + // +auto input, XOR 1.195 + // maybe these should be moved into DirectInput.cpp 1.196 + if (theApp.autoFire || theApp.autoFire2) 1.197 + { 1.198 + res ^= (theApp.autoFireToggle ? theApp.autoFire : theApp.autoFire2); 1.199 + if (!theApp.autofireAccountForLag || !systemCounters.laggedLast) 1.200 + { 1.201 + theApp.autoFireToggle = !theApp.autoFireToggle; 1.202 + } 1.203 + } 1.204 + if (theApp.autoHold) 1.205 + { 1.206 + res ^= theApp.autoHold; 1.207 + } 1.208 + 1.209 + // filter buttons 1.210 + // maybe better elsewhere? 1.211 + if (!theApp.allowLeftRight) 1.212 + { 1.213 + // disallow L+R or U+D to being pressed at the same time 1.214 + if ((res & (BUTTON_MASK_RIGHT | BUTTON_MASK_LEFT)) == (BUTTON_MASK_RIGHT | BUTTON_MASK_LEFT)) 1.215 + res &= ~BUTTON_MASK_RIGHT; // leave only LEFT on 1.216 + if ((res & (BUTTON_MASK_DOWN | BUTTON_MASK_UP)) == (BUTTON_MASK_DOWN | BUTTON_MASK_UP)) 1.217 + res &= ~BUTTON_MASK_DOWN; // leave only UP on 1.218 + } 1.219 + 1.220 + if (!sensor) 1.221 + { 1.222 + if (res & BUTTON_MOTION_MASK) 1.223 + res &= ~BUTTON_MOTION_MASK; 1.224 + } 1.225 + 1.226 + if (systemCartridgeType != 0 && !gbSgbMode) // regular GB has no L/R buttons 1.227 + { 1.228 + if (res & (BUTTON_GBA_ONLY)) 1.229 + res &= ~BUTTON_GBA_ONLY; 1.230 + } 1.231 + 1.232 + currentButtons[i] = res & BUTTON_REGULAR_RECORDING_MASK; 1.233 + 1.234 + return res; 1.235 +} 1.236 + 1.237 +u32 systemGetJoypad(int i, bool sensor) 1.238 +{ 1.239 + if (i < 0 || i > 3) 1.240 + i = 0; 1.241 + 1.242 + // input priority: original+auto < Lua < frame search < movie, correct this if wrong 1.243 + 1.244 + // get original+auto input 1.245 + u32 hackedButtons = systemGetOriginalJoypad(i, sensor) & BUTTON_NONRECORDINGONLY_MASK; 1.246 + u32 res = currentButtons[i]; 1.247 + 1.248 + // since movie input has the highest priority, there's no point to read from other input 1.249 + if (VBAMoviePlaying()) 1.250 + { 1.251 + // VBAMovieRead() overwrites currentButtons[i] 1.252 + VBAMovieRead(i, sensor); 1.253 + res = currentButtons[i]; 1.254 + } 1.255 + else 1.256 + { 1.257 + // Lua input, shouldn't have any side effect within them 1.258 + if (VBALuaUsingJoypad(i)) 1.259 + res = VBALuaReadJoypad(i); 1.260 + 1.261 + // override input above 1.262 + if (theApp.frameSearchSkipping) 1.263 + res = theApp.frameSearchOldInput[i]; 1.264 + 1.265 + // flush non-hack buttons into the "current buttons" input buffer, which will be read by the movie routine 1.266 + currentButtons[i] = res & BUTTON_REGULAR_RECORDING_MASK; 1.267 + VBAMovieWrite(i, sensor); 1.268 + } 1.269 + 1.270 + return res | hackedButtons; 1.271 +} 1.272 + 1.273 +void systemSetJoypad(int which, u32 buttons) 1.274 +{ 1.275 + if (which < 0 || which > 3) 1.276 + which = 0; 1.277 + 1.278 + currentButtons[which] = buttons; 1.279 + 1.280 + lastKeys = 0; 1.281 +} 1.282 + 1.283 +void systemClearJoypads() 1.284 +{ 1.285 + for (int i = 0; i < 3; ++i) 1.286 + currentButtons[i] = 0; 1.287 + 1.288 + lastKeys = 0; 1.289 +} 1.290 + 1.291 +// screen 1.292 + 1.293 +// delayed repaint 1.294 +void systemRefreshScreen() 1.295 +{ 1.296 + if (theApp.m_pMainWnd) 1.297 + { 1.298 + theApp.m_pMainWnd->PostMessage(WM_PAINT, NULL, NULL); 1.299 + } 1.300 +} 1.301 + 1.302 +extern bool vbaShuttingDown; 1.303 + 1.304 +void systemRenderFrame() 1.305 +{ 1.306 + extern long linearSoundFrameCount; 1.307 + extern long linearFrameCount; 1.308 + 1.309 + if (vbaShuttingDown) 1.310 + return; 1.311 + 1.312 + ++theApp.renderedFrames; 1.313 + 1.314 + VBAUpdateFrameCountDisplay(); 1.315 + VBAUpdateButtonPressDisplay(); 1.316 + 1.317 + // "in-game" text rendering 1.318 + if (textMethod == 0) // transparent text can only be painted once, so timed messages will not be updated 1.319 + { 1.320 + extern void DrawLuaGui(); 1.321 + DrawLuaGui(); 1.322 + 1.323 + int copyX = 240, copyY = 160; 1.324 + if (systemCartridgeType == 1) 1.325 + if (gbBorderOn) 1.326 + copyX = 256, copyY = 224; 1.327 + else 1.328 + copyX = 160, copyY = 144; 1.329 + int pitch = copyX * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4); // FIXME: sure? 1.330 + 1.331 + DrawTextMessages((u8 *)pix, pitch, 0, copyY); 1.332 + } 1.333 + 1.334 + ++linearFrameCount; 1.335 + if (!theApp.sound) 1.336 + { 1.337 + if (linearFrameCount > 10000) 1.338 + linearFrameCount -= 10000; 1.339 + linearSoundFrameCount = linearFrameCount; 1.340 + } 1.341 + 1.342 + // record avi 1.343 + int width = 240; 1.344 + int height = 160; 1.345 + switch (systemCartridgeType) 1.346 + { 1.347 + case 0: 1.348 + width = 240; 1.349 + height = 160; 1.350 + break; 1.351 + case 1: 1.352 + if (gbBorderOn) 1.353 + { 1.354 + width = 256; 1.355 + height = 224; 1.356 + } 1.357 + else 1.358 + { 1.359 + width = 160; 1.360 + height = 144; 1.361 + } 1.362 + break; 1.363 + } 1.364 + 1.365 + bool firstFrameLogged = false; 1.366 + --linearFrameCount; 1.367 + do 1.368 + { 1.369 + ++linearFrameCount; 1.370 + 1.371 + if (theApp.aviRecording && (!theApp.altAviRecordMethod || (theApp.altAviRecordMethod && !firstFrameLogged))) 1.372 + { 1.373 + // usually aviRecorder is created when vba starts avi recording, though 1.374 + if (theApp.aviRecorder == NULL) 1.375 + { 1.376 + theApp.aviRecorder = new AVIWrite(); 1.377 + 1.378 + theApp.aviRecorder->SetFPS(60); 1.379 + 1.380 + BITMAPINFOHEADER bi; 1.381 + memset(&bi, 0, sizeof(bi)); 1.382 + bi.biSize = 0x28; 1.383 + bi.biPlanes = 1; 1.384 + bi.biBitCount = 24; 1.385 + bi.biWidth = width; 1.386 + bi.biHeight = height; 1.387 + bi.biSizeImage = 3 * width * height; 1.388 + theApp.aviRecorder->SetVideoFormat(&bi); 1.389 + if (!theApp.aviRecorder->Open(theApp.aviRecordName)) 1.390 + { 1.391 + delete theApp.aviRecorder; 1.392 + theApp.aviRecorder = NULL; 1.393 + theApp.aviRecording = false; 1.394 + } 1.395 + } 1.396 + 1.397 + if (theApp.aviRecorder != NULL && !theApp.aviRecorder->IsPaused()) 1.398 + { 1.399 + assert( 1.400 + width <= BMP_BUFFER_MAX_WIDTH && height <= BMP_BUFFER_MAX_HEIGHT && systemColorDepth <= 1.401 + BMP_BUFFER_MAX_DEPTH * 8); 1.402 + utilWriteBMP(bmpBuffer, width, height, systemColorDepth, pix); 1.403 + theApp.aviRecorder->AddFrame(bmpBuffer); 1.404 + } 1.405 + } 1.406 + 1.407 + if (theApp.nvVideoLog) 1.408 + { 1.409 + // convert from whatever bit depth to 16-bit, while stripping away extra pixels 1.410 + assert(width <= BMP_BUFFER_MAX_WIDTH && height <= BMP_BUFFER_MAX_HEIGHT && 16 <= BMP_BUFFER_MAX_DEPTH * 8); 1.411 + utilWriteBMP(bmpBuffer, width, -height, 16, pix); 1.412 + NESVideoLoggingVideo((u8 *)bmpBuffer, width, height, 0x1000000 * 60); 1.413 + } 1.414 + 1.415 + firstFrameLogged = true; 1.416 + } 1.417 + while (linearFrameCount < linearSoundFrameCount); // compensate for frames lost due to frame skip being nonzero, etc. 1.418 + 1.419 + if (textMethod != 0) // do not draw Lua HUD to a video dump 1.420 + { 1.421 + extern void DrawLuaGui(); 1.422 + DrawLuaGui(); 1.423 + } 1.424 + 1.425 + // interframe blending 1.426 + if (theApp.ifbFunction) 1.427 + { 1.428 + if (systemColorDepth == 16) 1.429 + theApp.ifbFunction(pix + theApp.filterWidth * 2 + 4, theApp.filterWidth * 2 + 4, 1.430 + theApp.filterWidth, theApp.filterHeight); 1.431 + else 1.432 + theApp.ifbFunction(pix + theApp.filterWidth * 4 + 4, theApp.filterWidth * 4 + 4, 1.433 + theApp.filterWidth, theApp.filterHeight); 1.434 + } 1.435 + 1.436 + systemRedrawScreen(); 1.437 +} 1.438 + 1.439 +void systemRedrawScreen() 1.440 +{ 1.441 + if (vbaShuttingDown) 1.442 + return; 1.443 + 1.444 + if (theApp.display) 1.445 + theApp.display->render(); 1.446 + 1.447 + systemUpdateListeners(); 1.448 +} 1.449 + 1.450 +void systemUpdateListeners() 1.451 +{ 1.452 + if (vbaShuttingDown) 1.453 + return; 1.454 + 1.455 + Update_RAM_Search(); // updates RAM search and RAM watch 1.456 + 1.457 + // update viewers etc. 1.458 + if (theApp.updateCount) 1.459 + { 1.460 + POSITION pos = theApp.updateList.GetHeadPosition(); 1.461 + while (pos) 1.462 + { 1.463 + IUpdateListener *up = theApp.updateList.GetNext(pos); 1.464 + if (up) 1.465 + up->update(); 1.466 + } 1.467 + } 1.468 +} 1.469 + 1.470 +int systemScreenCapture(int captureNumber) 1.471 +{ 1.472 + return winScreenCapture(captureNumber); 1.473 +} 1.474 + 1.475 +void systemMessage(int number, const char *defaultMsg, ...) 1.476 +{ 1.477 + CString buffer; 1.478 + va_list valist; 1.479 + CString msg = defaultMsg; 1.480 + if (number) 1.481 + msg = winResLoadString(number); 1.482 + 1.483 + va_start(valist, defaultMsg); 1.484 + buffer.FormatV(msg, valist); 1.485 + 1.486 + theApp.winCheckFullscreen(); 1.487 + systemSoundClearBuffer(); 1.488 + AfxGetApp()->m_pMainWnd->MessageBox(buffer, winResLoadString(IDS_ERROR), MB_OK | MB_ICONERROR); 1.489 + 1.490 + va_end(valist); 1.491 +} 1.492 + 1.493 +void systemScreenMessage(const char *msg, int slot, int duration, const char *colorList) 1.494 +{ 1.495 + if (slot < 0 || slot > SCREEN_MESSAGE_SLOTS) 1.496 + return; 1.497 + 1.498 + theApp.screenMessage[slot] = true; 1.499 + theApp.screenMessageTime[slot] = GetTickCount(); 1.500 + theApp.screenMessageDuration[slot] = duration; 1.501 + theApp.screenMessageBuffer[slot] = msg; 1.502 + theApp.screenMessageColorBuffer[slot] = colorList ? colorList : ""; 1.503 + 1.504 + if (theApp.screenMessageBuffer[slot].GetLength() > 40) 1.505 + theApp.screenMessageBuffer[slot] = theApp.screenMessageBuffer[slot].Left(40); 1.506 + 1.507 + // update the display when a main slot message appears while the game is paused 1.508 + if (slot == 0 && (theApp.paused || (theApp.frameSearching))) 1.509 + systemRefreshScreen(); 1.510 +} 1.511 + 1.512 +void systemShowSpeed(int speed) 1.513 +{ 1.514 + systemSpeed = speed; 1.515 + theApp.showRenderedFrames = theApp.renderedFrames; 1.516 + theApp.renderedFrames = 0; 1.517 + if (theApp.videoOption <= VIDEO_4X && theApp.showSpeed) 1.518 + { 1.519 + CString buffer; 1.520 + if (theApp.showSpeed == 1) 1.521 + buffer.Format(VBA_NAME_AND_VERSION " %3d%%", systemSpeed); 1.522 + else 1.523 + buffer.Format(VBA_NAME_AND_VERSION " %3d%% (%d fps | %d skipped)", 1.524 + systemSpeed, 1.525 + theApp.showRenderedFrames, 1.526 + systemFrameSkip); 1.527 + 1.528 + systemSetTitle(buffer); 1.529 + } 1.530 +} 1.531 + 1.532 +void systemSetTitle(const char *title) 1.533 +{ 1.534 + if (theApp.m_pMainWnd != NULL) 1.535 + { 1.536 + AfxGetApp()->m_pMainWnd->SetWindowText(title); 1.537 + } 1.538 +} 1.539 + 1.540 +// timing/speed 1.541 + 1.542 +u32 systemGetClock() 1.543 +{ 1.544 + return timeGetTime(); 1.545 +} 1.546 + 1.547 +void systemIncreaseThrottle() 1.548 +{ 1.549 + int throttle = theApp.throttle; 1.550 + 1.551 + if (throttle < 6) 1.552 + ++throttle; 1.553 + else if (throttle < s_stockThrottleValues[_countof(s_stockThrottleValues) - 1]) 1.554 + { 1.555 + int i = 0; 1.556 + while (throttle >= s_stockThrottleValues[i]) 1.557 + { 1.558 + ++i; 1.559 + } 1.560 + throttle = s_stockThrottleValues[i]; 1.561 + } 1.562 + 1.563 + systemSetThrottle(throttle); 1.564 +} 1.565 + 1.566 +void systemDecreaseThrottle() 1.567 +{ 1.568 + int throttle = theApp.throttle; 1.569 + 1.570 + if (throttle > 6) 1.571 + { 1.572 + int i = _countof(s_stockThrottleValues) - 1; 1.573 + while (throttle <= s_stockThrottleValues[i]) 1.574 + { 1.575 + --i; 1.576 + } 1.577 + throttle = s_stockThrottleValues[i]; 1.578 + } 1.579 + else if (throttle > 1) 1.580 + --throttle; 1.581 + 1.582 + systemSetThrottle(throttle); 1.583 +} 1.584 + 1.585 +void systemSetThrottle(int throttle) 1.586 +{ 1.587 + theApp.throttle = throttle; 1.588 + char str[256]; 1.589 + sprintf(str, "%d%% throttle speed", theApp.throttle); 1.590 + systemScreenMessage(str); 1.591 +} 1.592 + 1.593 +int systemGetThrottle() 1.594 +{ 1.595 + return theApp.throttle; 1.596 +} 1.597 + 1.598 +void systemFrame() 1.599 +{ 1.600 + if (theApp.altAviRecordMethod && theApp.aviRecording) 1.601 + { 1.602 + if (theApp.aviRecorder) 1.603 + { 1.604 + if (!theApp.aviRecorder->IsSoundAdded()) 1.605 + { 1.606 + WAVEFORMATEX wfx; 1.607 + memset(&wfx, 0, sizeof(wfx)); 1.608 + wfx.wFormatTag = WAVE_FORMAT_PCM; 1.609 + wfx.nChannels = 2; 1.610 + wfx.nSamplesPerSec = 44100 / soundQuality; 1.611 + wfx.wBitsPerSample = 16; 1.612 + wfx.nBlockAlign = (wfx.wBitsPerSample / 8) * wfx.nChannels; 1.613 + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; 1.614 + wfx.cbSize = 0; 1.615 + theApp.aviRecorder->SetSoundFormat(&wfx); 1.616 + } 1.617 + theApp.aviRecorder->AddSound((u8 *)soundFrameSound, soundFrameSoundWritten * 2); 1.618 + } 1.619 + } 1.620 + 1.621 + soundFrameSoundWritten = 0; 1.622 + 1.623 + // no more stupid updates :) 1.624 + 1.625 + extern int quitAfterTime; // from VBA.cpp 1.626 + void VBAMovieStop(bool8 suppress_message); // from ../movie.cpp 1.627 + if (quitAfterTime >= 0 && systemCounters.frameCount == quitAfterTime) 1.628 + { 1.629 + VBAMovieStop(true); 1.630 + AfxPostQuitMessage(0); 1.631 + } 1.632 + 1.633 + // 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 1.634 + // because it's inexpensive 1.635 + if (theApp.sound) 1.636 + { 1.637 + theApp.sound->setSpeed( 1.638 + speedup || theApp.winPauseNextFrame || !synchronize || theApp.accuratePitchThrottle || theApp.useOldSync 1.639 + ? 1.0f : (float)theApp.throttle / 100.0f); 1.640 + } 1.641 + 1.642 + // if a throttle speed is set and we're not allowed to change the sound frequency to achieve it, 1.643 + // sleep for a certain amount each time we get here to approximate the necessary slowdown 1.644 + if (synchronize && (theApp.accuratePitchThrottle || !theApp.sound || theApp.throttle < 6) /*&& !theApp.winPauseNextFrame*/) 1.645 + { 1.646 + /// FIXME: this is still a horrible way of achieving a certain frame time 1.647 + /// (look at what Snes9x does - it's complicated but much much better) 1.648 + 1.649 + static float sleepAmt = 0.0f; // variable to smooth out the sleeping amount so it doesn't oscillate so fast 1.650 +// if(!theApp.wasPaused) { 1.651 + if (!speedup) 1.652 + { 1.653 + u32 time = systemGetClock(); 1.654 + u32 diff = time - theApp.throttleLastTime; 1.655 + if (theApp.wasPaused) 1.656 + diff = 0; 1.657 + 1.658 + int target = (100000 / (60 * theApp.throttle)); 1.659 + int d = (target - diff); 1.660 + 1.661 + if (d > 1000) // added to avoid 500-day waits for vba to start emulating. 1.662 + d = 1000; // I suspect most users aren't that patient, and would find 1 second to be a more reasonable delay. 1.663 + 1.664 + sleepAmt = 0.8f * sleepAmt + 0.2f * (float)d; 1.665 + if (d - sleepAmt <= 1.5f && d - sleepAmt >= -1.5f) 1.666 + d = (int)(sleepAmt); 1.667 + 1.668 + if (d > 0) 1.669 + { 1.670 + Sleep(d); 1.671 + } 1.672 + } 1.673 + theApp.throttleLastTime = systemGetClock(); 1.674 + //} 1.675 + //else 1.676 + //{ 1.677 + // Sleep(100); 1.678 + //} 1.679 + } 1.680 + 1.681 + if (systemCounters.frameCount % 10 == 0) 1.682 + { 1.683 + if (theApp.rewindMemory) 1.684 + { 1.685 + if (++theApp.rewindCounter >= (theApp.rewindTimer)) 1.686 + { 1.687 + theApp.rewindSaveNeeded = true; 1.688 + theApp.rewindCounter = 0; 1.689 + } 1.690 + } 1.691 + if (systemSaveUpdateCounter) 1.692 + { 1.693 + if (--systemSaveUpdateCounter <= SYSTEM_SAVE_NOT_UPDATED) 1.694 + { 1.695 + winWriteBatteryFile(); 1.696 + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 1.697 + } 1.698 + } 1.699 + } 1.700 + 1.701 + theApp.wasPaused = false; 1.702 +/// theApp.autoFrameSkipLastTime = time; 1.703 +} 1.704 + 1.705 +int systemFramesToSkip() 1.706 +{ 1.707 + int framesToSkip = systemFrameSkip; 1.708 + 1.709 + bool fastForward = speedup; 1.710 + 1.711 +#if (defined(WIN32) && !defined(SDL)) 1.712 + fastForward = (fastForward || theApp.frameSearchSkipping); 1.713 + int throttle = theApp.throttle; 1.714 + if (theApp.frameSearching && throttle < 100) 1.715 + throttle = 100; 1.716 +#else 1.717 + extern int throttle; 1.718 +#endif 1.719 + 1.720 +#if (defined(WIN32) && !defined(SDL)) 1.721 + if (theApp.aviRecording || theApp.nvVideoLog) 1.722 + { 1.723 + framesToSkip = 0; // render all frames 1.724 + } 1.725 + else 1.726 + { 1.727 + if (fastForward) 1.728 + framesToSkip = 9; // try 6 FPS during speedup 1.729 + else if (throttle != 100) 1.730 + framesToSkip = (framesToSkip * throttle) / 100; 1.731 + } 1.732 +#endif 1.733 + 1.734 + return framesToSkip; 1.735 +} 1.736 + 1.737 +// sound 1.738 + 1.739 +bool systemSoundInit() 1.740 +{ 1.741 + if (theApp.sound) 1.742 + delete theApp.sound; 1.743 + 1.744 + extern ISound *newDirectSound(); 1.745 + theApp.sound = newDirectSound(); 1.746 + return theApp.sound->init(); 1.747 +} 1.748 + 1.749 +void systemSoundShutdown() 1.750 +{ 1.751 + if (theApp.sound) 1.752 + delete theApp.sound; 1.753 + theApp.sound = NULL; 1.754 +} 1.755 + 1.756 +void systemSoundPause() 1.757 +{ 1.758 + if (theApp.sound) 1.759 + theApp.sound->pause(); 1.760 + soundPaused = 1; 1.761 +} 1.762 + 1.763 +void systemSoundResume() 1.764 +{ 1.765 + if (theApp.sound) 1.766 + theApp.sound->resume(); 1.767 + soundPaused = 0; 1.768 +} 1.769 + 1.770 +bool systemSoundIsPaused() 1.771 +{ 1.772 +// return soundPaused; 1.773 + return !(theApp.sound && theApp.sound->isPlaying()); 1.774 +} 1.775 + 1.776 +void systemSoundClearBuffer() 1.777 +{ 1.778 + if (theApp.sound) 1.779 + theApp.sound->clearAudioBuffer(); 1.780 +} 1.781 + 1.782 +void systemSoundReset() 1.783 +{ 1.784 + if (theApp.sound) 1.785 + theApp.sound->reset(); 1.786 +} 1.787 + 1.788 +void systemSoundWriteToBuffer() 1.789 +{ 1.790 + if (theApp.sound) 1.791 + theApp.sound->write(); 1.792 +} 1.793 + 1.794 +bool systemSoundCanChangeQuality() 1.795 +{ 1.796 + return true; 1.797 +} 1.798 + 1.799 +bool systemSoundSetQuality(int quality) 1.800 +{ 1.801 + if (systemCartridgeType == 0) 1.802 + soundSetQuality(quality); 1.803 + else 1.804 + gbSoundSetQuality(quality); 1.805 + 1.806 + return true; 1.807 +} 1.808 + 1.809 +// emulation 1.810 + 1.811 +bool systemIsEmulating() 1.812 +{ 1.813 + return emulating != 0; 1.814 +} 1.815 + 1.816 +void systemGbBorderOn() 1.817 +{ 1.818 + if (vbaShuttingDown) 1.819 + return; 1.820 + 1.821 + if (emulating && systemCartridgeType == 1) 1.822 + { 1.823 + theApp.updateWindowSize(theApp.videoOption); 1.824 + } 1.825 +} 1.826 + 1.827 +bool systemIsRunningGBA() 1.828 +{ 1.829 + return (systemCartridgeType == 0); 1.830 +} 1.831 + 1.832 +bool systemIsSpedUp() 1.833 +{ 1.834 + return theApp.speedupToggle; 1.835 +} 1.836 + 1.837 +bool systemIsPaused() 1.838 +{ 1.839 + return theApp.paused; 1.840 +} 1.841 + 1.842 +void systemSetPause(bool pause) 1.843 +{ 1.844 + if (pause) 1.845 + { 1.846 + capturePrevious = false; 1.847 + theApp.wasPaused = true; 1.848 + theApp.paused = true; 1.849 + theApp.speedupToggle = false; 1.850 + theApp.winPauseNextFrame = false; 1.851 + systemSoundPause(); 1.852 + systemRefreshScreen();; 1.853 + } 1.854 + else 1.855 + { 1.856 + theApp.paused = false; 1.857 + systemSoundResume(); 1.858 + } 1.859 +} 1.860 + 1.861 +// aka. frame advance 1.862 +bool systemPauseOnFrame() 1.863 +{ 1.864 + if (theApp.winPauseNextFrame) 1.865 + { 1.866 + if (!theApp.nextframeAccountForLag || !systemCounters.laggedLast) 1.867 + { 1.868 + theApp.winPauseNextFrame = false; 1.869 + return true; 1.870 + } 1.871 + } 1.872 + 1.873 + return false; 1.874 +} 1.875 + 1.876 +bool systemLoadBIOS(const char *biosFileName, bool useBiosFile) 1.877 +{ 1.878 + bool use = false; 1.879 + if (systemCartridgeType == 0) 1.880 + use = CPULoadBios(biosFileName, useBiosFile); 1.881 + else 1.882 + use = false; 1.883 + return use; 1.884 +} 1.885 + 1.886 +// FIXME: now platform-independant stuff 1.887 +// it should be admitted that the naming schema/code organization is a whole mess 1.888 +// these things should be moved somewhere else 1.889 + 1.890 +EmulatedSystemCounters systemCounters = 1.891 +{ 1.892 + // frameCount 1.893 + 0, 1.894 + // lagCount 1.895 + 0, 1.896 + // extraCount 1.897 + 0, 1.898 + // lagged 1.899 + true, 1.900 + // laggedLast 1.901 + true, 1.902 +}; 1.903 + 1.904 +// VBAxyz stuff are not part of the core. 1.905 + 1.906 +void VBAOnEnteringFrameBoundary() 1.907 +{ 1.908 + CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION); 1.909 + 1.910 + if (VBALuaRunning()) 1.911 + { 1.912 + VBALuaFrameBoundary(); 1.913 + } 1.914 + 1.915 + VBAMovieUpdateState(); 1.916 +} 1.917 + 1.918 +void VBAOnExitingFrameBoundary() 1.919 +{ 1.920 + ; 1.921 +} 1.922 + 1.923 +////////////////////////////////////////////// 1.924 +// ultility 1.925 + 1.926 +extern void toolsLog(const char *); 1.927 + 1.928 +void log(const char *msg, ...) 1.929 +{ 1.930 + CString buffer; 1.931 + va_list valist; 1.932 + 1.933 + va_start(valist, msg); 1.934 + buffer.FormatV(msg, valist); 1.935 + 1.936 + toolsLog(buffer); 1.937 + 1.938 + va_end(valist); 1.939 +}