Update to v106r36 release.

byuu says:

Changelog:

  - nall: renamed array to adaptive_array; marked it as deprecated
  - nall: created new array class; which is properly static (ala
    std::array) with optional bounds-checking
  - sfc/ppu-fast: converted unmanaged arrays to use nall/array (no speed
    penalty)
  - bsnes: rewrote the cheat code editor to a new design
  - nall: string class can stringify pointer types directly now, so
    pointer() was removed
  - nall: added array_view and pointer types (still unsure if/how I'll
    use pointer)
This commit is contained in:
Tim Allen 2018-06-04 12:44:57 +10:00
parent 77ac5f9e88
commit ec9729a9e1
26 changed files with 573 additions and 286 deletions

View File

@ -1,6 +1,7 @@
#pragma once
#include <nall/nall.hpp>
#include <nall/adaptive-array.hpp>
#include <nall/vfs.hpp>
using namespace nall;
@ -12,7 +13,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "106.35";
static const string Version = "106.36";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "https://byuu.org/";

View File

@ -140,8 +140,8 @@ struct VDP : Thread {
Pixel output;
array<Object, 80> oam;
array<Object, 20> objects;
adaptive_array<Object, 80> oam;
adaptive_array<Object, 20> objects;
};
Sprite sprite;

View File

@ -68,7 +68,7 @@ struct VDP : Thread {
uint4 color;
} output;
array<Object, 8> objects;
adaptive_array<Object, 8> objects;
} sprite;
//serialization.cpp

View File

@ -170,7 +170,7 @@ private:
bool vflip = 0;
bool first = 0;
};
array<Object, 64> objects;
adaptive_array<Object, 64> objects;
uint4 color;
uint4 palette;

View File

@ -3,8 +3,8 @@ auto PPU::Line::renderBackground(PPU::IO::Background& self, uint source) -> void
if(self.tileMode == TileMode::Mode7) return renderMode7(self, source);
if(self.tileMode == TileMode::Inactive) return;
bool windowAbove[256];
bool windowBelow[256];
array<bool[256]> windowAbove;
array<bool[256]> windowBelow;
renderWindow(self.window, self.window.aboveEnable, windowAbove);
renderWindow(self.window, self.window.belowEnable, windowBelow);

View File

