mirror of
https://github.com/libretro/gambatte-libretro.git
synced 2024-11-23 07:49:48 +00:00
save state selection
save state osd preview snapshots fix a few potential security holes when loading invalid state get rid of some undefined behaviour in statesaver always draw in rgb32, color convert afterwards, too bad for maemo/16-bit depth users get rid of silly c string stuff git-svn-id: https://gambatte.svn.sourceforge.net/svnroot/gambatte@142 9dfb2916-2d38-0410-aef4-c5fe6c9ffc24
This commit is contained in:
parent
3dda26e19b
commit
686e286d6a
@ -635,9 +635,6 @@ int GambatteSdl::exec() {
|
||||
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
if (e.key.keysym.sym == SDLK_ESCAPE)
|
||||
return 0;
|
||||
|
||||
if (e.key.keysym.mod & KMOD_CTRL) {
|
||||
switch (e.key.keysym.sym) {
|
||||
case SDLK_f:
|
||||
@ -649,6 +646,15 @@ int GambatteSdl::exec() {
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
} else {
|
||||
switch (e.key.keysym.sym) {
|
||||
case SDLK_ESCAPE: return 0;
|
||||
case SDLK_F5: gambatte.saveState(); break;
|
||||
case SDLK_F6: gambatte.selectState(gambatte.currentState() - 1); break;
|
||||
case SDLK_F7: gambatte.selectState(gambatte.currentState() + 1); break;
|
||||
case SDLK_F8: gambatte.loadState(); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
case SDL_KEYUP:
|
||||
for (std::pair<keymap_t::iterator,keymap_t::iterator> range(keyMap.equal_range(e.key.keysym.sym));
|
||||
|
@ -31,6 +31,7 @@ class CPU;
|
||||
namespace Gambatte {
|
||||
class GB {
|
||||
CPU *const z80;
|
||||
int stateNo;
|
||||
|
||||
public:
|
||||
GB();
|
||||
@ -54,6 +55,8 @@ public:
|
||||
bool isCgb() const;
|
||||
void saveState();
|
||||
void loadState();
|
||||
void selectState(int n);
|
||||
int currentState() const { return stateNo; }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,8 @@
|
||||
#ifndef ARRAY_H
|
||||
#define ARRAY_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
template<typename T>
|
||||
class Array {
|
||||
T *a;
|
||||
|
@ -78,7 +78,7 @@ unsigned long rgb32ToUyvy(unsigned long rgb32) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void rgb32ToRgb16(const Gambatte::uint_least32_t *s, Gambatte::uint_least16_t *d, unsigned w, unsigned h, unsigned dstPitch) {
|
||||
void rgb32ToRgb16(const Gambatte::uint_least32_t *s, Gambatte::uint_least16_t *d, const unsigned w, unsigned h, const unsigned dstPitch) {
|
||||
do {
|
||||
unsigned n = w;
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#define COLORCONVERSION_H
|
||||
|
||||
#include "int.h"
|
||||
#include <algorithm>
|
||||
|
||||
class Rgb32ToUyvy {
|
||||
struct CacheUnit {
|
||||
|
@ -88,6 +88,14 @@ public:
|
||||
memory.set_savedir(sdir);
|
||||
}
|
||||
|
||||
const std::string saveBasePath() const {
|
||||
return memory.saveBasePath();
|
||||
}
|
||||
|
||||
void setOsdElement(std::auto_ptr<OsdElement> osdElement) {
|
||||
memory.setOsdElement(osdElement);
|
||||
}
|
||||
|
||||
bool load(const char* romfile);
|
||||
|
||||
void sound_fill_buffer(Gambatte::uint_least16_t *const stream, const unsigned samples) {
|
||||
|
@ -71,13 +71,3 @@ void File::read(char *buffer, size_t amount)
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t File::size()
|
||||
{
|
||||
return(fsize);
|
||||
}
|
||||
|
||||
size_t File::gcount()
|
||||
{
|
||||
return(count);
|
||||
}
|
||||
|
@ -35,7 +35,8 @@ class File {
|
||||
void rewind();
|
||||
bool is_open();
|
||||
void close();
|
||||
std::size_t size();
|
||||
std::size_t size() const { return fsize; };
|
||||
void read(char *buffer, std::size_t amount);
|
||||
std::size_t gcount();
|
||||
std::size_t gcount() const { return count; }
|
||||
bool fail() const { return stream.fail(); }
|
||||
};
|
||||
|
@ -163,13 +163,3 @@ void File::read(char *buffer, size_t amount)
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t File::size()
|
||||
{
|
||||
return(fsize);
|
||||
}
|
||||
|
||||
size_t File::gcount()
|
||||
{
|
||||
return(count);
|
||||
}
|
||||
|
@ -21,9 +21,55 @@
|
||||
#include "savestate.h"
|
||||
#include "statesaver.h"
|
||||
#include "initstate.h"
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
class SaveStateOsdElement : public OsdElement {
|
||||
Gambatte::uint_least32_t pixels[StateSaver::SS_WIDTH * StateSaver::SS_HEIGHT];
|
||||
unsigned life;
|
||||
|
||||
public:
|
||||
SaveStateOsdElement(const char *fileName, unsigned stateNo);
|
||||
const Gambatte::uint_least32_t* update();
|
||||
};
|
||||
|
||||
SaveStateOsdElement::SaveStateOsdElement(const char *fileName, unsigned stateNo) : OsdElement(stateNo * ((160 - StateSaver::SS_WIDTH) / 10) + ((160 - StateSaver::SS_WIDTH) / 10) / 2, 4, StateSaver::SS_WIDTH, StateSaver::SS_HEIGHT), life(4 * 60) {
|
||||
std::memset(pixels, 0, sizeof(pixels));
|
||||
|
||||
std::ifstream file(fileName);
|
||||
|
||||
if (file.is_open() && file.get() == 0) {
|
||||
file.ignore(4);
|
||||
file.read(reinterpret_cast<char*>(pixels), sizeof(pixels));
|
||||
}
|
||||
}
|
||||
|
||||
const Gambatte::uint_least32_t* SaveStateOsdElement::update() {
|
||||
if (life--)
|
||||
return pixels;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const std::string itos(int i) {
|
||||
std::stringstream ss;
|
||||
|
||||
ss << i;
|
||||
|
||||
std::string out;
|
||||
|
||||
ss >> out;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static const std::string statePath(const std::string &basePath, int stateNo) {
|
||||
return basePath + "_" + itos(stateNo) + ".gqs";
|
||||
}
|
||||
|
||||
namespace Gambatte {
|
||||
GB::GB() : z80(new CPU) {}
|
||||
GB::GB() : z80(new CPU), stateNo(0) {}
|
||||
|
||||
GB::~GB() {
|
||||
delete z80;
|
||||
@ -82,11 +128,13 @@ bool GB::load(const char* romfile) {
|
||||
|
||||
const bool failed = z80->load(romfile);
|
||||
|
||||
SaveState state;
|
||||
z80->setStatePtrs(state);
|
||||
setInitState(state, z80->isCgb());
|
||||
z80->loadState(state);
|
||||
z80->loadSavedata();
|
||||
if (!failed) {
|
||||
SaveState state;
|
||||
z80->setStatePtrs(state);
|
||||
setInitState(state, z80->isCgb());
|
||||
z80->loadState(state);
|
||||
z80->loadSavedata();
|
||||
}
|
||||
|
||||
return failed;
|
||||
}
|
||||
@ -107,7 +155,7 @@ void GB::saveState() {
|
||||
SaveState state;
|
||||
z80->setStatePtrs(state);
|
||||
z80->saveState(state);
|
||||
StateSaver::saveState(state, "test.gqs");
|
||||
StateSaver::saveState(state, statePath(z80->saveBasePath(), stateNo).c_str());
|
||||
}
|
||||
|
||||
void GB::loadState() {
|
||||
@ -115,7 +163,14 @@ void GB::loadState() {
|
||||
|
||||
SaveState state;
|
||||
z80->setStatePtrs(state);
|
||||
StateSaver::loadState(state, "test.gqs");
|
||||
z80->loadState(state);
|
||||
|
||||
if (StateSaver::loadState(state, statePath(z80->saveBasePath(), stateNo).c_str()))
|
||||
z80->loadState(state);
|
||||
}
|
||||
|
||||
void GB::selectState(int n) {
|
||||
n -= (n / 10) * 10;
|
||||
stateNo = n < 0 ? n + 10 : n;
|
||||
z80->setOsdElement(std::auto_ptr<OsdElement>(new SaveStateOsdElement(statePath(z80->saveBasePath(), stateNo).c_str(), stateNo)));
|
||||
}
|
||||
}
|
||||
|
@ -37,9 +37,6 @@ oamDmaSrc(NULL),
|
||||
vrambank(vram),
|
||||
rsrambankptr(NULL),
|
||||
wsrambankptr(NULL),
|
||||
romfile(NULL),
|
||||
savedir(NULL),
|
||||
savename(NULL),
|
||||
getInput(NULL),
|
||||
div_lastUpdate(0),
|
||||
tima_lastUpdate(0),
|
||||
@ -135,10 +132,10 @@ void Memory::loadState(const SaveState &state, const unsigned long oldCc) {
|
||||
next_serialtime = state.mem.next_serialtime;
|
||||
lastOamDmaUpdate = state.mem.lastOamDmaUpdate;
|
||||
minIntTime = state.mem.minIntTime;
|
||||
rombank = state.mem.rombank;
|
||||
rombank = state.mem.rombank % rombanks;
|
||||
dmaSource = state.mem.dmaSource;
|
||||
dmaDestination = state.mem.dmaDestination;
|
||||
rambank = state.mem.rambank;
|
||||
rambank = state.mem.rambank & rambanks - 1;
|
||||
oamDmaPos = state.mem.oamDmaPos;
|
||||
IME = state.mem.IME;
|
||||
enable_ram = state.mem.enable_ram;
|
||||
@ -1544,15 +1541,15 @@ void Memory::nontrivial_write(const unsigned P, const unsigned data, const unsig
|
||||
ioamhram[P - 0xFE00] = data;
|
||||
}
|
||||
|
||||
bool Memory::loadROM(const char* file) {
|
||||
delete []romfile;
|
||||
romfile = new char[std::strlen(file) + 1];
|
||||
std::strcpy(romfile, file);
|
||||
|
||||
return loadROM();
|
||||
static void enforce8bit(unsigned char *data, unsigned long sz) {
|
||||
if (static_cast<unsigned char>(0x100))
|
||||
while (sz--)
|
||||
*data++ &= 0xFF;
|
||||
}
|
||||
|
||||
bool Memory::loadROM() {
|
||||
bool Memory::loadROM(const char *romfile) {
|
||||
romFilePath = romfile;
|
||||
|
||||
File rom(romfile);
|
||||
|
||||
if (!rom.is_open()) {
|
||||
@ -1748,22 +1745,10 @@ bool Memory::loadROM() {
|
||||
|
||||
rom.rewind();
|
||||
rom.read(reinterpret_cast<char*>(romdata[0]), rombanks * 0x4000ul);
|
||||
rom.close();
|
||||
|
||||
{
|
||||
char *tmp = std::strrchr(romfile, '/');
|
||||
|
||||
if (tmp == NULL || savedir == NULL)
|
||||
tmp = romfile;
|
||||
else
|
||||
++tmp;
|
||||
|
||||
const unsigned int namelen = std::strrchr(tmp, '.') == NULL ? std::strlen(tmp) : std::strrchr(tmp, '.') - tmp;
|
||||
delete []savename;
|
||||
savename = new char[namelen + 1];
|
||||
std::strncpy(savename, tmp, namelen);
|
||||
savename[namelen] = '\0';
|
||||
}
|
||||
enforce8bit(romdata[0], rombanks * 0x4000ul);
|
||||
|
||||
if (rom.fail())
|
||||
return 1;
|
||||
|
||||
sound.init(isCgb());
|
||||
display.reset(isCgb());
|
||||
@ -1772,108 +1757,82 @@ bool Memory::loadROM() {
|
||||
}
|
||||
|
||||
void Memory::loadSavedata() {
|
||||
const std::string &sbp = saveBasePath();
|
||||
|
||||
if (battery) {
|
||||
char *savefile;
|
||||
std::ifstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::in);
|
||||
|
||||
if (savedir != NULL) {
|
||||
savefile = new char[5 + std::strlen(savedir) + std::strlen(savename)];
|
||||
std::sprintf(savefile, "%s%s.sav", savedir, savename);
|
||||
} else {
|
||||
savefile = new char[5 + std::strlen(savename)];
|
||||
std::sprintf(savefile, "%s.sav", savename);
|
||||
if (file.is_open()) {
|
||||
file.read(reinterpret_cast<char*>(rambankdata), rambanks * 0x2000ul);
|
||||
enforce8bit(rambankdata, rambanks * 0x2000ul);
|
||||
}
|
||||
|
||||
std::ifstream load(savefile, std::ios::binary | std::ios::in);
|
||||
|
||||
if (load.is_open()) {
|
||||
load.read(reinterpret_cast<char*>(rambankdata), rambanks * 0x2000ul);
|
||||
load.close();
|
||||
}
|
||||
//else cout << "No savefile available\n";
|
||||
delete []savefile;
|
||||
}
|
||||
|
||||
if (rtcRom) {
|
||||
char *savefile;
|
||||
std::ifstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::in);
|
||||
|
||||
if (savedir != NULL) {
|
||||
savefile = new char[5 + std::strlen(savedir) + std::strlen(savename)];
|
||||
std::sprintf(savefile, "%s%s.rtc", savedir, savename);
|
||||
} else {
|
||||
savefile = new char[5 + std::strlen(savename)];
|
||||
std::sprintf(savefile, "%s.rtc", savename);
|
||||
}
|
||||
|
||||
std::ifstream load(savefile, std::ios::binary | std::ios::in);
|
||||
|
||||
if (load.is_open()) {
|
||||
std::time_t basetime;
|
||||
load.read(reinterpret_cast<char*>(&basetime), sizeof(basetime));
|
||||
load.close();
|
||||
if (file.is_open()) {
|
||||
unsigned long basetime = file.get() & 0xFF;
|
||||
|
||||
basetime = basetime << 8 | file.get() & 0xFF;
|
||||
basetime = basetime << 8 | file.get() & 0xFF;
|
||||
basetime = basetime << 8 | file.get() & 0xFF;
|
||||
|
||||
rtc.setBaseTime(basetime);
|
||||
}
|
||||
|
||||
delete []savefile;
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::saveSavedata() {
|
||||
const std::string &sbp = saveBasePath();
|
||||
|
||||
if (battery) {
|
||||
char *savefile;
|
||||
std::ofstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::out);
|
||||
|
||||
if (savedir != NULL) {
|
||||
savefile = new char[5 + std::strlen(savedir) + std::strlen(savename)];
|
||||
std::sprintf(savefile, "%s%s.sav", savedir, savename);
|
||||
} else {
|
||||
savefile = new char[5 + std::strlen(savename)];
|
||||
std::sprintf(savefile, "%s.sav", savename);
|
||||
}
|
||||
|
||||
std::ofstream save(savefile, std::ios::binary | std::ios::out);
|
||||
|
||||
if (save.is_open()) {
|
||||
save.write(reinterpret_cast<char*>(rambankdata), rambanks * 0x2000ul);
|
||||
save.close();
|
||||
} /*else cout << "Saving ramdata failed\n";*/
|
||||
|
||||
delete []savefile;
|
||||
file.write(reinterpret_cast<const char*>(rambankdata), rambanks * 0x2000ul);
|
||||
}
|
||||
|
||||
if (rtcRom) {
|
||||
char *savefile;
|
||||
std::ofstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::out);
|
||||
const unsigned long basetime = rtc.getBaseTime();
|
||||
|
||||
if (savedir != NULL) {
|
||||
savefile = new char[5 + std::strlen(savedir) + std::strlen(savename)];
|
||||
std::sprintf(savefile, "%s%s.rtc", savedir, savename);
|
||||
} else {
|
||||
savefile = new char[5 + std::strlen(savename)];
|
||||
std::sprintf(savefile, "%s.rtc", savename);
|
||||
}
|
||||
|
||||
std::ofstream save(savefile, std::ios::binary | std::ios::out);
|
||||
|
||||
if (save.is_open()) {
|
||||
std::time_t basetime = rtc.getBaseTime();
|
||||
save.write(reinterpret_cast<char*>(&basetime), sizeof(basetime));
|
||||
save.close();
|
||||
} /*else cout << "Saving rtcdata failed\n";*/
|
||||
|
||||
delete []savefile;
|
||||
file.put(basetime >> 24 & 0xFF);
|
||||
file.put(basetime >> 16 & 0xFF);
|
||||
file.put(basetime >> 8 & 0xFF);
|
||||
file.put(basetime & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::set_savedir(const char *dir) {
|
||||
delete []savedir;
|
||||
savedir = NULL;
|
||||
static const std::string stripExtension(const std::string &str) {
|
||||
const std::string::size_type lastDot = str.find_last_of('.');
|
||||
const std::string::size_type lastSlash = str.find_last_of('/');
|
||||
|
||||
if (lastDot != std::string::npos && (lastSlash == std::string::npos || lastSlash < lastDot))
|
||||
return str.substr(0, lastDot);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
if (dir != NULL) {
|
||||
savedir = new char[std::strlen(dir) + 2];
|
||||
std::strcpy(savedir, dir);
|
||||
|
||||
if (savedir[std::strlen(dir) - 1] != '/') {
|
||||
savedir[std::strlen(dir)] = '/';
|
||||
savedir[std::strlen(dir) + 1] = '\0';
|
||||
}
|
||||
static const std::string stripDir(const std::string &str) {
|
||||
const std::string::size_type lastSlash = str.find_last_of('/');
|
||||
|
||||
if (lastSlash != std::string::npos)
|
||||
return str.substr(lastSlash + 1);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
const std::string Memory::saveBasePath() const {
|
||||
const std::string &extStrippedFilePath = stripExtension(romFilePath);
|
||||
|
||||
return saveDir.empty() ? extStrippedFilePath : saveDir + stripDir(extStrippedFilePath);
|
||||
}
|
||||
|
||||
void Memory::set_savedir(const char *dir) {
|
||||
saveDir = dir ? dir : "";
|
||||
|
||||
if (!saveDir.empty() && saveDir[saveDir.length() - 1] != '/') {
|
||||
saveDir += '/';
|
||||
}
|
||||
}
|
||||
|
||||
@ -1901,8 +1860,5 @@ void Memory::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned lon
|
||||
Memory::~Memory() {
|
||||
saveSavedata();
|
||||
|
||||
delete []romfile;
|
||||
delete []savedir;
|
||||
delete []savename;
|
||||
delete []memchunk;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ class SaveState;
|
||||
|
||||
#include "interrupter.h"
|
||||
#include "rtc.h"
|
||||
#include <string>
|
||||
|
||||
namespace Gambatte {
|
||||
class InputStateGetter;
|
||||
@ -57,10 +58,6 @@ private:
|
||||
unsigned char *vrambank;
|
||||
unsigned char *rsrambankptr;
|
||||
unsigned char *wsrambankptr;
|
||||
|
||||
char *romfile;
|
||||
char *savedir;
|
||||
char *savename;
|
||||
|
||||
Gambatte::InputStateGetter *getInput;
|
||||
|
||||
@ -90,6 +87,9 @@ private:
|
||||
irqEvents next_irqEvent;
|
||||
cartridgetype romtype;
|
||||
|
||||
std::string romFilePath;
|
||||
std::string saveDir;
|
||||
|
||||
unsigned short rombanks;
|
||||
unsigned short rombank;
|
||||
unsigned short dmaSource;
|
||||
@ -137,8 +137,6 @@ private:
|
||||
void rescheduleIrq(unsigned long cycleCounter);
|
||||
void rescheduleHdmaReschedule();
|
||||
|
||||
bool loadROM();
|
||||
|
||||
bool isDoubleSpeed() const { return doubleSpeed; }
|
||||
|
||||
public:
|
||||
@ -150,6 +148,11 @@ public:
|
||||
void loadState(const SaveState &state, unsigned long oldCc);
|
||||
void loadSavedata();
|
||||
void saveSavedata();
|
||||
const std::string saveBasePath() const;
|
||||
|
||||
void setOsdElement(std::auto_ptr<OsdElement> osdElement) {
|
||||
display.setOsdElement(osdElement);
|
||||
}
|
||||
|
||||
void speedChange(unsigned long cycleCounter);
|
||||
bool isCgb() const { return cgb; }
|
||||
|
50
libgambatte/src/osd_element.h
Normal file
50
libgambatte/src/osd_element.h
Normal file
@ -0,0 +1,50 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 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 "int.h"
|
||||
|
||||
class OsdElement {
|
||||
unsigned x_;
|
||||
unsigned y_;
|
||||
unsigned w_;
|
||||
unsigned h_;
|
||||
|
||||
protected:
|
||||
OsdElement(unsigned x = 0, unsigned y = 0, unsigned w = 0, unsigned h = 0) {
|
||||
setPos(x, y);
|
||||
setSize(w, h);
|
||||
}
|
||||
|
||||
void setPos(unsigned x, unsigned y) {
|
||||
x_ = x;
|
||||
y_ = y;
|
||||
}
|
||||
|
||||
void setSize(unsigned w, unsigned h) {
|
||||
w_ = w;
|
||||
h_ = h;
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned x() const { return x_; }
|
||||
unsigned y() const { return y_; }
|
||||
unsigned w() const { return w_; }
|
||||
unsigned h() const { return h_; }
|
||||
|
||||
virtual const Gambatte::uint_least32_t* update() = 0;
|
||||
};
|
@ -19,7 +19,7 @@
|
||||
#ifndef SAVESTATE_H
|
||||
#define SAVESTATE_H
|
||||
|
||||
#include <ctime>
|
||||
#include "int.h"
|
||||
|
||||
struct SaveState {
|
||||
template<typename T>
|
||||
@ -76,6 +76,7 @@ struct SaveState {
|
||||
} mem;
|
||||
|
||||
struct PPU {
|
||||
Ptr<Gambatte::uint_least32_t> drawBuffer;
|
||||
Ptr<unsigned char> bgpData;
|
||||
Ptr<unsigned char> objpData;
|
||||
//SpriteMapper::OamReader
|
||||
@ -168,8 +169,8 @@ struct SaveState {
|
||||
} spu;
|
||||
|
||||
struct RTC {
|
||||
std::time_t baseTime;
|
||||
std::time_t haltTime;
|
||||
unsigned long baseTime;
|
||||
unsigned long haltTime;
|
||||
unsigned char index;
|
||||
unsigned char dataDh;
|
||||
unsigned char dataDl;
|
||||
|
@ -95,7 +95,7 @@ void Channel1::SweepUnit::saveState(SaveState &state) const {
|
||||
}
|
||||
|
||||
void Channel1::SweepUnit::loadState(const SaveState &state) {
|
||||
counter = state.spu.ch1.sweep.counter;
|
||||
counter = std::max(state.spu.ch1.sweep.counter, state.spu.cycleCounter);
|
||||
shadow = state.spu.ch1.sweep.shadow;
|
||||
nr0 = state.spu.ch1.sweep.nr0;
|
||||
negging = state.spu.ch1.sweep.negging;
|
||||
@ -202,9 +202,9 @@ void Channel1::saveState(SaveState &state) {
|
||||
|
||||
void Channel1::loadState(const SaveState &state) {
|
||||
sweepUnit.loadState(state);
|
||||
dutyUnit.loadState(state.spu.ch1.duty, state.mem.ioamhram.get()[0x111], state.spu.ch1.nr4);
|
||||
envelopeUnit.loadState(state.spu.ch1.env, state.mem.ioamhram.get()[0x112]);
|
||||
lengthCounter.loadState(state.spu.ch1.lcounter);
|
||||
dutyUnit.loadState(state.spu.ch1.duty, state.mem.ioamhram.get()[0x111], state.spu.ch1.nr4, state.spu.cycleCounter);
|
||||
envelopeUnit.loadState(state.spu.ch1.env, state.mem.ioamhram.get()[0x112], state.spu.cycleCounter);
|
||||
lengthCounter.loadState(state.spu.ch1.lcounter, state.spu.cycleCounter);
|
||||
|
||||
cycleCounter = state.spu.cycleCounter;
|
||||
nr4 = state.spu.ch1.nr4;
|
||||
|
@ -107,9 +107,9 @@ void Channel2::saveState(SaveState &state) {
|
||||
}
|
||||
|
||||
void Channel2::loadState(const SaveState &state) {
|
||||
dutyUnit.loadState(state.spu.ch2.duty, state.mem.ioamhram.get()[0x116], state.spu.ch2.nr4);
|
||||
envelopeUnit.loadState(state.spu.ch2.env, state.mem.ioamhram.get()[0x117]);
|
||||
lengthCounter.loadState(state.spu.ch2.lcounter);
|
||||
dutyUnit.loadState(state.spu.ch2.duty, state.mem.ioamhram.get()[0x116], state.spu.ch2.nr4,state.spu.cycleCounter);
|
||||
envelopeUnit.loadState(state.spu.ch2.env, state.mem.ioamhram.get()[0x117], state.spu.cycleCounter);
|
||||
lengthCounter.loadState(state.spu.ch2.lcounter, state.spu.cycleCounter);
|
||||
|
||||
cycleCounter = state.spu.cycleCounter;
|
||||
nr4 = state.spu.ch2.nr4;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "channel3.h"
|
||||
#include "../savestate.h"
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
static inline unsigned toPeriod(const unsigned nr3, const unsigned nr4) {
|
||||
return 0x800 - (nr4 << 8 & 0x700 | nr3);
|
||||
@ -109,14 +110,14 @@ void Channel3::saveState(SaveState &state) const {
|
||||
}
|
||||
|
||||
void Channel3::loadState(const SaveState &state) {
|
||||
lengthCounter.loadState(state.spu.ch3.lcounter);
|
||||
lengthCounter.loadState(state.spu.ch3.lcounter, state.spu.cycleCounter);
|
||||
|
||||
cycleCounter = state.spu.cycleCounter;
|
||||
waveCounter = state.spu.ch3.waveCounter;
|
||||
waveCounter = std::max(state.spu.ch3.waveCounter, state.spu.cycleCounter);
|
||||
lastReadTime = state.spu.ch3.lastReadTime;
|
||||
nr3 = state.spu.ch3.nr3;
|
||||
nr4 = state.spu.ch3.nr4;
|
||||
wavePos = state.spu.ch3.wavePos;
|
||||
wavePos = state.spu.ch3.wavePos & 0x1F;
|
||||
sampleBuf = state.spu.ch3.sampleBuf;
|
||||
master = state.spu.ch3.master;
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
***************************************************************************/
|
||||
#include "channel4.h"
|
||||
#include "../savestate.h"
|
||||
#include <algorithm>
|
||||
|
||||
static unsigned long toPeriod(const unsigned nr3) {
|
||||
unsigned s = (nr3 >> 4) + 3;
|
||||
@ -154,7 +155,7 @@ void Channel4::Lfsr::saveState(SaveState &state, const unsigned long cc) {
|
||||
}
|
||||
|
||||
void Channel4::Lfsr::loadState(const SaveState &state) {
|
||||
counter = backupCounter = state.spu.ch4.lfsr.counter;
|
||||
counter = backupCounter = std::max(state.spu.ch4.lfsr.counter, state.spu.cycleCounter);
|
||||
reg = state.spu.ch4.lfsr.reg;
|
||||
master = state.spu.ch4.master;
|
||||
nr3 = state.mem.ioamhram.get()[0x122];
|
||||
@ -246,8 +247,8 @@ void Channel4::saveState(SaveState &state) {
|
||||
|
||||
void Channel4::loadState(const SaveState &state) {
|
||||
lfsr.loadState(state);
|
||||
envelopeUnit.loadState(state.spu.ch4.env, state.mem.ioamhram.get()[0x121]);
|
||||
lengthCounter.loadState(state.spu.ch4.lcounter);
|
||||
envelopeUnit.loadState(state.spu.ch4.env, state.mem.ioamhram.get()[0x121], state.spu.cycleCounter);
|
||||
lengthCounter.loadState(state.spu.ch4.lcounter, state.spu.cycleCounter);
|
||||
|
||||
cycleCounter = state.spu.cycleCounter;
|
||||
nr4 = state.spu.ch4.nr4;
|
||||
|
@ -17,6 +17,7 @@
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "duty_unit.h"
|
||||
#include <algorithm>
|
||||
|
||||
static inline bool toOutState(const unsigned duty, const unsigned pos) {
|
||||
static const unsigned char duties[4] = { 0x80, 0x81, 0xE1, 0x7E };
|
||||
@ -116,9 +117,9 @@ void DutyUnit::saveState(SaveState::SPU::Duty &dstate, const unsigned long cc) {
|
||||
dstate.pos = pos;
|
||||
}
|
||||
|
||||
void DutyUnit::loadState(const SaveState::SPU::Duty &dstate, const unsigned nr1, const unsigned nr4) {
|
||||
nextPosUpdate = dstate.nextPosUpdate;
|
||||
pos = dstate.pos;
|
||||
void DutyUnit::loadState(const SaveState::SPU::Duty &dstate, const unsigned nr1, const unsigned nr4, const unsigned long cc) {
|
||||
nextPosUpdate = std::max(dstate.nextPosUpdate, cc);
|
||||
pos = dstate.pos & 7;
|
||||
setDuty(nr1);
|
||||
period = toPeriod(nr4 << 8 & 0x700 | dstate.nr3);
|
||||
enableEvents = true;
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
void nr4Change(unsigned newNr4, unsigned long cc);
|
||||
void reset();
|
||||
void saveState(SaveState::SPU::Duty &dstate, unsigned long cc);
|
||||
void loadState(const SaveState::SPU::Duty &dstate, unsigned nr1, unsigned nr4);
|
||||
void loadState(const SaveState::SPU::Duty &dstate, unsigned nr1, unsigned nr4, unsigned long cc);
|
||||
void resetCounters(unsigned long oldCc);
|
||||
void killCounter();
|
||||
void reviveCounter(unsigned long cc);
|
||||
|
@ -17,6 +17,7 @@
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "envelope_unit.h"
|
||||
#include <algorithm>
|
||||
|
||||
EnvelopeUnit::VolOnOffEvent EnvelopeUnit::nullEvent;
|
||||
|
||||
@ -93,8 +94,8 @@ void EnvelopeUnit::saveState(SaveState::SPU::Env &estate) const {
|
||||
estate.volume = volume;
|
||||
}
|
||||
|
||||
void EnvelopeUnit::loadState(const SaveState::SPU::Env &estate, const unsigned nr2) {
|
||||
counter = estate.counter;
|
||||
void EnvelopeUnit::loadState(const SaveState::SPU::Env &estate, const unsigned nr2, const unsigned long cc) {
|
||||
counter = std::max(estate.counter, cc);
|
||||
volume = estate.volume;
|
||||
this->nr2 = nr2;
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
bool nr4Init(unsigned long cycleCounter);
|
||||
void reset();
|
||||
void saveState(SaveState::SPU::Env &estate) const;
|
||||
void loadState(const SaveState::SPU::Env &estate, unsigned nr2);
|
||||
void loadState(const SaveState::SPU::Env &estate, unsigned nr2, unsigned long cc);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -18,6 +18,7 @@
|
||||
***************************************************************************/
|
||||
#include "length_counter.h"
|
||||
#include "master_disabler.h"
|
||||
#include <algorithm>
|
||||
|
||||
LengthCounter::LengthCounter(MasterDisabler &disabler, const unsigned mask) :
|
||||
disableMaster(disabler),
|
||||
@ -80,7 +81,7 @@ void LengthCounter::saveState(SaveState::SPU::LCounter &lstate) const {
|
||||
lstate.lengthCounter = lengthCounter;
|
||||
}
|
||||
|
||||
void LengthCounter::loadState(const SaveState::SPU::LCounter &lstate) {
|
||||
counter = lstate.counter;
|
||||
void LengthCounter::loadState(const SaveState::SPU::LCounter &lstate, const unsigned long cc) {
|
||||
counter = std::max(lstate.counter, cc);
|
||||
lengthCounter = lstate.lengthCounter;
|
||||
}
|
||||
|
@ -33,12 +33,12 @@ class LengthCounter : public SoundUnit {
|
||||
public:
|
||||
LengthCounter(MasterDisabler &disabler, unsigned lengthMask);
|
||||
void event();
|
||||
void nr1Change(unsigned newNr1, unsigned nr4, unsigned long cycleCounter);
|
||||
void nr4Change(unsigned oldNr4, unsigned newNr4, unsigned long cycleCounter);
|
||||
void nr1Change(unsigned newNr1, unsigned nr4, unsigned long cc);
|
||||
void nr4Change(unsigned oldNr4, unsigned newNr4, unsigned long cc);
|
||||
// void reset();
|
||||
void init(bool cgb);
|
||||
void saveState(SaveState::SPU::LCounter &lstate) const;
|
||||
void loadState(const SaveState::SPU::LCounter &lstate);
|
||||
void loadState(const SaveState::SPU::LCounter &lstate, unsigned long cc);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -24,6 +24,7 @@ class MasterDisabler {
|
||||
|
||||
public:
|
||||
MasterDisabler(bool &m) : master(m) {}
|
||||
virtual ~MasterDisabler() {}
|
||||
virtual void operator()() { master = false; }
|
||||
};
|
||||
|
||||
|
@ -46,6 +46,12 @@ static inline bool operator<(const Saver &l, const Saver &r) {
|
||||
return std::strcmp(l.label, r.label) < 0;
|
||||
}
|
||||
|
||||
static void put24(std::ofstream &file, const unsigned long data) {
|
||||
file.put(data >> 16 & 0xFF);
|
||||
file.put(data >> 8 & 0xFF);
|
||||
file.put(data & 0xFF);
|
||||
}
|
||||
|
||||
static void put32(std::ofstream &file, const unsigned long data) {
|
||||
file.put(data >> 24 & 0xFF);
|
||||
file.put(data >> 16 & 0xFF);
|
||||
@ -80,39 +86,23 @@ static inline void write(std::ofstream &file, const bool data) {
|
||||
}
|
||||
|
||||
static void write(std::ofstream &file, const unsigned char *data, const unsigned long sz) {
|
||||
file.put(sz >> 16 & 0xFF);
|
||||
file.put(sz >> 8 & 0xFF);
|
||||
file.put(sz & 0xFF);
|
||||
put24(file, sz);
|
||||
file.write(reinterpret_cast<const char*>(data), sz);
|
||||
}
|
||||
|
||||
static void write(std::ofstream &file, const bool *data, const unsigned long sz) {
|
||||
file.put(sz >> 16 & 0xFF);
|
||||
file.put(sz >> 8 & 0xFF);
|
||||
file.put(sz & 0xFF);
|
||||
put24(file, sz);
|
||||
|
||||
for (unsigned long i = 0; i < sz; ++i)
|
||||
file.put(data[i]);
|
||||
}
|
||||
|
||||
static void writeTime(std::ofstream &file, const std::time_t data) {
|
||||
static const char inf[] = { 0x00, 0x00, 0x08 };
|
||||
|
||||
file.write(inf, sizeof(inf));
|
||||
|
||||
if (sizeof(std::time_t) < sizeof(unsigned long)) {
|
||||
const unsigned long uldata = data;
|
||||
|
||||
put32(file, (uldata >> 31) >> 1);
|
||||
put32(file, uldata);
|
||||
} else {
|
||||
put32(file, (data >> 31) >> 1);
|
||||
put32(file, data);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long get24(std::ifstream &file) {
|
||||
return static_cast<unsigned long>(file.get() & 0xFF) << 16 | (file.get() & 0xFF) << 8 | file.get() & 0xFF;
|
||||
unsigned long tmp = file.get() & 0xFF;
|
||||
|
||||
tmp = tmp << 8 | file.get() & 0xFF;
|
||||
|
||||
return tmp << 8 | file.get() & 0xFF;
|
||||
}
|
||||
|
||||
static unsigned long read(std::ifstream &file) {
|
||||
@ -178,23 +168,6 @@ static void read(std::ifstream &file, bool *data, unsigned long sz) {
|
||||
file.ignore(size - sz);
|
||||
}
|
||||
|
||||
static void readTime(std::ifstream &file, std::time_t &data) {
|
||||
unsigned long size = get24(file);
|
||||
|
||||
if (size > 8) {
|
||||
file.ignore(size - 8);
|
||||
size = 8;
|
||||
}
|
||||
|
||||
std::time_t out = 0;
|
||||
|
||||
while (size-- && out >= 0) {
|
||||
out = out << 8 | file.get() & 0xFF;
|
||||
}
|
||||
|
||||
data = out;
|
||||
}
|
||||
|
||||
class SaverList {
|
||||
public:
|
||||
typedef std::vector<Saver> list_t;
|
||||
@ -231,16 +204,6 @@ SaverList::SaverList() {
|
||||
Saver saver = { label, Func::save, Func::load, sizeof label }; \
|
||||
list.push_back(saver); \
|
||||
} while (0)
|
||||
|
||||
#define ADDTIME(arg) do { \
|
||||
struct Func { \
|
||||
static void save(std::ofstream &file, const SaveState &state) { writeTime(file, state.arg); } \
|
||||
static void load(std::ifstream &file, SaveState &state) { readTime(file, state.arg); } \
|
||||
}; \
|
||||
\
|
||||
Saver saver = { label, Func::save, Func::load, sizeof label }; \
|
||||
list.push_back(saver); \
|
||||
} while (0)
|
||||
|
||||
{ static const char label[] = { c,c, NUL }; ADD(cpu.cycleCounter); }
|
||||
{ static const char label[] = { p,c, NUL }; ADD(cpu.PC); }
|
||||
@ -334,8 +297,8 @@ SaverList::SaverList() {
|
||||
{ static const char label[] = { l,e,n,NO4,v,a,l, NUL }; ADD(spu.ch4.lcounter.lengthCounter); }
|
||||
{ static const char label[] = { n,r,NO4,NO4, NUL }; ADD(spu.ch4.nr4); }
|
||||
{ static const char label[] = { c,NO4,m,a,s,t,r, NUL }; ADD(spu.ch4.master); }
|
||||
{ static const char label[] = { r,t,c,b,a,s,e, NUL }; ADDTIME(rtc.baseTime); }
|
||||
{ static const char label[] = { r,t,c,h,a,l,t, NUL }; ADDTIME(rtc.haltTime); }
|
||||
{ static const char label[] = { r,t,c,b,a,s,e, NUL }; ADD(rtc.baseTime); }
|
||||
{ static const char label[] = { r,t,c,h,a,l,t, NUL }; ADD(rtc.haltTime); }
|
||||
{ static const char label[] = { r,t,c,i,n,d,x, NUL }; ADD(rtc.index); }
|
||||
{ static const char label[] = { r,t,c,d,h, NUL }; ADD(rtc.dataDh); }
|
||||
{ static const char label[] = { r,t,c,d,l, NUL }; ADD(rtc.dataDl); }
|
||||
@ -359,6 +322,34 @@ SaverList::SaverList() {
|
||||
}
|
||||
}
|
||||
|
||||
static void writeSnapShot(std::ofstream &file, const Gambatte::uint_least32_t *pixels, const unsigned pitch) {
|
||||
put24(file, pixels ? StateSaver::SS_WIDTH * StateSaver::SS_HEIGHT * sizeof(Gambatte::uint_least32_t) : 0);
|
||||
|
||||
if (pixels) {
|
||||
Gambatte::uint_least32_t buf[StateSaver::SS_WIDTH];
|
||||
|
||||
for (unsigned h = StateSaver::SS_HEIGHT; h--;) {
|
||||
for (unsigned x = 0; x < StateSaver::SS_WIDTH; ++x) {
|
||||
unsigned long rb = 0;
|
||||
unsigned long g = 0;
|
||||
|
||||
static const unsigned w[StateSaver::SS_DIV] = { 1, 3, 3, 1 };
|
||||
|
||||
for (unsigned y = 0; y < StateSaver::SS_DIV; ++y)
|
||||
for (unsigned xx = 0; xx < StateSaver::SS_DIV; ++xx) {
|
||||
rb += (pixels[x * StateSaver::SS_DIV + y * pitch + xx] & 0xFF00FF) * w[y] * w[xx];
|
||||
g += (pixels[x * StateSaver::SS_DIV + y * pitch + xx] & 0x00FF00) * w[y] * w[xx];
|
||||
}
|
||||
|
||||
buf[x] = rb >> StateSaver::SS_SHIFT * 2 + 2 & 0xFF00FF | g >> StateSaver::SS_SHIFT * 2 + 2 & 0x00FF00;
|
||||
}
|
||||
|
||||
file.write(reinterpret_cast<const char*>(buf), sizeof(buf));
|
||||
pixels += pitch * StateSaver::SS_DIV;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static SaverList list;
|
||||
|
||||
void StateSaver::saveState(const SaveState &state, const char *filename) {
|
||||
@ -369,19 +360,22 @@ void StateSaver::saveState(const SaveState &state, const char *filename) {
|
||||
|
||||
{ static const char ver[] = { 0, 0 }; file.write(ver, sizeof(ver)); }
|
||||
|
||||
writeSnapShot(file, state.ppu.drawBuffer.get(), state.ppu.drawBuffer.getSz() / 144);
|
||||
|
||||
for (SaverList::const_iterator it = list.begin(); it != list.end(); ++it) {
|
||||
file.write(it->label, it->labelsize);
|
||||
(*it->save)(file, state);
|
||||
}
|
||||
}
|
||||
|
||||
void StateSaver::loadState(SaveState &state, const char *filename) {
|
||||
bool StateSaver::loadState(SaveState &state, const char *filename) {
|
||||
std::ifstream file(filename, std::ios_base::binary);
|
||||
|
||||
if (file.fail() || file.get() != 0)
|
||||
return;
|
||||
return false;
|
||||
|
||||
file.ignore();
|
||||
file.ignore(get24(file));
|
||||
|
||||
Array<char> labelbuf(list.maxLabelsize());
|
||||
const Saver labelbufSaver = { label: labelbuf, save: 0, load: 0, labelsize: list.maxLabelsize() };
|
||||
@ -405,4 +399,9 @@ void StateSaver::loadState(SaveState &state, const char *filename) {
|
||||
|
||||
(*it->load)(file, state);
|
||||
}
|
||||
|
||||
state.cpu.cycleCounter &= 0x7FFFFFFF;
|
||||
state.spu.cycleCounter &= 0x7FFFFFFF;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -25,8 +25,13 @@ class StateSaver {
|
||||
StateSaver();
|
||||
|
||||
public:
|
||||
enum { SS_SHIFT = 2 };
|
||||
enum { SS_DIV = 1 << 2 };
|
||||
enum { SS_WIDTH = 160 >> SS_SHIFT };
|
||||
enum { SS_HEIGHT = 144 >> SS_SHIFT };
|
||||
|
||||
static void saveState(const SaveState &state, const char *filename);
|
||||
static void loadState(SaveState &state, const char *filename);
|
||||
static bool loadState(SaveState &state, const char *filename);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -192,6 +192,7 @@ void LCD::setDoubleSpeed(const bool ds) {
|
||||
}
|
||||
|
||||
void LCD::setStatePtrs(SaveState &state) {
|
||||
state.ppu.drawBuffer.set(static_cast<Gambatte::uint_least32_t*>(dbuffer), dpitch * 144);
|
||||
state.ppu.bgpData.set(bgpData, sizeof bgpData);
|
||||
state.ppu.objpData.set(objpData, sizeof objpData);
|
||||
spriteMapper.setStatePtrs(state);
|
||||
@ -221,9 +222,9 @@ void LCD::loadState(const SaveState &state, const unsigned char *oamram) {
|
||||
setDoubleSpeed(cgb & state.mem.ioamhram.get()[0x14D] >> 7);
|
||||
|
||||
lastUpdate = state.cpu.cycleCounter;
|
||||
videoCycles = state.ppu.videoCycles;
|
||||
videoCycles = std::min(state.ppu.videoCycles, 70223ul);
|
||||
enableDisplayM0Time = state.ppu.enableDisplayM0Time;
|
||||
winYPos = state.ppu.winYPos;
|
||||
winYPos = state.ppu.winYPos > 143 ? 0xFF : state.ppu.winYPos;
|
||||
drawStartCycle = state.ppu.drawStartCycle;
|
||||
scReadOffset = state.ppu.scReadOffset;
|
||||
enabled = state.ppu.lcdc >> 7 & 1;
|
||||
@ -277,7 +278,7 @@ void LCD::setVideoBlitter(Gambatte::VideoBlitter *vb) {
|
||||
vBlitter = vb;
|
||||
|
||||
if (vBlitter) {
|
||||
vBlitter->setBufferDimensions(filter ? filter->info().outWidth : 160, filter ? filter->info().outHeight : 144);
|
||||
vBlitter->setBufferDimensions(videoWidth(), videoHeight());
|
||||
pb = vBlitter->inBuffer();
|
||||
}
|
||||
|
||||
@ -292,8 +293,8 @@ void LCD::videoBufferChange() {
|
||||
}
|
||||
|
||||
void LCD::setVideoFilter(const unsigned n) {
|
||||
const unsigned oldw = filter ? filter->info().outWidth : 160;
|
||||
const unsigned oldh = filter ? filter->info().outHeight : 144;
|
||||
const unsigned oldw = videoWidth();
|
||||
const unsigned oldh = videoHeight();
|
||||
|
||||
if (filter)
|
||||
filter->outit();
|
||||
@ -304,8 +305,8 @@ void LCD::setVideoFilter(const unsigned n) {
|
||||
filter->init();
|
||||
}
|
||||
|
||||
if (vBlitter && (oldw != (filter ? filter->info().outWidth : 160) || oldh != (filter ? filter->info().outHeight : 144))) {
|
||||
vBlitter->setBufferDimensions(filter ? filter->info().outWidth : 160, filter ? filter->info().outHeight : 144);
|
||||
if (vBlitter && (oldw != videoWidth() || oldh != videoHeight())) {
|
||||
vBlitter->setBufferDimensions(videoWidth(), videoHeight());
|
||||
pb = vBlitter->inBuffer();
|
||||
}
|
||||
|
||||
@ -336,19 +337,41 @@ void LCD::updateScreen(const unsigned long cycleCounter) {
|
||||
update(cycleCounter);
|
||||
|
||||
if (pb.pixels) {
|
||||
if (dbuffer && osdElement.get()) {
|
||||
const Gambatte::uint_least32_t *s = osdElement->update();
|
||||
|
||||
if (s) {
|
||||
Gambatte::uint_least32_t *d = static_cast<Gambatte::uint_least32_t*>(dbuffer) + osdElement->y() * dpitch + osdElement->x();
|
||||
|
||||
for (unsigned h = osdElement->h(); h--;) {
|
||||
for (unsigned w = osdElement->w(); w--;) {
|
||||
if (*s != 0xFFFFFFFF)
|
||||
*d = *s * 7 + *d - ((*s & 0x070707) * 7 + (*d & 0x070707) & 0x070707) >> 3;
|
||||
|
||||
++d;
|
||||
++s;
|
||||
}
|
||||
// std::memcpy(d, s, osdElement->w() * sizeof(Gambatte::uint_least32_t));
|
||||
// s += osdElement->w();
|
||||
d += dpitch - osdElement->w();
|
||||
}
|
||||
} else
|
||||
osdElement.reset();
|
||||
}
|
||||
|
||||
if (filter) {
|
||||
filter->filter(static_cast<Gambatte::uint_least32_t*>(tmpbuf ? tmpbuf : pb.pixels), pb.pitch);
|
||||
|
||||
if (tmpbuf) {
|
||||
switch (pb.format) {
|
||||
case Gambatte::PixelBuffer::RGB16:
|
||||
rgb32ToRgb16(tmpbuf, static_cast<Gambatte::uint_least16_t*>(pb.pixels), filter->info().outWidth, filter->info().outHeight, pb.pitch);
|
||||
break;
|
||||
case Gambatte::PixelBuffer::UYVY:
|
||||
rgb32ToUyvy(tmpbuf, static_cast<Gambatte::uint_least32_t*>(pb.pixels), filter->info().outWidth, filter->info().outHeight, pb.pitch);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmpbuf) {
|
||||
switch (pb.format) {
|
||||
case Gambatte::PixelBuffer::RGB16:
|
||||
rgb32ToRgb16(tmpbuf, static_cast<Gambatte::uint_least16_t*>(pb.pixels), videoWidth(), videoHeight(), pb.pitch);
|
||||
break;
|
||||
case Gambatte::PixelBuffer::UYVY:
|
||||
rgb32ToUyvy(tmpbuf, static_cast<Gambatte::uint_least32_t*>(pb.pixels), videoWidth(), videoHeight(), pb.pitch);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -385,10 +408,7 @@ void LCD::enableChange(const unsigned long cycleCounter) {
|
||||
if (!enabled && dbuffer) {
|
||||
const unsigned long color = cgb ? (*gbcToFormat)(0xFFFF) : dmgColors[0];
|
||||
|
||||
if (!filter && pb.format == Gambatte::PixelBuffer::RGB16)
|
||||
clear(static_cast<Gambatte::uint_least16_t*>(dbuffer), color, dpitch);
|
||||
else
|
||||
clear(static_cast<Gambatte::uint_least32_t*>(dbuffer), color, dpitch);
|
||||
clear(static_cast<Gambatte::uint_least32_t*>(dbuffer), color, dpitch);
|
||||
|
||||
// updateScreen(cycleCounter);
|
||||
}
|
||||
@ -854,42 +874,25 @@ void LCD::update(const unsigned long cycleCounter) {
|
||||
}
|
||||
|
||||
void LCD::setDBuffer() {
|
||||
tmpbuf.reset(pb.format == Gambatte::PixelBuffer::RGB32 ? 0 : videoWidth() * videoHeight());
|
||||
|
||||
if (cgb)
|
||||
draw = &LCD::cgb_draw<Gambatte::uint_least32_t>;
|
||||
else
|
||||
draw = &LCD::dmg_draw<Gambatte::uint_least32_t>;
|
||||
|
||||
gbcToFormat = &gbcToRgb32;
|
||||
dmgColors = dmgColorsRgb32;
|
||||
|
||||
if (filter) {
|
||||
dbuffer = filter->inBuffer();
|
||||
dpitch = filter->inPitch();
|
||||
} else {
|
||||
} else if (pb.format == Gambatte::PixelBuffer::RGB32) {
|
||||
dbuffer = pb.pixels;
|
||||
dpitch = pb.pitch;
|
||||
}
|
||||
|
||||
tmpbuf.reset(filter && pb.format != Gambatte::PixelBuffer::RGB32 ? filter->info().outWidth * filter->info().outHeight : 0);
|
||||
|
||||
/*if (filter || pb.bpp == 16)
|
||||
draw = memory.cgb ? &LCD::cgb_draw<uint16_t> : &LCD::dmg_draw<uint16_t>;
|
||||
else
|
||||
draw = memory.cgb ? &LCD::cgb_draw<uint32_t> : &LCD::dmg_draw<uint32_t>;*/
|
||||
|
||||
if (!filter && pb.format == Gambatte::PixelBuffer::RGB16) {
|
||||
if (cgb)
|
||||
draw = &LCD::cgb_draw<Gambatte::uint_least16_t>;
|
||||
else
|
||||
draw = &LCD::dmg_draw<Gambatte::uint_least16_t>;
|
||||
|
||||
gbcToFormat = &gbcToRgb16;
|
||||
dmgColors = dmgColorsRgb16;
|
||||
} else {
|
||||
if (cgb)
|
||||
draw = &LCD::cgb_draw<Gambatte::uint_least32_t>;
|
||||
else
|
||||
draw = &LCD::dmg_draw<Gambatte::uint_least32_t>;
|
||||
|
||||
if (filter || pb.format == Gambatte::PixelBuffer::RGB32) {
|
||||
gbcToFormat = &gbcToRgb32;
|
||||
dmgColors = dmgColorsRgb32;
|
||||
} else {
|
||||
gbcToFormat = &gbcToUyvy;
|
||||
dmgColors = dmgColorsUyvy;
|
||||
}
|
||||
dbuffer = tmpbuf;
|
||||
dpitch = 160;
|
||||
}
|
||||
|
||||
if (dbuffer == NULL)
|
||||
@ -1009,6 +1012,37 @@ static const unsigned char xflipt[0x100] = {
|
||||
#undef FLIP_ROW
|
||||
#undef FLIP
|
||||
|
||||
/*
|
||||
#define PREP(u8) (u8)
|
||||
|
||||
#define EXPAND(u8) ( PREP(u8) << 7 & 0x4000 | PREP(u8) << 6 & 0x1000 | PREP(u8) << 5 & 0x0400 | PREP(u8) << 4 & 0x0100 | \
|
||||
PREP(u8) << 3 & 0x0040 | PREP(u8) << 2 & 0x0010 | PREP(u8) << 1 & 0x0004 | PREP(u8) & 0x0001 )
|
||||
|
||||
#define EXPAND_ROW(n) EXPAND((n)|0x0), EXPAND((n)|0x1), EXPAND((n)|0x2), EXPAND((n)|0x3), \
|
||||
EXPAND((n)|0x4), EXPAND((n)|0x5), EXPAND((n)|0x6), EXPAND((n)|0x7), \
|
||||
EXPAND((n)|0x8), EXPAND((n)|0x9), EXPAND((n)|0xA), EXPAND((n)|0xB), \
|
||||
EXPAND((n)|0xC), EXPAND((n)|0xD), EXPAND((n)|0xE), EXPAND((n)|0xF)
|
||||
|
||||
#define EXPAND_TABLE EXPAND_ROW(0x00), EXPAND_ROW(0x10), EXPAND_ROW(0x20), EXPAND_ROW(0x30), \
|
||||
EXPAND_ROW(0x40), EXPAND_ROW(0x50), EXPAND_ROW(0x60), EXPAND_ROW(0x70), \
|
||||
EXPAND_ROW(0x80), EXPAND_ROW(0x90), EXPAND_ROW(0xA0), EXPAND_ROW(0xB0), \
|
||||
EXPAND_ROW(0xC0), EXPAND_ROW(0xD0), EXPAND_ROW(0xE0), EXPAND_ROW(0xF0)
|
||||
|
||||
static const unsigned short expand_lut[0x200] = {
|
||||
EXPAND_TABLE,
|
||||
|
||||
#undef PREP
|
||||
#define PREP(u8) ( (u8) << 7 & 0x80 | (u8) << 5 & 0x40 | (u8) << 3 & 0x20 | (u8) << 1 & 0x10 | \
|
||||
(u8) >> 1 & 0x08 | (u8) >> 3 & 0x04 | (u8) >> 5 & 0x02 | (u8) >> 7 & 0x01 )
|
||||
|
||||
EXPAND_TABLE
|
||||
};
|
||||
|
||||
#undef EXPAND_TABLE
|
||||
#undef EXPAND_ROW
|
||||
#undef EXPAND
|
||||
#undef PREP
|
||||
*/
|
||||
|
||||
//shoud work for the window too, if -wx is passed as scx.
|
||||
//tilemap and tiledata must point to the areas in the first vram bank
|
||||
|
@ -28,11 +28,13 @@ class Filter;
|
||||
class SaveState;
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "event_queue.h"
|
||||
#include "videoblitter.h"
|
||||
#include "array.h"
|
||||
#include "int.h"
|
||||
#include "colorconversion.h"
|
||||
#include "osd_element.h"
|
||||
|
||||
#include "video/video_event_comparer.h"
|
||||
#include "video/ly_counter.h"
|
||||
@ -104,6 +106,7 @@ class LCD {
|
||||
Gambatte::PixelBuffer pb;
|
||||
Array<Gambatte::uint_least32_t> tmpbuf;
|
||||
Rgb32ToUyvy rgb32ToUyvy;
|
||||
std::auto_ptr<OsdElement> osdElement;
|
||||
|
||||
std::vector<Filter*> filters;
|
||||
|
||||
@ -167,6 +170,10 @@ public:
|
||||
unsigned videoHeight() const;
|
||||
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32);
|
||||
|
||||
void setOsdElement(std::auto_ptr<OsdElement> osdElement) {
|
||||
this->osdElement = osdElement;
|
||||
}
|
||||
|
||||
void wdTileMapSelectChange(bool newValue, unsigned long cycleCounter);
|
||||
void bgTileMapSelectChange(bool newValue, unsigned long cycleCounter);
|
||||
void bgTileDataSelectChange(bool newValue, unsigned long cycleCounter);
|
||||
|
Loading…
Reference in New Issue
Block a user