Merge branch 'master' (early part) into medusa

This commit is contained in:
Vicki Pfau 2019-06-28 16:01:01 -07:00
commit a87b800414
24 changed files with 384 additions and 39 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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*);

View File

@ -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;

View File

@ -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];

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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];

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -39,7 +39,7 @@ protected:
std::shared_ptr<CoreController> m_gameController;
private:
QMetaObject::Connection m_autoattach;
bool m_autoattach = false;
};
}

View File

@ -34,7 +34,6 @@ void GDBController::setBindAddress(uint32_t bindAddress) {
}
void GDBController::listen() {
CoreController::Interrupter interrupter(m_gameController);
if (!isAttached()) {
attach();
}

View File

@ -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());
}
}

View File

@ -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;
};
}

View File

@ -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>

View File

@ -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);