Add support for DMG palette customization.

git-svn-id: https://gambatte.svn.sourceforge.net/svnroot/gambatte@93 9dfb2916-2d38-0410-aef4-c5fe6c9ffc24
This commit is contained in:
sinamas 2007-10-25 08:04:24 +00:00
parent 6439c65c8a
commit 635d90090e
13 changed files with 711 additions and 20 deletions

View File

@ -29,6 +29,7 @@
#include "videodialog.h"
#include "inputdialog.h"
#include "sounddialog.h"
#include "palettedialog.h"
#include "blittercontainer.h"
#include "addaudioengines.h"
@ -173,6 +174,16 @@ GambatteQt::GambatteQt(const int argc, const char *const argv[]) :
QSettings iniSettings(QSettings::IniFormat, QSettings::UserScope, "gambatte", "gambatte_qt");
QString savepath = iniSettings.fileName();
savepath.truncate(iniSettings.fileName().lastIndexOf("/") + 1);
{
QString palpath = savepath + "palettes";
QDir::root().mkpath(palpath);
globalPaletteDialog = new PaletteDialog(palpath, 0, this);
romPaletteDialog = new PaletteDialog(palpath, globalPaletteDialog, this);
connect(globalPaletteDialog, SIGNAL(accepted()), this, SLOT(globalPaletteChange()));
connect(romPaletteDialog, SIGNAL(accepted()), this, SLOT(romPaletteChange()));
}
savepath += "saves";
QDir::root().mkpath(savepath);
gambatte.set_savedir(savepath.toAscii().data());
@ -376,6 +387,22 @@ void GambatteQt::videoSettingsChange() {
resetVideoBuffer();
}
void GambatteQt::globalPaletteChange() {
romPaletteDialog->externalChange();
setDmgPaletteColors();
}
void GambatteQt::romPaletteChange() {
globalPaletteDialog->externalChange();
setDmgPaletteColors();
}
void GambatteQt::setDmgPaletteColors() {
for (unsigned palnum = 0; palnum < 3; ++palnum)
for (unsigned colornum = 0; colornum < 4; ++colornum)
gambatte.setDmgPaletteColor(palnum, colornum, romPaletteDialog->getColor(palnum, colornum));
}
void GambatteQt::createActions() {
exitAct = new QAction(tr("E&xit"), this);
exitAct->setShortcut(tr("Ctrl+Q"));
@ -387,7 +414,7 @@ void GambatteQt::createActions() {
hideMenuAct->setShortcut(tr("Esc"));
connect(hideMenuAct, SIGNAL(triggered()), this, SLOT(toggleMenuHidden()));
fsAct = new QAction(tr("&Full screen"), this);
fsAct = new QAction(tr("&Full Screen"), this);
fsAct->setShortcut(tr("Ctrl+F"));
fsAct->setCheckable(true);
connect(fsAct, SIGNAL(triggered()), this, SLOT(toggleFullScreen()));
@ -445,6 +472,24 @@ void GambatteQt::createMenus() {
settingsm->addAction(act);
}
settingsm->addSeparator();
{
QMenu *const palm = settingsm->addMenu(tr("DMG &Palette"));
{
QAction *act = new QAction(tr("&Global..."), this);
connect(act, SIGNAL(triggered()), this, SLOT(execGlobalPaletteDialog()));
palm->addAction(act);
}
romPaletteAct = new QAction(tr("Current &ROM..."), this);
romPaletteAct->setEnabled(false);
connect(romPaletteAct, SIGNAL(triggered()), this, SLOT(execRomPaletteDialog()));
palm->addAction(romPaletteAct);
}
settingsm->addSeparator();
settingsm->addAction(fsAct);
settingsm->addAction(hideMenuAct);
@ -464,6 +509,13 @@ void GambatteQt::loadFile(const QString &fileName) {
);
return;
}
if (!gambatte.isCgb()) {
romPaletteDialog->setSettingsFile(QFileInfo(fileName).completeBaseName() + ".pal");
setDmgPaletteColors();
}
romPaletteAct->setEnabled(!gambatte.isCgb());
setCurrentFile(fileName);
@ -488,6 +540,14 @@ void GambatteQt::execSoundDialog() {
execDialog(soundDialog);
}
void GambatteQt::execGlobalPaletteDialog() {
execDialog(globalPaletteDialog);
}
void GambatteQt::execRomPaletteDialog() {
execDialog(romPaletteDialog);
}
void GambatteQt::setSamplesPrFrame() {
const BlitterWidget::Rational r = blitter->frameTime();
const unsigned old = samplesPrFrame;
@ -628,7 +688,7 @@ void GambatteQt::setCurrentFile(const QString &fileName) {
if (curFile.isEmpty())
setWindowTitle(tr("Gambatte"));
else
setWindowTitle(tr("%1 - %2").arg(strippedName(curFile)) .arg(tr("Gambatte")));
setWindowTitle(tr("%1 - %2").arg(strippedName(curFile)).arg(tr("Gambatte")));
QSettings settings;
QStringList files = settings.value("recentFileList").toStringList();

View File

@ -41,6 +41,7 @@ class BlitterWidget;
class VideoDialog;
class InputDialog;
class SoundDialog;
class PaletteDialog;
class FullResToggler;
class BlitterContainer;
class JoyObserver;
@ -109,9 +110,12 @@ class GambatteQt : public QMainWindow {
QAction *fsAct;
QAction *hideMenuAct;
QAction *resetAct;
QAction *romPaletteAct;
InputDialog *inputDialog;
SoundDialog *soundDialog;
VideoDialog *videoDialog;
PaletteDialog *globalPaletteDialog;
PaletteDialog *romPaletteDialog;
BlitterWidget *blitter;
const std::auto_ptr<FullResToggler> fullResToggler;
@ -142,6 +146,7 @@ class GambatteQt : public QMainWindow {
void unpause();
void setSamplesPrFrame();
void setCurrentFile(const QString &fileName);
void setDmgPaletteColors();
void soundEngineFailure();
void updateRecentFileActions();
QString strippedName(const QString &fullFileName);
@ -160,9 +165,13 @@ private slots:
void inputSettingsChange();
void soundSettingsChange();
void videoSettingsChange();
void globalPaletteChange();
void romPaletteChange();
void execVideoDialog();
void execInputDialog();
void execSoundDialog();
void execGlobalPaletteDialog();
void execRomPaletteDialog();
protected:
void timerEvent(QTimerEvent *event);

View File

@ -0,0 +1,439 @@
/***************************************************************************
* Copyright (C) 2007 by Sindre Aamås *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License version 2 as *
* published by the Free Software Foundation. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License version 2 for more details. *
* *
* You should have received a copy of the GNU General Public License *
* version 2 along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "palettedialog.h"
#include <QColor>
#include <QPalette>
#include <QColorDialog>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QApplication>
#include <QDropEvent>
#include <QDragEnterEvent>
#include <QMimeData>
#include <QByteArray>
#include <QDataStream>
#include <QListView>
#include <QStringListModel>
#include <QDir>
#include <QSettings>
#include <QInputDialog>
#include <QMessageBox>
ColorPicker::ColorPicker(QRgb color, QWidget *parent)
: QFrame(parent), w(new QWidget)
{
setAcceptDrops(true);
w->setAutoFillBackground(true);
setLayout(new QVBoxLayout);
layout()->setMargin(0);
layout()->addWidget(w);
setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
setFocusPolicy(Qt::StrongFocus);
setColor(color);
}
const QColor& ColorPicker::getQColor() const {
return w->palette().color(QPalette::Background);
}
void ColorPicker::requestColor() {
QColor c = QColorDialog::getColor(QColor(getColor()), this);
if (c.isValid()) {
setColor(c);
emit colorChanged();
}
}
void ColorPicker::setColor(const QColor &color) {
QPalette p(w->palette());
p.setColor(QPalette::Background, color);
w->setPalette(p);
}
void ColorPicker::dragEnterEvent(QDragEnterEvent *e) {
if (e->mimeData()->hasColor() && e->source() != this)
e->acceptProposedAction();
}
void ColorPicker::dropEvent(QDropEvent *e) {
e->setDropAction(Qt::CopyAction);
e->accept();
setColor(qvariant_cast<QColor>(e->mimeData()->colorData()));
emit colorChanged();
}
void ColorPicker::mousePressEvent(QMouseEvent *e) {
dragStartPosition = e->pos();
}
void ColorPicker::mouseMoveEvent(QMouseEvent *e) {
if ((e->pos() - dragStartPosition).manhattanLength() < QApplication::startDragDistance())
return;
QDrag *const drag = new QDrag(this);
QMimeData *const mimeData = new QMimeData;
mimeData->setColorData(getQColor());
drag->setMimeData(mimeData);
drag->exec(Qt::CopyAction);
}
void ColorPicker::mouseReleaseEvent(QMouseEvent *e) {
e->ignore();
if (e->x() <= width() && e->y() <= height()) {
e->accept();
requestColor();
}
}
void ColorPicker::keyReleaseEvent(QKeyEvent *e) {
e->ignore();
if (e->key() == Qt::Key_Space) {
e->accept();
requestColor();
}
}
QRgb ColorPicker::getColor() const {
return getQColor().rgb() & 0xFFFFFF;
}
void ColorPicker::setColor(QRgb rgb32) {
setColor(QColor(rgb32));
}
ColorQuad::ColorQuad(const QString &label, QWidget *parent)
: QGroupBox(label, parent)
{
setAcceptDrops(true);
setLayout(new QHBoxLayout);
for (int i = 0; i < 4; ++i) {
layout()->addWidget(picker[i] = new ColorPicker);
connect(picker[i], SIGNAL(colorChanged()), this, SLOT(pickerChanged()));
}
// setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
}
void ColorQuad::pickerChanged() {
emit colorChanged();
}
void ColorQuad::dragEnterEvent(QDragEnterEvent *e) {
if (e->mimeData()->hasFormat("application/x-colorquad") && e->source() != this)
e->acceptProposedAction();
}
void ColorQuad::dropEvent(QDropEvent *e) {
e->setDropAction(Qt::CopyAction);
e->accept();
QDataStream dataStream(e->mimeData()->data("application/x-colorquad"));
QRgb color;
for (int i = 0; i < 4; ++i) {
dataStream >> color;
setColor(i, color);
}
pickerChanged();
}
void ColorQuad::mousePressEvent(QMouseEvent */*e*/) {
QByteArray itemData;
QDataStream dataStream(&itemData, QIODevice::WriteOnly);
for (int i = 0; i < 4; ++i)
dataStream << getColor(i);
QMimeData *const mimeData = new QMimeData;
mimeData->setData("application/x-colorquad", itemData);
QDrag *const drag = new QDrag(this);
drag->setMimeData(mimeData);
drag->exec(Qt::CopyAction);
}
class ImmutableStringListModel : public QStringListModel {
public:
ImmutableStringListModel(QObject *parent = 0) : QStringListModel(parent) {}
ImmutableStringListModel(const QStringList &strings, QObject *parent = 0) : QStringListModel(strings, parent) {}
Qt::ItemFlags flags(const QModelIndex &index) const { return QStringListModel::flags(index) & ~Qt::ItemIsEditable; }
};
static void setSchemeList(const QString &savedir, const bool hasGlobal, QStringListModel *const model) {
QDir dir(savedir, "*.pal", QDir::Name | QDir::IgnoreCase, QDir::Files | QDir::Readable);
QStringList dirlisting(dir.entryList());
for (QStringList::iterator it = dirlisting.begin(); it != dirlisting.end(); ++it)
it->chop(4);
model->setStringList((hasGlobal ? QStringList("Global Palette") : QStringList()) + QStringList("Current Scheme") + QStringList("Default Grey") + dirlisting);
}
static const QModelIndex schemeIndexOf(const QAbstractItemModel *const model, const QString &schemeStr) {
const int rows = model->rowCount();
for (int i = 0; i < rows; ++i) {
if (model->index(i, 0).data().toString() == schemeStr)
return model->index(i, 0);
}
return QModelIndex();
}
PaletteDialog::PaletteDialog(const QString &savepath, const PaletteDialog *global, QWidget *parent)
: QDialog(parent), global(global), listView(new QListView), rmSchemeButton(new QPushButton("Remove Scheme"))
{
setWindowTitle(global ? "Current ROM Palette" : "Global Palette");
QBoxLayout *const mainLayout = new QVBoxLayout;
{
QBoxLayout *const topLayout = new QHBoxLayout;
{
QGroupBox *const lframe = new QGroupBox("Scheme");
QBoxLayout *const frameLayout = new QVBoxLayout;
savedir = savepath + "/";
QDir::root().mkpath(savedir + "stored/");
listView->setModel(new ImmutableStringListModel);
setSchemeList(savedir + "stored/", global, reinterpret_cast<QStringListModel*>(listView->model()));
frameLayout->addWidget(listView);
{
QPushButton *const saveButton = new QPushButton("Save Scheme...");
connect(saveButton, SIGNAL(clicked()), this, SLOT(saveScheme()));
frameLayout->addWidget(saveButton);
}
connect(rmSchemeButton, SIGNAL(clicked()), this, SLOT(rmScheme()));
frameLayout->addWidget(rmSchemeButton);
lframe->setLayout(frameLayout);
topLayout->addWidget(lframe);
}
{
QBoxLayout *const vLayout = new QVBoxLayout;
vLayout->addWidget(quads[0] = new ColorQuad("Background"));
vLayout->addWidget(quads[1] = new ColorQuad("Sprite 1"));
vLayout->addWidget(quads[2] = new ColorQuad("Sprite 2"));
topLayout->addLayout(vLayout);
// topLayout->setAlignment(vLayout, Qt::AlignTop);
}
mainLayout->addLayout(topLayout);
}
{
QPushButton *const okButton = new QPushButton(tr("OK"));
QPushButton *const cancelButton = new QPushButton(tr("Cancel"));
okButton->setDefault(true);
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
QBoxLayout *const hLayout = new QHBoxLayout;
hLayout->addWidget(okButton);
hLayout->addWidget(cancelButton);
mainLayout->addLayout(hLayout);
mainLayout->setAlignment(hLayout, Qt::AlignBottom | Qt::AlignRight);
}
setLayout(mainLayout);
for (int i = 0; i < 3; ++i)
connect(quads[i], SIGNAL(colorChanged()), listView->selectionModel(), SLOT(clear()));
connect(listView->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(schemeChanged(const QModelIndex&, const QModelIndex&)));
if (global) {
schemeIndex = schemeIndexOf(listView->model(), "Global Palette");
restore();
store();
} else {
QSettings settings;
settings.beginGroup("palette");
loadSettings(settings);
settings.endGroup();
}
}
PaletteDialog::~PaletteDialog() {
if (global) {
saveToSettingsFile();
} else {
QSettings settings;
settings.beginGroup("palette");
saveSettings(settings);
settings.endGroup();
}
}
void PaletteDialog::saveSettings(QSettings &settings) {
settings.setValue("slectedScheme", schemeIndex.data());
for (unsigned i = 0; i < 3; ++i)
for (unsigned j = 0; j < 4; ++j)
settings.setValue(quads[i]->title() + QString::number(j), currentColors[i][j]);
}
void PaletteDialog::loadSettings(QSettings &settings) {
schemeIndex = schemeIndexOf(listView->model(), settings.value("slectedScheme", global ? "Global Palette" : "Default Grey").toString());
if (!schemeIndex.isValid())
schemeIndex = schemeIndexOf(listView->model(), "Current Scheme");
for (unsigned i = 0; i < 3; ++i)
for (unsigned j = 0; j < 4; ++j)
currentColors[i][j] = qvariant_cast<QRgb>(settings.value(quads[i]->title() + QString::number(j), (3 - (j & 3)) * 85 * 0x010101));
restore();
store();
}
void PaletteDialog::saveToSettingsFile() {
if (!settingsFile.isEmpty()) {
if (schemeIndex.data().toString() == "Global Palette") {
QDir(savedir).remove(settingsFile);
} else {
QSettings settings(savedir + settingsFile, QSettings::IniFormat);
saveSettings(settings);
}
}
}
void PaletteDialog::rmScheme() {
{
QDir(savedir + "stored/").remove(listView->currentIndex().data().toString() + ".pal");
}
listView->selectionModel()->clear();
setSchemeList(savedir + "stored/", global, reinterpret_cast<QStringListModel*>(listView->model()));
}
void PaletteDialog::saveScheme() {
bool ok;
const QString &text = QInputDialog::getText(this, "Save Scheme", "Scheme name:",
QLineEdit::Normal, QString(), &ok);
if (!ok)
return;
if (text.isEmpty() || "Global Palette" == text || "Current Scheme" == text || "Default Grey" == text || text.contains('/')) {
QMessageBox::information(this, "Invalid scheme name", "Invalid scheme name.");
return;
}
{
QSettings settings(savedir + "stored/" + text + ".pal", QSettings::IniFormat);
for (unsigned i = 0; i < 3; ++i)
for (unsigned j = 0; j < 4; ++j)
settings.setValue(quads[i]->title() + QString::number(j), quads[i]->getColor(j));
}
setSchemeList(savedir + "stored/", global, reinterpret_cast<QStringListModel*>(listView->model()));
listView->setCurrentIndex(schemeIndexOf(listView->model(), text));
}
void PaletteDialog::schemeChanged(const QModelIndex &current, const QModelIndex &/*previous*/) {
rmSchemeButton->setEnabled(false);
if (!current.isValid())
return;
const QString &str = current.data().toString();
if ("Global Palette" == str) {
for (unsigned i = 0; i < 3; ++i)
for (unsigned j = 0; j < 4; ++j)
quads[i]->setColor(j, global->getColor(i, j));
} else if ("Current Scheme" == str) {
for (unsigned i = 0; i < 3; ++i)
for (unsigned j = 0; j < 4; ++j)
quads[i]->setColor(j, currentColors[i][j]);
} else if("Default Grey" == str) {
for (unsigned i = 0; i < 3; ++i)
for (unsigned j = 0; j < 4; ++j)
quads[i]->setColor(j, (3 - (j & 3)) * 85 * 0x010101);
} else {
QSettings settings(savedir + "stored/" + str + ".pal", QSettings::IniFormat);
for (unsigned i = 0; i < 3; ++i)
for (unsigned j = 0; j < 4; ++j)
quads[i]->setColor(j, qvariant_cast<QRgb>(settings.value(quads[i]->title() + QString::number(j), 0)));
rmSchemeButton->setEnabled(true);
}
}
void PaletteDialog::store() {
for (unsigned i = 0; i < 3; ++i)
for (unsigned j = 0; j < 4; ++j)
currentColors[i][j] = quads[i]->getColor(j);
if (!listView->currentIndex().isValid())
listView->setCurrentIndex(schemeIndexOf(listView->model(), "Current Scheme")); //obs: will emit currentChanged()
schemeIndex = listView->currentIndex();
}
void PaletteDialog::restore() {
listView->setCurrentIndex(schemeIndex);
}
void PaletteDialog::externalChange() {
const QString &str = schemeIndex.data().toString();
setSchemeList(savedir + "stored/", global, reinterpret_cast<QStringListModel*>(listView->model()));
listView->setCurrentIndex(schemeIndexOf(listView->model(), str));
store();
}
void PaletteDialog::setSettingsFile(const QString &filename) {
saveToSettingsFile();
settingsFile = filename;
QSettings settings(savedir + settingsFile, QSettings::IniFormat);
loadSettings(settings);
}
void PaletteDialog::accept() {
store();
QDialog::accept();
}
void PaletteDialog::reject() {
restore();
QDialog::reject();
}

View File

@ -0,0 +1,120 @@
/***************************************************************************
* Copyright (C) 2007 by Sindre Aamås *
* aamas@stud.ntnu.no *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License version 2 as *
* published by the Free Software Foundation. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License version 2 for more details. *
* *
* You should have received a copy of the GNU General Public License *
* version 2 along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef PALETTEDIALOG_H
#define PALETTEDIALOG_H
class QListView;
class QPushButton;
class QSettings;
#include <QDialog>
#include <QColor>
#include <QFrame>
#include <QPoint>
#include <QSize>
#include <QGroupBox>
#include <QModelIndex>
#include <QString>
class ColorPicker : public QFrame {
Q_OBJECT
QWidget *const w;
QPoint dragStartPosition;
const QColor& getQColor() const;
void requestColor();
void setColor(const QColor &color);
protected:
void dragEnterEvent(QDragEnterEvent *e);
void dropEvent(QDropEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void keyReleaseEvent(QKeyEvent *e);
public:
ColorPicker(QRgb color = 0xFFFFFF, QWidget *parent = 0);
QRgb getColor() const;
void setColor(QRgb rgb32);
QSize sizeHint() const { return QSize(4*6, 3*6); }
signals:
void colorChanged();
};
class ColorQuad : public QGroupBox {
Q_OBJECT
ColorPicker* picker[4];
private slots:
void pickerChanged();
protected:
void dragEnterEvent(QDragEnterEvent *e);
void dropEvent(QDropEvent *e);
void mousePressEvent(QMouseEvent *e);
public:
ColorQuad(const QString &label, QWidget *parent = 0);
QRgb getColor(unsigned index) const { return picker[index & 3]->getColor(); }
void setColor(unsigned index, QRgb color) { picker[index & 3]->setColor(color); }
signals:
void colorChanged();
};
class PaletteDialog : public QDialog {
Q_OBJECT
const PaletteDialog *const global;
QListView *const listView;
QPushButton *const rmSchemeButton;
ColorQuad *quads[3];
QRgb currentColors[3][4];
QModelIndex schemeIndex;
QString savedir;
QString settingsFile;
void saveSettings(QSettings &settings);
void loadSettings(QSettings &settings);
void saveToSettingsFile();
void store();
void restore();
private slots:
void rmScheme();
void saveScheme();
void schemeChanged(const QModelIndex &current, const QModelIndex &previous);
public:
PaletteDialog(const QString &savepath, const PaletteDialog *global = 0, QWidget *parent = 0);
~PaletteDialog();
QRgb getColor(unsigned palnum, unsigned colornum) const { return currentColors[palnum < 3 ? palnum : 2][colornum & 3]; }
void externalChange();
void setSettingsFile(const QString &filename);
public slots:
void accept();
void reject();
};
#endif

View File

@ -13,7 +13,8 @@ SOURCES += gambatte_qt.cpp \
SDL_Joystick/src/SDL_joystick.c \
SDL_Joystick/src/SDL_string.c \
sounddialog.cpp \
audioengines/customdevconf.cpp
audioengines/customdevconf.cpp \
palettedialog.cpp
HEADERS += gambatte_qt.h \
blitterwidget.h \
@ -42,7 +43,8 @@ SDL_Joystick/src/SDL_joystick_c.h \
SDL_Joystick/src/SDL_sysjoystick.h \
sounddialog.h \
audioengines/nullaudioengine.h \
audioengines/customdevconf.h
audioengines/customdevconf.h \
palettedialog.h
TEMPLATE = app
CONFIG += warn_on \

View File

@ -40,6 +40,7 @@ public:
void videoBufferChange();
unsigned int videoWidth() const;
unsigned int videoHeight() const;
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32);
void setVideoFilter(unsigned int n);
std::vector<const FilterInfo*> filterInfo() const;
@ -48,6 +49,7 @@ public:
void fill_buffer(uint16_t *stream, unsigned samples);
void set_savedir(const char *sdir);
bool isCgb() const;
};
#endif

View File

@ -88,6 +88,12 @@ public:
void sound_fill_buffer(uint16_t *const stream, const unsigned samples) {
memory.sound_fill_buffer(stream, samples, cycleCounter_);
}
bool isCgb() const { return memory.isCgb(); }
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32) {
memory.setDmgPaletteColor(palNum, colorNum, rgb32, cycleCounter_);
}
};
#endif

View File

@ -73,3 +73,11 @@ bool Gambatte::load(const char* romfile) {
void Gambatte::fill_buffer(uint16_t *const stream, const unsigned samples) {
z80->sound_fill_buffer(stream, samples);
}
bool Gambatte::isCgb() const {
return z80->isCgb();
}
void Gambatte::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32) {
z80->setDmgPaletteColor(palNum, colorNum, rgb32);
}

View File

@ -1981,6 +1981,11 @@ void Memory::setVideoFilter(const unsigned int n, const unsigned cycleCounter) {
refreshPalettes(cycleCounter);
}
void Memory::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32, unsigned cycleCounter) {
display.setDmgPaletteColor(palNum, colorNum, rgb32);
refreshPalettes(cycleCounter);
}
Memory::~Memory() {
if (battery)
saveram();

View File

@ -181,6 +181,8 @@ public:
std::vector<const FilterInfo*> filterInfo() const {
return display.filterInfo();
}
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32, unsigned cycleCounter);
};
#endif

View File

@ -27,6 +27,7 @@
#include "video/basic_add_event.h"
/*
const uint32_t LCD::dmgColorsRgb32[4] = { 3 * 85 * 0x010101, 2 * 85 * 0x010101, 1 * 85 * 0x010101, 0 * 85 * 0x010101 };
const uint32_t LCD::dmgColorsRgb16[4] = { 3 * 10 * 0x0841, 2 * 10 * 0x0841, 1 * 10 * 0x0841, 0 * 10 * 0x0841 };
@ -43,6 +44,7 @@ const uint32_t LCD::dmgColorsUyvy[4] = {
0x00800080 | (16 + 73 * 1) * 0x01000100U,
0x00800080 | (16 + 73 * 0) * 0x01000100U };
#endif
*/
void LCD::setDmgPalette(uint32_t *const palette, const uint32_t *const dmgColors, const unsigned data) {
palette[0] = dmgColors[data & 3];
@ -113,6 +115,10 @@ LCD::LCD(const uint8_t *const oamram, const uint8_t *const vram_in) :
pb.format = PixelBuffer::RGB32;
pb.pitch = 0;
for (unsigned i = 0; i < sizeof(dmgColorsRgb32) / sizeof(uint32_t); ++i) {
setDmgPaletteColor(i, (3 - (i & 3)) * 85 * 0x010101);
}
filters.push_back(NULL);
filters.push_back(new Catrom2x);
filters.push_back(new Catrom3x);
@ -983,6 +989,19 @@ void LCD::setDBuffer() {
draw = &LCD::null_draw;
}
void LCD::setDmgPaletteColor(const unsigned index, const unsigned rgb32) {
dmgColorsRgb32[index] = rgb32;
dmgColorsRgb16[index] = Rgb16Putter::toRgb16(rgb32);
dmgColorsUyvy[index] = UyvyPutter::toUyvy(rgb32);
}
void LCD::setDmgPaletteColor(const unsigned palNum, const unsigned colorNum, const unsigned rgb32) {
if (palNum > 2 || colorNum > 3)
return;
setDmgPaletteColor(palNum * 4 | colorNum, rgb32);
}
void LCD::null_draw(unsigned /*xpos*/, const unsigned ypos, const unsigned endX) {
const bool enableWindow = (weMasterChecker.weMaster() || ypos == wyReg.value()) && we.value() && wyReg.value() <= ypos && wxReader.wx() < 0xA7;

View File

@ -51,9 +51,9 @@ class Filter;
class LCD {
//static const uint8_t xflipt[0x100];
static const uint32_t dmgColorsRgb32[4];
static const uint32_t dmgColorsRgb16[4];
static const uint32_t dmgColorsUyvy[4];
uint32_t dmgColorsRgb32[3 * 4];
uint32_t dmgColorsRgb16[3 * 4];
uint32_t dmgColorsUyvy[3 * 4];
uint32_t bgPalette[8 * 4];
uint32_t spPalette[8 * 4];
@ -120,6 +120,7 @@ class LCD {
bool spriteEnable;
static void setDmgPalette(uint32_t *palette, const uint32_t *dmgColors, unsigned data);
void setDmgPaletteColor(unsigned index, unsigned rgb32);
static unsigned gbcToRgb32(unsigned bgr15);
static unsigned gbcToRgb16(unsigned bgr15);
static unsigned gbcToUyvy(unsigned bgr15);
@ -160,6 +161,7 @@ public:
std::vector<const FilterInfo*> filterInfo() const;
unsigned int videoWidth() const;
unsigned int videoHeight() const;
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32);
void wdTileMapSelectChange(bool newValue, unsigned cycleCounter);
void bgTileMapSelectChange(bool newValue, unsigned cycleCounter);
@ -174,12 +176,12 @@ public:
void dmgSpPalette1Change(const unsigned data, const unsigned cycleCounter) {
update(cycleCounter);
setDmgPalette(spPalette, dmgColors, data);
setDmgPalette(spPalette, dmgColors + 4, data);
}
void dmgSpPalette2Change(const unsigned data, const unsigned cycleCounter) {
update(cycleCounter);
setDmgPalette(spPalette + 4, dmgColors, data);
setDmgPalette(spPalette + 4, dmgColors + 8, data);
}
void cgbBgColorChange(const unsigned index, const unsigned bgr15, const unsigned cycleCounter) {

View File

@ -34,26 +34,43 @@ class Rgb16Putter {
public:
typedef uint16_t pixel_t;
static unsigned toRgb16(const unsigned rgb32) {
return rgb32 >> 8 & 0xF800 | rgb32 >> 5 & 0x07E0 | rgb32 >> 3 & 0x001F;
}
void operator()(pixel_t *const dest, const unsigned rgb32) {
// const unsigned tmp = (rgb32 & 0xFCFEFC) + 0x040204;
const unsigned tmp = rgb32;
*dest = tmp >> 8 & 0xF800 | tmp >> 5 & 0x07E0 | tmp >> 3 & 0x001F;
*dest = toRgb16(rgb32);
}
};
class UyvyPutter {
public:
typedef uint32_t pixel_t;
void operator()(pixel_t *const dest, const unsigned rgb32) {
static void convert(unsigned &y, unsigned &u, unsigned &v, const unsigned rgb32) {
const unsigned r = rgb32 >> 16;
const unsigned g = rgb32 >> 8 & 0xFF;
const unsigned b = rgb32 & 0xFF;
const unsigned y = r * 66 + g * 129 + b * 25 + 16 * 256 + 128 >> 8;
const unsigned u = b * 112 - r * 38 - g * 74 + 128 * 256 + 128 >> 8;
const unsigned v = r * 112 - g * 94 - b * 18 + 128 * 256 + 128 >> 8;
y = r * 66 + g * 129 + b * 25 + 16 * 256 + 128 >> 8;
u = b * 112 - r * 38 - g * 74 + 128 * 256 + 128 >> 8;
v = r * 112 - g * 94 - b * 18 + 128 * 256 + 128 >> 8;
}
public:
typedef uint32_t pixel_t;
static unsigned toUyvy(const unsigned rgb32) {
unsigned y, u, v;
convert(y, u, v, rgb32);
#ifdef WORDS_BIGENDIAN
return u << 24 | y << 16 | v << 8 | y;
#else
return y << 24 | v << 16 | y << 8 | u;
#endif
}
void operator()(pixel_t *const dest, const unsigned rgb32) {
unsigned y, u, v;
convert(y, u, v, rgb32);
uint8_t * d = reinterpret_cast<uint8_t*>(dest);
*d++ = u;