mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' (early part) into medusa
This commit is contained in:
commit
a87b800414
1
CHANGES
1
CHANGES
|
@ -69,6 +69,7 @@ Misc:
|
|||
- GBA Memory: 64 MiB GBA Video cartridge support
|
||||
- PSP2: Use system enter key by default
|
||||
- 3DS: Remove deprecated CSND interface
|
||||
- Qt: Options to mess around with layer placement
|
||||
|
||||
0.6.3: (2017-04-14)
|
||||
Bugfixes:
|
||||
|
|
|
@ -679,7 +679,7 @@ if(USE_ELF)
|
|||
list(APPEND FEATURES ELF)
|
||||
include_directories(AFTER ${LIBELF_INCLUDE_DIRS})
|
||||
list(APPEND DEPENDENCY_LIB ${LIBELF_LIBRARIES})
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libelfg0")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libelf1")
|
||||
endif()
|
||||
|
||||
if(ENABLE_SCRIPTING)
|
||||
|
|
|
@ -160,6 +160,7 @@ struct mCore {
|
|||
size_t (*listAudioChannels)(const struct mCore*, const struct mCoreChannelInfo**);
|
||||
void (*enableVideoLayer)(struct mCore*, size_t id, bool enable);
|
||||
void (*enableAudioChannel)(struct mCore*, size_t id, bool enable);
|
||||
void (*adjustVideoLayer)(struct mCore*, size_t id, int32_t x, int32_t y);
|
||||
|
||||
#ifndef MINIMAL_CORE
|
||||
void (*startVideoLog)(struct mCore*, struct mVideoLogContext*);
|
||||
|
|
|
@ -38,6 +38,13 @@ struct GBVideoSoftwareRenderer {
|
|||
GBRegisterLCDC lcdc;
|
||||
enum GBModel model;
|
||||
|
||||
int16_t objOffsetX;
|
||||
int16_t objOffsetY;
|
||||
int16_t offsetScx;
|
||||
int16_t offsetScy;
|
||||
int16_t offsetWx;
|
||||
int16_t offsetWy;
|
||||
|
||||
int sgbTransfer;
|
||||
uint8_t sgbPacket[128];
|
||||
uint8_t sgbCommandHeader;
|
||||
|
|
|
@ -47,6 +47,8 @@ struct GBAVideoSoftwareBackground {
|
|||
uint16_t mapCache[64];
|
||||
color_t* extPalette;
|
||||
color_t* variantPalette;
|
||||
int32_t offsetX;
|
||||
int32_t offsetY;
|
||||
};
|
||||
|
||||
enum BlendEffect {
|
||||
|
@ -169,6 +171,8 @@ struct GBAVideoSoftwareRenderer {
|
|||
int tileStride;
|
||||
int bitmapStride;
|
||||
bool combinedObjSort;
|
||||
int16_t objOffsetX;
|
||||
int16_t objOffsetY;
|
||||
|
||||
uint32_t scanlineDirty[5];
|
||||
uint16_t nextIo[REG_SOUND1CNT_LO];
|
||||
|
|
|
@ -105,7 +105,10 @@ static void _magickVideoDimensionsChanged(struct mAVStream* stream, unsigned wid
|
|||
if (encoder->iwidth == width && encoder->iheight == height) {
|
||||
return;
|
||||
}
|
||||
free(encoder->frame);
|
||||
if (width * height > encoder->iwidth * encoder->iheight) {
|
||||
free(encoder->frame);
|
||||
encoder->frame = malloc(width * height * 4);
|
||||
}
|
||||
encoder->iwidth = width;
|
||||
encoder->iheight = height;
|
||||
encoder->frame = malloc(encoder->iwidth * encoder->iheight * 4);
|
||||
|
|
|
@ -814,13 +814,17 @@ static bool _GBCoreSavedataRestore(struct mCore* core, const void* sram, size_t
|
|||
|
||||
static size_t _GBCoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) {
|
||||
UNUSED(core);
|
||||
*info = _GBVideoLayers;
|
||||
if (info) {
|
||||
*info = _GBVideoLayers;
|
||||
}
|
||||
return sizeof(_GBVideoLayers) / sizeof(*_GBVideoLayers);
|
||||
}
|
||||
|
||||
static size_t _GBCoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) {
|
||||
UNUSED(core);
|
||||
*info = _GBAudioChannels;
|
||||
if (info) {
|
||||
*info = _GBAudioChannels;
|
||||
}
|
||||
return sizeof(_GBAudioChannels) / sizeof(*_GBAudioChannels);
|
||||
}
|
||||
|
||||
|
@ -855,6 +859,26 @@ static void _GBCoreEnableAudioChannel(struct mCore* core, size_t id, bool enable
|
|||
}
|
||||
}
|
||||
|
||||
static void _GBCoreAdjustVideoLayer(struct mCore* core, size_t id, int32_t x, int32_t y) {
|
||||
struct GBCore* gbcore = (struct GBCore*) core;
|
||||
switch (id) {
|
||||
case 0:
|
||||
gbcore->renderer.offsetScx = x;
|
||||
gbcore->renderer.offsetScy = y;
|
||||
break;
|
||||
case 1:
|
||||
gbcore->renderer.offsetWx = x;
|
||||
gbcore->renderer.offsetWy = y;
|
||||
break;
|
||||
case 2:
|
||||
gbcore->renderer.objOffsetX = x;
|
||||
gbcore->renderer.objOffsetY = y;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef MINIMAL_CORE
|
||||
static void _GBCoreStartVideoLog(struct mCore* core, struct mVideoLogContext* context) {
|
||||
struct GBCore* gbcore = (struct GBCore*) core;
|
||||
|
@ -959,6 +983,7 @@ struct mCore* GBCoreCreate(void) {
|
|||
core->listAudioChannels = _GBCoreListAudioChannels;
|
||||
core->enableVideoLayer = _GBCoreEnableVideoLayer;
|
||||
core->enableAudioChannel = _GBCoreEnableAudioChannel;
|
||||
core->adjustVideoLayer = _GBCoreAdjustVideoLayer;
|
||||
#ifndef MINIMAL_CORE
|
||||
core->startVideoLog = _GBCoreStartVideoLog;
|
||||
core->endVideoLog = _GBCoreEndVideoLog;
|
||||
|
|
20
src/gb/io.c
20
src/gb/io.c
|
@ -113,8 +113,21 @@ static void _writeSGBBits(struct GB* gb, int bits) {
|
|||
return;
|
||||
}
|
||||
gb->currentSgbBits = bits;
|
||||
if (bits == 3) {
|
||||
gb->sgbCurrentController = (gb->sgbCurrentController + 1) & gb->sgbControllers;
|
||||
if (gb->sgbBit > 128) {
|
||||
switch (bits) {
|
||||
case 1:
|
||||
gb->sgbBit |= 2;
|
||||
break;
|
||||
case 2:
|
||||
gb->sgbBit |= 4;
|
||||
break;
|
||||
case 3:
|
||||
if (gb->sgbBit == 135) {
|
||||
gb->sgbBit &= ~6;
|
||||
gb->sgbCurrentController = (gb->sgbCurrentController + 1) & gb->sgbControllers;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (gb->sgbBit == 128 && bits == 2) {
|
||||
GBVideoWriteSGBPacket(&gb->video, gb->sgbPacket);
|
||||
|
@ -511,8 +524,7 @@ static uint8_t _readKeys(struct GB* gb) {
|
|||
}
|
||||
switch (gb->memory.io[REG_JOYP] & 0x30) {
|
||||
case 0x30:
|
||||
// TODO: Increment
|
||||
keys = (gb->video.sgbCommandHeader >> 3) == SGB_MLT_REQ ? 0xF - gb->sgbCurrentController : 0;
|
||||
keys = gb->sgbCurrentController;
|
||||
break;
|
||||
case 0x20:
|
||||
keys >>= 4;
|
||||
|
|
|
@ -29,8 +29,8 @@ static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* rende
|
|||
|
||||
static void _clearScreen(struct GBVideoSoftwareRenderer* renderer) {
|
||||
size_t sgbOffset = 0;
|
||||
if (renderer->model == GB_MODEL_SGB && renderer->sgbBorders) {
|
||||
sgbOffset = renderer->outputBufferStride * 40 + 48;
|
||||
if (renderer->model == GB_MODEL_SGB) {
|
||||
return;
|
||||
}
|
||||
int y;
|
||||
for (y = 0; y < GB_VIDEO_VERTICAL_PIXELS; ++y) {
|
||||
|
@ -135,6 +135,30 @@ static void _parseAttrBlock(struct GBVideoSoftwareRenderer* renderer, int start)
|
|||
}
|
||||
}
|
||||
|
||||
static void _parseAttrLine(struct GBVideoSoftwareRenderer* renderer, int start) {
|
||||
uint8_t byte = renderer->sgbPacket[start];
|
||||
unsigned line = byte & 0x1F;
|
||||
int pal = (byte >> 5) & 3;
|
||||
|
||||
if (byte & 0x80) {
|
||||
if (line > GB_VIDEO_VERTICAL_PIXELS / 8) {
|
||||
return;
|
||||
}
|
||||
int x;
|
||||
for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS / 8; ++x) {
|
||||
_setAttribute(renderer->d.sgbAttributes, x, line, pal);
|
||||
}
|
||||
} else {
|
||||
if (line > GB_VIDEO_HORIZONTAL_PIXELS / 8) {
|
||||
return;
|
||||
}
|
||||
int y;
|
||||
for (y = 0; y < GB_VIDEO_VERTICAL_PIXELS / 8; ++y) {
|
||||
_setAttribute(renderer->d.sgbAttributes, line, y, pal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool _inWindow(struct GBVideoSoftwareRenderer* renderer) {
|
||||
return GBRegisterLCDCIsWindow(renderer->lcdc) && GB_VIDEO_HORIZONTAL_PIXELS + 7 > renderer->wx;
|
||||
}
|
||||
|
@ -174,6 +198,13 @@ static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum G
|
|||
softwareRenderer->sgbTransfer = 0;
|
||||
softwareRenderer->sgbCommandHeader = 0;
|
||||
softwareRenderer->sgbBorders = sgbBorders;
|
||||
softwareRenderer->objOffsetX = 0;
|
||||
softwareRenderer->objOffsetY = 0;
|
||||
softwareRenderer->offsetScx = 0;
|
||||
softwareRenderer->offsetScy = 0;
|
||||
softwareRenderer->offsetWx = 0;
|
||||
softwareRenderer->offsetWy = 0;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 64; ++i) {
|
||||
softwareRenderer->lookup[i] = i;
|
||||
|
@ -287,6 +318,13 @@ static void GBVideoSoftwareRendererWriteSGBPacket(struct GBVideoRenderer* render
|
|||
_parseAttrBlock(softwareRenderer, i);
|
||||
}
|
||||
break;
|
||||
case SGB_ATTR_LIN:
|
||||
sets = softwareRenderer->sgbPacket[1];
|
||||
i = 2;
|
||||
for (; i < (softwareRenderer->sgbCommandHeader & 7) << 4 && sets; ++i, --sets) {
|
||||
_parseAttrLine(softwareRenderer, i);
|
||||
}
|
||||
break;
|
||||
case SGB_ATTR_DIV:
|
||||
pAfter = softwareRenderer->sgbPacket[1] & 3;
|
||||
pBefore = (softwareRenderer->sgbPacket[1] >> 2) & 3;
|
||||
|
@ -440,7 +478,7 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
|
|||
int wy = softwareRenderer->wy + softwareRenderer->currentWy;
|
||||
if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && wy <= y && endX >= softwareRenderer->wx - 7) {
|
||||
if (softwareRenderer->wx - 7 > 0 && !softwareRenderer->d.disableBG) {
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, softwareRenderer->wx - 7, softwareRenderer->scx, softwareRenderer->scy + y);
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, softwareRenderer->wx - 7, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy);
|
||||
}
|
||||
|
||||
maps = &softwareRenderer->d.vram[GB_BASE_MAP];
|
||||
|
@ -448,10 +486,10 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
|
|||
maps += GB_SIZE_MAP;
|
||||
}
|
||||
if (!softwareRenderer->d.disableWIN) {
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, softwareRenderer->wx - 7, endX, 7 - softwareRenderer->wx, y - wy);
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, softwareRenderer->wx - 7, endX, 7 - softwareRenderer->wx - softwareRenderer->offsetWx, y - wy - softwareRenderer->offsetWy);
|
||||
}
|
||||
} else if (!softwareRenderer->d.disableBG) {
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, endX, softwareRenderer->scx, softwareRenderer->scy + y);
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, endX, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy);
|
||||
}
|
||||
} else if (!softwareRenderer->d.disableBG) {
|
||||
memset(&softwareRenderer->row[startX], 0, endX - startX);
|
||||
|
@ -747,15 +785,16 @@ static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer
|
|||
}
|
||||
|
||||
static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int startX, int endX, int y) {
|
||||
int ix = obj->x - 8;
|
||||
int objX = obj->x + renderer->objOffsetX;
|
||||
int ix = objX - 8;
|
||||
if (endX < ix || startX >= ix + 8) {
|
||||
return;
|
||||
}
|
||||
if (obj->x < endX) {
|
||||
endX = obj->x;
|
||||
if (objX < endX) {
|
||||
endX = objX;
|
||||
}
|
||||
if (obj->x - 8 > startX) {
|
||||
startX = obj->x - 8;
|
||||
if (objX - 8 > startX) {
|
||||
startX = objX - 8;
|
||||
}
|
||||
if (startX < 0) {
|
||||
startX = 0;
|
||||
|
@ -763,14 +802,15 @@ static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* rende
|
|||
uint8_t* data = renderer->d.vram;
|
||||
int tileOffset = 0;
|
||||
int bottomY;
|
||||
int objY = obj->y + renderer->objOffsetY;
|
||||
if (GBObjAttributesIsYFlip(obj->attr)) {
|
||||
bottomY = 7 - ((y - obj->y - 16) & 7);
|
||||
if (GBRegisterLCDCIsObjSize(renderer->lcdc) && y - obj->y < -8) {
|
||||
bottomY = 7 - ((y - objY - 16) & 7);
|
||||
if (GBRegisterLCDCIsObjSize(renderer->lcdc) && y - objY < -8) {
|
||||
++tileOffset;
|
||||
}
|
||||
} else {
|
||||
bottomY = (y - obj->y - 16) & 7;
|
||||
if (GBRegisterLCDCIsObjSize(renderer->lcdc) && y - obj->y >= -8) {
|
||||
bottomY = (y - objY - 16) & 7;
|
||||
if (GBRegisterLCDCIsObjSize(renderer->lcdc) && y - objY >= -8) {
|
||||
++tileOffset;
|
||||
}
|
||||
}
|
||||
|
@ -794,12 +834,12 @@ static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* rende
|
|||
}
|
||||
int bottomX;
|
||||
int x = startX;
|
||||
if ((x - obj->x) & 7) {
|
||||
if ((x - objX) & 7) {
|
||||
for (; x < endX; ++x) {
|
||||
if (GBObjAttributesIsXFlip(obj->attr)) {
|
||||
bottomX = (x - obj->x) & 7;
|
||||
bottomX = (x - objX) & 7;
|
||||
} else {
|
||||
bottomX = 7 - ((x - obj->x) & 7);
|
||||
bottomX = 7 - ((x - objX) & 7);
|
||||
}
|
||||
int objTile = obj->tile + tileOffset;
|
||||
uint8_t tileDataLower = data[(objTile * 8 + bottomY) * 2];
|
||||
|
|
|
@ -694,6 +694,7 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) {
|
|||
case SGB_ATTR_BLK:
|
||||
case SGB_ATTR_DIV:
|
||||
case SGB_ATTR_CHR:
|
||||
case SGB_ATTR_LIN:
|
||||
case SGB_PAL_TRN:
|
||||
case SGB_ATRC_EN:
|
||||
case SGB_CHR_TRN:
|
||||
|
@ -703,6 +704,7 @@ void GBVideoWriteSGBPacket(struct GBVideo* video, uint8_t* data) {
|
|||
break;
|
||||
case SGB_MLT_REQ:
|
||||
video->p->sgbControllers = video->sgbPacketBuffer[1] & 0x3;
|
||||
video->p->sgbCurrentController = 0;
|
||||
return;
|
||||
case SGB_MASK_EN:
|
||||
video->renderer->sgbRenderMode = video->sgbPacketBuffer[1] & 0x3;
|
||||
|
|
|
@ -21,7 +21,7 @@ static void _addBreakpoint(struct mCheatDevice* device, struct GBACheatSet* chea
|
|||
if (cheats->hook->reentries > 1) {
|
||||
return;
|
||||
}
|
||||
// TODO: Put back hooks
|
||||
GBASetBreakpoint(device->p->board, &device->d, cheats->hook->address, cheats->hook->mode, &cheats->hook->patchedOpcode);
|
||||
}
|
||||
|
||||
static void _removeBreakpoint(struct mCheatDevice* device, struct GBACheatSet* cheats) {
|
||||
|
@ -32,7 +32,7 @@ static void _removeBreakpoint(struct mCheatDevice* device, struct GBACheatSet* c
|
|||
if (cheats->hook->reentries > 0) {
|
||||
return;
|
||||
}
|
||||
// TODO: Put back hooks
|
||||
GBAClearBreakpoint(device->p->board, cheats->hook->address, cheats->hook->mode, cheats->hook->patchedOpcode);
|
||||
}
|
||||
|
||||
static void _patchROM(struct mCheatDevice* device, struct GBACheatSet* cheats) {
|
||||
|
|
|
@ -817,13 +817,17 @@ static bool _GBACoreSavedataRestore(struct mCore* core, const void* sram, size_t
|
|||
|
||||
static size_t _GBACoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) {
|
||||
UNUSED(core);
|
||||
*info = _GBAVideoLayers;
|
||||
if (info) {
|
||||
*info = _GBAVideoLayers;
|
||||
}
|
||||
return sizeof(_GBAVideoLayers) / sizeof(*_GBAVideoLayers);
|
||||
}
|
||||
|
||||
static size_t _GBACoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) {
|
||||
UNUSED(core);
|
||||
*info = _GBAAudioChannels;
|
||||
if (info) {
|
||||
*info = _GBAAudioChannels;
|
||||
}
|
||||
return sizeof(_GBAAudioChannels) / sizeof(*_GBAAudioChannels);
|
||||
}
|
||||
|
||||
|
@ -863,6 +867,27 @@ static void _GBACoreEnableAudioChannel(struct mCore* core, size_t id, bool enabl
|
|||
}
|
||||
}
|
||||
|
||||
static void _GBACoreAdjustVideoLayer(struct mCore* core, size_t id, int32_t x, int32_t y) {
|
||||
struct GBACore* gbacore = (struct GBACore*) core;
|
||||
switch (id) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
gbacore->renderer.bg[id].offsetX = x;
|
||||
gbacore->renderer.bg[id].offsetY = y;
|
||||
break;
|
||||
case 4:
|
||||
gbacore->renderer.objOffsetX = x;
|
||||
gbacore->renderer.objOffsetY = y;
|
||||
gbacore->renderer.oamDirty = 1;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
memset(gbacore->renderer.scanlineDirty, 0xFFFFFFFF, sizeof(gbacore->renderer.scanlineDirty));
|
||||
}
|
||||
|
||||
#ifndef MINIMAL_CORE
|
||||
static void _GBACoreStartVideoLog(struct mCore* core, struct mVideoLogContext* context) {
|
||||
struct GBACore* gbacore = (struct GBACore*) core;
|
||||
|
@ -970,6 +995,7 @@ struct mCore* GBACoreCreate(void) {
|
|||
core->listAudioChannels = _GBACoreListAudioChannels;
|
||||
core->enableVideoLayer = _GBACoreEnableVideoLayer;
|
||||
core->enableAudioChannel = _GBACoreEnableAudioChannel;
|
||||
core->adjustVideoLayer = _GBACoreAdjustVideoLayer;
|
||||
#ifndef MINIMAL_CORE
|
||||
core->startVideoLog = _GBACoreStartVideoLog;
|
||||
core->endVideoLog = _GBACoreEndVideoLog;
|
||||
|
|
|
@ -804,7 +804,9 @@ void GBAFrameEnded(struct GBA* gba) {
|
|||
size_t i;
|
||||
for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) {
|
||||
struct GBACheatSet* cheats = (struct GBACheatSet*) *mCheatSetsGetPointer(&device->cheats, i);
|
||||
mCheatRefresh(device, &cheats->d);
|
||||
if (!cheats->hook) {
|
||||
mCheatRefresh(device, &cheats->d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -578,13 +578,13 @@
|
|||
}
|
||||
|
||||
void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y) {
|
||||
int inX = (renderer->start + background->x) & 0x1FF;
|
||||
int inX = (renderer->start + background->x - background->offsetX) & 0x1FF;
|
||||
int length = renderer->end - renderer->start;
|
||||
if (background->mosaic) {
|
||||
int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1;
|
||||
y -= y % mosaicV;
|
||||
}
|
||||
int inY = y + background->y;
|
||||
int inY = y + background->y - background->offsetY;
|
||||
uint16_t mapData;
|
||||
|
||||
unsigned yBase = inY & 0xF8;
|
||||
|
|
|
@ -232,6 +232,7 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re
|
|||
}
|
||||
int32_t x = (uint32_t) GBAObjAttributesBGetX(sprite->b) << 23;
|
||||
x >>= 23;
|
||||
x += renderer->objOffsetX;
|
||||
unsigned charBase = GBAObjAttributesCGetTile(sprite->c);
|
||||
if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_BITMAP && renderer->bitmapStride) {
|
||||
charBase = (charBase & (renderer->bitmapStride - 1)) * 0x10 + (charBase & ~(renderer->bitmapStride - 1)) * 0x80;
|
||||
|
@ -283,7 +284,7 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re
|
|||
}
|
||||
}
|
||||
|
||||
int inY = y - (int) GBAObjAttributesAGetY(sprite->a);
|
||||
int inY = y - ((int) GBAObjAttributesAGetY(sprite->a) + renderer->objOffsetY);
|
||||
int stride = GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? (width >> !GBAObjAttributesAIs256Color(sprite->a)) : 0x80;
|
||||
if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_BITMAP && renderer->bitmapStride) {
|
||||
stride = renderer->bitmapStride << 3;
|
||||
|
|
|
@ -117,11 +117,15 @@ static void GBAVideoSoftwareRendererReset(struct GBAVideoRenderer* renderer) {
|
|||
softwareRenderer->winN[1] = (struct WindowN) { .control = { .priority = 1 } };
|
||||
softwareRenderer->objwin = (struct WindowControl) { .priority = 2 };
|
||||
softwareRenderer->winout = (struct WindowControl) { .priority = 3 };
|
||||
softwareRenderer->oamDirty = 1;
|
||||
softwareRenderer->oamMax = 0;
|
||||
|
||||
softwareRenderer->mosaic = 0;
|
||||
softwareRenderer->nextY = 0;
|
||||
|
||||
softwareRenderer->objOffsetX = 0;
|
||||
softwareRenderer->objOffsetY = 0;
|
||||
|
||||
memset(softwareRenderer->scanlineDirty, 0xFFFFFFFF, sizeof(softwareRenderer->scanlineDirty));
|
||||
memset(softwareRenderer->cache, 0, sizeof(softwareRenderer->cache));
|
||||
memset(softwareRenderer->nextIo, 0, sizeof(softwareRenderer->nextIo));
|
||||
|
@ -152,6 +156,8 @@ static void GBAVideoSoftwareRendererReset(struct GBAVideoRenderer* renderer) {
|
|||
bg->yCache = -1;
|
||||
bg->extPalette = NULL;
|
||||
bg->variantPalette = NULL;
|
||||
bg->offsetX = 0;
|
||||
bg->offsetY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -533,8 +539,9 @@ static void _cleanOAM(struct GBAVideoSoftwareRenderer* renderer) {
|
|||
height <<= GBAObjAttributesAGetDoubleSize(obj.a);
|
||||
}
|
||||
if (GBAObjAttributesAGetY(obj.a) < renderer->masterHeight || GBAObjAttributesAGetY(obj.a) + height >= 256) {
|
||||
renderer->sprites[oamMax].y = GBAObjAttributesAGetY(obj.a);
|
||||
renderer->sprites[oamMax].endY = GBAObjAttributesAGetY(obj.a) + height;
|
||||
int y = GBAObjAttributesAGetY(obj.a) + renderer->objOffsetY;
|
||||
renderer->sprites[oamMax].y = y;
|
||||
renderer->sprites[oamMax].endY = y + height;
|
||||
renderer->sprites[oamMax].obj = obj;
|
||||
++oamMax;
|
||||
}
|
||||
|
|
|
@ -100,6 +100,7 @@ set(SOURCE_FILES
|
|||
ObjView.cpp
|
||||
OverrideView.cpp
|
||||
PaletteView.cpp
|
||||
PlacementControl.cpp
|
||||
PrinterView.cpp
|
||||
RegisterView.cpp
|
||||
ROMInfo.cpp
|
||||
|
@ -137,6 +138,7 @@ set(UI_FILES
|
|||
ObjView.ui
|
||||
OverrideView.ui
|
||||
PaletteView.ui
|
||||
PlacementControl.ui
|
||||
PrinterView.ui
|
||||
ROMInfo.ui
|
||||
SensorView.ui
|
||||
|
|
|
@ -32,6 +32,10 @@ void DebuggerController::setController(std::shared_ptr<CoreController> controlle
|
|||
connect(m_gameController.get(), &CoreController::stopping, [this]() {
|
||||
setController(nullptr);
|
||||
});
|
||||
if (m_autoattach) {
|
||||
m_autoattach = false;
|
||||
attach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,11 +47,12 @@ void DebuggerController::attach() {
|
|||
attachInternal();
|
||||
m_gameController->setDebugger(m_debugger);
|
||||
mDebuggerEnter(m_debugger, DEBUGGER_ENTER_ATTACHED, 0);
|
||||
} else {
|
||||
m_autoattach = true;
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerController::detach() {
|
||||
QObject::disconnect(m_autoattach);
|
||||
if (!isAttached()) {
|
||||
return;
|
||||
}
|
||||
|
@ -55,6 +60,8 @@ void DebuggerController::detach() {
|
|||
CoreController::Interrupter interrupter(m_gameController);
|
||||
shutdownInternal();
|
||||
m_gameController->setDebugger(nullptr);
|
||||
} else {
|
||||
m_autoattach = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,7 +74,7 @@ void DebuggerController::breakInto() {
|
|||
}
|
||||
|
||||
void DebuggerController::shutdown() {
|
||||
QObject::disconnect(m_autoattach);
|
||||
m_autoattach = false;
|
||||
if (!isAttached()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ protected:
|
|||
std::shared_ptr<CoreController> m_gameController;
|
||||
|
||||
private:
|
||||
QMetaObject::Connection m_autoattach;
|
||||
bool m_autoattach = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ void GDBController::setBindAddress(uint32_t bindAddress) {
|
|||
}
|
||||
|
||||
void GDBController::listen() {
|
||||
CoreController::Interrupter interrupter(m_gameController);
|
||||
if (!isAttached()) {
|
||||
attach();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/* Copyright (c) 2013-2018 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "PlacementControl.h"
|
||||
|
||||
#include "CoreController.h"
|
||||
|
||||
#include <QGridLayout>
|
||||
|
||||
#include <mgba/core/core.h>
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
PlacementControl::PlacementControl(std::shared_ptr<CoreController> controller, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, m_controller(controller)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
connect(m_ui.offsetX, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this](int x) {
|
||||
adjustLayer(-1, x, m_ui.offsetY->value());
|
||||
});
|
||||
|
||||
connect(m_ui.offsetY, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this](int y) {
|
||||
adjustLayer(-1, m_ui.offsetX->value(), y);
|
||||
});
|
||||
|
||||
QGridLayout* grid = static_cast<QGridLayout*>(layout());
|
||||
CoreController::Interrupter interrupter(m_controller);
|
||||
const mCoreChannelInfo* info;
|
||||
size_t nVideo = m_controller->thread()->core->listVideoLayers(m_controller->thread()->core, &info);
|
||||
for (size_t i = 0; i < nVideo; ++i) {
|
||||
QSpinBox* offsetX = new QSpinBox;
|
||||
QSpinBox* offsetY = new QSpinBox;
|
||||
|
||||
offsetX->setWrapping(true);
|
||||
offsetX->setMaximum(127);
|
||||
offsetX->setMinimum(-128);
|
||||
offsetX->setAccelerated(true);
|
||||
|
||||
offsetY->setWrapping(true);
|
||||
offsetY->setMaximum(127);
|
||||
offsetY->setMinimum(-128);
|
||||
offsetY->setAccelerated(true);
|
||||
|
||||
m_layers.append(qMakePair(offsetX, offsetY));
|
||||
int row = grid->rowCount();
|
||||
grid->addWidget(new QLabel(QString(info[i].visibleName)), row, 0, Qt::AlignRight);
|
||||
grid->addWidget(offsetX, row, 1);
|
||||
grid->addWidget(offsetY, row, 2);
|
||||
|
||||
connect(offsetX, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this, i, offsetY](int x) {
|
||||
adjustLayer(i, x, offsetY->value());
|
||||
});
|
||||
|
||||
connect(offsetY, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this, i, offsetX](int y) {
|
||||
adjustLayer(i, offsetX->value(), y);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void PlacementControl::adjustLayer(int layer, int32_t x, int32_t y) {
|
||||
CoreController::Interrupter interrupter(m_controller);
|
||||
mCore* core = m_controller->thread()->core;
|
||||
size_t nVideo = core->listVideoLayers(core, nullptr);
|
||||
|
||||
if (layer < 0) {
|
||||
for (size_t i = 0; i < nVideo; ++i) {
|
||||
core->adjustVideoLayer(core, i, x + m_layers[i].first->value(), y + m_layers[i].second->value());
|
||||
}
|
||||
} else if ((size_t) layer < nVideo) {
|
||||
core->adjustVideoLayer(core, layer, x + m_ui.offsetX->value(), y + m_ui.offsetY->value());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/* Copyright (c) 2013-2018 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QList>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "ui_PlacementControl.h"
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class CoreController;
|
||||
|
||||
class PlacementControl : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PlacementControl(std::shared_ptr<CoreController>, QWidget* parent = nullptr);
|
||||
|
||||
private:
|
||||
void adjustLayer(int layer, int32_t x, int32_t y);
|
||||
|
||||
std::shared_ptr<CoreController> m_controller;
|
||||
QList<QPair<QSpinBox*, QSpinBox*>> m_layers;
|
||||
|
||||
Ui::PlacementControl m_ui;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PlacementControl</class>
|
||||
<widget class="QDialog" name="PlacementControl">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>202</width>
|
||||
<height>72</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Adjust placement</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0" alignment="Qt::AlignRight">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>All</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="offsetX">
|
||||
<property name="wrapping">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="accelerated">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-128</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>127</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QSpinBox" name="offsetY">
|
||||
<property name="wrapping">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="accelerated">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-128</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>127</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" alignment="Qt::AlignRight">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Offset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Y</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -43,6 +43,7 @@
|
|||
#include "OverrideView.h"
|
||||
#include "ObjView.h"
|
||||
#include "PaletteView.h"
|
||||
#include "PlacementControl.h"
|
||||
#include "PrinterView.h"
|
||||
#include "ROMInfo.h"
|
||||
#include "SensorView.h"
|
||||
|
@ -205,6 +206,9 @@ void Window::argumentsPassed(mArguments* args) {
|
|||
if (args->debuggerType == DEBUGGER_GDB) {
|
||||
if (!m_gdbController) {
|
||||
m_gdbController = new GDBController(this);
|
||||
if (m_controller) {
|
||||
m_gdbController->setController(m_controller);
|
||||
}
|
||||
m_gdbController->listen();
|
||||
}
|
||||
}
|
||||
|
@ -1500,6 +1504,11 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
m_videoLayers = avMenu->addMenu(tr("Video layers"));
|
||||
m_audioChannels = avMenu->addMenu(tr("Audio channels"));
|
||||
|
||||
QAction* placementControl = new QAction(tr("Adjust layer placement..."), avMenu);
|
||||
connect(placementControl, &QAction::triggered, openControllerTView<PlacementControl>());
|
||||
m_gameActions.append(placementControl);
|
||||
addControlledAction(avMenu, placementControl, "placementControl");
|
||||
|
||||
QMenu* toolsMenu = menubar->addMenu(tr("&Tools"));
|
||||
QAction* viewLogs = new QAction(tr("View &logs..."), toolsMenu);
|
||||
connect(viewLogs, &QAction::triggered, m_logView, &QWidget::show);
|
||||
|
|
Loading…
Reference in New Issue