mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' (early part) into medusa
This commit is contained in:
commit
5e82d97b5b
3
CHANGES
3
CHANGES
|
@ -64,6 +64,8 @@ Bugfixes:
|
|||
- GB Video: Fix SCX timing
|
||||
- GBA Video: Improve sprite cycle counting (fixes mgba.io/i/1126)
|
||||
- GB, GBA Savedata: Fix savestate loading overwriting saves on reset
|
||||
- GBA Video: Make layer disabling work consistently
|
||||
- GB: Fix IRQ disabling on the same T-cycle as an assert
|
||||
Misc:
|
||||
- GBA Timer: Use global cycles for timers
|
||||
- GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722)
|
||||
|
@ -94,6 +96,7 @@ Misc:
|
|||
- FFmpeg: Support lossless h.264 encoding
|
||||
- Feature: Added loading savestates from command line
|
||||
- Qt: Allow pausing game at load (fixes mgba.io/i/1129)
|
||||
- Wii: Move audio handling to callbacks (fixes mgba.io/i/803)
|
||||
|
||||
0.6.3: (2017-04-14)
|
||||
Bugfixes:
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
fail: true
|
11
src/gb/gb.c
11
src/gb/gb.c
|
@ -625,7 +625,11 @@ void GBUpdateIRQs(struct GB* gb) {
|
|||
}
|
||||
gb->cpu->halted = false;
|
||||
|
||||
if (!gb->memory.ime || gb->cpu->irqPending) {
|
||||
if (!gb->memory.ime) {
|
||||
gb->cpu->irqPending = false;
|
||||
return;
|
||||
}
|
||||
if (gb->cpu->irqPending) {
|
||||
return;
|
||||
}
|
||||
LR35902RaiseIRQ(gb->cpu);
|
||||
|
@ -661,12 +665,11 @@ void GBProcessEvents(struct LR35902Core* cpu) {
|
|||
|
||||
void GBSetInterrupts(struct LR35902Core* cpu, bool enable) {
|
||||
struct GB* gb = (struct GB*) cpu->master;
|
||||
mTimingDeschedule(&gb->timing, &gb->eiPending);
|
||||
if (!enable) {
|
||||
gb->memory.ime = enable;
|
||||
mTimingDeschedule(&gb->timing, &gb->eiPending);
|
||||
gb->memory.ime = false;
|
||||
GBUpdateIRQs(gb);
|
||||
} else {
|
||||
mTimingDeschedule(&gb->timing, &gb->eiPending);
|
||||
mTimingSchedule(&gb->timing, &gb->eiPending, 4);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ void GBMBCInit(struct GB* gb) {
|
|||
if (gb->memory.rom) {
|
||||
if (gb->memory.romSize >= 0x8000) {
|
||||
const struct GBCartridge* cartFooter = (const struct GBCartridge*) &gb->memory.rom[gb->memory.romSize - 0x7F00];
|
||||
if (doCrc32(cartFooter->logo, sizeof(cartFooter->logo)) == GB_LOGO_HASH) {
|
||||
if (doCrc32(cartFooter->logo, sizeof(cartFooter->logo)) == GB_LOGO_HASH && cartFooter->type >= 0x0B && cartFooter->type <= 0x0D) {
|
||||
cart = cartFooter;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -524,6 +524,7 @@ void GBADebug(struct GBA* gba, uint16_t flags) {
|
|||
level &= 0x1F;
|
||||
char oolBuf[0x101];
|
||||
strncpy(oolBuf, gba->debugString, sizeof(gba->debugString));
|
||||
memset(gba->debugString, 0, sizeof(gba->debugString));
|
||||
oolBuf[0x100] = '\0';
|
||||
mLog(_mLOG_CAT_GBA_DEBUG(), level, "%s", oolBuf);
|
||||
}
|
||||
|
|
|
@ -9,9 +9,6 @@
|
|||
SPRITE_YBASE_ ## DEPTH(inY); \
|
||||
unsigned tileData; \
|
||||
for (; outX < condition; ++outX, inX += xOffset) { \
|
||||
if (!(renderer->row[outX] & FLAG_UNWRITTEN)) { \
|
||||
continue; \
|
||||
} \
|
||||
renderer->spriteCyclesRemaining -= 1; \
|
||||
SPRITE_XBASE_ ## DEPTH(inX); \
|
||||
SPRITE_DRAW_PIXEL_ ## DEPTH ## _ ## TYPE(inX); \
|
||||
|
|
|
@ -222,7 +222,7 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re
|
|||
}
|
||||
|
||||
#define TEST_LAYER_ENABLED(X) \
|
||||
(softwareRenderer->bg[X].enabled && \
|
||||
(softwareRenderer->bg[X].enabled == 4 && \
|
||||
(GBAWindowControlIsBg ## X ## Enable(softwareRenderer->currentWindow.packed) || \
|
||||
(GBARegisterDISPCNTIsObjwinEnable(softwareRenderer->dispcnt) && GBAWindowControlIsBg ## X ## Enable (softwareRenderer->objwin.packed))) && \
|
||||
softwareRenderer->bg[X].priority == priority)
|
||||
|
|
|
@ -765,7 +765,7 @@ static void GBAVideoSoftwareRendererPutPixels(struct GBAVideoRenderer* renderer,
|
|||
}
|
||||
|
||||
static void _enableBg(struct GBAVideoSoftwareRenderer* renderer, int bg, bool active) {
|
||||
if (renderer->d.disableBG[bg] || !active) {
|
||||
if (!active) {
|
||||
renderer->bg[bg].enabled = 0;
|
||||
} else if (!renderer->bg[bg].enabled && active) {
|
||||
if (renderer->nextY == 0) {
|
||||
|
|
|
@ -137,7 +137,7 @@ static void _LR35902Step(struct LR35902Core* cpu) {
|
|||
}
|
||||
|
||||
void LR35902Tick(struct LR35902Core* cpu) {
|
||||
if (cpu->cycles >= cpu->nextEvent) {
|
||||
while (cpu->cycles >= cpu->nextEvent) {
|
||||
cpu->irqh.processEvents(cpu);
|
||||
}
|
||||
_LR35902Step(cpu);
|
||||
|
|
|
@ -3809,7 +3809,7 @@ Game Boy Advance ist ein eingetragenes Warenzeichen von Nintendo Co., Ltd.</tran
|
|||
<message>
|
||||
<location filename="../Window.cpp" line="1504"/>
|
||||
<source>Open debugger console...</source>
|
||||
<translation>Debugger-Konsole äffnen...</translation>
|
||||
<translation>Debugger-Konsole öffnen...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Window.cpp" line="1510"/>
|
||||
|
|
|
@ -404,7 +404,7 @@ static void _pauseAfterFrame(struct mCoreThread* context) {
|
|||
|
||||
static void _mSDLHandleKeypress(struct mCoreThread* context, struct mSDLPlayer* sdlContext, const struct SDL_KeyboardEvent* event) {
|
||||
int key = -1;
|
||||
if (!event->keysym.mod) {
|
||||
if (!(event->keysym.mod & ~(KMOD_NUM | KMOD_CAPS))) {
|
||||
key = mInputMapKey(sdlContext->bindings, SDL_BINDING_KEY, event->keysym.sym);
|
||||
}
|
||||
if (key != -1) {
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#define TEX_W 256
|
||||
#define TEX_H 224
|
||||
|
||||
#define ANALOG_DEADZONE 0x30
|
||||
|
||||
static void _mapKey(struct mInputMap* map, uint32_t binding, int nativeKey, enum GBAKey key) {
|
||||
mInputBindKey(map, binding, __builtin_ctz(nativeKey), key);
|
||||
}
|
||||
|
@ -67,6 +69,7 @@ static enum VideoMode {
|
|||
|
||||
static void _retraceCallback(u32 count);
|
||||
|
||||
static void _postAudioBuffer(struct mAVStream* stream, blip_t* left, blip_t* right);
|
||||
static void _audioDMA(void);
|
||||
static void _setRumble(struct mRumble* rumble, int enable);
|
||||
static void _sampleRotation(struct mRotationSource* source);
|
||||
|
@ -93,6 +96,7 @@ static s8 WPAD_StickX(u8 chan, u8 right);
|
|||
static s8 WPAD_StickY(u8 chan, u8 right);
|
||||
|
||||
static void* outputBuffer;
|
||||
static struct mAVStream stream;
|
||||
static struct mRumble rumble;
|
||||
static struct mRotationSource rotation;
|
||||
static GXRModeObj* vmode;
|
||||
|
@ -222,7 +226,7 @@ static void reconfigureScreen(struct mGUIRunner* runner) {
|
|||
runner->params.width = vmode->fbWidth * guiScale * wAdjust;
|
||||
runner->params.height = vmode->efbHeight * guiScale * hAdjust;
|
||||
if (runner->core) {
|
||||
double ratio = GBAAudioCalculateRatio(1,audioSampleRate, 1);
|
||||
double ratio = GBAAudioCalculateRatio(1, audioSampleRate, 1);
|
||||
blip_set_rates(runner->core->getAudioChannel(runner->core, 0), runner->core->frequency(runner->core), 48000 * ratio);
|
||||
blip_set_rates(runner->core->getAudioChannel(runner->core, 1), runner->core->frequency(runner->core), 48000 * ratio);
|
||||
|
||||
|
@ -317,6 +321,11 @@ int main(int argc, char* argv[]) {
|
|||
rotation.readTiltY = _readTiltY;
|
||||
rotation.readGyroZ = _readGyroZ;
|
||||
|
||||
stream.videoDimensionsChanged = NULL;
|
||||
stream.postVideoFrame = NULL;
|
||||
stream.postAudioFrame = NULL;
|
||||
stream.postAudioBuffer = _postAudioBuffer;
|
||||
|
||||
struct mGUIRunner runner = {
|
||||
.params = {
|
||||
720, 480,
|
||||
|
@ -554,6 +563,25 @@ static void _audioDMA(void) {
|
|||
audioBufferSize = 0;
|
||||
}
|
||||
|
||||
static void _postAudioBuffer(struct mAVStream* stream, blip_t* left, blip_t* right) {
|
||||
UNUSED(stream);
|
||||
int available = blip_samples_avail(left);
|
||||
if (available + audioBufferSize > SAMPLES) {
|
||||
available = SAMPLES - audioBufferSize;
|
||||
}
|
||||
available &= ~((32 / sizeof(struct GBAStereoSample)) - 1); // Force align to 32 bytes
|
||||
if (available > 0) {
|
||||
// These appear to be reversed for AUDIO_InitDMA
|
||||
blip_read_samples(left, &audioBuffer[currentAudioBuffer][audioBufferSize].right, available, true);
|
||||
blip_read_samples(right, &audioBuffer[currentAudioBuffer][audioBufferSize].left, available, true);
|
||||
audioBufferSize += available;
|
||||
}
|
||||
if (audioBufferSize == SAMPLES && !AUDIO_GetDMAEnableFlag()) {
|
||||
_audioDMA();
|
||||
AUDIO_StartDMA();
|
||||
}
|
||||
}
|
||||
|
||||
static void _drawStart(void) {
|
||||
VIDEO_SetBlack(false);
|
||||
|
||||
|
@ -611,16 +639,16 @@ static uint32_t _pollInput(const struct mInputMap* map) {
|
|||
int y = PAD_StickY(0);
|
||||
int w_x = WPAD_StickX(0, 0);
|
||||
int w_y = WPAD_StickY(0, 0);
|
||||
if (x < -0x20 || w_x < -0x20) {
|
||||
if (x < -ANALOG_DEADZONE || w_x < -ANALOG_DEADZONE) {
|
||||
keys |= 1 << GUI_INPUT_LEFT;
|
||||
}
|
||||
if (x > 0x20 || w_x > 0x20) {
|
||||
if (x > ANALOG_DEADZONE || w_x > ANALOG_DEADZONE) {
|
||||
keys |= 1 << GUI_INPUT_RIGHT;
|
||||
}
|
||||
if (y < -0x20 || w_y <- 0x20) {
|
||||
if (y < -ANALOG_DEADZONE || w_y < -ANALOG_DEADZONE) {
|
||||
keys |= 1 << GUI_INPUT_DOWN;
|
||||
}
|
||||
if (y > 0x20 || w_y > 0x20) {
|
||||
if (y > ANALOG_DEADZONE || w_y > ANALOG_DEADZONE) {
|
||||
keys |= 1 << GUI_INPUT_UP;
|
||||
}
|
||||
return keys;
|
||||
|
@ -665,6 +693,7 @@ void _guiPrepare(void) {
|
|||
void _setup(struct mGUIRunner* runner) {
|
||||
runner->core->setPeripheral(runner->core, mPERIPH_ROTATION, &rotation);
|
||||
runner->core->setPeripheral(runner->core, mPERIPH_RUMBLE, &rumble);
|
||||
runner->core->setAVStream(runner->core, &stream);
|
||||
|
||||
_mapKey(&runner->core->inputMap, GCN1_INPUT, PAD_BUTTON_A, GBA_KEY_A);
|
||||
_mapKey(&runner->core->inputMap, GCN1_INPUT, PAD_BUTTON_B, GBA_KEY_B);
|
||||
|
@ -700,10 +729,10 @@ void _setup(struct mGUIRunner* runner) {
|
|||
_mapKey(&runner->core->inputMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_FULL_L, GBA_KEY_L);
|
||||
_mapKey(&runner->core->inputMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_FULL_R, GBA_KEY_R);
|
||||
|
||||
struct mInputAxis desc = { GBA_KEY_RIGHT, GBA_KEY_LEFT, 0x20, -0x20 };
|
||||
struct mInputAxis desc = { GBA_KEY_RIGHT, GBA_KEY_LEFT, ANALOG_DEADZONE, -ANALOG_DEADZONE };
|
||||
mInputBindAxis(&runner->core->inputMap, GCN1_INPUT, 0, &desc);
|
||||
mInputBindAxis(&runner->core->inputMap, CLASSIC_INPUT, 0, &desc);
|
||||
desc = (struct mInputAxis) { GBA_KEY_UP, GBA_KEY_DOWN, 0x20, -0x20 };
|
||||
desc = (struct mInputAxis) { GBA_KEY_UP, GBA_KEY_DOWN, ANALOG_DEADZONE, -ANALOG_DEADZONE };
|
||||
mInputBindAxis(&runner->core->inputMap, GCN1_INPUT, 1, &desc);
|
||||
mInputBindAxis(&runner->core->inputMap, CLASSIC_INPUT, 1, &desc);
|
||||
|
||||
|
@ -783,22 +812,7 @@ void _unpaused(struct mGUIRunner* runner) {
|
|||
}
|
||||
|
||||
void _drawFrame(struct mGUIRunner* runner, bool faded) {
|
||||
int available = blip_samples_avail(runner->core->getAudioChannel(runner->core, 0));
|
||||
if (available + audioBufferSize > SAMPLES) {
|
||||
available = SAMPLES - audioBufferSize;
|
||||
}
|
||||
available &= ~((32 / sizeof(struct GBAStereoSample)) - 1); // Force align to 32 bytes
|
||||
if (available > 0) {
|
||||
// These appear to be reversed for AUDIO_InitDMA
|
||||
blip_read_samples(runner->core->getAudioChannel(runner->core, 0), &audioBuffer[currentAudioBuffer][audioBufferSize].right, available, true);
|
||||
blip_read_samples(runner->core->getAudioChannel(runner->core, 1), &audioBuffer[currentAudioBuffer][audioBufferSize].left, available, true);
|
||||
audioBufferSize += available;
|
||||
}
|
||||
if (audioBufferSize == SAMPLES && !AUDIO_GetDMAEnableFlag()) {
|
||||
_audioDMA();
|
||||
AUDIO_StartDMA();
|
||||
}
|
||||
|
||||
UNUSED(runner);
|
||||
uint32_t color = 0xFFFFFF3F;
|
||||
if (!faded) {
|
||||
color |= 0xC0;
|
||||
|
@ -986,77 +1000,65 @@ int32_t _readGyroZ(struct mRotationSource* source) {
|
|||
}
|
||||
|
||||
static s8 WPAD_StickX(u8 chan, u8 right) {
|
||||
float mag = 0.0;
|
||||
float ang = 0.0;
|
||||
WPADData *data = WPAD_Data(chan);
|
||||
struct expansion_t exp;
|
||||
WPAD_Expansion(chan, &exp);
|
||||
struct joystick_t* js = NULL;
|
||||
|
||||
switch (data->exp.type) {
|
||||
switch (exp.type) {
|
||||
case WPAD_EXP_NUNCHUK:
|
||||
case WPAD_EXP_GUITARHERO3:
|
||||
if (right == 0) {
|
||||
mag = data->exp.nunchuk.js.mag;
|
||||
ang = data->exp.nunchuk.js.ang;
|
||||
js = &exp.nunchuk.js;
|
||||
}
|
||||
break;
|
||||
case WPAD_EXP_CLASSIC:
|
||||
if (right == 0) {
|
||||
mag = data->exp.classic.ljs.mag;
|
||||
ang = data->exp.classic.ljs.ang;
|
||||
js = &exp.classic.ljs;
|
||||
} else {
|
||||
mag = data->exp.classic.rjs.mag;
|
||||
ang = data->exp.classic.rjs.ang;
|
||||
js = &exp.classic.rjs;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* calculate X value (angle need to be converted into radian) */
|
||||
if (mag > 1.0) {
|
||||
mag = 1.0;
|
||||
} else if (mag < -1.0) {
|
||||
mag = -1.0;
|
||||
if (!js) {
|
||||
return 0;
|
||||
}
|
||||
double val = mag * sinf(M_PI * ang / 180.0f);
|
||||
|
||||
return (s8)(val * 128.0f);
|
||||
int centered = (int) js->pos.x - (int) js->center.x;
|
||||
int range = js->max.x - js->min.x;
|
||||
return (centered * 0xFF) / range;
|
||||
}
|
||||
|
||||
static s8 WPAD_StickY(u8 chan, u8 right) {
|
||||
float mag = 0.0;
|
||||
float ang = 0.0;
|
||||
WPADData *data = WPAD_Data(chan);
|
||||
struct expansion_t exp;
|
||||
WPAD_Expansion(chan, &exp);
|
||||
struct joystick_t* js = NULL;
|
||||
|
||||
switch (data->exp.type) {
|
||||
switch (exp.type) {
|
||||
case WPAD_EXP_NUNCHUK:
|
||||
case WPAD_EXP_GUITARHERO3:
|
||||
if (right == 0) {
|
||||
mag = data->exp.nunchuk.js.mag;
|
||||
ang = data->exp.nunchuk.js.ang;
|
||||
js = &exp.nunchuk.js;
|
||||
}
|
||||
break;
|
||||
case WPAD_EXP_CLASSIC:
|
||||
if (right == 0) {
|
||||
mag = data->exp.classic.ljs.mag;
|
||||
ang = data->exp.classic.ljs.ang;
|
||||
js = &exp.classic.ljs;
|
||||
} else {
|
||||
mag = data->exp.classic.rjs.mag;
|
||||
ang = data->exp.classic.rjs.ang;
|
||||
js = &exp.classic.rjs;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* calculate X value (angle need to be converted into radian) */
|
||||
if (mag > 1.0) {
|
||||
mag = 1.0;
|
||||
} else if (mag < -1.0) {
|
||||
mag = -1.0;
|
||||
if (!js) {
|
||||
return 0;
|
||||
}
|
||||
double val = mag * cosf(M_PI * ang / 180.0f);
|
||||
|
||||
return (s8)(val * 128.0f);
|
||||
int centered = (int) js->pos.y - (int) js->center.y;
|
||||
int range = js->max.y - js->min.y;
|
||||
return (centered * 0xFF) / range;
|
||||
}
|
||||
|
||||
void _retraceCallback(u32 count) {
|
||||
|
|
Loading…
Reference in New Issue