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