@ -589,11 +589,11 @@ auto PPU::updateVideoMode() -> void {
io.bg2.tileMode = TileMode::BPP2;
io.bg3.tileMode = TileMode::BPP2;
io.bg4.tileMode = TileMode::BPP2;
memory::assign(io.bg1.priority, 8, 11);
memory::assign(io.bg2.priority, 7, 10);
memory::assign(io.bg3.priority, 2, 5);
memory::assign(io.bg4.priority, 1, 4);
memory::assign(io.obj.priority, 3, 6, 9, 12);
io.bg1.priority = { 8, 11};
io.bg2.priority = { 7, 10};
io.bg3.priority = { 2, 5};
io.bg4.priority = { 1, 4};
io.obj.priority = { 3, 6, 9, 12};
break;
case 1:
@ -602,15 +602,15 @@ auto PPU::updateVideoMode() -> void {
io.bg3.tileMode = TileMode::BPP2;
io.bg4.tileMode = TileMode::Inactive;
if(io.bgPriority) {
memory::assign(io.bg1.priority, 5, 8);
memory::assign(io.bg2.priority, 4, 7);
memory::assign(io.bg3.priority, 1, 10);
memory::assign(io.obj.priority, 2, 3, 6, 9);
io.bg1.priority = { 5, 8};
io.bg2.priority = { 4, 7};
io.bg3.priority = { 1, 10};
io.obj.priority = { 2, 3, 6, 9};
} else {
memory::assign(io.bg1.priority, 6, 9);
memory::assign(io.bg2.priority, 5, 8);
memory::assign(io.bg3.priority, 1, 3);
memory::assign(io.obj.priority, 2, 4, 7, 10);
io.bg1.priority = { 6, 9};
io.bg2.priority = { 5, 8};
io.bg3.priority = { 1, 3};
io.obj.priority = { 2, 4, 7, 10};
}
break;
@ -619,9 +619,9 @@ auto PPU::updateVideoMode() -> void {
io.bg2.tileMode = TileMode::BPP4;
io.bg3.tileMode = TileMode::Inactive;
io.bg4.tileMode = TileMode::Inactive;
memory::assign(io.bg1.priority, 3, 7);
memory::assign(io.bg2.priority, 1, 5);
memory::assign(io.obj.priority, 2, 4, 6, 8);
io.bg1.priority = { 3, 7};
io.bg2.priority = { 1, 5};
io.obj.priority = { 2, 4, 6, 8};
break;
case 3:
@ -629,9 +629,9 @@ auto PPU::updateVideoMode() -> void {
io.bg2.tileMode = TileMode::BPP4;
io.bg3.tileMode = TileMode::Inactive;
io.bg4.tileMode = TileMode::Inactive;
memory::assign(io.bg1.priority, 3, 7);
memory::assign(io.bg2.priority, 1, 5);
memory::assign(io.obj.priority, 2, 4, 6, 8);
io.bg1.priority = { 3, 7};
io.bg2.priority = { 1, 5};
io.obj.priority = { 2, 4, 6, 8};
break;
case 4:
@ -639,9 +639,9 @@ auto PPU::updateVideoMode() -> void {
io.bg2.tileMode = TileMode::BPP2;
io.bg3.tileMode = TileMode::Inactive;
io.bg4.tileMode = TileMode::Inactive;
memory::assign(io.bg1.priority, 3, 7);
memory::assign(io.bg2.priority, 1, 5);
memory::assign(io.obj.priority, 2, 4, 6, 8);
io.bg1.priority = { 3, 7};
io.bg2.priority = { 1, 5};
io.obj.priority = { 2, 4, 6, 8};
break;
case 5:
@ -649,9 +649,9 @@ auto PPU::updateVideoMode() -> void {
io.bg2.tileMode = TileMode::BPP2;
io.bg3.tileMode = TileMode::Inactive;
io.bg4.tileMode = TileMode::Inactive;
memory::assign(io.bg1.priority, 3, 7);
memory::assign(io.bg2.priority, 1, 5);
memory::assign(io.obj.priority, 2, 4, 6, 8);
io.bg1.priority = { 3, 7};
io.bg2.priority = { 1, 5};
io.obj.priority = { 2, 4, 6, 8};
break;
case 6:
@ -659,8 +659,8 @@ auto PPU::updateVideoMode() -> void {
io.bg2.tileMode = TileMode::Inactive;
io.bg3.tileMode = TileMode::Inactive;
io.bg4.tileMode = TileMode::Inactive;
memory::assign(io.bg1.priority, 2, 5);
memory::assign(io.obj.priority, 1, 3, 4, 6);
io.bg1.priority = { 2, 5};
io.obj.priority = { 1, 3, 4, 6};
break;
case 7:
@ -669,16 +669,16 @@ auto PPU::updateVideoMode() -> void {
io.bg2.tileMode = TileMode::Inactive;
io.bg3.tileMode = TileMode::Inactive;
io.bg4.tileMode = TileMode::Inactive;
memory::assign(io.bg1.priority, 2);
memory::assign(io.obj.priority, 1, 3, 4, 5);
io.bg1.priority = { 2};
io.obj.priority = { 1, 3, 4, 5};
} else {
io.bg1.tileMode = TileMode::Mode7;
io.bg2.tileMode = TileMode::Mode7;
io.bg3.tileMode = TileMode::Inactive;
io.bg4.tileMode = TileMode::Inactive;
memory::assign(io.bg1.priority, 3);
memory::assign(io.bg2.priority, 1, 5);
memory::assign(io.obj.priority, 2, 4, 6, 7);
io.bg1.priority = { 3};
io.bg2.priority = { 1, 5};
io.obj.priority = { 2, 4, 6, 7};
}
break;
}

View File

@ -20,8 +20,8 @@ auto PPU::Line::renderMode7(PPU::IO::Background& self, uint source) -> void {
int originX = (a * clip(hoffset - hcenter) & ~63) + (b * clip(voffset - vcenter) & ~63) + (b * y & ~63) + (hcenter << 8);
int originY = (c * clip(hoffset - hcenter) & ~63) + (d * clip(voffset - vcenter) & ~63) + (d * y & ~63) + (vcenter << 8);
bool windowAbove[256];
bool windowBelow[256];
array<bool[256]> windowAbove;
array<bool[256]> windowBelow;
renderWindow(self.window, self.window.aboveEnable, windowAbove);
renderWindow(self.window, self.window.belowEnable, windowBelow);

View File

@ -1,8 +1,8 @@
auto PPU::Line::renderObject(PPU::IO::Object& self) -> void {
if(!self.aboveEnable && !self.belowEnable) return;
bool windowAbove[256];
bool windowBelow[256];
array<bool[256]> windowAbove;
array<bool[256]> windowBelow;
renderWindow(self.window, self.window.aboveEnable, windowAbove);
renderWindow(self.window, self.window.belowEnable, windowBelow);

View File

@ -13,21 +13,21 @@ PPU ppu;
#include <sfc/ppu/counter/serialization.cpp>
PPU::PPU() {
output = new uint32[512 * 512];
output += 16 * 512; //overscan offset
output = new uint32[512 * 512] + 16 * 512; //overscan offset
tilecache[TileMode::BPP2] = new uint8[4096 * 8 * 8];
tilecache[TileMode::BPP4] = new uint8[2048 * 8 * 8];
tilecache[TileMode::BPP8] = new uint8[1024 * 8 * 8];
for(uint y : range(240)) {
for(uint y : range(lines.size())) {
lines[y].y = y;
}
}
PPU::~PPU() {
output -= 16 * 512; //overscan offset
delete[] output;
delete[] (output - 16 * 512); //overscan offset
delete[] tilecache[TileMode::BPP2];
delete[] tilecache[TileMode::BPP4];
delete[] tilecache[TileMode::BPP8];
}
auto PPU::Enter() -> void {

View File

@ -35,9 +35,9 @@ public:
//serialization.cpp
auto serialize(serializer&) -> void;
uint1 interlace;
uint1 overscan;
uint1 hires;
uint1 interlace;
uint1 overscan;
uint1 hires;
uint16 vram;
uint8 oam;
@ -153,7 +153,7 @@ public:
uint16 hoffset;
uint16 voffset;
uint3 tileMode;
uint4 priority[2];
array<uint4[2]> priority;
} bg1, bg2, bg3, bg4;
struct Object {
@ -170,7 +170,7 @@ public:
uint7 first;
uint1 rangeOver;
uint1 timeOver;
uint4 priority[4];
array<uint4[4]> priority;
} obj;
struct Color {
@ -178,7 +178,7 @@ public:
auto serialize(serializer&) -> void;
WindowColor window;
uint1 enable[7];
array<uint1[7]> enable;
uint1 directColor;
uint1 blendMode; //0 = fixed; 1 = pixel
uint1 halve;
@ -249,13 +249,13 @@ public:
Latch latch;
IO io;
uint16 vram[32 * 1024];
uint15 cgram[256];
Object objects[128];
array<uint16[32 * 1024]> vram;
array<uint15[256]> cgram;
array<Object[128]> objects;
//[unserialized]
uint32* output = nullptr;
uint8* tilecache[3] = {}; //bitplane -> bitmap tiledata
uint32* output;
array<uint8*[3]> tilecache; //bitplane -> bitmap tiledata
struct Line {
//line.cpp
@ -278,28 +278,29 @@ public:
auto renderObject(PPU::IO::Object&) -> void;
//window.cpp
auto renderWindow(PPU::IO::WindowLayer&, bool, bool*) -> void;
auto renderWindow(PPU::IO::WindowColor&, uint, bool*) -> void;
auto renderWindow(PPU::IO::WindowLayer&, bool, array<bool[256]>&) -> void;
auto renderWindow(PPU::IO::WindowColor&, uint, array<bool[256]>&) -> void;
//[unserialized]
uint9 y; //constant
IO io;
uint15 cgram[256];
array<uint15[256]> cgram;
ObjectItem items[32];
ObjectTile tiles[34];
array<ObjectItem[32]> items;
array<ObjectTile[34]> tiles;
Pixel above[256];
Pixel below[256];
array<Pixel[256]> above;
array<Pixel[256]> below;
bool windowAbove[256];
bool windowBelow[256];
array<bool[256]> windowAbove;
array<bool[256]> windowBelow;
//flush()
static uint start;
static uint count;
} lines[240];
};
array<Line[240]> lines;
};
extern PPU ppu;

View File

@ -1,6 +1,6 @@
auto PPU::Line::renderWindow(PPU::IO::WindowLayer& self, bool enable, bool* output) -> void {
auto PPU::Line::renderWindow(PPU::IO::WindowLayer& self, bool enable, array<bool[256]>& output) -> void {
if(!enable || (!self.oneEnable && !self.twoEnable)) {
memory::fill<bool>(output, 256, 0);
output.fill(0);
return;
}
@ -32,17 +32,17 @@ auto PPU::Line::renderWindow(PPU::IO::WindowLayer& self, bool enable, bool* outp
}
}
auto PPU::Line::renderWindow(PPU::IO::WindowColor& self, uint mask, bool* output) -> void {
auto PPU::Line::renderWindow(PPU::IO::WindowColor& self, uint mask, array<bool[256]>& output) -> void {
bool set, clear;
switch(mask) {
case 0: memory::fill<bool>(output, 256, 1); return; //always
case 1: set = 1, clear = 0; break; //inside
case 2: set = 0, clear = 1; break; //outside
case 3: memory::fill<bool>(output, 256, 0); return; //never
case 0: output.fill(1); return; //always
case 1: set = 1, clear = 0; break; //inside
case 2: set = 0, clear = 1; break; //outside
case 3: output.fill(0); return; //never
}
if(!self.oneEnable && !self.twoEnable) {
memory::fill<bool>(output, 256, clear);
output.fill(clear);
return;
}

View File

@ -57,6 +57,7 @@ Program::Program(string_vector arguments) {
new InputManager;
new SettingsWindow;
new CheatDatabase;
new CheatWindow;
new ToolsWindow;
new AboutWindow;

View File

@ -1,57 +0,0 @@
CheatDatabase::CheatDatabase() {
cheatDatabase = this;
layout.setMargin(5);
selectAllButton.setText("Select All").onActivate([&] {
for(auto item : cheatList.items()) item.setChecked(true);
});
unselectAllButton.setText("Unselect All").onActivate([&] {
for(auto item : cheatList.items()) item.setChecked(false);
});
addCheatsButton.setText("Add Cheats").onActivate([&] {
addCheats();
});
setSize({800, 400});
setAlignment({0.5, 1.0});
setDismissable();
}
auto CheatDatabase::findCheats() -> void {
auto sha256 = emulator->sha256();
auto document = BML::unserialize(string::read(locate("cheats.bml")));
for(auto game : document.find("cartridge")) {
if(game["sha256"].text() != sha256) continue;
cheatList.reset();
for(auto cheat : game.find("cheat")) {
cheatList.append(ListViewItem()
.setCheckable()
.setText(cheat["description"].text())
.setProperty("code", cheat["code"].text())
);
}
setTitle(game["name"].text());
setVisible();
return;
}
MessageDialog().setParent(*toolsWindow).setText("Sorry, no cheats were found for this game.").information();
}
auto CheatDatabase::addCheats() -> void {
for(auto item : cheatList.items()) {
if(!item.checked()) continue;
string code = item.property("code").replace("/", "=", 1L).replace("/", "?", 1L);
string description = item.text();
if(!toolsWindow->cheatEditor.addCode(false, code, description)) {
MessageDialog().setParent(*this).setText("Free slots exhausted. Not all cheats could be added.").warning();
break;
}
}
setVisible(false);
toolsWindow->cheatEditor.doRefresh();
}

View File

@ -1,139 +1,217 @@
CheatDatabase::CheatDatabase() {
cheatDatabase = this;
layout.setMargin(5);
selectAllButton.setText("Select All").onActivate([&] {
for(auto item : cheatList.items()) item.setChecked(true);
});
unselectAllButton.setText("Unselect All").onActivate([&] {
for(auto item : cheatList.items()) item.setChecked(false);
});
addCheatsButton.setText("Add Cheats").onActivate([&] {
addCheats();
});
setSize({800, 400});
setAlignment({0.5, 1.0});
setDismissable();
}
auto CheatDatabase::findCheats() -> void {
auto sha256 = emulator->sha256();
auto document = BML::unserialize(string::read(locate("cheats.bml")));
for(auto game : document.find("cartridge")) {
if(game["sha256"].text() != sha256) continue;
cheatList.reset();
for(auto cheat : game.find("cheat")) {
cheatList.append(ListViewItem()
.setCheckable()
.setText(cheat["description"].text())
.setProperty("code", cheat["code"].text())
);
}
setTitle(game["name"].text());
setVisible();
return;
}
MessageDialog().setParent(*toolsWindow).setText("Sorry, no cheats were found for this game.").information();
}
auto CheatDatabase::addCheats() -> void {
for(auto item : cheatList.items()) {
if(item.checked()) {
toolsWindow->cheatEditor.addCheat(item.text(), item.property("code"));
}
}
setVisible(false);
toolsWindow->cheatEditor.synchronizeCodes();
}
//
CheatWindow::CheatWindow() {
cheatWindow = this;
layout.setMargin(5);
nameLabel.setText("Name:");
nameValue.onChange([&] { doChange(); });
codeLabel.setText("Code:");
codeValue.onChange([&] { doChange(); });
enabledOption.setText("Enabled");
acceptButton.onActivate([&] { doAccept(); });
cancelButton.setText("Cancel");
setSize({480, layout.minimumSize().height()});
setDismissable();
}
auto CheatWindow::show(TableViewItem item) -> void {
this->item = item;
nameValue.setText(item.cell(1).text());
codeValue.setText(item.property("code"));
enabledOption.setChecked(item.cell(0).checked());
doChange();
setTitle(!item ? "Add Cheat Code" : "Edit Cheat Code");
setCentered(*toolsWindow);
setVisible();
setFocused();
nameValue.setFocused();
acceptButton.setText(!item ? "Add" : "Edit");
}
auto CheatWindow::doChange() -> void {
bool valid = true;
nameValue.setBackgroundColor(nameValue.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
codeValue.setBackgroundColor(codeValue.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
acceptButton.setEnabled(valid);
}
auto CheatWindow::doAccept() -> void {
if(item) {
item.cell(0).setChecked(enabledOption.checked());
item.cell(1).setText(nameValue.text());
item.setProperty("code", codeValue.text());
} else {
toolsWindow->cheatEditor.addCheat(nameValue.text(), codeValue.text(), enabledOption.checked());
}
setVisible(false);
}
//
CheatEditor::CheatEditor(TabFrame* parent) : TabFrameItem(parent) {
setIcon(Icon::Edit::Replace);
setText("Cheat Editor");
layout.setMargin(5);
cheatList.append(TableViewHeader().setVisible()
.append(TableViewColumn())
.append(TableViewColumn().setText("Slot").setForegroundColor({0, 128, 0}).setAlignment(1.0))
.append(TableViewColumn().setText("Code(s)"))
.append(TableViewColumn().setText("Description").setExpandable())
);
for(uint slot : range(Slots)) {
cheatList.append(TableViewItem()
.append(TableViewCell().setCheckable())
.append(TableViewCell().setText(1 + slot))
.append(TableViewCell())
.append(TableViewCell())
);
}
cheatList.onChange([&] { doChangeSelected(); });
cheatList.onToggle([&](auto cell) {
cheats[cell.parent().offset()].enabled = cell.checked();
this->synchronizeCodes();
cheatList.onActivate([&] { modifyButton.doActivate(); });
cheatList.onChange([&] {
auto selected = cheatList.selected();
upButton.setEnabled((bool)selected && selected.offset() != 0);
downButton.setEnabled((bool)selected && selected.offset() != cheatList.itemCount() - 1);
modifyButton.setEnabled((bool)selected);
removeButton.setEnabled((bool)selected);
});
codeLabel.setText("Code(s):");
codeValue.setEnabled(false).onChange([&] { doModify(); });
descriptionLabel.setText("Description:");
descriptionValue.setEnabled(false).onChange([&] { doModify(); });
findCodesButton.setText("Find Codes ...").onActivate([&] { cheatDatabase->findCheats(); });
resetButton.setText("Reset").onActivate([&] { doReset(); });
eraseButton.setText("Erase").onActivate([&] { doErase(); });
//do not display "Find Codes" button if there is no cheat database to look up codes in
if(!file::exists(locate("cheats.bml"))) findCodesButton.setVisible(false);
}
auto CheatEditor::doChangeSelected() -> void {
if(auto item = cheatList.selected()) {
auto& cheat = cheats[item.offset()];
codeValue.setEnabled(true).setText(cheat.code);
descriptionValue.setEnabled(true).setText(cheat.description);
eraseButton.setEnabled(true);
} else {
codeValue.setEnabled(false).setText("");
descriptionValue.setEnabled(false).setText("");
eraseButton.setEnabled(false);
}
}
auto CheatEditor::doModify() -> void {
if(auto item = cheatList.selected()) {
auto& cheat = cheats[item.offset()];
cheat.code = codeValue.text();
cheat.description = descriptionValue.text();
doRefresh();
synchronizeCodes();
}
}
auto CheatEditor::doRefresh() -> void {
for(uint slot : range(Slots)) {
auto& cheat = cheats[slot];
if(cheat.code || cheat.description) {
auto codes = cheat.code.split("+");
if(codes.size() > 1) codes[0].append("+...");
cheatList.item(slot).cell(0).setChecked(cheat.enabled);
cheatList.item(slot).cell(2).setText(codes[0]);
cheatList.item(slot).cell(3).setText(cheat.description).setForegroundColor({0, 0, 0});
} else {
cheatList.item(slot).cell(0).setChecked(false);
cheatList.item(slot).cell(2).setText("");
cheatList.item(slot).cell(3).setText("<empty>").setForegroundColor({128, 128, 128});
cheatList.onToggle([&](TableViewCell) { synchronizeCodes(); });
upButton.setIcon(Icon::Go::Up).onActivate([&] {
if(auto item = cheatList.selected()) {
swap(item.offset(), item.offset() - 1);
}
}
cheatList.resizeColumns();
});
downButton.setIcon(Icon::Go::Down).onActivate([&] {
if(auto item = cheatList.selected()) {
swap(item.offset(), item.offset() + 1);
}
});
findCheatsButton.setText("Find Cheats ...").onActivate([&] {
cheatDatabase->findCheats();
});
resetButton.setText("Reset").onActivate([&] {
if(MessageDialog("Are you sure you want to permanently erase all cheat codes?").setParent(*toolsWindow).question() == "Yes") {
cheatList.reset().append(TableViewHeader()
.append(TableViewColumn())
.append(TableViewColumn().setExpandable())
.setVisible(false)
);
synchronizeCodes();
}
});
appendButton.setText("Add").onActivate([&] {
cheatWindow->show();
});
modifyButton.setText("Edit").onActivate([&] {
if(auto item = cheatList.selected()) {
cheatWindow->show(item);
}
});
removeButton.setText("Remove").onActivate([&] {
if(auto item = cheatList.selected()) {
cheatList.remove(item).doChange();
}
});
//do not display "Find Cheats" button if there is no cheat database available
if(!file::exists(locate("cheats.bml"))) findCheatsButton.setVisible(false);
}
auto CheatEditor::doReset(bool force) -> void {
if(force || MessageDialog().setParent(*toolsWindow).setText("Permamently erase all cheats?").question() == "Yes") {
for(auto& cheat : cheats) cheat = {};
for(auto& item : cheatList.items()) item.cell(0).setChecked(false);
doChangeSelected();
doRefresh();
synchronizeCodes();
}
}
auto CheatEditor::doErase() -> void {
if(auto item = cheatList.selected()) {
cheats[item.offset()] = {};
codeValue.setText("");
descriptionValue.setText("");
doRefresh();
synchronizeCodes();
}
auto CheatEditor::swap(uint x, uint y) -> void {
auto itemX = cheatList.item(x);
auto itemY = cheatList.item(y);
auto enabled = itemX.cell(0).checked();
auto name = itemX.cell(1).text();
auto code = itemX.property("code");
itemX.cell(0).setChecked(itemY.cell(0).checked());
itemX.cell(1).setText(itemY.cell(1).text());
itemX.setProperty("code", itemY.property("code"));
itemY.cell(0).setChecked(enabled);
itemY.cell(1).setText(name);
itemY.setProperty("code", code);
itemY.setSelected();
cheatList.doChange();
}
auto CheatEditor::synchronizeCodes() -> void {
string_vector codes;
for(auto& cheat : cheats) {
if(!cheat.enabled || !cheat.code) continue;
codes.append(cheat.code);
for(auto item : cheatList.items()) {
if(item.cell(0).checked()) codes.append(item.property("code"));
}
emulator->cheatSet(codes);
}
auto CheatEditor::addCode(bool enabled, string code, string description) -> bool {
for(auto& cheat : cheats) {
if(cheat.code || cheat.description) continue;
cheat.enabled = enabled;
cheat.code = code;
cheat.description = description;
return true;
}
return false;
auto CheatEditor::addCheat(string name, string code, bool enabled) -> void {
cheatList.append(TableViewItem()
.append(TableViewCell().setChecked(enabled))
.append(TableViewCell().setText(name))
.setProperty("code", code)
).resizeColumns();
}
auto CheatEditor::loadCheats() -> void {
doReset(true);
cheatList.reset().append(TableViewHeader()
.append(TableViewColumn())
.append(TableViewColumn().setExpandable())
.setVisible(false)
);
auto location = program->path("Cheats", program->superNintendo.location, ".cht");
auto document = BML::unserialize(string::read(location));
for(auto cheat : document.find("cheat")) {
if(!addCode((bool)cheat["enabled"], cheat["code"].text(), cheat["description"].text())) break;
addCheat(cheat["name"].text(), cheat["code"].text(), (bool)cheat["enabled"]);
}
doRefresh();
cheatList.doChange();
synchronizeCodes();
}
auto CheatEditor::saveCheats() -> void {
string document;
for(auto& cheat : cheats) {
if(!cheat.code && !cheat.description) continue;
for(auto item : cheatList.items()) {
document.append("cheat\n");
document.append(" description: ", cheat.description, "\n");
document.append(" code: ", cheat.code, "\n");
if(cheat.enabled)
document.append(" name: ", item.cell(1).text(), "\n");
document.append(" code: ", item.property("code"), "\n");
if(item.cell(0).checked())
document.append(" enabled\n");
document.append("\n");
}

View File

@ -1,7 +1,7 @@
#include "../bsnes.hpp"
#include "cheat-database.cpp"
#include "cheat-editor.cpp"
unique_pointer<CheatDatabase> cheatDatabase;
unique_pointer<CheatWindow> cheatWindow;
unique_pointer<ToolsWindow> toolsWindow;
ToolsWindow::ToolsWindow() {
@ -17,10 +17,19 @@ ToolsWindow::ToolsWindow() {
onSize([&] {
cheatEditor.cheatList.resizeColumns();
});
onClose([&] {
setVisible(false);
});
}
auto ToolsWindow::setVisible(bool visible) -> ToolsWindow& {
return Window::setVisible(visible), *this;
Window::setVisible(visible);
if(!visible) {
cheatDatabase->setVisible(false);
cheatWindow->setVisible(false);
}
return *this;
}
auto ToolsWindow::show(uint index) -> void {

View File

@ -13,6 +13,52 @@ public:
Button addCheatsButton{&controlLayout, Size{100, 0}};
};
struct CheatWindow : Window {
CheatWindow();
auto show(TableViewItem item = {}) -> void;
auto doChange() -> void;
auto doAccept() -> void;
public:
TableViewItem item;
VerticalLayout layout{this};
HorizontalLayout nameLayout{&layout, Size{~0, 0}};
Label nameLabel{&nameLayout, Size{40, 0}};
LineEdit nameValue{&nameLayout, Size{~0, 0}};
HorizontalLayout codeLayout{&layout, Size{~0, 0}};
Label codeLabel{&codeLayout, Size{40, 0}};
LineEdit codeValue{&codeLayout, Size{~0, 0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Widget spacer{&controlLayout, Size{40, 0}};
CheckLabel enabledOption{&controlLayout, Size{~0, 0}};
Button acceptButton{&controlLayout, Size{80, 0}};
Button cancelButton{&controlLayout, Size{80, 0}};
};
struct CheatEditor : TabFrameItem {
CheatEditor(TabFrame*);
auto swap(uint x, uint y) -> void;
auto synchronizeCodes() -> void;
auto addCheat(string name, string code, bool enabled = false) -> void;
auto loadCheats() -> void;
auto saveCheats() -> void;
public:
VerticalLayout layout{this};
TableView cheatList{&layout, Size{~0, ~0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Button upButton{&controlLayout, Size{0, 0}};
Button downButton{&controlLayout, Size{0, 0}};
Button findCheatsButton{&controlLayout, Size{120, 0}};
Widget spacer{&controlLayout, Size{~0, 0}};
Button resetButton{&controlLayout, Size{80, 0}};
Button appendButton{&controlLayout, Size{80, 0}};
Button modifyButton{&controlLayout, Size{80, 0}};
Button removeButton{&controlLayout, Size{80, 0}};
};
/*
struct CheatEditor : TabFrameItem {
enum : uint { Slots = 128 };
@ -49,6 +95,7 @@ public:
Button resetButton{&controlLayout, Size{80, 0}};
Button eraseButton{&controlLayout, Size{80, 0}};
};
*/
struct ToolsWindow : Window {
ToolsWindow();
@ -62,4 +109,5 @@ public:
};
extern unique_pointer<CheatDatabase> cheatDatabase;
extern unique_pointer<CheatWindow> cheatWindow;
extern unique_pointer<ToolsWindow> toolsWindow;

View File

@ -1,6 +1,12 @@
#if defined(Hiro_ListView)
mListView::mListView() {
mTableView::onActivate([&] {
doActivate();
});
mTableView::onChange([&] {
doChange();
});
mTableView::onToggle([&](TableViewCell cell) {
if(auto item = cell->parentTableViewItem()) {
if(auto shared = item->instance.acquire()) {
@ -18,6 +24,14 @@ auto mListView::batched() const -> vector<ListViewItem> {
return result;
}
auto mListView::doActivate() const -> void {
if(state.onActivate) state.onActivate();
}
auto mListView::doChange() const -> void {
if(state.onChange) state.onChange();
}
auto mListView::doToggle(ListViewItem item) const -> void {
if(state.onToggle) state.onToggle(item);
}
@ -33,6 +47,16 @@ auto mListView::items() const -> vector<ListViewItem> {
return result;
}
auto mListView::onActivate(const function<void ()>& callback) -> type& {
state.onActivate = callback;
return *this;
}
auto mListView::onChange(const function<void ()>& callback) -> type& {
state.onChange = callback;
return *this;
}
auto mListView::onToggle(const function<void (ListViewItem)>& callback) -> type& {
state.onToggle = callback;
return *this;

View File

@ -11,15 +11,21 @@ struct mListView : mTableView {
mListView();
auto batched() const -> vector<ListViewItem>;
auto doActivate() const -> void;
auto doChange() const -> void;
auto doToggle(ListViewItem) const -> void;
auto item(uint position) const -> ListViewItem;
auto items() const -> vector<ListViewItem>;
auto onActivate(const function<void ()>& callback) -> type&;
auto onChange(const function<void ()>& callback) -> type&;
auto onToggle(const function<void (ListViewItem)>& callback) -> type&;
auto reset() -> type& override;
auto selected() const -> ListViewItem;
//private:
struct State {
function<void ()> onActivate;
function<void ()> onChange;
function<void (ListViewItem)> onToggle;
} state;
};

63
nall/adaptive-array.hpp Normal file
View File

@ -0,0 +1,63 @@
//deprecated
#pragma once
#include <nall/range.hpp>
namespace nall {
template<typename T, uint Capacity>
struct adaptive_array {
auto capacity() const -> uint { return Capacity; }
auto size() const -> uint { return _size; }
auto reset() -> void {
for(uint n : range(_size)) _pool.t[n].~T();
_size = 0;
}
auto operator[](uint index) -> T& {
#ifdef DEBUG
struct out_of_bounds {};
if(index >= Capacity) throw out_of_bounds{};
#endif
return _pool.t[index];
}
auto operator[](uint index) const -> const T& {
#ifdef DEBUG
struct out_of_bounds {};
if(index >= Capacity) throw out_of_bounds{};
#endif
return _pool.t[index];
}
auto append() -> T& {
new(_pool.t + _size) T;
return _pool.t[_size++];
}
auto append(const T& value) -> void {
new(_pool.t + _size++) T(value);
}
auto append(T&& value) -> void {
new(_pool.t + _size++) T(move(value));
}
auto begin() { return &_pool.t[0]; }
auto end() { return &_pool.t[_size]; }
auto begin() const { return &_pool.t[0]; }
auto end() const { return &_pool.t[_size]; }
private:
union U {
U() {}
~U() {}
T t[Capacity];
} _pool;
uint _size = 0;
};
}

View File

@ -1,61 +1,130 @@
#pragma once
#define DEBUG
#include <nall/range.hpp>
namespace nall {
template<typename T, uint Capacity>
struct array {
auto capacity() const -> uint { return Capacity; }
auto size() const -> uint { return _size; }
template<typename T> struct array;
auto reset() -> void {
for(uint n : range(_size)) _pool.t[n].~T();
_size = 0;
//usage: int x[256] => array<int, 256>
template<typename T, uint Size> struct array<T[Size]> {
array() = default;
array(const initializer_list<T>& source) {
uint index = 0;
for(auto& value : source) {
operator[](index++) = value;
}
}
auto operator[](uint index) -> T& {
alwaysinline auto operator[](uint index) -> T& {
#ifdef DEBUG
struct out_of_bounds {};
if(index >= Capacity) throw out_of_bounds{};
if(index >= Size) throw out_of_bounds{};
#endif
return _pool.t[index];
return values[index];
}
auto operator[](uint index) const -> const T& {
alwaysinline auto operator[](uint index) const -> const T& {
#ifdef DEBUG
struct out_of_bounds {};
if(index >= Capacity) throw out_of_bounds{};
if(index >= Size) throw out_of_bounds{};
#endif
return _pool.t[index];
return values[index];
}
auto append() -> T& {
new(_pool.t + _size) T;
return _pool.t[_size++];
alwaysinline auto operator()(uint index, const T& fallback = {}) const -> const T& {
if(index >= Size) return fallback;
return values[index];
}
auto append(const T& value) -> void {
new(_pool.t + _size++) T(value);
auto fill(const T& fill = {}) {
for(auto& value : values) value = fill;
}
auto append(T&& value) -> void {
new(_pool.t + _size++) T(move(value));
}
auto data() -> T* { return values; }
auto data() const -> const T* { return values; }
auto size() const -> uint { return Size; }
auto begin() { return &_pool.t[0]; }
auto end() { return &_pool.t[_size]; }
auto begin() -> T* { return &values[0]; }
auto end() -> T* { return &values[Size]; }
auto begin() const { return &_pool.t[0]; }
auto end() const { return &_pool.t[_size]; }
auto begin() const -> const T* { return &values[0]; }
auto end() const -> const T* { return &values[Size]; }
private:
union U {
U() {}
~U() {}
T t[Capacity];
} _pool;
uint _size = 0;
T values[Size];
};
template<typename T> struct array_view;
template<typename T, uint Size> struct array_view<T[Size]> {
array_view() = default;
template<uint Capacity>
array_view(array<T[Capacity]>& source, uint offset = 0) {
#ifdef DEBUG
struct out_of_bounds {};
if(offset + Size >= Capacity) throw out_of_bounds{};
#endif
values = &source.data()[offset];
}
template<uint Capacity>
array_view(T (&source)[Capacity], uint offset = 0) {
#ifdef DEBUG
struct out_of_bounds {};
if(offset + Size >= Capacity) throw out_of_bounds{};
#endif
values = &source[offset];
}
array_view(T* source, uint offset = 0) {
values = &source[offset];
}
explicit operator bool() const {
return values;
}
alwaysinline auto operator[](uint index) -> T& {
#ifdef DEBUG
struct out_of_bounds {};
if(index >= Size) throw out_of_bounds{};
#endif
return values[index];
}
alwaysinline auto operator[](uint index) const -> const T& {
#ifdef DEBUG
struct out_of_bounds {};
if(index >= Size) throw out_of_bounds{};
#endif
return values[index];
}
alwaysinline auto operator()(uint index, const T& fallback = {}) const -> const T& {
if(index >= Size) return fallback;
return values[index];
}
auto fill(const T& fill = {}) -> void {
for(uint index : range(Size)) values[index] = fill;
}
auto data() -> T* { return values; }
auto data() const -> const T* { return values; }
auto size() const -> uint { return Size; }
auto begin() -> T* { return &values[0]; }
auto end() -> T* { return &values[Size]; }
auto begin() const -> const T* { return &values[0]; }
auto end() const -> const T* { return &values[Size]; }
private:
T* values = nullptr;
};
}

View File

@ -40,6 +40,7 @@
#include <nall/maybe.hpp>
#include <nall/memory.hpp>
#include <nall/path.hpp>
#include <nall/pointer.hpp>
#include <nall/primitives.hpp>
#include <nall/property.hpp>
#include <nall/queue.hpp>

34
nall/pointer.hpp Normal file
View File

@ -0,0 +1,34 @@
#pragma once
namespace nall {
template<typename T>
struct pointer {
explicit operator bool() const { return value; }
pointer() = default;
pointer(T* source) { value = source; }
pointer(const pointer& source) { value = source.value; }
auto& operator=(T* source) { value = source; return *this; }
auto& operator=(const pointer& source) { value = source.value; return *this; }
auto operator()() -> T* { return value; }
auto operator()() const -> const T* { return value; }
auto operator->() -> T* { return value; }
auto operator->() const -> const T* { return value; }
auto operator*() -> T& { return *value; }
auto operator*() const -> const T& { return *value; }
auto reset() -> void { value = nullptr; }
auto data() -> T* { return value; }
auto data() const -> const T* { return value; }
private:
T* value = nullptr;
};
}

View File

@ -11,6 +11,7 @@
//- only plain-old-data can be stored. complex classes must provide serialize(serializer&);
//- floating-point usage is not portable across different implementations
#include <nall/array.hpp>
#include <nall/range.hpp>
#include <nall/stdint.hpp>
#include <nall/traits.hpp>
@ -96,6 +97,10 @@ struct serializer {
return *this;
}
template<typename T, uint Size> auto array(nall::array<T[Size]>& array) -> serializer& {
for(auto& value : array) operator()(value);
}
template<typename T> auto operator()(T& value, typename std::enable_if<has_serialize<T>::value>::type* = 0) -> serializer& { value.serialize(*this); return *this; }
template<typename T> auto operator()(T& value, typename std::enable_if<std::is_integral<T>::value>::type* = 0) -> serializer& { return integer(value); }
template<typename T> auto operator()(T& value, typename std::enable_if<std::is_floating_point<T>::value>::type* = 0) -> serializer& { return floatingpoint(value); }

View File

@ -66,8 +66,6 @@ template<typename T> inline auto pad(const T& value, long precision = 0, char pa
inline auto hex(uintmax value, long precision = 0, char padchar = '0') -> string;
inline auto octal(uintmax value, long precision = 0, char padchar = '0') -> string;
inline auto binary(uintmax value, long precision = 0, char padchar = '0') -> string;
inline auto pointer(uintptr value, long precision = 0) -> string;
template<typename T> inline auto pointer(const T* value, long precision = 0) -> string;
//match.hpp
inline auto tokenize(const char* s, const char* p) -> bool;

View File

@ -234,6 +234,22 @@ template<> struct stringify<const string_view&> {
const string_view& _view;
};
//pointers
template<typename T> struct stringify<T*> {
stringify(const T* source) {
if(!source) {
memory::copy(_data, "(nullptr)", 10);
} else {
memory::copy(_data, "0x", 2);
fromNatural(_data + 2, (uintptr)source);
}
}
auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); }
char _data[256];
};
//
template<typename T> auto make_string(T value) -> stringify<T> {

View File

@ -133,14 +133,4 @@ auto binary(uintmax value, long precision, char padchar) -> string {
return buffer;
}
auto pointer(uintptr value, long precision) -> string {
if(value == 0) return "(nullptr)";
return {"0x", hex(value, precision)};
}
template<typename T> auto pointer(const T* value, long precision) -> string {
if(value == nullptr) return "(nullptr)";
return {"0x", hex((uintptr)value, precision)};
}
}