diff --git a/genius/GNUmakefile b/genius/GNUmakefile
deleted file mode 100644
index f119cd8f..00000000
--- a/genius/GNUmakefile
+++ /dev/null
@@ -1,59 +0,0 @@
-name := genius
-build := stable
-flags += -I..
-
-nall.path := ../nall
-include $(nall.path)/GNUmakefile
-
-hiro.path := ../hiro
-hiro.resource := data/$(name).rc
-include $(hiro.path)/GNUmakefile
-
-objects := obj/genius.o
-
-obj/genius.o: genius.cpp
-
-all: $(hiro.objects) $(objects)
- $(info Linking out/$(name) ...)
- +@$(compiler) -o out/$(name) $(hiro.objects) $(objects) $(hiro.options) $(options)
-ifeq ($(platform),macos)
- rm -rf out/$(name).app
- mkdir -p out/$(name).app/Contents/MacOS/
- mkdir -p out/$(name).app/Contents/Resources/
- mv out/$(name) out/$(name).app/Contents/MacOS/$(name)
- cp data/$(name).plist out/$(name).app/Contents/Info.plist
- sips -s format icns data/$(name).png --out out/$(name).app/Contents/Resources/$(name).icns
-endif
-
-verbose: hiro.verbose nall.verbose all;
-
-clean:
-ifeq ($(platform),macos)
- rm -rf out/$(name).app
-endif
- $(call delete,obj/*)
- $(call delete,out/*)
-
-install: all
-ifeq ($(platform),macos)
- cp -R out/$(name).app /Applications/$(name).app
-else ifneq ($(filter $(platform),linux bsd),)
- mkdir -p $(prefix)/bin/
- mkdir -p $(prefix)/share/applications/
- mkdir -p $(prefix)/share/icons/
- mkdir -p $(prefix)/share/$(name)/
- cp out/$(name) $(prefix)/bin/$(name)
- cp data/$(name).desktop $(prefix)/share/applications/$(name).desktop
- cp data/$(name).png $(prefix)/share/icons/$(name).png
-endif
-
-uninstall:
-ifeq ($(platform),macos)
- rm -rf /Applications/$(name).app
-else ifneq ($(filter $(platform),linux bsd),)
- rm -f $(prefix)/bin/$(name)
- rm -f $(prefix)/share/applications/$(name).desktop
- rm -f $(prefix)/share/icons/$(name).png
-endif
-
--include obj/*.d
diff --git a/genius/data/genius.Manifest b/genius/data/genius.Manifest
deleted file mode 100644
index 2491101a..00000000
--- a/genius/data/genius.Manifest
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- false
-
-
-
diff --git a/genius/data/genius.desktop b/genius/data/genius.desktop
deleted file mode 100644
index 4218c54f..00000000
--- a/genius/data/genius.desktop
+++ /dev/null
@@ -1,8 +0,0 @@
-[Desktop Entry]
-Name=genius
-Comment=Emulator
-Exec=genius
-Icon=genius
-Terminal=false
-Type=Application
-Categories=Game;Emulator;
diff --git a/genius/data/genius.ico b/genius/data/genius.ico
deleted file mode 100644
index b5859acf..00000000
Binary files a/genius/data/genius.ico and /dev/null differ
diff --git a/genius/data/genius.plist b/genius/data/genius.plist
deleted file mode 100644
index 9618f8d7..00000000
--- a/genius/data/genius.plist
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
- CFBundleIdentifier
- org.byuu.genius
- CFBundleDisplayName
- genius
- CFBundleExecutable
- genius
- CFBundleIconFile
- genius.icns
- NSHighResolutionCapable
-
- NSSupportsAutomaticGraphicsSwitching
-
-
-
diff --git a/genius/data/genius.png b/genius/data/genius.png
deleted file mode 100644
index b32718b1..00000000
Binary files a/genius/data/genius.png and /dev/null differ
diff --git a/genius/data/genius.rc b/genius/data/genius.rc
deleted file mode 100644
index b6cbd16c..00000000
--- a/genius/data/genius.rc
+++ /dev/null
@@ -1,2 +0,0 @@
-1 24 "genius.Manifest"
-2 ICON DISCARDABLE "genius.ico"
diff --git a/genius/data/genius.svg b/genius/data/genius.svg
deleted file mode 100644
index aaa7c846..00000000
--- a/genius/data/genius.svg
+++ /dev/null
@@ -1,80 +0,0 @@
-
-
-
-
diff --git a/genius/genius.cpp b/genius/genius.cpp
deleted file mode 100644
index 85528b2c..00000000
--- a/genius/genius.cpp
+++ /dev/null
@@ -1,629 +0,0 @@
-#include
-using namespace nall;
-
-#include
-using namespace hiro;
-
-#include "genius.hpp"
-unique_pointer listWindow;
-unique_pointer gameWindow;
-unique_pointer memoryWindow;
-unique_pointer oscillatorWindow;
-
-//
-
-ListWindow::ListWindow() {
- listWindow = this;
-
- fileMenu.setText("File");
- newAction.setText("New").onActivate([&] { newDatabase(); });
- openAction.setText("Open ...").onActivate([&] {
- if(auto location = BrowserDialog().setParent(*this).setFilters({"*.bml"}).openFile()) {
- loadDatabase(location);
- }
- });
- saveAction.setText("Save").onActivate([&] {
- if(!location) return saveAsAction.doActivate();
- saveDatabase(location);
- });
- saveAsAction.setText("Save As ...").onActivate([&] {
- if(auto location = BrowserDialog().setParent(*this).setFilters({"*.bml"}).saveFile()) {
- saveDatabase(location);
- }
- });
- quitAction.setText("Quit").onActivate([&] { quit(); });
-
- helpMenu.setText("Help");
- aboutAction.setText("About ...").onActivate([&] {
- MessageDialog().setParent(*this).setTitle("About").setText({
- "genius\n",
- "Author: byuu\n",
- "Website: https://byuu.org/"
- }).information();
- });
-
- layout.setPadding(5);
- gameList.setHeadered();
- gameList.onActivate([&] { modifyButton.doActivate(); });
- gameList.onChange([&] { updateWindow(); });
- appendButton.setText("Append").onActivate([&] {
- setEnabled(false);
- gameWindow->show();
- });
- modifyButton.setText("Modify").onActivate([&] {
- if(auto item = gameList.selected()) {
- setEnabled(false);
- gameWindow->show(games[item.offset()]);
- }
- });
- removeButton.setText("Remove").onActivate([&] { removeGame(); });
-
- onClose([&] { quit(); });
-
- setSize({820, 600});
- reloadList();
- updateWindow();
- setCentered();
-}
-
-auto ListWindow::quit() -> void {
- if(!modified || MessageDialog().setParent(*this).setText({
- "Are you sure you want to quit without saving your changes?"
- }).question() == "Yes") {
- Application::quit();
- }
-}
-
-auto ListWindow::reloadList() -> void {
- gameList.reset();
- gameList.append(TableViewColumn().setText("Name").setExpandable());
- gameList.append(TableViewColumn().setText("Region"));
- gameList.append(TableViewColumn().setText("Revision"));
- gameList.append(TableViewColumn().setText("Board"));
- for(auto& game : games) {
- TableViewItem item{&gameList};
- item.append(TableViewCell().setText(game.name));
- item.append(TableViewCell().setText(game.region));
- item.append(TableViewCell().setText(game.revision));
- item.append(TableViewCell().setText(game.board));
- }
- Application::processEvents();
- gameList.resizeColumns();
-}
-
-auto ListWindow::updateWindow() -> void {
- modifyButton.setEnabled((bool)gameList.selected());
- removeButton.setEnabled((bool)gameList.selected());
- string name = Location::base(location);
- if(!name) name = "(Untitled)";
- setTitle({modified ? "*" : "", name, " [", games.size(), "] - genius"});
-}
-
-auto ListWindow::newDatabase() -> void {
- games.reset();
- modified = false;
- location = "";
- reloadList();
- updateWindow();
-}
-
-auto ListWindow::loadDatabase(string location) -> void {
- auto document = BML::unserialize(string::read(location));
-
- games.reset();
- for(auto node : document.find("game")) {
- Game game;
- game.sha256 = node["sha256"].text();
- game.label = node["label"].text();
- game.name = node["name"].text();
- game.region = node["region"].text();
- game.revision = node["revision"].text();
- game.board = node["board"].text();
- for(auto object : node["board"]) {
- Component component;
- if(object.name() == "memory") {
- component.type = Component::Type::Memory;
- component.memory.type = object["type"].text();
- component.memory.size = object["size"].text();
- component.memory.content = object["content"].text();
- component.memory.manufacturer = object["manufacturer"].text();
- component.memory.architecture = object["architecture"].text();
- component.memory.identifier = object["identifier"].text();
- component.memory.Volatile = (bool)object["volatile"];
- }
- if(object.name() == "oscillator") {
- component.type = Component::Type::Oscillator;
- component.oscillator.frequency = object["frequency"].text();
- }
- game.components.append(component);
- }
- game.note = node["note"].text();
- games.append(game);
- }
-
- modified = false;
- this->location = location;
- reloadList();
- updateWindow();
-}
-
-auto ListWindow::saveDatabase(string location) -> void {
- auto fp = file::open(location, file::mode::write);
- if(!fp) return MessageDialog().setParent(*this).setText({
- "Error: failed to write file.\n\n",
- "Name: ", location
- }).error(), void();
-
- auto copy = games;
- copy.sort([](auto x, auto y) {
- return string::icompare(
- {x.name, "\n", x.region, "\n", x.revision},
- {y.name, "\n", y.region, "\n", y.revision}
- ) < 0;
- });
-
- fp.print("database\n");
- fp.print(" revision: ", chrono::local::date(), "\n\n");
-
- for(auto& game : copy) {
- fp.print("game\n");
- fp.print(" sha256: ", game.sha256, "\n");
- if(game.label)
- fp.print(" label: ", game.label, "\n");
- fp.print(" name: ", game.name, "\n");
- fp.print(" region: ", game.region, "\n");
- fp.print(" revision: ", game.revision, "\n");
- if(game.board)
- fp.print(" board: ", game.board, "\n");
- else if(game.components)
- fp.print(" board\n");
- for(auto& component : game.components) {
- if(component.type == Component::Type::Memory) {
- fp.print(" memory\n");
- fp.print(" type: ", component.memory.type, "\n");
- fp.print(" size: ", component.memory.size, "\n");
- fp.print(" content: ", component.memory.content, "\n");
- if(component.memory.manufacturer)
- fp.print(" manufacturer: ", component.memory.manufacturer, "\n");
- if(component.memory.architecture)
- fp.print(" architecture: ", component.memory.architecture, "\n");
- if(component.memory.identifier)
- fp.print(" identifier: ", component.memory.identifier, "\n");
- if(component.memory.Volatile)
- fp.print(" volatile\n");
- }
-
- if(component.type == Component::Type::Oscillator) {
- fp.print(" oscillator\n");
- fp.print(" frequency: ", component.oscillator.frequency, "\n");
- }
- }
- if(game.note)
- fp.print(" note: ", game.note, "\n");
- fp.print("\n");
- }
-
- modified = false;
- this->location = location;
- updateWindow();
-}
-
-auto ListWindow::appendGame(Game game) -> void {
- modified = true;
- auto offset = games.size();
- games.append(game);
- reloadList();
- gameList.item(offset).setSelected().setFocused();
- updateWindow();
-}
-
-auto ListWindow::modifyGame(Game game) -> void {
- if(auto item = gameList.selected()) {
- modified = true;
- auto offset = item.offset();
- games[offset] = game;
- reloadList();
- gameList.item(offset).setSelected().setFocused();
- updateWindow();
- }
-}
-
-auto ListWindow::removeGame() -> void {
- if(auto item = gameList.selected()) {
- if(MessageDialog().setParent(*this).setText({
- "Are you sure you want to permanently remove this game?\n\n",
- "Name: ", item.cell(0).text()
- }).question() == "Yes") {
- modified = true;
- games.remove(item.offset());
- reloadList();
- updateWindow();
- }
- }
-}
-
-//
-
-GameWindow::GameWindow() {
- gameWindow = this;
-
- layout.setPadding(5);
- hashLabel.setText("SHA256:").setAlignment(1.0);
- hashEdit.setFont(Font().setFamily(Font::Mono)).onChange([&] { modified = true, updateWindow(); });
- regionLabel.setText("Region:").setAlignment(1.0);
- regionEdit.setFont(Font().setFamily(Font::Mono)).onChange([&] { modified = true, updateWindow(); });
- revisionLabel.setText("Revision:");
- revisionEdit.setFont(Font().setFamily(Font::Mono)).onChange([&] { modified = true, updateWindow(); });
- boardLabel.setText("Board:");
- boardEdit.setFont(Font().setFamily(Font::Mono)).onChange([&] { modified = true, updateWindow(); });
- nameLabel.setText("Name:").setAlignment(1.0);
- nameEdit.onChange([&] { modified = true, updateWindow(); });
- labelLabel.setText("Label:").setAlignment(1.0);
- labelEdit.onChange([&] { modified = true, updateWindow(); });
- noteLabel.setText("Note:").setAlignment(1.0);
- noteEdit.onChange([&] { modified = true, updateWindow(); });
- componentLabel.setText("Tree:").setAlignment({1.0, 0.0});
- componentTree.onActivate([&] { modifyComponentButton.doActivate(); });
- componentTree.onChange([&] { updateWindow(); });
- appendMemoryButton.setText("Memory").onActivate([&] {
- setEnabled(false);
- memoryWindow->show();
- });
- appendOscillatorButton.setText("Oscillator").onActivate([&] {
- setEnabled(false);
- oscillatorWindow->show();
- });
- modifyComponentButton.setText("Modify").onActivate([&] {
- if(auto item = componentTree.selected()) {
- setEnabled(false);
- auto path = item.path().split("/");
- auto offset = path(0).natural();
- Component component = game.components[offset];
- if(component.type == Component::Type::Memory) {
- memoryWindow->show(component.memory);
- }
- if(component.type == Component::Type::Oscillator) {
- oscillatorWindow->show(component.oscillator);
- }
- }
- });
- removeComponentButton.setText("Remove").onActivate([&] { removeComponent(); });
- acceptButton.setText("Accept").onActivate([&] { accept(); });
- cancelButton.setText("Cancel").onActivate([&] { cancel(); });
-
- onClose([&] { cancel(); });
-
- setSize({640, 480});
- setDismissable();
-}
-
-auto GameWindow::show(Game game) -> void {
- this->game = game;
- modified = false;
- create = !game.sha256;
-
- hashEdit.setText(game.sha256);
- regionEdit.setText(game.region);
- revisionEdit.setText(game.revision);
- boardEdit.setText(game.board);
- nameEdit.setText(game.name);
- labelEdit.setText(game.label);
- noteEdit.setText(game.note);
- acceptButton.setText(create ? "Create" : "Apply");
-
- reloadList();
- updateWindow();
- setCentered(*listWindow);
- setVisible();
-
- if(create) {
- hashEdit.setFocused();
- } else {
- cancelButton.setFocused();
- }
-}
-
-auto GameWindow::accept() -> void {
- game.sha256 = hashEdit.text().strip();
- game.region = regionEdit.text().strip();
- game.revision = revisionEdit.text().strip();
- game.board = boardEdit.text().strip();
- game.name = nameEdit.text().strip();
- game.label = labelEdit.text().strip();
- game.note = noteEdit.text().strip();
-
- if(create) {
- listWindow->appendGame(game);
- } else {
- listWindow->modifyGame(game);
- }
-
- memoryWindow->setVisible(false);
- setVisible(false);
- listWindow->setEnabled();
- listWindow->setFocused();
-}
-
-auto GameWindow::cancel() -> void {
- if(!modified || MessageDialog().setParent(*this).setText({
- "Are you sure you want to discard your changes to this game?"
- }).question() == "Yes") {
- memoryWindow->setVisible(false);
- setVisible(false);
- listWindow->setEnabled();
- listWindow->setFocused();
- }
-}
-
-auto GameWindow::reloadList() -> void {
- componentTree.reset();
- uint counter = 1;
- for(auto& component : game.components) {
- TreeViewItem item;
-
- string index = {"[", counter++, "] "};
- if(component.type == Component::Type::Memory) {
- item.setText({index, "Memory"});
- item.append(TreeViewItem().setText({"Type: ", component.memory.type}));
- item.append(TreeViewItem().setText({"Size: ", component.memory.size}));
- item.append(TreeViewItem().setText({"Content: ", component.memory.content}));
- if(component.memory.manufacturer)
- item.append(TreeViewItem().setText({"Manufacturer: ", component.memory.manufacturer}));
- if(component.memory.architecture)
- item.append(TreeViewItem().setText({"Architecture: ", component.memory.architecture}));
- if(component.memory.identifier)
- item.append(TreeViewItem().setText({"Identifier: ", component.memory.identifier}));
- if(component.memory.Volatile)
- item.append(TreeViewItem().setText({"Volatile"}));
- }
-
- if(component.type == Component::Type::Oscillator) {
- item.setText({index, "Oscillator"});
- item.append(TreeViewItem().setText({"Frequency: ", component.oscillator.frequency}));
- }
-
- componentTree.append(item);
- }
-
- Application::processEvents();
- for(auto& item : componentTree.items()) item.setExpanded();
-}
-
-auto GameWindow::updateWindow() -> void {
- bool valid = true;
- bool hashValid = hashEdit.text().strip().size() == 64;
- hashEdit.setEditable(!hashValid).setBackgroundColor(
- !create || hashValid ? Color{192, 255, 192}
- : (valid = false, Color{255, 224, 224}));
- regionEdit.setBackgroundColor(regionEdit.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
- revisionEdit.setBackgroundColor(revisionEdit.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
- boardEdit.setBackgroundColor(boardEdit.text().strip() ? Color{} : (Color{255, 255, 240}));
- nameEdit.setBackgroundColor(nameEdit.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
- labelEdit.setBackgroundColor(labelEdit.text().strip() ? Color{} : (Color{255, 255, 240}));
- noteEdit.setBackgroundColor(noteEdit.text().strip() ? Color{} : (Color{255, 255, 240}));
- modifyComponentButton.setEnabled((bool)componentTree.selected());
- removeComponentButton.setEnabled((bool)componentTree.selected());
- acceptButton.setEnabled(valid);
- setTitle({modified ? "*" : "", create ? "Add New Game" : "Modify Game Details"});
- if(create && hashValid && hashEdit.focused()) regionEdit.setFocused();
-}
-
-auto GameWindow::appendComponent(Component component) -> void {
- modified = true;
- auto offset = game.components.size();
- game.components.append(component);
- reloadList();
- componentTree.item(offset).setSelected().setFocused();
- updateWindow();
-}
-
-auto GameWindow::modifyComponent(Component component) -> void {
- if(auto item = componentTree.selected()) {
- modified = true;
- auto path = item.path().split("/");
- auto offset = path(0).natural();
- game.components[offset] = component;
- reloadList();
- componentTree.item(offset).setSelected().setFocused();
- updateWindow();
- }
-}
-
-auto GameWindow::removeComponent() -> void {
- if(auto item = componentTree.selected()) {
- if(MessageDialog().setParent(*this).setText({
- "Are you sure you want to permanently remove this component?"
- }).question() == "Yes") {
- modified = true;
- auto path = item.path().split("/");
- auto offset = path(0).natural();
- game.components.remove(offset);
- reloadList();
- updateWindow();
- }
- }
-}
-
-//
-
-MemoryWindow::MemoryWindow() {
- memoryWindow = this;
-
- layout.setPadding(5);
- typeLabel.setText("Type:").setAlignment(1.0);
- typeEdit.append(ComboEditItem().setText("ROM"));
- typeEdit.append(ComboEditItem().setText("EEPROM"));
- typeEdit.append(ComboEditItem().setText("Flash"));
- typeEdit.append(ComboEditItem().setText("RAM"));
- typeEdit.append(ComboEditItem().setText("RTC"));
- typeEdit.onChange([&] { modified = true, updateWindow(); });
- sizeLabel.setText("Size:").setAlignment(1.0);
- sizeEdit.onChange([&] { modified = true, updateWindow(); });
- contentLabel.setText("Content:").setAlignment(1.0);
- contentEdit.append(ComboEditItem().setText("Program"));
- contentEdit.append(ComboEditItem().setText("Data"));
- contentEdit.append(ComboEditItem().setText("Character"));
- contentEdit.append(ComboEditItem().setText("Save"));
- contentEdit.append(ComboEditItem().setText("Time"));
- contentEdit.onChange([&] { modified = true, updateWindow(); });
- manufacturerLabel.setText("Manufacturer:").setAlignment(1.0);
- manufacturerEdit.onChange([&] { modified = true, updateWindow(); });
- architectureLabel.setText("Architecture:").setAlignment(1.0);
- architectureEdit.onChange([&] { modified = true, updateWindow(); });
- identifierLabel.setText("Identifier:").setAlignment(1.0);
- identifierEdit.onChange([&] { modified = true, updateWindow(); });
- volatileOption.setText("Volatile").onToggle([&] { modified = true, updateWindow(); });
- acceptButton.setText("Accept").onActivate([&] { accept(); });
- cancelButton.setText("Cancel").onActivate([&] { cancel(); });
-
- onClose([&] { cancel(); });
-
- setSize({320, layout.minimumSize().height()});
- setDismissable();
-}
-
-auto MemoryWindow::show(Memory memory) -> void {
- this->memory = memory;
- modified = false;
- create = !memory.type;
-
- typeEdit.setText(memory.type);
- sizeEdit.setText(memory.size);
- contentEdit.setText(memory.content);
- manufacturerEdit.setText(memory.manufacturer);
- architectureEdit.setText(memory.architecture);
- identifierEdit.setText(memory.identifier);
- volatileOption.setChecked(memory.Volatile);
-
- updateWindow();
- setCentered(*gameWindow);
- setVisible();
-
- typeEdit.setFocused();
-}
-
-auto MemoryWindow::accept() -> void {
- memory.type = typeEdit.text().strip();
- memory.size = sizeEdit.text().strip();
- memory.content = contentEdit.text().strip();
- memory.manufacturer = manufacturerEdit.text().strip();
- memory.architecture = architectureEdit.text().strip();
- memory.identifier = identifierEdit.text().strip();
- memory.Volatile = volatileOption.checked() && (memory.type == "RAM" || memory.type == "RTC");
-
- Component component{Component::Type::Memory};
- component.memory = memory;
- if(create) {
- gameWindow->appendComponent(component);
- } else {
- gameWindow->modifyComponent(component);
- }
-
- setVisible(false);
- gameWindow->setEnabled();
- gameWindow->setFocused();
-}
-
-auto MemoryWindow::cancel() -> void {
- if(!modified || MessageDialog().setParent(*this).setText({
- "Are you sure you want to discard your changes to this memory?"
- }).question() == "Yes") {
- setVisible(false);
- gameWindow->setEnabled();
- gameWindow->setFocused();
- }
-}
-
-auto MemoryWindow::updateWindow() -> void {
- bool valid = true;
- typeEdit.setBackgroundColor(typeEdit.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
- sizeEdit.setBackgroundColor(sizeEdit.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
- contentEdit.setBackgroundColor(contentEdit.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
- manufacturerEdit.setBackgroundColor(manufacturerEdit.text().strip() ? Color{} : (Color{255, 255, 240}));
- architectureEdit.setBackgroundColor(architectureEdit.text().strip() ? Color{} : (Color{255, 255, 240}));
- identifierEdit.setBackgroundColor(identifierEdit.text().strip() ? Color{} : (Color{255, 255, 240}));
- volatileOption.setEnabled(typeEdit.text().strip() == "RAM" || typeEdit.text().strip() == "RTC");
- acceptButton.setEnabled(valid);
- setTitle({modified ? "*" : "", create ? "Add New Memory" : "Modify Memory Details"});
-}
-
-//
-
-OscillatorWindow::OscillatorWindow() {
- oscillatorWindow = this;
-
- layout.setPadding(5);
- frequencyLabel.setText("Frequency:").setAlignment(1.0);
- frequencyEdit.onChange([&] { modified = true, updateWindow(); });
- acceptButton.setText("Accept").onActivate([&] { accept(); });
- cancelButton.setText("Cancel").onActivate([&] { cancel(); });
-
- onClose([&] { cancel(); });
-
- setSize({320, layout.minimumSize().height()});
- setDismissable();
-}
-
-auto OscillatorWindow::show(Oscillator oscillator) -> void {
- this->oscillator = oscillator;
- modified = false;
- create = !oscillator.frequency;
-
- frequencyEdit.setText(oscillator.frequency);
-
- updateWindow();
- setCentered(*gameWindow);
- setVisible();
-
- frequencyEdit.setFocused();
-}
-
-auto OscillatorWindow::accept() -> void {
- oscillator.frequency = frequencyEdit.text().strip();
-
- Component component{Component::Type::Oscillator};
- component.oscillator = oscillator;
- if(create) {
- gameWindow->appendComponent(component);
- } else {
- gameWindow->modifyComponent(component);
- }
-
- setVisible(false);
- gameWindow->setEnabled();
- gameWindow->setFocused();
-}
-
-auto OscillatorWindow::cancel() -> void {
- if(!modified || MessageDialog().setParent(*this).setText({
- "Are you sure you want to discard your changes to this property?"
- }).question() == "Yes") {
- setVisible(false);
- gameWindow->setEnabled();
- gameWindow->setFocused();
- }
-}
-
-auto OscillatorWindow::updateWindow() -> void {
- bool valid = true;
- frequencyEdit.setBackgroundColor(frequencyEdit.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
- acceptButton.setEnabled(valid);
- setTitle({modified ? "*" : "", create ? "Add New Property" : "Modify Property Details"});
-}
-
-//
-
-auto hiro::initialize() -> void {
- Application::setName("genius");
-}
-
-#include
-auto nall::main(Arguments) -> void {
- new ListWindow;
- new GameWindow;
- new MemoryWindow;
- new OscillatorWindow;
-
- listWindow->setVisible();
- Application::run();
-}
diff --git a/genius/genius.hpp b/genius/genius.hpp
deleted file mode 100644
index 43ec1b46..00000000
--- a/genius/genius.hpp
+++ /dev/null
@@ -1,178 +0,0 @@
-struct Memory {
- string type;
- string size;
- string content;
- string manufacturer;
- string architecture;
- string identifier;
- boolean Volatile;
-};
-
-struct Oscillator {
- string frequency;
-};
-
-//variant meta-class
-struct Component {
- enum class Type : uint {
- Memory,
- Oscillator,
- } type;
- Memory memory;
- Oscillator oscillator;
-};
-
-struct Game {
- string sha256;
- string region;
- string revision;
- string board;
- string name;
- string label;
- string note;
- vector components;
-};
-
-struct ListWindow : Window {
- ListWindow();
- auto quit() -> void;
- auto reloadList() -> void;
- auto updateWindow() -> void;
- auto newDatabase() -> void;
- auto loadDatabase(string) -> void;
- auto saveDatabase(string) -> void;
- auto appendGame(Game) -> void;
- auto modifyGame(Game) -> void;
- auto removeGame() -> void;
-
-private:
- bool modified = false;
- vector games;
- string location;
-
- MenuBar menuBar{this};
- Menu fileMenu{&menuBar};
- MenuItem newAction{&fileMenu};
- MenuItem openAction{&fileMenu};
- MenuItem saveAction{&fileMenu};
- MenuItem saveAsAction{&fileMenu};
- MenuSeparator quitSeparator{&fileMenu};
- MenuItem quitAction{&fileMenu};
- Menu helpMenu{&menuBar};
- MenuItem aboutAction{&helpMenu};
-
- HorizontalLayout layout{this};
- TableView gameList{&layout, Size{~0, ~0}};
- VerticalLayout controlLayout{&layout, Size{80, ~0}};
- Button appendButton{&controlLayout, Size{~0, 0}};
- Button modifyButton{&controlLayout, Size{~0, 0}};
- Button removeButton{&controlLayout, Size{~0, 0}};
-};
-
-struct GameWindow : Window {
- GameWindow();
- auto show(Game = {}) -> void;
- auto accept() -> void;
- auto cancel() -> void;
- auto reloadList() -> void;
- auto updateWindow() -> void;
- auto appendComponent(Component) -> void;
- auto modifyComponent(Component) -> void;
- auto removeComponent() -> void;
-
-private:
- bool modified = false;
- bool create = true;
- Game game;
-
- VerticalLayout layout{this};
- HorizontalLayout hashLayout{&layout, Size{~0, 0}};
- Label hashLabel{&hashLayout, Size{50, 0}};
- LineEdit hashEdit{&hashLayout, Size{~0, 0}};
- HorizontalLayout infoLayout{&layout, Size{~0, 0}};
- Label regionLabel{&infoLayout, Size{50, 0}};
- LineEdit regionEdit{&infoLayout, Size{~0, 0}};
- Label revisionLabel{&infoLayout, Size{0, 0}};
- LineEdit revisionEdit{&infoLayout, Size{~0, 0}};
- Label boardLabel{&infoLayout, Size{0, 0}};
- LineEdit boardEdit{&infoLayout, Size{~0, 0}, 0};
- HorizontalLayout nameLayout{&layout, Size{~0, 0}};
- Label nameLabel{&nameLayout, Size{50, 0}};
- LineEdit nameEdit{&nameLayout, Size{~0, 0}};
- HorizontalLayout labelLayout{&layout, Size{~0, 0}};
- Label labelLabel{&labelLayout, Size{50, 0}};
- LineEdit labelEdit{&labelLayout, Size{~0, 0}};
- HorizontalLayout noteLayout{&layout, Size{~0, 0}};
- Label noteLabel{¬eLayout, Size{50, 0}};
- LineEdit noteEdit{¬eLayout, Size{~0, 0}};
- HorizontalLayout lowerLayout{&layout, Size{~0, ~0}};
- Label componentLabel{&lowerLayout, Size{50, ~0}};
- TreeView componentTree{&lowerLayout, Size{~0, ~0}};
- VerticalLayout controlLayout{&lowerLayout, Size{0, ~0}};
- Button appendMemoryButton{&controlLayout, Size{80, 0}};
- Button appendOscillatorButton{&controlLayout, Size{80, 0}};
- Button modifyComponentButton{&controlLayout, Size{80, 0}};
- Button removeComponentButton{&controlLayout, Size{80, 0}};
- Widget controlSpacer{&controlLayout, Size{0, ~0}};
- Button acceptButton{&controlLayout, Size{80, 0}};
- Button cancelButton{&controlLayout, Size{80, 0}};
-};
-
-struct MemoryWindow : Window {
- MemoryWindow();
- auto show(Memory = {}) -> void;
- auto accept() -> void;
- auto cancel() -> void;
- auto updateWindow() -> void;
-
-private:
- bool modified = false;
- bool create = true;
- Memory memory;
-
- VerticalLayout layout{this};
- HorizontalLayout infoLayout{&layout, Size{~0, 0}};
- Label typeLabel{&infoLayout, Size{80, 0}};
- ComboEdit typeEdit{&infoLayout, Size{~0, 0}};
- Label sizeLabel{&infoLayout, Size{0, 0}};
- LineEdit sizeEdit{&infoLayout, Size{~0, 0}};
- HorizontalLayout contentLayout{&layout, Size{~0, 0}};
- Label contentLabel{&contentLayout, Size{80, 0}};
- ComboEdit contentEdit{&contentLayout, Size{~0, 0}};
- HorizontalLayout manufacturerLayout{&layout, Size{~0, 0}};
- Label manufacturerLabel{&manufacturerLayout, Size{80, 0}};
- LineEdit manufacturerEdit{&manufacturerLayout, Size{~0, 0}};
- HorizontalLayout architectureLayout{&layout, Size{~0, 0}};
- Label architectureLabel{&architectureLayout, Size{80, 0}};
- LineEdit architectureEdit{&architectureLayout, Size{~0, 0}};
- HorizontalLayout identifierLayout{&layout, Size{~0, 0}};
- Label identifierLabel{&identifierLayout, Size{80, 0}};
- LineEdit identifierEdit{&identifierLayout, Size{~0, 0}};
- HorizontalLayout controlLayout{&layout, Size{~0, 0}};
- Widget controlSpacer{&controlLayout, Size{~0, 0}};
- CheckLabel volatileOption{&controlLayout, Size{0, 0}};
- Button acceptButton{&controlLayout, Size{80, 0}};
- Button cancelButton{&controlLayout, Size{80, 0}};
-};
-
-struct OscillatorWindow : Window {
- OscillatorWindow();
- auto show(Oscillator = {}) -> void;
- auto accept() -> void;
- auto cancel() -> void;
- auto updateWindow() -> void;
-
-private:
- bool modified = false;
- bool create = true;
- Oscillator oscillator;
-
- VerticalLayout layout{this};
- HorizontalLayout frequencyLayout{&layout, Size{~0, 0}};
- Label frequencyLabel{&frequencyLayout, Size{60, 0}};
- LineEdit frequencyEdit{&frequencyLayout, Size{~0, 0}};
- HorizontalLayout controlLayout{&layout, Size{~0, 0}};
- Widget controlSpacer{&controlLayout, Size{~0, 0}};
- Button acceptButton{&controlLayout, Size{80, 0}};
- Button cancelButton{&controlLayout, Size{80, 0}};
-};
diff --git a/genius/obj/.gitignore b/genius/obj/.gitignore
deleted file mode 100644
index 6142305d..00000000
--- a/genius/obj/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*.o
-*.d
diff --git a/genius/out/.gitignore b/genius/out/.gitignore
deleted file mode 100644
index 40663658..00000000
--- a/genius/out/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-genius
diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp
index ab8698ba..36791c41 100644
--- a/higan/emulator/emulator.hpp
+++ b/higan/emulator/emulator.hpp
@@ -31,7 +31,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
- static const string Version = "107";
+ static const string Version = "107.1";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "https://byuu.org/";
diff --git a/higan/sfc/GNUmakefile b/higan/sfc/GNUmakefile
index e8a9725c..b8f49690 100644
--- a/higan/sfc/GNUmakefile
+++ b/higan/sfc/GNUmakefile
@@ -10,6 +10,7 @@ objects += sfc-armdsp sfc-hitachidsp sfc-necdsp
objects += sfc-epsonrtc sfc-sharprtc
objects += sfc-spc7110 sfc-sdd1
objects += sfc-obc1 sfc-msu1
+objects += sfc-cx4 sfc-dsp1 sfc-dsp2 sfc-dsp4 sfc-st0010
objects += sfc-bsmemory sfc-sufamiturbo
obj/sfc-interface.o: sfc/interface/interface.cpp
@@ -49,5 +50,11 @@ obj/sfc-obc1.o: sfc/coprocessor/obc1/obc1.cpp
obj/sfc-msu1.o: sfc/coprocessor/msu1/msu1.cpp
+obj/sfc-cx4.o: sfc/coprocessor/cx4/cx4.cpp
+obj/sfc-dsp1.o: sfc/coprocessor/dsp1/dsp1.cpp
+obj/sfc-dsp2.o: sfc/coprocessor/dsp2/dsp2.cpp
+obj/sfc-dsp4.o: sfc/coprocessor/dsp4/dsp4.cpp
+obj/sfc-st0010.o: sfc/coprocessor/st0010/st0010.cpp
+
obj/sfc-bsmemory.o: sfc/slot/bsmemory/bsmemory.cpp
obj/sfc-sufamiturbo.o: sfc/slot/sufamiturbo/sufamiturbo.cpp
diff --git a/higan/sfc/cartridge/cartridge.hpp b/higan/sfc/cartridge/cartridge.hpp
index 741727b7..c07a9890 100644
--- a/higan/sfc/cartridge/cartridge.hpp
+++ b/higan/sfc/cartridge/cartridge.hpp
@@ -38,6 +38,12 @@ struct Cartridge {
boolean OBC1;
boolean MSU1;
+ boolean Cx4;
+ boolean DSP1;
+ boolean DSP2;
+ boolean DSP4;
+ boolean ST0010;
+
boolean GameBoySlot;
boolean BSMemorySlot;
boolean SufamiTurboSlotA;
diff --git a/higan/sfc/cartridge/load.cpp b/higan/sfc/cartridge/load.cpp
index 2034d66d..9aede3f0 100644
--- a/higan/sfc/cartridge/load.cpp
+++ b/higan/sfc/cartridge/load.cpp
@@ -406,8 +406,6 @@ auto Cartridge::loadARMDSP(Markup::Node node) -> void {
//processor(architecture=HG51BS169)
auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void {
- has.HitachiDSP = true;
-
for(auto& word : hitachidsp.dataROM) word = 0x000000;
for(auto& word : hitachidsp.dataRAM) word = 0x00;
@@ -419,10 +417,6 @@ auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void {
hitachidsp.Roms = roms; //1 or 2
hitachidsp.Mapping = 0; //0 or 1
- for(auto map : node.find("map")) {
- loadMap(map, {&HitachiDSP::readIO, &hitachidsp}, {&HitachiDSP::writeIO, &hitachidsp});
- }
-
if(auto memory = node["memory(type=ROM,content=Program)"]) {
loadMemory(hitachidsp.rom, memory, File::Required);
for(auto map : memory.find("map")) {
@@ -437,6 +431,19 @@ auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void {
}
}
+ if(configuration.hacks.coprocessors.hle) {
+ has.Cx4 = true;
+ for(auto map : node.find("map")) {
+ loadMap(map, {&Cx4::read, &cx4}, {&Cx4::write, &cx4});
+ }
+ if(auto memory = node["memory(type=RAM,content=Data,architecture=HG51BS169)"]) {
+ for(auto map : memory.find("map")) {
+ loadMap(map, {&Cx4::read, &cx4}, {&Cx4::write, &cx4});
+ }
+ }
+ return;
+ }
+
if(auto memory = node["memory(type=ROM,content=Data,architecture=HG51BS169)"]) {
if(auto file = game.memory(memory)) {
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read, File::Required)) {
@@ -455,13 +462,16 @@ auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void {
loadMap(map, {&HitachiDSP::readDRAM, &hitachidsp}, {&HitachiDSP::writeDRAM, &hitachidsp});
}
}
+
+ has.HitachiDSP = true;
+
+ for(auto map : node.find("map")) {
+ loadMap(map, {&HitachiDSP::readIO, &hitachidsp}, {&HitachiDSP::writeIO, &hitachidsp});
+ }
}
//processor(architecture=uPD7725)
auto Cartridge::loaduPD7725(Markup::Node node) -> void {
- has.NECDSP = true;
- necdsp.revision = NECDSP::Revision::uPD7725;
-
for(auto& word : necdsp.programROM) word = 0x000000;
for(auto& word : necdsp.dataROM) word = 0x0000;
for(auto& word : necdsp.dataRAM) word = 0x0000;
@@ -472,26 +482,55 @@ auto Cartridge::loaduPD7725(Markup::Node node) -> void {
necdsp.Frequency = 7'600'000;
}
- for(auto map : node.find("map")) {
- loadMap(map, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
- }
+ bool failed = false;
if(auto memory = node["memory(type=ROM,content=Program,architecture=uPD7725)"]) {
if(auto file = game.memory(memory)) {
- if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read, File::Required)) {
+ if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) {
for(auto n : range(2048)) necdsp.programROM[n] = fp->readl(3);
- }
+ } else failed = true;
}
}
if(auto memory = node["memory(type=ROM,content=Data,architecture=uPD7725)"]) {
if(auto file = game.memory(memory)) {
- if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read, File::Required)) {
+ if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) {
for(auto n : range(1024)) necdsp.dataROM[n] = fp->readl(2);
- }
+ } else failed = true;
}
}
+ if(failed || configuration.hacks.coprocessors.hle) {
+ auto manifest = BML::serialize(game.document);
+ if(manifest.find("identifier: DSP1")) { //also matches DSP1B
+ has.DSP1 = true;
+ for(auto map : node.find("map")) {
+ loadMap(map, {&DSP1::read, &dsp1}, {&DSP1::write, &dsp1});
+ }
+ return;
+ }
+ if(manifest.find("identifier: DSP2")) {
+ has.DSP2 = true;
+ for(auto map : node.find("map")) {
+ loadMap(map, {&DSP2::read, &dsp2}, {&DSP2::write, &dsp2});
+ }
+ return;
+ }
+ if(manifest.find("identifier: DSP4")) {
+ has.DSP4 = true;
+ for(auto map : node.find("map")) {
+ loadMap(map, {&DSP4::read, &dsp4}, {&DSP4::write, &dsp4});
+ }
+ return;
+ }
+ }
+
+ if(failed) {
+ //throw an error to the user
+ platform->open(ID::SuperFamicom, "", File::Read, File::Required);
+ return;
+ }
+
if(auto memory = node["memory(type=RAM,content=Data,architecture=uPD7725)"]) {
if(auto file = game.memory(memory)) {
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) {
@@ -502,13 +541,17 @@ auto Cartridge::loaduPD7725(Markup::Node node) -> void {
loadMap(map, {&NECDSP::readRAM, &necdsp}, {&NECDSP::writeRAM, &necdsp});
}
}
+
+ has.NECDSP = true;
+ necdsp.revision = NECDSP::Revision::uPD7725;
+
+ for(auto map : node.find("map")) {
+ loadMap(map, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
+ }
}
//processor(architecture=uPD96050)
auto Cartridge::loaduPD96050(Markup::Node node) -> void {
- has.NECDSP = true;
- necdsp.revision = NECDSP::Revision::uPD96050;
-
for(auto& word : necdsp.programROM) word = 0x000000;
for(auto& word : necdsp.dataROM) word = 0x0000;
for(auto& word : necdsp.dataRAM) word = 0x0000;
@@ -519,26 +562,43 @@ auto Cartridge::loaduPD96050(Markup::Node node) -> void {
necdsp.Frequency = 11'000'000;
}
- for(auto map : node.find("map")) {
- loadMap(map, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
- }
+ bool failed = false;
if(auto memory = node["memory(type=ROM,content=Program,architecture=uPD96050)"]) {
if(auto file = game.memory(memory)) {
- if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read, File::Required)) {
+ if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) {
for(auto n : range(16384)) necdsp.programROM[n] = fp->readl(3);
- }
+ } else failed = true;
}
}
if(auto memory = node["memory(type=ROM,content=Data,architecture=uPD96050)"]) {
if(auto file = game.memory(memory)) {
- if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read, File::Required)) {
+ if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) {
for(auto n : range(2048)) necdsp.dataROM[n] = fp->readl(2);
- }
+ } else failed = false;
}
}
+ if(failed || configuration.hacks.coprocessors.hle) {
+ auto manifest = BML::serialize(game.document);
+ if(manifest.find("identifier: ST010")) {
+ has.ST0010 = true;
+ if(auto memory = node["memory(type=RAM,content=Data,architecture=uPD96050)"]) {
+ for(auto map : memory.find("map")) {
+ loadMap(map, {&ST0010::read, &st0010}, {&ST0010::write, &st0010});
+ }
+ }
+ return;
+ }
+ }
+
+ if(failed) {
+ //throw an error to the user
+ platform->open(ID::SuperFamicom, "", File::Read, File::Required);
+ return;
+ }
+
if(auto memory = node["memory(type=RAM,content=Data,architecture=uPD96050)"]) {
if(auto file = game.memory(memory)) {
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) {
@@ -549,6 +609,13 @@ auto Cartridge::loaduPD96050(Markup::Node node) -> void {
loadMap(map, {&NECDSP::readRAM, &necdsp}, {&NECDSP::writeRAM, &necdsp});
}
}
+
+ has.NECDSP = true;
+ necdsp.revision = NECDSP::Revision::uPD96050;
+
+ for(auto map : node.find("map")) {
+ loadMap(map, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
+ }
}
//rtc(manufacturer=Epson)
diff --git a/higan/sfc/coprocessor/coprocessor.hpp b/higan/sfc/coprocessor/coprocessor.hpp
index 58ea81b2..f01516a7 100644
--- a/higan/sfc/coprocessor/coprocessor.hpp
+++ b/higan/sfc/coprocessor/coprocessor.hpp
@@ -18,3 +18,9 @@
#include
#include
+
+#include
+#include
+#include
+#include
+#include
diff --git a/higan/sfc/coprocessor/cx4/cx4.cpp b/higan/sfc/coprocessor/cx4/cx4.cpp
new file mode 100644
index 00000000..2417ba43
--- /dev/null
+++ b/higan/sfc/coprocessor/cx4/cx4.cpp
@@ -0,0 +1,191 @@
+#include
+
+namespace SuperFamicom {
+
+Cx4 cx4;
+#define CX4_CPP
+#include "data.cpp"
+#include "functions.cpp"
+#include "oam.cpp"
+#include "opcodes.cpp"
+#include "serialization.cpp"
+
+auto Cx4::power() -> void {
+ memset(ram, 0, 0x0c00);
+ memset(reg, 0, 0x0100);
+}
+
+uint32 Cx4::ldr(uint8 r) {
+ uint16 addr = 0x0080 + (r * 3);
+ return (reg[addr + 0] << 0)
+ | (reg[addr + 1] << 8)
+ | (reg[addr + 2] << 16);
+}
+
+void Cx4::str(uint8 r, uint32 data) {
+ uint16 addr = 0x0080 + (r * 3);
+ reg[addr + 0] = (data >> 0);
+ reg[addr + 1] = (data >> 8);
+ reg[addr + 2] = (data >> 16);
+}
+
+void Cx4::mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh) {
+ int64 rx = x & 0xffffff;
+ int64 ry = y & 0xffffff;
+ if(rx & 0x800000)rx |= ~0x7fffff;
+ if(ry & 0x800000)ry |= ~0x7fffff;
+
+ rx *= ry;
+
+ rl = (rx) & 0xffffff;
+ rh = (rx >> 24) & 0xffffff;
+}
+
+uint32 Cx4::sin(uint32 rx) {
+ r0 = rx & 0x1ff;
+ if(r0 & 0x100)r0 ^= 0x1ff;
+ if(r0 & 0x080)r0 ^= 0x0ff;
+ if(rx & 0x100) {
+ return sin_table[r0 + 0x80];
+ } else {
+ return sin_table[r0];
+ }
+}
+
+uint32 Cx4::cos(uint32 rx) {
+ return sin(rx + 0x080);
+}
+
+void Cx4::immediate_reg(uint32 start) {
+ r0 = ldr(0);
+ for(uint32 i = start; i < 48; i++) {
+ if((r0 & 0x0fff) < 0x0c00) {
+ ram[r0 & 0x0fff] = immediate_data[i];
+ }
+ r0++;
+ }
+ str(0, r0);
+}
+
+void Cx4::transfer_data() {
+ uint32 src;
+ uint16 dest, count;
+
+ src = (reg[0x40]) | (reg[0x41] << 8) | (reg[0x42] << 16);
+ count = (reg[0x43]) | (reg[0x44] << 8);
+ dest = (reg[0x45]) | (reg[0x46] << 8);
+
+ for(uint32 i=0;i> 2;
+ return;
+ }
+
+ switch(data) {
+ case 0x00: op00(); break;
+ case 0x01: op01(); break;
+ case 0x05: op05(); break;
+ case 0x0d: op0d(); break;
+ case 0x10: op10(); break;
+ case 0x13: op13(); break;
+ case 0x15: op15(); break;
+ case 0x1f: op1f(); break;
+ case 0x22: op22(); break;
+ case 0x25: op25(); break;
+ case 0x2d: op2d(); break;
+ case 0x40: op40(); break;
+ case 0x54: op54(); break;
+ case 0x5c: op5c(); break;
+ case 0x5e: op5e(); break;
+ case 0x60: op60(); break;
+ case 0x62: op62(); break;
+ case 0x64: op64(); break;
+ case 0x66: op66(); break;
+ case 0x68: op68(); break;
+ case 0x6a: op6a(); break;
+ case 0x6c: op6c(); break;
+ case 0x6e: op6e(); break;
+ case 0x70: op70(); break;
+ case 0x72: op72(); break;
+ case 0x74: op74(); break;
+ case 0x76: op76(); break;
+ case 0x78: op78(); break;
+ case 0x7a: op7a(); break;
+ case 0x7c: op7c(); break;
+ case 0x89: op89(); break;
+ }
+ }
+}
+
+void Cx4::writeb(uint16 addr, uint8 data) {
+ write(addr, data);
+}
+
+void Cx4::writew(uint16 addr, uint16 data) {
+ write(addr + 0, data >> 0);
+ write(addr + 1, data >> 8);
+}
+
+void Cx4::writel(uint16 addr, uint32 data) {
+ write(addr + 0, data >> 0);
+ write(addr + 1, data >> 8);
+ write(addr + 2, data >> 16);
+}
+
+uint8 Cx4::read(uint24 addr, uint8 data) {
+ addr &= 0x1fff;
+
+ if(addr < 0x0c00) {
+ return ram[addr];
+ }
+
+ if(addr >= 0x1f00) {
+ return reg[addr & 0xff];
+ }
+
+ return cpu.r.mdr;
+}
+
+uint8 Cx4::readb(uint16 addr) {
+ return read(addr);
+}
+
+uint16 Cx4::readw(uint16 addr) {
+ return read(addr) | (read(addr + 1) << 8);
+}
+
+uint32 Cx4::readl(uint16 addr) {
+ return read(addr) | (read(addr + 1) << 8) + (read(addr + 2) << 16);
+}
+
+}
diff --git a/higan/sfc/coprocessor/cx4/cx4.hpp b/higan/sfc/coprocessor/cx4/cx4.hpp
new file mode 100644
index 00000000..16bc3b0b
--- /dev/null
+++ b/higan/sfc/coprocessor/cx4/cx4.hpp
@@ -0,0 +1,90 @@
+struct Cx4 {
+ auto power() -> void;
+
+ auto read(uint24 addr, uint8 data = 0) -> uint8;
+ auto write(uint24 addr, uint8 data) -> void;
+
+ auto serialize(serializer&) -> void;
+
+ uint8 ram[0x0c00];
+ uint8 reg[0x0100];
+ uint32 r0, r1, r2, r3, r4, r5, r6, r7,
+ r8, r9, r10, r11, r12, r13, r14, r15;
+
+ static const uint8 immediate_data[48];
+ static const uint16 wave_data[40];
+ static const uint32 sin_table[256];
+
+ static const int16 SinTable[512];
+ static const int16 CosTable[512];
+
+ int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
+ int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
+
+ void C4TransfWireFrame();
+ void C4TransfWireFrame2();
+ void C4CalcWireFrame();
+ void C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color);
+ void C4DrawWireFrame();
+ void C4DoScaleRotate(int row_padding);
+
+public:
+ uint32 ldr(uint8 r);
+ void str(uint8 r, uint32 data);
+ void mul(uint32 x, uint32 y, uint32 &rl, uint32 &rh);
+ uint32 sin(uint32 rx);
+ uint32 cos(uint32 rx);
+
+ void transfer_data();
+ void immediate_reg(uint32 num);
+
+ void op00_00();
+ void op00_03();
+ void op00_05();
+ void op00_07();
+ void op00_08();
+ void op00_0b();
+ void op00_0c();
+
+ void op00();
+ void op01();
+ void op05();
+ void op0d();
+ void op10();
+ void op13();
+ void op15();
+ void op1f();
+ void op22();
+ void op25();
+ void op2d();
+ void op40();
+ void op54();
+ void op5c();
+ void op5e();
+ void op60();
+ void op62();
+ void op64();
+ void op66();
+ void op68();
+ void op6a();
+ void op6c();
+ void op6e();
+ void op70();
+ void op72();
+ void op74();
+ void op76();
+ void op78();
+ void op7a();
+ void op7c();
+ void op89();
+
+ uint8 readb(uint16 addr);
+ uint16 readw(uint16 addr);
+ uint32 readl(uint16 addr);
+
+ void writeb(uint16 addr, uint8 data);
+ void writew(uint16 addr, uint16 data);
+ void writel(uint16 addr, uint32 data);
+};
+
+extern Cx4 cx4;
diff --git a/higan/sfc/coprocessor/cx4/data.cpp b/higan/sfc/coprocessor/cx4/data.cpp
new file mode 100644
index 00000000..8538f602
--- /dev/null
+++ b/higan/sfc/coprocessor/cx4/data.cpp
@@ -0,0 +1,187 @@
+#ifdef CX4_CPP
+
+const uint8 Cx4::immediate_data[48] = {
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f,
+ 0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff,
+ 0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00
+};
+
+const uint16 Cx4::wave_data[40] = {
+ 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
+ 0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e,
+ 0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e,
+ 0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e,
+ 0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e
+};
+
+const uint32 Cx4::sin_table[256] = {
+ 0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6,
+ 0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb,
+ 0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d,
+ 0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e,
+ 0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5,
+ 0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a,
+ 0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6,
+ 0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8,
+ 0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2,
+ 0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318,
+ 0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046,
+ 0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b,
+ 0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b,
+ 0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73,
+ 0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70,
+ 0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb,
+ 0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09,
+ 0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124,
+ 0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2,
+ 0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1,
+ 0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a,
+ 0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465,
+ 0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009,
+ 0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37,
+ 0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e,
+ 0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7,
+ 0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9,
+ 0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4,
+ 0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4,
+ 0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d,
+ 0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f,
+ 0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004
+};
+
+const int16 Cx4::SinTable[512] = {
+ 0, 402, 804, 1206, 1607, 2009, 2410, 2811,
+ 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
+ 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
+ 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
+ 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
+ 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
+ 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
+ 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
+ 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
+ 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
+ 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
+ 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
+ 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
+ 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
+ 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
+ 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765,
+ 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
+ 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
+ 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
+ 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
+ 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
+ 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
+ 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
+ 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
+ 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
+ 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
+ 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
+ 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
+ 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
+ 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
+ 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
+ 3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
+ 0, -402, -804, -1206, -1607, -2009, -2410, -2811,
+ -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
+ -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
+ -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
+ -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
+ -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
+ -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
+ -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
+ -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
+ -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
+ -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
+ -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
+ -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
+ -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
+ -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
+ -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
+ -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
+ -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
+ -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
+ -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
+ -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
+ -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
+ -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
+ -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
+ -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
+ -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
+ -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
+ -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
+ -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
+ -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
+ -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
+ -3211, -2811, -2410, -2009, -1607, -1206, -804, -402
+};
+
+const int16 Cx4::CosTable[512] = {
+ 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
+ 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
+ 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
+ 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
+ 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
+ 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
+ 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
+ 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
+ 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
+ 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
+ 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
+ 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
+ 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
+ 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
+ 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
+ 3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
+ 0, -402, -804, -1206, -1607, -2009, -2410, -2811,
+ -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
+ -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
+ -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
+ -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
+ -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
+ -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
+ -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
+ -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
+ -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
+ -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
+ -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
+ -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
+ -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
+ -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
+ -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
+ -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
+ -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
+ -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
+ -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
+ -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
+ -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
+ -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
+ -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
+ -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
+ -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
+ -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
+ -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
+ -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
+ -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
+ -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
+ -3211, -2811, -2410, -2009, -1607, -1206, -804, -402,
+ 0, 402, 804, 1206, 1607, 2009, 2410, 2811,
+ 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
+ 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
+ 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
+ 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
+ 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
+ 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
+ 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
+ 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
+ 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
+ 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
+ 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
+ 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
+ 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
+ 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
+ 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765
+};
+
+#endif
diff --git a/higan/sfc/coprocessor/cx4/functions.cpp b/higan/sfc/coprocessor/cx4/functions.cpp
new file mode 100644
index 00000000..b4684dd4
--- /dev/null
+++ b/higan/sfc/coprocessor/cx4/functions.cpp
@@ -0,0 +1,251 @@
+#ifdef CX4_CPP
+
+#include
+#define Tan(a) (CosTable[a] ? ((((int32)SinTable[a]) << 16) / CosTable[a]) : 0x80000000)
+#define sar(b, n) ((b) >> (n))
+#ifdef PI
+#undef PI
+#endif
+#define PI 3.1415926535897932384626433832795
+
+//Wireframe Helpers
+void Cx4::C4TransfWireFrame() {
+ double c4x = (double)C4WFXVal;
+ double c4y = (double)C4WFYVal;
+ double c4z = (double)C4WFZVal - 0x95;
+ double tanval, c4x2, c4y2, c4z2;
+
+ //Rotate X
+ tanval = -(double)C4WFX2Val * PI * 2 / 128;
+ c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
+ c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
+
+ //Rotate Y
+ tanval = -(double)C4WFY2Val * PI * 2 / 128;
+ c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
+ c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
+
+ //Rotate Z
+ tanval = -(double)C4WFDist * PI * 2 / 128;
+ c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
+ c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
+
+ //Scale
+ C4WFXVal = (int16)(c4x * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
+ C4WFYVal = (int16)(c4y * C4WFScale / (0x90 * (c4z + 0x95)) * 0x95);
+}
+
+void Cx4::C4CalcWireFrame() {
+ C4WFXVal = C4WFX2Val - C4WFXVal;
+ C4WFYVal = C4WFY2Val - C4WFYVal;
+
+ if(abs(C4WFXVal) > abs(C4WFYVal)) {
+ C4WFDist = abs(C4WFXVal) + 1;
+ C4WFYVal = (256 * (long)C4WFYVal) / abs(C4WFXVal);
+ C4WFXVal = (C4WFXVal < 0) ? -256 : 256;
+ } else if(C4WFYVal != 0) {
+ C4WFDist = abs(C4WFYVal) + 1;
+ C4WFXVal = (256 * (long)C4WFXVal) / abs(C4WFYVal);
+ C4WFYVal = (C4WFYVal < 0) ? -256 : 256;
+ } else {
+ C4WFDist = 0;
+ }
+}
+
+void Cx4::C4TransfWireFrame2() {
+ double c4x = (double)C4WFXVal;
+ double c4y = (double)C4WFYVal;
+ double c4z = (double)C4WFZVal;
+ double tanval, c4x2, c4y2, c4z2;
+
+ //Rotate X
+ tanval = -(double)C4WFX2Val * PI * 2 / 128;
+ c4y2 = c4y * ::cos(tanval) - c4z * ::sin(tanval);
+ c4z2 = c4y * ::sin(tanval) + c4z * ::cos(tanval);
+
+ //Rotate Y
+ tanval = -(double)C4WFY2Val * PI * 2 / 128;
+ c4x2 = c4x * ::cos(tanval) + c4z2 * ::sin(tanval);
+ c4z = c4x * -::sin(tanval) + c4z2 * ::cos(tanval);
+
+ //Rotate Z
+ tanval = -(double)C4WFDist * PI * 2 / 128;
+ c4x = c4x2 * ::cos(tanval) - c4y2 * ::sin(tanval);
+ c4y = c4x2 * ::sin(tanval) + c4y2 * ::cos(tanval);
+
+ //Scale
+ C4WFXVal = (int16)(c4x * C4WFScale / 0x100);
+ C4WFYVal = (int16)(c4y * C4WFScale / 0x100);
+}
+
+void Cx4::C4DrawWireFrame() {
+ uint32 line = readl(0x1f80);
+ uint32 point1, point2;
+ int16 X1, Y1, Z1;
+ int16 X2, Y2, Z2;
+ uint8 Color;
+
+ for(int32 i = ram[0x0295]; i > 0; i--, line += 5) {
+ if(bus.read(line) == 0xff && bus.read(line + 1) == 0xff) {
+ int32 tmp = line - 5;
+ while(bus.read(tmp + 2) == 0xff && bus.read(tmp + 3) == 0xff && (tmp + 2) >= 0) { tmp -= 5; }
+ point1 = (read(0x1f82) << 16) | (bus.read(tmp + 2) << 8) | bus.read(tmp + 3);
+ } else {
+ point1 = (read(0x1f82) << 16) | (bus.read(line) << 8) | bus.read(line + 1);
+ }
+ point2 = (read(0x1f82) << 16) | (bus.read(line + 2) << 8) | bus.read(line + 3);
+
+ X1=(bus.read(point1 + 0) << 8) | bus.read(point1 + 1);
+ Y1=(bus.read(point1 + 2) << 8) | bus.read(point1 + 3);
+ Z1=(bus.read(point1 + 4) << 8) | bus.read(point1 + 5);
+ X2=(bus.read(point2 + 0) << 8) | bus.read(point2 + 1);
+ Y2=(bus.read(point2 + 2) << 8) | bus.read(point2 + 3);
+ Z2=(bus.read(point2 + 4) << 8) | bus.read(point2 + 5);
+ Color = bus.read(line + 4);
+ C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
+ }
+}
+
+void Cx4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) {
+ //Transform coordinates
+ C4WFXVal = (int16)X1;
+ C4WFYVal = (int16)Y1;
+ C4WFZVal = Z1;
+ C4WFScale = read(0x1f90);
+ C4WFX2Val = read(0x1f86);
+ C4WFY2Val = read(0x1f87);
+ C4WFDist = read(0x1f88);
+ C4TransfWireFrame2();
+ X1 = (C4WFXVal + 48) << 8;
+ Y1 = (C4WFYVal + 48) << 8;
+
+ C4WFXVal = (int16)X2;
+ C4WFYVal = (int16)Y2;
+ C4WFZVal = Z2;
+ C4TransfWireFrame2();
+ X2 = (C4WFXVal + 48) << 8;
+ Y2 = (C4WFYVal + 48) << 8;
+
+ //Get line info
+ C4WFXVal = (int16)(X1 >> 8);
+ C4WFYVal = (int16)(Y1 >> 8);
+ C4WFX2Val = (int16)(X2 >> 8);
+ C4WFY2Val = (int16)(Y2 >> 8);
+ C4CalcWireFrame();
+ X2 = (int16)C4WFXVal;
+ Y2 = (int16)C4WFYVal;
+
+ //Render line
+ for(int32 i = C4WFDist ? C4WFDist : (int16)1; i > 0; i--) {
+ if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) {
+ uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
+ uint8 bit = 0x80 >> ((X1 >> 8) & 7);
+ ram[addr + 0x300] &= ~bit;
+ ram[addr + 0x301] &= ~bit;
+ if(Color & 1) ram[addr + 0x300] |= bit;
+ if(Color & 2) ram[addr + 0x301] |= bit;
+ }
+ X1 += X2;
+ Y1 += Y2;
+ }
+}
+
+void Cx4::C4DoScaleRotate(int row_padding) {
+ int16 A, B, C, D;
+
+ //Calculate matrix
+ int32 XScale = readw(0x1f8f);
+ int32 YScale = readw(0x1f92);
+
+ if(XScale & 0x8000)XScale = 0x7fff;
+ if(YScale & 0x8000)YScale = 0x7fff;
+
+ if(readw(0x1f80) == 0) { //no rotation
+ A = (int16)XScale;
+ B = 0;
+ C = 0;
+ D = (int16)YScale;
+ } else if(readw(0x1f80) == 128) { //90 degree rotation
+ A = 0;
+ B = (int16)(-YScale);
+ C = (int16)XScale;
+ D = 0;
+ } else if(readw(0x1f80) == 256) { //180 degree rotation
+ A = (int16)(-XScale);
+ B = 0;
+ C = 0;
+ D = (int16)(-YScale);
+ } else if(readw(0x1f80) == 384) { //270 degree rotation
+ A = 0;
+ B = (int16)YScale;
+ C = (int16)(-XScale);
+ D = 0;
+ } else {
+ A = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * XScale, 15);
+ B = (int16)(-sar(SinTable[readw(0x1f80) & 0x1ff] * YScale, 15));
+ C = (int16) sar(SinTable[readw(0x1f80) & 0x1ff] * XScale, 15);
+ D = (int16) sar(CosTable[readw(0x1f80) & 0x1ff] * YScale, 15);
+ }
+
+ //Calculate Pixel Resolution
+ uint8 w = read(0x1f89) & ~7;
+ uint8 h = read(0x1f8c) & ~7;
+
+ //Clear the output RAM
+ memset(ram, 0, (w + row_padding / 4) * h / 2);
+
+ int32 Cx = (int16)readw(0x1f83);
+ int32 Cy = (int16)readw(0x1f86);
+
+ //Calculate start position (i.e. (Ox, Oy) = (0, 0))
+ //The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
+ //the function. We do Cx*A etc normally because the matrix parameters
+ //already have the fractional parts.
+ int32 LineX = (Cx << 12) - Cx * A - Cx * B;
+ int32 LineY = (Cy << 12) - Cy * C - Cy * D;
+
+ //Start loop
+ uint32 X, Y;
+ uint8 byte;
+ int32 outidx = 0;
+ uint8 bit = 0x80;
+
+ for(int32 y = 0; y < h; y++) {
+ X = LineX;
+ Y = LineY;
+ for(int32 x = 0; x < w; x++) {
+ if((X >> 12) >= w || (Y >> 12) >= h) {
+ byte = 0;
+ } else {
+ uint32 addr = (Y >> 12) * w + (X >> 12);
+ byte = read(0x600 + (addr >> 1));
+ if(addr & 1) { byte >>= 4; }
+ }
+
+ //De-bitplanify
+ if(byte & 1) ram[outidx ] |= bit;
+ if(byte & 2) ram[outidx + 1] |= bit;
+ if(byte & 4) ram[outidx + 16] |= bit;
+ if(byte & 8) ram[outidx + 17] |= bit;
+
+ bit >>= 1;
+ if(!bit) {
+ bit = 0x80;
+ outidx += 32;
+ }
+
+ X += A; //Add 1 to output x => add an A and a C
+ Y += C;
+ }
+ outidx += 2 + row_padding;
+ if(outidx & 0x10) {
+ outidx &= ~0x10;
+ } else {
+ outidx -= w * 4 + row_padding;
+ }
+ LineX += B; //Add 1 to output y => add a B and a D
+ LineY += D;
+ }
+}
+
+#endif
diff --git a/higan/sfc/coprocessor/cx4/oam.cpp b/higan/sfc/coprocessor/cx4/oam.cpp
new file mode 100644
index 00000000..af958b58
--- /dev/null
+++ b/higan/sfc/coprocessor/cx4/oam.cpp
@@ -0,0 +1,228 @@
+#ifdef CX4_CPP
+
+//Build OAM
+void Cx4::op00_00() {
+ uint32 oamptr = ram[0x626] << 2;
+ for(int32 i = 0x1fd; i > oamptr && i >= 0; i -= 4) {
+ //clear oam-to-be
+ if(i >= 0) ram[i] = 0xe0;
+ }
+
+ uint16 globalx, globaly;
+ uint32 oamptr2;
+ int16 sprx, spry;
+ uint8 sprname, sprattr;
+ uint8 sprcount;
+
+ globalx = readw(0x621);
+ globaly = readw(0x623);
+ oamptr2 = 0x200 + (ram[0x626] >> 2);
+
+ if(!ram[0x620]) return;
+
+ sprcount = 128 - ram[0x626];
+ uint8 offset = (ram[0x626] & 3) * 2;
+ uint32 srcptr = 0x220;
+
+ for(int i = ram[0x620]; i > 0 && sprcount > 0; i--, srcptr += 16) {
+ sprx = readw(srcptr) - globalx;
+ spry = readw(srcptr + 2) - globaly;
+ sprname = ram[srcptr + 5];
+ sprattr = ram[srcptr + 4] | ram[srcptr + 6];
+
+ uint32 spraddr = readl(srcptr + 7);
+ if(bus.read(spraddr)) {
+ int16 x, y;
+ for(int sprcnt = bus.read(spraddr++); sprcnt > 0 && sprcount > 0; sprcnt--, spraddr += 4) {
+ x = (int8)bus.read(spraddr + 1);
+ if(sprattr & 0x40) {
+ x = -x - ((bus.read(spraddr) & 0x20) ? 16 : 8);
+ }
+ x += sprx;
+ if(x >= -16 && x <= 272) {
+ y = (int8)bus.read(spraddr + 2);
+ if(sprattr & 0x80) {
+ y = -y - ((bus.read(spraddr) & 0x20) ? 16 : 8);
+ }
+ y += spry;
+ if(y >= -16 && y <= 224) {
+ ram[oamptr ] = (uint8)x;
+ ram[oamptr + 1] = (uint8)y;
+ ram[oamptr + 2] = sprname + bus.read(spraddr + 3);
+ ram[oamptr + 3] = sprattr ^ (bus.read(spraddr) & 0xc0);
+ ram[oamptr2] &= ~(3 << offset);
+ if(x & 0x100) ram[oamptr2] |= 1 << offset;
+ if(bus.read(spraddr) & 0x20) ram[oamptr2] |= 2 << offset;
+ oamptr += 4;
+ sprcount--;
+ offset = (offset + 2) & 6;
+ if(!offset)oamptr2++;
+ }
+ }
+ }
+ } else if(sprcount > 0) {
+ ram[oamptr ] = (uint8)sprx;
+ ram[oamptr + 1] = (uint8)spry;
+ ram[oamptr + 2] = sprname;
+ ram[oamptr + 3] = sprattr;
+ ram[oamptr2] &= ~(3 << offset);
+ if(sprx & 0x100) ram[oamptr2] |= 3 << offset;
+ else ram[oamptr2] |= 2 << offset;
+ oamptr += 4;
+ sprcount--;
+ offset = (offset + 2) & 6;
+ if(!offset) oamptr2++;
+ }
+ }
+}
+
+//Scale and Rotate
+void Cx4::op00_03() {
+ C4DoScaleRotate(0);
+}
+
+//Transform Lines
+void Cx4::op00_05() {
+ C4WFX2Val = read(0x1f83);
+ C4WFY2Val = read(0x1f86);
+ C4WFDist = read(0x1f89);
+ C4WFScale = read(0x1f8c);
+
+//Transform Vertices
+uint32 ptr = 0;
+ for(int32 i = readw(0x1f80); i > 0; i--, ptr += 0x10) {
+ C4WFXVal = readw(ptr + 1);
+ C4WFYVal = readw(ptr + 5);
+ C4WFZVal = readw(ptr + 9);
+ C4TransfWireFrame();
+
+ //Displace
+ writew(ptr + 1, C4WFXVal + 0x80);
+ writew(ptr + 5, C4WFYVal + 0x50);
+ }
+
+ writew(0x600, 23);
+ writew(0x602, 0x60);
+ writew(0x605, 0x40);
+ writew(0x600 + 8, 23);
+ writew(0x602 + 8, 0x60);
+ writew(0x605 + 8, 0x40);
+
+ ptr = 0xb02;
+ uint32 ptr2 = 0;
+
+ for(int32 i = readw(0xb00); i > 0; i--, ptr += 2, ptr2 += 8) {
+ C4WFXVal = readw((read(ptr + 0) << 4) + 1);
+ C4WFYVal = readw((read(ptr + 0) << 4) + 5);
+ C4WFX2Val = readw((read(ptr + 1) << 4) + 1);
+ C4WFY2Val = readw((read(ptr + 1) << 4) + 5);
+ C4CalcWireFrame();
+ writew(ptr2 + 0x600, C4WFDist ? C4WFDist : (int16)1);
+ writew(ptr2 + 0x602, C4WFXVal);
+ writew(ptr2 + 0x605, C4WFYVal);
+ }
+}
+
+//Scale and Rotate
+void Cx4::op00_07() {
+ C4DoScaleRotate(64);
+}
+
+//Draw Wireframe
+void Cx4::op00_08() {
+ C4DrawWireFrame();
+}
+
+//Disintegrate
+void Cx4::op00_0b() {
+ uint8 width, height;
+ uint32 startx, starty;
+ uint32 srcptr;
+ uint32 x, y;
+ int32 scalex, scaley;
+ int32 cx, cy;
+ int32 i, j;
+
+ width = read(0x1f89);
+ height = read(0x1f8c);
+ cx = readw(0x1f80);
+ cy = readw(0x1f83);
+
+ scalex = (int16)readw(0x1f86);
+ scaley = (int16)readw(0x1f8f);
+ startx = -cx * scalex + (cx << 8);
+ starty = -cy * scaley + (cy << 8);
+ srcptr = 0x600;
+
+ for(i = 0; i < (width * height) >> 1; i++) {
+ write(i, 0);
+ }
+
+ for(y = starty, i = 0;i < height; i++, y += scaley) {
+ for(x = startx, j = 0;j < width; j++, x += scalex) {
+ if((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000) {
+ uint8 pixel = (j & 1) ? (uint8)(ram[srcptr] >> 4) : (ram[srcptr]);
+ int32 index = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2;
+ uint8 mask = 0x80 >> ((x >> 8) & 7);
+
+ if(pixel & 1) ram[index ] |= mask;
+ if(pixel & 2) ram[index + 1] |= mask;
+ if(pixel & 4) ram[index + 16] |= mask;
+ if(pixel & 8) ram[index + 17] |= mask;
+ }
+ if(j & 1) srcptr++;
+ }
+ }
+}
+
+//Bitplane Wave
+void Cx4::op00_0c() {
+ uint32 destptr = 0;
+ uint32 waveptr = read(0x1f83);
+ uint16 mask1 = 0xc0c0;
+ uint16 mask2 = 0x3f3f;
+
+ for(int j = 0; j < 0x10; j++) {
+ do {
+ int16 height = -((int8)read(waveptr + 0xb00)) - 16;
+ for(int i = 0; i < 40; i++) {
+ uint16 temp = readw(destptr + wave_data[i]) & mask2;
+ if(height >= 0) {
+ if(height < 8) {
+ temp |= mask1 & readw(0xa00 + height * 2);
+ } else {
+ temp |= mask1 & 0xff00;
+ }
+ }
+ writew(destptr + wave_data[i], temp);
+ height++;
+ }
+ waveptr = (waveptr + 1) & 0x7f;
+ mask1 = (mask1 >> 2) | (mask1 << 6);
+ mask2 = (mask2 >> 2) | (mask2 << 6);
+ } while(mask1 != 0xc0c0);
+ destptr += 16;
+
+ do {
+ int16 height = -((int8)read(waveptr + 0xb00)) - 16;
+ for(int i = 0; i < 40; i++) {
+ uint16 temp = readw(destptr + wave_data[i]) & mask2;
+ if(height >= 0) {
+ if(height < 8) {
+ temp |= mask1 & readw(0xa10 + height * 2);
+ } else {
+ temp |= mask1 & 0xff00;
+ }
+ }
+ writew(destptr + wave_data[i], temp);
+ height++;
+ }
+ waveptr = (waveptr + 1) & 0x7f;
+ mask1 = (mask1 >> 2) | (mask1 << 6);
+ mask2 = (mask2 >> 2) | (mask2 << 6);
+ } while(mask1 != 0xc0c0);
+ destptr += 16;
+ }
+}
+
+#endif
diff --git a/higan/sfc/coprocessor/cx4/opcodes.cpp b/higan/sfc/coprocessor/cx4/opcodes.cpp
new file mode 100644
index 00000000..639097b1
--- /dev/null
+++ b/higan/sfc/coprocessor/cx4/opcodes.cpp
@@ -0,0 +1,228 @@
+#ifdef CX4_CPP
+
+//Sprite Functions
+void Cx4::op00() {
+ switch(reg[0x4d]) {
+ case 0x00: op00_00(); break;
+ case 0x03: op00_03(); break;
+ case 0x05: op00_05(); break;
+ case 0x07: op00_07(); break;
+ case 0x08: op00_08(); break;
+ case 0x0b: op00_0b(); break;
+ case 0x0c: op00_0c(); break;
+ }
+}
+
+//Draw Wireframe
+void Cx4::op01() {
+ memset(ram + 0x300, 0, 2304);
+ C4DrawWireFrame();
+}
+
+//Propulsion
+void Cx4::op05() {
+ int32 temp = 0x10000;
+ if(readw(0x1f83)) {
+ temp = sar((temp / readw(0x1f83)) * readw(0x1f81), 8);
+ }
+ writew(0x1f80, temp);
+}
+
+//Set Vector length
+void Cx4::op0d() {
+ C41FXVal = readw(0x1f80);
+ C41FYVal = readw(0x1f83);
+ C41FDistVal = readw(0x1f86);
+ double tanval = sqrt(((double)C41FYVal) * ((double)C41FYVal) + ((double)C41FXVal) * ((double)C41FXVal));
+ tanval = (double)C41FDistVal / tanval;
+ C41FYVal = (int16)(((double)C41FYVal * tanval) * 0.99);
+ C41FXVal = (int16)(((double)C41FXVal * tanval) * 0.98);
+ writew(0x1f89, C41FXVal);
+ writew(0x1f8c, C41FYVal);
+}
+
+//Triangle
+void Cx4::op10() {
+ r0 = ldr(0);
+ r1 = ldr(1);
+
+ r4 = r0 & 0x1ff;
+ if(r1 & 0x8000)r1 |= ~0x7fff;
+ else r1 &= 0x7fff;
+
+ mul(cos(r4), r1, r5, r2);
+ r5 = (r5 >> 16) & 0xff;
+ r2 = (r2 << 8) + r5;
+
+ mul(sin(r4), r1, r5, r3);
+ r5 = (r5 >> 16) & 0xff;
+ r3 = (r3 << 8) + r5;
+
+ str(0, r0);
+ str(1, r1);
+ str(2, r2);
+ str(3, r3);
+ str(4, r4);
+ str(5, r5);
+}
+
+//Triangle
+void Cx4::op13() {
+ r0 = ldr(0);
+ r1 = ldr(1);
+
+ r4 = r0 & 0x1ff;
+
+ mul(cos(r4), r1, r5, r2);
+ r5 = (r5 >> 8) & 0xffff;
+ r2 = (r2 << 16) + r5;
+
+ mul(sin(r4), r1, r5, r3);
+ r5 = (r5 >> 8) & 0xffff;
+ r3 = (r3 << 16) + r5;
+
+ str(0, r0);
+ str(1, r1);
+ str(2, r2);
+ str(3, r3);
+ str(4, r4);
+ str(5, r5);
+}
+
+//Pythagorean
+void Cx4::op15() {
+ C41FXVal = readw(0x1f80);
+ C41FYVal = readw(0x1f83);
+ C41FDist = (int16)sqrt((double)C41FXVal * (double)C41FXVal + (double)C41FYVal * (double)C41FYVal);
+ writew(0x1f80, C41FDist);
+}
+
+//Calculate distance
+void Cx4::op1f() {
+ C41FXVal = readw(0x1f80);
+ C41FYVal = readw(0x1f83);
+ if(!C41FXVal) {
+ C41FAngleRes = (C41FYVal > 0) ? 0x080 : 0x180;
+ } else {
+ double tanval = ((double)C41FYVal) / ((double)C41FXVal);
+ C41FAngleRes = (short)(atan(tanval) / (PI * 2) * 512);
+ C41FAngleRes = C41FAngleRes;
+ if(C41FXVal < 0) {
+ C41FAngleRes += 0x100;
+ }
+ C41FAngleRes &= 0x1ff;
+ }
+ writew(0x1f86, C41FAngleRes);
+}
+
+//Trapezoid
+void Cx4::op22() {
+ int16 angle1 = readw(0x1f8c) & 0x1ff;
+ int16 angle2 = readw(0x1f8f) & 0x1ff;
+ int32 tan1 = Tan(angle1);
+ int32 tan2 = Tan(angle2);
+ int16 y = readw(0x1f83) - readw(0x1f89);
+ int16 left, right;
+
+ for(int32 j = 0; j < 225; j++, y++) {
+ if(y >= 0) {
+ left = sar((int32)tan1 * y, 16) - readw(0x1f80) + readw(0x1f86);
+ right = sar((int32)tan2 * y, 16) - readw(0x1f80) + readw(0x1f86) + readw(0x1f93);
+
+ if(left < 0 && right < 0) {
+ left = 1;
+ right = 0;
+ } else if(left < 0) {
+ left = 0;
+ } else if(right < 0) {
+ right = 0;
+ }
+
+ if(left > 255 && right > 255) {
+ left = 255;
+ right = 254;
+ } else if(left > 255) {
+ left = 255;
+ } else if(right > 255) {
+ right = 255;
+ }
+ } else {
+ left = 1;
+ right = 0;
+ }
+ ram[j + 0x800] = (uint8)left;
+ ram[j + 0x900] = (uint8)right;
+ }
+}
+
+//Multiply
+void Cx4::op25() {
+ r0 = ldr(0);
+ r1 = ldr(1);
+ mul(r0, r1, r0, r1);
+ str(0, r0);
+ str(1, r1);
+}
+
+//Transform Coords
+void Cx4::op2d() {
+ C4WFXVal = readw(0x1f81);
+ C4WFYVal = readw(0x1f84);
+ C4WFZVal = readw(0x1f87);
+ C4WFX2Val = read (0x1f89);
+ C4WFY2Val = read (0x1f8a);
+ C4WFDist = read (0x1f8b);
+ C4WFScale = readw(0x1f90);
+ C4TransfWireFrame2();
+ writew(0x1f80, C4WFXVal);
+ writew(0x1f83, C4WFYVal);
+}
+
+//Sum
+void Cx4::op40() {
+ r0 = 0;
+ for(uint32 i=0;i<0x800;i++) {
+ r0 += ram[i];
+ }
+ str(0, r0);
+}
+
+//Square
+void Cx4::op54() {
+ r0 = ldr(0);
+ mul(r0, r0, r1, r2);
+ str(1, r1);
+ str(2, r2);
+}
+
+//Immediate Register
+void Cx4::op5c() {
+ str(0, 0x000000);
+ immediate_reg(0);
+}
+
+//Immediate Register (Multiple)
+void Cx4::op5e() { immediate_reg( 0); }
+void Cx4::op60() { immediate_reg( 3); }
+void Cx4::op62() { immediate_reg( 6); }
+void Cx4::op64() { immediate_reg( 9); }
+void Cx4::op66() { immediate_reg(12); }
+void Cx4::op68() { immediate_reg(15); }
+void Cx4::op6a() { immediate_reg(18); }
+void Cx4::op6c() { immediate_reg(21); }
+void Cx4::op6e() { immediate_reg(24); }
+void Cx4::op70() { immediate_reg(27); }
+void Cx4::op72() { immediate_reg(30); }
+void Cx4::op74() { immediate_reg(33); }
+void Cx4::op76() { immediate_reg(36); }
+void Cx4::op78() { immediate_reg(39); }
+void Cx4::op7a() { immediate_reg(42); }
+void Cx4::op7c() { immediate_reg(45); }
+
+//Immediate ROM
+void Cx4::op89() {
+ str(0, 0x054336);
+ str(1, 0xffffff);
+}
+
+#endif
diff --git a/higan/sfc/coprocessor/cx4/serialization.cpp b/higan/sfc/coprocessor/cx4/serialization.cpp
new file mode 100644
index 00000000..55cac823
--- /dev/null
+++ b/higan/sfc/coprocessor/cx4/serialization.cpp
@@ -0,0 +1,35 @@
+auto Cx4::serialize(serializer& s) -> void {
+ s.array(ram);
+ s.array(reg);
+
+ s.integer(r0);
+ s.integer(r1);
+ s.integer(r2);
+ s.integer(r3);
+ s.integer(r4);
+ s.integer(r5);
+ s.integer(r6);
+ s.integer(r7);
+ s.integer(r8);
+ s.integer(r9);
+ s.integer(r10);
+ s.integer(r11);
+ s.integer(r12);
+ s.integer(r13);
+ s.integer(r14);
+ s.integer(r15);
+
+ s.integer(C4WFXVal);
+ s.integer(C4WFYVal);
+ s.integer(C4WFZVal);
+ s.integer(C4WFX2Val);
+ s.integer(C4WFY2Val);
+ s.integer(C4WFDist);
+ s.integer(C4WFScale);
+
+ s.integer(C41FXVal);
+ s.integer(C41FYVal);
+ s.integer(C41FAngleRes);
+ s.integer(C41FDist);
+ s.integer(C41FDistVal);
+}
diff --git a/higan/sfc/coprocessor/dsp1/dsp1.cpp b/higan/sfc/coprocessor/dsp1/dsp1.cpp
new file mode 100644
index 00000000..d7cea030
--- /dev/null
+++ b/higan/sfc/coprocessor/dsp1/dsp1.cpp
@@ -0,0 +1,48 @@
+#include
+
+namespace SuperFamicom {
+
+#define int8 int8_t
+#define int16 int16_t
+#define int32 int32_t
+#define int64 int64_t
+#define uint8 uint8_t
+#define uint16 uint16_t
+#define uint32 uint32_t
+#define uint64 uint64_t
+#define DSP1_CPP
+#include "dsp1emu.hpp"
+#include "dsp1emu.cpp"
+Dsp1 dsp1emu;
+#undef int8
+#undef int16
+#undef int32
+#undef int64
+#undef uint8
+#undef uint16
+#undef uint32
+#undef uint64
+
+DSP1 dsp1;
+#include "serialization.cpp"
+
+auto DSP1::power() -> void {
+ dsp1emu.reset();
+}
+
+auto DSP1::read(uint24 addr, uint8 data) -> uint8 {
+ if(addr & 1) {
+ return dsp1emu.getSr();
+ } else {
+ return dsp1emu.getDr();
+ }
+}
+
+auto DSP1::write(uint24 addr, uint8 data) -> void {
+ if(addr & 1) {
+ } else {
+ return dsp1emu.setDr(data);
+ }
+}
+
+}
diff --git a/higan/sfc/coprocessor/dsp1/dsp1.hpp b/higan/sfc/coprocessor/dsp1/dsp1.hpp
new file mode 100644
index 00000000..fcf75329
--- /dev/null
+++ b/higan/sfc/coprocessor/dsp1/dsp1.hpp
@@ -0,0 +1,10 @@
+struct DSP1 {
+ auto power() -> void;
+
+ auto read(uint24 addr, uint8 data) -> uint8;
+ auto write(uint24 addr, uint8 data) -> void;
+
+ auto serialize(serializer&) -> void;
+};
+
+extern DSP1 dsp1;
diff --git a/higan/sfc/coprocessor/dsp1/dsp1emu.cpp b/higan/sfc/coprocessor/dsp1/dsp1emu.cpp
new file mode 100644
index 00000000..d933b11c
--- /dev/null
+++ b/higan/sfc/coprocessor/dsp1/dsp1emu.cpp
@@ -0,0 +1,1625 @@
+#ifdef DSP1_CPP
+
+// DSP-1's emulation code
+//
+// Based on research by Overload, The Dumper, Neviksti and Andreas Naive
+// Date: June 2006
+
+//////////////////////////////////////////////////////////////////
+
+Dsp1::Dsp1()
+{
+ reset();
+}
+
+//////////////////////////////////////////////////////////////////
+
+uint8 Dsp1::getSr()
+{
+ mSrLowByteAccess = ~mSrLowByteAccess;
+ if (mSrLowByteAccess)
+ return 0;
+ else
+ return mSr;
+}
+
+//////////////////////////////////////////////////////////////////
+
+uint8 Dsp1::getDr()
+{
+ uint8 oDr;
+
+ fsmStep(true, oDr);
+ return oDr;
+}
+
+//////////////////////////////////////////////////////////////////
+
+void Dsp1::setDr(uint8 iDr)
+{
+ fsmStep(false, iDr);
+}
+
+//////////////////////////////////////////////////////////////////
+
+void Dsp1::reset()
+{
+ mSr = DRC|RQM;
+ mSrLowByteAccess = false;
+ mDr = 0x0080; // Only a supposition. Is this correct?
+ mFreeze = false;
+ mFsmMajorState = WAIT_COMMAND;
+ memset(&shared, 0, sizeof(SharedData)); // another supposition
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Though the DSP-1 is unaware of the type of operation (read or write)
+// we need to know what is being done by the program, as the class
+// is responsible for maintaining the binding between the
+// "external" and "internal" representations of the DR (data register).
+
+void Dsp1::fsmStep(bool read, uint8 &data)
+{
+ if (0 == (mSr&RQM)) return;
+ // Now RQM would be cleared; however, as this code is not to be used in
+ // a multithread environment, we will simply fake RQM operation.
+ // (The only exception would be Op1A's freeze.)
+
+ // binding
+ if (read)
+ {
+ if (mSr&DRS)
+ data = static_cast(mDr>>8);
+ else
+ data = static_cast(mDr);
+ }
+ else
+ {
+ if (mSr&DRS)
+ {
+ mDr &= 0x00ff;
+ mDr |= data<<8;
+ }
+ else
+ {
+ mDr &= 0xff00;
+ mDr |= data;
+ }
+ }
+
+
+ switch (mFsmMajorState)
+ {
+ case WAIT_COMMAND:
+ mCommand = static_cast(mDr);
+ if (!(mCommand & 0xc0)) // valid command?
+ {
+ switch(mCommand)
+ {
+ // freeze cases
+ case 0x1a:
+ case 0x2a:
+ case 0x3a:
+ mFreeze = true;
+ break;
+ // normal cases
+ default:
+ mDataCounter=0;
+ mFsmMajorState = READ_DATA;
+ mSr &= ~DRC;
+ break;
+ }
+ }
+ break;
+ case READ_DATA:
+ mSr ^= DRS;
+ if (!(mSr&DRS))
+ {
+ mReadBuffer[mDataCounter++] = static_cast(mDr);
+ if (mDataCounter >= mCommandTable[mCommand].reads)
+ {
+ (this->*mCommandTable[mCommand].callback)(mReadBuffer, mWriteBuffer);
+ if (0 != mCommandTable[mCommand].writes) // any output?
+ {
+ mDataCounter = 0;
+ mDr = static_cast(mWriteBuffer[mDataCounter]);
+ mFsmMajorState = WRITE_DATA;
+ }
+ else
+ {
+ mDr = 0x0080; // valid command completion
+ mFsmMajorState = WAIT_COMMAND;
+ mSr |= DRC;
+ }
+ }
+ }
+ break;
+ case WRITE_DATA:
+ mSr ^= DRS;
+ if (!(mSr&DRS))
+ {
+ ++mDataCounter;
+ if (mDataCounter >= mCommandTable[mCommand].writes)
+ {
+ if ((mCommand == 0x0a)&&(mDr != 0x8000))
+ {
+ // works in continuous mode
+ mReadBuffer[0]++; // next raster line
+ (this->*mCommandTable[mCommand].callback)(mReadBuffer, mWriteBuffer);
+ mDataCounter = 0;
+ mDr = static_cast(mWriteBuffer[mDataCounter]);
+ }
+ else
+ {
+ mDr = 0x0080; // valid command completion
+ mFsmMajorState = WAIT_COMMAND;
+ mSr |= DRC;
+ }
+ }
+ else
+ {
+ mDr = static_cast(mWriteBuffer[mDataCounter]);
+ }
+ }
+ break;
+ }
+
+
+
+ // Now RQM would be set (except when executing Op1A -command equals 0x1a, 0x2a or 0x3a-).
+ if (mFreeze)
+ mSr &= ~RQM;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// The info on this table follows Overload's docs.
+
+const Dsp1::Command Dsp1::mCommandTable[0x40] = {
+ {&Dsp1::multiply, 2, 1}, //0x00
+ {&Dsp1::attitudeA, 4, 0}, //0x01
+ {&Dsp1::parameter, 7, 4}, //0x02
+ {&Dsp1::subjectiveA, 3, 3}, //0x03
+ {&Dsp1::triangle, 2, 2}, //0x04
+ {&Dsp1::attitudeA, 4, 0}, //0x01
+ {&Dsp1::project, 3, 3}, //0x06
+ {&Dsp1::memoryTest, 1, 1}, //0x0f
+ {&Dsp1::radius, 3, 2}, //0x08
+ {&Dsp1::objectiveA, 3, 3}, //0x0d
+ {&Dsp1::raster, 1, 4}, // 0x0a. This will normally work in continuous mode
+ {&Dsp1::scalarA, 3, 1}, //0x0b
+ {&Dsp1::rotate, 3, 2}, //0x0c
+ {&Dsp1::objectiveA, 3, 3}, //0x0d
+ {&Dsp1::target, 2, 2}, //0x0e
+ {&Dsp1::memoryTest, 1, 1}, //0x0f
+
+ {&Dsp1::inverse, 2, 2}, //0x10
+ {&Dsp1::attitudeB, 4, 0}, //0x11
+ {&Dsp1::parameter, 7, 4}, //0x02
+ {&Dsp1::subjectiveB, 3, 3}, //0x13
+ {&Dsp1::gyrate, 6, 3}, //0x14
+ {&Dsp1::attitudeB, 4, 0}, //0x11
+ {&Dsp1::project, 3, 3}, //0x06
+ {&Dsp1::memoryDump, 1, 1024}, //0x1f
+ {&Dsp1::range, 4, 1}, //0x18
+ {&Dsp1::objectiveB, 3, 3}, //0x1d
+ {0, 0, 0}, // 0x1a; the chip freezes
+ {&Dsp1::scalarB, 3, 1}, //0x1b
+ {&Dsp1::polar, 6, 3}, //0x1c
+ {&Dsp1::objectiveB, 3, 3}, //0x1d
+ {&Dsp1::target, 2, 2}, //0x0e
+ {&Dsp1::memoryDump, 1, 1024}, //0x1f
+
+ {&Dsp1::multiply2, 2, 1}, //0x20
+ {&Dsp1::attitudeC, 4, 0}, //0x21
+ {&Dsp1::parameter, 7, 4}, //0x02
+ {&Dsp1::subjectiveC, 3, 3}, //0x23
+ {&Dsp1::triangle, 2, 2}, //0x04
+ {&Dsp1::attitudeC, 4, 0}, //0x21
+ {&Dsp1::project, 3, 3}, //0x06
+ {&Dsp1::memorySize, 1, 1}, //0x2f
+ {&Dsp1::distance, 3, 1}, //0x28
+ {&Dsp1::objectiveC, 3, 3}, //0x2d
+ {0, 0, 0}, // 0x1a; the chip freezes
+ {&Dsp1::scalarC, 3, 1}, //0x2b
+ {&Dsp1::rotate, 3, 2}, //0x0c
+ {&Dsp1::objectiveC, 3, 3}, //0x2d
+ {&Dsp1::target, 2, 2}, //0x0e
+ {&Dsp1::memorySize, 1, 1}, //0x2f
+
+ {&Dsp1::inverse, 2, 2}, //0x10
+ {&Dsp1::attitudeA, 4, 0}, //0x01
+ {&Dsp1::parameter, 7, 4}, //0x02
+ {&Dsp1::subjectiveA, 3, 3}, //0x03
+ {&Dsp1::gyrate, 6, 3}, //0x14
+ {&Dsp1::attitudeA, 4, 0}, //0x01
+ {&Dsp1::project, 3, 3}, //0x06
+ {&Dsp1::memoryDump, 1, 1024}, //0x1f
+ {&Dsp1::range2, 4, 1}, //0x38
+ {&Dsp1::objectiveA, 3, 3}, //0x0d
+ {0, 0, 0}, // 0x1a; the chip freezes
+ {&Dsp1::scalarA, 3, 1}, //0x0b
+ {&Dsp1::polar, 6, 3}, //0x1c
+ {&Dsp1::objectiveA, 3, 3}, //0x0d
+ {&Dsp1::target, 2, 2}, //0x0e
+ {&Dsp1::memoryDump, 1, 1024}, //0x1f
+};
+
+//////////////////////////////////////////////////////////////////
+
+void Dsp1::memoryTest(int16 *input, int16 *output)
+{
+ int16& Size = input[0];
+ int16& Result = output[0];
+
+ Result = 0x0000;
+}
+
+//////////////////////////////////////////////////////////////////
+
+void Dsp1::memoryDump(int16 *input, int16 *output)
+{
+ memcpy(output, DataRom, 1024);
+}
+
+//////////////////////////////////////////////////////////////////
+
+void Dsp1::memorySize(int16 *input, int16 *output)
+{
+ int16& Size = output[0];
+
+ Size = 0x0100;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// 16-bit multiplication
+
+void Dsp1::multiply(int16 *input, int16 *output)
+{
+ int16& Multiplicand = input[0];
+ int16& Multiplier = input[1];
+ int16& Product = output[0];
+
+ Product = Multiplicand * Multiplier >> 15;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// 16-bit multiplication. 'Alternative' method. Can anyone check this carefully?
+
+void Dsp1::multiply2(int16 *input, int16 *output)
+{
+ int16& Multiplicand = input[0];
+ int16& Multiplier = input[1];
+ int16& Product = output[0];
+
+ Product = (Multiplicand * Multiplier >> 15)+1;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// This command determines the inverse of a floating point decimal number.
+
+void Dsp1::inverse(int16 *input, int16 *output)
+{
+ int16& Coefficient = input[0];
+ int16& Exponent = input[1];
+ int16& iCoefficient = output[0];
+ int16& iExponent = output[1];
+
+ inverse(Coefficient, Exponent, iCoefficient, iExponent);
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Vector component calculation. Determines the X and Y components for a
+// two-dimensional vector whose size and direction is known.
+// Y = Radius * sin(Angle)
+// X = Radius * cos(Angle)
+
+void Dsp1::triangle(int16 *input, int16 *output)
+{
+ int16& Angle = input[0];
+ int16& Radius = input[1];
+ int16& Y = output[0];
+ int16& X = output[1];
+
+ Y = sin(Angle) * Radius >> 15;
+ X = cos(Angle) * Radius >> 15;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Determines the squared norm of a vector (X,Y,Z)
+// The output is Radius = X^2+Y^2+Z^2 (double integer)
+
+void Dsp1::radius(int16 *input, int16 *output)
+{
+ int16& X = input[0];
+ int16& Y = input[1];
+ int16& Z = input[2];
+ int16& RadiusLow = output[0];
+ int16& RadiusHigh = output[1];
+
+ int32 Radius;
+
+ Radius = (X * X + Y * Y + Z * Z) << 1;
+ RadiusLow = static_cast(Radius);
+ RadiusHigh = static_cast(Radius>>16);
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Vector size comparison. This command compares the size of the vector (X,Y,Z) and the distance (R)
+// from a particular point, and so may be used to determine if a point is within the sphere or radius R.
+// The output is D = X^2+Y^2+Z^2-R^2
+
+void Dsp1::range(int16 *input, int16 *output)
+{
+ int16& X = input[0];
+ int16& Y = input[1];
+ int16& Z = input[2];
+ int16& Radius = input[3];
+ int16& Range = output[0];
+
+ Range = (X * X + Y * Y + Z * Z - Radius * Radius) >> 15;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Vector size comparison. 'Alternative' method.
+
+void Dsp1::range2(int16 *input, int16 *output)
+{
+ int16& X = input[0];
+ int16& Y = input[1];
+ int16& Z = input[2];
+ int16& Radius = input[3];
+ int16& Range = output[0];
+
+ Range = ((X * X + Y * Y + Z * Z - Radius * Radius) >> 15) + 1;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// This command calculates the norm of a (X,Y,Z) vector, or the distance from
+// the point (X,Y,Z) to (0,0,0), as you prefer to see it.
+// Distance = sqrt(X^2+Y^2+Z^2)
+// The square root of a number 'a' is calculated by doing this: you
+// write 'a' as b*2^2n, with 'b' between 1/4 and 1; then, you calculate
+// c=sqrt(b) by using lineal interpolation between points of a
+// look-up table and, finally, you output the result as c*2^n.
+
+void Dsp1::distance(int16 *input, int16 *output)
+{
+ int16& X = input[0];
+ int16& Y = input[1];
+ int16& Z = input[2];
+ int16& Distance = output[0];
+
+ int32 Radius = X * X + Y * Y + Z * Z;
+
+ if (Radius == 0) Distance = 0;
+ else
+ {
+ int16 C, E;
+ normalizeDouble(Radius, C, E);
+ if (E & 1) C = C * 0x4000 >> 15;
+
+ int16 Pos = C * 0x0040 >> 15;
+
+ int16 Node1 = DataRom[0x00d5 + Pos];
+ int16 Node2 = DataRom[0x00d6 + Pos];
+
+ Distance = ((Node2 - Node1) * (C & 0x1ff) >> 9) + Node1;
+
+#if DSP1_VERSION < 0x0102
+ if (Pos & 1) Distance -= (Node2 - Node1);
+#endif
+ Distance >>= (E >> 1);
+ }
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Determines the (X2, Y2) coordinates obtained by rotating (X1, Y1)
+// clockwise for an angle 'Angle'. The official documentation says
+// 'counterclockwise', but it's obviously wrong (surprise! :P)
+//
+// In matrix notation:
+// |X2| |cos(Angle) sin(Angle)| |X1|
+// | | = | | | |
+// |Y2| |-sin(Angle cos(Angle)| |Y1|
+
+void Dsp1::rotate(int16 *input, int16 *output)
+{
+ int16& Angle = input[0];
+ int16& X1 = input[1];
+ int16& Y1 = input[2];
+ int16& X2 = output[0];
+ int16& Y2 = output[1];
+
+ X2 = (Y1 * sin(Angle) >> 15) + (X1 * cos(Angle) >> 15);
+ Y2 = (Y1 * cos(Angle) >> 15) - (X1 * sin(Angle) >> 15);
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Calculate the coordinates (X2, Y2, Z2) obtained when rotating (X1, Y1, Z1)
+// three-dimensionally. Rotation is done in the order of Az around the Z axis,
+// Ay around the Y axis and Ax around the X axis. As occur with the "attitude" commands
+// (see comments in the "gyrate" command), this doesn't match what explained in
+// the official documentation, but it's coherent with what it is done in the "attitude"
+// command (but not with the "gyrate" command).
+//
+// In matrix notation:
+// |X2| |1 0 0 | |cosRy 0 -sinRy| | cosRz sinRz 0| |X1|
+// |Y2| = |0 cosRx sinRx| | 0 1 0 | |-sinRz cosRz 0| |Y1|
+// |Z2| |0 -sinRx cosRx| |sinRy 0 cosRy| | 0 0 1| |Z1|
+
+void Dsp1::polar(int16 *input, int16 *output)
+{
+ int16& Az = input[0];
+ int16& Ay = input[1];
+ int16& Ax = input[2];
+ int16& X1 = input[3];
+ int16& Y1 = input[4];
+ int16& Z1 = input[5];
+ int16& X2 = output[0];
+ int16& Y2 = output[1];
+ int16& Z2 = output[2];
+
+ int16 X, Y, Z;
+
+ // Rotate Around Z
+ X = (Y1 * sin(Az) >> 15) + (X1 * cos(Az) >> 15);
+ Y = (Y1 * cos(Az) >> 15) - (X1 * sin(Az) >> 15);
+ X1 = X; Y1 = Y;
+
+ // Rotate Around Y
+ Z = (X1 * sin(Ay) >> 15) + (Z1 * cos(Ay) >> 15);
+ X = (X1 * cos(Ay) >> 15) - (Z1 * sin(Ay) >> 15);
+ X2 = X; Z1 = Z;
+
+ // Rotate Around X
+ Y = (Z1 * sin(Ax) >> 15) + (Y1 * cos(Ax) >> 15);
+ Z = (Z1 * cos(Ax) >> 15) - (Y1 * sin(Ax) >> 15);
+ Y2 = Y; Z2 = Z;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Set up the elements of an "attitude matrix" (there are other ones):
+// S | cosRz sinRz 0| |cosRy 0 -sinRy| |1 0 0 |
+// MatrixA = - |-sinRz cosRz 0| | 0 1 0 | |0 cosRx sinRx|
+// 2 | 0 0 1| |sinRy 0 cosRy| |0 -sinRx cosRx|
+// This matrix is thought to be used within the following framework:
+// let's suppose we define positive rotations around a system of orthogonal axes in this manner:
+// a rotation of +90 degrees around axis3 converts axis2 into axis1
+// a rotation of +90 degrees around axis2 converts axis1 into axis3
+// a rotation of +90 degrees around axis1 converts axis3 into axis2
+// and let's suppose that we have defined a new orthonormal axes system (FLU)
+// by doing the following operations about the standard one (XYZ):
+// first rotating the XYZ system around Z by an angle Rz (obtaining X'Y'Z'),
+// then rotating the resulting system around Y by an angle Ry (obtaining X''Y''Z'')
+// and, finally, rotating the resulting system around X by an angle Rx (obtaining FLU)
+// This FLU (forward/left/up) system represents an "attitude" and, then, the matrix here defined
+// is the change of coordinates matrix that transform coordinates in the FLU
+// system (the "object coordinates") into the standard XYZ system (the "global coordinates"),
+// multiplied by a scale factor S/2, that is:
+// |x| S |f|
+// |y| * - = MatrixA * |l|
+// |z| 2 |u|
+// In a similar way, if we use the transpose of the matrix, we can transform global coordinates
+// into object coordinates:
+// |f| S |x|
+// |l| * - = MatrixA_transposed * |y|
+// |u| 2 |z|
+//
+// input[0]: S
+// input[1]: Rz
+// input[2]: Ry
+// input[3]: Rx
+
+void Dsp1::attitudeA(int16 *input, int16 *output)
+{
+ int16& S = input[0];
+ int16& Rz = input[1];
+ int16& Ry = input[2];
+ int16& Rx = input[3];
+
+ int16 SinRz = sin(Rz);
+ int16 CosRz = cos(Rz);
+ int16 SinRy = sin(Ry);
+ int16 CosRy = cos(Ry);
+ int16 SinRx = sin(Rx);
+ int16 CosRx = cos(Rx);
+
+ S >>= 1;
+
+ shared.MatrixA[0][0] = (S * CosRz >> 15) * CosRy >> 15;
+ shared.MatrixA[0][1] = ((S * SinRz >> 15) * CosRx >> 15) + (((S * CosRz >> 15) * SinRx >> 15) * SinRy >> 15);
+ shared.MatrixA[0][2] = ((S * SinRz >> 15) * SinRx >> 15) - (((S * CosRz >> 15) * CosRx >> 15) * SinRy >> 15);
+
+ shared.MatrixA[1][0] = -((S * SinRz >> 15) * CosRy >> 15);
+ shared.MatrixA[1][1] = ((S * CosRz >> 15) * CosRx >> 15) - (((S * SinRz >> 15) * SinRx >> 15) * SinRy >> 15);
+ shared.MatrixA[1][2] = ((S * CosRz >> 15) * SinRx >> 15) + (((S * SinRz >> 15) * CosRx >> 15) * SinRy >> 15);
+
+ shared.MatrixA[2][0] = S * SinRy >> 15;
+ shared.MatrixA[2][1] = -((S * SinRx >> 15) * CosRy >> 15);
+ shared.MatrixA[2][2] = (S * CosRx >> 15) * CosRy >> 15;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Same than 'attitudeA', but with a difference attitude matrix (matrixB)
+
+void Dsp1::attitudeB(int16 *input, int16 *output)
+{
+ int16& S = input[0];
+ int16& Rz = input[1];
+ int16& Ry = input[2];
+ int16& Rx = input[3];
+
+ int16 SinRz = sin(Rz);
+ int16 CosRz = cos(Rz);
+ int16 SinRy = sin(Ry);
+ int16 CosRy = cos(Ry);
+ int16 SinRx = sin(Rx);
+ int16 CosRx = cos(Rx);
+
+ S >>= 1;
+
+ shared.MatrixB[0][0] = (S * CosRz >> 15) * CosRy >> 15;
+ shared.MatrixB[0][1] = ((S * SinRz >> 15) * CosRx >> 15) + (((S * CosRz >> 15) * SinRx >> 15) * SinRy >> 15);
+ shared.MatrixB[0][2] = ((S * SinRz >> 15) * SinRx >> 15) - (((S * CosRz >> 15) * CosRx >> 15) * SinRy >> 15);
+
+ shared.MatrixB[1][0] = -((S * SinRz >> 15) * CosRy >> 15);
+ shared.MatrixB[1][1] = ((S * CosRz >> 15) * CosRx >> 15) - (((S * SinRz >> 15) * SinRx >> 15) * SinRy >> 15);
+ shared.MatrixB[1][2] = ((S * CosRz >> 15) * SinRx >> 15) + (((S * SinRz >> 15) * CosRx >> 15) * SinRy >> 15);
+
+ shared.MatrixB[2][0] = S * SinRy >> 15;
+ shared.MatrixB[2][1] = -((S * SinRx >> 15) * CosRy >> 15);
+ shared.MatrixB[2][2] = (S * CosRx >> 15) * CosRy >> 15;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Same than 'attitudeA', but with a difference attitude matrix (matrixC)
+
+void Dsp1::attitudeC(int16 *input, int16 *output)
+{
+ int16& S = input[0];
+ int16& Rz = input[1];
+ int16& Ry = input[2];
+ int16& Rx = input[3];
+
+ int16 SinRz = sin(Rz);
+ int16 CosRz = cos(Rz);
+ int16 SinRy = sin(Ry);
+ int16 CosRy = cos(Ry);
+ int16 SinRx = sin(Rx);
+ int16 CosRx = cos(Rx);
+
+ S >>= 1;
+
+ shared.MatrixC[0][0] = (S * CosRz >> 15) * CosRy >> 15;
+ shared.MatrixC[0][1] = ((S * SinRz >> 15) * CosRx >> 15) + (((S * CosRz >> 15) * SinRx >> 15) * SinRy >> 15);
+ shared.MatrixC[0][2] = ((S * SinRz >> 15) * SinRx >> 15) - (((S * CosRz >> 15) * CosRx >> 15) * SinRy >> 15);
+
+ shared.MatrixC[1][0] = -((S * SinRz >> 15) * CosRy >> 15);
+ shared.MatrixC[1][1] = ((S * CosRz >> 15) * CosRx >> 15) - (((S * SinRz >> 15) * SinRx >> 15) * SinRy >> 15);
+ shared.MatrixC[1][2] = ((S * CosRz >> 15) * SinRx >> 15) + (((S * SinRz >> 15) * CosRx >> 15) * SinRy >> 15);
+
+ shared.MatrixC[2][0] = S * SinRy >> 15;
+ shared.MatrixC[2][1] = -((S * SinRx >> 15) * CosRy >> 15);
+ shared.MatrixC[2][2] = (S * CosRx >> 15) * CosRy >> 15;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Convert global coordinates (X,Y,Z) to object coordinates (F,L,U)
+// See the comment in "attitudeA" for a explanation about the calculation.
+//
+// input[0]: X ; input[1]: Y ; input[2]: Z
+// output[0]: F ; output[1]: L ; output[2]: U
+
+void Dsp1::objectiveA(int16 *input, int16 *output)
+{
+ int16& X = input[0];
+ int16& Y = input[1];
+ int16& Z = input[2];
+ int16& F = output[0];
+ int16& L = output[1];
+ int16& U = output[2];
+
+ F = (shared.MatrixA[0][0] * X >> 15) + (shared.MatrixA[1][0] * Y >> 15) + (shared.MatrixA[2][0] * Z >> 15);
+ L = (shared.MatrixA[0][1] * X >> 15) + (shared.MatrixA[1][1] * Y >> 15) + (shared.MatrixA[2][1] * Z >> 15);
+ U = (shared.MatrixA[0][2] * X >> 15) + (shared.MatrixA[1][2] * Y >> 15) + (shared.MatrixA[2][2] * Z >> 15);
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Same than 'objectiveA', but for the 'B' attitude
+
+void Dsp1::objectiveB(int16 *input, int16 *output)
+{
+ int16& X = input[0];
+ int16& Y = input[1];
+ int16& Z = input[2];
+ int16& F = output[0];
+ int16& L = output[1];
+ int16& U = output[2];
+
+ F = (shared.MatrixB[0][0] * X >> 15) + (shared.MatrixB[1][0] * Y >> 15) + (shared.MatrixB[2][0] * Z >> 15);
+ L = (shared.MatrixB[0][1] * X >> 15) + (shared.MatrixB[1][1] * Y >> 15) + (shared.MatrixB[2][1] * Z >> 15);
+ U = (shared.MatrixB[0][2] * X >> 15) + (shared.MatrixB[1][2] * Y >> 15) + (shared.MatrixB[2][2] * Z >> 15);
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Same than 'objectiveA', but for the 'C' attitude
+
+void Dsp1::objectiveC(int16 *input, int16 *output)
+{
+ int16& X = input[0];
+ int16& Y = input[1];
+ int16& Z = input[2];
+ int16& F = output[0];
+ int16& L = output[1];
+ int16& U = output[2];
+
+ F = (shared.MatrixC[0][0] * X >> 15) + (shared.MatrixC[1][0] * Y >> 15) + (shared.MatrixC[2][0] * Z >> 15);
+ L = (shared.MatrixC[0][1] * X >> 15) + (shared.MatrixC[1][1] * Y >> 15) + (shared.MatrixC[2][1] * Z >> 15);
+ U = (shared.MatrixC[0][2] * X >> 15) + (shared.MatrixC[1][2] * Y >> 15) + (shared.MatrixC[2][2] * Z >> 15);
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Convert object coordinates (F,L,U) to object coordinates (X,Y,Z)
+// See the comment in "attitudeA" for a explanation about the calculation.
+//
+// input[0]: F ; input[1]: L ; input[2]: U
+// output[0]: X ; output[1]: Y ; output[2]: Z
+
+void Dsp1::subjectiveA(int16 *input, int16 *output)
+{
+ int16& F = input[0];
+ int16& L = input[1];
+ int16& U = input[2];
+ int16& X = output[0];
+ int16& Y = output[1];
+ int16& Z = output[2];
+
+ X = (shared.MatrixA[0][0] * F >> 15) + (shared.MatrixA[0][1] * L >> 15) + (shared.MatrixA[0][2] * U >> 15);
+ Y = (shared.MatrixA[1][0] * F >> 15) + (shared.MatrixA[1][1] * L >> 15) + (shared.MatrixA[1][2] * U >> 15);
+ Z = (shared.MatrixA[2][0] * F >> 15) + (shared.MatrixA[2][1] * L >> 15) + (shared.MatrixA[2][2] * U >> 15);
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Same than 'subjectiveA', but for the 'B' attitude
+
+void Dsp1::subjectiveB(int16 *input, int16 *output)
+{
+ int16& F = input[0];
+ int16& L = input[1];
+ int16& U = input[2];
+ int16& X = output[0];
+ int16& Y = output[1];
+ int16& Z = output[2];
+
+ X = (shared.MatrixB[0][0] * F >> 15) + (shared.MatrixB[0][1] * L >> 15) + (shared.MatrixB[0][2] * U >> 15);
+ Y = (shared.MatrixB[1][0] * F >> 15) + (shared.MatrixB[1][1] * L >> 15) + (shared.MatrixB[1][2] * U >> 15);
+ Z = (shared.MatrixB[2][0] * F >> 15) + (shared.MatrixB[2][1] * L >> 15) + (shared.MatrixB[2][2] * U >> 15);
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Same than 'subjectiveA', but for the 'C' attitude
+
+void Dsp1::subjectiveC(int16 *input, int16 *output)
+{
+ int16& F = input[0];
+ int16& L = input[1];
+ int16& U = input[2];
+ int16& X = output[0];
+ int16& Y = output[1];
+ int16& Z = output[2];
+
+ X = (shared.MatrixC[0][0] * F >> 15) + (shared.MatrixC[0][1] * L >> 15) + (shared.MatrixC[0][2] * U >> 15);
+ Y = (shared.MatrixC[1][0] * F >> 15) + (shared.MatrixC[1][1] * L >> 15) + (shared.MatrixC[1][2] * U >> 15);
+ Z = (shared.MatrixC[2][0] * F >> 15) + (shared.MatrixC[2][1] * L >> 15) + (shared.MatrixC[2][2] * U >> 15);
+}
+
+//////////////////////////////////////////////////////////////////
+
+// This command calculates the inner product (S) of a vector (X,Y,Z) and
+// the first column of MatrixA. It should be noted that that first column
+// represent the global coordinates of an unity vector in the forward
+// direction in the object coordinate system (coordinates (1,0,0) in the FLU
+// axes system).
+//
+// input[0]: X ; input[1]: Y ; input[2]: Z
+// output[0]: S
+
+void Dsp1::scalarA(int16 *input, int16 *output)
+{
+ int16& X = input[0];
+ int16& Y = input[1];
+ int16& Z = input[2];
+ int16& S = output[0];
+
+ S = (X * shared.MatrixA[0][0] + Y * shared.MatrixA[1][0] + Z * shared.MatrixA[2][0]) >> 15;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Same than 'scalarA', but for the 'B' attitude
+
+void Dsp1::scalarB(int16 *input, int16 *output)
+{
+ int16& X = input[0];
+ int16& Y = input[1];
+ int16& Z = input[2];
+ int16& S = output[0];
+
+ S = (X * shared.MatrixB[0][0] + Y * shared.MatrixB[1][0] + Z * shared.MatrixB[2][0]) >> 15;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Same than 'scalarA', but for the 'C' attitude
+
+void Dsp1::scalarC(int16 *input, int16 *output)
+{
+ int16& X = input[0];
+ int16& Y = input[1];
+ int16& Z = input[2];
+ int16& S = output[0];
+
+ S = (X * shared.MatrixC[0][0] + Y * shared.MatrixC[1][0] + Z * shared.MatrixC[2][0]) >> 15;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// This command determines the final attitude angles after the body with attitude angles (Ax, Ay, Az) with
+// respect to the global coordinates is rotated by the minor angular displacements (DeltaF, DeltaL, DeltaU).
+// It means that the XYZ axes are rotated by (Ax, Ay, Az) to obtain the FLU axes and, then, these
+// are rotated by (DeltaF, DeltaL, DeltaU). The command calculates and return the new FLU angles respect to the
+// XYZ system (Rx, Ry, Rz)
+// The formulae are:
+// Rx = Ax + (DeltaU*sin(Ay)+DeltaF*cos(Ay))
+// Ry = Ay + DeltaL - tan(Ax)*(DeltaU*cos(Ay)+DeltaF*sin(Ay))
+// Rz = Az + sec(Ax)*(DeltaU*cos(Ay)-DeltaF*sin(Ay))
+//
+// Now the discussion: according to the official documentation, as described in various commands, you pass from
+// XYZ to FLU by doing the rotations in the order Y, X, Z. In this command, the formulae are coherent with the
+// fact that Y is the first axis to do a rotation around it. However, in the "attitude" command, while the official
+// document describe it that way, we have discovered, when reverse engineering the command, that the calculated
+// matrix do the rotation around Y in the second place. This incoherent behaviour of various commands is, in my
+// opinion, a pretty severe implementation error. However, if you only use small "minor displacements", the error term
+// introduced by that incoherence should be almost negligible.
+
+void Dsp1::gyrate(int16 *input, int16 *output)
+{
+ int16& Az = input[0];
+ int16& Ax = input[1];
+ int16& Ay = input[2];
+ int16& U = input[3];
+ int16& F = input[4];
+ int16& L = input[5];
+ int16& Rz = output[0];
+ int16& Rx = output[1];
+ int16& Ry = output[2];
+
+ int16 CSec, ESec, CSin, C, E;
+ int16 SinAy = sin(Ay);
+ int16 CosAy = cos(Ay);
+
+ inverse(cos(Ax), 0, CSec, ESec);
+
+ // Rotation Around Z
+ normalizeDouble(U * CosAy - F * SinAy, C, E);
+
+ E = ESec - E;
+
+ normalize(C * CSec >> 15, C, E);
+
+ Rz = Az + denormalizeAndClip(C, E);
+
+ // Rotation Around X
+ Rx = Ax + (U * SinAy >> 15) + (F * CosAy >> 15);
+
+ // Rotation Around Y
+ normalizeDouble(U * CosAy + F * SinAy, C, E);
+
+ E = ESec - E;
+
+ normalize(sin(Ax), CSin, E);
+
+ normalize(-(C * (CSec * CSin >> 15) >> 15), C, E);
+
+ Ry = Ay + denormalizeAndClip(C, E) + L;
+}
+
+//////////////////////////////////////////////////////////////////
+
+const int16 Dsp1::MaxAZS_Exp[16] = {
+ 0x38b4, 0x38b7, 0x38ba, 0x38be, 0x38c0, 0x38c4, 0x38c7, 0x38ca,
+ 0x38ce, 0x38d0, 0x38d4, 0x38d7, 0x38da, 0x38dd, 0x38e0, 0x38e4
+};
+
+//////////////////////////////////////////////////////////////////
+
+
+// Set-up the projection framework. Besides returning some values, it store in RAM some values that
+// will be used by the other three projection commands (raster, target an project)
+// Input:
+// (Fx, Fy, Fz)-> coordinates of base point (global coordinates)
+// Lfe-> distance between the base point and the viewpoint (center of projection)
+// Les-> distance between the base point and the screen
+// Aas-> azimuth angle (0 degrees is east; 90 degrees is north)
+// Azs-> zenith angle (0 degrees is zenith)
+// Output:
+// Vof-> raster line of imaginary center (whatever it means ;) )
+// Vva-> raster line representing the horizon line
+// (Cx, Cy)-> coordinates of the projection of the center of the screen over the ground (ground coordinates)
+
+void Dsp1::parameter(int16 *input, int16 *output)
+{
+ int16& Fx = input[0];
+ int16& Fy = input[1];
+ int16& Fz = input[2];
+ int16& Lfe = input[3];
+ int16& Les = input[4];
+ int16& Aas = input[5];
+ int16& Azs = input[6];
+ int16& Vof = output[0];
+ int16& Vva = output[1];
+ int16& Cx = output[2];
+ int16& Cy = output[3];
+
+ int16 CSec, C, E;
+ int16 LfeNx, LfeNy, LfeNz;
+ int16 LesNx, LesNy, LesNz;
+
+ // Copy Zenith angle for clipping
+ int16 AZS = Azs;
+
+ // Store Les and his coefficient and exponent when normalized
+ shared.Les = Les;
+ shared.E_Les=0;
+ normalize(Les, shared.C_Les, shared.E_Les);
+
+ // Store Sine and Cosine of Azimuth and Zenith angle
+ shared.SinAas = sin(Aas);
+ shared.CosAas = cos(Aas);
+ shared.SinAzs = sin(Azs);
+ shared.CosAzs = cos(Azs);
+
+ // normal vector to the screen (norm 1, points toward the center of projection)
+ shared.Nx = shared.SinAzs * -shared.SinAas >> 15;
+ shared.Ny = shared.SinAzs * shared.CosAas >> 15;
+ shared.Nz = shared.CosAzs * 0x7fff >> 15;
+
+ // horizontal vector of the screen (Hz=0, norm 1, points toward the right of the screen)
+ shared.Hx = shared.CosAas*0x7fff>>15;
+ shared.Hy = shared.SinAas*0x7fff>>15;
+
+ // vertical vector of the screen (norm 1, points toward the top of the screen)
+ shared.Vx = shared.CosAzs*-shared.SinAas>>15;
+ shared.Vy = shared.CosAzs*shared.CosAas>>15;
+ shared.Vz = -shared.SinAzs*0x7fff>>15;
+
+ LfeNx = Lfe*shared.Nx>>15;
+ LfeNy = Lfe*shared.Ny>>15;
+ LfeNz = Lfe*shared.Nz>>15;
+
+ // Center of Projection
+ shared.CentreX = Fx+LfeNx;
+ shared.CentreY = Fy+LfeNy;
+ shared.CentreZ = Fz+LfeNz;
+
+ LesNx = Les*shared.Nx>>15;
+ LesNy = Les*shared.Ny>>15;
+ LesNz = Les*shared.Nz>>15;
+
+ // center of the screen (global coordinates)
+ shared.Gx=shared.CentreX-LesNx;
+ shared.Gy=shared.CentreY-LesNy;
+ shared.Gz=shared.CentreZ-LesNz;
+
+
+ E = 0;
+ normalize(shared.CentreZ, C, E);
+
+ shared.CentreZ_C = C;
+ shared.CentreZ_E = E;
+
+ // Determine clip boundary and clip Zenith angle if necessary
+ // (Why to clip? Maybe to avoid the screen can only show sky with no ground? Only a guess...)
+ int16 MaxAZS = MaxAZS_Exp[-E];
+
+ if (AZS < 0) {
+ MaxAZS = -MaxAZS;
+ if (AZS < MaxAZS + 1) AZS = MaxAZS + 1;
+ } else {
+ if (AZS > MaxAZS) AZS = MaxAZS;
+ }
+
+ // Store Sine and Cosine of clipped Zenith angle
+ shared.SinAZS = sin(AZS);
+ shared.CosAZS = cos(AZS);
+
+ // calculate the separation of (cx, cy) from the projection of
+ // the 'centre of projection' over the ground... (CentreZ*tg(AZS))
+ inverse(shared.CosAZS, 0, shared.SecAZS_C1, shared.SecAZS_E1);
+ normalize(C * shared.SecAZS_C1 >> 15, C, E);
+ E += shared.SecAZS_E1;
+ C = denormalizeAndClip(C, E) * shared.SinAZS >> 15;
+
+ // ... and then take into account the position of the centre of
+ // projection and the azimuth angle
+ shared.CentreX += C * shared.SinAas >> 15;
+ shared.CentreY -= C * shared.CosAas >> 15;
+
+ Cx = shared.CentreX;
+ Cy = shared.CentreY;
+
+ // Raster number of imaginary center and horizontal line
+ Vof = 0;
+
+ if ((Azs != AZS) || (Azs == MaxAZS))
+ {
+ // correct vof and vva when Azs is outside the 'non-clipping interval'
+ // we have only some few Taylor coefficients, so we cannot guess which ones
+ // are the approximated functions and, what is worse, we don't know why
+ // the own clipping stuff (and, particularly, this correction) is done
+ if (Azs == -32768) Azs = -32767;
+
+ C = Azs - MaxAZS;
+ if (C >= 0) C--;
+ int16 Aux = ~(C << 2);
+
+ // Vof += x+(1/3)*x^3, where x ranges from 0 to PI/4 when Azs-MaxAZS goes from 0 to 0x2000
+ C = Aux * DataRom[0x0328] >> 15;
+ C = (C * Aux >> 15) + DataRom[0x0327];
+ Vof -= (C * Aux >> 15) * Les >> 15;
+
+ // CosAZS *= 1+(1/2)*x^2+(5/24)*x^24, where x ranges from 0 to PI/4 when Azs-MaxAZS goes from 0 to 0x2000
+ C = Aux * Aux >> 15;
+ Aux = (C * DataRom[0x0324] >> 15) + DataRom[0x0325];
+ shared.CosAZS += (C * Aux >> 15) * shared.CosAZS >> 15;
+ }
+
+ // vertical offset of the screen with regard to the horizontal plane
+ // containing the centre of projection
+ shared.VOffset = Les * shared.CosAZS >> 15;
+
+ // The horizon line (the line in the screen that is crossed by the horizon plane
+ // -the horizontal plane containing the 'centre of projection'-),
+ // will be at distance Les*cotg(AZS) from the centre of the screen. This is difficult
+ // to explain but easily seen in a graph. To better see it, consider it in this way:
+ // Les*tg(AZS-90), draw some lines and apply basic trigonometry. ;)
+ inverse(shared.SinAZS, 0, CSec, E);
+ normalize(shared.VOffset, C, E);
+ normalize(C * CSec >> 15, C, E);
+
+ if (C == -32768) { C >>= 1; E++; }
+
+ Vva = denormalizeAndClip(-C, E);
+
+ // Store Secant of clipped Zenith angle
+ inverse(shared.CosAZS, 0, shared.SecAZS_C2, shared.SecAZS_E2);
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Calculates the matrix which transform an object situated on a raster line (Vs) into
+// his projection over the ground. The modified SecAZS is used here, so
+// i don't understand the fine details, but, basically, it's done
+// this way: The vertical offset between the point of projection and the
+// raster line is calculated (Vs*SinAzs>>15)+VOffset, then the height of
+// the center of projection is measured in that units (*CentreZ_C). If, now
+// you consider the "reference case" (center of projection at an unit of height),
+// the projection of a thin strip containing the raster line will have the same
+// width (as the raster line would be on the ground in this case, but will suffer a
+// change of scale in height (as the ground and the vertical axis would form an angle of 180-Azs degrees).
+// This scale factor, when the angle 'center of screen-center of projection-raster line' is small,
+// can be aproximated by the one of the center of the screen, 1/cos(Azs).(**) (Here is when it's used
+// SecAZS). By last, you have to consider the effect of the azimuth angle Aas, and you are done.
+//
+// Using matrix notation:
+// |A B| Centre_ZS | cos(Aas) -sin(Aas)| |1 0|
+// ProjectionMatrix = | | = ----------- * | | * | |
+// |C D| Vs*sin(Azs) |sin(Aas) cos(Aas)| |0 sec(Azs)|
+//
+// (**)
+// If Les=1, the vertical offset between the center
+// of projection and the center of the screen is Cos(Azs); then, if the vertical
+// offset is 1, the ratio of the projection over the ground respect to the
+// line on the screen is 1/cos(Azs).
+
+void Dsp1::raster(int16 *input, int16 *output)
+{
+ int16& Vs = input[0];
+ int16& An = output[0];
+ int16& Bn = output[1];
+ int16& Cn = output[2];
+ int16& Dn = output[3];
+
+ int16 C, E, C1, E1;
+
+ inverse((Vs * shared.SinAzs >> 15) + shared.VOffset, 7, C, E);
+
+ E += shared.CentreZ_E;
+ C1 = C * shared.CentreZ_C >> 15;
+
+ E1 = E + shared.SecAZS_E2;
+
+ normalize(C1, C, E);
+ C = denormalizeAndClip(C, E);
+
+ An = C * shared.CosAas >> 15;
+ Cn = C * shared.SinAas >> 15;
+
+ normalize(C1 * shared.SecAZS_C2 >> 15, C, E1);
+ C = denormalizeAndClip(C, E1);
+
+ Bn = C * -shared.SinAas >> 15;
+ Dn = C * shared.CosAas >> 15;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Calculate the projection over the ground of a selected point of screen
+// It simply apply the projection matrix described in the "Raster" command
+// to the vector (H,V) transposed, and add the result to the position of
+// the centre of projection.
+// The only special point to take into account is the directions on the screen:
+// H is positive rightward, but V is positive downward; this is why
+// the signs take that configuration
+
+void Dsp1::target(int16 *input, int16 *output)
+{
+ int16& H = input[0];
+ int16& V = input[1];
+ int16& X = output[0];
+ int16& Y = output[1];
+
+ int16 C, E, C1, E1;
+
+ inverse((V * shared.SinAzs >> 15) + shared.VOffset, 8, C, E);
+
+ E += shared.CentreZ_E;
+ C1 = C * shared.CentreZ_C >> 15;
+
+ E1 = E + shared.SecAZS_E1;
+
+ H <<= 8;
+ normalize(C1, C, E);
+ C = denormalizeAndClip(C, E) * H >> 15;
+
+ X = shared.CentreX + (C * shared.CosAas >> 15);
+ Y = shared.CentreY - (C * shared.SinAas >> 15);
+
+ V <<= 8;
+ normalize(C1 * shared.SecAZS_C1 >> 15, C, E1);
+ C = denormalizeAndClip(C, E1) * V >> 15;
+
+ X += C * -shared.SinAas >> 15;
+ Y += C * shared.CosAas >> 15;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Calculation of the projection over the screen (H,V) of an object (X,Y,Z) and his
+// 'enlargement ratio' (M). The positive directions on the screen are as described
+// in the targe command. M is scaled down by 2^-7, that is, M==0x0100 means ratio 1:1
+
+ void Dsp1::project(int16 *input, int16 *output)
+{
+ int16& X = input[0];
+ int16& Y = input[1];
+ int16& Z = input[2];
+ int16& H = output[0];
+ int16& V = output[1];
+ int16& M = output[2];
+
+ int32 aux, aux4;
+ int16 E, E2, E3, E4, E5, refE, E6, E7;
+ int16 C2, C4, C6, C8, C9, C10, C11, C12, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25, C26;
+ int16 Px, Py, Pz;
+
+ E4=E3=E2=E=E5=0;
+
+ normalizeDouble(int32(X)-shared.Gx, Px, E4);
+ normalizeDouble(int32(Y)-shared.Gy, Py, E);
+ normalizeDouble(int32(Z)-shared.Gz, Pz, E3);
+ Px>>=1; E4--; // to avoid overflows when calculating the scalar products
+ Py>>=1; E--;
+ Pz>>=1; E3--;
+
+ refE = (E>15);
+ C8=- (Py*shared.Ny>>15);
+ C9=- (Pz*shared.Nz>>15);
+ C12=C11+C8+C9; // this cannot overflow!
+
+ aux4=C12; // de-normalization with 32-bits arithmetic
+ refE = 16-refE; // refE can be up to 3
+ if (refE>=0)
+ aux4 <<=(refE);
+ else
+ aux4 >>=-(refE);
+ if (aux4==-1) aux4 = 0; // why?
+ aux4>>=1;
+
+ aux = static_cast(shared.Les) + aux4; // Les - the scalar product of P with the normal vector of the screen
+ normalizeDouble(aux, C10, E2);
+ E2 = 15-E2;
+
+ inverse(C10, 0, C4, E4);
+ C2=C4*shared.C_Les>>15; // scale factor
+
+
+ // H
+ E7=0;
+ C16= (Px*shared.Hx>>15);
+ C20= (Py*shared.Hy>>15);
+ C17=C16+C20; // scalar product of P with the normalized horizontal vector of the screen...
+
+ C18=C17*C2>>15; // ... multiplied by the scale factor
+ normalize(C18, C19, E7);
+ H=denormalizeAndClip(C19, shared.E_Les-E2+refE+E7);
+
+ // V
+ E6=0;
+ C21 = Px*shared.Vx>>15;
+ C22 = Py*shared.Vy>>15;
+ C23 = Pz*shared.Vz>>15;
+ C24=C21+C22+C23; // scalar product of P with the normalized vertical vector of the screen...
+
+ C26=C24*C2>>15; // ... multiplied by the scale factor
+ normalize(C26, C25, E6);
+ V=denormalizeAndClip(C25, shared.E_Les-E2+refE+E6);
+
+ // M
+ normalize(C2, C6, E4);
+ M=denormalizeAndClip(C6, E4+shared.E_Les-E2-7); // M is the scale factor divided by 2^7
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Calculate the sine of the input parameter
+// this is done by linear interpolation between
+// the points of a look-up table
+
+int16 Dsp1::sin(int16 Angle)
+{
+ if (Angle < 0) {
+ if (Angle == -32768) return 0;
+ return -sin(-Angle);
+ }
+ int32 S = SinTable[Angle >> 8] + (MulTable[Angle & 0xff] * SinTable[0x40 + (Angle >> 8)] >> 15);
+ if (S > 32767) S = 32767;
+ return (int16) S;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Calculate the cosine of the input parameter.
+// It's used the same method than in sin(int16)
+
+int16 Dsp1::cos(int16 Angle)
+{
+ if (Angle < 0) {
+ if (Angle == -32768) return -32768;
+ Angle = -Angle;
+ }
+ int32 S = SinTable[0x40 + (Angle >> 8)] - (MulTable[Angle & 0xff] * SinTable[Angle >> 8] >> 15);
+ if (S < -32768) S = -32767;
+ return (int16) S;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Determines the inverse of a floating point decimal number
+// iCoefficient*2^iExponent = 1/(Coefficient*2^Exponent), with the output
+// normalized (iCoefficient represents a number whose absolute value is between 1/2 and 1)
+// To invert 'Coefficient' a first initial guess is taken from a look-up table
+// and, then, two iterations of the Newton method (applied to the function
+// f(x)=1/(2*x)-Coefficient) are done. This results in a close approximation (iCoefficient) to a number 'y'
+// that verify Coefficient*y=1/2. This is why you have to correct the exponent by one
+// unit at the end.
+
+void Dsp1::inverse(int16 Coefficient, int16 Exponent, int16 &iCoefficient, int16 &iExponent)
+{
+ // Step One: Division by Zero
+ if (Coefficient == 0x0000)
+ {
+ iCoefficient = 0x7fff;
+ iExponent = 0x002f;
+ }
+ else
+ {
+ int16 Sign = 1;
+
+ // Step Two: Remove Sign
+ if (Coefficient < 0)
+ {
+ if (Coefficient < -32767) Coefficient = -32767;
+ Coefficient = -Coefficient;
+ Sign = -1;
+ }
+
+ // Step Three: Normalize
+ while (Coefficient < 0x4000)
+ {
+ Coefficient <<= 1;
+ Exponent--;
+ }
+
+ // Step Four: Special Case
+ if (Coefficient == 0x4000)
+ if (Sign == 1) iCoefficient = 0x7fff;
+ else {
+ iCoefficient = -0x4000;
+ Exponent--;
+ }
+ else {
+ // Step Five: Initial Guess
+ int16 i = DataRom[((Coefficient - 0x4000) >> 7) + 0x0065];
+
+ // Step Six: Iterate Newton's Method
+ i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1;
+ i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1;
+
+ iCoefficient = i * Sign;
+ }
+
+ iExponent = 1 - Exponent;
+ }
+}
+
+//////////////////////////////////////////////////////////////////
+
+int16 Dsp1::denormalizeAndClip(int16 C, int16 E)
+{
+ if (E > 0) {
+ if (C > 0) return 32767; else if (C < 0) return -32767;
+ } else {
+ if (E < 0) return C * DataRom[0x0031 + E] >> 15;
+ }
+ return C;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Normalize the input number (m), understood as ranging from -1 to 1,
+// to the form: Coefficient*2^Exponent,
+// where the absolute value of Coefficient is >= 1/2
+// (Coefficient>=0x4000 or Coefficient <= (int16)0xc001)
+
+void Dsp1::normalize(int16 m, int16 &Coefficient, int16 &Exponent)
+{
+ int16 i = 0x4000;
+ int16 e = 0;
+
+ if (m < 0)
+ while ((m & i) && i)
+ {
+ i >>= 1;
+ e++;
+ }
+ else
+ while (!(m & i) && i)
+ {
+ i >>= 1;
+ e++;
+ }
+
+ if (e > 0)
+ Coefficient = m * DataRom[0x21 + e] << 1;
+ else
+ Coefficient = m;
+
+ Exponent -= e;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Same than 'normalize' but with an int32 input
+
+void Dsp1::normalizeDouble(int32 Product, int16 &Coefficient, int16 &Exponent)
+{
+ int16 n = Product & 0x7fff;
+ int16 m = Product >> 15;
+ int16 i = 0x4000;
+ int16 e = 0;
+
+ if (m < 0)
+ while ((m & i) && i)
+ {
+ i >>= 1;
+ e++;
+ }
+ else
+ while (!(m & i) && i)
+ {
+ i >>= 1;
+ e++;
+ }
+
+ if (e > 0)
+ {
+ Coefficient = m * DataRom[0x0021 + e] << 1;
+
+ if (e < 15)
+ Coefficient += n * DataRom[0x0040 - e] >> 15;
+ else
+ {
+ i = 0x4000;
+
+ if (m < 0)
+ while ((n & i) && i)
+ {
+ i >>= 1;
+ e++;
+ }
+ else
+ while (!(n & i) && i)
+ {
+ i >>= 1;
+ e++;
+ }
+
+ if (e > 15)
+ Coefficient = n * DataRom[0x0012 + e] << 1;
+ else
+ Coefficient += n;
+ }
+ }
+ else
+ Coefficient = m;
+
+ Exponent = e;
+}
+
+//////////////////////////////////////////////////////////////////
+
+// Shift to the right
+
+int16 Dsp1::shiftR(int16 C, int16 E)
+{
+ return (C * DataRom[0x0031 + E] >> 15);
+}
+
+//////////////////////////////////////////////////////////////////
+
+// this is, indeed, only part of the Data ROM
+const int16 Dsp1::SinTable[256] = {
+ 0x0000, 0x0324, 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2,
+ 0x18f8, 0x1c0b, 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
+ 0x30fb, 0x33de, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
+ 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842,
+ 0x5a82, 0x5cb4, 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6,
+ 0x6a6d, 0x6c24, 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504,
+ 0x7641, 0x776c, 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3,
+ 0x7d8a, 0x7e1d, 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6,
+ 0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d,
+ 0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c,
+ 0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24,
+ 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4,
+ 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4,
+ 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de,
+ 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b,
+ 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324,
+ -0x0000, -0x0324, -0x0647, -0x096a, -0x0c8b, -0x0fab, -0x12c8, -0x15e2,
+ -0x18f8, -0x1c0b, -0x1f19, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11,
+ -0x30fb, -0x33de, -0x36ba, -0x398c, -0x3c56, -0x3f17, -0x41ce, -0x447a,
+ -0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842,
+ -0x5a82, -0x5cb4, -0x5ed7, -0x60ec, -0x62f2, -0x64e8, -0x66cf, -0x68a6,
+ -0x6a6d, -0x6c24, -0x6dca, -0x6f5f, -0x70e2, -0x7255, -0x73b5, -0x7504,
+ -0x7641, -0x776c, -0x7884, -0x798a, -0x7a7d, -0x7b5d, -0x7c29, -0x7ce3,
+ -0x7d8a, -0x7e1d, -0x7e9d, -0x7f09, -0x7f62, -0x7fa7, -0x7fd8, -0x7ff6,
+ -0x7fff, -0x7ff6, -0x7fd8, -0x7fa7, -0x7f62, -0x7f09, -0x7e9d, -0x7e1d,
+ -0x7d8a, -0x7ce3, -0x7c29, -0x7b5d, -0x7a7d, -0x798a, -0x7884, -0x776c,
+ -0x7641, -0x7504, -0x73b5, -0x7255, -0x70e2, -0x6f5f, -0x6dca, -0x6c24,
+ -0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f2, -0x60ec, -0x5ed7, -0x5cb4,
+ -0x5a82, -0x5842, -0x55f5, -0x539b, -0x5133, -0x4ebf, -0x4c3f, -0x49b4,
+ -0x471c, -0x447a, -0x41ce, -0x3f17, -0x3c56, -0x398c, -0x36ba, -0x33de,
+ -0x30fb, -0x2e11, -0x2b1f, -0x2826, -0x2528, -0x2223, -0x1f19, -0x1c0b,
+ -0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324};
+
+ //////////////////////////////////////////////////////////////////
+
+// Optimised for Performance
+ const int16 Dsp1::MulTable[256] = {
+ 0x0000, 0x0003, 0x0006, 0x0009, 0x000c, 0x000f, 0x0012, 0x0015,
+ 0x0019, 0x001c, 0x001f, 0x0022, 0x0025, 0x0028, 0x002b, 0x002f,
+ 0x0032, 0x0035, 0x0038, 0x003b, 0x003e, 0x0041, 0x0045, 0x0048,
+ 0x004b, 0x004e, 0x0051, 0x0054, 0x0057, 0x005b, 0x005e, 0x0061,
+ 0x0064, 0x0067, 0x006a, 0x006d, 0x0071, 0x0074, 0x0077, 0x007a,
+ 0x007d, 0x0080, 0x0083, 0x0087, 0x008a, 0x008d, 0x0090, 0x0093,
+ 0x0096, 0x0099, 0x009d, 0x00a0, 0x00a3, 0x00a6, 0x00a9, 0x00ac,
+ 0x00af, 0x00b3, 0x00b6, 0x00b9, 0x00bc, 0x00bf, 0x00c2, 0x00c5,
+ 0x00c9, 0x00cc, 0x00cf, 0x00d2, 0x00d5, 0x00d8, 0x00db, 0x00df,
+ 0x00e2, 0x00e5, 0x00e8, 0x00eb, 0x00ee, 0x00f1, 0x00f5, 0x00f8,
+ 0x00fb, 0x00fe, 0x0101, 0x0104, 0x0107, 0x010b, 0x010e, 0x0111,
+ 0x0114, 0x0117, 0x011a, 0x011d, 0x0121, 0x0124, 0x0127, 0x012a,
+ 0x012d, 0x0130, 0x0133, 0x0137, 0x013a, 0x013d, 0x0140, 0x0143,
+ 0x0146, 0x0149, 0x014d, 0x0150, 0x0153, 0x0156, 0x0159, 0x015c,
+ 0x015f, 0x0163, 0x0166, 0x0169, 0x016c, 0x016f, 0x0172, 0x0175,
+ 0x0178, 0x017c, 0x017f, 0x0182, 0x0185, 0x0188, 0x018b, 0x018e,
+ 0x0192, 0x0195, 0x0198, 0x019b, 0x019e, 0x01a1, 0x01a4, 0x01a8,
+ 0x01ab, 0x01ae, 0x01b1, 0x01b4, 0x01b7, 0x01ba, 0x01be, 0x01c1,
+ 0x01c4, 0x01c7, 0x01ca, 0x01cd, 0x01d0, 0x01d4, 0x01d7, 0x01da,
+ 0x01dd, 0x01e0, 0x01e3, 0x01e6, 0x01ea, 0x01ed, 0x01f0, 0x01f3,
+ 0x01f6, 0x01f9, 0x01fc, 0x0200, 0x0203, 0x0206, 0x0209, 0x020c,
+ 0x020f, 0x0212, 0x0216, 0x0219, 0x021c, 0x021f, 0x0222, 0x0225,
+ 0x0228, 0x022c, 0x022f, 0x0232, 0x0235, 0x0238, 0x023b, 0x023e,
+ 0x0242, 0x0245, 0x0248, 0x024b, 0x024e, 0x0251, 0x0254, 0x0258,
+ 0x025b, 0x025e, 0x0261, 0x0264, 0x0267, 0x026a, 0x026e, 0x0271,
+ 0x0274, 0x0277, 0x027a, 0x027d, 0x0280, 0x0284, 0x0287, 0x028a,
+ 0x028d, 0x0290, 0x0293, 0x0296, 0x029a, 0x029d, 0x02a0, 0x02a3,
+ 0x02a6, 0x02a9, 0x02ac, 0x02b0, 0x02b3, 0x02b6, 0x02b9, 0x02bc,
+ 0x02bf, 0x02c2, 0x02c6, 0x02c9, 0x02cc, 0x02cf, 0x02d2, 0x02d5,
+ 0x02d8, 0x02db, 0x02df, 0x02e2, 0x02e5, 0x02e8, 0x02eb, 0x02ee,
+ 0x02f1, 0x02f5, 0x02f8, 0x02fb, 0x02fe, 0x0301, 0x0304, 0x0307,
+ 0x030b, 0x030e, 0x0311, 0x0314, 0x0317, 0x031a, 0x031d, 0x0321};
+
+//////////////////////////////////////////////////////////////////
+
+// Data ROM, as logged from a DSP-1B with the 0x1f command;
+// it contains the tables and constants used by the commands.
+// The tables used are: two shift tables (0x022-0x031 and 0x031-0x040 -this last one
+// with an error in 0x03c which has survived to all the DSP-1 revisions-); a inverse
+// table (used as initial guess) at 0x065-0x0e4; a square root table (used also
+// as initial guess) at 0x0e5-0x115; two sin and cos tables (used as nodes to construct
+// a interpolation curve) at, respectively, 0x116-0x197 and 0x196-0x215.
+// As a curiosity, in the positions 0x21c-0x31c it's contained a
+// 257-points arccos table that, apparently, have been not used anywhere
+// (maybe for the MaxAZS_Exp table?).
+ const uint16 Dsp1::DataRom[1024] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020,
+ 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000,
+ 0x4000, 0x7fff, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200,
+ 0x0100, 0x0080, 0x0040, 0x0020, 0x0001, 0x0008, 0x0004, 0x0002,
+ 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x8000, 0xffe5, 0x0100, 0x7fff, 0x7f02, 0x7e08,
+ 0x7d12, 0x7c1f, 0x7b30, 0x7a45, 0x795d, 0x7878, 0x7797, 0x76ba,
+ 0x75df, 0x7507, 0x7433, 0x7361, 0x7293, 0x71c7, 0x70fe, 0x7038,
+ 0x6f75, 0x6eb4, 0x6df6, 0x6d3a, 0x6c81, 0x6bca, 0x6b16, 0x6a64,
+ 0x69b4, 0x6907, 0x685b, 0x67b2, 0x670b, 0x6666, 0x65c4, 0x6523,
+ 0x6484, 0x63e7, 0x634c, 0x62b3, 0x621c, 0x6186, 0x60f2, 0x6060,
+ 0x5fd0, 0x5f41, 0x5eb5, 0x5e29, 0x5d9f, 0x5d17, 0x5c91, 0x5c0c,
+ 0x5b88, 0x5b06, 0x5a85, 0x5a06, 0x5988, 0x590b, 0x5890, 0x5816,
+ 0x579d, 0x5726, 0x56b0, 0x563b, 0x55c8, 0x5555, 0x54e4, 0x5474,
+ 0x5405, 0x5398, 0x532b, 0x52bf, 0x5255, 0x51ec, 0x5183, 0x511c,
+ 0x50b6, 0x5050, 0x4fec, 0x4f89, 0x4f26, 0x4ec5, 0x4e64, 0x4e05,
+ 0x4da6, 0x4d48, 0x4cec, 0x4c90, 0x4c34, 0x4bda, 0x4b81, 0x4b28,
+ 0x4ad0, 0x4a79, 0x4a23, 0x49cd, 0x4979, 0x4925, 0x48d1, 0x487f,
+ 0x482d, 0x47dc, 0x478c, 0x473c, 0x46ed, 0x469f, 0x4651, 0x4604,
+ 0x45b8, 0x456c, 0x4521, 0x44d7, 0x448d, 0x4444, 0x43fc, 0x43b4,
+ 0x436d, 0x4326, 0x42e0, 0x429a, 0x4255, 0x4211, 0x41cd, 0x4189,
+ 0x4146, 0x4104, 0x40c2, 0x4081, 0x4040, 0x3fff, 0x41f7, 0x43e1,
+ 0x45bd, 0x478d, 0x4951, 0x4b0b, 0x4cbb, 0x4e61, 0x4fff, 0x5194,
+ 0x5322, 0x54a9, 0x5628, 0x57a2, 0x5914, 0x5a81, 0x5be9, 0x5d4a,
+ 0x5ea7, 0x5fff, 0x6152, 0x62a0, 0x63ea, 0x6530, 0x6672, 0x67b0,
+ 0x68ea, 0x6a20, 0x6b53, 0x6c83, 0x6daf, 0x6ed9, 0x6fff, 0x7122,
+ 0x7242, 0x735f, 0x747a, 0x7592, 0x76a7, 0x77ba, 0x78cb, 0x79d9,
+ 0x7ae5, 0x7bee, 0x7cf5, 0x7dfa, 0x7efe, 0x7fff, 0x0000, 0x0324,
+ 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, 0x18f8, 0x1c0b,
+ 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, 0x30fb, 0x33de,
+ 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, 0x471c, 0x49b4,
+ 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, 0x5a82, 0x5cb4,
+ 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, 0x6a6d, 0x6c24,
+ 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, 0x7641, 0x776c,
+ 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, 0x7d8a, 0x7e1d,
+ 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, 0x7fff, 0x7ff6,
+ 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3,
+ 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504,
+ 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6,
+ 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842,
+ 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a,
+ 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11,
+ 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2,
+ 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x7fff, 0x7ff6,
+ 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3,
+ 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504,
+ 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6,
+ 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842,
+ 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a,
+ 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11,
+ 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2,
+ 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x0000, 0xfcdc,
+ 0xf9b9, 0xf696, 0xf375, 0xf055, 0xed38, 0xea1e, 0xe708, 0xe3f5,
+ 0xe0e7, 0xdddd, 0xdad8, 0xd7da, 0xd4e1, 0xd1ef, 0xcf05, 0xcc22,
+ 0xc946, 0xc674, 0xc3aa, 0xc0e9, 0xbe32, 0xbb86, 0xb8e4, 0xb64c,
+ 0xb3c1, 0xb141, 0xaecd, 0xac65, 0xaa0b, 0xa7be, 0xa57e, 0xa34c,
+ 0xa129, 0x9f14, 0x9d0e, 0x9b18, 0x9931, 0x975a, 0x9593, 0x93dc,
+ 0x9236, 0x90a1, 0x8f1e, 0x8dab, 0x8c4b, 0x8afc, 0x89bf, 0x8894,
+ 0x877c, 0x8676, 0x8583, 0x84a3, 0x83d7, 0x831d, 0x8276, 0x81e3,
+ 0x8163, 0x80f7, 0x809e, 0x8059, 0x8028, 0x800a, 0x6488, 0x0080,
+ 0x03ff, 0x0116, 0x0002, 0x0080, 0x4000, 0x3fd7, 0x3faf, 0x3f86,
+ 0x3f5d, 0x3f34, 0x3f0c, 0x3ee3, 0x3eba, 0x3e91, 0x3e68, 0x3e40,
+ 0x3e17, 0x3dee, 0x3dc5, 0x3d9c, 0x3d74, 0x3d4b, 0x3d22, 0x3cf9,
+ 0x3cd0, 0x3ca7, 0x3c7f, 0x3c56, 0x3c2d, 0x3c04, 0x3bdb, 0x3bb2,
+ 0x3b89, 0x3b60, 0x3b37, 0x3b0e, 0x3ae5, 0x3abc, 0x3a93, 0x3a69,
+ 0x3a40, 0x3a17, 0x39ee, 0x39c5, 0x399c, 0x3972, 0x3949, 0x3920,
+ 0x38f6, 0x38cd, 0x38a4, 0x387a, 0x3851, 0x3827, 0x37fe, 0x37d4,
+ 0x37aa, 0x3781, 0x3757, 0x372d, 0x3704, 0x36da, 0x36b0, 0x3686,
+ 0x365c, 0x3632, 0x3609, 0x35df, 0x35b4, 0x358a, 0x3560, 0x3536,
+ 0x350c, 0x34e1, 0x34b7, 0x348d, 0x3462, 0x3438, 0x340d, 0x33e3,
+ 0x33b8, 0x338d, 0x3363, 0x3338, 0x330d, 0x32e2, 0x32b7, 0x328c,
+ 0x3261, 0x3236, 0x320b, 0x31df, 0x31b4, 0x3188, 0x315d, 0x3131,
+ 0x3106, 0x30da, 0x30ae, 0x3083, 0x3057, 0x302b, 0x2fff, 0x2fd2,
+ 0x2fa6, 0x2f7a, 0x2f4d, 0x2f21, 0x2ef4, 0x2ec8, 0x2e9b, 0x2e6e,
+ 0x2e41, 0x2e14, 0x2de7, 0x2dba, 0x2d8d, 0x2d60, 0x2d32, 0x2d05,
+ 0x2cd7, 0x2ca9, 0x2c7b, 0x2c4d, 0x2c1f, 0x2bf1, 0x2bc3, 0x2b94,
+ 0x2b66, 0x2b37, 0x2b09, 0x2ada, 0x2aab, 0x2a7c, 0x2a4c, 0x2a1d,
+ 0x29ed, 0x29be, 0x298e, 0x295e, 0x292e, 0x28fe, 0x28ce, 0x289d,
+ 0x286d, 0x283c, 0x280b, 0x27da, 0x27a9, 0x2777, 0x2746, 0x2714,
+ 0x26e2, 0x26b0, 0x267e, 0x264c, 0x2619, 0x25e7, 0x25b4, 0x2581,
+ 0x254d, 0x251a, 0x24e6, 0x24b2, 0x247e, 0x244a, 0x2415, 0x23e1,
+ 0x23ac, 0x2376, 0x2341, 0x230b, 0x22d6, 0x229f, 0x2269, 0x2232,
+ 0x21fc, 0x21c4, 0x218d, 0x2155, 0x211d, 0x20e5, 0x20ad, 0x2074,
+ 0x203b, 0x2001, 0x1fc7, 0x1f8d, 0x1f53, 0x1f18, 0x1edd, 0x1ea1,
+ 0x1e66, 0x1e29, 0x1ded, 0x1db0, 0x1d72, 0x1d35, 0x1cf6, 0x1cb8,
+ 0x1c79, 0x1c39, 0x1bf9, 0x1bb8, 0x1b77, 0x1b36, 0x1af4, 0x1ab1,
+ 0x1a6e, 0x1a2a, 0x19e6, 0x19a1, 0x195c, 0x1915, 0x18ce, 0x1887,
+ 0x183f, 0x17f5, 0x17ac, 0x1761, 0x1715, 0x16c9, 0x167c, 0x162e,
+ 0x15df, 0x158e, 0x153d, 0x14eb, 0x1497, 0x1442, 0x13ec, 0x1395,
+ 0x133c, 0x12e2, 0x1286, 0x1228, 0x11c9, 0x1167, 0x1104, 0x109e,
+ 0x1036, 0x0fcc, 0x0f5f, 0x0eef, 0x0e7b, 0x0e04, 0x0d89, 0x0d0a,
+ 0x0c86, 0x0bfd, 0x0b6d, 0x0ad6, 0x0a36, 0x098d, 0x08d7, 0x0811,
+ 0x0736, 0x063e, 0x0519, 0x039a, 0x0000, 0x7fff, 0x0100, 0x0080,
+ 0x021d, 0x00c8, 0x00ce, 0x0048, 0x0a26, 0x277a, 0x00ce, 0x6488,
+ 0x14ac, 0x0001, 0x00f9, 0x00fc, 0x00ff, 0x00fc, 0x00f9, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
+
+//////////////////////////////////////////////////////////////////
+
+#endif
diff --git a/higan/sfc/coprocessor/dsp1/dsp1emu.hpp b/higan/sfc/coprocessor/dsp1/dsp1emu.hpp
new file mode 100644
index 00000000..9ae313ac
--- /dev/null
+++ b/higan/sfc/coprocessor/dsp1/dsp1emu.hpp
@@ -0,0 +1,129 @@
+// DSP-1's emulation code
+//
+// Based on research by Overload, The Dumper, Neviksti and Andreas Naive
+// Date: June 2006
+
+#ifndef __DSP1EMUL_H
+#define __DSP1EMUL_H
+
+#define DSP1_VERSION 0x0102
+
+class Dsp1
+{
+ public:
+ // The DSP-1 status register has 16 bits, but only
+ // the upper 8 bits can be accessed from an external device, so all these
+ // positions are referred to the upper byte (bits D8 to D15)
+ enum SrFlags {DRC=0x04, DRS=0x10, RQM=0x80};
+
+ // According to Overload's docs, these are the meanings of the flags:
+ // DRC: The Data Register Control (DRC) bit specifies the data transfer length to and from the host CPU.
+ // 0: Data transfer to and from the DSP-1 is 16 bits.
+ // 1: Data transfer to and from the DSP-1 is 8 bits.
+ // DRS: The Data Register Status (DRS) bit indicates the data transfer status in the case of transfering 16-bit data.
+ // 0: Data transfer has terminated.
+ // 1: Data transfer in progress.
+ // RQM: The Request for Master (RQM) indicates that the DSP1 is requesting host CPU for data read/write.
+ // 0: Internal Data Register Transfer.
+ // 1: External Data Register Transfer.
+
+ Dsp1();
+ uint8 getSr(); // return the status register's high byte
+ uint8 getDr();
+ void setDr(uint8 iDr);
+ void reset();
+
+ void serialize(serializer&);
+
+ private:
+ enum FsmMajorState {WAIT_COMMAND, READ_DATA, WRITE_DATA};
+ enum MaxDataAccesses {MAX_READS=7, MAX_WRITES=1024};
+
+ struct Command {
+ void (Dsp1::*callback)(int16 *, int16 *);
+ unsigned int reads;
+ unsigned int writes;
+ };
+
+ static const Command mCommandTable[];
+ static const int16 MaxAZS_Exp[16];
+ static const int16 SinTable[];
+ static const int16 MulTable[];
+ static const uint16 DataRom[];
+
+ struct SharedData { // some RAM variables shared between commands
+ int16 MatrixA[3][3]; // attitude matrix A
+ int16 MatrixB[3][3];
+ int16 MatrixC[3][3];
+ int16 CentreX, CentreY, CentreZ; // center of projection
+ int16 CentreZ_C, CentreZ_E;
+ int16 VOffset; // vertical offset of the screen with regard to the centre of projection
+ int16 Les, C_Les, E_Les;
+ int16 SinAas, CosAas;
+ int16 SinAzs, CosAzs;
+ int16 SinAZS, CosAZS;
+ int16 SecAZS_C1, SecAZS_E1;
+ int16 SecAZS_C2, SecAZS_E2;
+ int16 Nx, Ny, Nz; // normal vector to the screen (norm 1, points toward the center of projection)
+ int16 Gx, Gy, Gz; // center of the screen (global coordinates)
+ int16 Hx, Hy; // horizontal vector of the screen (Hz=0, norm 1, points toward the right of the screen)
+ int16 Vx, Vy, Vz; // vertical vector of the screen (norm 1, points toward the top of the screen)
+
+ } shared;
+
+ uint8 mSr; // status register
+ int mSrLowByteAccess;
+ uint16 mDr; // "internal" representation of the data register
+ unsigned mFsmMajorState; // current major state of the FSM
+ uint8 mCommand; // current command processed by the FSM
+ uint8 mDataCounter; // #uint16 read/writes counter used by the FSM
+ int16 mReadBuffer[MAX_READS];
+ int16 mWriteBuffer[MAX_WRITES];
+ bool mFreeze; // need explanation? ;)
+
+ void fsmStep(bool read, uint8 &data); // FSM logic
+
+ // commands
+ void memoryTest(int16 *input, int16 *output);
+ void memoryDump(int16 *input, int16 *output);
+ void memorySize(int16 *input, int16 *output);
+ void multiply(int16* input, int16* output);
+ void multiply2(int16* input, int16* output);
+ void inverse(int16 *input, int16 *output);
+ void triangle(int16 *input, int16 *output);
+ void radius(int16 *input, int16 *output);
+ void range(int16 *input, int16 *output);
+ void range2(int16 *input, int16 *output);
+ void distance(int16 *input, int16 *output);
+ void rotate(int16 *input, int16 *output);
+ void polar(int16 *input, int16 *output);
+ void attitudeA(int16 *input, int16 *output);
+ void attitudeB(int16 *input, int16 *output);
+ void attitudeC(int16 *input, int16 *output);
+ void objectiveA(int16 *input, int16 *output);
+ void objectiveB(int16 *input, int16 *output);
+ void objectiveC(int16 *input, int16 *output);
+ void subjectiveA(int16 *input, int16 *output);
+ void subjectiveB(int16 *input, int16 *output);
+ void subjectiveC(int16 *input, int16 *output);
+ void scalarA(int16 *input, int16 *output);
+ void scalarB(int16 *input, int16 *output);
+ void scalarC(int16 *input, int16 *output);
+ void gyrate(int16 *input, int16 *output);
+ void parameter(int16 *input, int16 *output);
+ void raster(int16 *input, int16 *output);
+ void target(int16 *input, int16 *output);
+ void project(int16 *input, int16 *output);
+
+ // auxiliar functions
+ int16 sin(int16 Angle);
+ int16 cos(int16 Angle);
+ void inverse(int16 Coefficient, int16 Exponent, int16 &iCoefficient, int16 &iExponent);
+ int16 denormalizeAndClip(int16 C, int16 E);
+ void normalize(int16 m, int16 &Coefficient, int16 &Exponent);
+ void normalizeDouble(int32 Product, int16 &Coefficient, int16 &Exponent);
+ int16 shiftR(int16 C, int16 E);
+};
+
+#endif
+
diff --git a/higan/sfc/coprocessor/dsp1/serialization.cpp b/higan/sfc/coprocessor/dsp1/serialization.cpp
new file mode 100644
index 00000000..a3781f03
--- /dev/null
+++ b/higan/sfc/coprocessor/dsp1/serialization.cpp
@@ -0,0 +1,52 @@
+auto DSP1::serialize(serializer& s) -> void {
+ dsp1emu.serialize(s);
+}
+
+auto Dsp1::serialize(serializer &s) -> void {
+ for(unsigned i = 0; i < 3; i++) {
+ s.array(shared.MatrixA[i]);
+ s.array(shared.MatrixB[i]);
+ s.array(shared.MatrixC[i]);
+ }
+
+ s.integer(shared.CentreX);
+ s.integer(shared.CentreY);
+ s.integer(shared.CentreZ);
+ s.integer(shared.CentreZ_C);
+ s.integer(shared.CentreZ_E);
+ s.integer(shared.VOffset);
+ s.integer(shared.Les);
+ s.integer(shared.C_Les);
+ s.integer(shared.E_Les);
+ s.integer(shared.SinAas);
+ s.integer(shared.CosAas);
+ s.integer(shared.SinAzs);
+ s.integer(shared.CosAzs);
+ s.integer(shared.SinAZS);
+ s.integer(shared.CosAZS);
+ s.integer(shared.SecAZS_C1);
+ s.integer(shared.SecAZS_E1);
+ s.integer(shared.SecAZS_C2);
+ s.integer(shared.SecAZS_E2);
+ s.integer(shared.Nx);
+ s.integer(shared.Ny);
+ s.integer(shared.Nz);
+ s.integer(shared.Gx);
+ s.integer(shared.Gy);
+ s.integer(shared.Gz);
+ s.integer(shared.Hx);
+ s.integer(shared.Hy);
+ s.integer(shared.Vx);
+ s.integer(shared.Vy);
+ s.integer(shared.Vz);
+
+ s.integer(mSr);
+ s.integer(mSrLowByteAccess);
+ s.integer(mDr);
+ s.integer(mFsmMajorState);
+ s.integer(mCommand);
+ s.integer(mDataCounter);
+ s.array(mReadBuffer);
+ s.array(mWriteBuffer);
+ s.integer(mFreeze);
+}
diff --git a/higan/sfc/coprocessor/dsp2/dsp2.cpp b/higan/sfc/coprocessor/dsp2/dsp2.cpp
new file mode 100644
index 00000000..8167b39f
--- /dev/null
+++ b/higan/sfc/coprocessor/dsp2/dsp2.cpp
@@ -0,0 +1,136 @@
+#include
+
+namespace SuperFamicom {
+
+#define DSP2_CPP
+#include "opcodes.cpp"
+
+DSP2 dsp2;
+#include "serialization.cpp"
+
+auto DSP2::power() -> void {
+ status.waiting_for_command = true;
+ status.in_count = 0;
+ status.in_index = 0;
+ status.out_count = 0;
+ status.out_index = 0;
+
+ status.op05transparent = 0;
+ status.op05haslen = false;
+ status.op05len = 0;
+ status.op06haslen = false;
+ status.op06len = 0;
+ status.op09word1 = 0;
+ status.op09word2 = 0;
+ status.op0dhaslen = false;
+ status.op0doutlen = 0;
+ status.op0dinlen = 0;
+}
+
+auto DSP2::read(uint24 addr, uint8 data) -> uint8 {
+ if(addr & 1) return 0x00;
+
+ uint8 r = 0xff;
+ if(status.out_count) {
+ r = status.output[status.out_index++];
+ status.out_index &= 511;
+ if(status.out_count == status.out_index) {
+ status.out_count = 0;
+ }
+ }
+ return r;
+}
+
+auto DSP2::write(uint24 addr, uint8 data) -> void {
+ if(addr & 1) return;
+
+ if(status.waiting_for_command) {
+ status.command = data;
+ status.in_index = 0;
+ status.waiting_for_command = false;
+
+ switch(data) {
+ case 0x01: status.in_count = 32; break;
+ case 0x03: status.in_count = 1; break;
+ case 0x05: status.in_count = 1; break;
+ case 0x06: status.in_count = 1; break;
+ case 0x07: break;
+ case 0x08: break;
+ case 0x09: status.in_count = 4; break;
+ case 0x0d: status.in_count = 2; break;
+ case 0x0f: status.in_count = 0; break;
+ }
+ } else {
+ status.parameters[status.in_index++] = data;
+ status.in_index &= 511;
+ }
+
+ if(status.in_count == status.in_index) {
+ status.waiting_for_command = true;
+ status.out_index = 0;
+ switch(status.command) {
+ case 0x01: {
+ status.out_count = 32;
+ op01();
+ } break;
+
+ case 0x03: {
+ op03();
+ } break;
+
+ case 0x05: {
+ if(status.op05haslen) {
+ status.op05haslen = false;
+ status.out_count = status.op05len;
+ op05();
+ } else {
+ status.op05len = status.parameters[0];
+ status.in_index = 0;
+ status.in_count = status.op05len * 2;
+ status.op05haslen = true;
+ if(data)status.waiting_for_command = false;
+ }
+ } break;
+
+ case 0x06: {
+ if(status.op06haslen) {
+ status.op06haslen = false;
+ status.out_count = status.op06len;
+ op06();
+ } else {
+ status.op06len = status.parameters[0];
+ status.in_index = 0;
+ status.in_count = status.op06len;
+ status.op06haslen = true;
+ if(data)status.waiting_for_command = false;
+ }
+ } break;
+
+ case 0x07: break;
+ case 0x08: break;
+
+ case 0x09: {
+ op09();
+ } break;
+
+ case 0x0d: {
+ if(status.op0dhaslen) {
+ status.op0dhaslen = false;
+ status.out_count = status.op0doutlen;
+ op0d();
+ } else {
+ status.op0dinlen = status.parameters[0];
+ status.op0doutlen = status.parameters[1];
+ status.in_index = 0;
+ status.in_count = (status.op0dinlen + 1) >> 1;
+ status.op0dhaslen = true;
+ if(data)status.waiting_for_command = false;
+ }
+ } break;
+
+ case 0x0f: break;
+ }
+ }
+}
+
+}
diff --git a/higan/sfc/coprocessor/dsp2/dsp2.hpp b/higan/sfc/coprocessor/dsp2/dsp2.hpp
new file mode 100644
index 00000000..bdace27a
--- /dev/null
+++ b/higan/sfc/coprocessor/dsp2/dsp2.hpp
@@ -0,0 +1,38 @@
+struct DSP2 {
+ auto power() -> void;
+
+ auto read(uint24 addr, uint8 data) -> uint8;
+ auto write(uint24 addr, uint8 data) -> void;
+
+ auto serialize(serializer&) -> void;
+
+ struct {
+ bool waiting_for_command;
+ unsigned command;
+ unsigned in_count, in_index;
+ unsigned out_count, out_index;
+
+ uint8_t parameters[512];
+ uint8_t output[512];
+
+ uint8 op05transparent;
+ bool op05haslen;
+ int op05len;
+ bool op06haslen;
+ int op06len;
+ uint16 op09word1;
+ uint16 op09word2;
+ bool op0dhaslen;
+ int op0doutlen;
+ int op0dinlen;
+ } status;
+
+ void op01();
+ void op03();
+ void op05();
+ void op06();
+ void op09();
+ void op0d();
+};
+
+extern DSP2 dsp2;
diff --git a/higan/sfc/coprocessor/dsp2/opcodes.cpp b/higan/sfc/coprocessor/dsp2/opcodes.cpp
new file mode 100644
index 00000000..f015ac32
--- /dev/null
+++ b/higan/sfc/coprocessor/dsp2/opcodes.cpp
@@ -0,0 +1,177 @@
+#ifdef DSP2_CPP
+
+//convert bitmap to bitplane tile
+void DSP2::op01() {
+//op01 size is always 32 bytes input and output
+//the hardware does strange things if you vary the size
+
+unsigned char c0, c1, c2, c3;
+unsigned char *p1 = status.parameters;
+unsigned char *p2a = status.output;
+unsigned char *p2b = status.output + 16; //halfway
+
+//process 8 blocks of 4 bytes each
+ for(int j = 0; j < 8; j++) {
+ c0 = *p1++;
+ c1 = *p1++;
+ c2 = *p1++;
+ c3 = *p1++;
+
+ *p2a++ = (c0 & 0x10) << 3 |
+ (c0 & 0x01) << 6 |
+ (c1 & 0x10) << 1 |
+ (c1 & 0x01) << 4 |
+ (c2 & 0x10) >> 1 |
+ (c2 & 0x01) << 2 |
+ (c3 & 0x10) >> 3 |
+ (c3 & 0x01);
+
+ *p2a++ = (c0 & 0x20) << 2 |
+ (c0 & 0x02) << 5 |
+ (c1 & 0x20) |
+ (c1 & 0x02) << 3 |
+ (c2 & 0x20) >> 2 |
+ (c2 & 0x02) << 1 |
+ (c3 & 0x20) >> 4 |
+ (c3 & 0x02) >> 1;
+
+ *p2b++ = (c0 & 0x40) << 1 |
+ (c0 & 0x04) << 4 |
+ (c1 & 0x40) >> 1 |
+ (c1 & 0x04) << 2 |
+ (c2 & 0x40) >> 3 |
+ (c2 & 0x04) |
+ (c3 & 0x40) >> 5 |
+ (c3 & 0x04) >> 2;
+
+ *p2b++ = (c0 & 0x80) |
+ (c0 & 0x08) << 3 |
+ (c1 & 0x80) >> 2 |
+ (c1 & 0x08) << 1 |
+ (c2 & 0x80) >> 4 |
+ (c2 & 0x08) >> 1 |
+ (c3 & 0x80) >> 6 |
+ (c3 & 0x08) >> 3;
+ }
+}
+
+//set transparent color
+void DSP2::op03() {
+ status.op05transparent = status.parameters[0];
+}
+
+//replace bitmap using transparent color
+void DSP2::op05() {
+uint8 color;
+// Overlay bitmap with transparency.
+// Input:
+//
+// Bitmap 1: i[0] <=> i[size-1]
+// Bitmap 2: i[size] <=> i[2*size-1]
+//
+// Output:
+//
+// Bitmap 3: o[0] <=> o[size-1]
+//
+// Processing:
+//
+// Process all 4-bit pixels (nibbles) in the bitmap
+//
+// if ( BM2_pixel == transparent_color )
+// pixelout = BM1_pixel
+// else
+// pixelout = BM2_pixel
+
+// The max size bitmap is limited to 255 because the size parameter is a byte
+// I think size=0 is an error. The behavior of the chip on size=0 is to
+// return the last value written to DR if you read DR on Op05 with
+// size = 0. I don't think it's worth implementing this quirk unless it's
+// proven necessary.
+
+unsigned char c1, c2;
+unsigned char *p1 = status.parameters;
+unsigned char *p2 = status.parameters + status.op05len;
+unsigned char *p3 = status.output;
+
+ color = status.op05transparent & 0x0f;
+
+ for(int n = 0; n < status.op05len; n++) {
+ c1 = *p1++;
+ c2 = *p2++;
+ *p3++ = ( ((c2 >> 4) == color ) ? c1 & 0xf0 : c2 & 0xf0 ) |
+ ( ((c2 & 0x0f) == color ) ? c1 & 0x0f : c2 & 0x0f );
+ }
+}
+
+//reverse bitmap
+void DSP2::op06() {
+// Input:
+// size
+// bitmap
+
+int i, j;
+ for(i = 0, j = status.op06len - 1; i < status.op06len; i++, j--) {
+ status.output[j] = (status.parameters[i] << 4) | (status.parameters[i] >> 4);
+ }
+}
+
+//multiply
+void DSP2::op09() {
+ status.out_count = 4;
+
+ status.op09word1 = status.parameters[0] | (status.parameters[1] << 8);
+ status.op09word2 = status.parameters[2] | (status.parameters[3] << 8);
+
+uint32 r;
+ r = status.op09word1 * status.op09word2;
+ status.output[0] = r;
+ status.output[1] = r >> 8;
+ status.output[2] = r >> 16;
+ status.output[3] = r >> 24;
+}
+
+//scale bitmap
+void DSP2::op0d() {
+// Bit accurate hardware algorithm - uses fixed point math
+// This should match the DSP2 Op0D output exactly
+// I wouldn't recommend using this unless you're doing hardware debug.
+// In some situations it has small visual artifacts that
+// are not readily apparent on a TV screen but show up clearly
+// on a monitor. Use Overload's scaling instead.
+// This is for hardware verification testing.
+//
+// One note: the HW can do odd byte scaling but since we divide
+// by two to get the count of bytes this won't work well for
+// odd byte scaling (in any of the current algorithm implementations).
+// So far I haven't seen Dungeon Master use it.
+// If it does we can adjust the parameters and code to work with it
+
+uint32 multiplier; // Any size int >= 32-bits
+uint32 pixloc; // match size of multiplier
+int i, j;
+uint8 pixelarray[512];
+ if(status.op0dinlen <= status.op0doutlen) {
+ multiplier = 0x10000; // In our self defined fixed point 0x10000 == 1
+ } else {
+ multiplier = (status.op0dinlen << 17) / ((status.op0doutlen << 1) + 1);
+ }
+
+ pixloc = 0;
+ for(i = 0; i < status.op0doutlen * 2; i++) {
+ j = pixloc >> 16;
+
+ if(j & 1) {
+ pixelarray[i] = (status.parameters[j >> 1] & 0x0f);
+ } else {
+ pixelarray[i] = (status.parameters[j >> 1] & 0xf0) >> 4;
+ }
+
+ pixloc += multiplier;
+ }
+
+ for(i = 0; i < status.op0doutlen; i++) {
+ status.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1];
+ }
+}
+
+#endif
diff --git a/higan/sfc/coprocessor/dsp2/serialization.cpp b/higan/sfc/coprocessor/dsp2/serialization.cpp
new file mode 100644
index 00000000..b2193619
--- /dev/null
+++ b/higan/sfc/coprocessor/dsp2/serialization.cpp
@@ -0,0 +1,22 @@
+auto DSP2::serialize(serializer& s) -> void {
+ s.integer(status.waiting_for_command);
+ s.integer(status.command);
+ s.integer(status.in_count);
+ s.integer(status.in_index);
+ s.integer(status.out_count);
+ s.integer(status.out_index);
+
+ s.array(status.parameters);
+ s.array(status.output);
+
+ s.integer(status.op05transparent);
+ s.integer(status.op05haslen);
+ s.integer(status.op05len);
+ s.integer(status.op06haslen);
+ s.integer(status.op06len);
+ s.integer(status.op09word1);
+ s.integer(status.op09word2);
+ s.integer(status.op0dhaslen);
+ s.integer(status.op0doutlen);
+ s.integer(status.op0dinlen);
+}
diff --git a/higan/sfc/coprocessor/dsp4/dsp4.cpp b/higan/sfc/coprocessor/dsp4/dsp4.cpp
new file mode 100644
index 00000000..e283fe14
--- /dev/null
+++ b/higan/sfc/coprocessor/dsp4/dsp4.cpp
@@ -0,0 +1,62 @@
+#include
+
+namespace SuperFamicom {
+
+namespace DSP4i {
+ #define bool8 uint8_t
+ #define int8 int8_t
+ #define int16 int16_t
+ #define int32 int32_t
+ #define int64 int64_t
+ #define uint8 uint8_t
+ #define uint16 uint16_t
+ #define uint32 uint32_t
+ #define uint64 uint64_t
+ #define DSP4_CPP
+ inline uint16 READ_WORD(uint8 *addr) {
+ return (addr[0]) + (addr[1] << 8);
+ }
+ inline uint32 READ_DWORD(uint8 *addr) {
+ return (addr[0]) + (addr[1] << 8) + (addr[2] << 16) + (addr[3] << 24);
+ }
+ inline void WRITE_WORD(uint8 *addr, uint16 data) {
+ addr[0] = data;
+ addr[1] = data >> 8;
+ }
+ #include "dsp4emu.h"
+ #include "dsp4emu.c"
+ #undef bool8
+ #undef int8
+ #undef int16
+ #undef int32
+ #undef int64
+ #undef uint8
+ #undef uint16
+ #undef uint32
+ #undef uint64
+}
+
+DSP4 dsp4;
+#include "serialization.cpp"
+
+auto DSP4::power() -> void {
+ DSP4i::InitDSP4();
+}
+
+auto DSP4::read(uint24 addr, uint8 data) -> uint8 {
+ if(addr & 1) return 0x80;
+
+ DSP4i::dsp4_address = addr;
+ DSP4i::DSP4GetByte();
+ return DSP4i::dsp4_byte;
+}
+
+auto DSP4::write(uint24 addr, uint8 data) -> void {
+ if(addr & 1) return;
+
+ DSP4i::dsp4_address = addr;
+ DSP4i::dsp4_byte = data;
+ DSP4i::DSP4SetByte();
+}
+
+}
diff --git a/higan/sfc/coprocessor/dsp4/dsp4.hpp b/higan/sfc/coprocessor/dsp4/dsp4.hpp
new file mode 100644
index 00000000..c0c8ca1a
--- /dev/null
+++ b/higan/sfc/coprocessor/dsp4/dsp4.hpp
@@ -0,0 +1,10 @@
+struct DSP4 {
+ auto power() -> void;
+
+ auto read(uint24 addr, uint8 data) -> uint8;
+ auto write(uint24 addr, uint8 data) -> void;
+
+ auto serialize(serializer&) -> void;
+};
+
+extern DSP4 dsp4;
diff --git a/higan/sfc/coprocessor/dsp4/dsp4emu.c b/higan/sfc/coprocessor/dsp4/dsp4emu.c
new file mode 100644
index 00000000..73c1ec3d
--- /dev/null
+++ b/higan/sfc/coprocessor/dsp4/dsp4emu.c
@@ -0,0 +1,2150 @@
+#ifdef DSP4_CPP
+
+//DSP-4 emulator code
+//Copyright (c) 2004-2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden
+
+/*
+Due recognition and credit are given on Overload's DSP website.
+Thank those contributors for their hard work on this chip.
+
+
+Fixed-point math reminder:
+
+[sign, integer, fraction]
+1.15.00 * 1.15.00 = 2.30.00 -> 1.30.00 (DSP) -> 1.31.00 (LSB is '0')
+1.15.00 * 1.00.15 = 2.15.15 -> 1.15.15 (DSP) -> 1.15.16 (LSB is '0')
+*/
+
+#include "dsp4emu.h"
+
+struct DSP4_t DSP4;
+struct DSP4_vars_t DSP4_vars;
+
+//////////////////////////////////////////////////////////////
+
+// input protocol
+
+static int16 DSP4_READ_WORD()
+{
+ int16 out;
+
+ out = READ_WORD(DSP4.parameters + DSP4.in_index);
+ DSP4.in_index += 2;
+
+ return out;
+}
+
+static int32 DSP4_READ_DWORD()
+{
+ int32 out;
+
+ out = READ_DWORD(DSP4.parameters + DSP4.in_index);
+ DSP4.in_index += 4;
+
+ return out;
+}
+
+
+//////////////////////////////////////////////////////////////
+
+// output protocol
+
+#define DSP4_CLEAR_OUT() \
+{ DSP4.out_count = 0; DSP4.out_index = 0; }
+
+#define DSP4_WRITE_BYTE( d ) \
+{ WRITE_WORD( DSP4.output + DSP4.out_count, ( d ) ); DSP4.out_count++; }
+
+#define DSP4_WRITE_WORD( d ) \
+{ WRITE_WORD( DSP4.output + DSP4.out_count, ( d ) ); DSP4.out_count += 2; }
+
+#ifndef MSB_FIRST
+#define DSP4_WRITE_16_WORD( d ) \
+{ memcpy(DSP4.output + DSP4.out_count, ( d ), 32); DSP4.out_count += 32; }
+#else
+#define DSP4_WRITE_16_WORD( d ) \
+{ int16 *p = ( d ), *end = ( d )+16; \
+ for (; p != end; p++) \
+ { \
+ WRITE_WORD( DSP4.output + DSP4.out_count, *p ); \
+ } \
+ DSP4.out_count += 32; \
+}
+#endif
+
+#ifdef PRINT_OP
+#define DSP4_WRITE_DEBUG( x, d ) \
+ WRITE_WORD( nop + x, d );
+#endif
+
+#ifdef DEBUG_DSP
+#define DSP4_WRITE_DEBUG( x, d ) \
+ WRITE_WORD( nop + x, d );
+#endif
+
+//////////////////////////////////////////////////////////////
+
+// used to wait for dsp i/o
+
+#define DSP4_WAIT( x ) \
+ DSP4.in_index = 0; DSP4_vars.DSP4_Logic = x; return;
+
+//////////////////////////////////////////////////////////////
+
+// 1.7.8 -> 1.15.16
+#define SEX78( a ) ( ( (int32) ( (int16) (a) ) ) << 8 )
+
+// 1.15.0 -> 1.15.16
+#define SEX16( a ) ( ( (int32) ( (int16) (a) ) ) << 16 )
+
+#ifdef PRINT_OP
+#define U16( a ) ( (uint16) ( a ) )
+#endif
+
+#ifdef DEBUG_DSP
+#define U16( a ) ( (uint16) ( a ) )
+#endif
+
+//////////////////////////////////////////////////////////////
+
+// Attention: This lookup table is not verified
+static const uint16 div_lut[64] = { 0x0000, 0x8000, 0x4000, 0x2aaa, 0x2000, 0x1999, 0x1555, 0x1249, 0x1000, 0x0e38,
+ 0x0ccc, 0x0ba2, 0x0aaa, 0x09d8, 0x0924, 0x0888, 0x0800, 0x0787, 0x071c, 0x06bc,
+ 0x0666, 0x0618, 0x05d1, 0x0590, 0x0555, 0x051e, 0x04ec, 0x04bd, 0x0492, 0x0469,
+ 0x0444, 0x0421, 0x0400, 0x03e0, 0x03c3, 0x03a8, 0x038e, 0x0375, 0x035e, 0x0348,
+ 0x0333, 0x031f, 0x030c, 0x02fa, 0x02e8, 0x02d8, 0x02c8, 0x02b9, 0x02aa, 0x029c,
+ 0x028f, 0x0282, 0x0276, 0x026a, 0x025e, 0x0253, 0x0249, 0x023e, 0x0234, 0x022b,
+ 0x0222, 0x0219, 0x0210, 0x0208, };
+int16 DSP4_Inverse(int16 value)
+{
+ // saturate bounds
+ if (value < 0)
+ {
+ value = 0;
+ }
+ if (value > 63)
+ {
+ value = 63;
+ }
+
+ return div_lut[value];
+}
+
+//////////////////////////////////////////////////////////////
+
+// Prototype
+void DSP4_OP0B(bool8 *draw, int16 sp_x, int16 sp_y, int16 sp_attr, bool8 size, bool8 stop);
+
+//////////////////////////////////////////////////////////////
+
+// OP00
+void DSP4_Multiply(int16 Multiplicand, int16 Multiplier, int32 *Product)
+{
+ *Product = (Multiplicand * Multiplier << 1) >> 1;
+}
+
+//////////////////////////////////////////////////////////////
+
+
+void DSP4_OP01()
+{
+ DSP4.waiting4command = FALSE;
+
+ // op flow control
+ switch (DSP4_vars.DSP4_Logic)
+ {
+ case 1:
+ goto resume1; break;
+ case 2:
+ goto resume2; break;
+ case 3:
+ goto resume3; break;
+ }
+
+ ////////////////////////////////////////////////////
+ // process initial inputs
+
+ // sort inputs
+ DSP4_vars.world_y = DSP4_READ_DWORD();
+ DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_top[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD();
+ DSP4_vars.viewport_bottom = DSP4_READ_WORD();
+ DSP4_vars.world_x = DSP4_READ_DWORD();
+ DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD();
+ DSP4_vars.world_yofs = DSP4_READ_WORD();
+ DSP4_vars.world_dy = DSP4_READ_DWORD();
+ DSP4_vars.world_dx = DSP4_READ_DWORD();
+ DSP4_vars.distance = DSP4_READ_WORD();
+ DSP4_READ_WORD(); // 0x0000
+ DSP4_vars.world_xenv = DSP4_READ_DWORD();
+ DSP4_vars.world_ddy = DSP4_READ_WORD();
+ DSP4_vars.world_ddx = DSP4_READ_WORD();
+ DSP4_vars.view_yofsenv = DSP4_READ_WORD();
+
+ // initial (x,y,offset) at starting DSP4_vars.raster line
+ DSP4_vars.view_x1 = (int16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16);
+ DSP4_vars.view_y1 = (int16)(DSP4_vars.world_y >> 16);
+ DSP4_vars.view_xofs1 = (int16)(DSP4_vars.world_x >> 16);
+ DSP4_vars.view_yofs1 = DSP4_vars.world_yofs;
+ DSP4_vars.view_turnoff_x = 0;
+ DSP4_vars.view_turnoff_dx = 0;
+
+ // first DSP4_vars.raster line
+ DSP4_vars.poly_raster[0][0] = DSP4_vars.poly_bottom[0][0];
+
+ do
+ {
+ ////////////////////////////////////////////////////
+ // process one iteration of projection
+
+ // perspective projection of world (x,y,scroll) points
+ // based on the current projection lines
+ DSP4_vars.view_x2 = (int16)(( ( ( DSP4_vars.world_x + DSP4_vars.world_xenv ) >> 16 ) * DSP4_vars.distance >> 15 ) + ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 ));
+ DSP4_vars.view_y2 = (int16)((DSP4_vars.world_y >> 16) * DSP4_vars.distance >> 15);
+ DSP4_vars.view_xofs2 = DSP4_vars.view_x2;
+ DSP4_vars.view_yofs2 = (DSP4_vars.world_yofs * DSP4_vars.distance >> 15) + DSP4_vars.poly_bottom[0][0] - DSP4_vars.view_y2;
+
+
+ // 1. World x-location before transformation
+ // 2. Viewer x-position at the next
+ // 3. World y-location before perspective projection
+ // 4. Viewer y-position below the horizon
+ // 5. Number of DSP4_vars.raster lines drawn in this iteration
+
+ DSP4_CLEAR_OUT();
+ DSP4_WRITE_WORD((uint16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16));
+ DSP4_WRITE_WORD(DSP4_vars.view_x2);
+ DSP4_WRITE_WORD((uint16)(DSP4_vars.world_y >> 16));
+ DSP4_WRITE_WORD(DSP4_vars.view_y2);
+
+ //////////////////////////////////////////////////////
+
+ // SR = 0x00
+
+ // determine # of DSP4_vars.raster lines used
+ DSP4_vars.segments = DSP4_vars.poly_raster[0][0] - DSP4_vars.view_y2;
+
+ // prevent overdraw
+ if (DSP4_vars.view_y2 >= DSP4_vars.poly_raster[0][0])
+ DSP4_vars.segments = 0;
+ else
+ DSP4_vars.poly_raster[0][0] = DSP4_vars.view_y2;
+
+ // don't draw outside the window
+ if (DSP4_vars.view_y2 < DSP4_vars.poly_top[0][0])
+ {
+ DSP4_vars.segments = 0;
+
+ // flush remaining DSP4_vars.raster lines
+ if (DSP4_vars.view_y1 >= DSP4_vars.poly_top[0][0])
+ DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.poly_top[0][0];
+ }
+
+ // SR = 0x80
+
+ DSP4_WRITE_WORD(DSP4_vars.segments);
+
+ //////////////////////////////////////////////////////
+
+ // scan next command if no SR check needed
+ if (DSP4_vars.segments)
+ {
+ int32 px_dx, py_dy;
+ int32 x_scroll, y_scroll;
+
+ // SR = 0x00
+
+ // linear interpolation (lerp) between projected points
+ px_dx = (DSP4_vars.view_xofs2 - DSP4_vars.view_xofs1) * DSP4_Inverse(DSP4_vars.segments) << 1;
+ py_dy = (DSP4_vars.view_yofs2 - DSP4_vars.view_yofs1) * DSP4_Inverse(DSP4_vars.segments) << 1;
+
+ // starting step values
+ x_scroll = SEX16(DSP4_vars.poly_cx[0][0] + DSP4_vars.view_xofs1);
+ y_scroll = SEX16(-DSP4_vars.viewport_bottom + DSP4_vars.view_yofs1 + DSP4_vars.view_yofsenv + DSP4_vars.poly_cx[1][0] - DSP4_vars.world_yofs);
+
+ // SR = 0x80
+
+ // rasterize line
+ for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++)
+ {
+ // 1. HDMA memory pointer (bg1)
+ // 2. vertical scroll offset ($210E)
+ // 3. horizontal scroll offset ($210D)
+
+ DSP4_WRITE_WORD(DSP4_vars.poly_ptr[0][0]);
+ DSP4_WRITE_WORD((uint16)((y_scroll + 0x8000) >> 16));
+ DSP4_WRITE_WORD((uint16)((x_scroll + 0x8000) >> 16));
+
+
+ // update memory address
+ DSP4_vars.poly_ptr[0][0] -= 4;
+
+ // update screen values
+ x_scroll += px_dx;
+ y_scroll += py_dy;
+ }
+ }
+
+ ////////////////////////////////////////////////////
+ // Post-update
+
+ // update new viewer (x,y,scroll) to last DSP4_vars.raster line drawn
+ DSP4_vars.view_x1 = DSP4_vars.view_x2;
+ DSP4_vars.view_y1 = DSP4_vars.view_y2;
+ DSP4_vars.view_xofs1 = DSP4_vars.view_xofs2;
+ DSP4_vars.view_yofs1 = DSP4_vars.view_yofs2;
+
+ // add deltas for projection lines
+ DSP4_vars.world_dx += SEX78(DSP4_vars.world_ddx);
+ DSP4_vars.world_dy += SEX78(DSP4_vars.world_ddy);
+
+ // update projection lines
+ DSP4_vars.world_x += (DSP4_vars.world_dx + DSP4_vars.world_xenv);
+ DSP4_vars.world_y += DSP4_vars.world_dy;
+
+ // update road turnoff position
+ DSP4_vars.view_turnoff_x += DSP4_vars.view_turnoff_dx;
+
+ ////////////////////////////////////////////////////
+ // command check
+
+ // scan next command
+ DSP4.in_count = 2;
+ DSP4_WAIT(1) resume1 :
+
+ // check for termination
+ DSP4_vars.distance = DSP4_READ_WORD();
+ if (DSP4_vars.distance == -0x8000)
+ break;
+
+ // road turnoff
+ if( (uint16) DSP4_vars.distance == 0x8001 )
+ {
+ DSP4.in_count = 6;
+ DSP4_WAIT(2) resume2:
+
+ DSP4_vars.distance = DSP4_READ_WORD();
+ DSP4_vars.view_turnoff_x = DSP4_READ_WORD();
+ DSP4_vars.view_turnoff_dx = DSP4_READ_WORD();
+
+ // factor in new changes
+ DSP4_vars.view_x1 += ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 );
+ DSP4_vars.view_xofs1 += ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 );
+
+ // update stepping values
+ DSP4_vars.view_turnoff_x += DSP4_vars.view_turnoff_dx;
+
+ DSP4.in_count = 2;
+ DSP4_WAIT(1)
+ }
+
+ // already have 2 bytes read
+ DSP4.in_count = 6;
+ DSP4_WAIT(3) resume3 :
+
+ // inspect inputs
+ DSP4_vars.world_ddy = DSP4_READ_WORD();
+ DSP4_vars.world_ddx = DSP4_READ_WORD();
+ DSP4_vars.view_yofsenv = DSP4_READ_WORD();
+
+ // no envelope here
+ DSP4_vars.world_xenv = 0;
+ }
+ while (1);
+
+ // terminate op
+ DSP4.waiting4command = TRUE;
+}
+
+//////////////////////////////////////////////////////////////
+
+
+void DSP4_OP03()
+{
+ DSP4_vars.OAM_RowMax = 33;
+ memset(DSP4_vars.OAM_Row, 0, 64);
+}
+
+
+//////////////////////////////////////////////////////////////
+
+
+void DSP4_OP05()
+{
+ DSP4_vars.OAM_index = 0;
+ DSP4_vars.OAM_bits = 0;
+ memset(DSP4_vars.OAM_attr, 0, 32);
+ DSP4_vars.sprite_count = 0;
+}
+
+
+//////////////////////////////////////////////////////////////
+
+void DSP4_OP06()
+{
+ DSP4_CLEAR_OUT();
+ DSP4_WRITE_16_WORD(DSP4_vars.OAM_attr);
+}
+
+//////////////////////////////////////////////////////////////
+
+
+void DSP4_OP07()
+{
+ DSP4.waiting4command = FALSE;
+
+ // op flow control
+ switch (DSP4_vars.DSP4_Logic)
+ {
+ case 1:
+ goto resume1; break;
+ case 2:
+ goto resume2; break;
+ }
+
+ ////////////////////////////////////////////////////
+ // sort inputs
+
+ DSP4_vars.world_y = DSP4_READ_DWORD();
+ DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_top[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD();
+ DSP4_vars.viewport_bottom = DSP4_READ_WORD();
+ DSP4_vars.world_x = DSP4_READ_DWORD();
+ DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD();
+ DSP4_vars.world_yofs = DSP4_READ_WORD();
+ DSP4_vars.distance = DSP4_READ_WORD();
+ DSP4_vars.view_y2 = DSP4_READ_WORD();
+ DSP4_vars.view_dy = DSP4_READ_WORD() * DSP4_vars.distance >> 15;
+ DSP4_vars.view_x2 = DSP4_READ_WORD();
+ DSP4_vars.view_dx = DSP4_READ_WORD() * DSP4_vars.distance >> 15;
+ DSP4_vars.view_yofsenv = DSP4_READ_WORD();
+
+ // initial (x,y,offset) at starting DSP4_vars.raster line
+ DSP4_vars.view_x1 = (int16)(DSP4_vars.world_x >> 16);
+ DSP4_vars.view_y1 = (int16)(DSP4_vars.world_y >> 16);
+ DSP4_vars.view_xofs1 = DSP4_vars.view_x1;
+ DSP4_vars.view_yofs1 = DSP4_vars.world_yofs;
+
+ // first DSP4_vars.raster line
+ DSP4_vars.poly_raster[0][0] = DSP4_vars.poly_bottom[0][0];
+
+
+ do
+ {
+ ////////////////////////////////////////////////////
+ // process one iteration of projection
+
+ // add shaping
+ DSP4_vars.view_x2 += DSP4_vars.view_dx;
+ DSP4_vars.view_y2 += DSP4_vars.view_dy;
+
+ // vertical scroll calculation
+ DSP4_vars.view_xofs2 = DSP4_vars.view_x2;
+ DSP4_vars.view_yofs2 = (DSP4_vars.world_yofs * DSP4_vars.distance >> 15) + DSP4_vars.poly_bottom[0][0] - DSP4_vars.view_y2;
+
+ // 1. Viewer x-position at the next
+ // 2. Viewer y-position below the horizon
+ // 3. Number of DSP4_vars.raster lines drawn in this iteration
+
+ DSP4_CLEAR_OUT();
+ DSP4_WRITE_WORD(DSP4_vars.view_x2);
+ DSP4_WRITE_WORD(DSP4_vars.view_y2);
+
+ //////////////////////////////////////////////////////
+
+ // SR = 0x00
+
+ // determine # of DSP4_vars.raster lines used
+ DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.view_y2;
+
+ // prevent overdraw
+ if (DSP4_vars.view_y2 >= DSP4_vars.poly_raster[0][0])
+ DSP4_vars.segments = 0;
+ else
+ DSP4_vars.poly_raster[0][0] = DSP4_vars.view_y2;
+
+ // don't draw outside the window
+ if (DSP4_vars.view_y2 < DSP4_vars.poly_top[0][0])
+ {
+ DSP4_vars.segments = 0;
+
+ // flush remaining DSP4_vars.raster lines
+ if (DSP4_vars.view_y1 >= DSP4_vars.poly_top[0][0])
+ DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.poly_top[0][0];
+ }
+
+ // SR = 0x80
+
+ DSP4_WRITE_WORD(DSP4_vars.segments);
+
+ //////////////////////////////////////////////////////
+
+ // scan next command if no SR check needed
+ if (DSP4_vars.segments)
+ {
+ int32 px_dx, py_dy;
+ int32 x_scroll, y_scroll;
+
+ // SR = 0x00
+
+ // linear interpolation (lerp) between projected points
+ px_dx = (DSP4_vars.view_xofs2 - DSP4_vars.view_xofs1) * DSP4_Inverse(DSP4_vars.segments) << 1;
+ py_dy = (DSP4_vars.view_yofs2 - DSP4_vars.view_yofs1) * DSP4_Inverse(DSP4_vars.segments) << 1;
+
+ // starting step values
+ x_scroll = SEX16(DSP4_vars.poly_cx[0][0] + DSP4_vars.view_xofs1);
+ y_scroll = SEX16(-DSP4_vars.viewport_bottom + DSP4_vars.view_yofs1 + DSP4_vars.view_yofsenv + DSP4_vars.poly_cx[1][0] - DSP4_vars.world_yofs);
+
+ // SR = 0x80
+
+ // rasterize line
+ for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++)
+ {
+ // 1. HDMA memory pointer (bg2)
+ // 2. vertical scroll offset ($2110)
+ // 3. horizontal scroll offset ($210F)
+
+ DSP4_WRITE_WORD(DSP4_vars.poly_ptr[0][0]);
+ DSP4_WRITE_WORD((uint16)((y_scroll + 0x8000) >> 16));
+ DSP4_WRITE_WORD((uint16)((x_scroll + 0x8000) >> 16));
+
+ // update memory address
+ DSP4_vars.poly_ptr[0][0] -= 4;
+
+ // update screen values
+ x_scroll += px_dx;
+ y_scroll += py_dy;
+ }
+ }
+
+ /////////////////////////////////////////////////////
+ // Post-update
+
+ // update new viewer (x,y,scroll) to last DSP4_vars.raster line drawn
+ DSP4_vars.view_x1 = DSP4_vars.view_x2;
+ DSP4_vars.view_y1 = DSP4_vars.view_y2;
+ DSP4_vars.view_xofs1 = DSP4_vars.view_xofs2;
+ DSP4_vars.view_yofs1 = DSP4_vars.view_yofs2;
+
+ ////////////////////////////////////////////////////
+ // command check
+
+ // scan next command
+ DSP4.in_count = 2;
+ DSP4_WAIT(1) resume1 :
+
+ // check for opcode termination
+ DSP4_vars.distance = DSP4_READ_WORD();
+ if (DSP4_vars.distance == -0x8000)
+ break;
+
+ // already have 2 bytes in queue
+ DSP4.in_count = 10;
+ DSP4_WAIT(2) resume2 :
+
+ // inspect inputs
+ DSP4_vars.view_y2 = DSP4_READ_WORD();
+ DSP4_vars.view_dy = DSP4_READ_WORD() * DSP4_vars.distance >> 15;
+ DSP4_vars.view_x2 = DSP4_READ_WORD();
+ DSP4_vars.view_dx = DSP4_READ_WORD() * DSP4_vars.distance >> 15;
+ DSP4_vars.view_yofsenv = DSP4_READ_WORD();
+ }
+ while (1);
+
+ DSP4.waiting4command = TRUE;
+}
+
+//////////////////////////////////////////////////////////////
+
+void DSP4_OP08()
+{
+ int16 win_left, win_right;
+ int16 view_x[2], view_y[2];
+ int16 envelope[2][2];
+
+ DSP4.waiting4command = FALSE;
+
+ // op flow control
+ switch (DSP4_vars.DSP4_Logic)
+ {
+ case 1:
+ goto resume1; break;
+ case 2:
+ goto resume2; break;
+ }
+
+ ////////////////////////////////////////////////////
+ // process initial inputs for two polygons
+
+ // clip values
+ DSP4_vars.poly_clipRt[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_clipRt[0][1] = DSP4_READ_WORD();
+ DSP4_vars.poly_clipRt[1][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_clipRt[1][1] = DSP4_READ_WORD();
+
+ DSP4_vars.poly_clipLf[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_clipLf[0][1] = DSP4_READ_WORD();
+ DSP4_vars.poly_clipLf[1][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_clipLf[1][1] = DSP4_READ_WORD();
+
+ // unknown (constant) (ex. 1P/2P = $00A6, $00A6, $00A6, $00A6)
+ DSP4_READ_WORD();
+ DSP4_READ_WORD();
+ DSP4_READ_WORD();
+ DSP4_READ_WORD();
+
+ // unknown (constant) (ex. 1P/2P = $00A5, $00A5, $00A7, $00A7)
+ DSP4_READ_WORD();
+ DSP4_READ_WORD();
+ DSP4_READ_WORD();
+ DSP4_READ_WORD();
+
+ // polygon centering (left,right)
+ DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_cx[0][1] = DSP4_READ_WORD();
+ DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_cx[1][1] = DSP4_READ_WORD();
+
+ // HDMA pointer locations
+ DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_ptr[0][1] = DSP4_READ_WORD();
+ DSP4_vars.poly_ptr[1][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_ptr[1][1] = DSP4_READ_WORD();
+
+ // starting DSP4_vars.raster line below the horizon
+ DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_bottom[0][1] = DSP4_READ_WORD();
+ DSP4_vars.poly_bottom[1][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_bottom[1][1] = DSP4_READ_WORD();
+
+ // top boundary line to clip
+ DSP4_vars.poly_top[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_top[0][1] = DSP4_READ_WORD();
+ DSP4_vars.poly_top[1][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_top[1][1] = DSP4_READ_WORD();
+
+ // unknown
+ // (ex. 1P = $2FC8, $0034, $FF5C, $0035)
+ //
+ // (ex. 2P = $3178, $0034, $FFCC, $0035)
+ // (ex. 2P = $2FC8, $0034, $FFCC, $0035)
+
+ DSP4_READ_WORD();
+ DSP4_READ_WORD();
+ DSP4_READ_WORD();
+ DSP4_READ_WORD();
+
+ // look at guidelines for both polygon shapes
+ DSP4_vars.distance = DSP4_READ_WORD();
+ view_x[0] = DSP4_READ_WORD();
+ view_y[0] = DSP4_READ_WORD();
+ view_x[1] = DSP4_READ_WORD();
+ view_y[1] = DSP4_READ_WORD();
+
+ // envelope shaping guidelines (one frame only)
+ envelope[0][0] = DSP4_READ_WORD();
+ envelope[0][1] = DSP4_READ_WORD();
+ envelope[1][0] = DSP4_READ_WORD();
+ envelope[1][1] = DSP4_READ_WORD();
+
+ // starting base values to project from
+ DSP4_vars.poly_start[0] = view_x[0];
+ DSP4_vars.poly_start[1] = view_x[1];
+
+ // starting DSP4_vars.raster lines to begin drawing
+ DSP4_vars.poly_raster[0][0] = view_y[0];
+ DSP4_vars.poly_raster[0][1] = view_y[0];
+ DSP4_vars.poly_raster[1][0] = view_y[1];
+ DSP4_vars.poly_raster[1][1] = view_y[1];
+
+ // starting distances
+ DSP4_vars.poly_plane[0] = DSP4_vars.distance;
+ DSP4_vars.poly_plane[1] = DSP4_vars.distance;
+
+ // SR = 0x00
+
+ // re-center coordinates
+ win_left = DSP4_vars.poly_cx[0][0] - view_x[0] + envelope[0][0];
+ win_right = DSP4_vars.poly_cx[0][1] - view_x[0] + envelope[0][1];
+
+ // saturate offscreen data for polygon #1
+ if (win_left < DSP4_vars.poly_clipLf[0][0])
+ {
+ win_left = DSP4_vars.poly_clipLf[0][0];
+ }
+ if (win_left > DSP4_vars.poly_clipRt[0][0])
+ {
+ win_left = DSP4_vars.poly_clipRt[0][0];
+ }
+ if (win_right < DSP4_vars.poly_clipLf[0][1])
+ {
+ win_right = DSP4_vars.poly_clipLf[0][1];
+ }
+ if (win_right > DSP4_vars.poly_clipRt[0][1])
+ {
+ win_right = DSP4_vars.poly_clipRt[0][1];
+ }
+
+ // SR = 0x80
+
+ // initial output for polygon #1
+ DSP4_CLEAR_OUT();
+ DSP4_WRITE_BYTE(win_left & 0xff);
+ DSP4_WRITE_BYTE(win_right & 0xff);
+
+
+ do
+ {
+ int16 polygon;
+ ////////////////////////////////////////////////////
+ // command check
+
+ // scan next command
+ DSP4.in_count = 2;
+ DSP4_WAIT(1) resume1 :
+
+ // terminate op
+ DSP4_vars.distance = DSP4_READ_WORD();
+ if (DSP4_vars.distance == -0x8000)
+ break;
+
+ // already have 2 bytes in queue
+ DSP4.in_count = 16;
+
+ DSP4_WAIT(2) resume2 :
+
+ // look at guidelines for both polygon shapes
+ view_x[0] = DSP4_READ_WORD();
+ view_y[0] = DSP4_READ_WORD();
+ view_x[1] = DSP4_READ_WORD();
+ view_y[1] = DSP4_READ_WORD();
+
+ // envelope shaping guidelines (one frame only)
+ envelope[0][0] = DSP4_READ_WORD();
+ envelope[0][1] = DSP4_READ_WORD();
+ envelope[1][0] = DSP4_READ_WORD();
+ envelope[1][1] = DSP4_READ_WORD();
+
+ ////////////////////////////////////////////////////
+ // projection begins
+
+ // init
+ DSP4_CLEAR_OUT();
+
+
+ //////////////////////////////////////////////
+ // solid polygon renderer - 2 shapes
+
+ for (polygon = 0; polygon < 2; polygon++)
+ {
+ int32 left_inc, right_inc;
+ int16 x1_final, x2_final;
+ int16 env[2][2];
+ int16 poly;
+
+ // SR = 0x00
+
+ // # DSP4_vars.raster lines to draw
+ DSP4_vars.segments = DSP4_vars.poly_raster[polygon][0] - view_y[polygon];
+
+ // prevent overdraw
+ if (DSP4_vars.segments > 0)
+ {
+ // bump drawing cursor
+ DSP4_vars.poly_raster[polygon][0] = view_y[polygon];
+ DSP4_vars.poly_raster[polygon][1] = view_y[polygon];
+ }
+ else
+ DSP4_vars.segments = 0;
+
+ // don't draw outside the window
+ if (view_y[polygon] < DSP4_vars.poly_top[polygon][0])
+ {
+ DSP4_vars.segments = 0;
+
+ // flush remaining DSP4_vars.raster lines
+ if (view_y[polygon] >= DSP4_vars.poly_top[polygon][0])
+ DSP4_vars.segments = view_y[polygon] - DSP4_vars.poly_top[polygon][0];
+ }
+
+ // SR = 0x80
+
+ // tell user how many DSP4_vars.raster structures to read in
+ DSP4_WRITE_WORD(DSP4_vars.segments);
+
+ // normal parameters
+ poly = polygon;
+
+ /////////////////////////////////////////////////////
+
+ // scan next command if no SR check needed
+ if (DSP4_vars.segments)
+ {
+ int32 win_left, win_right;
+
+ // road turnoff selection
+ if( (uint16) envelope[ polygon ][ 0 ] == (uint16) 0xc001 )
+ poly = 1;
+ else if( envelope[ polygon ][ 1 ] == 0x3fff )
+ poly = 1;
+
+ ///////////////////////////////////////////////
+ // left side of polygon
+
+ // perspective correction on additional shaping parameters
+ env[0][0] = envelope[polygon][0] * DSP4_vars.poly_plane[poly] >> 15;
+ env[0][1] = envelope[polygon][0] * DSP4_vars.distance >> 15;
+
+ // project new shapes (left side)
+ x1_final = view_x[poly] + env[0][0];
+ x2_final = DSP4_vars.poly_start[poly] + env[0][1];
+
+ // interpolate between projected points with shaping
+ left_inc = (x2_final - x1_final) * DSP4_Inverse(DSP4_vars.segments) << 1;
+ if (DSP4_vars.segments == 1)
+ left_inc = -left_inc;
+
+ ///////////////////////////////////////////////
+ // right side of polygon
+
+ // perspective correction on additional shaping parameters
+ env[1][0] = envelope[polygon][1] * DSP4_vars.poly_plane[poly] >> 15;;
+ env[1][1] = envelope[polygon][1] * DSP4_vars.distance >> 15;
+
+ // project new shapes (right side)
+ x1_final = view_x[poly] + env[1][0];
+ x2_final = DSP4_vars.poly_start[poly] + env[1][1];
+
+
+ // interpolate between projected points with shaping
+ right_inc = (x2_final - x1_final) * DSP4_Inverse(DSP4_vars.segments) << 1;
+ if (DSP4_vars.segments == 1)
+ right_inc = -right_inc;
+
+ ///////////////////////////////////////////////
+ // update each point on the line
+
+ win_left = SEX16(DSP4_vars.poly_cx[polygon][0] - DSP4_vars.poly_start[poly] + env[0][0]);
+ win_right = SEX16(DSP4_vars.poly_cx[polygon][1] - DSP4_vars.poly_start[poly] + env[1][0]);
+
+ // update DSP4_vars.distance drawn into world
+ DSP4_vars.poly_plane[polygon] = DSP4_vars.distance;
+
+ // rasterize line
+ for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++)
+ {
+ int16 x_left, x_right;
+
+ // project new coordinates
+ win_left += left_inc;
+ win_right += right_inc;
+
+ // grab integer portion, drop fraction (no rounding)
+ x_left = (int16)(win_left >> 16);
+ x_right = (int16)(win_right >> 16);
+
+ // saturate offscreen data
+ if (x_left < DSP4_vars.poly_clipLf[polygon][0])
+ x_left = DSP4_vars.poly_clipLf[polygon][0];
+ if (x_left > DSP4_vars.poly_clipRt[polygon][0])
+ x_left = DSP4_vars.poly_clipRt[polygon][0];
+ if (x_right < DSP4_vars.poly_clipLf[polygon][1])
+ x_right = DSP4_vars.poly_clipLf[polygon][1];
+ if (x_right > DSP4_vars.poly_clipRt[polygon][1])
+ x_right = DSP4_vars.poly_clipRt[polygon][1];
+
+ // 1. HDMA memory pointer
+ // 2. Left window position ($2126/$2128)
+ // 3. Right window position ($2127/$2129)
+
+ DSP4_WRITE_WORD(DSP4_vars.poly_ptr[polygon][0]);
+ DSP4_WRITE_BYTE(x_left & 0xff);
+ DSP4_WRITE_BYTE(x_right & 0xff);
+
+
+ // update memory pointers
+ DSP4_vars.poly_ptr[polygon][0] -= 4;
+ DSP4_vars.poly_ptr[polygon][1] -= 4;
+ } // end rasterize line
+ }
+
+ ////////////////////////////////////////////////
+ // Post-update
+
+ // new projection spot to continue rasterizing from
+ DSP4_vars.poly_start[polygon] = view_x[poly];
+ } // end polygon rasterizer
+ }
+ while (1);
+
+ // unknown output
+ DSP4_CLEAR_OUT();
+ DSP4_WRITE_WORD(0);
+
+
+ DSP4.waiting4command = TRUE;
+}
+
+//////////////////////////////////////////////////////////////
+
+void DSP4_OP09()
+{
+ DSP4.waiting4command = FALSE;
+
+ // op flow control
+ switch (DSP4_vars.DSP4_Logic)
+ {
+ case 1:
+ goto resume1; break;
+ case 2:
+ goto resume2; break;
+ case 3:
+ goto resume3; break;
+ case 4:
+ goto resume4; break;
+ case 5:
+ goto resume5; break;
+ case 6:
+ goto resume6; break;
+ }
+
+ ////////////////////////////////////////////////////
+ // process initial inputs
+
+ // grab screen information
+ DSP4_vars.viewport_cx = DSP4_READ_WORD();
+ DSP4_vars.viewport_cy = DSP4_READ_WORD();
+ DSP4_READ_WORD(); // 0x0000
+ DSP4_vars.viewport_left = DSP4_READ_WORD();
+ DSP4_vars.viewport_right = DSP4_READ_WORD();
+ DSP4_vars.viewport_top = DSP4_READ_WORD();
+ DSP4_vars.viewport_bottom = DSP4_READ_WORD();
+
+ // starting DSP4_vars.raster line below the horizon
+ DSP4_vars.poly_bottom[0][0] = DSP4_vars.viewport_bottom - DSP4_vars.viewport_cy;
+ DSP4_vars.poly_raster[0][0] = 0x100;
+
+ do
+ {
+ ////////////////////////////////////////////////////
+ // check for new sprites
+
+ DSP4.in_count = 4;
+ DSP4_WAIT(1) resume1 :
+
+ ////////////////////////////////////////////////
+ // DSP4_vars.raster overdraw check
+
+ DSP4_vars.raster = DSP4_READ_WORD();
+
+ // continue updating the DSP4_vars.raster line where overdraw begins
+ if (DSP4_vars.raster < DSP4_vars.poly_raster[0][0])
+ {
+ DSP4_vars.sprite_clipy = DSP4_vars.viewport_bottom - (DSP4_vars.poly_bottom[0][0] - DSP4_vars.raster);
+ DSP4_vars.poly_raster[0][0] = DSP4_vars.raster;
+ }
+
+ /////////////////////////////////////////////////
+ // identify sprite
+
+ // op termination
+ DSP4_vars.distance = DSP4_READ_WORD();
+ if (DSP4_vars.distance == -0x8000)
+ goto terminate;
+
+
+ // no sprite
+ if (DSP4_vars.distance == 0x0000)
+ {
+ continue;
+ }
+
+ ////////////////////////////////////////////////////
+ // process projection information
+
+ // vehicle sprite
+ if ((uint16) DSP4_vars.distance == 0x9000)
+ {
+ int16 car_left, car_right, car_back;
+ int16 impact_left, impact_back;
+ int16 world_spx, world_spy;
+ int16 view_spx, view_spy;
+ uint16 energy;
+
+ // we already have 4 bytes we want
+ DSP4.in_count = 14;
+ DSP4_WAIT(2) resume2 :
+
+ // filter inputs
+ energy = DSP4_READ_WORD();
+ impact_back = DSP4_READ_WORD();
+ car_back = DSP4_READ_WORD();
+ impact_left = DSP4_READ_WORD();
+ car_left = DSP4_READ_WORD();
+ DSP4_vars.distance = DSP4_READ_WORD();
+ car_right = DSP4_READ_WORD();
+
+ // calculate car's world (x,y) values
+ world_spx = car_right - car_left;
+ world_spy = car_back;
+
+ // add in collision vector [needs bit-twiddling]
+ world_spx -= energy * (impact_left - car_left) >> 16;
+ world_spy -= energy * (car_back - impact_back) >> 16;
+
+ // perspective correction for world (x,y)
+ view_spx = world_spx * DSP4_vars.distance >> 15;
+ view_spy = world_spy * DSP4_vars.distance >> 15;
+
+ // convert to screen values
+ DSP4_vars.sprite_x = DSP4_vars.viewport_cx + view_spx;
+ DSP4_vars.sprite_y = DSP4_vars.viewport_bottom - (DSP4_vars.poly_bottom[0][0] - view_spy);
+
+ // make the car's (x)-coordinate available
+ DSP4_CLEAR_OUT();
+ DSP4_WRITE_WORD(world_spx);
+
+ // grab a few remaining vehicle values
+ DSP4.in_count = 4;
+ DSP4_WAIT(3) resume3 :
+
+ // add vertical lift factor
+ DSP4_vars.sprite_y += DSP4_READ_WORD();
+ }
+ // terrain sprite
+ else
+ {
+ int16 world_spx, world_spy;
+ int16 view_spx, view_spy;
+
+ // we already have 4 bytes we want
+ DSP4.in_count = 10;
+ DSP4_WAIT(4) resume4 :
+
+ // sort loop inputs
+ DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_raster[0][1] = DSP4_READ_WORD();
+ world_spx = DSP4_READ_WORD();
+ world_spy = DSP4_READ_WORD();
+
+ // compute base DSP4_vars.raster line from the bottom
+ DSP4_vars.segments = DSP4_vars.poly_bottom[0][0] - DSP4_vars.raster;
+
+ // perspective correction for world (x,y)
+ view_spx = world_spx * DSP4_vars.distance >> 15;
+ view_spy = world_spy * DSP4_vars.distance >> 15;
+
+ // convert to screen values
+ DSP4_vars.sprite_x = DSP4_vars.viewport_cx + view_spx - DSP4_vars.poly_cx[0][0];
+ DSP4_vars.sprite_y = DSP4_vars.viewport_bottom - DSP4_vars.segments + view_spy;
+ }
+
+ // default sprite size: 16x16
+ DSP4_vars.sprite_size = 1;
+ DSP4_vars.sprite_attr = DSP4_READ_WORD();
+
+ ////////////////////////////////////////////////////
+ // convert tile data to SNES OAM format
+
+ do
+ {
+ uint16 header;
+
+ int16 sp_x, sp_y, sp_attr, sp_dattr;
+ int16 sp_dx, sp_dy;
+ int16 pixels;
+
+ bool8 draw;
+
+ DSP4.in_count = 2;
+ DSP4_WAIT(5) resume5 :
+
+ draw = TRUE;
+
+ // opcode termination
+ DSP4_vars.raster = DSP4_READ_WORD();
+ if (DSP4_vars.raster == -0x8000)
+ goto terminate;
+
+ // stop code
+ if (DSP4_vars.raster == 0x0000 && !DSP4_vars.sprite_size)
+ break;
+
+ // toggle sprite size
+ if (DSP4_vars.raster == 0x0000)
+ {
+ DSP4_vars.sprite_size = !DSP4_vars.sprite_size;
+ continue;
+ }
+
+ // check for valid sprite header
+ header = DSP4_vars.raster;
+ header >>= 8;
+ if (header != 0x20 &&
+ header != 0x2e && //This is for attractor sprite
+ header != 0x40 &&
+ header != 0x60 &&
+ header != 0xa0 &&
+ header != 0xc0 &&
+ header != 0xe0)
+ break;
+
+ // read in rest of sprite data
+ DSP4.in_count = 4;
+ DSP4_WAIT(6) resume6 :
+
+ draw = TRUE;
+
+ /////////////////////////////////////
+ // process tile data
+
+ // sprite deltas
+ sp_dattr = DSP4_vars.raster;
+ sp_dy = DSP4_READ_WORD();
+ sp_dx = DSP4_READ_WORD();
+
+ // update coordinates to screen space
+ sp_x = DSP4_vars.sprite_x + sp_dx;
+ sp_y = DSP4_vars.sprite_y + sp_dy;
+
+ // update sprite nametable/attribute information
+ sp_attr = DSP4_vars.sprite_attr + sp_dattr;
+
+ // allow partially visibile tiles
+ pixels = DSP4_vars.sprite_size ? 15 : 7;
+
+ DSP4_CLEAR_OUT();
+
+ // transparent tile to clip off parts of a sprite (overdraw)
+ if (DSP4_vars.sprite_clipy - pixels <= sp_y &&
+ sp_y <= DSP4_vars.sprite_clipy &&
+ sp_x >= DSP4_vars.viewport_left - pixels &&
+ sp_x <= DSP4_vars.viewport_right &&
+ DSP4_vars.sprite_clipy >= DSP4_vars.viewport_top - pixels &&
+ DSP4_vars.sprite_clipy <= DSP4_vars.viewport_bottom)
+ {
+ DSP4_OP0B(&draw, sp_x, DSP4_vars.sprite_clipy, 0x00EE, DSP4_vars.sprite_size, 0);
+ }
+
+
+ // normal sprite tile
+ if (sp_x >= DSP4_vars.viewport_left - pixels &&
+ sp_x <= DSP4_vars.viewport_right &&
+ sp_y >= DSP4_vars.viewport_top - pixels &&
+ sp_y <= DSP4_vars.viewport_bottom &&
+ sp_y <= DSP4_vars.sprite_clipy)
+ {
+ DSP4_OP0B(&draw, sp_x, sp_y, sp_attr, DSP4_vars.sprite_size, 0);
+ }
+
+
+ // no following OAM data
+ DSP4_OP0B(&draw, 0, 0x0100, 0, 0, 1);
+ }
+ while (1);
+ }
+ while (1);
+
+ terminate : DSP4.waiting4command = TRUE;
+}
+
+//////////////////////////////////////////////////////////////
+
+const uint16 OP0A_Values[16] = { 0x0000, 0x0030, 0x0060, 0x0090, 0x00c0, 0x00f0, 0x0120, 0x0150, 0xfe80,
+ 0xfeb0, 0xfee0, 0xff10, 0xff40, 0xff70, 0xffa0, 0xffd0 };
+
+void DSP4_OP0A(int16 n2, int16 *o1, int16 *o2, int16 *o3, int16 *o4)
+{
+ *o4 = OP0A_Values[(n2 & 0x000f)];
+ *o3 = OP0A_Values[(n2 & 0x00f0) >> 4];
+ *o2 = OP0A_Values[(n2 & 0x0f00) >> 8];
+ *o1 = OP0A_Values[(n2 & 0xf000) >> 12];
+}
+
+//////////////////////////////////////////////////////////////
+
+void DSP4_OP0B(bool8 *draw, int16 sp_x, int16 sp_y, int16 sp_attr, bool8 size, bool8 stop)
+{
+ int16 Row1, Row2;
+
+ // SR = 0x00
+
+ // align to nearest 8-pixel row
+ Row1 = (sp_y >> 3) & 0x1f;
+ Row2 = (Row1 + 1) & 0x1f;
+
+ // check boundaries
+ if (!((sp_y < 0) || ((sp_y & 0x01ff) < 0x00eb)))
+ {
+ *draw = 0;
+ }
+ if (size)
+ {
+ if (DSP4_vars.OAM_Row[Row1] + 1 >= DSP4_vars.OAM_RowMax)
+ *draw = 0;
+ if (DSP4_vars.OAM_Row[Row2] + 1 >= DSP4_vars.OAM_RowMax)
+ *draw = 0;
+ }
+ else
+ {
+ if (DSP4_vars.OAM_Row[Row1] >= DSP4_vars.OAM_RowMax)
+ {
+ *draw = 0;
+ }
+ }
+
+ // emulator fail-safe (unknown if this really exists)
+ if (DSP4_vars.sprite_count >= 128)
+ {
+ *draw = 0;
+ }
+
+ // SR = 0x80
+
+ if (*draw)
+ {
+ // Row tiles
+ if (size)
+ {
+ DSP4_vars.OAM_Row[Row1] += 2;
+ DSP4_vars.OAM_Row[Row2] += 2;
+ }
+ else
+ {
+ DSP4_vars.OAM_Row[Row1]++;
+ }
+
+ // yield OAM output
+ DSP4_WRITE_WORD(1);
+
+ // pack OAM data: x,y,name,attr
+ DSP4_WRITE_BYTE(sp_x & 0xff);
+ DSP4_WRITE_BYTE(sp_y & 0xff);
+ DSP4_WRITE_WORD(sp_attr);
+
+ DSP4_vars.sprite_count++;
+
+ // OAM: size,msb data
+ // save post-oam table data for future retrieval
+ DSP4_vars.OAM_attr[DSP4_vars.OAM_index] |= ((sp_x <0 || sp_x> 255) << DSP4_vars.OAM_bits);
+ DSP4_vars.OAM_bits++;
+
+ DSP4_vars.OAM_attr[DSP4_vars.OAM_index] |= (size << DSP4_vars.OAM_bits);
+ DSP4_vars.OAM_bits++;
+
+ // move to next byte in buffer
+ if (DSP4_vars.OAM_bits == 16)
+ {
+ DSP4_vars.OAM_bits = 0;
+ DSP4_vars.OAM_index++;
+ }
+ }
+ else if (stop)
+ {
+ // yield no OAM output
+ DSP4_WRITE_WORD(0);
+ }
+}
+
+//////////////////////////////////////////////////////////////
+
+void DSP4_OP0D()
+{
+ DSP4.waiting4command = FALSE;
+
+ // op flow control
+ switch (DSP4_vars.DSP4_Logic)
+ {
+ case 1:
+ goto resume1; break;
+ case 2:
+ goto resume2; break;
+ }
+
+ ////////////////////////////////////////////////////
+ // process initial inputs
+
+ // sort inputs
+ DSP4_vars.world_y = DSP4_READ_DWORD();
+ DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_top[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD();
+ DSP4_vars.viewport_bottom = DSP4_READ_WORD();
+ DSP4_vars.world_x = DSP4_READ_DWORD();
+ DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD();
+ DSP4_vars.world_yofs = DSP4_READ_WORD();
+ DSP4_vars.world_dy = DSP4_READ_DWORD();
+ DSP4_vars.world_dx = DSP4_READ_DWORD();
+ DSP4_vars.distance = DSP4_READ_WORD();
+ DSP4_READ_WORD(); // 0x0000
+ DSP4_vars.world_xenv = SEX78(DSP4_READ_WORD());
+ DSP4_vars.world_ddy = DSP4_READ_WORD();
+ DSP4_vars.world_ddx = DSP4_READ_WORD();
+ DSP4_vars.view_yofsenv = DSP4_READ_WORD();
+
+ // initial (x,y,offset) at starting DSP4_vars.raster line
+ DSP4_vars.view_x1 = (int16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16);
+ DSP4_vars.view_y1 = (int16)(DSP4_vars.world_y >> 16);
+ DSP4_vars.view_xofs1 = (int16)(DSP4_vars.world_x >> 16);
+ DSP4_vars.view_yofs1 = DSP4_vars.world_yofs;
+
+ // first DSP4_vars.raster line
+ DSP4_vars.poly_raster[0][0] = DSP4_vars.poly_bottom[0][0];
+
+
+ do
+ {
+ ////////////////////////////////////////////////////
+ // process one iteration of projection
+
+ // perspective projection of world (x,y,scroll) points
+ // based on the current projection lines
+ DSP4_vars.view_x2 = (int16)(( ( ( DSP4_vars.world_x + DSP4_vars.world_xenv ) >> 16 ) * DSP4_vars.distance >> 15 ) + ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 ));
+ DSP4_vars.view_y2 = (int16)((DSP4_vars.world_y >> 16) * DSP4_vars.distance >> 15);
+ DSP4_vars.view_xofs2 = DSP4_vars.view_x2;
+ DSP4_vars.view_yofs2 = (DSP4_vars.world_yofs * DSP4_vars.distance >> 15) + DSP4_vars.poly_bottom[0][0] - DSP4_vars.view_y2;
+
+ // 1. World x-location before transformation
+ // 2. Viewer x-position at the current
+ // 3. World y-location before perspective projection
+ // 4. Viewer y-position below the horizon
+ // 5. Number of DSP4_vars.raster lines drawn in this iteration
+
+ DSP4_CLEAR_OUT();
+ DSP4_WRITE_WORD((uint16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16));
+ DSP4_WRITE_WORD(DSP4_vars.view_x2);
+ DSP4_WRITE_WORD((uint16)(DSP4_vars.world_y >> 16));
+ DSP4_WRITE_WORD(DSP4_vars.view_y2);
+
+ //////////////////////////////////////////////////////////
+
+ // SR = 0x00
+
+ // determine # of DSP4_vars.raster lines used
+ DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.view_y2;
+
+ // prevent overdraw
+ if (DSP4_vars.view_y2 >= DSP4_vars.poly_raster[0][0])
+ DSP4_vars.segments = 0;
+ else
+ DSP4_vars.poly_raster[0][0] = DSP4_vars.view_y2;
+
+ // don't draw outside the window
+ if (DSP4_vars.view_y2 < DSP4_vars.poly_top[0][0])
+ {
+ DSP4_vars.segments = 0;
+
+ // flush remaining DSP4_vars.raster lines
+ if (DSP4_vars.view_y1 >= DSP4_vars.poly_top[0][0])
+ DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.poly_top[0][0];
+ }
+
+ // SR = 0x80
+
+ DSP4_WRITE_WORD(DSP4_vars.segments);
+
+ //////////////////////////////////////////////////////////
+
+ // scan next command if no SR check needed
+ if (DSP4_vars.segments)
+ {
+ int32 px_dx, py_dy;
+ int32 x_scroll, y_scroll;
+
+ // SR = 0x00
+
+ // linear interpolation (lerp) between projected points
+ px_dx = (DSP4_vars.view_xofs2 - DSP4_vars.view_xofs1) * DSP4_Inverse(DSP4_vars.segments) << 1;
+ py_dy = (DSP4_vars.view_yofs2 - DSP4_vars.view_yofs1) * DSP4_Inverse(DSP4_vars.segments) << 1;
+
+ // starting step values
+ x_scroll = SEX16(DSP4_vars.poly_cx[0][0] + DSP4_vars.view_xofs1);
+ y_scroll = SEX16(-DSP4_vars.viewport_bottom + DSP4_vars.view_yofs1 + DSP4_vars.view_yofsenv + DSP4_vars.poly_cx[1][0] - DSP4_vars.world_yofs);
+
+ // SR = 0x80
+
+ // rasterize line
+ for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++)
+ {
+ // 1. HDMA memory pointer (bg1)
+ // 2. vertical scroll offset ($210E)
+ // 3. horizontal scroll offset ($210D)
+
+ DSP4_WRITE_WORD(DSP4_vars.poly_ptr[0][0]);
+ DSP4_WRITE_WORD((uint16)((y_scroll + 0x8000) >> 16));
+ DSP4_WRITE_WORD((uint16)((x_scroll + 0x8000) >> 16));
+
+
+ // update memory address
+ DSP4_vars.poly_ptr[0][0] -= 4;
+
+ // update screen values
+ x_scroll += px_dx;
+ y_scroll += py_dy;
+ }
+ }
+
+ /////////////////////////////////////////////////////
+ // Post-update
+
+ // update new viewer (x,y,scroll) to last DSP4_vars.raster line drawn
+ DSP4_vars.view_x1 = DSP4_vars.view_x2;
+ DSP4_vars.view_y1 = DSP4_vars.view_y2;
+ DSP4_vars.view_xofs1 = DSP4_vars.view_xofs2;
+ DSP4_vars.view_yofs1 = DSP4_vars.view_yofs2;
+
+ // add deltas for projection lines
+ DSP4_vars.world_dx += SEX78(DSP4_vars.world_ddx);
+ DSP4_vars.world_dy += SEX78(DSP4_vars.world_ddy);
+
+ // update projection lines
+ DSP4_vars.world_x += (DSP4_vars.world_dx + DSP4_vars.world_xenv);
+ DSP4_vars.world_y += DSP4_vars.world_dy;
+
+ ////////////////////////////////////////////////////
+ // command check
+
+ // scan next command
+ DSP4.in_count = 2;
+ DSP4_WAIT(1) resume1 :
+
+ // inspect input
+ DSP4_vars.distance = DSP4_READ_WORD();
+
+ // terminate op
+ if (DSP4_vars.distance == -0x8000)
+ break;
+
+ // already have 2 bytes in queue
+ DSP4.in_count = 6;
+ DSP4_WAIT(2) resume2:
+
+ // inspect inputs
+ DSP4_vars.world_ddy = DSP4_READ_WORD();
+ DSP4_vars.world_ddx = DSP4_READ_WORD();
+ DSP4_vars.view_yofsenv = DSP4_READ_WORD();
+
+ // no envelope here
+ DSP4_vars.world_xenv = 0;
+ }
+ while (1);
+
+ DSP4.waiting4command = TRUE;
+}
+
+//////////////////////////////////////////////////////////////
+
+
+void DSP4_OP0E()
+{
+ DSP4_vars.OAM_RowMax = 16;
+ memset(DSP4_vars.OAM_Row, 0, 64);
+}
+
+
+//////////////////////////////////////////////////////////////
+
+void DSP4_OP0F()
+{
+ DSP4.waiting4command = FALSE;
+
+ // op flow control
+ switch (DSP4_vars.DSP4_Logic)
+ {
+ case 1:
+ goto resume1; break;
+ case 2:
+ goto resume2; break;
+ case 3:
+ goto resume3; break;
+ case 4:
+ goto resume4; break;
+ }
+
+ ////////////////////////////////////////////////////
+ // process initial inputs
+
+ // sort inputs
+ DSP4_READ_WORD(); // 0x0000
+ DSP4_vars.world_y = DSP4_READ_DWORD();
+ DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_top[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD();
+ DSP4_vars.viewport_bottom = DSP4_READ_WORD();
+ DSP4_vars.world_x = DSP4_READ_DWORD();
+ DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD();
+ DSP4_vars.world_yofs = DSP4_READ_WORD();
+ DSP4_vars.world_dy = DSP4_READ_DWORD();
+ DSP4_vars.world_dx = DSP4_READ_DWORD();
+ DSP4_vars.distance = DSP4_READ_WORD();
+ DSP4_READ_WORD(); // 0x0000
+ DSP4_vars.world_xenv = DSP4_READ_DWORD();
+ DSP4_vars.world_ddy = DSP4_READ_WORD();
+ DSP4_vars.world_ddx = DSP4_READ_WORD();
+ DSP4_vars.view_yofsenv = DSP4_READ_WORD();
+
+ // initial (x,y,offset) at starting DSP4_vars.raster line
+ DSP4_vars.view_x1 = (int16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16);
+ DSP4_vars.view_y1 = (int16)(DSP4_vars.world_y >> 16);
+ DSP4_vars.view_xofs1 = (int16)(DSP4_vars.world_x >> 16);
+ DSP4_vars.view_yofs1 = DSP4_vars.world_yofs;
+ DSP4_vars.view_turnoff_x = 0;
+ DSP4_vars.view_turnoff_dx = 0;
+
+ // first DSP4_vars.raster line
+ DSP4_vars.poly_raster[0][0] = DSP4_vars.poly_bottom[0][0];
+
+
+ do
+ {
+ ////////////////////////////////////////////////////
+ // process one iteration of projection
+
+ // perspective projection of world (x,y,scroll) points
+ // based on the current projection lines
+ DSP4_vars.view_x2 = (int16)(((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16) * DSP4_vars.distance >> 15);
+ DSP4_vars.view_y2 = (int16)((DSP4_vars.world_y >> 16) * DSP4_vars.distance >> 15);
+ DSP4_vars.view_xofs2 = DSP4_vars.view_x2;
+ DSP4_vars.view_yofs2 = (DSP4_vars.world_yofs * DSP4_vars.distance >> 15) + DSP4_vars.poly_bottom[0][0] - DSP4_vars.view_y2;
+
+ // 1. World x-location before transformation
+ // 2. Viewer x-position at the next
+ // 3. World y-location before perspective projection
+ // 4. Viewer y-position below the horizon
+ // 5. Number of DSP4_vars.raster lines drawn in this iteration
+
+ DSP4_CLEAR_OUT();
+ DSP4_WRITE_WORD((uint16)((DSP4_vars.world_x + DSP4_vars.world_xenv) >> 16));
+ DSP4_WRITE_WORD(DSP4_vars.view_x2);
+ DSP4_WRITE_WORD((uint16)(DSP4_vars.world_y >> 16));
+ DSP4_WRITE_WORD(DSP4_vars.view_y2);
+
+ //////////////////////////////////////////////////////
+
+ // SR = 0x00
+
+ // determine # of DSP4_vars.raster lines used
+ DSP4_vars.segments = DSP4_vars.poly_raster[0][0] - DSP4_vars.view_y2;
+
+ // prevent overdraw
+ if (DSP4_vars.view_y2 >= DSP4_vars.poly_raster[0][0])
+ DSP4_vars.segments = 0;
+ else
+ DSP4_vars.poly_raster[0][0] = DSP4_vars.view_y2;
+
+ // don't draw outside the window
+ if (DSP4_vars.view_y2 < DSP4_vars.poly_top[0][0])
+ {
+ DSP4_vars.segments = 0;
+
+ // flush remaining DSP4_vars.raster lines
+ if (DSP4_vars.view_y1 >= DSP4_vars.poly_top[0][0])
+ DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.poly_top[0][0];
+ }
+
+ // SR = 0x80
+
+ DSP4_WRITE_WORD(DSP4_vars.segments);
+
+ //////////////////////////////////////////////////////
+
+ // scan next command if no SR check needed
+ if (DSP4_vars.segments)
+ {
+ int32 px_dx, py_dy;
+ int32 x_scroll, y_scroll;
+
+ for (DSP4_vars.lcv = 0; DSP4_vars.lcv < 4; DSP4_vars.lcv++)
+ {
+ // grab inputs
+ DSP4.in_count = 4;
+ DSP4_WAIT(1);
+ resume1 :
+ for (;;)
+ {
+ int16 distance;
+ int16 color, red, green, blue;
+
+ distance = DSP4_READ_WORD();
+ color = DSP4_READ_WORD();
+
+ // U1+B5+G5+R5
+ red = color & 0x1f;
+ green = (color >> 5) & 0x1f;
+ blue = (color >> 10) & 0x1f;
+
+ // dynamic lighting
+ red = (red * distance >> 15) & 0x1f;
+ green = (green * distance >> 15) & 0x1f;
+ blue = (blue * distance >> 15) & 0x1f;
+ color = red | (green << 5) | (blue << 10);
+
+ DSP4_CLEAR_OUT();
+ DSP4_WRITE_WORD(color);
+ break;
+ }
+ }
+
+ //////////////////////////////////////////////////////
+
+ // SR = 0x00
+
+ // linear interpolation (lerp) between projected points
+ px_dx = (DSP4_vars.view_xofs2 - DSP4_vars.view_xofs1) * DSP4_Inverse(DSP4_vars.segments) << 1;
+ py_dy = (DSP4_vars.view_yofs2 - DSP4_vars.view_yofs1) * DSP4_Inverse(DSP4_vars.segments) << 1;
+
+
+ // starting step values
+ x_scroll = SEX16(DSP4_vars.poly_cx[0][0] + DSP4_vars.view_xofs1);
+ y_scroll = SEX16(-DSP4_vars.viewport_bottom + DSP4_vars.view_yofs1 + DSP4_vars.view_yofsenv + DSP4_vars.poly_cx[1][0] - DSP4_vars.world_yofs);
+
+ // SR = 0x80
+
+ // rasterize line
+ for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++)
+ {
+ // 1. HDMA memory pointer
+ // 2. vertical scroll offset ($210E)
+ // 3. horizontal scroll offset ($210D)
+
+ DSP4_WRITE_WORD(DSP4_vars.poly_ptr[0][0]);
+ DSP4_WRITE_WORD((uint16)((y_scroll + 0x8000) >> 16));
+ DSP4_WRITE_WORD((uint16)((x_scroll + 0x8000) >> 16));
+
+ // update memory address
+ DSP4_vars.poly_ptr[0][0] -= 4;
+
+ // update screen values
+ x_scroll += px_dx;
+ y_scroll += py_dy;
+ }
+ }
+
+ ////////////////////////////////////////////////////
+ // Post-update
+
+ // update new viewer (x,y,scroll) to last DSP4_vars.raster line drawn
+ DSP4_vars.view_x1 = DSP4_vars.view_x2;
+ DSP4_vars.view_y1 = DSP4_vars.view_y2;
+ DSP4_vars.view_xofs1 = DSP4_vars.view_xofs2;
+ DSP4_vars.view_yofs1 = DSP4_vars.view_yofs2;
+
+ // add deltas for projection lines
+ DSP4_vars.world_dx += SEX78(DSP4_vars.world_ddx);
+ DSP4_vars.world_dy += SEX78(DSP4_vars.world_ddy);
+
+ // update projection lines
+ DSP4_vars.world_x += (DSP4_vars.world_dx + DSP4_vars.world_xenv);
+ DSP4_vars.world_y += DSP4_vars.world_dy;
+
+ // update road turnoff position
+ DSP4_vars.view_turnoff_x += DSP4_vars.view_turnoff_dx;
+
+ ////////////////////////////////////////////////////
+ // command check
+
+ // scan next command
+ DSP4.in_count = 2;
+ DSP4_WAIT(2) resume2:
+
+ // check for termination
+ DSP4_vars.distance = DSP4_READ_WORD();
+ if (DSP4_vars.distance == -0x8000)
+ break;
+
+ // road splice
+ if( (uint16) DSP4_vars.distance == 0x8001 )
+ {
+ DSP4.in_count = 6;
+ DSP4_WAIT(3) resume3:
+
+ DSP4_vars.distance = DSP4_READ_WORD();
+ DSP4_vars.view_turnoff_x = DSP4_READ_WORD();
+ DSP4_vars.view_turnoff_dx = DSP4_READ_WORD();
+
+ // factor in new changes
+ DSP4_vars.view_x1 += ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 );
+ DSP4_vars.view_xofs1 += ( DSP4_vars.view_turnoff_x * DSP4_vars.distance >> 15 );
+
+ // update stepping values
+ DSP4_vars.view_turnoff_x += DSP4_vars.view_turnoff_dx;
+
+ DSP4.in_count = 2;
+ DSP4_WAIT(2)
+ }
+
+ // already have 2 bytes in queue
+ DSP4.in_count = 6;
+ DSP4_WAIT(4) resume4 :
+
+ // inspect inputs
+ DSP4_vars.world_ddy = DSP4_READ_WORD();
+ DSP4_vars.world_ddx = DSP4_READ_WORD();
+ DSP4_vars.view_yofsenv = DSP4_READ_WORD();
+
+ // no envelope here
+ DSP4_vars.world_xenv = 0;
+ }
+ while (1);
+
+ // terminate op
+ DSP4.waiting4command = TRUE;
+}
+
+//////////////////////////////////////////////////////////////
+
+
+void DSP4_OP10()
+{
+ DSP4.waiting4command = FALSE;
+
+ // op flow control
+ switch (DSP4_vars.DSP4_Logic)
+ {
+ case 1:
+ goto resume1; break;
+ case 2:
+ goto resume2; break;
+ case 3:
+ goto resume3; break;
+ }
+
+ ////////////////////////////////////////////////////
+ // sort inputs
+
+ DSP4_READ_WORD(); // 0x0000
+ DSP4_vars.world_y = DSP4_READ_DWORD();
+ DSP4_vars.poly_bottom[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_top[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_cx[1][0] = DSP4_READ_WORD();
+ DSP4_vars.viewport_bottom = DSP4_READ_WORD();
+ DSP4_vars.world_x = DSP4_READ_DWORD();
+ DSP4_vars.poly_cx[0][0] = DSP4_READ_WORD();
+ DSP4_vars.poly_ptr[0][0] = DSP4_READ_WORD();
+ DSP4_vars.world_yofs = DSP4_READ_WORD();
+ DSP4_vars.distance = DSP4_READ_WORD();
+ DSP4_vars.view_y2 = DSP4_READ_WORD();
+ DSP4_vars.view_dy = DSP4_READ_WORD() * DSP4_vars.distance >> 15;
+ DSP4_vars.view_x2 = DSP4_READ_WORD();
+ DSP4_vars.view_dx = DSP4_READ_WORD() * DSP4_vars.distance >> 15;
+ DSP4_vars.view_yofsenv = DSP4_READ_WORD();
+
+ // initial (x,y,offset) at starting DSP4_vars.raster line
+ DSP4_vars.view_x1 = (int16)(DSP4_vars.world_x >> 16);
+ DSP4_vars.view_y1 = (int16)(DSP4_vars.world_y >> 16);
+ DSP4_vars.view_xofs1 = DSP4_vars.view_x1;
+ DSP4_vars.view_yofs1 = DSP4_vars.world_yofs;
+
+ // first DSP4_vars.raster line
+ DSP4_vars.poly_raster[0][0] = DSP4_vars.poly_bottom[0][0];
+
+ do
+ {
+ ////////////////////////////////////////////////////
+ // process one iteration of projection
+
+ // add shaping
+ DSP4_vars.view_x2 += DSP4_vars.view_dx;
+ DSP4_vars.view_y2 += DSP4_vars.view_dy;
+
+ // vertical scroll calculation
+ DSP4_vars.view_xofs2 = DSP4_vars.view_x2;
+ DSP4_vars.view_yofs2 = (DSP4_vars.world_yofs * DSP4_vars.distance >> 15) + DSP4_vars.poly_bottom[0][0] - DSP4_vars.view_y2;
+
+ // 1. Viewer x-position at the next
+ // 2. Viewer y-position below the horizon
+ // 3. Number of DSP4_vars.raster lines drawn in this iteration
+
+ DSP4_CLEAR_OUT();
+ DSP4_WRITE_WORD(DSP4_vars.view_x2);
+ DSP4_WRITE_WORD(DSP4_vars.view_y2);
+
+ //////////////////////////////////////////////////////
+
+ // SR = 0x00
+
+ // determine # of DSP4_vars.raster lines used
+ DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.view_y2;
+
+ // prevent overdraw
+ if (DSP4_vars.view_y2 >= DSP4_vars.poly_raster[0][0])
+ DSP4_vars.segments = 0;
+ else
+ DSP4_vars.poly_raster[0][0] = DSP4_vars.view_y2;
+
+ // don't draw outside the window
+ if (DSP4_vars.view_y2 < DSP4_vars.poly_top[0][0])
+ {
+ DSP4_vars.segments = 0;
+
+ // flush remaining DSP4_vars.raster lines
+ if (DSP4_vars.view_y1 >= DSP4_vars.poly_top[0][0])
+ DSP4_vars.segments = DSP4_vars.view_y1 - DSP4_vars.poly_top[0][0];
+ }
+
+ // SR = 0x80
+
+ DSP4_WRITE_WORD(DSP4_vars.segments);
+
+ //////////////////////////////////////////////////////
+
+ // scan next command if no SR check needed
+ if (DSP4_vars.segments)
+ {
+ for (DSP4_vars.lcv = 0; DSP4_vars.lcv < 4; DSP4_vars.lcv++)
+ {
+ // grab inputs
+ DSP4.in_count = 4;
+ DSP4_WAIT(1);
+ resume1 :
+ for (;;)
+ {
+ int16 distance;
+ int16 color, red, green, blue;
+
+ distance = DSP4_READ_WORD();
+ color = DSP4_READ_WORD();
+
+ // U1+B5+G5+R5
+ red = color & 0x1f;
+ green = (color >> 5) & 0x1f;
+ blue = (color >> 10) & 0x1f;
+
+ // dynamic lighting
+ red = (red * distance >> 15) & 0x1f;
+ green = (green * distance >> 15) & 0x1f;
+ blue = (blue * distance >> 15) & 0x1f;
+ color = red | (green << 5) | (blue << 10);
+
+ DSP4_CLEAR_OUT();
+ DSP4_WRITE_WORD(color);
+ break;
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////
+
+ // scan next command if no SR check needed
+ if (DSP4_vars.segments)
+ {
+ int32 px_dx, py_dy;
+ int32 x_scroll, y_scroll;
+
+ // SR = 0x00
+
+ // linear interpolation (lerp) between projected points
+ px_dx = (DSP4_vars.view_xofs2 - DSP4_vars.view_xofs1) * DSP4_Inverse(DSP4_vars.segments) << 1;
+ py_dy = (DSP4_vars.view_yofs2 - DSP4_vars.view_yofs1) * DSP4_Inverse(DSP4_vars.segments) << 1;
+
+ // starting step values
+ x_scroll = SEX16(DSP4_vars.poly_cx[0][0] + DSP4_vars.view_xofs1);
+ y_scroll = SEX16(-DSP4_vars.viewport_bottom + DSP4_vars.view_yofs1 + DSP4_vars.view_yofsenv + DSP4_vars.poly_cx[1][0] - DSP4_vars.world_yofs);
+
+ // SR = 0x80
+
+ // rasterize line
+ for (DSP4_vars.lcv = 0; DSP4_vars.lcv < DSP4_vars.segments; DSP4_vars.lcv++)
+ {
+ // 1. HDMA memory pointer (bg2)
+ // 2. vertical scroll offset ($2110)
+ // 3. horizontal scroll offset ($210F)
+
+ DSP4_WRITE_WORD(DSP4_vars.poly_ptr[0][0]);
+ DSP4_WRITE_WORD((uint16)((y_scroll + 0x8000) >> 16));
+ DSP4_WRITE_WORD((uint16)((x_scroll + 0x8000) >> 16));
+
+ // update memory address
+ DSP4_vars.poly_ptr[0][0] -= 4;
+
+ // update screen values
+ x_scroll += px_dx;
+ y_scroll += py_dy;
+ }
+ }
+
+ /////////////////////////////////////////////////////
+ // Post-update
+
+ // update new viewer (x,y,scroll) to last DSP4_vars.raster line drawn
+ DSP4_vars.view_x1 = DSP4_vars.view_x2;
+ DSP4_vars.view_y1 = DSP4_vars.view_y2;
+ DSP4_vars.view_xofs1 = DSP4_vars.view_xofs2;
+ DSP4_vars.view_yofs1 = DSP4_vars.view_yofs2;
+
+ ////////////////////////////////////////////////////
+ // command check
+
+ // scan next command
+ DSP4.in_count = 2;
+ DSP4_WAIT(2) resume2 :
+
+ // check for opcode termination
+ DSP4_vars.distance = DSP4_READ_WORD();
+ if (DSP4_vars.distance == -0x8000)
+ break;
+
+ // already have 2 bytes in queue
+ DSP4.in_count = 10;
+ DSP4_WAIT(3) resume3 :
+
+
+ // inspect inputs
+ DSP4_vars.view_y2 = DSP4_READ_WORD();
+ DSP4_vars.view_dy = DSP4_READ_WORD() * DSP4_vars.distance >> 15;
+ DSP4_vars.view_x2 = DSP4_READ_WORD();
+ DSP4_vars.view_dx = DSP4_READ_WORD() * DSP4_vars.distance >> 15;
+ }
+ while (1);
+
+ DSP4.waiting4command = TRUE;
+}
+
+//////////////////////////////////////////////////////////////
+
+void DSP4_OP11(int16 A, int16 B, int16 C, int16 D, int16 *M)
+{
+ // 0x155 = 341 = Horizontal Width of the Screen
+ *M = ((A * 0x0155 >> 2) & 0xf000) |
+ ((B * 0x0155 >> 6) & 0x0f00) |
+ ((C * 0x0155 >> 10) & 0x00f0) |
+ ((D * 0x0155 >> 14) & 0x000f);
+}
+
+
+
+
+
+/////////////////////////////////////////////////////////////
+//Processing Code
+/////////////////////////////////////////////////////////////
+uint8 dsp4_byte;
+uint16 dsp4_address;
+
+void InitDSP4()
+{
+ memset(&DSP4, 0, sizeof(DSP4));
+ DSP4.waiting4command = TRUE;
+}
+
+void DSP4SetByte()
+{
+ // clear pending read
+ if (DSP4.out_index < DSP4.out_count)
+ {
+ DSP4.out_index++;
+ return;
+ }
+
+ if (DSP4.waiting4command)
+ {
+ if (DSP4.half_command)
+ {
+ DSP4.command |= (dsp4_byte << 8);
+ DSP4.in_index = 0;
+ DSP4.waiting4command = FALSE;
+ DSP4.half_command = FALSE;
+ DSP4.out_count = 0;
+ DSP4.out_index = 0;
+
+ DSP4_vars.DSP4_Logic = 0;
+
+
+ switch (DSP4.command)
+ {
+ case 0x0000:
+ DSP4.in_count = 4; break;
+ case 0x0001:
+ DSP4.in_count = 44; break;
+ case 0x0003:
+ DSP4.in_count = 0; break;
+ case 0x0005:
+ DSP4.in_count = 0; break;
+ case 0x0006:
+ DSP4.in_count = 0; break;
+ case 0x0007:
+ DSP4.in_count = 34; break;
+ case 0x0008:
+ DSP4.in_count = 90; break;
+ case 0x0009:
+ DSP4.in_count = 14; break;
+ case 0x000a:
+ DSP4.in_count = 6; break;
+ case 0x000b:
+ DSP4.in_count = 6; break;
+ case 0x000d:
+ DSP4.in_count = 42; break;
+ case 0x000e:
+ DSP4.in_count = 0; break;
+ case 0x000f:
+ DSP4.in_count = 46; break;
+ case 0x0010:
+ DSP4.in_count = 36; break;
+ case 0x0011:
+ DSP4.in_count = 8; break;
+ default:
+ DSP4.waiting4command = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ DSP4.command = dsp4_byte;
+ DSP4.half_command = TRUE;
+ }
+ }
+ else
+ {
+ DSP4.parameters[DSP4.in_index] = dsp4_byte;
+ DSP4.in_index++;
+ }
+
+ if (!DSP4.waiting4command && DSP4.in_count == DSP4.in_index)
+ {
+ // Actually execute the command
+ DSP4.waiting4command = TRUE;
+ DSP4.out_index = 0;
+ DSP4.in_index = 0;
+
+ switch (DSP4.command)
+ {
+ // 16-bit multiplication
+ case 0x0000:
+ {
+ int16 multiplier, multiplicand;
+ int32 product;
+
+ multiplier = DSP4_READ_WORD();
+ multiplicand = DSP4_READ_WORD();
+
+ DSP4_Multiply(multiplicand, multiplier, &product);
+
+ DSP4_CLEAR_OUT();
+ DSP4_WRITE_WORD((uint16)(product));
+ DSP4_WRITE_WORD((uint16)(product >> 16));
+ }
+ break;
+
+ // single-player track projection
+ case 0x0001:
+ DSP4_OP01(); break;
+
+ // single-player selection
+ case 0x0003:
+ DSP4_OP03(); break;
+
+ // clear OAM
+ case 0x0005:
+ DSP4_OP05(); break;
+
+ // transfer OAM
+ case 0x0006:
+ DSP4_OP06(); break;
+
+ // single-player track turnoff projection
+ case 0x0007:
+ DSP4_OP07(); break;
+
+ // solid polygon projection
+ case 0x0008:
+ DSP4_OP08(); break;
+
+ // sprite projection
+ case 0x0009:
+ DSP4_OP09(); break;
+
+ // unknown
+ case 0x000A:
+ {
+ int16 in1a = DSP4_READ_WORD();
+ int16 in2a = DSP4_READ_WORD();
+ int16 in3a = DSP4_READ_WORD();
+ int16 out1a, out2a, out3a, out4a;
+
+ DSP4_OP0A(in2a, &out2a, &out1a, &out4a, &out3a);
+
+ DSP4_CLEAR_OUT();
+ DSP4_WRITE_WORD(out1a);
+ DSP4_WRITE_WORD(out2a);
+ DSP4_WRITE_WORD(out3a);
+ DSP4_WRITE_WORD(out4a);
+ }
+ break;
+
+ // set OAM
+ case 0x000B:
+ {
+ int16 sp_x = DSP4_READ_WORD();
+ int16 sp_y = DSP4_READ_WORD();
+ int16 sp_attr = DSP4_READ_WORD();
+ bool8 draw = 1;
+
+ DSP4_CLEAR_OUT();
+
+ DSP4_OP0B(&draw, sp_x, sp_y, sp_attr, 0, 1);
+ }
+ break;
+
+ // multi-player track projection
+ case 0x000D:
+ DSP4_OP0D(); break;
+
+ // multi-player selection
+ case 0x000E:
+ DSP4_OP0E(); break;
+
+ // single-player track projection with lighting
+ case 0x000F:
+ DSP4_OP0F(); break;
+
+ // single-player track turnoff projection with lighting
+ case 0x0010:
+ DSP4_OP10(); break;
+
+ // unknown: horizontal mapping command
+ case 0x0011:
+ {
+ int16 a, b, c, d, m;
+
+
+ d = DSP4_READ_WORD();
+ c = DSP4_READ_WORD();
+ b = DSP4_READ_WORD();
+ a = DSP4_READ_WORD();
+
+ DSP4_OP11(a, b, c, d, &m);
+
+ DSP4_CLEAR_OUT();
+ DSP4_WRITE_WORD(m);
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+}
+
+void DSP4GetByte()
+{
+ if (DSP4.out_count)
+ {
+ dsp4_byte = (uint8) DSP4.output[DSP4.out_index&0x1FF];
+ DSP4.out_index++;
+ if (DSP4.out_count == DSP4.out_index)
+ DSP4.out_count = 0;
+ }
+ else
+ {
+ dsp4_byte = 0xff;
+ }
+}
+
+#endif
diff --git a/higan/sfc/coprocessor/dsp4/dsp4emu.h b/higan/sfc/coprocessor/dsp4/dsp4emu.h
new file mode 100644
index 00000000..834b33de
--- /dev/null
+++ b/higan/sfc/coprocessor/dsp4/dsp4emu.h
@@ -0,0 +1,108 @@
+//DSP-4 emulator code
+//Copyright (c) 2004-2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden
+
+#ifndef DSP4EMU_H
+#define DSP4EMU_H
+
+#undef TRUE
+#undef FALSE
+#define TRUE true
+#define FALSE false
+
+struct DSP4_t
+{
+ bool8 waiting4command;
+ bool8 half_command;
+ uint16 command;
+ uint32 in_count;
+ uint32 in_index;
+ uint32 out_count;
+ uint32 out_index;
+ uint8 parameters[512];
+ uint8 output[512];
+};
+
+extern struct DSP4_t DSP4;
+
+struct DSP4_vars_t
+{
+ // op control
+ int8 DSP4_Logic; // controls op flow
+
+
+ // projection format
+ int16 lcv; // loop-control variable
+ int16 distance; // z-position into virtual world
+ int16 raster; // current raster line
+ int16 segments; // number of raster lines drawn
+
+ // 1.15.16 or 1.15.0 [sign, integer, fraction]
+ int32 world_x; // line of x-projection in world
+ int32 world_y; // line of y-projection in world
+ int32 world_dx; // projection line x-delta
+ int32 world_dy; // projection line y-delta
+ int16 world_ddx; // x-delta increment
+ int16 world_ddy; // y-delta increment
+ int32 world_xenv; // world x-shaping factor
+ int16 world_yofs; // world y-vertical scroll
+
+ int16 view_x1; // current viewer-x
+ int16 view_y1; // current viewer-y
+ int16 view_x2; // future viewer-x
+ int16 view_y2; // future viewer-y
+ int16 view_dx; // view x-delta factor
+ int16 view_dy; // view y-delta factor
+ int16 view_xofs1; // current viewer x-vertical scroll
+ int16 view_yofs1; // current viewer y-vertical scroll
+ int16 view_xofs2; // future viewer x-vertical scroll
+ int16 view_yofs2; // future viewer y-vertical scroll
+ int16 view_yofsenv; // y-scroll shaping factor
+ int16 view_turnoff_x; // road turnoff data
+ int16 view_turnoff_dx; // road turnoff delta factor
+
+
+ // drawing area
+
+ int16 viewport_cx; // x-center of viewport window
+ int16 viewport_cy; // y-center of render window
+ int16 viewport_left; // x-left of viewport
+ int16 viewport_right; // x-right of viewport
+ int16 viewport_top; // y-top of viewport
+ int16 viewport_bottom; // y-bottom of viewport
+
+
+ // sprite structure
+
+ int16 sprite_x; // projected x-pos of sprite
+ int16 sprite_y; // projected y-pos of sprite
+ int16 sprite_attr; // obj attributes
+ bool8 sprite_size; // sprite size: 8x8 or 16x16
+ int16 sprite_clipy; // visible line to clip pixels off
+ int16 sprite_count;
+
+ // generic projection variables designed for
+ // two solid polygons + two polygon sides
+
+ int16 poly_clipLf[2][2]; // left clip boundary
+ int16 poly_clipRt[2][2]; // right clip boundary
+ int16 poly_ptr[2][2]; // HDMA structure pointers
+ int16 poly_raster[2][2]; // current raster line below horizon
+ int16 poly_top[2][2]; // top clip boundary
+ int16 poly_bottom[2][2]; // bottom clip boundary
+ int16 poly_cx[2][2]; // center for left/right points
+ int16 poly_start[2]; // current projection points
+ int16 poly_plane[2]; // previous z-plane distance
+
+
+ // OAM
+ int16 OAM_attr[16]; // OAM (size,MSB) data
+ int16 OAM_index; // index into OAM table
+ int16 OAM_bits; // offset into OAM table
+
+ int16 OAM_RowMax; // maximum number of tiles per 8 aligned pixels (row)
+ int16 OAM_Row[32]; // current number of tiles per row
+};
+
+extern struct DSP4_vars_t DSP4_vars;
+
+#endif
diff --git a/higan/sfc/coprocessor/dsp4/serialization.cpp b/higan/sfc/coprocessor/dsp4/serialization.cpp
new file mode 100644
index 00000000..a7f06471
--- /dev/null
+++ b/higan/sfc/coprocessor/dsp4/serialization.cpp
@@ -0,0 +1,72 @@
+auto DSP4::serialize(serializer& s) -> void {
+ s.integer(DSP4i::DSP4.waiting4command);
+ s.integer(DSP4i::DSP4.half_command);
+ s.integer(DSP4i::DSP4.command);
+ s.integer(DSP4i::DSP4.in_count);
+ s.integer(DSP4i::DSP4.in_index);
+ s.integer(DSP4i::DSP4.out_count);
+ s.integer(DSP4i::DSP4.out_index);
+ s.array(DSP4i::DSP4.parameters);
+ s.array(DSP4i::DSP4.output);
+
+ s.integer(DSP4i::DSP4_vars.DSP4_Logic);
+ s.integer(DSP4i::DSP4_vars.lcv);
+ s.integer(DSP4i::DSP4_vars.distance);
+ s.integer(DSP4i::DSP4_vars.raster);
+ s.integer(DSP4i::DSP4_vars.segments);
+ s.integer(DSP4i::DSP4_vars.world_x);
+ s.integer(DSP4i::DSP4_vars.world_y);
+ s.integer(DSP4i::DSP4_vars.world_dx);
+ s.integer(DSP4i::DSP4_vars.world_dy);
+ s.integer(DSP4i::DSP4_vars.world_ddx);
+ s.integer(DSP4i::DSP4_vars.world_ddy);
+ s.integer(DSP4i::DSP4_vars.world_xenv);
+ s.integer(DSP4i::DSP4_vars.world_yofs);
+ s.integer(DSP4i::DSP4_vars.view_x1);
+ s.integer(DSP4i::DSP4_vars.view_y1);
+ s.integer(DSP4i::DSP4_vars.view_x2);
+ s.integer(DSP4i::DSP4_vars.view_y2);
+ s.integer(DSP4i::DSP4_vars.view_dx);
+ s.integer(DSP4i::DSP4_vars.view_dy);
+ s.integer(DSP4i::DSP4_vars.view_xofs1);
+ s.integer(DSP4i::DSP4_vars.view_yofs1);
+ s.integer(DSP4i::DSP4_vars.view_xofs2);
+ s.integer(DSP4i::DSP4_vars.view_yofs2);
+ s.integer(DSP4i::DSP4_vars.view_yofsenv);
+ s.integer(DSP4i::DSP4_vars.view_turnoff_x);
+ s.integer(DSP4i::DSP4_vars.view_turnoff_dx);
+ s.integer(DSP4i::DSP4_vars.viewport_cx);
+ s.integer(DSP4i::DSP4_vars.viewport_cy);
+ s.integer(DSP4i::DSP4_vars.viewport_left);
+ s.integer(DSP4i::DSP4_vars.viewport_right);
+ s.integer(DSP4i::DSP4_vars.viewport_top);
+ s.integer(DSP4i::DSP4_vars.viewport_bottom);
+ s.integer(DSP4i::DSP4_vars.sprite_x);
+ s.integer(DSP4i::DSP4_vars.sprite_y);
+ s.integer(DSP4i::DSP4_vars.sprite_attr);
+ s.integer(DSP4i::DSP4_vars.sprite_size);
+ s.integer(DSP4i::DSP4_vars.sprite_clipy);
+ s.integer(DSP4i::DSP4_vars.sprite_count);
+
+ s.array(DSP4i::DSP4_vars.poly_clipLf[0]);
+ s.array(DSP4i::DSP4_vars.poly_clipLf[1]);
+ s.array(DSP4i::DSP4_vars.poly_clipRt[0]);
+ s.array(DSP4i::DSP4_vars.poly_clipRt[1]);
+ s.array(DSP4i::DSP4_vars.poly_ptr[0]);
+ s.array(DSP4i::DSP4_vars.poly_ptr[1]);
+ s.array(DSP4i::DSP4_vars.poly_raster[0]);
+ s.array(DSP4i::DSP4_vars.poly_raster[1]);
+ s.array(DSP4i::DSP4_vars.poly_top[0]);
+ s.array(DSP4i::DSP4_vars.poly_top[1]);
+ s.array(DSP4i::DSP4_vars.poly_bottom[0]);
+ s.array(DSP4i::DSP4_vars.poly_bottom[1]);
+ s.array(DSP4i::DSP4_vars.poly_cx[0]);
+ s.array(DSP4i::DSP4_vars.poly_cx[1]);
+ s.array(DSP4i::DSP4_vars.poly_start);
+ s.array(DSP4i::DSP4_vars.poly_plane);
+ s.array(DSP4i::DSP4_vars.OAM_attr);
+ s.integer(DSP4i::DSP4_vars.OAM_index);
+ s.integer(DSP4i::DSP4_vars.OAM_bits);
+ s.integer(DSP4i::DSP4_vars.OAM_RowMax);
+ s.array(DSP4i::DSP4_vars.OAM_Row);
+}
diff --git a/higan/sfc/coprocessor/st0010/data.hpp b/higan/sfc/coprocessor/st0010/data.hpp
new file mode 100644
index 00000000..52b251f9
--- /dev/null
+++ b/higan/sfc/coprocessor/st0010/data.hpp
@@ -0,0 +1,130 @@
+#ifdef ST0010_CPP
+
+const int16 ST0010::sin_table[256] = {
+ 0x0000, 0x0324, 0x0648, 0x096a, 0x0c8c, 0x0fab, 0x12c8, 0x15e2,
+ 0x18f9, 0x1c0b, 0x1f1a, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
+ 0x30fb, 0x33df, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
+ 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842,
+ 0x5a82, 0x5cb3, 0x5ed7, 0x60eb, 0x62f1, 0x64e8, 0x66cf, 0x68a6,
+ 0x6a6d, 0x6c23, 0x6dc9, 0x6f5e, 0x70e2, 0x7254, 0x73b5, 0x7504,
+ 0x7641, 0x776b, 0x7884, 0x7989, 0x7a7c, 0x7b5c, 0x7c29, 0x7ce3,
+ 0x7d89, 0x7e1d, 0x7e9c, 0x7f09, 0x7f61, 0x7fa6, 0x7fd8, 0x7ff5,
+ 0x7fff, 0x7ff5, 0x7fd8, 0x7fa6, 0x7f61, 0x7f09, 0x7e9c, 0x7e1d,
+ 0x7d89, 0x7ce3, 0x7c29, 0x7b5c, 0x7a7c, 0x7989, 0x7884, 0x776b,
+ 0x7641, 0x7504, 0x73b5, 0x7254, 0x70e2, 0x6f5e, 0x6dc9, 0x6c23,
+ 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f1, 0x60eb, 0x5ed7, 0x5cb3,
+ 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4,
+ 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33df,
+ 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f1a, 0x1c0b,
+ 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8c, 0x096a, 0x0648, 0x0324,
+ 0x0000, -0x0324, -0x0648, -0x096b, -0x0c8c, -0x0fab, -0x12c8, -0x15e2,
+ -0x18f9, -0x1c0b, -0x1f1a, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11,
+ -0x30fb, -0x33df, -0x36ba, -0x398d, -0x3c56, -0x3f17, -0x41ce, -0x447a,
+ -0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842,
+ -0x5a82, -0x5cb3, -0x5ed7, -0x60ec, -0x62f1, -0x64e8, -0x66cf, -0x68a6,
+ -0x6a6d, -0x6c23, -0x6dc9, -0x6f5e, -0x70e2, -0x7254, -0x73b5, -0x7504,
+ -0x7641, -0x776b, -0x7884, -0x7989, -0x7a7c, -0x7b5c, -0x7c29, -0x7ce3,
+ -0x7d89, -0x7e1d, -0x7e9c, -0x7f09, -0x7f61, -0x7fa6, -0x7fd8, -0x7ff5,
+ -0x7fff, -0x7ff5, -0x7fd8, -0x7fa6, -0x7f61, -0x7f09, -0x7e9c, -0x7e1d,
+ -0x7d89, -0x7ce3, -0x7c29, -0x7b5c, -0x7a7c, -0x7989, -0x7883, -0x776b,
+ -0x7641, -0x7504, -0x73b5, -0x7254, -0x70e2, -0x6f5e, -0x6dc9, -0x6c23,
+ -0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f1, -0x60eb, -0x5ed7, -0x5cb3,
+ -0x5a82, -0x5842, -0x55f5, -0x539a, -0x5133, -0x4ebf, -0x4c3f, -0x49b3,
+ -0x471c, -0x447a, -0x41cd, -0x3f17, -0x3c56, -0x398c, -0x36b9, -0x33de,
+ -0x30fb, -0x2e10, -0x2b1f, -0x2826, -0x2527, -0x2223, -0x1f19, -0x1c0b,
+ -0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324
+};
+
+const int16 ST0010::mode7_scale[176] = {
+ 0x0380, 0x0325, 0x02da, 0x029c, 0x0268, 0x023b, 0x0215, 0x01f3,
+ 0x01d5, 0x01bb, 0x01a3, 0x018e, 0x017b, 0x016a, 0x015a, 0x014b,
+ 0x013e, 0x0132, 0x0126, 0x011c, 0x0112, 0x0109, 0x0100, 0x00f8,
+ 0x00f0, 0x00e9, 0x00e3, 0x00dc, 0x00d6, 0x00d1, 0x00cb, 0x00c6,
+ 0x00c1, 0x00bd, 0x00b8, 0x00b4, 0x00b0, 0x00ac, 0x00a8, 0x00a5,
+ 0x00a2, 0x009e, 0x009b, 0x0098, 0x0095, 0x0093, 0x0090, 0x008d,
+ 0x008b, 0x0088, 0x0086, 0x0084, 0x0082, 0x0080, 0x007e, 0x007c,
+ 0x007a, 0x0078, 0x0076, 0x0074, 0x0073, 0x0071, 0x006f, 0x006e,
+ 0x006c, 0x006b, 0x0069, 0x0068, 0x0067, 0x0065, 0x0064, 0x0063,
+ 0x0062, 0x0060, 0x005f, 0x005e, 0x005d, 0x005c, 0x005b, 0x005a,
+ 0x0059, 0x0058, 0x0057, 0x0056, 0x0055, 0x0054, 0x0053, 0x0052,
+ 0x0051, 0x0051, 0x0050, 0x004f, 0x004e, 0x004d, 0x004d, 0x004c,
+ 0x004b, 0x004b, 0x004a, 0x0049, 0x0048, 0x0048, 0x0047, 0x0047,
+ 0x0046, 0x0045, 0x0045, 0x0044, 0x0044, 0x0043, 0x0042, 0x0042,
+ 0x0041, 0x0041, 0x0040, 0x0040, 0x003f, 0x003f, 0x003e, 0x003e,
+ 0x003d, 0x003d, 0x003c, 0x003c, 0x003b, 0x003b, 0x003a, 0x003a,
+ 0x003a, 0x0039, 0x0039, 0x0038, 0x0038, 0x0038, 0x0037, 0x0037,
+ 0x0036, 0x0036, 0x0036, 0x0035, 0x0035, 0x0035, 0x0034, 0x0034,
+ 0x0034, 0x0033, 0x0033, 0x0033, 0x0032, 0x0032, 0x0032, 0x0031,
+ 0x0031, 0x0031, 0x0030, 0x0030, 0x0030, 0x0030, 0x002f, 0x002f,
+ 0x002f, 0x002e, 0x002e, 0x002e, 0x002e, 0x002d, 0x002d, 0x002d,
+ 0x002d, 0x002c, 0x002c, 0x002c, 0x002c, 0x002b, 0x002b, 0x002b
+};
+
+const uint8 ST0010::arctan[32][32] = {
+ { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
+ { 0x80, 0xa0, 0xad, 0xb3, 0xb6, 0xb8, 0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd,
+ 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf },
+ { 0x80, 0x93, 0xa0, 0xa8, 0xad, 0xb0, 0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb,
+ 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd },
+ { 0x80, 0x8d, 0x98, 0xa0, 0xa6, 0xaa, 0xad, 0xb0, 0xb1, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb7, 0xb8,
+ 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc },
+ { 0x80, 0x8a, 0x93, 0x9a, 0xa0, 0xa5, 0xa8, 0xab, 0xad, 0xaf, 0xb0, 0xb2, 0xb3, 0xb4, 0xb5, 0xb5,
+ 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb },
+ { 0x80, 0x88, 0x90, 0x96, 0x9b, 0xa0, 0xa4, 0xa7, 0xa9, 0xab, 0xad, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
+ 0xb4, 0xb4, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9 },
+ { 0x80, 0x87, 0x8d, 0x93, 0x98, 0x9c, 0xa0, 0xa3, 0xa6, 0xa8, 0xaa, 0xac, 0xad, 0xae, 0xb0, 0xb0,
+ 0xb1, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8 },
+ { 0x80, 0x86, 0x8b, 0x90, 0x95, 0x99, 0x9d, 0xa0, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac, 0xad, 0xae,
+ 0xaf, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7 },
+ { 0x80, 0x85, 0x8a, 0x8f, 0x93, 0x97, 0x9a, 0x9d, 0xa0, 0xa2, 0xa5, 0xa6, 0xa8, 0xaa, 0xab, 0xac,
+ 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb5 },
+ { 0x80, 0x85, 0x89, 0x8d, 0x91, 0x95, 0x98, 0x9b, 0x9e, 0xa0, 0xa0, 0xa4, 0xa6, 0xa7, 0xa9, 0xaa,
+ 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4 },
+ { 0x80, 0x84, 0x88, 0x8c, 0x90, 0x93, 0x96, 0x99, 0x9b, 0x9e, 0xa0, 0xa2, 0xa4, 0xa5, 0xa7, 0xa8,
+ 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3 },
+ { 0x80, 0x84, 0x87, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, 0xa6,
+ 0xa7, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2 },
+ { 0x80, 0x83, 0x87, 0x8a, 0x8d, 0x90, 0x93, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1 },
+ { 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x94, 0x96, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xb0 },
+ { 0x80, 0x83, 0x86, 0x89, 0x8b, 0x8e, 0x90, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa1,
+ 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf },
+ { 0x80, 0x83, 0x85, 0x88, 0x8b, 0x8d, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9b, 0x9d, 0x9f, 0xa0,
+ 0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae },
+ { 0x80, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8f, 0x91, 0x93, 0x95, 0x97, 0x99, 0x9a, 0x9c, 0x9d, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa5, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xad },
+ { 0x80, 0x82, 0x85, 0x87, 0x89, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x97, 0x99, 0x9b, 0x9c, 0x9d,
+ 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac },
+ { 0x80, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x8d, 0x8f, 0x91, 0x93, 0x95, 0x96, 0x98, 0x99, 0x9b, 0x9c,
+ 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab },
+ { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x9a, 0x9b,
+ 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa },
+ { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x99, 0x9a,
+ 0x9b, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9 },
+ { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8f, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x99,
+ 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8 },
+ { 0x80, 0x82, 0x84, 0x86, 0x87, 0x89, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x98,
+ 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7 },
+ { 0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x94, 0x95, 0x96, 0x98,
+ 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6 },
+ { 0x80, 0x82, 0x83, 0x85, 0x87, 0x88, 0x8a, 0x8c, 0x8d, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5 },
+ { 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa4 },
+ { 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x89, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x95,
+ 0x96, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4 },
+ { 0x80, 0x82, 0x83, 0x85, 0x86, 0x87, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, 0x95,
+ 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2, 0xa3 },
+ { 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x89, 0x8a, 0x8b, 0x8d, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94,
+ 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2 },
+ { 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x88, 0x8a, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93,
+ 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1, 0xa1 },
+ { 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8b, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93,
+ 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1 },
+ { 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
+ 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0 }
+};
+
+#endif
diff --git a/higan/sfc/coprocessor/st0010/opcodes.cpp b/higan/sfc/coprocessor/st0010/opcodes.cpp
new file mode 100644
index 00000000..57a54975
--- /dev/null
+++ b/higan/sfc/coprocessor/st0010/opcodes.cpp
@@ -0,0 +1,301 @@
+#ifdef ST0010_CPP
+
+int16 ST0010::sin(int16 theta) {
+ return sin_table[(theta >> 8) & 0xff];
+}
+
+int16 ST0010::cos(int16 theta) {
+ return sin_table[((theta + 0x4000) >> 8) & 0xff];
+}
+
+uint8 ST0010::readb(uint16 addr) {
+ return ram[addr & 0xfff];
+}
+
+uint16 ST0010::readw(uint16 addr) {
+ return (readb(addr + 0) << 0) |
+ (readb(addr + 1) << 8);
+}
+
+uint32 ST0010::readd(uint16 addr) {
+ return (readb(addr + 0) << 0) |
+ (readb(addr + 1) << 8) |
+ (readb(addr + 2) << 16) |
+ (readb(addr + 3) << 24);
+}
+
+void ST0010::writeb(uint16 addr, uint8 data) {
+ ram[addr & 0xfff] = data;
+}
+
+void ST0010::writew(uint16 addr, uint16 data) {
+ writeb(addr + 0, data >> 0);
+ writeb(addr + 1, data >> 8);
+}
+
+void ST0010::writed(uint16 addr, uint32 data) {
+ writeb(addr + 0, data >> 0);
+ writeb(addr + 1, data >> 8);
+ writeb(addr + 2, data >> 16);
+ writeb(addr + 3, data >> 24);
+}
+
+//ST-0010 emulation code - Copyright (C) 2003 The Dumper, Matthew Kendora, Overload, Feather
+//bsnes port - Copyright (C) 2007 byuu
+
+void ST0010::op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta) {
+ if((x0 < 0) && (y0 < 0)) {
+ x1 = -x0;
+ y1 = -y0;
+ quadrant = -0x8000;
+ } else if(x0 < 0) {
+ x1 = y0;
+ y1 = -x0;
+ quadrant = -0x4000;
+ } else if(y0 < 0) {
+ x1 = -y0;
+ y1 = x0;
+ quadrant = 0x4000;
+ } else {
+ x1 = x0;
+ y1 = y0;
+ quadrant = 0x0000;
+ }
+
+ while((x1 > 0x1f) || (y1 > 0x1f)) {
+ if(x1 > 1) { x1 >>= 1; }
+ if(y1 > 1) { y1 >>= 1; }
+ }
+
+ if(y1 == 0) { quadrant += 0x4000; }
+
+ theta = (arctan[y1][x1] << 8) ^ quadrant;
+}
+
+//
+
+void ST0010::op_01() {
+ int16 x0 = readw(0x0000);
+ int16 y0 = readw(0x0002);
+ int16 x1, y1, quadrant, theta;
+
+ op_01(x0, y0, x1, y1, quadrant, theta);
+
+ writew(0x0000, x1);
+ writew(0x0002, y1);
+ writew(0x0004, quadrant);
+//writew(0x0006, y0); //Overload's docs note this write occurs, SNES9x disagrees
+ writew(0x0010, theta);
+}
+
+void ST0010::op_02() {
+ int16 positions = readw(0x0024);
+ uint16 *places = (uint16*)(ram + 0x0040);
+ uint16 *drivers = (uint16*)(ram + 0x0080);
+
+ bool sorted;
+ uint16 temp;
+ if(positions > 1) {
+ do {
+ sorted = true;
+ for(int i = 0; i < positions - 1; i++) {
+ if(places[i] < places[i + 1]) {
+ temp = places[i + 1];
+ places[i + 1] = places[i];
+ places[i] = temp;
+
+ temp = drivers[i + 1];
+ drivers[i + 1] = drivers[i];
+ drivers[i] = temp;
+
+ sorted = false;
+ }
+ }
+ positions--;
+ } while(!sorted);
+ }
+}
+
+void ST0010::op_03() {
+ int16 x0 = readw(0x0000);
+ int16 y0 = readw(0x0002);
+ int16 multiplier = readw(0x0004);
+ int32 x1, y1;
+
+ x1 = x0 * multiplier << 1;
+ y1 = y0 * multiplier << 1;
+
+ writed(0x0010, x1);
+ writed(0x0014, y1);
+}
+
+void ST0010::op_04() {
+ int16 x = readw(0x0000);
+ int16 y = readw(0x0002);
+ int16 square;
+ //calculate the vector length of (x,y)
+ square = (int16)sqrt((double)(y * y + x * x));
+
+ writew(0x0010, square);
+}
+
+void ST0010::op_05() {
+ int32 dx, dy;
+ int16 a1, b1, c1;
+ uint16 o1;
+ bool wrap = false;
+
+ //target (x,y) coordinates
+ int16 ypos_max = readw(0x00c0);
+ int16 xpos_max = readw(0x00c2);
+
+ //current coordinates and direction
+ int32 ypos = readd(0x00c4);
+ int32 xpos = readd(0x00c8);
+ uint16 rot = readw(0x00cc);
+
+ //physics
+ uint16 speed = readw(0x00d4);
+ uint16 accel = readw(0x00d6);
+ uint16 speed_max = readw(0x00d8);
+
+ //special condition acknowledgement
+ int16 system = readw(0x00da);
+ int16 flags = readw(0x00dc);
+
+ //new target coordinates
+ int16 ypos_new = readw(0x00de);
+ int16 xpos_new = readw(0x00e0);
+
+ //mask upper bit
+ xpos_new &= 0x7fff;
+
+ //get the current distance
+ dx = xpos_max - (xpos >> 16);
+ dy = ypos_max - (ypos >> 16);
+
+ //quirk: clear and move in9
+ writew(0x00d2, 0xffff);
+ writew(0x00da, 0x0000);
+
+ //grab the target angle
+ op_01(dy, dx, a1, b1, c1, (int16&)o1);
+
+ //check for wrapping
+ if(abs(o1 - rot) > 0x8000) {
+ o1 += 0x8000;
+ rot += 0x8000;
+ wrap = true;
+ }
+
+ uint16 old_speed = speed;
+
+ //special case
+ if(abs(o1 - rot) == 0x8000) {
+ speed = 0x100;
+ }
+
+ //slow down for sharp curves
+ else if(abs(o1 - rot) >= 0x1000) {
+ uint32 slow = abs(o1 - rot);
+ slow >>= 4; //scaling
+ speed -= slow;
+ }
+
+ //otherwise accelerate
+ else {
+ speed += accel;
+ if(speed > speed_max) {
+ speed = speed_max; //clip speed
+ }
+ }
+
+ //prevent negative/positive overflow
+ if(abs(old_speed - speed) > 0x8000) {
+ if(old_speed < speed) { speed = 0; }
+ else speed = 0xff00;
+ }
+
+ //adjust direction by so many degrees
+ //be careful of negative adjustments
+ if((o1 > rot && (o1 - rot) > 0x80) || (o1 < rot && (rot - o1) >= 0x80)) {
+ if(o1 < rot) { rot -= 0x280; }
+ else if(o1 > rot) { rot += 0x280; }
+ }
+
+ //turn off wrapping
+ if(wrap) { rot -= 0x8000; }
+
+ //now check the distances (store for later)
+ dx = (xpos_max << 16) - xpos;
+ dy = (ypos_max << 16) - ypos;
+ dx >>= 16;
+ dy >>= 16;
+
+ //if we're in so many units of the target, signal it
+ if((system && (dy <= 6 && dy >= -8) && (dx <= 126 && dx >= -128)) || (!system && (dx <= 6 && dx >= -8) && (dy <= 126 && dy >= -128))) {
+ //announce our new destination and flag it
+ xpos_max = xpos_new & 0x7fff;
+ ypos_max = ypos_new;
+ flags |= 0x08;
+ }
+
+ //update position
+ xpos -= (cos(rot) * 0x400 >> 15) * (speed >> 8) << 1;
+ ypos -= (sin(rot) * 0x400 >> 15) * (speed >> 8) << 1;
+
+ //quirk: mask upper byte
+ xpos &= 0x1fffffff;
+ ypos &= 0x1fffffff;
+
+ writew(0x00c0, ypos_max);
+ writew(0x00c2, xpos_max);
+ writed(0x00c4, ypos);
+ writed(0x00c8, xpos);
+ writew(0x00cc, rot);
+ writew(0x00d4, speed);
+ writew(0x00dc, flags);
+}
+
+void ST0010::op_06() {
+ int16 multiplicand = readw(0x0000);
+ int16 multiplier = readw(0x0002);
+ int32 product;
+
+ product = multiplicand * multiplier << 1;
+
+ writed(0x0010, product);
+}
+
+void ST0010::op_07() {
+ int16 theta = readw(0x0000);
+
+ int16 data;
+ for(int i = 0, offset = 0; i < 176; i++) {
+ data = mode7_scale[i] * cos(theta) >> 15;
+ writew(0x00f0 + offset, data);
+ writew(0x0510 + offset, data);
+
+ data = mode7_scale[i] * sin(theta) >> 15;
+ writew(0x0250 + offset, data);
+ if(data) { data = ~data; }
+ writew(0x03b0 + offset, data);
+
+ offset += 2;
+ }
+}
+
+void ST0010::op_08() {
+ int16 x0 = readw(0x0000);
+ int16 y0 = readw(0x0002);
+ int16 theta = readw(0x0004);
+ int16 x1, y1;
+
+ x1 = (y0 * sin(theta) >> 15) + (x0 * cos(theta) >> 15);
+ y1 = (y0 * cos(theta) >> 15) - (x0 * sin(theta) >> 15);
+
+ writew(0x0010, x1);
+ writew(0x0012, y1);
+}
+
+#endif
diff --git a/higan/sfc/coprocessor/st0010/serialization.cpp b/higan/sfc/coprocessor/st0010/serialization.cpp
new file mode 100644
index 00000000..25bf4789
--- /dev/null
+++ b/higan/sfc/coprocessor/st0010/serialization.cpp
@@ -0,0 +1,3 @@
+auto ST0010::serialize(serializer& s) -> void {
+ s.array(ram);
+}
diff --git a/higan/sfc/coprocessor/st0010/st0010.cpp b/higan/sfc/coprocessor/st0010/st0010.cpp
new file mode 100644
index 00000000..1509aa29
--- /dev/null
+++ b/higan/sfc/coprocessor/st0010/st0010.cpp
@@ -0,0 +1,39 @@
+#include
+
+namespace SuperFamicom {
+
+#define ST0010_CPP
+#include "data.hpp"
+#include "opcodes.cpp"
+
+ST0010 st0010;
+#include "serialization.cpp"
+
+auto ST0010::power() -> void {
+ memset(ram, 0x00, sizeof ram);
+}
+
+auto ST0010::read(uint24 addr, uint8 data) -> uint8 {
+ return readb(addr);
+}
+
+auto ST0010::write(uint24 addr, uint8 data) -> void {
+ writeb(addr, data);
+
+ if((addr & 0xfff) == 0x0021 && (data & 0x80)) {
+ switch(ram[0x0020]) {
+ case 0x01: op_01(); break;
+ case 0x02: op_02(); break;
+ case 0x03: op_03(); break;
+ case 0x04: op_04(); break;
+ case 0x05: op_05(); break;
+ case 0x06: op_06(); break;
+ case 0x07: op_07(); break;
+ case 0x08: op_08(); break;
+ }
+
+ ram[0x0021] &= ~0x80;
+ }
+}
+
+}
diff --git a/higan/sfc/coprocessor/st0010/st0010.hpp b/higan/sfc/coprocessor/st0010/st0010.hpp
new file mode 100644
index 00000000..a87314d5
--- /dev/null
+++ b/higan/sfc/coprocessor/st0010/st0010.hpp
@@ -0,0 +1,39 @@
+struct ST0010 {
+ auto power() -> void;
+
+ auto read(uint24 addr, uint8 data) -> uint8;
+ auto write(uint24 addr, uint8 data) -> void;
+
+ auto serialize(serializer&) -> void;
+
+ uint8 ram[0x1000];
+ static const int16 sin_table[256];
+ static const int16 mode7_scale[176];
+ static const uint8 arctan[32][32];
+
+ //interfaces to sin table
+ int16 sin(int16 theta);
+ int16 cos(int16 theta);
+
+ //interfaces to ram buffer
+ uint8 readb (uint16 addr);
+ uint16 readw (uint16 addr);
+ uint32 readd (uint16 addr);
+ void writeb(uint16 addr, uint8 data);
+ void writew(uint16 addr, uint16 data);
+ void writed(uint16 addr, uint32 data);
+
+ //opcodes
+ void op_01();
+ void op_02();
+ void op_03();
+ void op_04();
+ void op_05();
+ void op_06();
+ void op_07();
+ void op_08();
+
+ void op_01(int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &quadrant, int16 &theta);
+};
+
+extern ST0010 st0010;
diff --git a/higan/sfc/interface/configuration.cpp b/higan/sfc/interface/configuration.cpp
index 186d895f..768ae2c2 100644
--- a/higan/sfc/interface/configuration.cpp
+++ b/higan/sfc/interface/configuration.cpp
@@ -20,6 +20,7 @@ auto Configuration::process(Markup::Node document, bool load) -> void {
bind(boolean, "Hacks/FastPPU/NoSpriteLimit", hacks.ppuFast.noSpriteLimit);
bind(boolean, "Hacks/FastPPU/HiresMode7", hacks.ppuFast.hiresMode7);
bind(boolean, "Hacks/FastDSP/Enable", hacks.dspFast.enable);
+ bind(boolean, "Hacks/Coprocessors/HLE", hacks.coprocessors.hle);
bind(boolean, "Hacks/Coprocessors/DelayedSync", hacks.coprocessors.delayedSync);
#undef bind
diff --git a/higan/sfc/interface/configuration.hpp b/higan/sfc/interface/configuration.hpp
index dd0b3cc6..159b7d18 100644
--- a/higan/sfc/interface/configuration.hpp
+++ b/higan/sfc/interface/configuration.hpp
@@ -35,6 +35,7 @@ struct Configuration {
} dspFast;
struct Coprocessors {
bool delayedSync = true;
+ bool hle = true;
} coprocessors;
} hacks;
diff --git a/higan/sfc/memory/memory.hpp b/higan/sfc/memory/memory.hpp
index 7ef71b0c..6f28b587 100644
--- a/higan/sfc/memory/memory.hpp
+++ b/higan/sfc/memory/memory.hpp
@@ -24,7 +24,7 @@ struct Bus {
~Bus();
- alwaysinline auto read(uint24 address, uint8 data) -> uint8;
+ alwaysinline auto read(uint24 address, uint8 data = 0) -> uint8;
alwaysinline auto write(uint24 address, uint8 data) -> void;
auto reset() -> void;
diff --git a/higan/sfc/ppu-fast/io.cpp b/higan/sfc/ppu-fast/io.cpp
index cecaf68c..1176f6cf 100644
--- a/higan/sfc/ppu-fast/io.cpp
+++ b/higan/sfc/ppu-fast/io.cpp
@@ -53,7 +53,8 @@ auto PPU::readOAM(uint10 address) -> uint8 {
auto PPU::writeOAM(uint10 address, uint8 data) -> void {
Line::flush();
- if(!io.displayDisable && cpu.vcounter() < vdisp()) address = latch.oamAddress;
+ //Uniracers 2-player mode hack
+ if(!io.displayDisable && cpu.vcounter() < vdisp()) address = 0x0218; //latch.oamAddress;
return writeObject(address, data);
}
diff --git a/higan/sfc/ppu/object.cpp b/higan/sfc/ppu/object.cpp
index 4d063231..92088ebc 100644
--- a/higan/sfc/ppu/object.cpp
+++ b/higan/sfc/ppu/object.cpp
@@ -137,8 +137,6 @@ auto PPU::Object::tilefetch() -> void {
uint16 addr = (pos & 0xfff0) + (y & 7);
oamTile[n].data.bits( 0,15) = ppu.vram[addr + 0];
- ppu.step(2);
-
oamTile[n].data.bits(16,31) = ppu.vram[addr + 8];
ppu.step(2);
}
diff --git a/higan/sfc/ppu/ppu.cpp b/higan/sfc/ppu/ppu.cpp
index 946c3192..3e4117bb 100644
--- a/higan/sfc/ppu/ppu.cpp
+++ b/higan/sfc/ppu/ppu.cpp
@@ -74,7 +74,7 @@ auto PPU::main() -> void {
step(2);
}
- step(14);
+ step(14 + 34 * 2);
obj.tilefetch();
}
diff --git a/higan/sfc/system/serialization.cpp b/higan/sfc/system/serialization.cpp
index d3d91d08..7a490f4f 100644
--- a/higan/sfc/system/serialization.cpp
+++ b/higan/sfc/system/serialization.cpp
@@ -68,6 +68,12 @@ auto System::serializeAll(serializer& s) -> void {
if(cartridge.has.OBC1) obc1.serialize(s);
if(cartridge.has.MSU1) msu1.serialize(s);
+ if(cartridge.has.Cx4) cx4.serialize(s);
+ if(cartridge.has.DSP1) dsp1.serialize(s);
+ if(cartridge.has.DSP2) dsp2.serialize(s);
+ if(cartridge.has.DSP4) dsp4.serialize(s);
+ if(cartridge.has.ST0010) st0010.serialize(s);
+
if(cartridge.has.BSMemorySlot) bsmemory.serialize(s);
if(cartridge.has.SufamiTurboSlotA) sufamiturboA.serialize(s);
if(cartridge.has.SufamiTurboSlotB) sufamiturboB.serialize(s);
diff --git a/higan/sfc/system/system.cpp b/higan/sfc/system/system.cpp
index f6a1380b..09ec5a25 100644
--- a/higan/sfc/system/system.cpp
+++ b/higan/sfc/system/system.cpp
@@ -111,6 +111,11 @@ auto System::power(bool reset) -> void {
if(cartridge.has.SDD1) sdd1.power();
if(cartridge.has.OBC1) obc1.power();
if(cartridge.has.MSU1) msu1.power();
+ if(cartridge.has.Cx4) cx4.power();
+ if(cartridge.has.DSP1) dsp1.power();
+ if(cartridge.has.DSP2) dsp2.power();
+ if(cartridge.has.DSP4) dsp4.power();
+ if(cartridge.has.ST0010) st0010.power();
if(cartridge.has.BSMemorySlot) bsmemory.power();
if(cartridge.has.SufamiTurboSlotA) sufamiturboA.power();
if(cartridge.has.SufamiTurboSlotB) sufamiturboB.power();
diff --git a/higan/systems/Super Famicom.sys/boards.bml b/higan/systems/Super Famicom.sys/boards.bml
index 387cdc4d..416924fa 100644
--- a/higan/systems/Super Famicom.sys/boards.bml
+++ b/higan/systems/Super Famicom.sys/boards.bml
@@ -237,7 +237,7 @@ board: SHVC-1CB0N7S-01
map address=00-3f,80-bf:6000-7fff size=0x2000
map address=70-71:0000-ffff
-board: SHVC-1CB5B-20
+board: SHVC-1CB5B-(01,20)
processor architecture=GSU
map address=00-3f,80-bf:3000-34ff
memory type=ROM content=Program
diff --git a/higan/target-bsnes/bsnes.cpp b/higan/target-bsnes/bsnes.cpp
index 6056199d..c222679f 100644
--- a/higan/target-bsnes/bsnes.cpp
+++ b/higan/target-bsnes/bsnes.cpp
@@ -18,10 +18,6 @@ auto locate(string name) -> string {
return {Path::userData(), "bsnes/", name};
}
-auto hiro::initialize() -> void {
- Application::setName("bsnes");
-}
-
#include
auto nall::main(Arguments arguments) -> void {
settings.location = locate("settings.bml");
@@ -45,6 +41,7 @@ auto nall::main(Arguments arguments) -> void {
}
settings.load();
+ Application::setName("bsnes");
Application::setScreenSaver(settings.general.screenSaver);
Application::setToolTips(settings.general.toolTips);
emulator = new SuperFamicom::Interface;
diff --git a/higan/target-bsnes/input/hotkeys.cpp b/higan/target-bsnes/input/hotkeys.cpp
index 4fcf0bb7..7daec2b5 100644
--- a/higan/target-bsnes/input/hotkeys.cpp
+++ b/higan/target-bsnes/input/hotkeys.cpp
@@ -46,9 +46,11 @@ auto InputManager::bindHotkeys() -> void {
hotkeys.append(InputHotkey("Fast Forward").onPress([] {
video.setBlocking(false);
audio.setBlocking(false);
+ audio.setDynamic(false);
}).onRelease([] {
video.setBlocking(settings.video.blocking);
audio.setBlocking(settings.audio.blocking);
+ audio.setDynamic(settings.audio.dynamic);
}));
hotkeys.append(InputHotkey("Pause Emulation").onPress([] {
diff --git a/higan/target-bsnes/presentation/presentation.cpp b/higan/target-bsnes/presentation/presentation.cpp
index 4d5da280..62e342b2 100644
--- a/higan/target-bsnes/presentation/presentation.cpp
+++ b/higan/target-bsnes/presentation/presentation.cpp
@@ -104,7 +104,7 @@ auto Presentation::create() -> void {
program.loadState("Quick/Redo");
}));
loadState.append(MenuItem().setIcon(Icon::Edit::Clear).setText("Remove All States").onActivate([&] {
- if(MessageDialog("Are you sure you want to permanently remove all quick states for this game?").setParent(*this).question() == "Yes") {
+ if(MessageDialog("Are you sure you want to permanently remove all quick states for this game?").setAlignment(*this).question() == "Yes") {
for(uint index : range(QuickStates)) program.removeState({"Quick/Slot ", 1 + index});
program.removeState("Quick/Undo");
program.removeState("Quick/Redo");
@@ -141,7 +141,7 @@ auto Presentation::create() -> void {
.setAuthor("byuu")
.setLicense("GPLv3")
.setWebsite("https://byuu.org/")
- .setParent(*this)
+ .setAlignment(*this)
.show();
});
@@ -195,7 +195,7 @@ auto Presentation::create() -> void {
setTitle({"bsnes v", Emulator::Version});
setBackgroundColor({0, 0, 0});
resizeWindow();
- setCentered();
+ setAlignment(Alignment::Center);
setFullScreen(startFullScreen);
#if defined(PLATFORM_MACOS)
@@ -324,7 +324,7 @@ auto Presentation::toggleFullscreenMode() -> void {
menuBar.setVisible(true);
if(settings.general.statusBar) layout.append(statusLayout, Size{~0, StatusHeight});
resizeWindow();
- setCentered();
+ setAlignment(Alignment::Center);
}
}
@@ -419,7 +419,7 @@ auto Presentation::updateSizeMenu() -> void {
resizeWindow();
}));
sizeMenu.append(MenuItem().setIcon(Icon::Place::Settings).setText("Center Window").onActivate([&] {
- setCentered();
+ setAlignment(Alignment::Center);
}));
}
diff --git a/higan/target-bsnes/program/audio.cpp b/higan/target-bsnes/program/audio.cpp
index 9284acb2..a0aaf80e 100644
--- a/higan/target-bsnes/program/audio.cpp
+++ b/higan/target-bsnes/program/audio.cpp
@@ -16,7 +16,7 @@ auto Program::updateAudioDriver(Window parent) -> void {
if(!audio.ready()) {
MessageDialog({
"Error: failed to initialize [", settings.audio.driver, "] audio driver."
- }).setParent(parent).error();
+ }).setAlignment(parent).error();
settings.audio.driver = "None";
return updateAudioDriver(parent);
}
diff --git a/higan/target-bsnes/program/game.cpp b/higan/target-bsnes/program/game.cpp
index bf2d5ed2..b8c60020 100644
--- a/higan/target-bsnes/program/game.cpp
+++ b/higan/target-bsnes/program/game.cpp
@@ -18,7 +18,7 @@ auto Program::load() -> void {
"Warning: this game image is unverified.\n"
"Running it *may* be a security risk.\n\n"
"Do you wish to run the game anyway?"
- ).setParent(*presentation).question({"Always", "Yes", "No"});
+ ).setAlignment(*presentation).question({"Always", "Yes", "No"});
if(response == "No") {
emulator->unload();
return showMessage("Game loading cancelled");
diff --git a/higan/target-bsnes/program/input.cpp b/higan/target-bsnes/program/input.cpp
index 609cd0f7..cabefcf9 100644
--- a/higan/target-bsnes/program/input.cpp
+++ b/higan/target-bsnes/program/input.cpp
@@ -12,7 +12,7 @@ auto Program::updateInputDriver(Window parent) -> void {
if(!input.ready()) {
MessageDialog({
"Error: failed to initialize [", settings.input.driver, "] input driver."
- }).setParent(parent).error();
+ }).setAlignment(parent).error();
settings.input.driver = "None";
return updateInputDriver(parent);
}
diff --git a/higan/target-bsnes/program/patch.cpp b/higan/target-bsnes/program/patch.cpp
index c01a772f..9695e0df 100644
--- a/higan/target-bsnes/program/patch.cpp
+++ b/higan/target-bsnes/program/patch.cpp
@@ -119,6 +119,6 @@ auto Program::applyPatchBPS(vector& input, string location) -> bool {
MessageDialog({
error, "\n\n",
"Please ensure you are using the correct (headerless) ROM for this patch."
- }).setParent(*presentation).error();
+ }).setAlignment(*presentation).error();
return false;
}
diff --git a/higan/target-bsnes/program/platform.cpp b/higan/target-bsnes/program/platform.cpp
index e794a1f9..51775255 100644
--- a/higan/target-bsnes/program/platform.cpp
+++ b/higan/target-bsnes/program/platform.cpp
@@ -91,7 +91,7 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) ->
if(MessageDialog({
"Error: missing required data: ", name, "\n\n",
"Would you like to view the online documentation for more information?"
- }).setParent(*presentation).error({"Yes", "No"}) == "Yes") {
+ }).setAlignment(*presentation).error({"Yes", "No"}) == "Yes") {
presentation.documentation.doActivate();
}
}
@@ -101,7 +101,7 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) ->
auto Program::load(uint id, string name, string type, vector options) -> Emulator::Platform::Load {
BrowserDialog dialog;
- dialog.setParent(*presentation);
+ dialog.setAlignment(*presentation);
dialog.setOptions(options);
if(id == 1 && name == "Super Famicom" && type == "sfc") {
diff --git a/higan/target-bsnes/program/program.cpp b/higan/target-bsnes/program/program.cpp
index fedb52fd..1803c4ff 100644
--- a/higan/target-bsnes/program/program.cpp
+++ b/higan/target-bsnes/program/program.cpp
@@ -40,7 +40,7 @@ auto Program::create() -> void {
MessageDialog(
"Driver crash detected. Hardware drivers have been disabled.\n"
"Please reconfigure drivers in the advanced settings panel."
- ).setParent(*presentation).information();
+ ).setAlignment(*presentation).information();
settings.video.driver = "None";
settings.audio.driver = "None";
settings.input.driver = "None";
@@ -90,5 +90,5 @@ auto Program::quit() -> void {
video.reset();
audio.reset();
input.reset();
- Application::kill();
+ Application::exit();
}
diff --git a/higan/target-bsnes/program/video.cpp b/higan/target-bsnes/program/video.cpp
index cb92be7f..b462740b 100644
--- a/higan/target-bsnes/program/video.cpp
+++ b/higan/target-bsnes/program/video.cpp
@@ -24,7 +24,7 @@ auto Program::updateVideoDriver(Window parent) -> void {
if(!video.ready()) {
MessageDialog({
"Error: failed to initialize [", settings.video.driver, "] video driver."
- }).setParent(parent).error();
+ }).setAlignment(parent).error();
settings.video.driver = "None";
return updateVideoDriver(parent);
}
diff --git a/higan/target-bsnes/resource/bsnes.Manifest b/higan/target-bsnes/resource/bsnes.Manifest
index c429a86b..c84422c6 100644
--- a/higan/target-bsnes/resource/bsnes.Manifest
+++ b/higan/target-bsnes/resource/bsnes.Manifest
@@ -7,8 +7,9 @@
-
- false
+
+ true/pm
+ PerMonitorV2, PerMonitor
diff --git a/higan/target-bsnes/resource/resource.cpp b/higan/target-bsnes/resource/resource.cpp
index fb28bcd7..ebb04639 100644
--- a/higan/target-bsnes/resource/resource.cpp
+++ b/higan/target-bsnes/resource/resource.cpp
@@ -849,7 +849,7 @@ const unsigned char Logo[23467] = {
0,0,0,73,69,78,68,174,66,96,130,
};
namespace System {
-const char Boards[30183] = {
+const char Boards[30188] = {
100,97,116,97,98,97,115,101,10,32,32,114,101,118,105,115,105,111,110,58,32,50,48,49,56,45,48,55,45,50,53,10,
10,47,47,66,111,97,114,100,115,32,40,80,114,111,100,117,99,116,105,111,110,41,10,10,100,97,116,97,98,97,115,101,
10,32,32,114,101,118,105,115,105,111,110,58,32,50,48,49,56,45,48,53,45,49,54,10,10,98,111,97,114,100,58,32,
@@ -1090,490 +1090,294 @@ const char Boards[30183] = {
110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,
51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,115,105,122,101,61,48,120,50,48,48,48,10,32,
32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,49,58,48,48,48,48,45,102,102,102,102,
- 10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,67,66,53,66,45,50,48,10,32,32,112,114,111,99,101,115,115,
- 111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,71,83,85,10,32,32,32,32,109,97,112,32,97,100,100,114,
- 101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,52,102,102,10,32,32,32,32,109,101,
- 109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,
- 32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,58,56,48,48,48,45,102,102,102,102,32,
- 109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,
- 45,53,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,
- 77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,
- 61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,115,105,122,101,61,48,120,50,48,
- 48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,49,58,48,48,48,48,45,
- 102,102,102,102,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,67,66,55,66,45,48,49,10,32,32,112,114,111,
- 99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,71,83,85,10,32,32,32,32,109,97,112,32,
- 97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,52,102,102,10,32,32,
- 32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,
- 109,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,58,56,48,48,48,45,102,
- 102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
- 115,61,52,48,45,53,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,
- 101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,
- 114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,115,105,122,101,61,
- 48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,49,58,48,
- 48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,68,67,48,78,45,48,49,10,32,
- 32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,
- 57,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,99,
- 48,48,45,54,102,102,102,44,55,99,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,
- 101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,97,112,32,
- 97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,
- 115,107,61,48,120,56,48,48,48,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,
- 110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,
- 55,55,58,48,48,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,
- 32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,
- 83,49,54,57,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,
- 61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,10,32,32,32,
- 32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,
- 54,98,102,102,44,55,48,48,48,45,55,98,102,102,32,109,97,115,107,61,48,120,102,48,48,48,10,32,32,32,32,111,
- 115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,68,83,48,66,45,50,48,10,
- 32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,
- 109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,
- 48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,
- 97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,57,54,48,53,48,10,32,32,32,32,109,97,112,32,97,100,
- 100,114,101,115,115,61,54,48,45,54,55,44,101,48,45,101,55,58,48,48,48,48,45,51,102,102,102,10,32,32,32,32,
- 109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,
- 97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,57,54,48,53,48,10,32,32,32,32,109,101,109,111,114,121,
- 32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,
- 117,114,101,61,117,80,68,57,54,48,53,48,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,
- 32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,57,54,
- 48,53,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,54,56,45,54,102,44,101,56,45,101,
- 102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,111,115,99,105,
- 108,108,97,116,111,114,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,74,48,78,45,40,48,49,44,49,48,44,
- 50,48,41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,
- 111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,
- 102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,
- 100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,
- 74,49,77,45,40,49,49,44,50,48,41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,
- 110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,
- 45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,
- 101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,
- 114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,
- 32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,
- 97,115,107,61,48,120,101,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,74,51,66,45,48,49,10,
- 32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,
- 109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,
- 48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,
- 45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,
- 99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,
- 51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,10,
- 98,111,97,114,100,58,32,83,72,86,67,45,49,74,51,77,45,40,48,49,44,49,49,44,50,48,41,10,32,32,109,101,
- 109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,
- 32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,
- 102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,
- 48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,
- 101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,
- 48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,10,98,111,97,114,
- 100,58,32,83,72,86,67,45,49,74,53,77,45,40,48,49,44,49,49,44,50,48,41,10,32,32,109,101,109,111,114,121,
- 32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,
- 112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,
- 32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,
- 45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,
- 83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,
- 58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,10,98,111,97,114,100,58,32,83,
- 72,86,67,45,49,75,48,78,45,48,49,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,
- 110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,
- 45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,
- 101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,112,114,111,99,
- 101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,
- 97,112,32,97,100,100,114,101,115,115,61,48,48,45,49,102,44,56,48,45,57,102,58,54,48,48,48,45,55,102,102,102,
- 32,109,97,115,107,61,48,120,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,
- 99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,
- 55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,
- 61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,
- 101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,
- 105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,
- 10,98,111,97,114,100,58,32,83,72,86,67,45,49,75,49,66,45,48,49,10,32,32,109,101,109,111,114,121,32,116,121,
- 112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,
- 100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,
- 32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,
- 102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,
- 101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,
- 48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,
- 97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,97,112,32,97,100,100,
- 114,101,115,115,61,48,48,45,49,102,44,56,48,45,57,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,
- 48,120,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,
- 116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,
- 32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,
- 97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,
- 116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,
- 114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,
- 58,32,83,72,86,67,45,49,76,48,78,51,83,45,48,49,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,
- 104,105,116,101,99,116,117,114,101,61,87,54,53,67,56,49,54,83,10,32,32,32,32,109,97,112,32,97,100,100,114,101,
- 115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,50,50,48,48,45,50,51,102,102,10,32,32,32,32,109,99,117,
- 10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,
- 48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,52,48,56,48,48,48,10,32,32,32,32,32,32,109,97,112,
- 32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,
- 101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,
- 32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,
- 32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,
- 48,48,45,55,102,102,102,32,115,105,122,101,61,48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,
- 100,114,101,115,115,61,52,48,45,52,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,101,109,111,114,121,
- 32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,73,110,116,101,114,110,97,108,10,32,32,32,32,32,
- 32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,55,
- 102,102,32,115,105,122,101,61,48,120,56,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,76,51,66,45,
- 40,48,50,44,49,49,41,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,
- 61,87,54,53,67,56,49,54,83,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,
- 56,48,45,98,102,58,50,50,48,48,45,50,51,102,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,
- 112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,
- 109,97,115,107,61,48,120,52,48,56,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
- 99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,
- 101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,101,109,111,114,121,
- 32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,
- 32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,115,
- 105,122,101,61,48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,
- 52,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,
- 32,99,111,110,116,101,110,116,61,73,110,116,101,114,110,97,108,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,
- 101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,55,102,102,32,115,105,122,101,61,48,
- 120,56,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,76,53,66,45,40,49,49,44,50,48,41,10,32,
- 32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,87,54,53,67,56,49,54,83,
- 10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,50,50,48,
- 48,45,50,51,102,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,
- 61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,52,48,
- 56,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48,48,
- 48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,
- 116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,
- 32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
- 48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,115,105,122,101,61,48,120,50,48,48,
- 48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,52,102,58,48,48,48,48,45,102,
- 102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,
- 73,110,116,101,114,110,97,108,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,
- 44,56,48,45,98,102,58,51,48,48,48,45,51,55,102,102,32,115,105,122,101,61,48,120,56,48,48,10,10,98,111,97,
- 114,100,58,32,83,72,86,67,45,49,78,48,78,45,40,48,49,44,49,48,41,10,32,32,112,114,111,99,101,115,115,111,
- 114,32,105,100,101,110,116,105,102,105,101,114,61,83,68,68,49,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
- 115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,48,102,10,32,32,32,32,109,99,117,10,
- 32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,
- 48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,
- 48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,
- 99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,65,48,
- 78,45,48,49,35,65,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,
- 61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,50,102,44,56,
- 48,45,97,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,109,
- 97,112,32,97,100,100,114,101,115,115,61,52,48,45,54,102,44,99,48,45,101,102,58,48,48,48,48,45,102,102,102,102,
- 32,109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,65,48,78,45,40,
- 48,49,44,49,48,44,49,49,44,50,48,41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,
- 111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,
- 48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,
- 10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,
- 48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,
- 50,65,49,77,45,48,49,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,
- 116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,
- 56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,
- 109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,
- 97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,
- 32,109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,65,51,66,45,48,
- 49,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,
- 114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,
- 56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,
- 121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,
- 114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,
- 48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,65,51,77,45,48,49,35,65,10,32,32,
- 109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,
- 32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,
- 45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,
- 82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,
- 61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,
- 48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,65,51,77,45,40,48,49,44,49,49,44,50,48,41,10,
- 32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,
- 109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,
- 48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,
- 101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,
- 115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,
- 56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,65,53,77,45,48,49,10,32,32,109,101,109,111,
- 114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,
- 109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,
- 102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,
- 99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,
- 55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,10,
- 98,111,97,114,100,58,32,83,72,86,67,45,50,66,51,66,45,48,49,10,32,32,109,101,109,111,114,121,32,116,121,112,
- 101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,
- 100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,
- 61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,
- 116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,
- 102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,
- 115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,97,
- 112,32,97,100,100,114,101,115,115,61,54,48,45,54,102,44,101,48,45,101,102,58,48,48,48,48,45,55,102,102,102,32,
- 109,97,115,107,61,48,120,51,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,
- 99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,
- 55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,
- 61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,
- 101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,
- 105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,
- 10,98,111,97,114,100,58,32,83,72,86,67,45,50,68,67,48,78,45,48,49,10,32,32,112,114,111,99,101,115,115,111,
- 114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,10,32,32,32,32,109,97,112,
- 32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,99,48,48,45,54,102,102,102,44,55,
- 99,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,
- 116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,
- 48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,
- 10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,
- 101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,55,58,48,48,48,48,45,55,
- 102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,
- 68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,10,32,32,32,32,
- 109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,
- 104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,10,32,32,32,32,32,32,109,97,112,32,97,100,
- 100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,54,98,102,102,44,55,48,48,48,
- 45,55,98,102,102,32,109,97,115,107,61,48,120,102,48,48,48,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,
- 10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,69,51,77,45,48,49,10,32,32,109,101,109,111,114,121,32,116,
- 121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,
- 97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,
- 115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,
- 61,79,66,67,49,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,
- 102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,32,32,109,97,112,32,
- 97,100,100,114,101,115,115,61,55,48,45,55,49,44,102,48,45,102,49,58,54,48,48,48,45,55,102,102,102,44,101,48,
- 48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,32,32,109,101,109,111,114,121,32,116,
- 121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,10,98,111,97,114,100,58,32,83,72,86,
- 67,45,50,74,48,78,45,40,48,49,44,49,48,44,49,49,44,50,48,41,10,32,32,109,101,109,111,114,121,32,116,121,
- 112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,
- 100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,
- 32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,
- 102,102,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,74,51,77,45,40,48,49,44,49,49,44,50,48,41,10,
- 32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,
- 109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,
- 48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,
- 45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,
- 99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,49,48,45,
- 49,102,44,51,48,45,51,102,44,57,48,45,57,102,44,98,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,
- 97,115,107,61,48,120,101,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,74,53,77,45,48,49,10,
- 32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,
- 109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,
- 48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,
- 45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,
- 99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,49,48,45,
- 49,102,44,51,48,45,51,102,44,57,48,45,57,102,44,98,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,
- 97,115,107,61,48,120,101,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,51,74,48,78,45,48,49,10,
- 32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,
- 109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,50,102,44,56,48,45,97,102,58,56,48,
- 48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,54,102,44,99,48,
- 45,101,102,58,48,48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,83,72,86,67,45,66,65,48,78,45,
- 40,48,49,44,49,48,41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,
- 116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,
- 56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,
- 109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,55,102,102,
- 102,32,109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,66,65,49,77,45,
- 48,49,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,
- 103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,
- 58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,
- 116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,
- 100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,
- 61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,66,65,51,77,45,40,48,49,44,49,48,
- 41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,
- 114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,
- 56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,
- 121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,
- 114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,
- 48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,66,74,48,78,45,40,48,49,44,50,48,41,
+ 10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,67,66,53,66,45,40,48,49,44,50,48,41,10,32,32,112,114,
+ 111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,71,83,85,10,32,32,32,32,109,97,112,
+ 32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,52,102,102,10,32,
+ 32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,
+ 97,109,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,58,56,48,48,48,45,
+ 102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,
+ 115,115,61,52,48,45,53,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,
+ 112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,
+ 100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,115,105,122,101,
+ 61,48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,49,58,
+ 48,48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,67,66,55,66,45,48,49,10,
+ 32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,71,83,85,10,32,32,32,
+ 32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,52,
+ 102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,
+ 114,111,103,114,97,109,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,58,56,
+ 48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,
+ 100,100,114,101,115,115,61,52,48,45,53,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,101,109,111,114,
+ 121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,
+ 112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,
+ 115,105,122,101,61,48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,
+ 45,55,49,58,48,48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,68,67,48,78,
+ 45,48,49,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,
+ 49,66,83,49,54,57,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,
+ 98,102,58,54,99,48,48,45,54,102,102,102,44,55,99,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,
+ 121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,
+ 32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,
+ 102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,
+ 65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
+ 115,61,55,48,45,55,55,58,48,48,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,
+ 101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,
+ 72,71,53,49,66,83,49,54,57,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,
+ 110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,
+ 57,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,
+ 54,48,48,48,45,54,98,102,102,44,55,48,48,48,45,55,98,102,102,32,109,97,115,107,61,48,120,102,48,48,48,10,
+ 32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,68,83,48,
+ 66,45,50,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,
+ 114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,
+ 102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,
+ 115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,57,54,48,53,48,10,32,32,32,32,109,
+ 97,112,32,97,100,100,114,101,115,115,61,54,48,45,54,55,44,101,48,45,101,55,58,48,48,48,48,45,51,102,102,102,
+ 10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,
+ 103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,57,54,48,53,48,10,32,32,32,32,109,
+ 101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,
+ 105,116,101,99,116,117,114,101,61,117,80,68,57,54,48,53,48,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,
+ 101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,
+ 117,80,68,57,54,48,53,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,54,56,45,54,102,
+ 44,101,56,45,101,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,
+ 32,111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,74,48,78,45,40,48,
+ 49,44,49,48,44,50,48,41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,
+ 110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,
+ 44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,
+ 61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,83,
+ 72,86,67,45,49,74,49,77,45,40,49,49,44,50,48,41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,
+ 79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,
+ 115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,
+ 32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,
+ 32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,
+ 32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,
+ 102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,74,51,
+ 66,45,48,49,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,
+ 114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,
+ 98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,
+ 55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,
+ 61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
+ 115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,
+ 48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,74,51,77,45,40,48,49,44,49,49,44,50,48,41,
10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,
97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,
48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,
- 48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,83,72,86,67,45,66,74,49,77,
- 45,40,49,48,44,50,48,41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,
- 110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,
- 44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,
- 61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,
- 116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,
- 100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,
- 61,48,120,101,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,66,74,51,77,45,40,49,48,44,50,48,
- 41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,
- 114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,
- 56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,
- 99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,
- 77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,
- 48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,
- 10,10,98,111,97,114,100,58,32,83,72,86,67,45,76,68,72,51,67,45,48,49,10,32,32,112,114,111,99,101,115,115,
- 111,114,32,105,100,101,110,116,105,102,105,101,114,61,83,80,67,55,49,49,48,10,32,32,32,32,109,97,112,32,97,100,
- 100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,51,102,10,32,32,32,32,
- 109,97,112,32,97,100,100,114,101,115,115,61,53,48,44,53,56,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,
- 109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,
- 102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,48,48,10,32,32,32,32,32,32,
- 109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,
- 61,48,120,99,48,48,48,48,48,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,
- 99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,
- 101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,10,32,32,32,32,109,101,109,111,114,121,32,116,121,
- 112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,
- 100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,
- 61,48,120,101,48,48,48,10,32,32,114,116,99,32,109,97,110,117,102,97,99,116,117,114,101,114,61,69,112,115,111,110,
- 10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,52,
- 48,45,52,56,52,50,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,84,67,32,99,111,110,116,101,
- 110,116,61,84,105,109,101,32,109,97,110,117,102,97,99,116,117,114,101,114,61,69,112,115,111,110,10,10,98,111,97,114,
- 100,58,32,83,72,86,67,45,76,78,51,66,45,48,49,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,
- 77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,
- 48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,
- 10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,51,58,48,48,48,48,45,102,102,102,102,
- 10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,83,68,68,49,10,32,32,32,
- 32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,
- 48,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,
- 51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,97,112,32,97,100,100,
- 114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,
- 121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,10,98,111,97,114,
- 100,58,32,83,72,86,67,45,83,71,66,50,45,48,49,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,
- 77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
- 115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,
- 48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,
- 48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111,
- 114,32,105,100,101,110,116,105,102,105,101,114,61,73,67,68,32,114,101,118,105,115,105,111,110,61,50,10,32,32,32,32,
- 109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,54,55,102,
- 102,44,55,48,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,
- 99,111,110,116,101,110,116,61,66,111,111,116,32,97,114,99,104,105,116,101,99,116,117,114,101,61,76,82,51,53,57,48,
- 50,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,32,32,32,32,115,108,111,116,32,116,121,112,101,61,71,
- 97,109,101,66,111,121,10,10,98,111,97,114,100,58,32,83,72,86,67,45,89,65,48,78,45,48,49,10,32,32,109,101,
- 109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,
- 32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,
- 102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
- 52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,
- 48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,89,74,48,78,45,48,49,10,32,32,109,101,109,111,114,121,32,
- 116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,
- 32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,
- 32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,
- 102,102,102,102,10,10,47,47,66,111,97,114,100,115,32,40,71,101,110,101,114,105,99,41,10,10,100,97,116,97,98,97,
- 115,101,10,32,32,114,101,118,105,115,105,111,110,58,32,50,48,49,56,45,48,55,45,50,53,10,10,98,111,97,114,100,
- 58,32,65,82,77,45,76,79,82,79,77,45,82,65,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,
- 77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
- 115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,
- 48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,54,102,44,99,48,45,101,102,58,
- 48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,
- 121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,
- 114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,112,114,111,
- 99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,65,82,77,54,10,32,32,32,32,109,97,112,
- 32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,56,48,48,45,51,56,102,102,10,32,
- 32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,
- 97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,65,82,77,54,10,32,32,32,32,109,101,109,111,114,121,32,
- 116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,
- 114,101,61,65,82,77,54,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,
- 101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,65,82,77,54,10,32,32,32,32,111,
- 115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,32,66,83,45,72,73,82,79,77,45,82,65,77,10,32,
- 32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,
- 10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,49,102,44,56,48,45,57,102,58,56,48,48,
- 48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,53,102,44,99,48,45,
- 100,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,
- 111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,
- 102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,
- 115,108,111,116,32,116,121,112,101,61,66,83,77,101,109,111,114,121,10,32,32,32,32,109,97,112,32,97,100,100,114,101,
- 115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,
- 32,97,100,100,114,101,115,115,61,54,48,45,55,100,44,101,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,10,
- 98,111,97,114,100,58,32,66,83,45,76,79,82,79,77,45,82,65,77,10,32,32,109,101,109,111,114,121,32,116,121,112,
- 101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,
- 100,114,101,115,115,61,48,48,45,49,102,58,56,48,48,48,45,102,102,102,102,32,98,97,115,101,61,48,120,48,48,48,
- 48,48,48,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
- 50,48,45,51,102,58,56,48,48,48,45,102,102,102,102,32,98,97,115,101,61,48,120,49,48,48,48,48,48,32,109,97,
- 115,107,61,48,120,56,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,56,48,45,57,102,58,
- 56,48,48,48,45,102,102,102,102,32,98,97,115,101,61,48,120,50,48,48,48,48,48,32,109,97,115,107,61,48,120,56,
- 48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,97,48,45,98,102,58,56,48,48,48,45,102,
- 102,102,102,32,98,97,115,101,61,48,120,49,48,48,48,48,48,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,
- 109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,
- 32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,
- 102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,115,108,111,116,32,116,121,112,101,61,66,83,77,101,109,
- 111,114,121,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,101,102,58,48,48,48,48,45,102,
- 102,102,102,10,10,98,111,97,114,100,58,32,66,83,45,77,67,67,45,82,65,77,10,32,32,109,101,109,111,114,121,32,
- 116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,
- 100,114,101,115,115,61,49,48,45,49,55,58,53,48,48,48,45,53,102,102,102,32,109,97,115,107,61,48,120,102,48,48,
- 48,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,77,67,67,10,32,32,32,
- 32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,48,102,58,53,48,48,48,45,53,102,102,102,10,32,32,32,
- 32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,
- 98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,
- 48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,97,112,32,97,
- 100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,10,32,32,32,
- 32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,
- 97,109,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,
- 61,68,111,119,110,108,111,97,100,10,32,32,32,32,32,32,115,108,111,116,32,116,121,112,101,61,66,83,77,101,109,111,
- 114,121,10,10,98,111,97,114,100,58,32,66,83,45,83,65,49,45,82,65,77,10,32,32,112,114,111,99,101,115,115,111,
+ 48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,
+ 32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,
+ 45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,
+ 10,98,111,97,114,100,58,32,83,72,86,67,45,49,74,53,77,45,40,48,49,44,49,49,44,50,48,41,10,32,32,109,
+ 101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,
+ 32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,
+ 102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,
+ 58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,
+ 116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,
+ 97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,10,98,111,97,
+ 114,100,58,32,83,72,86,67,45,49,75,48,78,45,48,49,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,
+ 79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,
+ 115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,
+ 32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,
+ 32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,
+ 32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,49,102,44,56,48,45,57,102,58,54,48,48,48,
+ 45,55,102,102,102,32,109,97,115,107,61,48,120,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,
+ 61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,
+ 101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,
+ 110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,
+ 32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,
+ 32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,
+ 97,116,111,114,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,75,49,66,45,48,49,10,32,32,109,101,109,111,
+ 114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,
+ 109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,
+ 102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,
+ 48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,
+ 116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,
+ 98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,112,114,111,99,101,
+ 115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,97,
+ 112,32,97,100,100,114,101,115,115,61,48,48,45,49,102,44,56,48,45,57,102,58,54,48,48,48,45,55,102,102,102,32,
+ 109,97,115,107,61,48,120,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,
+ 111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,
+ 55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,
+ 68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,
+ 109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,
+ 116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,
+ 98,111,97,114,100,58,32,83,72,86,67,45,49,76,48,78,51,83,45,48,49,10,32,32,112,114,111,99,101,115,115,111,
114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,87,54,53,67,56,49,54,83,10,32,32,32,32,109,97,112,32,
97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,50,50,48,48,45,50,51,102,102,10,32,32,
32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,
45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,52,48,56,48,48,48,10,32,32,32,32,
32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,
32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,
- 114,97,109,10,32,32,32,32,32,32,115,108,111,116,32,116,121,112,101,61,66,83,77,101,109,111,114,121,10,32,32,32,
- 32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,
- 32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,
- 45,55,102,102,102,32,115,105,122,101,61,48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,
- 101,115,115,61,52,48,45,52,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,
- 121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,73,110,116,101,114,110,97,108,10,32,32,32,32,32,32,109,
- 97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,55,102,102,
- 32,115,105,122,101,61,48,120,56,48,48,10,10,98,111,97,114,100,58,32,69,86,69,78,84,45,67,67,57,50,10,32,
- 32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,
- 32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,
- 102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,109,97,110,117,
- 102,97,99,116,117,114,101,114,61,78,69,67,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,56,50,
- 49,52,10,32,32,32,32,105,100,101,110,116,105,102,105,101,114,58,32,67,97,109,112,117,115,32,67,104,97,108,108,101,
- 110,103,101,32,39,57,50,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,44,101,48,58,48,48,
- 48,48,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,
- 49,102,44,56,48,45,57,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,
- 116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,
- 101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,76,101,118,101,108,45,49,10,32,
- 32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,76,101,118,
- 101,108,45,50,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,
- 110,116,61,76,101,118,101,108,45,51,10,32,32,32,32,100,105,112,10,32,32,112,114,111,99,101,115,115,111,114,32,109,
- 97,110,117,102,97,99,116,117,114,101,114,61,78,69,67,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,
- 55,55,50,53,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,
- 58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,55,102,102,102,10,32,32,32,32,109,101,109,111,114,
- 121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,
- 116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,
- 82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,
- 68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,
- 116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,
- 111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,32,69,86,69,78,84,45,80,70,57,52,10,32,32,
- 109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,
- 32,109,97,112,32,97,100,100,114,101,115,115,61,51,48,45,51,102,44,98,48,45,98,102,58,54,48,48,48,45,55,102,
- 102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,109,97,110,117,102,
- 97,99,116,117,114,101,114,61,78,69,67,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,56,50,49,
- 52,10,32,32,32,32,105,100,101,110,116,105,102,105,101,114,58,32,80,111,119,101,114,70,101,115,116,32,39,57,52,10,
- 32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,49,48,44,50,48,58,54,48,48,48,10,32,32,32,32,109,
- 99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,
- 58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,
- 102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,
- 79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,101,109,111,114,121,32,
- 116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,76,101,118,101,108,45,49,10,32,32,32,32,32,32,109,
- 101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,76,101,118,101,108,45,50,10,32,
- 32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,76,101,118,
- 101,108,45,51,10,32,32,32,32,100,105,112,10,32,32,112,114,111,99,101,115,115,111,114,32,109,97,110,117,102,97,99,
- 116,117,114,101,114,61,78,69,67,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,
- 32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,48,102,44,56,48,45,56,102,58,54,48,48,48,45,
- 55,102,102,102,32,109,97,115,107,61,48,120,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,
- 82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,
- 61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,
- 116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,
- 32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,
- 97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,
- 116,111,114,10,10,98,111,97,114,100,58,32,69,88,72,73,82,79,77,45,82,65,77,10,32,32,109,101,109,111,114,121,
- 32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,
- 112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,58,56,48,48,48,45,102,102,102,102,32,98,97,115,101,61,48,
- 120,52,48,48,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,58,48,48,
- 48,48,45,102,102,102,102,32,98,97,115,101,61,48,120,52,48,48,48,48,48,10,32,32,32,32,109,97,112,32,97,100,
- 100,114,101,115,115,61,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,99,48,48,
- 48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,
- 102,102,102,32,109,97,115,107,61,48,120,99,48,48,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,
- 82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,
- 61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,
- 48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,58,48,48,48,48,45,55,102,
- 102,102,10,10,98,111,97,114,100,58,32,69,88,72,73,82,79,77,45,82,65,77,45,83,72,65,82,80,82,84,67,10,
- 32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,
- 109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,58,56,48,48,48,45,102,102,102,
- 102,32,98,97,115,101,61,48,120,52,48,48,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
- 52,48,45,55,100,58,48,48,48,48,45,102,102,102,102,32,98,97,115,101,61,48,120,52,48,48,48,48,48,10,32,32,
- 32,32,109,97,112,32,97,100,100,114,101,115,115,61,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,
- 115,107,61,48,120,99,48,48,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,
- 102,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,99,48,48,48,48,48,10,32,32,109,101,109,111,
- 114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,
- 32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,
- 97,115,107,61,48,120,101,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,
- 58,48,48,48,48,45,55,102,102,102,10,32,32,114,116,99,32,109,97,110,117,102,97,99,116,117,114,101,114,61,83,104,
- 97,114,112,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,
- 50,56,48,48,45,50,56,48,49,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,84,67,32,99,111,
- 110,116,101,110,116,61,84,105,109,101,32,109,97,110,117,102,97,99,116,117,114,101,114,61,83,104,97,114,112,10,10,98,
- 111,97,114,100,58,32,69,88,78,69,67,45,76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,
+ 114,97,109,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,
+ 83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,
+ 98,102,58,54,48,48,48,45,55,102,102,102,32,115,105,122,101,61,48,120,50,48,48,48,10,32,32,32,32,32,32,109,
+ 97,112,32,97,100,100,114,101,115,115,61,52,48,45,52,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,
+ 101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,73,110,116,101,114,110,97,108,10,
+ 32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,
+ 48,48,45,51,55,102,102,32,115,105,122,101,61,48,120,56,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,
+ 49,76,51,66,45,40,48,50,44,49,49,41,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,
+ 99,116,117,114,101,61,87,54,53,67,56,49,54,83,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,
+ 48,45,51,102,44,56,48,45,98,102,58,50,50,48,48,45,50,51,102,102,10,32,32,32,32,109,99,117,10,32,32,32,
+ 32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,
+ 102,102,102,102,32,109,97,115,107,61,48,120,52,48,56,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,
+ 114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,
+ 121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,
+ 101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,
+ 32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,
+ 102,102,102,32,115,105,122,101,61,48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
+ 115,61,52,48,45,52,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,
+ 101,61,82,65,77,32,99,111,110,116,101,110,116,61,73,110,116,101,114,110,97,108,10,32,32,32,32,32,32,109,97,112,
+ 32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,55,102,102,32,115,
+ 105,122,101,61,48,120,56,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,76,53,66,45,40,49,49,44,
+ 50,48,41,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,87,54,53,
+ 67,56,49,54,83,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,
+ 102,58,50,50,48,48,45,50,51,102,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,
+ 100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,
+ 61,48,120,52,48,56,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,
+ 102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,
+ 77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,
+ 101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,
+ 114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,115,105,122,101,61,
+ 48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,52,102,58,48,
+ 48,48,48,45,102,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,
+ 116,101,110,116,61,73,110,116,101,114,110,97,108,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
+ 48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,55,102,102,32,115,105,122,101,61,48,120,56,48,48,
+ 10,10,98,111,97,114,100,58,32,83,72,86,67,45,49,78,48,78,45,40,48,49,44,49,48,41,10,32,32,112,114,111,
+ 99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,83,68,68,49,10,32,32,32,32,109,97,112,32,97,
+ 100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,48,102,10,32,32,32,
+ 32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,
+ 98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,
+ 48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,
+ 61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,10,98,111,97,114,100,58,32,83,72,86,
+ 67,45,50,65,48,78,45,48,49,35,65,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,
+ 110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,
+ 45,50,102,44,56,48,45,97,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,
+ 32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,54,102,44,99,48,45,101,102,58,48,48,48,48,
+ 45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,
+ 65,48,78,45,40,48,49,44,49,48,44,49,49,44,50,48,41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,
82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,
101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,
- 120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,
- 80,68,57,54,48,53,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,54,48,45,54,55,44,101,48,
- 45,101,55,58,48,48,48,48,45,51,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,
- 77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,
- 80,68,57,54,48,53,48,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,
- 101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,57,54,48,53,48,10,32,
- 32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,
- 97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,57,54,48,53,48,10,32,32,32,32,32,32,109,97,112,32,
- 97,100,100,114,101,115,115,61,54,56,45,54,102,44,101,56,45,101,102,58,48,48,48,48,45,55,102,102,102,32,109,97,
- 115,107,61,48,120,56,48,48,48,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,
- 32,69,88,83,80,67,55,49,49,48,45,82,65,77,45,69,80,83,79,78,82,84,67,10,32,32,109,101,109,111,114,121,
- 32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,69,120,112,97,110,115,105,111,110,10,32,32,32,32,
- 109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,52,102,58,48,48,48,48,45,102,102,102,102,10,32,32,112,114,
+ 120,56,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,
+ 102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,
+ 83,72,86,67,45,50,65,49,77,45,48,49,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,
+ 111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,
+ 48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,
+ 10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,
+ 32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,
+ 45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,
+ 65,51,66,45,48,49,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,
+ 61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,
+ 48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,
+ 111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,
+ 112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,
+ 109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,65,51,77,45,48,49,
+ 35,65,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,
+ 103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,
+ 58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,
+ 116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,
+ 100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,
+ 61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,65,51,77,45,40,48,49,44,49,49,
+ 44,50,48,41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,
+ 114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,
+ 102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,
+ 121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,
+ 97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,
+ 115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,65,53,77,45,48,49,10,32,
+ 32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,
+ 10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,
+ 48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,
+ 61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
+ 115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,
+ 48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,66,51,66,45,48,49,10,32,32,109,101,109,111,114,
+ 121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,
+ 97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,
+ 32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,
+ 111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,
+ 100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,
+ 112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,
+ 32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,54,48,45,54,102,44,101,48,45,101,102,58,48,48,48,48,45,
+ 55,102,102,102,32,109,97,115,107,61,48,120,51,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,
+ 61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,
+ 101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,
+ 110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,
+ 32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,
+ 32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,
+ 97,116,111,114,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,68,67,48,78,45,48,49,10,32,32,112,114,111,
+ 99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,10,32,32,
+ 32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,99,48,48,45,54,
+ 102,102,102,44,55,99,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,
+ 77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,
+ 101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,
+ 120,56,48,48,48,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,
+ 116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,55,58,48,
+ 48,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,
+ 116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,
+ 10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,
+ 97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,10,32,32,32,32,32,32,109,
+ 97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,54,98,102,102,
+ 44,55,48,48,48,45,55,98,102,102,32,109,97,115,107,61,48,120,102,48,48,48,10,32,32,32,32,111,115,99,105,108,
+ 108,97,116,111,114,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,69,51,77,45,48,49,10,32,32,109,101,109,
+ 111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,
+ 32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,
+ 102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,
+ 105,102,105,101,114,61,79,66,67,49,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,
+ 44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,32,
+ 32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,49,44,102,48,45,102,49,58,54,48,48,48,45,55,102,
+ 102,102,44,101,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,32,32,109,101,109,
+ 111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,10,98,111,97,114,100,
+ 58,32,83,72,86,67,45,50,74,48,78,45,40,48,49,44,49,48,44,49,49,44,50,48,41,10,32,32,109,101,109,111,
+ 114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,
+ 109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,
+ 102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,
+ 48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,74,51,77,45,40,48,49,44,49,49,
+ 44,50,48,41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,
+ 114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,
+ 98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,
+ 55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,
+ 61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
+ 115,61,49,48,45,49,102,44,51,48,45,51,102,44,57,48,45,57,102,44,98,48,45,98,102,58,54,48,48,48,45,55,
+ 102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,50,74,53,
+ 77,45,48,49,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,
+ 114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,
+ 98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,
+ 55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,
+ 61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
+ 115,61,49,48,45,49,102,44,51,48,45,51,102,44,57,48,45,57,102,44,98,48,45,98,102,58,54,48,48,48,45,55,
+ 102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,51,74,48,
+ 78,45,48,49,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,
+ 114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,50,102,44,56,48,45,
+ 97,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,
+ 54,102,44,99,48,45,101,102,58,48,48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,83,72,86,67,45,
+ 66,65,48,78,45,40,48,49,44,49,48,41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,
+ 111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,
+ 48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,
+ 10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,
+ 48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,
+ 66,65,49,77,45,48,49,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,
+ 116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,
+ 56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,
+ 109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,
+ 97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,
+ 32,109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,66,65,51,77,45,40,
+ 48,49,44,49,48,41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,
+ 61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,
+ 48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,
+ 111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,
+ 112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,
+ 109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,66,74,48,78,45,40,48,
+ 49,44,50,48,41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,
+ 80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,
+ 45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,
+ 45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,83,72,86,67,
+ 45,66,74,49,77,45,40,49,48,44,50,48,41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,
+ 99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
+ 48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,
+ 100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,
+ 109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,
+ 97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,
+ 32,109,97,115,107,61,48,120,101,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,66,74,51,77,45,40,
+ 49,48,44,50,48,41,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,
+ 61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,
+ 48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,
+ 48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,
+ 112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,
+ 101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,
+ 120,101,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,76,68,72,51,67,45,48,49,10,32,32,112,114,
111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,83,80,67,55,49,49,48,10,32,32,32,32,109,
97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,51,102,
10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,53,48,44,53,56,58,48,48,48,48,45,102,102,102,102,
@@ -1589,70 +1393,281 @@ const char Boards[30183] = {
69,112,115,111,110,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,
102,58,52,56,52,48,45,52,56,52,50,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,84,67,32,
99,111,110,116,101,110,116,61,84,105,109,101,32,109,97,110,117,102,97,99,116,117,114,101,114,61,69,112,115,111,110,10,
- 10,98,111,97,114,100,58,32,71,66,45,76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,
- 79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,
- 115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,
- 56,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,
- 58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,
- 111,114,32,105,100,101,110,116,105,102,105,101,114,61,73,67,68,32,114,101,118,105,115,105,111,110,61,50,10,32,32,32,
- 32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,54,55,
- 102,102,44,55,48,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,
- 32,99,111,110,116,101,110,116,61,66,111,111,116,32,97,114,99,104,105,116,101,99,116,117,114,101,61,76,82,51,53,57,
- 48,50,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,32,32,32,32,115,108,111,116,32,116,121,112,101,61,
- 71,97,109,101,66,111,121,10,10,98,111,97,114,100,58,32,71,83,85,45,82,65,77,10,32,32,112,114,111,99,101,115,
- 115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,71,83,85,10,32,32,32,32,109,97,112,32,97,100,100,
- 114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,52,102,102,10,32,32,32,32,109,
+ 10,98,111,97,114,100,58,32,83,72,86,67,45,76,78,51,66,45,48,49,10,32,32,109,101,109,111,114,121,32,116,121,
+ 112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,
+ 101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,
+ 120,101,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,51,58,48,48,48,48,
+ 45,102,102,102,102,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,83,68,68,
+ 49,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,
+ 48,48,45,52,56,48,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
+ 115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,97,
+ 112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,
+ 109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,
+ 10,98,111,97,114,100,58,32,83,72,86,67,45,83,71,66,50,45,48,49,10,32,32,109,101,109,111,114,121,32,116,121,
+ 112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,
+ 100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,
+ 107,61,48,120,56,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,
+ 48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,
+ 99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,73,67,68,32,114,101,118,105,115,105,111,110,61,50,
+ 10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,
+ 48,45,54,55,102,102,44,55,48,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,
+ 61,82,79,77,32,99,111,110,116,101,110,116,61,66,111,111,116,32,97,114,99,104,105,116,101,99,116,117,114,101,61,76,
+ 82,51,53,57,48,50,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,32,32,32,32,115,108,111,116,32,116,
+ 121,112,101,61,71,97,109,101,66,111,121,10,10,98,111,97,114,100,58,32,83,72,86,67,45,89,65,48,78,45,48,49,
+ 10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,
+ 97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,
+ 48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,
+ 114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,
+ 48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,83,72,86,67,45,89,74,48,78,45,48,49,10,32,32,109,101,
+ 109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,
+ 32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,
+ 102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,
+ 48,48,48,48,45,102,102,102,102,10,10,47,47,66,111,97,114,100,115,32,40,71,101,110,101,114,105,99,41,10,10,100,
+ 97,116,97,98,97,115,101,10,32,32,114,101,118,105,115,105,111,110,58,32,50,48,49,56,45,48,55,45,50,53,10,10,
+ 98,111,97,114,100,58,32,65,82,77,45,76,79,82,79,77,45,82,65,77,10,32,32,109,101,109,111,114,121,32,116,121,
+ 112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,
+ 100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,
+ 107,61,48,120,56,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,54,102,44,99,
+ 48,45,101,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,
+ 111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,
+ 112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,
+ 32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,65,82,77,54,10,32,32,
+ 32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,56,48,48,45,51,
+ 56,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,
+ 80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,65,82,77,54,10,32,32,32,32,109,101,
+ 109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,
+ 116,101,99,116,117,114,101,61,65,82,77,54,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,
+ 32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,65,82,77,54,10,
+ 32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,32,66,83,45,72,73,82,79,77,45,
+ 82,65,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,
+ 111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,49,102,44,56,48,45,57,
+ 102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,53,
+ 102,44,99,48,45,100,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,
+ 82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,
+ 61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,
+ 48,48,10,32,32,115,108,111,116,32,116,121,112,101,61,66,83,77,101,109,111,114,121,10,32,32,32,32,109,97,112,32,
+ 97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,
+ 32,32,109,97,112,32,97,100,100,114,101,115,115,61,54,48,45,55,100,44,101,48,45,102,102,58,48,48,48,48,45,102,
+ 102,102,102,10,10,98,111,97,114,100,58,32,66,83,45,76,79,82,79,77,45,82,65,77,10,32,32,109,101,109,111,114,
+ 121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,
+ 97,112,32,97,100,100,114,101,115,115,61,48,48,45,49,102,58,56,48,48,48,45,102,102,102,102,32,98,97,115,101,61,
+ 48,120,48,48,48,48,48,48,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,
+ 114,101,115,115,61,50,48,45,51,102,58,56,48,48,48,45,102,102,102,102,32,98,97,115,101,61,48,120,49,48,48,48,
+ 48,48,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,56,
+ 48,45,57,102,58,56,48,48,48,45,102,102,102,102,32,98,97,115,101,61,48,120,50,48,48,48,48,48,32,109,97,115,
+ 107,61,48,120,56,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,97,48,45,98,102,58,56,
+ 48,48,48,45,102,102,102,102,32,98,97,115,101,61,48,120,49,48,48,48,48,48,32,109,97,115,107,61,48,120,56,48,
+ 48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,
+ 101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,
+ 48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,115,108,111,116,32,116,121,112,101,61,
+ 66,83,77,101,109,111,114,121,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,101,102,58,48,
+ 48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,66,83,45,77,67,67,45,82,65,77,10,32,32,109,101,
+ 109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,
+ 97,112,32,97,100,100,114,101,115,115,61,49,48,45,49,55,58,53,48,48,48,45,53,102,102,102,32,109,97,115,107,61,
+ 48,120,102,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,77,67,
+ 67,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,48,102,58,53,48,48,48,45,53,102,102,
+ 102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,
+ 102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,
+ 101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,
+ 109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,
+ 102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,
+ 80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,
+ 110,116,101,110,116,61,68,111,119,110,108,111,97,100,10,32,32,32,32,32,32,115,108,111,116,32,116,121,112,101,61,66,
+ 83,77,101,109,111,114,121,10,10,98,111,97,114,100,58,32,66,83,45,83,65,49,45,82,65,77,10,32,32,112,114,111,
+ 99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,87,54,53,67,56,49,54,83,10,32,32,32,
+ 32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,50,50,48,48,45,50,51,
+ 102,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,
+ 51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,52,48,56,48,48,48,
+ 10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,
+ 102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,
+ 61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,115,108,111,116,32,116,121,112,101,61,66,83,77,101,109,111,114,
+ 121,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,
+ 118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,
+ 58,54,48,48,48,45,55,102,102,102,32,115,105,122,101,61,48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,
+ 32,97,100,100,114,101,115,115,61,52,48,45,52,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,101,109,
+ 111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,73,110,116,101,114,110,97,108,10,32,32,
+ 32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,
+ 45,51,55,102,102,32,115,105,122,101,61,48,120,56,48,48,10,10,98,111,97,114,100,58,32,69,86,69,78,84,45,67,
+ 67,57,50,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,
+ 118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,
+ 48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,
+ 32,109,97,110,117,102,97,99,116,117,114,101,114,61,78,69,67,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,
+ 80,68,55,56,50,49,52,10,32,32,32,32,105,100,101,110,116,105,102,105,101,114,58,32,67,97,109,112,117,115,32,67,
+ 104,97,108,108,101,110,103,101,32,39,57,50,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,44,
+ 101,48,58,48,48,48,48,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
+ 115,61,48,48,45,49,102,44,56,48,45,57,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,
+ 109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,
+ 32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,76,101,118,101,
+ 108,45,49,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,
+ 116,61,76,101,118,101,108,45,50,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,
+ 99,111,110,116,101,110,116,61,76,101,118,101,108,45,51,10,32,32,32,32,100,105,112,10,32,32,112,114,111,99,101,115,
+ 115,111,114,32,109,97,110,117,102,97,99,116,117,114,101,114,61,78,69,67,32,97,114,99,104,105,116,101,99,116,117,114,
+ 101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,
+ 97,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,55,102,102,102,10,32,32,32,32,
+ 109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,
+ 97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,
+ 116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,
+ 114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,
+ 111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,
+ 10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,32,69,86,69,78,84,45,80,70,
+ 57,52,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,
+ 101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,51,48,45,51,102,44,98,48,45,98,102,58,54,48,
+ 48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,
+ 109,97,110,117,102,97,99,116,117,114,101,114,61,78,69,67,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,
+ 68,55,56,50,49,52,10,32,32,32,32,105,100,101,110,116,105,102,105,101,114,58,32,80,111,119,101,114,70,101,115,116,
+ 32,39,57,52,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,49,48,44,50,48,58,54,48,48,48,10,
+ 32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,
+ 56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
+ 115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,
+ 121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,101,
+ 109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,76,101,118,101,108,45,49,10,32,32,
+ 32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,76,101,118,101,
+ 108,45,50,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,
+ 116,61,76,101,118,101,108,45,51,10,32,32,32,32,100,105,112,10,32,32,112,114,111,99,101,115,115,111,114,32,109,97,
+ 110,117,102,97,99,116,117,114,101,114,61,78,69,67,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,
+ 55,50,53,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,48,102,44,56,48,45,56,102,58,
+ 54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,
+ 116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,
+ 99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,
+ 77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,
+ 55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,
+ 68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,
+ 99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,32,69,88,72,73,82,79,77,45,82,65,77,10,32,32,109,
101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,
- 32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,
- 48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,
- 114,101,115,115,61,52,48,45,53,102,44,99,48,45,100,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,
- 101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,
- 32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,
- 102,102,102,32,115,105,122,101,61,48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
- 115,61,55,48,45,55,49,44,102,48,45,102,49,58,48,48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,
- 72,73,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,
- 80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,
- 45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,
- 45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,72,73,82,79,
- 77,45,82,65,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,
- 80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,
- 45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,
- 45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,
- 101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,
- 115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,
- 101,48,48,48,10,10,98,111,97,114,100,58,32,72,73,84,65,67,72,73,45,76,79,82,79,77,10,32,32,112,114,111,
- 99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,10,32,32,
- 32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,99,48,48,45,54,
- 102,102,102,44,55,99,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,
- 77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,
- 101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,
- 120,56,48,48,48,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,
- 116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,55,58,48,
- 48,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,
- 116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,
- 10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,
- 97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,10,32,32,32,32,32,32,109,
- 97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,54,98,102,102,
- 44,55,48,48,48,45,55,98,102,102,32,109,97,115,107,61,48,120,102,48,48,48,10,32,32,32,32,111,115,99,105,108,
- 108,97,116,111,114,10,10,98,111,97,114,100,58,32,76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,
- 101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,
- 100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,
- 61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,76,79,82,79,77,45,82,65,77,10,32,32,109,101,109,111,
- 114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,
- 109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,
- 102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,
- 99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,
- 55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,10,
- 98,111,97,114,100,58,32,76,79,82,79,77,45,82,65,77,35,65,10,32,32,109,101,109,111,114,121,32,116,121,112,101,
- 61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,
- 114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,
- 48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,
- 61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,
- 102,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,
- 78,69,67,45,72,73,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,
- 101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,
- 102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
- 115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,112,114,111,99,101,115,
+ 32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,58,56,48,48,48,45,102,102,102,102,32,98,
+ 97,115,101,61,48,120,52,48,48,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,
+ 55,100,58,48,48,48,48,45,102,102,102,102,32,98,97,115,101,61,48,120,52,48,48,48,48,48,10,32,32,32,32,109,
+ 97,112,32,97,100,100,114,101,115,115,61,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,
+ 48,120,99,48,48,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,
+ 48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,99,48,48,48,48,48,10,32,32,109,101,109,111,114,121,32,
+ 116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,
+ 100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,
+ 61,48,120,101,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,58,48,48,
+ 48,48,45,55,102,102,102,10,10,98,111,97,114,100,58,32,69,88,72,73,82,79,77,45,82,65,77,45,83,72,65,82,
+ 80,82,84,67,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,
+ 114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,58,56,48,48,
+ 48,45,102,102,102,102,32,98,97,115,101,61,48,120,52,48,48,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,
+ 114,101,115,115,61,52,48,45,55,100,58,48,48,48,48,45,102,102,102,102,32,98,97,115,101,61,48,120,52,48,48,48,
+ 48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,56,48,45,98,102,58,56,48,48,48,45,102,102,
+ 102,102,32,109,97,115,107,61,48,120,99,48,48,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,
+ 61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,99,48,48,48,48,48,10,32,
+ 32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,
+ 32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,
+ 102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
+ 55,48,45,55,100,58,48,48,48,48,45,55,102,102,102,10,32,32,114,116,99,32,109,97,110,117,102,97,99,116,117,114,
+ 101,114,61,83,104,97,114,112,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,
+ 48,45,98,102,58,50,56,48,48,45,50,56,48,49,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,
+ 84,67,32,99,111,110,116,101,110,116,61,84,105,109,101,32,109,97,110,117,102,97,99,116,117,114,101,114,61,83,104,97,
+ 114,112,10,10,98,111,97,114,100,58,32,69,88,78,69,67,45,76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,
+ 116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,
+ 32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,
+ 97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,
+ 117,114,101,61,117,80,68,57,54,48,53,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,54,48,45,
+ 54,55,44,101,48,45,101,55,58,48,48,48,48,45,51,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,
+ 112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,
+ 117,114,101,61,117,80,68,57,54,48,53,48,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,
+ 32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,57,54,
+ 48,53,48,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,
+ 68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,57,54,48,53,48,10,32,32,32,32,32,
+ 32,109,97,112,32,97,100,100,114,101,115,115,61,54,56,45,54,102,44,101,56,45,101,102,58,48,48,48,48,45,55,102,
+ 102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,
+ 111,97,114,100,58,32,69,88,83,80,67,55,49,49,48,45,82,65,77,45,69,80,83,79,78,82,84,67,10,32,32,109,
+ 101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,69,120,112,97,110,115,105,111,110,
+ 10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,52,102,58,48,48,48,48,45,102,102,102,102,
+ 10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,83,80,67,55,49,49,48,10,
+ 32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,
+ 45,52,56,51,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,53,48,44,53,56,58,48,48,48,48,
+ 45,102,102,102,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
+ 48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,
+ 48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,
+ 45,102,102,102,102,32,109,97,115,107,61,48,120,99,48,48,48,48,48,10,32,32,32,32,32,32,109,101,109,111,114,121,
+ 32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,
+ 109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,10,32,32,32,
+ 32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,
+ 32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,
+ 45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,114,116,99,32,109,97,110,117,102,97,99,116,
+ 117,114,101,114,61,69,112,115,111,110,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,
+ 44,56,48,45,98,102,58,52,56,52,48,45,52,56,52,50,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,
+ 61,82,84,67,32,99,111,110,116,101,110,116,61,84,105,109,101,32,109,97,110,117,102,97,99,116,117,114,101,114,61,69,
+ 112,115,111,110,10,10,98,111,97,114,100,58,32,71,66,45,76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,
+ 121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,
+ 97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,
+ 115,107,61,48,120,56,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,
+ 99,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,
+ 111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,73,67,68,32,114,101,118,105,115,105,111,110,61,
+ 50,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,
+ 48,48,45,54,55,102,102,44,55,48,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,
+ 101,61,82,79,77,32,99,111,110,116,101,110,116,61,66,111,111,116,32,97,114,99,104,105,116,101,99,116,117,114,101,61,
+ 76,82,51,53,57,48,50,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,32,32,32,32,115,108,111,116,32,
+ 116,121,112,101,61,71,97,109,101,66,111,121,10,10,98,111,97,114,100,58,32,71,83,85,45,82,65,77,10,32,32,112,
+ 114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,71,83,85,10,32,32,32,32,109,97,
+ 112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,52,102,102,10,
+ 32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,
+ 114,97,109,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,
+ 102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,32,32,109,97,
+ 112,32,97,100,100,114,101,115,115,61,52,48,45,53,102,44,99,48,45,100,102,58,48,48,48,48,45,102,102,102,102,10,
+ 32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,
+ 10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,
+ 48,48,48,45,55,102,102,102,32,115,105,122,101,61,48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,
+ 100,100,114,101,115,115,61,55,48,45,55,49,44,102,48,45,102,49,58,48,48,48,48,45,102,102,102,102,10,10,98,111,
+ 97,114,100,58,32,72,73,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,
+ 116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,
+ 51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,
+ 115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,
+ 32,72,73,82,79,77,45,82,65,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,
+ 116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,
+ 51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,
+ 115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,
+ 121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,
+ 97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,
+ 115,107,61,48,120,101,48,48,48,10,10,98,111,97,114,100,58,32,72,73,84,65,67,72,73,45,76,79,82,79,77,10,
+ 32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,
+ 54,57,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,
+ 99,48,48,45,54,102,102,102,44,55,99,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,
+ 112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,97,112,
+ 32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,
+ 97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,
+ 111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,
+ 45,55,55,58,48,48,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,
+ 77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,
+ 66,83,49,54,57,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,
+ 116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,10,32,32,
+ 32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,
+ 45,54,98,102,102,44,55,48,48,48,45,55,98,102,102,32,109,97,115,107,61,48,120,102,48,48,48,10,32,32,32,32,
+ 111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,32,76,79,82,79,77,10,32,32,109,101,109,111,114,
+ 121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,
+ 97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,
+ 32,109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,76,79,82,79,77,45,82,65,77,10,32,
+ 32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,
+ 10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,
+ 48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,
+ 61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
+ 115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,
+ 48,48,48,10,10,98,111,97,114,100,58,32,76,79,82,79,77,45,82,65,77,35,65,10,32,32,109,101,109,111,114,121,
+ 32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,
+ 112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,
+ 109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,
+ 110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,
+ 44,102,48,45,102,102,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,
+ 97,114,100,58,32,78,69,67,45,72,73,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,
+ 32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,
+ 61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,
+ 100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,112,
+ 114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,
+ 32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,49,102,44,56,48,45,57,102,58,54,48,48,48,45,55,
+ 102,102,102,32,109,97,115,107,61,48,120,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,
+ 79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,
+ 117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,
+ 101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,
+ 32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,
+ 114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,
+ 111,114,10,10,98,111,97,114,100,58,32,78,69,67,45,72,73,82,79,77,45,82,65,77,10,32,32,109,101,109,111,114,
+ 121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,
+ 97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,
+ 10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,
+ 48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,
+ 61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,
+ 102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,112,114,111,99,101,115,
115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,97,112,
32,97,100,100,114,101,115,115,61,48,48,45,49,102,44,56,48,45,57,102,58,54,48,48,48,45,55,102,102,102,32,109,
97,115,107,61,48,120,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,
@@ -1661,139 +1676,124 @@ const char Boards[30183] = {
97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,
111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,
101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,
- 111,97,114,100,58,32,78,69,67,45,72,73,82,79,77,45,82,65,77,10,32,32,109,101,109,111,114,121,32,116,121,112,
- 101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,
- 100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,
- 109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,
- 102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,
- 10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,
- 48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,97,
- 114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,97,112,32,97,100,100,114,
- 101,115,115,61,48,48,45,49,102,44,56,48,45,57,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,
- 120,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,
- 61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,
- 32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,
- 114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,
- 121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,
- 101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,
- 32,78,69,67,45,76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,
- 116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,
- 49,102,44,56,48,45,57,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,
- 32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,
- 32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,51,48,45,51,102,44,98,48,45,98,102,58,56,48,48,48,
- 45,102,102,102,102,32,109,97,115,107,61,48,120,51,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,
- 101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,
- 114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,
- 111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,
- 10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,
- 97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,
- 108,97,116,111,114,10,10,98,111,97,114,100,58,32,78,69,67,45,76,79,82,79,77,45,82,65,77,10,32,32,109,101,
+ 111,97,114,100,58,32,78,69,67,45,76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,
+ 77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
+ 115,61,48,48,45,49,102,44,56,48,45,57,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,
+ 48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,
+ 55,55,50,53,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,51,48,45,51,102,44,98,48,45,98,102,
+ 58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,51,102,102,102,10,32,32,32,32,109,101,109,111,114,
+ 121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,
+ 116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,
+ 82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,
+ 68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,
+ 116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,
+ 111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,32,78,69,67,45,76,79,82,79,77,45,82,65,77,
+ 10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,
+ 97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,
+ 48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,
+ 112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,
+ 101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,
+ 120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,
+ 80,68,55,55,50,53,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,54,48,45,54,102,44,101,48,45,
+ 101,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,51,102,102,102,10,32,32,32,32,109,101,109,
+ 111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,
+ 104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,
+ 101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,
+ 117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,
+ 101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,
+ 32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,32,78,69,67,45,76,79,82,79,77,45,82,
+ 65,77,35,65,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,
+ 114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,49,102,44,56,48,45,
+ 57,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,
+ 121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,
+ 97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,
+ 112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,
+ 32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,56,48,48,48,45,
+ 102,102,102,102,32,109,97,115,107,61,48,120,51,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,
+ 61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,
+ 101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,
+ 110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,
+ 32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,
+ 32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,
+ 97,116,111,114,10,10,98,111,97,114,100,58,32,79,66,67,49,45,76,79,82,79,77,45,82,65,77,10,32,32,109,101,
109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,
32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,
- 102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,
- 77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,
- 48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,
- 10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,
- 53,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,54,48,45,54,102,44,101,48,45,101,102,58,48,48,
- 48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,51,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,
- 121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,
- 116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,
- 32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,
- 50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,
- 97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,
- 105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,32,78,69,67,45,76,79,82,79,77,45,82,65,77,35,65,10,
- 32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,
- 109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,49,102,44,56,48,45,57,102,58,56,48,
- 48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,
- 101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,
- 115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,112,114,111,99,101,
- 115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,97,
- 112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,
- 109,97,115,107,61,48,120,51,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,
- 99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,
- 55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,
- 61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,
- 101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,
- 105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,
- 10,98,111,97,114,100,58,32,79,66,67,49,45,76,79,82,79,77,45,82,65,77,10,32,32,109,101,109,111,114,121,32,
- 116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,
- 32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,
- 97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,
- 114,61,79,66,67,49,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,
- 98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,32,32,109,97,112,
- 32,97,100,100,114,101,115,115,61,55,48,45,55,49,44,102,48,45,102,49,58,54,48,48,48,45,55,102,102,102,44,101,
- 48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,32,32,109,101,109,111,114,121,32,
- 116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,10,98,111,97,114,100,58,32,83,65,
- 49,45,82,65,77,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,87,
- 54,53,67,56,49,54,83,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,
- 45,98,102,58,50,50,48,48,45,50,51,102,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,
- 97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,
- 115,107,61,48,120,52,48,56,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,
- 45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,
- 82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,101,109,111,114,121,32,116,
- 121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,
- 100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,115,105,122,
- 101,61,48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,52,102,
- 58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,
- 111,110,116,101,110,116,61,73,110,116,101,114,110,97,108,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
- 115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,55,102,102,32,115,105,122,101,61,48,120,56,
- 48,48,10,10,98,111,97,114,100,58,32,83,68,68,49,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,
- 116,105,102,105,101,114,61,83,68,68,49,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,
- 102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,48,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,
- 109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,
- 102,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,
- 102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,
- 116,61,80,114,111,103,114,97,109,10,10,98,111,97,114,100,58,32,83,68,68,49,45,82,65,77,10,32,32,109,101,109,
- 111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,
- 112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,
- 109,97,115,107,61,48,120,101,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,
- 51,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,
- 115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,83,68,68,49,10,32,32,32,32,109,97,112,32,97,100,100,114,
- 101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,48,102,10,32,32,32,32,109,99,
- 117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,
- 56,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,
- 102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,
- 77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,10,98,111,97,114,100,58,32,83,80,67,55,49,49,
- 48,45,82,65,77,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,83,80,67,
- 55,49,49,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,
- 58,52,56,48,48,45,52,56,51,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,53,48,44,53,56,
- 58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,
- 114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,
- 48,120,56,48,48,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,
- 58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,99,48,48,48,48,48,10,32,32,32,32,32,32,109,
- 101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,
- 32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,
- 97,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,
- 118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,
- 58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,10,98,111,97,114,100,58,32,83,
- 80,67,55,49,49,48,45,82,65,77,45,69,80,83,79,78,82,84,67,10,32,32,112,114,111,99,101,115,115,111,114,32,
- 105,100,101,110,116,105,102,105,101,114,61,83,80,67,55,49,49,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,
- 115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,51,102,10,32,32,32,32,109,97,112,
- 32,97,100,100,114,101,115,115,61,53,48,44,53,56,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,99,117,
- 10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,
- 48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,48,48,10,32,32,32,32,32,32,109,97,112,
- 32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,
- 99,48,48,48,48,48,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,
- 116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,
- 79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,
- 82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,
- 115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,
- 101,48,48,48,10,32,32,114,116,99,32,109,97,110,117,102,97,99,116,117,114,101,114,61,69,112,115,111,110,10,32,32,
- 32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,52,48,45,52,
- 56,52,50,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,84,67,32,99,111,110,116,101,110,116,61,
- 84,105,109,101,32,109,97,110,117,102,97,99,116,117,114,101,114,61,69,112,115,111,110,10,10,98,111,97,114,100,58,32,
- 83,84,45,76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,
- 110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,49,102,
- 44,56,48,45,57,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,115,
- 108,111,116,32,116,121,112,101,61,83,117,102,97,109,105,84,117,114,98,111,10,32,32,32,32,114,111,109,10,32,32,32,
- 32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,56,48,48,48,45,
- 102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,114,97,109,10,32,32,32,32,32,32,109,
- 97,112,32,97,100,100,114,101,115,115,61,54,48,45,54,102,44,101,48,45,101,102,58,48,48,48,48,45,102,102,102,102,
- 10,32,32,115,108,111,116,32,116,121,112,101,61,83,117,102,97,109,105,84,117,114,98,111,10,32,32,32,32,114,111,109,
- 10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,53,102,44,99,48,45,100,102,58,48,
- 48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,114,97,109,10,32,32,32,
- 32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,
- 102,102,102,102,10,10,
+ 102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,
+ 116,105,102,105,101,114,61,79,66,67,49,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,
+ 102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,
+ 32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,49,44,102,48,45,102,49,58,54,48,48,48,45,55,
+ 102,102,102,44,101,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,32,32,109,101,
+ 109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,10,98,111,97,114,
+ 100,58,32,83,65,49,45,82,65,77,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,
+ 117,114,101,61,87,54,53,67,56,49,54,83,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,
+ 51,102,44,56,48,45,98,102,58,50,50,48,48,45,50,51,102,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,
+ 32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,
+ 102,102,32,109,97,115,107,61,48,120,52,48,56,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,
+ 115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,
+ 116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,101,109,
+ 111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,
+ 109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,
+ 102,32,115,105,122,101,61,48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
+ 52,48,45,52,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,
+ 82,65,77,32,99,111,110,116,101,110,116,61,73,110,116,101,114,110,97,108,10,32,32,32,32,32,32,109,97,112,32,97,
+ 100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,55,102,102,32,115,105,122,
+ 101,61,48,120,56,48,48,10,10,98,111,97,114,100,58,32,83,68,68,49,10,32,32,112,114,111,99,101,115,115,111,114,
+ 32,105,100,101,110,116,105,102,105,101,114,61,83,68,68,49,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,
+ 61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,48,102,10,32,32,32,32,109,99,117,10,32,
+ 32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,
+ 48,45,102,102,102,102,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,
+ 48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,
+ 111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,10,98,111,97,114,100,58,32,83,68,68,49,45,82,65,77,10,
+ 32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,
+ 32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,
+ 55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,
+ 61,55,48,45,55,51,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,
+ 114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,83,68,68,49,10,32,32,32,32,109,97,112,
+ 32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,48,102,10,32,
+ 32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,
+ 48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,
+ 61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,
+ 112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,10,98,111,97,114,100,58,32,83,
+ 80,67,55,49,49,48,45,82,65,77,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,
+ 114,61,83,80,67,55,49,49,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,
+ 56,48,45,98,102,58,52,56,48,48,45,52,56,51,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
+ 53,48,44,53,56,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,
+ 112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,
+ 109,97,115,107,61,48,120,56,48,48,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
+ 99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,99,48,48,48,48,48,10,32,32,
+ 32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,
+ 114,97,109,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,
+ 116,61,68,97,116,97,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,
+ 110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,
+ 56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,10,98,111,97,
+ 114,100,58,32,83,80,67,55,49,49,48,45,82,65,77,45,69,80,83,79,78,82,84,67,10,32,32,112,114,111,99,101,
+ 115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,83,80,67,55,49,49,48,10,32,32,32,32,109,97,112,32,
+ 97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,51,102,10,32,32,
+ 32,32,109,97,112,32,97,100,100,114,101,115,115,61,53,48,44,53,56,58,48,48,48,48,45,102,102,102,102,10,32,32,
+ 32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,
+ 45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,48,48,10,32,32,32,32,
+ 32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,32,109,97,
+ 115,107,61,48,120,99,48,48,48,48,48,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,
+ 77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,
+ 121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,10,32,32,32,32,109,101,109,111,114,121,32,
+ 116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,
+ 97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,
+ 115,107,61,48,120,101,48,48,48,10,32,32,114,116,99,32,109,97,110,117,102,97,99,116,117,114,101,114,61,69,112,115,
+ 111,110,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,
+ 56,52,48,45,52,56,52,50,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,84,67,32,99,111,110,
+ 116,101,110,116,61,84,105,109,101,32,109,97,110,117,102,97,99,116,117,114,101,114,61,69,112,115,111,110,10,10,98,111,
+ 97,114,100,58,32,83,84,45,76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,
+ 99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
+ 48,48,45,49,102,44,56,48,45,57,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,
+ 48,10,32,32,115,108,111,116,32,116,121,112,101,61,83,117,102,97,109,105,84,117,114,98,111,10,32,32,32,32,114,111,
+ 109,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,
+ 56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,114,97,109,10,32,32,
+ 32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,54,48,45,54,102,44,101,48,45,101,102,58,48,48,48,48,
+ 45,102,102,102,102,10,32,32,115,108,111,116,32,116,121,112,101,61,83,117,102,97,109,105,84,117,114,98,111,10,32,32,
+ 32,32,114,111,109,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,53,102,44,99,48,
+ 45,100,102,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,114,97,
+ 109,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,
+ 48,48,48,48,45,102,102,102,102,10,10,
};
const unsigned char IPLROM[64] = {
205,239,189,232,0,198,29,208,252,143,170,244,143,187,245,120,204,244,208,251,47,25,235,244,208,252,126,244,208,11,228,245,
diff --git a/higan/target-bsnes/resource/resource.hpp b/higan/target-bsnes/resource/resource.hpp
index 833f43c2..dfa53ec3 100644
--- a/higan/target-bsnes/resource/resource.hpp
+++ b/higan/target-bsnes/resource/resource.hpp
@@ -2,7 +2,7 @@ namespace Resource {
extern const unsigned char Icon[3463];
extern const unsigned char Logo[23467];
namespace System {
-extern const char Boards[30183];
+extern const char Boards[30188];
extern const unsigned char IPLROM[64];
}
}
diff --git a/higan/target-bsnes/settings/audio.cpp b/higan/target-bsnes/settings/audio.cpp
index ab9e539e..500db81e 100644
--- a/higan/target-bsnes/settings/audio.cpp
+++ b/higan/target-bsnes/settings/audio.cpp
@@ -2,7 +2,7 @@ auto AudioSettings::create() -> void {
setIcon(Icon::Device::Speaker);
setText("Audio");
- layout.setPadding(5);
+ layout.setPadding(5_sx);
effectsLabel.setFont(Font().setBold()).setText("Effects");
effectsLayout.setSize({3, 3});
diff --git a/higan/target-bsnes/settings/drivers.cpp b/higan/target-bsnes/settings/drivers.cpp
index 740291c1..59d0a573 100644
--- a/higan/target-bsnes/settings/drivers.cpp
+++ b/higan/target-bsnes/settings/drivers.cpp
@@ -2,7 +2,7 @@ auto DriverSettings::create() -> void {
setIcon(Icon::Place::Settings);
setText("Drivers");
- layout.setPadding(5);
+ layout.setPadding(5_sx);
videoLabel.setText("Video").setFont(Font().setBold());
videoLayout.setSize({2, 2});
@@ -77,7 +77,7 @@ auto DriverSettings::create() -> void {
presentation.speedMenu.setEnabled(!videoBlockingToggle.checked() && audioBlockingToggle.checked());
});
audioDynamicToggle.setText("Dynamic rate").setToolTip(
- "(OSS, XAudio drivers only)\n\n"
+ "(OSS, XAudio2, waveOut drivers only)\n\n"
"Dynamically adjusts the audio frequency by tiny amounts.\n"
"Use this with video sync enabled, and audio sync disabled.\n\n"
"This can produce perfectly smooth video and clean audio,\n"
@@ -132,7 +132,7 @@ auto DriverSettings::videoDriverChange() -> void {
"Warning: incompatible drivers may cause bsnes to crash.\n"
"It is highly recommended you unload your game first to be safe.\n"
"Do you wish to proceed with the video driver change now anyway?"
- ).setParent(*settingsWindow).question() == "Yes") {
+ ).setAlignment(*settingsWindow).question() == "Yes") {
program.save();
program.saveUndoState();
settings.general.crashed = true;
@@ -189,7 +189,7 @@ auto DriverSettings::audioDriverChange() -> void {
"Warning: incompatible drivers may cause bsnes to crash.\n"
"It is highly recommended you unload your game first to be safe.\n"
"Do you wish to proceed with the audio driver change now anyway?"
- ).setParent(*settingsWindow).question() == "Yes") {
+ ).setAlignment(*settingsWindow).question() == "Yes") {
program.save();
program.saveUndoState();
settings.general.crashed = true;
@@ -275,7 +275,7 @@ auto DriverSettings::inputDriverChange() -> void {
"Warning: incompatible drivers may cause bsnes to crash.\n"
"It is highly recommended you unload your game first to be safe.\n"
"Do you wish to proceed with the input driver change now anyway?"
- ).setParent(*settingsWindow).question() == "Yes") {
+ ).setAlignment(*settingsWindow).question() == "Yes") {
program.save();
program.saveUndoState();
settings.general.crashed = true;
diff --git a/higan/target-bsnes/settings/emulator.cpp b/higan/target-bsnes/settings/emulator.cpp
index 6ce69274..52641c80 100644
--- a/higan/target-bsnes/settings/emulator.cpp
+++ b/higan/target-bsnes/settings/emulator.cpp
@@ -2,7 +2,7 @@ auto EmulatorSettings::create() -> void {
setIcon(Icon::Action::Settings);
setText("Emulator");
- layout.setPadding(5);
+ layout.setPadding(5_sx);
optionsLabel.setText("Options").setFont(Font().setBold());
inputFocusLabel.setText("When focus is lost:");
@@ -60,6 +60,9 @@ auto EmulatorSettings::create() -> void {
coprocessorsDelayedSyncOption.setText("Fast coprocessors (delayed sync)").setChecked(settings.emulator.hack.coprocessors.delayedSync).onToggle([&] {
settings.emulator.hack.coprocessors.delayedSync = coprocessorsDelayedSyncOption.checked();
});
+ coprocessorsHLEOption.setText("Prefer HLE for coprocessors").setChecked(settings.emulator.hack.coprocessors.hle).onToggle([&] {
+ settings.emulator.hack.coprocessors.hle = coprocessorsHLEOption.checked();
+ });
superFXLabel.setText("SuperFX clock speed:");
superFXValue.setAlignment(0.5);
superFXClock.setLength(71).setPosition((settings.emulator.hack.fastSuperFX - 100) / 10).onChange([&] {
@@ -75,4 +78,5 @@ auto EmulatorSettings::updateConfiguration() -> void {
emulator->configure("Hacks/FastPPU/HiresMode7", hiresMode7.checked());
emulator->configure("Hacks/FastDSP/Enable", fastDSPOption.checked());
emulator->configure("Hacks/Coprocessor/DelayedSync", coprocessorsDelayedSyncOption.checked());
+ emulator->configure("Hacks/Coprocessor/HLE", coprocessorsHLEOption.checked());
}
diff --git a/higan/target-bsnes/settings/hotkeys.cpp b/higan/target-bsnes/settings/hotkeys.cpp
index 432e5c2d..f1e93620 100644
--- a/higan/target-bsnes/settings/hotkeys.cpp
+++ b/higan/target-bsnes/settings/hotkeys.cpp
@@ -2,7 +2,7 @@ auto HotkeySettings::create() -> void {
setIcon(Icon::Device::Keyboard);
setText("Hotkeys");
- layout.setPadding(5);
+ layout.setPadding(5_sx);
mappingList.setBatchable();
mappingList.setHeadered();
mappingList.onActivate([&] {
diff --git a/higan/target-bsnes/settings/input.cpp b/higan/target-bsnes/settings/input.cpp
index e5c01b2e..e2da602d 100644
--- a/higan/target-bsnes/settings/input.cpp
+++ b/higan/target-bsnes/settings/input.cpp
@@ -2,7 +2,7 @@ auto InputSettings::create() -> void {
setIcon(Icon::Device::Joypad);
setText("Input");
- layout.setPadding(5);
+ layout.setPadding(5_sx);
portLabel.setText("Port:");
portList.onChange([&] { reloadDevices(); });
deviceLabel.setText("Device:");
diff --git a/higan/target-bsnes/settings/paths.cpp b/higan/target-bsnes/settings/paths.cpp
index 9869d659..661389e3 100644
--- a/higan/target-bsnes/settings/paths.cpp
+++ b/higan/target-bsnes/settings/paths.cpp
@@ -2,14 +2,14 @@ auto PathSettings::create() -> void {
setIcon(Icon::Emblem::Folder);
setText("Paths");
- layout.setPadding(5);
+ layout.setPadding(5_sx);
layout.setSize({4, 6});
layout.column(0).setAlignment(1.0);
gamesLabel.setText("Games:");
gamesPath.setEditable(false);
gamesAssign.setText("Assign ...").onActivate([&] {
- if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) {
+ if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
settings.path.games = location;
refreshPaths();
}
@@ -22,7 +22,7 @@ auto PathSettings::create() -> void {
patchesLabel.setText("Patches:");
patchesPath.setEditable(false);
patchesAssign.setText("Assign ...").onActivate([&] {
- if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) {
+ if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
settings.path.patches = location;
refreshPaths();
}
@@ -35,7 +35,7 @@ auto PathSettings::create() -> void {
savesLabel.setText("Saves:");
savesPath.setEditable(false);
savesAssign.setText("Assign ...").onActivate([&] {
- if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) {
+ if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
settings.path.saves = location;
refreshPaths();
}
@@ -48,7 +48,7 @@ auto PathSettings::create() -> void {
cheatsLabel.setText("Cheats:");
cheatsPath.setEditable(false);
cheatsAssign.setText("Assign ...").onActivate([&] {
- if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) {
+ if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
settings.path.cheats = location;
refreshPaths();
}
@@ -61,7 +61,7 @@ auto PathSettings::create() -> void {
statesLabel.setText("States:");
statesPath.setEditable(false);
statesAssign.setText("Assign ...").onActivate([&] {
- if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) {
+ if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
settings.path.states = location;
refreshPaths();
}
@@ -74,7 +74,7 @@ auto PathSettings::create() -> void {
screenshotsLabel.setText("Screenshots:");
screenshotsPath.setEditable(false);
screenshotsAssign.setText("Assign ...").onActivate([&] {
- if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) {
+ if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
settings.path.screenshots = location;
refreshPaths();
}
diff --git a/higan/target-bsnes/settings/settings.cpp b/higan/target-bsnes/settings/settings.cpp
index 0f6c3dd5..7e5b83b3 100644
--- a/higan/target-bsnes/settings/settings.cpp
+++ b/higan/target-bsnes/settings/settings.cpp
@@ -100,6 +100,7 @@ auto Settings::process(bool load) -> void {
bind(boolean, "Emulator/Hack/FastPPU/HiresMode7", emulator.hack.fastPPU.hiresMode7);
bind(boolean, "Emulator/Hack/FastDSP/Enable", emulator.hack.fastDSP.enable);
bind(boolean, "Emulator/Hack/Coprocessors/DelayedSync", emulator.hack.coprocessors.delayedSync);
+ bind(boolean, "Emulator/Hack/Coprocessors/HLE", emulator.hack.coprocessors.hle);
bind(natural, "Emulator/Hack/FastSuperFX", emulator.hack.fastSuperFX);
bind(boolean, "Emulator/Cheats/Enable", emulator.cheats.enable);
@@ -112,7 +113,7 @@ auto Settings::process(bool load) -> void {
}
auto SettingsWindow::create() -> void {
- layout.setPadding(5);
+ layout.setPadding(5_sx);
panel.append(videoSettings);
panel.append(audioSettings);
panel.append(inputSettings);
@@ -123,7 +124,7 @@ auto SettingsWindow::create() -> void {
statusBar.setFont(Font().setBold());
setTitle("Settings");
- setSize({600, 400});
+ setSize({600_sx, 400_sx});
setAlignment({0.0, 1.0});
setDismissable();
diff --git a/higan/target-bsnes/settings/settings.hpp b/higan/target-bsnes/settings/settings.hpp
index 7e2d65f3..4c781d04 100644
--- a/higan/target-bsnes/settings/settings.hpp
+++ b/higan/target-bsnes/settings/settings.hpp
@@ -1,4 +1,6 @@
struct Settings : Markup::Node {
+ using string = nall::string;
+
auto load() -> void;
auto save() -> void;
auto process(bool load) -> void;
@@ -83,6 +85,7 @@ struct Settings : Markup::Node {
} fastDSP;
struct Coprocessors {
bool delayedSync = true;
+ bool hle = true;
} coprocessors;
uint fastSuperFX = 100;
} hack;
@@ -107,15 +110,15 @@ private:
Label colorAdjustmentLabel{&layout, Size{~0, 0}, 2};
TableLayout colorLayout{&layout, Size{~0, 0}};
Label luminanceLabel{&colorLayout, Size{0, 0}};
- Label luminanceValue{&colorLayout, Size{50, 0}};
+ Label luminanceValue{&colorLayout, Size{50_sx, 0}};
HorizontalSlider luminanceSlider{&colorLayout, Size{~0, 0}};
//
Label saturationLabel{&colorLayout, Size{0, 0}};
- Label saturationValue{&colorLayout, Size{50, 0}};
+ Label saturationValue{&colorLayout, Size{50_sx, 0}};
HorizontalSlider saturationSlider{&colorLayout, Size{~0, 0}};
//
Label gammaLabel{&colorLayout, Size{0, 0}};
- Label gammaValue{&colorLayout, Size{50, 0}};
+ Label gammaValue{&colorLayout, Size{50_sx, 0}};
HorizontalSlider gammaSlider{&colorLayout, Size{~0, 0}};
};
@@ -127,15 +130,15 @@ private:
Label effectsLabel{&layout, Size{~0, 0}, 2};
TableLayout effectsLayout{&layout, Size{~0, 0}};
Label skewLabel{&effectsLayout, Size{0, 0}};
- Label skewValue{&effectsLayout, Size{50, 0}};
+ Label skewValue{&effectsLayout, Size{50_sx, 0}};
HorizontalSlider skewSlider{&effectsLayout, Size{~0, 0}};
//
Label volumeLabel{&effectsLayout, Size{0, 0}};
- Label volumeValue{&effectsLayout, Size{50, 0}};
+ Label volumeValue{&effectsLayout, Size{50_sx, 0}};
HorizontalSlider volumeSlider{&effectsLayout, Size{~0, 0}};
//
Label balanceLabel{&effectsLayout, Size{0, 0}};
- Label balanceValue{&effectsLayout, Size{50, 0}};
+ Label balanceValue{&effectsLayout, Size{50_sx, 0}};
HorizontalSlider balanceSlider{&effectsLayout, Size{~0, 0}};
};
@@ -168,12 +171,12 @@ private:
ComboButton turboList{&selectionLayout, Size{0, 0}};
TableView mappingList{&layout, Size{~0, ~0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
- Button assignMouse1{&controlLayout, Size{100, 0}};
- Button assignMouse2{&controlLayout, Size{100, 0}};
- Button assignMouse3{&controlLayout, Size{100, 0}};
+ Button assignMouse1{&controlLayout, Size{100_sx, 0}};
+ Button assignMouse2{&controlLayout, Size{100_sx, 0}};
+ Button assignMouse3{&controlLayout, Size{100_sx, 0}};
Widget controlSpacer{&controlLayout, Size{~0, 0}};
- Button assignButton{&controlLayout, Size{80, 0}};
- Button clearButton{&controlLayout, Size{80, 0}};
+ Button assignButton{&controlLayout, Size{80_sx, 0}};
+ Button clearButton{&controlLayout, Size{80_sx, 0}};
};
struct HotkeySettings : TabFrameItem {
@@ -193,8 +196,8 @@ private:
TableView mappingList{&layout, Size{~0, ~0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Widget controlSpacer{&controlLayout, Size{~0, 0}};
- Button assignButton{&controlLayout, Size{80, 0}};
- Button clearButton{&controlLayout, Size{80, 0}};
+ Button assignButton{&controlLayout, Size{80_sx, 0}};
+ Button clearButton{&controlLayout, Size{80_sx, 0}};
};
struct PathSettings : TabFrameItem {
@@ -205,33 +208,33 @@ public:
TableLayout layout{this};
Label gamesLabel{&layout, Size{0, 0}};
LineEdit gamesPath{&layout, Size{~0, 0}};
- Button gamesAssign{&layout, Size{80, 0}};
- Button gamesReset{&layout, Size{80, 0}};
+ Button gamesAssign{&layout, Size{80_sx, 0}};
+ Button gamesReset{&layout, Size{80_sx, 0}};
//
Label patchesLabel{&layout, Size{0, 0}};
LineEdit patchesPath{&layout, Size{~0, 0}};
- Button patchesAssign{&layout, Size{80, 0}};
- Button patchesReset{&layout, Size{80, 0}};
+ Button patchesAssign{&layout, Size{80_sx, 0}};
+ Button patchesReset{&layout, Size{80_sx, 0}};
//
Label savesLabel{&layout, Size{0, 0}};
LineEdit savesPath{&layout, Size{~0, 0}};
- Button savesAssign{&layout, Size{80, 0}};
- Button savesReset{&layout, Size{80, 0}};
+ Button savesAssign{&layout, Size{80_sx, 0}};
+ Button savesReset{&layout, Size{80_sx, 0}};
//
Label cheatsLabel{&layout, Size{0, 0}};
LineEdit cheatsPath{&layout, Size{~0, 0}};
- Button cheatsAssign{&layout, Size{80, 0}};
- Button cheatsReset{&layout, Size{80, 0}};
+ Button cheatsAssign{&layout, Size{80_sx, 0}};
+ Button cheatsReset{&layout, Size{80_sx, 0}};
//
Label statesLabel{&layout, Size{0, 0}};
LineEdit statesPath{&layout, Size{~0, 0}};
- Button statesAssign{&layout, Size{80, 0}};
- Button statesReset{&layout, Size{80, 0}};
+ Button statesAssign{&layout, Size{80_sx, 0}};
+ Button statesReset{&layout, Size{80_sx, 0}};
//
Label screenshotsLabel{&layout, Size{0, 0}};
LineEdit screenshotsPath{&layout, Size{~0, 0}};
- Button screenshotsAssign{&layout, Size{80, 0}};
- Button screenshotsReset{&layout, Size{80, 0}};
+ Button screenshotsAssign{&layout, Size{80_sx, 0}};
+ Button screenshotsReset{&layout, Size{80_sx, 0}};
};
struct EmulatorSettings : TabFrameItem {
@@ -259,10 +262,12 @@ public:
CheckLabel noSpriteLimit{&fastPPULayout, Size{0, 0}};
CheckLabel hiresMode7{&fastPPULayout, Size{0, 0}};
CheckLabel fastDSPOption{&layout, Size{~0, 0}};
- CheckLabel coprocessorsDelayedSyncOption{&layout, Size{~0, 0}};
+ HorizontalLayout coprocessorsLayout{&layout, Size{~0, 0}};
+ CheckLabel coprocessorsDelayedSyncOption{&coprocessorsLayout, Size{0, 0}};
+ CheckLabel coprocessorsHLEOption{&coprocessorsLayout, Size{0, 0}};
HorizontalLayout superFXLayout{&layout, Size{~0, 0}};
Label superFXLabel{&superFXLayout, Size{0, 0}};
- Label superFXValue{&superFXLayout, Size{50, 0}};
+ Label superFXValue{&superFXLayout, Size{50_sx, 0}};
HorizontalSlider superFXClock{&superFXLayout, Size{~0, 0}};
Label hacksNote{&layout, Size{~0, 0}};
};
diff --git a/higan/target-bsnes/settings/video.cpp b/higan/target-bsnes/settings/video.cpp
index cf5debc3..28d055e3 100644
--- a/higan/target-bsnes/settings/video.cpp
+++ b/higan/target-bsnes/settings/video.cpp
@@ -2,7 +2,7 @@ auto VideoSettings::create() -> void {
setIcon(Icon::Device::Display);
setText("Video");
- layout.setPadding(5);
+ layout.setPadding(5_sx);
colorAdjustmentLabel.setFont(Font().setBold()).setText("Color Adjustment");
colorLayout.setSize({3, 3});
diff --git a/higan/target-bsnes/tools/cheat-editor.cpp b/higan/target-bsnes/tools/cheat-editor.cpp
index c7d338db..cc731cd9 100644
--- a/higan/target-bsnes/tools/cheat-editor.cpp
+++ b/higan/target-bsnes/tools/cheat-editor.cpp
@@ -1,5 +1,5 @@
auto CheatDatabase::create() -> void {
- layout.setPadding(5);
+ layout.setPadding(5_sx);
selectAllButton.setText("Select All").onActivate([&] {
for(auto item : cheatList.items()) item.setChecked(true);
});
@@ -10,7 +10,7 @@ auto CheatDatabase::create() -> void {
addCheats();
});
- setSize({800, 400});
+ setSize({800_sx, 400_sx});
setAlignment({0.5, 1.0});
setDismissable();
}
@@ -36,7 +36,7 @@ auto CheatDatabase::findCheats() -> void {
return;
}
- MessageDialog().setParent(*toolsWindow).setText("Sorry, no cheats were found for this game.").information();
+ MessageDialog().setAlignment(*toolsWindow).setText("Sorry, no cheats were found for this game.").information();
}
auto CheatDatabase::addCheats() -> void {
@@ -51,7 +51,7 @@ auto CheatDatabase::addCheats() -> void {
//
auto CheatWindow::create() -> void {
- layout.setPadding(5);
+ layout.setPadding(5_sx);
tableLayout.setSize({2, 2});
tableLayout.cell(0).setAlignment({1.0, 0.5});
tableLayout.cell(2).setAlignment({1.0, 0.0});
@@ -65,7 +65,7 @@ auto CheatWindow::create() -> void {
acceptButton.onActivate([&] { doAccept(); });
cancelButton.setText("Cancel").onActivate([&] { setVisible(false); });
- setSize({400, layout.minimumSize().height() + 100});
+ setSize({400_sx, layout.minimumSize().height() + 100_sx});
setDismissable();
}
@@ -75,7 +75,7 @@ auto CheatWindow::show(Cheat cheat) -> void {
enableOption.setChecked(cheat.enable);
doChange();
setTitle(!cheat.name ? "Add Cheat" : "Edit Cheat");
- setCentered(*toolsWindow);
+ setAlignment(*toolsWindow);
setVisible();
setFocused();
nameValue.setFocused();
@@ -105,7 +105,7 @@ auto CheatEditor::create() -> void {
setIcon(Icon::Edit::Replace);
setText("Cheat Editor");
- layout.setPadding(5);
+ layout.setPadding(5_sx);
cheatList.setBatchable();
cheatList.setHeadered();
cheatList.setSortable();
@@ -201,7 +201,7 @@ auto CheatEditor::editCheat(Cheat cheat) -> void {
auto CheatEditor::removeCheats() -> void {
if(auto batched = cheatList.batched()) {
if(MessageDialog("Are you sure you want to permanently remove the selected cheat(s)?")
- .setParent(*toolsWindow).question() == "Yes") {
+ .setAlignment(*toolsWindow).question() == "Yes") {
for(auto& item : reverse(batched)) cheats.remove(item.offset());
cheats.sort();
refresh();
diff --git a/higan/target-bsnes/tools/manifest-viewer.cpp b/higan/target-bsnes/tools/manifest-viewer.cpp
index 61577b59..7bea962d 100644
--- a/higan/target-bsnes/tools/manifest-viewer.cpp
+++ b/higan/target-bsnes/tools/manifest-viewer.cpp
@@ -2,7 +2,7 @@ auto ManifestViewer::create() -> void {
setIcon(Icon::Emblem::Text);
setText("Manifest Viewer");
- layout.setPadding(5);
+ layout.setPadding(5_sx);
manifestLabel.setText("Manifest:");
manifestOption.onChange([&] { selectManifest(); });
manifestSpacer.setColor({192, 192, 192});
diff --git a/higan/target-bsnes/tools/state-manager.cpp b/higan/target-bsnes/tools/state-manager.cpp
index 11dbe9dd..115a9ebc 100644
--- a/higan/target-bsnes/tools/state-manager.cpp
+++ b/higan/target-bsnes/tools/state-manager.cpp
@@ -1,12 +1,14 @@
+#include
+
auto StateWindow::create() -> void {
- layout.setPadding(5);
+ layout.setPadding(5_sx);
nameLabel.setText("Name:");
nameValue.onActivate([&] { if(acceptButton.enabled()) acceptButton.doActivate(); });
nameValue.onChange([&] { doChange(); });
acceptButton.onActivate([&] { doAccept(); });
cancelButton.setText("Cancel").onActivate([&] { setVisible(false); });
- setSize({400, layout.minimumSize().height()});
+ setSize({400_sx, layout.minimumSize().height()});
setDismissable();
}
@@ -16,7 +18,7 @@ auto StateWindow::show(string name) -> void {
nameValue.setText(property("name"));
doChange();
setTitle(!property("name") ? "Add State" : "Rename State");
- setCentered(*toolsWindow);
+ setAlignment(*toolsWindow);
setVisible();
setFocused();
nameValue.setFocused();
@@ -48,7 +50,7 @@ auto StateManager::create() -> void {
setIcon(Icon::Application::FileManager);
setText("State Manager");
- layout.setPadding(5);
+ layout.setPadding(5_sx);
stateLayout.setAlignment(0.0);
stateList.setBatchable();
stateList.setHeadered();
@@ -131,7 +133,7 @@ auto StateManager::modifyState(string name) -> void {
auto StateManager::removeStates() -> void {
if(auto batched = stateList.batched()) {
if(MessageDialog("Are you sure you want to permanently remove the selected state(s)?")
- .setParent(*toolsWindow).question() == "Yes") {
+ .setAlignment(*toolsWindow).question() == "Yes") {
auto lock = acquire();
for(auto& item : batched) program.removeState(item.property("name"));
loadStates();
@@ -159,9 +161,18 @@ auto StateManager::updateSelection() -> void {
if(signature == Program::State::Signature && preview) {
uint offset = 3 * sizeof(uint) + serializer;
auto preview = Decode::RLE<2>({saveState.data() + offset, max(offset, saveState.size()) - offset});
- image icon{0, 15, 0x8000, 0x7c00, 0x03e0, 0x001f};
+ image icon{0, 16, 0x8000, 0x7c00, 0x03e0, 0x001f};
icon.copy(preview.data(), 256 * sizeof(uint16_t), 256, 240);
icon.transform();
+ //restore the missing alpha channel
+ for(uint y : range(icon.height())) {
+ auto data = icon.data() + y * icon.pitch();
+ for(uint x : range(icon.width())) {
+ auto pixel = icon.read(data);
+ icon.write(data, 0xff000000 | pixel);
+ data += icon.stride();
+ }
+ }
statePreview.setIcon(icon);
}
}
diff --git a/higan/target-bsnes/tools/tools.cpp b/higan/target-bsnes/tools/tools.cpp
index f104a616..98da0e9f 100644
--- a/higan/target-bsnes/tools/tools.cpp
+++ b/higan/target-bsnes/tools/tools.cpp
@@ -11,7 +11,7 @@ ManifestViewer manifestViewer;
ToolsWindow toolsWindow;
auto ToolsWindow::create() -> void {
- layout.setPadding(5);
+ layout.setPadding(5_sx);
panel.append(cheatEditor);
panel.append(stateManager);
panel.append(manifestViewer);
@@ -22,7 +22,7 @@ auto ToolsWindow::create() -> void {
});
setTitle("Tools");
- setSize({720, 480});
+ setSize({720_sx, 480_sx});
setAlignment({1.0, 1.0});
setDismissable();
diff --git a/higan/target-bsnes/tools/tools.hpp b/higan/target-bsnes/tools/tools.hpp
index 7061721e..979023ff 100644
--- a/higan/target-bsnes/tools/tools.hpp
+++ b/higan/target-bsnes/tools/tools.hpp
@@ -21,10 +21,10 @@ public:
VerticalLayout layout{this};
ListView cheatList{&layout, Size{~0, ~0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
- Button selectAllButton{&controlLayout, Size{100, 0}};
- Button unselectAllButton{&controlLayout, Size{100, 0}};
+ Button selectAllButton{&controlLayout, Size{100_sx, 0}};
+ Button unselectAllButton{&controlLayout, Size{100_sx, 0}};
Widget spacer{&controlLayout, Size{~0, 0}};
- Button addCheatsButton{&controlLayout, Size{100, 0}};
+ Button addCheatsButton{&controlLayout, Size{100_sx, 0}};
};
struct CheatWindow : Window {
@@ -43,8 +43,8 @@ public:
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Widget controlSpacer{&controlLayout, Size{~0, 0}};
CheckLabel enableOption{&controlLayout, Size{0, 0}};
- Button acceptButton{&controlLayout, Size{80, 0}};
- Button cancelButton{&controlLayout, Size{80, 0}};
+ Button acceptButton{&controlLayout, Size{80_sx, 0}};
+ Button cancelButton{&controlLayout, Size{80_sx, 0}};
};
struct CheatEditor : TabFrameItem {
@@ -63,12 +63,12 @@ public:
VerticalLayout layout{this};
TableView cheatList{&layout, Size{~0, ~0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
- Button findCheatsButton{&controlLayout, Size{120, 0}};
+ Button findCheatsButton{&controlLayout, Size{120_sx, 0}};
Widget spacer{&controlLayout, Size{~0, 0}};
CheckLabel enableCheats{&controlLayout, Size{0, 0}};
- Button addButton{&controlLayout, Size{80, 0}};
- Button editButton{&controlLayout, Size{80, 0}};
- Button removeButton{&controlLayout, Size{80, 0}};
+ Button addButton{&controlLayout, Size{80_sx, 0}};
+ Button editButton{&controlLayout, Size{80_sx, 0}};
+ Button removeButton{&controlLayout, Size{80_sx, 0}};
};
struct StateWindow : Window {
@@ -80,12 +80,12 @@ struct StateWindow : Window {
public:
VerticalLayout layout{this};
HorizontalLayout nameLayout{&layout, Size{~0, 0}};
- Label nameLabel{&nameLayout, Size{40, 0}};
+ Label nameLabel{&nameLayout, Size{40_sx, 0}};
LineEdit nameValue{&nameLayout, Size{~0, 0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Widget spacer{&controlLayout, Size{~0, 0}};
- Button acceptButton{&controlLayout, Size{80, 0}};
- Button cancelButton{&controlLayout, Size{80, 0}};
+ Button acceptButton{&controlLayout, Size{80_sx, 0}};
+ Button cancelButton{&controlLayout, Size{80_sx, 0}};
};
struct StateManager : TabFrameItem, Lock {
@@ -117,12 +117,12 @@ public:
Label statePreviewLabel{&previewLayout, Size{~0, 0}};
Canvas statePreview{&previewLayout, Size{256, 224}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
- Button loadButton{&controlLayout, Size{80, 0}};
- Button saveButton{&controlLayout, Size{80, 0}};
+ Button loadButton{&controlLayout, Size{80_sx, 0}};
+ Button saveButton{&controlLayout, Size{80_sx, 0}};
Widget spacer{&controlLayout, Size{~0, 0}};
- Button addButton{&controlLayout, Size{80, 0}};
- Button editButton{&controlLayout, Size{80, 0}};
- Button removeButton{&controlLayout, Size{80, 0}};
+ Button addButton{&controlLayout, Size{80_sx, 0}};
+ Button editButton{&controlLayout, Size{80_sx, 0}};
+ Button removeButton{&controlLayout, Size{80_sx, 0}};
};
struct ManifestViewer : TabFrameItem {
diff --git a/hiro/GNUmakefile b/hiro/GNUmakefile
index 463988da..fd9c8c37 100644
--- a/hiro/GNUmakefile
+++ b/hiro/GNUmakefile
@@ -5,7 +5,7 @@ ifeq ($(platform),windows)
ifeq ($(hiro),windows)
hiro.flags = $(flags.cpp) -DHIRO_WINDOWS
- hiro.options = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -luxtheme -lmsimg32 -lshlwapi
+ hiro.options = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -luxtheme -lmsimg32 -lshlwapi -ldwmapi
endif
ifeq ($(hiro),gtk2)
@@ -14,7 +14,7 @@ ifeq ($(platform),windows)
endif
ifeq ($(hiro),gtk3)
- hiro.flags = $(flags.cpp) -DHIRO_GTK=3 $(shell pkg-config --cflags gtk+-3.0 gtksourceview-3.0)
+ hiro.flags = $(flags.cpp) -DHIRO_GTK=3 $(shell pkg-config --cflags gtk+-3.0 gtksourceview-3.0) -Wno-deprecated-declarations
hiro.options = $(shell pkg-config --libs gtk+-3.0 gtksourceview-3.0)
endif
endif
@@ -41,12 +41,12 @@ ifneq ($(filter $(platform),linux bsd),)
endif
ifeq ($(hiro),gtk3)
- hiro.flags = $(flags.cpp) -DHIRO_GTK=3 $(shell pkg-config --cflags gtk+-3.0 gtksourceview-3.0)
+ hiro.flags = $(flags.cpp) -DHIRO_GTK=3 $(shell pkg-config --cflags gtk+-3.0 gtksourceview-3.0) -Wno-deprecated-declarations
hiro.options = -lX11 $(shell pkg-config --libs gtk+-3.0 gtksourceview-3.0)
endif
ifeq ($(hiro),qt4)
- moc = moc-qt4
+ moc = /usr/local/lib/qt4/bin/moc
hiro.flags = $(flags.cpp) -DHIRO_QT=4 $(shell pkg-config --cflags QtCore QtGui)
hiro.options = -lX11 $(shell pkg-config --libs QtCore QtGui)
endif
diff --git a/hiro/cocoa/timer.cpp b/hiro/cocoa/timer.cpp
index 45fedec7..e9a183fc 100644
--- a/hiro/cocoa/timer.cpp
+++ b/hiro/cocoa/timer.cpp
@@ -28,7 +28,7 @@
}
-(void) run:(NSTimer*)instance {
- if(Application::state().quit) return;
+ if(hiro::Application::state().quit) return;
if(timer->enabled()) {
timer->doActivate();
diff --git a/hiro/cocoa/widget/canvas.cpp b/hiro/cocoa/widget/canvas.cpp
index 5271c285..4cc83daa 100644
--- a/hiro/cocoa/widget/canvas.cpp
+++ b/hiro/cocoa/widget/canvas.cpp
@@ -113,6 +113,10 @@ auto pCanvas::minimumSize() const -> Size {
return {0, 0};
}
+auto pCanvas::setAlignment(Alignment) -> void {
+ update();
+}
+
auto pCanvas::setColor(Color color) -> void {
update();
}
@@ -147,6 +151,7 @@ auto pCanvas::update() -> void {
}
}
+//todo: support cases where the icon size does not match the canvas size (alignment)
auto pCanvas::_rasterize() -> void {
@autoreleasepool {
int width = 0;
diff --git a/hiro/cocoa/widget/canvas.hpp b/hiro/cocoa/widget/canvas.hpp
index 64f77f19..6c1d9a9c 100644
--- a/hiro/cocoa/widget/canvas.hpp
+++ b/hiro/cocoa/widget/canvas.hpp
@@ -27,6 +27,7 @@ struct pCanvas : pWidget {
Declare(Canvas, Widget)
auto minimumSize() const -> Size;
+ auto setAlignment(Alignment) -> void;
auto setColor(Color color) -> void;
auto setDroppable(bool droppable) -> void;
auto setGeometry(Geometry geometry) -> void override;
diff --git a/hiro/cocoa/widget/tab-frame.cpp b/hiro/cocoa/widget/tab-frame.cpp
index 68585966..9a019340 100644
--- a/hiro/cocoa/widget/tab-frame.cpp
+++ b/hiro/cocoa/widget/tab-frame.cpp
@@ -154,9 +154,7 @@ auto pTabFrame::_synchronizeSizable() -> void {
int selected = tabViewItem ? [cocoaView indexOfTabViewItem:tabViewItem] : -1;
for(auto& item : state().items) {
item->state.selected = item->offset() == selected;
- if(auto& sizable = item->state.sizable) {
- if(auto self = sizable->self()) self->setVisible(sizable->visible(true) && item->selected());
- }
+ if(auto& sizable = item->state.sizable) sizable->setVisible(item->selected());
}
}
}
diff --git a/hiro/cocoa/widget/tab-frame.hpp b/hiro/cocoa/widget/tab-frame.hpp
index dd9c426f..39006dc1 100644
--- a/hiro/cocoa/widget/tab-frame.hpp
+++ b/hiro/cocoa/widget/tab-frame.hpp
@@ -34,7 +34,6 @@ struct pTabFrame : pWidget {
auto _synchronizeSizable() -> void;
CocoaTabFrame* cocoaTabFrame = nullptr;
- vector tabs;
};
}
diff --git a/hiro/cocoa/window.cpp b/hiro/cocoa/window.cpp
index 71a05b0a..b5b0d60c 100644
--- a/hiro/cocoa/window.cpp
+++ b/hiro/cocoa/window.cpp
@@ -242,6 +242,10 @@ auto pWindow::frameMargin() const -> Geometry {
}
}
+auto pWindow::handle() const -> uintptr_t {
+ return (uintptr_t)cocoaWindow;
+}
+
auto pWindow::monitor() const -> uint {
//TODO
return 0;
diff --git a/hiro/cocoa/window.hpp b/hiro/cocoa/window.hpp
index f5e19b8e..ef33e361 100644
--- a/hiro/cocoa/window.hpp
+++ b/hiro/cocoa/window.hpp
@@ -35,6 +35,7 @@ struct pWindow : pObject {
auto append(sStatusBar statusBar) -> void;
auto focused() const -> bool override;
auto frameMargin() const -> Geometry;
+ auto handle() const -> uintptr_t;
auto monitor() const -> uint;
auto remove(sMenuBar menuBar) -> void;
auto remove(sSizable sizable) -> void;
diff --git a/hiro/components.hpp b/hiro/components.hpp
index 390dc59c..71a6e616 100644
--- a/hiro/components.hpp
+++ b/hiro/components.hpp
@@ -95,18 +95,24 @@
#define Hiro_VerticalLayout
#define Hiro_TableLayout
+#if defined(Hiro_Timer) && defined(Hiro_Canvas)
+ #define Hiro_HorizontalResizeGrip
+ #define Hiro_VerticalResizeGrip
+#endif
+
#if defined(Hiro_TableView)
#define Hiro_ListView
#endif
#if defined(Hiro_Button) && defined(Hiro_Canvas) && defined(Hiro_Label)
#define Hiro_MessageDialog
+ #define Hiro_NameDialog
#endif
-#if defined(Hiro_Button) && defined(Hiro_ComboButton) && defined(Hiro_LineEdit) && defined(Hiro_ListView) && defined(Hiro_MessageDialog)
+#if defined(Hiro_Button) && defined(Hiro_ComboButton) && defined(Hiro_LineEdit) && defined(Hiro_ListView) && defined(Hiro_MessageDialog) && defined(Hiro_NameDialog)
#define Hiro_BrowserDialog
#endif
-#if defined(Hiro_Label)
+#if defined(Hiro_Canvas) && defined(Hiro_Label)
#define Hiro_AboutDialog
#endif
diff --git a/hiro/core/alignment.cpp b/hiro/core/alignment.cpp
index bbc626d2..ba968e26 100644
--- a/hiro/core/alignment.cpp
+++ b/hiro/core/alignment.cpp
@@ -1,5 +1,7 @@
#if defined(Hiro_Alignment)
+const Alignment Alignment::Center = {0.5, 0.5};
+
Alignment::Alignment() {
setAlignment(-1.0, -1.0);
}
diff --git a/hiro/core/application.cpp b/hiro/core/application.cpp
index 5534f4bb..790d66ff 100644
--- a/hiro/core/application.cpp
+++ b/hiro/core/application.cpp
@@ -1,16 +1,21 @@
#if defined(Hiro_Application)
+auto Application::abort() -> void {
+ quit();
+ ::abort();
+}
+
auto Application::doMain() -> void {
if(state().onMain) return state().onMain();
}
-auto Application::font() -> Font {
- return state().font;
+auto Application::exit() -> void {
+ quit();
+ ::exit(EXIT_SUCCESS);
}
-auto Application::kill() -> void {
- quit();
- exit(EXIT_SUCCESS);
+auto Application::font() -> Font {
+ return state().font;
}
auto Application::locale() -> Locale& {
@@ -134,7 +139,6 @@ auto Application::Cocoa::onQuit(const function& callback) -> void {
auto Application::initialize() -> void {
if(!state().initialized) {
state().initialized = true;
- hiro::initialize();
pApplication::initialize();
pApplication::setScreenSaver(state().screenSaver);
}
diff --git a/hiro/core/application.hpp b/hiro/core/application.hpp
index fc99a3e9..daae3ccc 100644
--- a/hiro/core/application.hpp
+++ b/hiro/core/application.hpp
@@ -2,9 +2,10 @@
struct Application {
Application() = delete;
+ static auto abort() -> void;
static auto doMain() -> void;
+ static auto exit() -> void;
static auto font() -> Font;
- static auto kill() -> void;
static auto locale() -> Locale&;
static auto modal() -> bool;
static auto name() -> string;
diff --git a/hiro/core/core.hpp b/hiro/core/core.hpp
index e6e34df6..064c6142 100644
--- a/hiro/core/core.hpp
+++ b/hiro/core/core.hpp
@@ -1,4 +1,5 @@
#include
+#include
#include
#include
#include
@@ -17,6 +18,7 @@
#include
#include
+using nall::any;
using nall::function;
using nall::image;
using nall::Locale;
@@ -31,8 +33,6 @@ using nall::vector;
namespace hiro {
-auto initialize() -> void;
-
struct Font;
struct Keyboard;
@@ -158,6 +158,7 @@ struct Gradient {
#if defined(Hiro_Alignment)
struct Alignment {
using type = Alignment;
+ static const Alignment Center;
Alignment();
Alignment(float horizontal, float vertical = 0.5);
@@ -408,24 +409,7 @@ struct MessageWindow {
};
#endif
-struct Property {
- using type = Property;
-
- Property(const string& name, const string& value = "");
-
- auto operator==(const Property& source) const -> bool;
- auto operator< (const Property& source) const -> bool;
-
- auto name() const -> string;
- auto setValue(const string& value = "") -> type&;
- auto value() const -> string;
-
-private:
- struct State {
- string name;
- string value;
- } state;
-};
+#include "property.hpp"
#define Declare(Name) \
using type = m##Name; \
@@ -652,47 +636,7 @@ struct mButton : mWidget {
};
#endif
-#if defined(Hiro_Canvas)
-struct mCanvas : mWidget {
- Declare(Canvas)
-
- auto color() const -> Color;
- auto data() -> uint32_t*;
- auto droppable() const -> bool;
- auto doDrop(vector names) const -> void;
- auto doMouseLeave() const -> void;
- auto doMouseMove(Position position) const -> void;
- auto doMousePress(Mouse::Button button) const -> void;
- auto doMouseRelease(Mouse::Button button) const -> void;
- auto gradient() const -> Gradient;
- auto icon() const -> image;
- auto onDrop(const function)>& callback = {}) -> type&;
- auto onMouseLeave(const function& callback = {}) -> type&;
- auto onMouseMove(const function& callback = {}) -> type&;
- auto onMousePress(const function& callback = {}) -> type&;
- auto onMouseRelease(const function& callback = {}) -> type&;
- auto setColor(Color color = {}) -> type&;
- auto setDroppable(bool droppable = true) -> type&;
- auto setGradient(Gradient gradient = {}) -> type&;
- auto setIcon(const image& icon = {}) -> type&;
- auto setSize(Size size = {}) -> type&;
- auto size() const -> Size;
- auto update() -> type&;
-
-//private:
- struct State {
- Color color;
- bool droppable = false;
- Gradient gradient;
- image icon;
- function)> onDrop;
- function onMouseLeave;
- function onMouseMove;
- function onMousePress;
- function onMouseRelease;
- } state;
-};
-#endif
+#include "widget/canvas.hpp"
#if defined(Hiro_CheckButton)
struct mCheckButton : mWidget {
diff --git a/hiro/core/monitor.hpp b/hiro/core/monitor.hpp
index 213c87e7..d20ce38e 100644
--- a/hiro/core/monitor.hpp
+++ b/hiro/core/monitor.hpp
@@ -8,4 +8,19 @@ struct Monitor {
static auto primary() -> uint;
static auto workspace(maybe monitor = nothing) -> Geometry;
};
+
+//DPI scale X
+inline auto sx(float x) -> float {
+ static auto scale = Monitor::dpi().x() / 96.0;
+ return x * scale;
+}
+
+//DPI scale y
+inline auto sy(float y) -> float {
+ static auto scale = Monitor::dpi().y() / 96.0;
+ return y * scale;
+}
+
+inline auto operator"" _sx(unsigned long long x) -> float { return sx(x); }
+inline auto operator"" _sy(unsigned long long y) -> float { return sy(y); }
#endif
diff --git a/hiro/core/object.cpp b/hiro/core/object.cpp
index dc24d079..ab8094d1 100644
--- a/hiro/core/object.cpp
+++ b/hiro/core/object.cpp
@@ -249,13 +249,6 @@ auto mObject::parentWindow(bool recursive) const -> mWindow* {
}
#endif
-auto mObject::property(const string& name) const -> string {
- if(auto property = state.properties.find({name})) {
- return property->value();
- }
- return {};
-}
-
auto mObject::remove() -> type& {
signal(remove);
return *this;
@@ -295,16 +288,6 @@ auto mObject::setParent(mObject* parent, int offset) -> type& {
return *this;
}
-auto mObject::setProperty(const string& name, const string& value) -> type& {
- if(auto property = state.properties.find(name)) {
- if(value) property->setValue(value);
- else state.properties.remove(*property);
- } else {
- if(value) state.properties.insert({name, value});
- }
- return *this;
-}
-
auto mObject::setVisible(bool visible) -> type& {
state.visible = visible;
signal(setVisible, this->visible(true));
diff --git a/hiro/core/object.hpp b/hiro/core/object.hpp
index 5942053b..a77d143f 100644
--- a/hiro/core/object.hpp
+++ b/hiro/core/object.hpp
@@ -33,7 +33,6 @@ struct mObject {
auto parentTreeViewItem(bool recursive = false) const -> mTreeViewItem*;
auto parentWidget(bool recursive = false) const -> mWidget*;
auto parentWindow(bool recursive = false) const -> mWindow*;
- auto property(const string& name) const -> string;
virtual auto remove() -> type&;
virtual auto reset() -> type&;
virtual auto setEnabled(bool enabled = true) -> type&;
@@ -41,10 +40,34 @@ struct mObject {
virtual auto setFont(const Font& font = {}) -> type&;
virtual auto setGroup(sGroup group = {}) -> type&;
virtual auto setParent(mObject* parent = nullptr, int offset = -1) -> type&;
- virtual auto setProperty(const string& name, const string& value = "") -> type&;
virtual auto setVisible(bool visible = true) -> type&;
auto visible(bool recursive = false) const -> bool;
+ template auto property(const string& name) const -> T {
+ if(auto property = state.properties.find(name)) {
+ if(property->value().is()) return property->value().get();
+ }
+ return {};
+ }
+
+ //this template basically disables implicit template type deduction:
+ //if setProperty(name, value) is called without a type, the type will be a string, so property(name) will just work.
+ //if setProperty(name, value) is called, the type will be T. as such, U must be cast to T on assignment.
+ //when T = string, value must be convertible to a string.
+ //U defaults to a string, so that setProperty(name, {values, ...}) will deduce U as a string.
+ template auto setProperty(const string& name, const U& value) -> type& {
+ if constexpr(std::is_same_v && !std::is_same_v) {
+ return setProperty(name, string{value});
+ }
+ if(auto property = state.properties.find(name)) {
+ if((const T&)value) property->setValue((const T&)value);
+ else state.properties.remove(*property);
+ } else {
+ if((const T&)value) state.properties.insert({name, (const T&)value});
+ }
+ return *this;
+ }
+
//private:
//sizeof(mObject) == 88
struct State {
diff --git a/hiro/core/property.cpp b/hiro/core/property.cpp
index e1b75361..809fa2c1 100644
--- a/hiro/core/property.cpp
+++ b/hiro/core/property.cpp
@@ -1,6 +1,6 @@
#if defined(Hiro_Property)
-Property::Property(const string& name, const string& value) {
+Property::Property(const string& name, const any& value) {
state.name = name;
state.value = value;
}
@@ -17,12 +17,12 @@ auto Property::name() const -> string {
return state.name;
}
-auto Property::setValue(const string& value) -> type& {
+auto Property::setValue(const any& value) -> type& {
state.value = value;
return *this;
}
-auto Property::value() const -> string {
+auto Property::value() const -> any& {
return state.value;
}
diff --git a/hiro/core/property.hpp b/hiro/core/property.hpp
new file mode 100644
index 00000000..c66cf480
--- /dev/null
+++ b/hiro/core/property.hpp
@@ -0,0 +1,20 @@
+#if defined(Hiro_Property)
+struct Property {
+ using type = Property;
+
+ Property(const string& name, const any& value = {});
+
+ auto operator==(const Property& source) const -> bool;
+ auto operator< (const Property& source) const -> bool;
+
+ auto name() const -> string;
+ auto setValue(const any& value = {}) -> type&;
+ auto value() const -> any&;
+
+private:
+ struct State {
+ string name;
+ mutable any value;
+ } state;
+};
+#endif
diff --git a/hiro/core/shared.hpp b/hiro/core/shared.hpp
index 6466e758..83b421a3 100644
--- a/hiro/core/shared.hpp
+++ b/hiro/core/shared.hpp
@@ -38,12 +38,12 @@
} \
return Object(); \
} \
- auto property(const string& name) const { return self().property(name); } \
+ template auto property(const string& name) const { return self().property(name); } \
auto remove() { return self().remove(), *this; } \
auto setEnabled(bool enabled = true) { return self().setEnabled(enabled), *this; } \
auto setFocused() { return self().setFocused(), *this; } \
auto setFont(const Font& font = {}) { return self().setFont(font), *this; } \
- auto setProperty(const string& name, const string& value = "") { return self().setProperty(name, value), *this; } \
+ template auto setProperty(const string& name, const U& value = {}) { return self().setProperty(name, value), *this; } \
auto setVisible(bool visible = true) { return self().setVisible(visible), *this; } \
auto visible(bool recursive = false) const { return self().visible(recursive); } \
@@ -210,6 +210,7 @@ struct Button : sButton {
struct Canvas : sCanvas {
DeclareSharedWidget(Canvas)
+ auto alignment() const { return self().alignment(); }
auto color() const { return self().color(); }
auto data() { return self().data(); }
auto droppable() const { return self().droppable(); }
@@ -225,6 +226,7 @@ struct Canvas : sCanvas {
auto onMouseMove(const function& callback = {}) { return self().onMouseMove(callback), *this; }
auto onMousePress(const function& callback = {}) { return self().onMousePress(callback), *this; }
auto onMouseRelease(const function& callback = {}) { return self().onMouseRelease(callback), *this; }
+ auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; }
auto setColor(Color color) { return self().setColor(color), *this; }
auto setDroppable(bool droppable = true) { return self().setDroppable(droppable), *this; }
auto setGradient(Gradient gradient = {}) { return self().setGradient(gradient), *this; }
@@ -761,6 +763,8 @@ struct TreeViewItem : sTreeViewItem {
auto backgroundColor() const { return self().backgroundColor(); }
auto checkable() const { return self().checkable(); }
auto checked() const { return self().checked(); }
+ auto collapse(bool recursive = true) { return self().collapse(recursive), *this; }
+ auto expand(bool recursive = true) { return self().expand(recursive), *this; }
auto expanded() const { return self().expanded(); }
auto foregroundColor() const { return self().foregroundColor(); }
auto icon() const { return self().icon(); }
@@ -788,10 +792,12 @@ struct TreeView : sTreeView {
auto append(sTreeViewItem item) { return self().append(item), *this; }
auto backgroundColor() const { return self().backgroundColor(); }
+ auto collapse(bool recursive = true) { return self().collapse(recursive), *this; }
auto doActivate() const { return self().doActivate(); }
auto doChange() const { return self().doChange(); }
auto doContext() const { return self().doContext(); }
auto doToggle(sTreeViewItem item) const { return self().doToggle(item); }
+ auto expand(bool recursive = true) { return self().expand(recursive), *this; }
auto foregroundColor() const { return self().foregroundColor(); }
auto item(const string& path) const { return self().item(path); }
auto itemCount() const { return self().itemCount(); }
@@ -908,6 +914,7 @@ struct Window : sWindow {
auto frameGeometry() const { return self().frameGeometry(); }
auto fullScreen() const { return self().fullScreen(); }
auto geometry() const { return self().geometry(); }
+ auto handle() const { return self().handle(); }
auto maximized() const { return self().maximized(); }
auto maximumSize() const { return self().maximumSize(); }
auto menuBar() const { return self().menuBar(); }
@@ -926,9 +933,9 @@ struct Window : sWindow {
auto remove(sStatusBar statusBar) { return self().remove(statusBar), *this; }
auto reset() { return self().reset(), *this; }
auto resizable() const { return self().resizable(); }
- auto setAlignment(Alignment alignment) { return self().setAlignment(alignment), *this; }
+ auto setAlignment(Alignment alignment = Alignment::Center) { return self().setAlignment(alignment), *this; }
+ auto setAlignment(sWindow relativeTo, Alignment alignment = Alignment::Center) { return self().setAlignment(relativeTo, alignment), *this; }
auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; }
- auto setCentered(sWindow parent = {}) { return self().setCentered(parent), *this; }
auto setDismissable(bool dismissable = true) { return self().setDismissable(dismissable), *this; }
auto setDroppable(bool droppable = true) { return self().setDroppable(droppable), *this; }
auto setFrameGeometry(Geometry geometry) { return self().setFrameGeometry(geometry), *this; }
@@ -942,6 +949,7 @@ struct Window : sWindow {
auto setMinimumSize(Size size = {}) { return self().setMinimumSize(size), *this; }
auto setModal(bool modal = true) { return self().setModal(modal), *this; }
auto setPosition(Position position) { return self().setPosition(position), *this; }
+ auto setPosition(sWindow relativeTo, Position position) { return self().setPosition(relativeTo, position), *this; }
auto setResizable(bool resizable = true) { return self().setResizable(resizable), *this; }
auto setSize(Size size) { return self().setSize(size), *this; }
auto setTitle(const string& title = "") { return self().setTitle(title), *this; }
diff --git a/hiro/core/widget/canvas.cpp b/hiro/core/widget/canvas.cpp
index 19b224e0..2377bbfb 100644
--- a/hiro/core/widget/canvas.cpp
+++ b/hiro/core/widget/canvas.cpp
@@ -6,6 +6,10 @@ auto mCanvas::allocate() -> pObject* {
//
+auto mCanvas::alignment() const -> Alignment {
+ return state.alignment;
+}
+
auto mCanvas::color() const -> Color {
return state.color;
}
@@ -71,6 +75,12 @@ auto mCanvas::onMouseRelease(const function& callback) ->
return *this;
}
+auto mCanvas::setAlignment(Alignment alignment) -> type& {
+ state.alignment = alignment;
+ signal(setAlignment, alignment);
+ return *this;
+}
+
auto mCanvas::setColor(Color color) -> type& {
state.color = color;
state.gradient = {};
diff --git a/hiro/core/widget/canvas.hpp b/hiro/core/widget/canvas.hpp
new file mode 100644
index 00000000..2d9089b0
--- /dev/null
+++ b/hiro/core/widget/canvas.hpp
@@ -0,0 +1,44 @@
+#if defined(Hiro_Canvas)
+struct mCanvas : mWidget {
+ Declare(Canvas)
+
+ auto alignment() const -> Alignment;
+ auto color() const -> Color;
+ auto data() -> uint32_t*;
+ auto droppable() const -> bool;
+ auto doDrop(vector names) const -> void;
+ auto doMouseLeave() const -> void;
+ auto doMouseMove(Position position) const -> void;
+ auto doMousePress(Mouse::Button button) const -> void;
+ auto doMouseRelease(Mouse::Button button) const -> void;
+ auto gradient() const -> Gradient;
+ auto icon() const -> image;
+ auto onDrop(const function)>& callback = {}) -> type&;
+ auto onMouseLeave(const function& callback = {}) -> type&;
+ auto onMouseMove(const function& callback = {}) -> type&;
+ auto onMousePress(const function& callback = {}) -> type&;
+ auto onMouseRelease(const function& callback = {}) -> type&;
+ auto setAlignment(Alignment alignment = {}) -> type&;
+ auto setColor(Color color = {}) -> type&;
+ auto setDroppable(bool droppable = true) -> type&;
+ auto setGradient(Gradient gradient = {}) -> type&;
+ auto setIcon(const image& icon = {}) -> type&;
+ auto setSize(Size size = {}) -> type&;
+ auto size() const -> Size;
+ auto update() -> type&;
+
+//private:
+ struct State {
+ Alignment alignment;
+ Color color;
+ bool droppable = false;
+ Gradient gradient;
+ image icon;
+ function)> onDrop;
+ function onMouseLeave;
+ function onMouseMove;
+ function onMousePress;
+ function onMouseRelease;
+ } state;
+};
+#endif
diff --git a/hiro/core/widget/tree-view-item.cpp b/hiro/core/widget/tree-view-item.cpp
index fe798138..181cefba 100644
--- a/hiro/core/widget/tree-view-item.cpp
+++ b/hiro/core/widget/tree-view-item.cpp
@@ -39,6 +39,18 @@ auto mTreeViewItem::checked() const -> bool {
return state.checked;
}
+auto mTreeViewItem::collapse(bool recursive) -> type& {
+ if(recursive) for(auto& item : state.items) item->collapse(recursive);
+ setExpanded(false);
+ return *this;
+}
+
+auto mTreeViewItem::expand(bool recursive) -> type& {
+ setExpanded(true);
+ if(recursive) for(auto& item : state.items) item->expand(recursive);
+ return *this;
+}
+
auto mTreeViewItem::expanded() const -> bool {
return state.expanded;
}
diff --git a/hiro/core/widget/tree-view-item.hpp b/hiro/core/widget/tree-view-item.hpp
index 20cb8a27..40156bd3 100644
--- a/hiro/core/widget/tree-view-item.hpp
+++ b/hiro/core/widget/tree-view-item.hpp
@@ -6,6 +6,8 @@ struct mTreeViewItem : mObject {
auto backgroundColor(bool recursive = false) const -> Color;
auto checkable() const -> bool;
auto checked() const -> bool;
+ auto collapse(bool recursive = true) -> type&;
+ auto expand(bool recursive = true) -> type&;
auto expanded() const -> bool;
auto foregroundColor(bool recursive = false) const -> Color;
auto icon() const -> image;
diff --git a/hiro/core/widget/tree-view.cpp b/hiro/core/widget/tree-view.cpp
index ce0455b3..847f6550 100644
--- a/hiro/core/widget/tree-view.cpp
+++ b/hiro/core/widget/tree-view.cpp
@@ -22,6 +22,11 @@ auto mTreeView::backgroundColor() const -> Color {
return state.backgroundColor;
}
+auto mTreeView::collapse(bool recursive) -> type& {
+ for(auto& item : state.items) item->collapse(recursive);
+ return *this;
+}
+
auto mTreeView::doActivate() const -> void {
if(state.onActivate) return state.onActivate();
}
@@ -38,6 +43,11 @@ auto mTreeView::doToggle(sTreeViewItem item) const -> void {
if(state.onToggle) return state.onToggle(item);
}
+auto mTreeView::expand(bool recursive) -> type& {
+ for(auto& item : state.items) item->expand(recursive);
+ return *this;
+}
+
auto mTreeView::foregroundColor() const -> Color {
return state.foregroundColor;
}
diff --git a/hiro/core/widget/tree-view.hpp b/hiro/core/widget/tree-view.hpp
index 44291f3e..100f4702 100644
--- a/hiro/core/widget/tree-view.hpp
+++ b/hiro/core/widget/tree-view.hpp
@@ -5,10 +5,12 @@ struct mTreeView : mWidget {
auto append(sTreeViewItem item) -> type&;
auto backgroundColor() const -> Color;
+ auto collapse(bool recursive = true) -> type&;
auto doActivate() const -> void;
auto doChange() const -> void;
auto doContext() const -> void;
auto doToggle(sTreeViewItem item) const -> void;
+ auto expand(bool recursive = true) -> type&;
auto foregroundColor() const -> Color;
auto item(const string& path) const -> TreeViewItem;
auto itemCount() const -> uint;
diff --git a/hiro/core/window.cpp b/hiro/core/window.cpp
index fc1dde15..60ed3448 100644
--- a/hiro/core/window.cpp
+++ b/hiro/core/window.cpp
@@ -93,6 +93,10 @@ auto mWindow::geometry() const -> Geometry {
return state.geometry;
}
+auto mWindow::handle() const -> uintptr_t {
+ return signal(handle);
+}
+
auto mWindow::maximized() const -> bool {
return state.maximized;
}
@@ -184,12 +188,30 @@ auto mWindow::resizable() const -> bool {
}
auto mWindow::setAlignment(Alignment alignment) -> type& {
- if(!alignment) alignment = {0.0, 0.0};
auto workspace = Desktop::workspace();
auto geometry = frameGeometry();
- int left = alignment.horizontal() * (workspace.width() - geometry.width());
- int top = alignment.vertical() * (workspace.height() - geometry.height());
- setFramePosition({left, top});
+ auto x = alignment.horizontal() * (workspace.width() - geometry.width());
+ auto y = alignment.vertical() * (workspace.height() - geometry.height());
+ setFramePosition({(int)x, (int)y});
+ return *this;
+}
+
+auto mWindow::setAlignment(sWindow relativeTo, Alignment alignment) -> type& {
+ if(!relativeTo) return setAlignment(alignment);
+ auto parent = relativeTo->frameGeometry();
+ auto window = frameGeometry();
+ //+0 .. +1 => within parent window
+ auto x = parent.x() + (parent.width() - window.width()) * alignment.horizontal();
+ auto y = parent.y() + (parent.height() - window.height()) * alignment.vertical();
+ //-1 .. -0 => beyond parent window
+ //... I know, relying on -0 IEE754 here is ... less than ideal
+ if(signbit(alignment.horizontal())) {
+ x = (parent.x() - window.width()) + (parent.width() + window.width()) * abs(alignment.horizontal());
+ }
+ if(signbit(alignment.vertical())) {
+ y = (parent.y() - window.height()) + (parent.height() + window.height()) * abs(alignment.vertical());
+ }
+ setFramePosition({(int)x, (int)y});
return *this;
}
@@ -199,21 +221,6 @@ auto mWindow::setBackgroundColor(Color color) -> type& {
return *this;
}
-auto mWindow::setCentered(sWindow parent) -> type& {
- Geometry workspace = Desktop::workspace();
- Geometry parentGeometry = parent ? parent->frameGeometry() : workspace;
- Geometry geometry = frameGeometry();
- //center the window to its parent window ...
- int x = parentGeometry.x() + (parentGeometry.width() - geometry.width()) / 2;
- int y = parentGeometry.y() + (parentGeometry.height() - geometry.height()) / 2;
- //try and keep the window onscreen ...
- if(x + geometry.width() > workspace.width()) x = workspace.width() - geometry.width();
- if(y + geometry.height() > workspace.height()) y = workspace.height() - geometry.height();
- if(x < workspace.x()) x = workspace.x();
- if(y < workspace.y()) y = workspace.y();
- return setFrameGeometry({x, y, geometry.width(), geometry.height()});
-}
-
auto mWindow::setDismissable(bool dismissable) -> type& {
state.dismissable = dismissable;
signal(setDismissable, dismissable);
@@ -309,6 +316,15 @@ auto mWindow::setPosition(Position position) -> type& {
});
}
+auto mWindow::setPosition(sWindow relativeTo, Position position) -> type& {
+ if(!relativeTo) return setPosition(position);
+ auto geometry = relativeTo->frameGeometry();
+ return setFramePosition({
+ geometry.x() + position.x(),
+ geometry.y() + position.y()
+ });
+}
+
auto mWindow::setResizable(bool resizable) -> type& {
state.resizable = resizable;
signal(setResizable, resizable);
diff --git a/hiro/core/window.hpp b/hiro/core/window.hpp
index 9133c76e..45000235 100644
--- a/hiro/core/window.hpp
+++ b/hiro/core/window.hpp
@@ -20,6 +20,7 @@ struct mWindow : mObject {
auto frameGeometry() const -> Geometry;
auto fullScreen() const -> bool;
auto geometry() const -> Geometry;
+ auto handle() const -> uintptr_t;
auto maximized() const -> bool;
auto maximumSize() const -> Size;
auto menuBar() const -> MenuBar;
@@ -38,9 +39,9 @@ struct mWindow : mObject {
auto remove(sStatusBar statusBar) -> type&;
auto reset() -> type& override;
auto resizable() const -> bool;
- auto setAlignment(Alignment alignment) -> type&;
+ auto setAlignment(Alignment = Alignment::Center) -> type&;
+ auto setAlignment(sWindow relativeTo, Alignment = Alignment::Center) -> type&;
auto setBackgroundColor(Color color = {}) -> type&;
- auto setCentered(sWindow parent = {}) -> type&;
auto setDismissable(bool dismissable = true) -> type&;
auto setDroppable(bool droppable = true) -> type&;
auto setFrameGeometry(Geometry geometry) -> type&;
@@ -53,7 +54,8 @@ struct mWindow : mObject {
auto setMinimized(bool minimized = true) -> type&;
auto setMinimumSize(Size size = {}) -> type&;
auto setModal(bool modal = true) -> type&;
- auto setPosition(Position position) -> type&;
+ auto setPosition(Position) -> type&;
+ auto setPosition(sWindow relativeTo, Position) -> type&;
auto setResizable(bool resizable = true) -> type&;
auto setSize(Size size) -> type&;
auto setTitle(const string& title = "") -> type&;
diff --git a/hiro/extension/about-dialog.cpp b/hiro/extension/about-dialog.cpp
index c16e55be..12b29f6e 100644
--- a/hiro/extension/about-dialog.cpp
+++ b/hiro/extension/about-dialog.cpp
@@ -1,5 +1,17 @@
#if defined(Hiro_AboutDialog)
+auto AboutDialog::setAlignment(Alignment alignment) -> type& {
+ state.alignment = alignment;
+ state.relativeTo = {};
+ return *this;
+}
+
+auto AboutDialog::setAlignment(sWindow relativeTo, Alignment alignment) -> type& {
+ state.alignment = alignment;
+ state.relativeTo = relativeTo;
+ return *this;
+}
+
auto AboutDialog::setAuthor(const string& author) -> type& {
state.author = author;
return *this;
@@ -27,11 +39,6 @@ auto AboutDialog::setName(const string& name) -> type& {
return *this;
}
-auto AboutDialog::setParent(sWindow parent) -> type& {
- state.parent = parent;
- return *this;
-}
-
auto AboutDialog::setVersion(const string& version) -> type& {
state.version = version;
return *this;
@@ -47,7 +54,7 @@ auto AboutDialog::show() -> void {
window.onClose([&] { window.setModal(false); });
VerticalLayout layout{&window};
- layout.setPadding(5);
+ layout.setPadding(5_sx, 5_sy);
Label nameLabel{&layout, Size{~0, 0}};
nameLabel.setCollapsible();
@@ -59,8 +66,13 @@ auto AboutDialog::show() -> void {
Canvas logoCanvas{&layout, Size{~0, 0}};
logoCanvas.setCollapsible();
- logoCanvas.setIcon(state.logo);
- logoCanvas.setVisible((bool)state.logo);
+ if(state.logo) {
+ image logo{state.logo};
+ logo.scale(sx(logo.width()), sy(logo.height()));
+ logoCanvas.setIcon(logo);
+ } else {
+ logoCanvas.setVisible(false);
+ }
Label descriptionLabel{&layout, Size{~0, 0}};
descriptionLabel.setCollapsible();
@@ -71,7 +83,7 @@ auto AboutDialog::show() -> void {
HorizontalLayout versionLayout{&layout, Size{~0, 0}, 0};
versionLayout.setCollapsible();
- Label versionLabel{&versionLayout, Size{~0, 0}, 3};
+ Label versionLabel{&versionLayout, Size{~0, 0}, 3_sx};
versionLabel.setAlignment(1.0);
versionLabel.setFont(Font().setBold());
versionLabel.setForegroundColor({0, 0, 0});
@@ -85,7 +97,7 @@ auto AboutDialog::show() -> void {
HorizontalLayout authorLayout{&layout, Size{~0, 0}, 0};
authorLayout.setCollapsible();
- Label authorLabel{&authorLayout, Size{~0, 0}, 3};
+ Label authorLabel{&authorLayout, Size{~0, 0}, 3_sx};
authorLabel.setAlignment(1.0);
authorLabel.setFont(Font().setBold());
authorLabel.setForegroundColor({0, 0, 0});
@@ -99,7 +111,7 @@ auto AboutDialog::show() -> void {
HorizontalLayout licenseLayout{&layout, Size{~0, 0}, 0};
licenseLayout.setCollapsible();
- Label licenseLabel{&licenseLayout, Size{~0, 0}, 3};
+ Label licenseLabel{&licenseLayout, Size{~0, 0}, 3_sx};
licenseLabel.setAlignment(1.0);
licenseLabel.setFont(Font().setBold());
licenseLabel.setForegroundColor({0, 0, 0});
@@ -113,7 +125,7 @@ auto AboutDialog::show() -> void {
HorizontalLayout websiteLayout{&layout, Size{~0, 0}, 0};
websiteLayout.setCollapsible();
- Label websiteLabel{&websiteLayout, Size{~0, 0}, 3};
+ Label websiteLabel{&websiteLayout, Size{~0, 0}, 3_sx};
websiteLabel.setAlignment(1.0);
websiteLabel.setFont(Font().setBold());
websiteLabel.setForegroundColor({0, 0, 0});
@@ -123,16 +135,16 @@ auto AboutDialog::show() -> void {
websiteValue.setFont(Font().setBold());
websiteValue.setForegroundColor({0, 0, 240});
websiteValue.setText(state.website);
- websiteValue.onMouseRelease([&](Mouse::Button button) {
+ websiteValue.onMouseRelease([&](auto button) {
if(button == Mouse::Button::Left) invoke(state.website);
});
if(!state.website) websiteLayout.setVisible(false);
window.setTitle({"About ", state.name ? state.name : Application::name(), " ..."});
window.setBackgroundColor({255, 255, 240});
- window.setSize({max(360, layout.minimumSize().width()), layout.minimumSize().height()});
+ window.setSize({max(360_sx, layout.minimumSize().width()), layout.minimumSize().height()});
window.setResizable(false);
- window.setCentered(state.parent);
+ window.setAlignment(state.relativeTo, state.alignment);
window.setDismissable();
window.setVisible();
window.setModal();
diff --git a/hiro/extension/about-dialog.hpp b/hiro/extension/about-dialog.hpp
index c1cf8d3f..530b6fc7 100644
--- a/hiro/extension/about-dialog.hpp
+++ b/hiro/extension/about-dialog.hpp
@@ -3,24 +3,26 @@
struct AboutDialog {
using type = AboutDialog;
+ auto setAlignment(Alignment = Alignment::Center) -> type&;
+ auto setAlignment(sWindow relativeTo, Alignment = Alignment::Center) -> type&;
auto setAuthor(const string& author = "") -> type&;
auto setDescription(const string& description = "") -> type&;
auto setLicense(const string& license = "") -> type&;
auto setLogo(const image& logo = {}) -> type&;
auto setName(const string& name = "") -> type&;
- auto setParent(sWindow parent = {}) -> type&;
auto setVersion(const string& version = "") -> type&;
auto setWebsite(const string& website = "") -> type&;
auto show() -> void;
private:
struct State {
+ Alignment alignment = Alignment::Center;
string author;
string description;
string license;
image logo;
string name;
- sWindow parent;
+ sWindow relativeTo;
string version;
string website;
} state;
diff --git a/hiro/extension/browser-dialog.cpp b/hiro/extension/browser-dialog.cpp
index 9cc45ff6..d71fa47a 100644
--- a/hiro/extension/browser-dialog.cpp
+++ b/hiro/extension/browser-dialog.cpp
@@ -7,6 +7,7 @@ struct BrowserDialogWindow {
auto accept() -> void;
auto activate() -> void;
auto change() -> void;
+ auto context() -> void;
auto isFolder(const string& name) -> bool;
auto isMatch(const string& name) -> bool;
auto run() -> BrowserDialog::Response;
@@ -15,18 +16,26 @@ struct BrowserDialogWindow {
private:
Window window;
VerticalLayout layout{&window};
- HorizontalLayout pathLayout{&layout, Size{~0, 0}, 5};
+ HorizontalLayout pathLayout{&layout, Size{~0, 0}, 5_sx};
LineEdit pathName{&pathLayout, Size{~0, 0}, 0};
Button pathRefresh{&pathLayout, Size{0, 0}, 0};
+ Button pathNew{&pathLayout, Size{0, 0}, 0};
Button pathHome{&pathLayout, Size{0, 0}, 0};
Button pathUp{&pathLayout, Size{0, 0}, 0};
- ListView view{&layout, Size{~0, ~0}, 5};
+ ListView view{&layout, Size{~0, ~0}, 5_sx};
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
- ComboButton filterList{&controlLayout, Size{0, 0}, 5};
- LineEdit fileName{&controlLayout, Size{~0, 0}, 5};
- ComboButton optionList{&controlLayout, Size{0, 0}, 5};
- Button acceptButton{&controlLayout, Size{80, 0}, 5};
- Button cancelButton{&controlLayout, Size{80, 0}, 5};
+ ComboButton filterList{&controlLayout, Size{0, 0}, 5_sx};
+ LineEdit fileName{&controlLayout, Size{~0, 0}, 5_sx};
+ ComboButton optionList{&controlLayout, Size{0, 0}, 5_sx};
+ Button acceptButton{&controlLayout, Size{80_sx, 0}, 5_sx};
+ Button cancelButton{&controlLayout, Size{80_sx, 0}, 5_sx};
+
+ PopupMenu contextMenu;
+ MenuItem createAction{&contextMenu};
+ MenuItem renameAction{&contextMenu};
+ MenuItem removeAction{&contextMenu};
+ MenuSeparator contextSeparator{&contextMenu};
+ MenuCheckItem showHiddenOption{&contextMenu};
BrowserDialog::State& state;
BrowserDialog::Response response;
@@ -45,6 +54,8 @@ auto BrowserDialogWindow::accept() -> void {
}
if(state.action == "openFiles" && batched) {
+ string name = batched[0].text();
+ if(isFolder(name) && batched.size() == 1) return setPath({state.path, name});
for(auto item : batched) {
string name = item.text();
if(isFolder(name)) {
@@ -135,6 +146,24 @@ auto BrowserDialogWindow::change() -> void {
}
}
+auto BrowserDialogWindow::context() -> void {
+ auto batched = view.batched();
+ if(!batched) {
+ createAction.setVisible(true);
+ renameAction.setVisible(false);
+ removeAction.setVisible(false);
+ } else if(batched.size() == 1) {
+ createAction.setVisible(false);
+ renameAction.setVisible(true);
+ removeAction.setVisible(true);
+ } else {
+ createAction.setVisible(false);
+ renameAction.setVisible(false);
+ removeAction.setVisible(true);
+ }
+ contextMenu.setVisible();
+}
+
auto BrowserDialogWindow::isFolder(const string& name) -> bool {
return directory::exists({state.path, name});
}
@@ -151,12 +180,28 @@ auto BrowserDialogWindow::isMatch(const string& name) -> bool {
auto BrowserDialogWindow::run() -> BrowserDialog::Response {
response = {};
- layout.setPadding(5);
+ auto document = BML::unserialize(file::read({Path::userSettings(), "hiro/browser-dialog.bml"}));
+ struct Settings {
+ bool showHidden = true;
+ } settings;
+ if(auto node = document["BrowserDialog/ShowHidden"]) settings.showHidden = node.boolean();
+
+ layout.setPadding(5_sx, 5_sy);
pathName.onActivate([&] { setPath(pathName.text()); });
- pathRefresh.setBordered(false).setIcon(Icon::Action::Refresh).onActivate([&] { setPath(state.path); });
- pathHome.setBordered(false).setIcon(Icon::Go::Home).onActivate([&] { setPath(Path::user()); });
- pathUp.setBordered(false).setIcon(Icon::Go::Up).onActivate([&] { setPath(Location::dir(state.path)); });
+ image iconRefresh{Icon::Action::Refresh};
+ iconRefresh.scale(16_sx, 16_sy);
+ pathRefresh.setBordered(false).setIcon(iconRefresh).onActivate([&] { setPath(state.path); });
+ image iconNew{Icon::Action::NewFolder};
+ iconNew.scale(16_sx, 16_sy);
+ pathNew.setBordered(false).setIcon(iconNew).onActivate([&] { createAction.doActivate(); });
+ image iconHome{Icon::Go::Home};
+ iconHome.scale(16_sx, 16_sy);
+ pathHome.setBordered(false).setIcon(iconHome).onActivate([&] { setPath(Path::user()); });
+ image iconUp{Icon::Go::Up};
+ iconUp.scale(16_sx, 16_sy);
+ pathUp.setBordered(false).setIcon(iconUp).onActivate([&] { setPath(Location::dir(state.path)); });
view.setBatchable(state.action == "openFiles").onActivate([&] { activate(); }).onChange([&] { change(); });
+ view.onContext([&] { context(); });
filterList.setVisible(state.action != "selectFolder").onChange([&] { setPath(state.path); });
for(auto& filter : state.filters) {
auto part = filter.split("|", 1L);
@@ -184,12 +229,101 @@ auto BrowserDialogWindow::run() -> BrowserDialog::Response {
filters.append(part.right().split(":"));
}
+ createAction.setIcon(Icon::Action::NewFolder).setText("Create Folder ...").onActivate([&] {
+ if(auto name = NameDialog()
+ .setTitle("Create Folder")
+ .setText("Enter a new folder name:")
+ .setIcon(Icon::Emblem::Folder)
+ .setAlignment(window)
+ .create()
+ ) {
+ directory::create({state.path, name});
+ pathRefresh.doActivate();
+ }
+ });
+
+ renameAction.setIcon(Icon::Application::TextEditor).setText("Rename ...").onActivate([&] {
+ auto batched = view.batched();
+ if(batched.size() != 1) return;
+ auto name = batched[0].text();
+ if(directory::exists({state.path, name})) {
+ if(auto rename = NameDialog()
+ .setTitle({"Rename ", name})
+ .setText("Enter the new folder name:")
+ .setIcon(Icon::Emblem::Folder)
+ .setAlignment(window)
+ .rename(name)
+ ) {
+ if(name == rename) return;
+ if(!directory::rename({state.path, name}, {state.path, rename})) return (void)MessageDialog()
+ .setTitle("Error")
+ .setText("Failed to rename folder.")
+ .setAlignment(window)
+ .error();
+ pathRefresh.doActivate();
+ }
+ } else if(file::exists({state.path, name})) {
+ if(auto rename = NameDialog()
+ .setTitle({"Rename ", name})
+ .setText("Enter the new file name:")
+ .setIcon(Icon::Emblem::File)
+ .setAlignment(window)
+ .rename(name)
+ ) {
+ if(name == rename) return;
+ if(!file::rename({state.path, name}, {state.path, rename})) return (void)MessageDialog()
+ .setTitle("Error")
+ .setText("Failed to rename file.")
+ .setAlignment(window)
+ .error();
+ pathRefresh.doActivate();
+ }
+ }
+ });
+
+ removeAction.setIcon(Icon::Action::Remove).setText("Delete ...").onActivate([&] {
+ auto batched = view.batched();
+ if(!batched) return;
+ if(MessageDialog()
+ .setTitle("Remove Selected")
+ .setText({"Are you sure you want to permanently delete the selected item", batched.size() == 1 ? "" : "s", "?"})
+ .setAlignment(window)
+ .question() == "No") return;
+ for(auto& item : batched) {
+ auto name = item.text();
+ if(directory::exists({state.path, name})) {
+ if(!directory::remove({state.path, name})) {
+ if(MessageDialog()
+ .setTitle("Warning")
+ .setText({"Failed to remove ", name, "\n\nContinue trying to remove remaining items?"})
+ .question() == "No") break;
+ }
+ } else if(file::exists({state.path, name})) {
+ if(!file::remove({state.path, name})) {
+ if(MessageDialog()
+ .setTitle("Warning")
+ .setText({"Failed to remove ", name, "\n\nContinue trying to remove remaining items?"})
+ .question() == "No") break;
+ }
+ }
+ }
+ pathRefresh.doActivate();
+ });
+
+ showHiddenOption.setChecked(settings.showHidden).setText("Show Hidden").onToggle([&] {
+ auto document = BML::unserialize(file::read({Path::userSettings(), "hiro/browser-dialog.bml"}));
+ document("BrowserDialog/ShowHidden").setValue(showHiddenOption.checked());
+ directory::create({Path::userSettings(), "hiro/"});
+ file::write({Path::userSettings(), "hiro/browser-dialog.bml"}, BML::serialize(document));
+ pathRefresh.doActivate();
+ });
+
setPath(state.path);
window.onClose([&] { window.setModal(false); });
window.setTitle(state.title);
- window.setSize({640, 480});
- window.setCentered(state.parent);
+ window.setSize({640_sx, 480_sy});
+ window.setAlignment(state.relativeTo, state.alignment);
window.setDismissable();
window.setVisible();
view.setFocused();
@@ -218,6 +352,7 @@ auto BrowserDialogWindow::setPath(string path) -> void {
} else {
continue;
}
+ if(!showHiddenOption.checked() && directory::hidden({state.path, content})) continue;
view.append(ListViewItem().setText(content).setIcon(Icon::Emblem::Folder));
}
@@ -230,6 +365,7 @@ auto BrowserDialogWindow::setPath(string path) -> void {
if(state.action == "openFolder") continue;
}
if(!isMatch(content)) continue;
+ if(!showHiddenOption.checked() && file::hidden({state.path, content})) continue;
view.append(ListViewItem().setText(content).setIcon(isFolder ? (image)Icon::Action::Open : (image)Icon::Emblem::File));
}
@@ -293,6 +429,18 @@ auto BrowserDialog::selectFolder() -> string {
return {};
}
+auto BrowserDialog::setAlignment(Alignment alignment) -> type& {
+ state.alignment = alignment;
+ state.relativeTo = {};
+ return *this;
+}
+
+auto BrowserDialog::setAlignment(sWindow relativeTo, Alignment alignment) -> type& {
+ state.alignment = alignment;
+ state.relativeTo = relativeTo;
+ return *this;
+}
+
auto BrowserDialog::setFilters(const vector& filters) -> type& {
state.filters = filters;
return *this;
@@ -303,11 +451,6 @@ auto BrowserDialog::setOptions(const vector& options) -> type& {
return *this;
}
-auto BrowserDialog::setParent(const sWindow& parent) -> type& {
- state.parent = parent;
- return *this;
-}
-
auto BrowserDialog::setPath(const string& path) -> type& {
state.path = path;
return *this;
diff --git a/hiro/extension/browser-dialog.hpp b/hiro/extension/browser-dialog.hpp
index 8ba3cd25..dbba5c39 100644
--- a/hiro/extension/browser-dialog.hpp
+++ b/hiro/extension/browser-dialog.hpp
@@ -14,19 +14,21 @@ struct BrowserDialog {
auto saveFile() -> string; //one file
auto selected() -> vector;
auto selectFolder() -> string; //one existing folder
+ auto setAlignment(Alignment = Alignment::Center) -> type&;
+ auto setAlignment(sWindow relativeTo, Alignment = Alignment::Center) -> type&;
auto setFilters(const vector& filters = {}) -> type&;
auto setOptions(const vector& options = {}) -> type&;
- auto setParent(const sWindow& parent) -> type&;
auto setPath(const string& path = "") -> type&;
auto setTitle(const string& title = "") -> type&;
private:
struct State {
string action;
+ Alignment alignment = Alignment::Center;
vector filters = {"*"};
vector options;
- sWindow parent;
string path;
+ sWindow relativeTo;
string title;
} state;
diff --git a/hiro/extension/extension.cpp b/hiro/extension/extension.cpp
index b2ba0d5f..a6c1c2a6 100644
--- a/hiro/extension/extension.cpp
+++ b/hiro/extension/extension.cpp
@@ -7,8 +7,11 @@ namespace hiro {
#include "horizontal-layout.cpp"
#include "vertical-layout.cpp"
#include "table-layout.cpp"
+ #include "horizontal-resize-grip.cpp"
+ #include "vertical-resize-grip.cpp"
#include "list-view.cpp"
- #include "browser-dialog.cpp"
#include "message-dialog.cpp"
+ #include "name-dialog.cpp"
+ #include "browser-dialog.cpp"
#include "about-dialog.cpp"
}
diff --git a/hiro/extension/extension.hpp b/hiro/extension/extension.hpp
index 19458863..e8de1d9a 100644
--- a/hiro/extension/extension.hpp
+++ b/hiro/extension/extension.hpp
@@ -4,9 +4,12 @@ namespace hiro {
#include "horizontal-layout.hpp"
#include "vertical-layout.hpp"
#include "table-layout.hpp"
+ #include "horizontal-resize-grip.hpp"
+ #include "vertical-resize-grip.hpp"
#include "list-view.hpp"
#include "shared.hpp"
- #include "browser-dialog.hpp"
#include "message-dialog.hpp"
+ #include "name-dialog.hpp"
+ #include "browser-dialog.hpp"
#include "about-dialog.hpp"
}
diff --git a/hiro/extension/fixed-layout.cpp b/hiro/extension/fixed-layout.cpp
index 102c33ff..03963d4b 100644
--- a/hiro/extension/fixed-layout.cpp
+++ b/hiro/extension/fixed-layout.cpp
@@ -24,6 +24,10 @@ auto mFixedLayout::cell(sSizable sizable) const -> FixedLayoutCell {
return {};
}
+auto mFixedLayout::cells() const -> vector {
+ return state.cells;
+}
+
auto mFixedLayout::cellCount() const -> uint {
return state.cells.size();
}
@@ -63,6 +67,11 @@ auto mFixedLayout::reset() -> type& {
return synchronize();
}
+auto mFixedLayout::resize() -> type& {
+ setGeometry(geometry());
+ return *this;
+}
+
auto mFixedLayout::setEnabled(bool enabled) -> type& {
mSizable::setEnabled(enabled);
for(auto& cell : state.cells) cell.sizable().setEnabled(cell.sizable().enabled());
diff --git a/hiro/extension/fixed-layout.hpp b/hiro/extension/fixed-layout.hpp
index 46f07687..77d23937 100644
--- a/hiro/extension/fixed-layout.hpp
+++ b/hiro/extension/fixed-layout.hpp
@@ -16,11 +16,13 @@ struct mFixedLayout : mSizable {
auto append(sSizable sizable, Geometry geometry) -> type&;
auto cell(uint position) const -> FixedLayoutCell;
auto cell(sSizable sizable) const -> FixedLayoutCell;
+ auto cells() const -> vector;
auto cellCount() const -> uint;
auto minimumSize() const -> Size override;
auto remove(sSizable sizable) -> type&;
auto remove(sFixedLayoutCell cell) -> type&;
auto reset() -> type& override;
+ auto resize() -> type&;
auto setEnabled(bool enabled) -> type& override;
auto setFont(const Font& font) -> type& override;
auto setParent(mObject* parent = nullptr, int offset = -1) -> type& override;
diff --git a/hiro/extension/horizontal-layout.cpp b/hiro/extension/horizontal-layout.cpp
index a47918fb..d6c6b11a 100644
--- a/hiro/extension/horizontal-layout.cpp
+++ b/hiro/extension/horizontal-layout.cpp
@@ -29,6 +29,10 @@ auto mHorizontalLayout::cell(sSizable sizable) const -> HorizontalLayoutCell {
return {};
}
+auto mHorizontalLayout::cells() const -> vector {
+ return state.cells;
+}
+
auto mHorizontalLayout::cellCount() const -> uint {
return state.cells.size();
}
@@ -95,6 +99,11 @@ auto mHorizontalLayout::reset() -> type& {
return synchronize();
}
+auto mHorizontalLayout::resize() -> type& {
+ setGeometry(geometry());
+ return *this;
+}
+
auto mHorizontalLayout::setAlignment(maybe alignment) -> type& {
state.alignment = alignment;
return synchronize();
@@ -113,7 +122,7 @@ auto mHorizontalLayout::setFont(const Font& font) -> type& {
}
auto mHorizontalLayout::setGeometry(Geometry requestedGeometry) -> type& {
- if(!visible(true)) return mSizable::setGeometry(requestedGeometry), *this;
+//if(!visible(true)) return mSizable::setGeometry(requestedGeometry), *this;
auto geometry = requestedGeometry;
geometry.setX(geometry.x() + padding().x());
diff --git a/hiro/extension/horizontal-layout.hpp b/hiro/extension/horizontal-layout.hpp
index c99cd2f0..bad2b15c 100644
--- a/hiro/extension/horizontal-layout.hpp
+++ b/hiro/extension/horizontal-layout.hpp
@@ -14,15 +14,17 @@ struct mHorizontalLayout : mSizable {
using mSizable::remove;
auto alignment() const -> maybe;
- auto append(sSizable sizable, Size size, float spacing = 5) -> type&;
+ auto append(sSizable sizable, Size size, float spacing = 5_sy) -> type&;
auto cell(uint position) const -> HorizontalLayoutCell;
auto cell(sSizable sizable) const -> HorizontalLayoutCell;
+ auto cells() const -> vector;
auto cellCount() const -> uint;
auto minimumSize() const -> Size override;
auto padding() const -> Geometry;
auto remove(sSizable sizable) -> type&;
auto remove(sHorizontalLayoutCell cell) -> type&;
auto reset() -> type& override;
+ auto resize() -> type&;
auto setAlignment(maybe alignment) -> type&;
auto setEnabled(bool enabled) -> type& override;
auto setFont(const Font& font) -> type& override;
@@ -41,7 +43,7 @@ private:
maybe alignment;
vector cells;
Geometry padding;
- float spacing = 5;
+ float spacing = 5_sx;
} state;
};
@@ -70,7 +72,7 @@ private:
maybe alignment;
sSizable sizable;
Size size;
- float spacing = 5;
+ float spacing = 5_sx;
} state;
friend class mHorizontalLayout;
diff --git a/hiro/extension/horizontal-resize-grip.cpp b/hiro/extension/horizontal-resize-grip.cpp
new file mode 100644
index 00000000..afdae850
--- /dev/null
+++ b/hiro/extension/horizontal-resize-grip.cpp
@@ -0,0 +1,49 @@
+#if defined(Hiro_HorizontalResizeGrip)
+
+mHorizontalResizeGrip::mHorizontalResizeGrip() {
+ image icon;
+ icon.allocate(5, 15);
+ for(uint y : range(icon.height())) {
+ auto data = icon.data() + y * icon.pitch();
+ icon.write(data, 0x00000000); data += icon.stride();
+ icon.write(data, 0xff9f9f9f); data += icon.stride();
+ icon.write(data, 0x00000000); data += icon.stride();
+ icon.write(data, 0xff9f9f9f); data += icon.stride();
+ icon.write(data, 0x00000000); data += icon.stride();
+ }
+ mCanvas::setIcon(icon);
+ mCanvas::onMousePress([&](auto button) {
+ if(button == Mouse::Button::Left && !state.timer.enabled()) {
+ doActivate();
+ state.offset = 0;
+ state.origin = Mouse::position();
+ state.timer.setEnabled();
+ }
+ });
+ state.timer.setInterval(10).onActivate([&] {
+ if(!Mouse::pressed(Mouse::Button::Left)) return (void)state.timer.setEnabled(false);
+ auto position = Mouse::position();
+ auto offset = position.x() - state.origin.x();
+ if(offset != state.offset) doResize(offset), offset = state.offset;
+ });
+}
+
+auto mHorizontalResizeGrip::doActivate() const -> void {
+ if(state.onActivate) state.onActivate();
+}
+
+auto mHorizontalResizeGrip::doResize(int offset) const -> void {
+ if(state.onResize) state.onResize(offset);
+}
+
+auto mHorizontalResizeGrip::onActivate(const function& callback) -> type& {
+ state.onActivate = callback;
+ return *this;
+}
+
+auto mHorizontalResizeGrip::onResize(const function& callback) -> type& {
+ state.onResize = callback;
+ return *this;
+}
+
+#endif
diff --git a/hiro/extension/horizontal-resize-grip.hpp b/hiro/extension/horizontal-resize-grip.hpp
new file mode 100644
index 00000000..8f7b588b
--- /dev/null
+++ b/hiro/extension/horizontal-resize-grip.hpp
@@ -0,0 +1,26 @@
+#if defined(Hiro_HorizontalResizeGrip)
+
+struct HorizontalResizeGrip;
+struct mHorizontalResizeGrip;
+using sHorizontalResizeGrip = shared_pointer;
+
+struct mHorizontalResizeGrip : mCanvas {
+ using type = mHorizontalResizeGrip;
+
+ mHorizontalResizeGrip();
+ auto doActivate() const -> void;
+ auto doResize(int offset) const -> void;
+ auto onActivate(const function& callback) -> type&;
+ auto onResize(const function& callback) -> type&;
+
+//private:
+ struct State {
+ function onActivate;
+ function onResize;
+ int offset = 0;
+ Position origin;
+ Timer timer;
+ } state;
+};
+
+#endif
diff --git a/hiro/extension/list-view.cpp b/hiro/extension/list-view.cpp
index 24802613..22c780f6 100644
--- a/hiro/extension/list-view.cpp
+++ b/hiro/extension/list-view.cpp
@@ -1,12 +1,9 @@
#if defined(Hiro_ListView)
mListView::mListView() {
- mTableView::onActivate([&] {
- doActivate();
- });
- mTableView::onChange([&] {
- doChange();
- });
+ mTableView::onActivate([&] { doActivate(); });
+ mTableView::onChange([&] { doChange(); });
+ mTableView::onContext([&] { doContext(); });
mTableView::onToggle([&](TableViewCell cell) {
if(auto item = cell->parentTableViewItem()) {
if(auto shared = item->instance.acquire()) {
@@ -32,6 +29,10 @@ auto mListView::doChange() const -> void {
if(state.onChange) state.onChange();
}
+auto mListView::doContext() const -> void {
+ if(state.onContext) state.onContext();
+}
+
auto mListView::doToggle(ListViewItem item) const -> void {
if(state.onToggle) state.onToggle(item);
}
@@ -57,6 +58,11 @@ auto mListView::onChange(const function& callback) -> type& {
return *this;
}
+auto mListView::onContext(const function& callback) -> type& {
+ state.onContext = callback;
+ return *this;
+}
+
auto mListView::onToggle(const function& callback) -> type& {
state.onToggle = callback;
return *this;
@@ -68,10 +74,26 @@ auto mListView::reset() -> type& {
return *this;
}
+auto mListView::resize() -> type& {
+ mTableView::resizeColumns();
+ return *this;
+}
+
auto mListView::selected() const -> ListViewItem {
return ListViewItem{mTableView::selected()};
}
+auto mListView::setVisible(bool visible) -> type& {
+ mTableView::setVisible(visible);
+#if 0
+ if(visible) {
+ Application::processEvents(); //heavy-handed, but necessary for proper Widget geometry
+ mTableView::resizeColumns();
+ }
+#endif
+ return *this;
+}
+
//
mListViewItem::mListViewItem() {
diff --git a/hiro/extension/list-view.hpp b/hiro/extension/list-view.hpp
index ce7a7f41..e1c7c382 100644
--- a/hiro/extension/list-view.hpp
+++ b/hiro/extension/list-view.hpp
@@ -18,19 +18,24 @@ struct mListView : mTableView {
auto batched() const -> vector;
auto doActivate() const -> void;
auto doChange() const -> void;
+ auto doContext() const -> void;
auto doToggle(ListViewItem) const -> void;
auto item(uint position) const -> ListViewItem;
auto items() const -> vector;
auto onActivate(const function& callback) -> type&;
auto onChange(const function& callback) -> type&;
+ auto onContext(const function& callback) -> type&;
auto onToggle(const function& callback) -> type&;
auto reset() -> type& override;
+ auto resize() -> type&;
auto selected() const -> ListViewItem;
+ auto setVisible(bool visible = true) -> type&;
//private:
struct State {
function onActivate;
function onChange;
+ function onContext;
function onToggle;
} state;
};
diff --git a/hiro/extension/message-dialog.cpp b/hiro/extension/message-dialog.cpp
index ebfcd7a0..ff35cba7 100644
--- a/hiro/extension/message-dialog.cpp
+++ b/hiro/extension/message-dialog.cpp
@@ -4,6 +4,10 @@ MessageDialog::MessageDialog(const string& text) {
state.text = text;
}
+auto MessageDialog::checked() const -> bool {
+ return state.checked;
+}
+
auto MessageDialog::error(const vector& buttons) -> string {
state.buttons = buttons;
state.icon = Icon::Prompt::Error;
@@ -22,8 +26,25 @@ auto MessageDialog::question(const vector& buttons) -> string {
return _run();
}
-auto MessageDialog::setParent(shared_pointer parent) -> type& {
- state.parent = parent;
+auto MessageDialog::setAlignment(Alignment alignment) -> type& {
+ state.alignment = alignment;
+ state.relativeTo = {};
+ return *this;
+}
+
+auto MessageDialog::setAlignment(sWindow relativeTo, Alignment alignment) -> type& {
+ state.alignment = alignment;
+ state.relativeTo = relativeTo;
+ return *this;
+}
+
+auto MessageDialog::setChecked(bool checked) -> type& {
+ state.checked = checked;
+ return *this;
+}
+
+auto MessageDialog::setOption(const string& option) -> type& {
+ state.option = option;
return *this;
}
@@ -44,23 +65,32 @@ auto MessageDialog::warning(const vector& buttons) -> string {
}
auto MessageDialog::_run() -> string {
+ if(!state.buttons) return {}; //nothing to do
Application::Namespace tr{"MessageDialog"};
Window window;
VerticalLayout layout{&window};
- HorizontalLayout messageLayout{&layout, Size{~0, 0}, 5};
- VerticalLayout messageIconLayout{&messageLayout, Size{16, ~0}, 5};
- Canvas messageIcon{&messageIconLayout, Size{16, 16}, 0};
- Widget messageIconSpacer{&messageIconLayout, Size{16, ~0}};
+ HorizontalLayout messageLayout{&layout, Size{~0, 0}, 5_sy};
+ VerticalLayout messageIconLayout{&messageLayout, Size{16_sx, ~0}, 5_sx};
+ Canvas messageIcon{&messageIconLayout, Size{16_sx, 16_sy}, 0};
+ Widget messageIconSpacer{&messageIconLayout, Size{16_sx, ~0}};
Label messageText{&messageLayout, Size{~0, 0}};
+ Widget optionSpacer{&layout, Size{0, 0}};
+ CheckLabel optionText{&layout, Size{~0, 0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Widget controlSpacer{&controlLayout, Size{~0, 0}};
- layout.setPadding(5);
- messageIcon.setIcon(state.icon);
+ layout.setPadding(5_sx, 5_sy);
+ image icon{state.icon};
+ icon.scale(16_sx, 16_sy);
+ messageIcon.setIcon(icon);
messageText.setText(state.text);
+ optionSpacer.setCollapsible().setVisible((bool)state.option);
+ optionText.setCollapsible().setChecked(state.checked).setText(state.option).setVisible((bool)state.option).onToggle([&] {
+ state.checked = optionText.checked();
+ });
for(auto n : range(state.buttons.size())) {
- Button button{&controlLayout, Size{80, 0}, 5};
+ Button button{&controlLayout, Size{80_sx, 0}, 5_sx};
button.onActivate([&, n] {
state.response = state.buttons[n];
window.setModal(false);
@@ -69,15 +99,26 @@ auto MessageDialog::_run() -> string {
button.setFocused(); //the last button will have effective focus
}
- int widthMessage = 5 + 16 + 5 + Font().size(state.text).width() + 5;
- int widthButtons = 5 + state.buttons.size() * 85;
- int width = max(320, widthMessage, widthButtons);
+ int widthMessage = 5_sx + 16 + 5_sx + Font().size(state.text).width() + 5_sx;
+ int widthButtons = 5_sx + state.buttons.size() * 85_sx;
+ int width = max(320_sx, widthMessage, widthButtons);
+
+ window.onClose([&] {
+ //if the dialog is dismissed (escape pressed, or window manager close button clicked),
+ //set the response to the last button shown (which is also the default selected button),
+ //and set a flag to indicate that the dialog was dismissed to the caller.
+ //note that the safest option should always be the last option in the buttons list.
+ if(!state.response) {
+ state.response = state.buttons.last();
+ state.dismissed = true;
+ }
+ window.setModal(false);
+ });
- window.onClose([&] { window.setModal(false); });
window.setTitle(state.title);
window.setResizable(false);
window.setSize({width, layout.minimumSize().height()});
- window.setCentered(state.parent);
+ window.setAlignment(state.relativeTo, state.alignment);
window.setDismissable();
window.setVisible();
window.setModal();
diff --git a/hiro/extension/message-dialog.hpp b/hiro/extension/message-dialog.hpp
index 3cbd4d64..23fab7c2 100644
--- a/hiro/extension/message-dialog.hpp
+++ b/hiro/extension/message-dialog.hpp
@@ -4,19 +4,28 @@ struct MessageDialog {
using type = MessageDialog;
MessageDialog(const string& text = "");
+ auto checked() const -> bool;
+ auto dismissed() const -> bool;
auto error(const vector& buttons = {"Ok"}) -> string;
auto information(const vector& buttons = {"Ok"}) -> string;
auto question(const vector& buttons = {"Yes", "No"}) -> string;
- auto setParent(sWindow parent = {}) -> type&;
+ auto setAlignment(Alignment = Alignment::Center) -> type&;
+ auto setAlignment(sWindow relativeTo, Alignment = Alignment::Center) -> type&;
+ auto setChecked(bool checked = true) -> type&;
+ auto setOption(const string& option = "") -> type&;
auto setText(const string& text = "") -> type&;
auto setTitle(const string& title = "") -> type&;
auto warning(const vector& buttons = {"Ok"}) -> string;
private:
struct State {
+ Alignment alignment = Alignment::Center;
vector buttons;
+ bool checked = false;
+ bool dismissed = false;
image icon;
- sWindow parent;
+ string option;
+ sWindow relativeTo;
string response;
string text;
string title;
diff --git a/hiro/extension/name-dialog.cpp b/hiro/extension/name-dialog.cpp
new file mode 100644
index 00000000..e1f98b82
--- /dev/null
+++ b/hiro/extension/name-dialog.cpp
@@ -0,0 +1,80 @@
+#if defined(Hiro_NameDialog)
+
+NameDialog::NameDialog() {
+ layout.setPadding(5_sx, 5_sy);
+ typeIcon.setCollapsible();
+ nameValue.onActivate([&] { acceptButton.doActivate(); });
+ acceptButton.onActivate([&] {
+ response = nameValue.text();
+ window.doClose();
+ });
+ cancelButton.setText("Cancel").onActivate([&] { window.doClose(); });
+
+ window.onClose([&] {
+ window.setModal(false);
+ window.setVisible(false);
+ });
+
+ window.setDismissable();
+}
+
+auto NameDialog::create(string name) -> string {
+ return show("Create", name);
+}
+
+auto NameDialog::rename(string name) -> string {
+ return show("Rename", name);
+}
+
+auto NameDialog::setAlignment(Alignment alignment) -> type& {
+ state.alignment = alignment;
+ state.relativeTo = {};
+ return *this;
+}
+
+auto NameDialog::setAlignment(sWindow relativeTo, Alignment alignment) -> type& {
+ state.alignment = alignment;
+ state.relativeTo = relativeTo;
+ return *this;
+}
+
+auto NameDialog::setIcon(const image& icon) -> type& {
+ state.icon = icon;
+ return *this;
+}
+
+auto NameDialog::setText(const string& text) -> type& {
+ state.text = text;
+ return *this;
+}
+
+auto NameDialog::setTitle(const string& title) -> type& {
+ state.title = title;
+ return *this;
+}
+
+auto NameDialog::show(string mode, string name) -> string {
+ response = {};
+ setTitle(state.title);
+ if(!state.title && mode == "Create") setTitle("Create");
+ if(!state.title && mode == "Rename") setTitle({"Rename ", name});
+ textLabel.setText(state.text ? state.text : "Enter a name:");
+ if(state.icon) {
+ image icon{state.icon};
+ icon.scale(16_sx, 16_sy);
+ typeIcon.setIcon(icon);
+ } else {
+ typeIcon.setVisible(false);
+ }
+ nameValue.setText(name);
+ acceptButton.setText(mode);
+ window.setTitle(state.title);
+ window.setSize({400_sx, layout.minimumSize().height()});
+ window.setAlignment(state.relativeTo, state.alignment);
+ window.setVisible();
+ nameValue.setFocused();
+ window.setModal();
+ return response;
+}
+
+#endif
diff --git a/hiro/extension/name-dialog.hpp b/hiro/extension/name-dialog.hpp
new file mode 100644
index 00000000..fec7c1ef
--- /dev/null
+++ b/hiro/extension/name-dialog.hpp
@@ -0,0 +1,40 @@
+#if defined(Hiro_NameDialog)
+
+struct NameDialog {
+ using type = NameDialog;
+
+ NameDialog();
+ auto create(string name = "") -> string;
+ auto rename(string name) -> string;
+ auto setIcon(const image& icon = {}) -> type&;
+ auto setAlignment(Alignment = Alignment::Center) -> type&;
+ auto setAlignment(sWindow relativeTo, Alignment = Alignment::Center) -> type&;
+ auto setText(const string& text = {}) -> type&;
+ auto setTitle(const string& title = {}) -> type&;
+
+private:
+ auto show(string mode, string name) -> string;
+
+ Window window;
+ VerticalLayout layout{&window};
+ Label textLabel{&layout, Size{~0, 0}};
+ HorizontalLayout nameLayout{&layout, Size{~0, 0}};
+ Canvas typeIcon{&nameLayout, Size{16_sx, 16_sy}};
+ LineEdit nameValue{&nameLayout, Size{~0, 0}};
+ HorizontalLayout controlLayout{&layout, Size{~0, 0}};
+ Widget controlSpacer{&controlLayout, Size{~0, 0}};
+ Button acceptButton{&controlLayout, Size{80, 0}};
+ Button cancelButton{&controlLayout, Size{80, 0}};
+
+ struct State {
+ Alignment alignment = Alignment::Center;
+ image icon;
+ sWindow relativeTo;
+ string text;
+ string title;
+ } state;
+
+ string response;
+};
+
+#endif
diff --git a/hiro/extension/shared.hpp b/hiro/extension/shared.hpp
index 9cc50c8b..7cb444e0 100644
--- a/hiro/extension/shared.hpp
+++ b/hiro/extension/shared.hpp
@@ -14,10 +14,12 @@ struct FixedLayout : sFixedLayout {
auto append(sSizable sizable, Geometry geometry) { return self().append(sizable, geometry), *this; }
auto cell(uint position) const { return self().cell(position); }
auto cell(sSizable sizable) const { return self().cell(sizable); }
+ auto cells() const { return self().cells(); }
auto cellCount() const { return self().cellCount(); }
auto remove(sSizable sizable) { return self().remove(sizable), *this; }
auto remove(sFixedLayoutCell cell) { return self().remove(cell), *this; }
auto reset() { return self().reset(), *this; }
+ auto resize() { return self().resize(), *this; }
};
#endif
@@ -30,7 +32,7 @@ struct HorizontalLayoutCell : sHorizontalLayoutCell {
auto setAlignment(maybe alignment = {}) { return self().setAlignment(alignment), *this; }
auto setSizable(sSizable sizable) { return self().setSizable(sizable), *this; }
auto setSize(Size size) { return self().setSize(size), *this; }
- auto setSpacing(float spacing = 5) { return self().setSpacing(spacing), *this; }
+ auto setSpacing(float spacing = 5_sx) { return self().setSpacing(spacing), *this; }
auto sizable() const { return self().sizable(); }
auto size() const { return self().size(); }
auto spacing() const { return self().spacing(); }
@@ -40,17 +42,20 @@ struct HorizontalLayout : sHorizontalLayout {
DeclareSharedSizable(HorizontalLayout)
auto alignment() const { return self().alignment(); }
- auto append(sSizable sizable, Size size, float spacing = 5) { return self().append(sizable, size, spacing), *this; }
+ auto append(sSizable sizable, Size size, float spacing = 5_sx) { return self().append(sizable, size, spacing), *this; }
auto cell(uint position) const { return self().cell(position); }
auto cell(sSizable sizable) const { return self().cell(sizable); }
+ auto cells() const { return self().cells(); }
auto cellCount() const { return self().cellCount(); }
auto remove(sSizable sizable) { return self().remove(sizable), *this; }
auto remove(sHorizontalLayoutCell cell) { return self().remove(cell), *this; }
auto reset() { return self().reset(), *this; }
+ auto resize() { return self().resize(), *this; }
auto setAlignment(maybe alignment = {}) { return self().setAlignment(alignment), *this; }
auto setPadding(float padding) { return self().setPadding({padding, padding, padding, padding}), *this; }
+ auto setPadding(float x, float y) { return self().setPadding({x, y, x, y}), *this; }
auto setPadding(Geometry padding = {}) { return self().setPadding(padding), *this; }
- auto setSpacing(float spacing = 5) { return self().setSpacing(spacing), *this; }
+ auto setSpacing(float spacing = 5_sx) { return self().setSpacing(spacing), *this; }
};
#endif
@@ -63,7 +68,7 @@ struct VerticalLayoutCell : sVerticalLayoutCell {
auto setAlignment(maybe alignment = {}) { return self().setAlignment(alignment), *this; }
auto setSizable(sSizable sizable) { return self().setSizable(sizable), *this; }
auto setSize(Size size) { return self().setSize(size), *this; }
- auto setSpacing(float spacing = 5) { return self().setSpacing(spacing), *this; }
+ auto setSpacing(float spacing = 5_sy) { return self().setSpacing(spacing), *this; }
auto sizable() const { return self().sizable(); }
auto size() const { return self().size(); }
auto spacing() const { return self().spacing(); }
@@ -73,17 +78,20 @@ struct VerticalLayout : sVerticalLayout {
DeclareSharedSizable(VerticalLayout)
auto alignment() const { return self().alignment(); }
- auto append(sSizable sizable, Size size, float spacing = 5) { return self().append(sizable, size, spacing), *this; }
+ auto append(sSizable sizable, Size size, float spacing = 5_sy) { return self().append(sizable, size, spacing), *this; }
auto cell(uint position) const { return self().cell(position); }
auto cell(sSizable sizable) const { return self().cell(sizable); }
+ auto cells() const { return self().cells(); }
auto cellCount() const { return self().cellCount(); }
auto remove(sSizable sizable) { return self().remove(sizable), *this; }
auto remove(sVerticalLayoutCell cell) { return self().remove(cell), *this; }
auto reset() { return self().reset(), *this; }
+ auto resize() { return self().resize(), *this; }
auto setAlignment(maybe alignment = {}) { return self().setAlignment(alignment), *this; }
auto setPadding(float padding) { return self().setPadding({padding, padding, padding, padding}), *this; }
+ auto setPadding(float x, float y) { return self().setPadding({x, y, x, y}), *this; }
auto setPadding(Geometry padding = {}) { return self().setPadding(padding), *this; }
- auto setSpacing(float spacing = 5) { return self().setSpacing(spacing), *this; }
+ auto setSpacing(float spacing = 5_sy) { return self().setSpacing(spacing), *this; }
};
#endif
@@ -104,7 +112,7 @@ struct TableLayoutColumn : sTableLayoutColumn {
auto alignment() const { return self().alignment(); }
auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; }
- auto setSpacing(float spacing = 5) { return self().setSpacing(spacing), *this; }
+ auto setSpacing(float spacing = 5_sx) { return self().setSpacing(spacing), *this; }
auto spacing() const { return self().spacing(); }
};
@@ -113,7 +121,7 @@ struct TableLayoutRow : sTableLayoutRow {
auto alignment() const { return self().alignment(); }
auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; }
- auto setSpacing(float spacing = 5) { return self().setSpacing(spacing), *this; }
+ auto setSpacing(float spacing = 5_sy) { return self().setSpacing(spacing), *this; }
auto spacing() const { return self().spacing(); }
};
@@ -125,23 +133,50 @@ struct TableLayout : sTableLayout {
auto cell(uint position) const { return self().cell(position); }
auto cell(uint x, uint y) const { return self().cell(x, y); }
auto cell(sSizable sizable) const { return self().cell(sizable); }
+ auto cells() const { return self().cells(); }
auto cellCount() const { return self().cellCount(); }
auto column(uint position) const { return self().column(position); }
+ auto columns() const { return self().columns(); }
auto columnCount() const { return self().columnCount(); }
auto padding() const { return self().padding(); }
auto remove(sSizable sizable) { return self().remove(sizable), *this; }
auto remove(sTableLayoutCell cell) { return self().remove(cell), *this; }
auto reset() { return self().reset(), *this; }
+ auto resize() { return self().resize(), *this; }
auto row(uint position) const { return self().row(position); }
+ auto rows() const { return self().rows(); }
auto rowCount() const { return self().rowCount(); }
auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; }
auto setPadding(float padding) { return self().setPadding({padding, padding, padding, padding}), *this; }
+ auto setPadding(float x, float y) { return self().setPadding({x, y, x, y}), *this; }
auto setPadding(Geometry padding = {}) { return self().setPadding(padding), *this; }
auto setSize(Size size) { return self().setSize(size), *this; }
auto size() const { return self().size(); }
};
#endif
+#if defined(Hiro_HorizontalResizeGrip)
+struct HorizontalResizeGrip : sHorizontalResizeGrip {
+ DeclareSharedWidget(HorizontalResizeGrip)
+
+ auto doActivate() const { return self().doActivate(); }
+ auto doResize(int offset) const { return self().doResize(offset); }
+ auto onActivate(const function& callback) { return self().onActivate(callback), *this; }
+ auto onResize(const function& callback) { return self().onResize(callback), *this; }
+};
+#endif
+
+#if defined(Hiro_VerticalResizeGrip)
+struct VerticalResizeGrip : sVerticalResizeGrip {
+ DeclareSharedWidget(VerticalResizeGrip)
+
+ auto doActivate() const { return self().doActivate(); }
+ auto doResize(int offset) const { return self().doResize(offset); }
+ auto onActivate(const function& callback) { return self().onActivate(callback), *this; }
+ auto onResize(const function& callback) { return self().onResize(callback), *this; }
+};
+#endif
+
#if defined(Hiro_ListView)
struct ListViewItem : sListViewItem {
DeclareSharedObject(ListViewItem)
@@ -153,12 +188,14 @@ struct ListViewItem : sListViewItem {
auto foregroundColor() const { return self().foregroundColor(); }
auto icon() const { return self().icon(); }
auto reset() { return self().reset(), *this; }
+ auto selected() const { return self().selected(); }
auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; }
auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; }
auto setCheckable(bool checkable = true) { return self().setCheckable(checkable), *this; }
auto setChecked(bool checked = true) { return self().setChecked(checked), *this; }
auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; }
auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; }
+ auto setSelected(bool selected = true) { return self().setSelected(selected), *this; }
auto setText(const string& text = "") { return self().setText(text), *this; }
auto text() const { return self().text(); }
};
@@ -185,6 +222,7 @@ struct ListView : sListView {
auto onToggle(const function& callback = {}) { return self().onToggle(callback), *this; }
auto remove(sListViewItem item) { return self().remove(item), *this; }
auto reset() { return self().reset(), *this; }
+ auto resize() { return self().resize(), *this; }
auto selected() { return self().selected(); }
auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; }
auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; }
diff --git a/hiro/extension/table-layout.cpp b/hiro/extension/table-layout.cpp
index 1c659e0b..5e240f98 100644
--- a/hiro/extension/table-layout.cpp
+++ b/hiro/extension/table-layout.cpp
@@ -33,6 +33,10 @@ auto mTableLayout::cell(sSizable sizable) const -> TableLayoutCell {
return {};
}
+auto mTableLayout::cells() const -> vector {
+ return state.cells;
+}
+
auto mTableLayout::cellCount() const -> uint {
return state.cells.size();
}
@@ -41,6 +45,10 @@ auto mTableLayout::column(uint position) const -> TableLayoutColumn {
return state.columns(position, {});
}
+auto mTableLayout::columns() const -> vector {
+ return state.columns;
+}
+
auto mTableLayout::columnCount() const -> uint {
return state.columns.size();
}
@@ -118,10 +126,19 @@ auto mTableLayout::reset() -> type& {
return synchronize();
}
+auto mTableLayout::resize() -> type& {
+ setGeometry(geometry());
+ return *this;
+}
+
auto mTableLayout::row(uint position) const -> TableLayoutRow {
return state.rows(position, {});
}
+auto mTableLayout::rows() const -> vector {
+ return state.rows;
+}
+
auto mTableLayout::rowCount() const -> uint {
return state.rows.size();
}
@@ -144,7 +161,7 @@ auto mTableLayout::setFont(const Font& font) -> type& {
}
auto mTableLayout::setGeometry(Geometry requestedGeometry) -> type& {
- if(!visible(true)) return mSizable::setGeometry(requestedGeometry), *this;
+//if(!visible(true)) return mSizable::setGeometry(requestedGeometry), *this;
auto geometry = requestedGeometry;
geometry.setX(geometry.x() + padding().x());
diff --git a/hiro/extension/table-layout.hpp b/hiro/extension/table-layout.hpp
index e67ef54d..b9cc4cc0 100644
--- a/hiro/extension/table-layout.hpp
+++ b/hiro/extension/table-layout.hpp
@@ -24,15 +24,19 @@ struct mTableLayout : mSizable {
auto cell(uint position) const -> TableLayoutCell;
auto cell(uint x, uint y) const -> TableLayoutCell;
auto cell(sSizable sizable) const -> TableLayoutCell;
+ auto cells() const -> vector;
auto cellCount() const -> uint;
auto column(uint position) const -> TableLayoutColumn;
+ auto columns() const -> vector;
auto columnCount() const -> uint;
auto minimumSize() const -> Size override;
auto padding() const -> Geometry;
auto remove(sSizable sizable) -> type&;
auto remove(sTableLayoutCell cell) -> type&;
- auto reset() -> type&;
+ auto reset() -> type& override;
+ auto resize() -> type&;
auto row(uint position) const -> TableLayoutRow;
+ auto rows() const -> vector;
auto rowCount() const -> uint;
auto setAlignment(Alignment alignment) -> type&;
auto setEnabled(bool enabled) -> type& override;
@@ -70,7 +74,7 @@ struct mTableLayoutColumn : mObject {
private:
struct State {
Alignment alignment;
- float spacing = 5;
+ float spacing = 5_sx;
} state;
friend class mTableLayout;
@@ -88,7 +92,7 @@ struct mTableLayoutRow : mObject {
private:
struct State {
Alignment alignment;
- float spacing = 5;
+ float spacing = 5_sy;
} state;
friend class mTableLayout;
diff --git a/hiro/extension/vertical-layout.cpp b/hiro/extension/vertical-layout.cpp
index 8e272734..f487968f 100644
--- a/hiro/extension/vertical-layout.cpp
+++ b/hiro/extension/vertical-layout.cpp
@@ -29,6 +29,10 @@ auto mVerticalLayout::cell(sSizable sizable) const -> VerticalLayoutCell {
return {};
}
+auto mVerticalLayout::cells() const -> vector {
+ return state.cells;
+}
+
auto mVerticalLayout::cellCount() const -> uint {
return state.cells.size();
}
@@ -95,6 +99,11 @@ auto mVerticalLayout::reset() -> type& {
return synchronize();
}
+auto mVerticalLayout::resize() -> type& {
+ setGeometry(geometry());
+ return *this;
+}
+
auto mVerticalLayout::setAlignment(maybe alignment) -> type& {
state.alignment = alignment;
return synchronize();
@@ -113,7 +122,7 @@ auto mVerticalLayout::setFont(const Font& font) -> type& {
}
auto mVerticalLayout::setGeometry(Geometry requestedGeometry) -> type& {
- if(!visible(true)) return mSizable::setGeometry(requestedGeometry), *this;
+//if(!visible(true)) return mSizable::setGeometry(requestedGeometry), *this;
auto geometry = requestedGeometry;
geometry.setX(geometry.x() + padding().x());
diff --git a/hiro/extension/vertical-layout.hpp b/hiro/extension/vertical-layout.hpp
index 35302d72..b68a3d39 100644
--- a/hiro/extension/vertical-layout.hpp
+++ b/hiro/extension/vertical-layout.hpp
@@ -14,15 +14,17 @@ struct mVerticalLayout : mSizable {
using mSizable::remove;
auto alignment() const -> maybe;
- auto append(sSizable sizable, Size size, float spacing = 5) -> type&;
+ auto append(sSizable sizable, Size size, float spacing = 5_sy) -> type&;
auto cell(uint position) const -> VerticalLayoutCell;
auto cell(sSizable sizable) const -> VerticalLayoutCell;
+ auto cells() const -> vector;
auto cellCount() const -> uint;
auto minimumSize() const -> Size override;
auto padding() const -> Geometry;
auto remove(sSizable sizable) -> type&;
auto remove(sVerticalLayoutCell cell) -> type&;
auto reset() -> type& override;
+ auto resize() -> type&;
auto setAlignment(maybe alignment) -> type&;
auto setEnabled(bool enabled) -> type& override;
auto setFont(const Font& font) -> type& override;
@@ -41,7 +43,7 @@ private:
maybe alignment;
vector cells;
Geometry padding;
- float spacing = 5;
+ float spacing = 5_sy;
} state;
};
@@ -70,7 +72,7 @@ private:
maybe alignment;
sSizable sizable;
Size size;
- float spacing = 5;
+ float spacing = 5_sy;
} state;
friend class mVerticalLayout;
diff --git a/hiro/extension/vertical-resize-grip.cpp b/hiro/extension/vertical-resize-grip.cpp
new file mode 100644
index 00000000..f62ba4eb
--- /dev/null
+++ b/hiro/extension/vertical-resize-grip.cpp
@@ -0,0 +1,49 @@
+#if defined(Hiro_VerticalResizeGrip)
+
+mVerticalResizeGrip::mVerticalResizeGrip() {
+ image icon;
+ icon.allocate(15, 5);
+ for(uint x : range(icon.width())) {
+ auto data = icon.data() + x * icon.stride();
+ icon.write(data, 0x00000000); data += icon.pitch();
+ icon.write(data, 0xff9f9f9f); data += icon.pitch();
+ icon.write(data, 0x00000000); data += icon.pitch();
+ icon.write(data, 0xff9f9f9f); data += icon.pitch();
+ icon.write(data, 0x00000000); data += icon.pitch();
+ }
+ mCanvas::setIcon(icon);
+ mCanvas::onMousePress([&](auto button) {
+ if(button == Mouse::Button::Left && !state.timer.enabled()) {
+ doActivate();
+ state.offset = 0;
+ state.origin = Mouse::position();
+ state.timer.setEnabled();
+ }
+ });
+ state.timer.setInterval(10).onActivate([&] {
+ if(!Mouse::pressed(Mouse::Button::Left)) return (void)state.timer.setEnabled(false);
+ auto position = Mouse::position();
+ auto offset = position.y() - state.origin.y();
+ if(offset != state.offset) doResize(offset), offset = state.offset;
+ });
+}
+
+auto mVerticalResizeGrip::doActivate() const -> void {
+ if(state.onActivate) state.onActivate();
+}
+
+auto mVerticalResizeGrip::doResize(int offset) const -> void {
+ if(state.onResize) state.onResize(offset);
+}
+
+auto mVerticalResizeGrip::onActivate(const function& callback) -> type& {
+ state.onActivate = callback;
+ return *this;
+}
+
+auto mVerticalResizeGrip::onResize(const function& callback) -> type& {
+ state.onResize = callback;
+ return *this;
+}
+
+#endif
diff --git a/hiro/extension/vertical-resize-grip.hpp b/hiro/extension/vertical-resize-grip.hpp
new file mode 100644
index 00000000..68e31e80
--- /dev/null
+++ b/hiro/extension/vertical-resize-grip.hpp
@@ -0,0 +1,26 @@
+#if defined(Hiro_VerticalResizeGrip)
+
+struct VerticalResizeGrip;
+struct mVerticalResizeGrip;
+using sVerticalResizeGrip = shared_pointer;
+
+struct mVerticalResizeGrip : mCanvas {
+ using type = mVerticalResizeGrip;
+
+ mVerticalResizeGrip();
+ auto doActivate() const -> void;
+ auto doResize(int offset) const -> void;
+ auto onActivate(const function& callback) -> type&;
+ auto onResize(const function& callback) -> type&;
+
+//private:
+ struct State {
+ function onActivate;
+ function onResize;
+ int offset = 0;
+ Position origin;
+ Timer timer;
+ } state;
+};
+
+#endif
diff --git a/hiro/gtk/application.cpp b/hiro/gtk/application.cpp
index 4eed937c..273e8a8d 100644
--- a/hiro/gtk/application.cpp
+++ b/hiro/gtk/application.cpp
@@ -2,6 +2,9 @@
namespace hiro {
+auto Log_Ignore(const char* logDomain, GLogLevelFlags logLevel, const char* message, void* userData) -> void {
+}
+
auto pApplication::modal() -> bool {
return Application::state().modal > 0;
}
@@ -86,6 +89,10 @@ auto pApplication::initialize() -> void {
}
#endif
+ //prevent useless terminal messages:
+ //GVFS-RemoteVolumeMonitor: "invoking List() failed for type GProxyVolumeMonitorHal: method not implemented"
+ g_log_set_handler("GVFS-RemoteVolumeMonitor", G_LOG_LEVEL_MASK, Log_Ignore, nullptr);
+
//set WM_CLASS to Application::name()
auto name = Application::state().name ? Application::state().name : string{"hiro"};
gdk_set_program_class(name);
diff --git a/hiro/gtk/settings.cpp b/hiro/gtk/settings.cpp
index a24e7ebf..85c9b586 100644
--- a/hiro/gtk/settings.cpp
+++ b/hiro/gtk/settings.cpp
@@ -1,7 +1,7 @@
namespace hiro {
Settings::Settings() {
- string path = {Path::userData(), "hiro/"};
+ string path = {Path::userSettings(), "hiro/"};
#if HIRO_GTK==2
auto document = BML::unserialize(file::read({path, "gtk2.bml"}));
#elif HIRO_GTK==3
@@ -25,7 +25,7 @@ Settings::Settings() {
}
Settings::~Settings() {
- string path = {Path::userData(), "hiro/"};
+ string path = {Path::userSettings(), "hiro/"};
directory::create(path, 0755);
Markup::Node document;
diff --git a/hiro/gtk/widget/canvas.cpp b/hiro/gtk/widget/canvas.cpp
index 91b643a5..03a07300 100644
--- a/hiro/gtk/widget/canvas.cpp
+++ b/hiro/gtk/widget/canvas.cpp
@@ -88,6 +88,10 @@ auto pCanvas::minimumSize() const -> Size {
return {0, 0};
}
+auto pCanvas::setAlignment(Alignment) -> void {
+ update();
+}
+
auto pCanvas::setColor(Color color) -> void {
update();
}
@@ -123,20 +127,21 @@ auto pCanvas::_onDraw(cairo_t* context) -> void {
int sx = 0, sy = 0, dx = 0, dy = 0;
int width = surfaceWidth, height = surfaceHeight;
auto geometry = pSizable::state().geometry;
+ auto alignment = state().alignment ? state().alignment : Alignment{0.5, 0.5};
if(width <= geometry.width()) {
sx = 0;
- dx = (geometry.width() - width) / 2;
+ dx = (geometry.width() - width) * alignment.horizontal();
} else {
- sx = (width - geometry.width()) / 2;
+ sx = (width - geometry.width()) * alignment.horizontal();
dx = 0;
}
if(height <= geometry.height()) {
sy = 0;
- dy = (geometry.height() - height) / 2;
+ dy = (geometry.height() - height) * alignment.vertical();
} else {
- sy = (height - geometry.height()) / 2;
+ sy = (height - geometry.height()) * alignment.vertical();
dy = 0;
}
diff --git a/hiro/gtk/widget/canvas.hpp b/hiro/gtk/widget/canvas.hpp
index 368b261a..f921f826 100644
--- a/hiro/gtk/widget/canvas.hpp
+++ b/hiro/gtk/widget/canvas.hpp
@@ -6,6 +6,7 @@ struct pCanvas : pWidget {
Declare(Canvas, Widget)
auto minimumSize() const -> Size;
+ auto setAlignment(Alignment) -> void;
auto setColor(Color color) -> void;
auto setDroppable(bool droppable) -> void;
auto setGeometry(Geometry geometry) -> void override;
diff --git a/hiro/gtk/widget/frame.cpp b/hiro/gtk/widget/frame.cpp
index eb38dc34..feaba54d 100644
--- a/hiro/gtk/widget/frame.cpp
+++ b/hiro/gtk/widget/frame.cpp
@@ -7,6 +7,9 @@ auto pFrame::construct() -> void {
gtkLabel = gtk_label_new("");
gtk_frame_set_label_widget(GTK_FRAME(gtkWidget), gtkLabel);
gtk_widget_show(gtkLabel);
+ gtkChild = gtk_fixed_new();
+ gtk_container_add(GTK_CONTAINER(gtkWidget), gtkChild);
+ gtk_widget_show(gtkChild);
setText(state().text);
@@ -14,14 +17,24 @@ auto pFrame::construct() -> void {
}
auto pFrame::destruct() -> void {
+ gtk_widget_destroy(gtkChild);
+ gtk_widget_destroy(gtkLabel);
gtk_widget_destroy(gtkWidget);
}
auto pFrame::append(sSizable sizable) -> void {
- if(auto sizable = _sizable()) sizable->setFont(sizable->self().font(true));
+ if(auto sizable = _sizable()) {
+ sizable->setFont(sizable->self().font(true));
+ sizable->setVisible(sizable->self().visible(true));
+ }
}
auto pFrame::container(mWidget& widget) -> GtkWidget* {
+ if(auto parent = widget.parentFrame(true)) {
+ if(auto self = parent->self()) {
+ return self->gtkChild;
+ }
+ }
return gtk_widget_get_parent(gtkWidget);
}
@@ -39,13 +52,22 @@ auto pFrame::setFont(const Font& font) -> void {
}
auto pFrame::setGeometry(Geometry geometry) -> void {
+ if(!state().text) {
+ //a frame without a title is generally used as a border box (client edge)
+ //remove the excess spacing so that the frame renders around the entire widget
+ //todo: it may be better to custom draw the frame in this case to avoid hard-coded offsets
+ geometry.setY(geometry.y() - 7);
+ geometry.setHeight(geometry.height() + 8);
+ }
+ //match the dimensions of other client edge widgets (eg GtkTreeView)
+ geometry.setWidth(geometry.width() + 1);
pWidget::setGeometry(geometry);
+
if(auto& sizable = state().sizable) {
Size size = pFont::size(self().font(true), state().text);
- if(!state().text) size.setHeight(10);
- geometry.setX(geometry.x() + 2);
- geometry.setY(geometry.y() + (size.height() - 1));
- geometry.setWidth(geometry.width() - 5);
+ if(!state().text) size.setHeight(18);
+ geometry.setPosition({4, 0});
+ geometry.setWidth(geometry.width() - 13);
geometry.setHeight(geometry.height() - (size.height() + 2));
sizable->setGeometry(geometry);
}
@@ -53,10 +75,11 @@ auto pFrame::setGeometry(Geometry geometry) -> void {
auto pFrame::setText(const string& text) -> void {
gtk_label_set_text(GTK_LABEL(gtkLabel), text);
+ setGeometry(self().geometry());
}
auto pFrame::setVisible(bool visible) -> void {
- if(auto sizable = _sizable()) sizable->setVisible(sizable->self().visible(true));
+ if(auto& sizable = state().sizable) sizable->setVisible(visible);
pWidget::setVisible(visible);
}
diff --git a/hiro/gtk/widget/frame.hpp b/hiro/gtk/widget/frame.hpp
index 28db8d64..1dc40fad 100644
--- a/hiro/gtk/widget/frame.hpp
+++ b/hiro/gtk/widget/frame.hpp
@@ -17,6 +17,7 @@ struct pFrame : pWidget {
auto _sizable() -> maybe;
GtkWidget* gtkLabel = nullptr;
+ GtkWidget* gtkChild = nullptr;
};
}
diff --git a/hiro/gtk/widget/table-view.cpp b/hiro/gtk/widget/table-view.cpp
index 7ee43f4e..6d27c810 100644
--- a/hiro/gtk/widget/table-view.cpp
+++ b/hiro/gtk/widget/table-view.cpp
@@ -7,14 +7,13 @@ static auto TableView_buttonEvent(GtkTreeView* treeView, GdkEventButton* event,
static auto TableView_change(GtkTreeSelection*, pTableView* p) -> void { return p->_doChange(); }
static auto TableView_edit(GtkCellRendererText* renderer, const char* path, const char* text, pTableView* p) -> void { return p->_doEdit(renderer, path, text); }
static auto TableView_headerActivate(GtkTreeViewColumn* column, pTableView* p) -> void { return p->_doHeaderActivate(column); }
+static auto TableView_keyPressEvent(GtkTreeView* treeView, GdkEventKey* event, pTableView* p) -> bool { return p->_doKeyPress(event); }
static auto TableView_mouseMoveEvent(GtkWidget*, GdkEvent*, pTableView* p) -> signed { return p->_doMouseMove(); }
static auto TableView_popup(GtkTreeView*, pTableView* p) -> void { return p->_doContext(); }
static auto TableView_dataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter, pTableView* p) -> void { return p->_doDataFunc(column, renderer, iter); }
static auto TableView_toggle(GtkCellRendererToggle* toggle, const char* path, pTableView* p) -> void { return p->_doToggle(toggle, path); }
-//gtk_tree_view_set_rules_hint(gtkTreeView, true);
-
auto pTableView::construct() -> void {
gtkWidget = gtk_scrolled_window_new(0, 0);
gtkScrolledWindow = GTK_SCROLLED_WINDOW(gtkWidget);
@@ -39,20 +38,27 @@ auto pTableView::construct() -> void {
g_signal_connect(G_OBJECT(gtkTreeView), "button-press-event", G_CALLBACK(TableView_buttonEvent), (gpointer)this);
g_signal_connect(G_OBJECT(gtkTreeView), "button-release-event", G_CALLBACK(TableView_buttonEvent), (gpointer)this);
+ g_signal_connect(G_OBJECT(gtkTreeView), "key-press-event", G_CALLBACK(TableView_keyPressEvent), (gpointer)this);
g_signal_connect(G_OBJECT(gtkTreeView), "motion-notify-event", G_CALLBACK(TableView_mouseMoveEvent), (gpointer)this);
g_signal_connect(G_OBJECT(gtkTreeView), "popup-menu", G_CALLBACK(TableView_popup), (gpointer)this);
g_signal_connect(G_OBJECT(gtkTreeView), "row-activated", G_CALLBACK(TableView_activate), (gpointer)this);
g_signal_connect(G_OBJECT(gtkTreeSelection), "changed", G_CALLBACK(TableView_change), (gpointer)this);
+ //searching doesn't currently work anyway ...
+ gtkEntry = (GtkEntry*)gtk_entry_new();
+ gtk_tree_view_set_search_entry(gtkTreeView, gtkEntry);
+
pWidget::construct();
}
auto pTableView::destruct() -> void {
+ gtk_widget_destroy(GTK_WIDGET(gtkEntry));
gtk_widget_destroy(gtkWidgetChild);
gtk_widget_destroy(gtkWidget);
}
auto pTableView::append(sTableViewColumn column) -> void {
+ _updateRulesHint();
}
auto pTableView::append(sTableViewItem item) -> void {
@@ -63,6 +69,7 @@ auto pTableView::focused() const -> bool {
}
auto pTableView::remove(sTableViewColumn column) -> void {
+ _updateRulesHint();
}
auto pTableView::remove(sTableViewItem item) -> void {
@@ -103,11 +110,13 @@ auto pTableView::resizeColumns() -> void {
}
auto pTableView::setAlignment(Alignment alignment) -> void {
+ _updateRulesHint();
}
auto pTableView::setBackgroundColor(Color color) -> void {
GdkColor gdkColor = CreateColor(color);
gtk_widget_modify_base(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr);
+ _updateRulesHint();
}
auto pTableView::setBatchable(bool batchable) -> void {
@@ -121,11 +130,13 @@ auto pTableView::setBordered(bool bordered) -> void {
auto pTableView::setFocused() -> void {
//gtk_widget_grab_focus() will select the first item if nothing is currently selected
//this behavior is undesirable. detect selection state first, and restore if required
- lock();
- bool selected = gtk_tree_selection_get_selected(gtkTreeSelection, nullptr, nullptr);
- gtk_widget_grab_focus(gtkWidgetChild);
- if(!selected) gtk_tree_selection_unselect_all(gtkTreeSelection);
- unlock();
+ if(!state().batchable) { //gtk_tree_selection_get_selected() will throw a critical exception in batchable mode
+ lock();
+ bool selected = gtk_tree_selection_get_selected(gtkTreeSelection, nullptr, nullptr);
+ gtk_widget_grab_focus(gtkWidgetChild);
+ if(!selected) gtk_tree_selection_unselect_all(gtkTreeSelection);
+ unlock();
+ }
}
auto pTableView::setFont(const Font& font) -> void {
@@ -134,6 +145,7 @@ auto pTableView::setFont(const Font& font) -> void {
auto pTableView::setForegroundColor(Color color) -> void {
GdkColor gdkColor = CreateColor(color);
gtk_widget_modify_text(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr);
+ _updateRulesHint();
}
auto pTableView::setGeometry(Geometry geometry) -> void {
@@ -208,11 +220,6 @@ auto pTableView::_createModel() -> void {
gtkListStore = gtk_list_store_newv(types.size(), types.data());
gtkTreeModel = GTK_TREE_MODEL(gtkListStore);
gtk_tree_view_set_model(gtkTreeView, gtkTreeModel);
-
-// for(auto& item : state().items) {
-// gtk_list_store_append(gtkListStore, &item->self()->gtkIter);
-// item->self()->_setState();
-// }
}
auto pTableView::_doActivate() -> void {
@@ -344,6 +351,26 @@ auto pTableView::_doHeaderActivate(GtkTreeViewColumn* gtkTreeViewColumn) -> void
}
}
+auto pTableView::_doKeyPress(GdkEventKey* event) -> bool {
+ if(state().batchable && event->type == GDK_KEY_PRESS) {
+ //when using keyboard to activate tree view items in GTK_SELECTION_MULTIPLE mode, GTK will deselect all but the last item
+ //this code detects said case, blocks the key from being propagated, and calls the activate callback directly
+ //the result is that the enter key can be used to activate multiple selected items at a time
+ //there are four ways to activate items via the keyboard in GTK, so we have to detect all of them here
+ auto modifiers = event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_SUPER_MASK); //ignore other modifiers (eg mouse buttons)
+ if((event->keyval == GDK_KEY_Return && !modifiers)
+ || (event->keyval == GDK_KEY_KP_Enter && !modifiers)
+ || (event->keyval == GDK_KEY_space && !modifiers)
+ || (event->keyval == GDK_KEY_space && modifiers == GDK_SHIFT_MASK)
+ ) {
+ _doActivate();
+ return true;
+ }
+ }
+ //allow GTK to handle this keypress
+ return false;
+}
+
//GtkTreeView::cursor-changed and GtkTreeSelection::changed do not send signals for changes during rubber-banding selection
//so here we capture motion-notify-event, and if the selections have changed, invoke TableView::onChange
auto pTableView::_doMouseMove() -> signed {
@@ -370,6 +397,17 @@ auto pTableView::_doToggle(GtkCellRendererToggle* gtkCellRendererToggle, const c
}
}
+//the rules hint draws each row with alternating background colors
+//this isn't currently exposed as a hiro API call, so try and determine if we should apply it here
+//basically, if there's two or more columns and no custom colors applied, then we do so
+auto pTableView::_updateRulesHint() -> void {
+ bool rules = true;
+ if(state().backgroundColor) rules = false;
+ if(state().foregroundColor) rules = false;
+ if(state().columns.size() <= 1) rules = false;
+ gtk_tree_view_set_rules_hint(gtkTreeView, rules);
+}
+
//compare currently selected items to previously selected items
//if different, invoke the onChange callback unless locked, and cache current selection
//this prevents firing an onChange event when the actual selection has not changed
diff --git a/hiro/gtk/widget/table-view.hpp b/hiro/gtk/widget/table-view.hpp
index 70c66ba6..c04a8062 100644
--- a/hiro/gtk/widget/table-view.hpp
+++ b/hiro/gtk/widget/table-view.hpp
@@ -32,8 +32,10 @@ struct pTableView : pWidget {
auto _doEdit(GtkCellRendererText* gtkCellRendererText, const char* path, const char* text) -> void;
auto _doEvent(GdkEventButton* event) -> int;
auto _doHeaderActivate(GtkTreeViewColumn* column) -> void;
+ auto _doKeyPress(GdkEventKey* event) -> bool;
auto _doMouseMove() -> int;
auto _doToggle(GtkCellRendererToggle* gtkCellRendererToggle, const char* path) -> void;
+ auto _updateRulesHint() -> void;
auto _updateSelected() -> void;
auto _width(uint column) -> uint;
@@ -43,6 +45,7 @@ struct pTableView : pWidget {
GtkTreeSelection* gtkTreeSelection = nullptr;
GtkListStore* gtkListStore = nullptr;
GtkTreeModel* gtkTreeModel = nullptr;
+ GtkEntry* gtkEntry = nullptr;
vector currentSelection;
bool suppressChange = false;
};
diff --git a/hiro/gtk/widget/tree-view-item.cpp b/hiro/gtk/widget/tree-view-item.cpp
index db199879..3a6fe613 100644
--- a/hiro/gtk/widget/tree-view-item.cpp
+++ b/hiro/gtk/widget/tree-view-item.cpp
@@ -33,6 +33,7 @@ auto pTreeViewItem::setBackgroundColor(Color color) -> void {
}
auto pTreeViewItem::setCheckable(bool checkable) -> void {
+ _updateWidth();
}
auto pTreeViewItem::setChecked(bool checked) -> void {
@@ -46,6 +47,11 @@ auto pTreeViewItem::setExpanded(bool expanded) -> void {
auto path = gtk_tree_model_get_path(parentWidget->gtkTreeModel, >kIter);
if(expanded) {
gtk_tree_view_expand_row(parentWidget->gtkTreeView, path, false);
+ //if you collapse a parent node, GTK collapses all child nodes
+ //this isn't very desirable, so restore any child expansions recursively here
+ for(auto& item : state().items) {
+ item->setExpanded(item->expanded());
+ }
} else {
gtk_tree_view_collapse_row(parentWidget->gtkTreeView, path);
}
@@ -74,6 +80,7 @@ auto pTreeViewItem::setIcon(const image& icon) -> void {
gtk_tree_store_set(parentWidget->gtkTreeStore, >kIter, 1, nullptr, -1);
}
}
+ _updateWidth();
}
auto pTreeViewItem::setSelected() -> void {
@@ -92,10 +99,22 @@ auto pTreeViewItem::setText(const string& text) -> void {
if(auto parentWidget = _parentWidget()) {
gtk_tree_store_set(parentWidget->gtkTreeStore, >kIter, 2, (const char*)text, -1);
}
+ _updateWidth();
}
//
+//recursive function to find the minimum (pre-computed / cached) width of a TreeViewItem tree
+auto pTreeViewItem::_minimumWidth(uint depth) -> uint {
+ uint width = TreeViewIndentation * depth + _width;
+ for(auto& item : state().items) {
+ if(auto self = item->self()) {
+ width = max(width, self->_minimumWidth(depth + 1));
+ }
+ }
+ return width;
+}
+
auto pTreeViewItem::_parentItem() -> pTreeViewItem* {
if(auto parentItem = self().parentTreeViewItem()) return parentItem->self();
return nullptr;
@@ -106,6 +125,17 @@ auto pTreeViewItem::_parentWidget() -> pTreeView* {
return nullptr;
}
+//this is called any time a TreeViewItem's checkability, icon, or text is updated
+//in other words, whenever the width of the item might have changed
+//it may change the requirement of the TreeView needing a scrollbar, so notify the TreeView as well
+auto pTreeViewItem::_updateWidth() -> void {
+ _width = 4;
+ if(state().checkable) _width += 16 + (state().icon || state().text ? 4 : 0);
+ if(auto& icon = state().icon) _width += icon.width() + 2;
+ if(auto& text = state().text) _width += pFont::size(self().font(true), text).width();
+ if(auto parent = _parentWidget()) parent->_updateScrollBars();
+}
+
}
#endif
diff --git a/hiro/gtk/widget/tree-view-item.hpp b/hiro/gtk/widget/tree-view-item.hpp
index 7633a489..e0abc493 100644
--- a/hiro/gtk/widget/tree-view-item.hpp
+++ b/hiro/gtk/widget/tree-view-item.hpp
@@ -17,10 +17,13 @@ struct pTreeViewItem : pObject {
auto setSelected() -> void;
auto setText(const string& text) -> void;
+ auto _minimumWidth(uint depth = 0) -> uint;
auto _parentItem() -> pTreeViewItem*;
auto _parentWidget() -> pTreeView*;
+ auto _updateWidth() -> void;
GtkTreeIter gtkIter;
+ uint _width = 0;
};
}
diff --git a/hiro/gtk/widget/tree-view.cpp b/hiro/gtk/widget/tree-view.cpp
index 5df48a5c..0accd4e4 100644
--- a/hiro/gtk/widget/tree-view.cpp
+++ b/hiro/gtk/widget/tree-view.cpp
@@ -2,6 +2,8 @@
namespace hiro {
+static const uint TreeViewIndentation = 20;
+
//gtk_tree_view_collapse_all(gtkTreeView);
//gtk_tree_view_expand_all(gtkTreeView);
@@ -26,7 +28,7 @@ auto pTreeView::construct() -> void {
gtkTreeSelection = gtk_tree_view_get_selection(gtkTreeView);
gtk_tree_view_set_headers_visible(gtkTreeView, false);
gtk_tree_view_set_show_expanders(gtkTreeView, false);
- gtk_tree_view_set_level_indentation(gtkTreeView, 20);
+ gtk_tree_view_set_level_indentation(gtkTreeView, TreeViewIndentation);
gtk_container_add(GTK_CONTAINER(gtkWidget), gtkWidgetChild);
gtk_widget_show(gtkWidgetChild);
@@ -105,6 +107,11 @@ auto pTreeView::setForegroundColor(Color color) -> void {
gtk_widget_modify_text(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr);
}
+auto pTreeView::setGeometry(Geometry geometry) -> void {
+ pWidget::setGeometry(geometry);
+ _updateScrollBars();
+}
+
//
auto pTreeView::_activatePath(GtkTreePath* gtkPath) -> void {
@@ -198,6 +205,35 @@ auto pTreeView::_togglePath(string path) -> void {
}
}
+//it is necessary to compute the minimum width necessary to show all items in a tree,
+//before a horizontal scroll bar must be shown. this is because GTK2 (and possibly GTK3)
+//fail to subtract the tree view indentation level on items before determining if the
+//horizontal scroll bar is necessary. as a result, without this, the scroll bar shows up
+//far before it is necessary, and gets worse the more nested the tree is.
+//
+//this is called whenever the TreeView geometry changes, or whenever a TreeViewItem's
+//checkability, icon, or text is updated. in other words, whenever the need for a horizontal
+//scroll bar to show all items in the tree is necessary or not.
+auto pTreeView::_updateScrollBars() -> void {
+ int maximumWidth = self().geometry().width() - 6;
+ if(auto scrollBar = gtk_scrolled_window_get_vscrollbar(gtkScrolledWindow)) {
+ GtkAllocation allocation;
+ gtk_widget_get_allocation(scrollBar, &allocation);
+ if(gtk_widget_get_visible(scrollBar)) maximumWidth -= allocation.width;
+ }
+
+ int minimumWidth = 0;
+ for(auto& item : state().items) {
+ if(auto self = item->self()) {
+ minimumWidth = max(minimumWidth, self->_minimumWidth());
+ }
+ }
+
+ gtk_scrolled_window_set_policy(gtkScrolledWindow,
+ minimumWidth >= maximumWidth ? GTK_POLICY_ALWAYS : GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+}
+
auto pTreeView::_updateSelected() -> void {
if(suppressChange) {
suppressChange = false;
diff --git a/hiro/gtk/widget/tree-view.hpp b/hiro/gtk/widget/tree-view.hpp
index 79c8bf2d..96002895 100644
--- a/hiro/gtk/widget/tree-view.hpp
+++ b/hiro/gtk/widget/tree-view.hpp
@@ -10,12 +10,16 @@ struct pTreeView : pWidget {
auto setBackgroundColor(Color color) -> void;
auto setFocused() -> void override;
auto setForegroundColor(Color color) -> void;
+ auto setGeometry(Geometry geometry) -> void;
auto _activatePath(GtkTreePath* gtkPath) -> void;
auto _buttonEvent(GdkEventButton* gdkEvent) -> signed;
auto _doDataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeIter* iter) -> void;
auto _togglePath(string path) -> void;
+ auto _updateScrollBars() -> void;
auto _updateSelected() -> void;
+ auto _width(sTreeViewItem item, uint depth = 0) -> uint;
+ auto _widthRecursive() -> uint;
GtkScrolledWindow* gtkScrolledWindow = nullptr;
GtkWidget* gtkWidgetChild = nullptr;
diff --git a/hiro/gtk/window.cpp b/hiro/gtk/window.cpp
index 3cca9c4a..fce4dee2 100644
--- a/hiro/gtk/window.cpp
+++ b/hiro/gtk/window.cpp
@@ -255,7 +255,7 @@ auto pWindow::frameMargin() const -> Geometry {
};
}
-auto pWindow::handle() const -> uintptr {
+auto pWindow::handle() const -> uintptr_t {
#if defined(DISPLAY_WINDOWS)
return (uintptr)GDK_WINDOW_HWND(gtk_widget_get_window(widget));
#endif
diff --git a/hiro/gtk/window.hpp b/hiro/gtk/window.hpp
index 74a24da4..9a31f5e3 100644
--- a/hiro/gtk/window.hpp
+++ b/hiro/gtk/window.hpp
@@ -10,7 +10,7 @@ struct pWindow : pObject {
auto append(sStatusBar statusBar) -> void;
auto focused() const -> bool override;
auto frameMargin() const -> Geometry;
- auto handle() const -> uintptr;
+ auto handle() const -> uintptr_t;
auto monitor() const -> uint;
auto remove(sMenuBar menuBar) -> void;
auto remove(sSizable sizable) -> void;
diff --git a/hiro/qt/qt.moc b/hiro/qt/qt.moc
index f8a9f82c..58136bab 100644
--- a/hiro/qt/qt.moc
+++ b/hiro/qt/qt.moc
@@ -1,48 +1,24 @@
/****************************************************************************
** Meta object code from reading C++ file 'qt.hpp'
**
-** Created by: The Qt Meta Object Compiler version 67 (Qt 5.11.2)
+** Created by: The Qt Meta Object Compiler version 63 (Qt 4.8.7)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
-#include
-#include
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'qt.hpp' doesn't include ."
-#elif Q_MOC_OUTPUT_REVISION != 67
-#error "This file was generated using the moc from 5.11.2. It"
+#elif Q_MOC_OUTPUT_REVISION != 63
+#error "This file was generated using the moc from 4.8.7. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif
QT_BEGIN_MOC_NAMESPACE
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
-struct qt_meta_stringdata_hiro__QtTimer_t {
- QByteArrayData data[3];
- char stringdata0[26];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtTimer_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtTimer_t qt_meta_stringdata_hiro__QtTimer = {
- {
-QT_MOC_LITERAL(0, 0, 13), // "hiro::QtTimer"
-QT_MOC_LITERAL(1, 14, 10), // "onActivate"
-QT_MOC_LITERAL(2, 25, 0) // ""
-
- },
- "hiro::QtTimer\0onActivate\0"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtTimer[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -52,20 +28,21 @@ static const uint qt_meta_data_hiro__QtTimer[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
+ // slots: signature, parameters, type, tag, flags
+ 14, 27, 27, 27, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtTimer[] = {
+ "hiro::QtTimer\0onActivate()\0\0"
+};
+
void hiro::QtTimer::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtTimer *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onActivate(); break;
default: ;
@@ -74,22 +51,29 @@ void hiro::QtTimer::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _i
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtTimer::staticMetaObject = {
- { &QTimer::staticMetaObject, qt_meta_stringdata_hiro__QtTimer.data,
- qt_meta_data_hiro__QtTimer, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtTimer::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtTimer::staticMetaObject = {
+ { &QTimer::staticMetaObject, qt_meta_stringdata_hiro__QtTimer,
+ qt_meta_data_hiro__QtTimer, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtTimer::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtTimer::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtTimer::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtTimer.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtTimer))
+ return static_cast(const_cast< QtTimer*>(this));
return QTimer::qt_metacast(_clname);
}
@@ -102,37 +86,13 @@ int hiro::QtTimer::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtMenuItem_t {
- QByteArrayData data[3];
- char stringdata0[29];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtMenuItem_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtMenuItem_t qt_meta_stringdata_hiro__QtMenuItem = {
- {
-QT_MOC_LITERAL(0, 0, 16), // "hiro::QtMenuItem"
-QT_MOC_LITERAL(1, 17, 10), // "onActivate"
-QT_MOC_LITERAL(2, 28, 0) // ""
-
- },
- "hiro::QtMenuItem\0onActivate\0"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtMenuItem[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -142,20 +102,21 @@ static const uint qt_meta_data_hiro__QtMenuItem[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
+ // slots: signature, parameters, type, tag, flags
+ 17, 30, 30, 30, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtMenuItem[] = {
+ "hiro::QtMenuItem\0onActivate()\0\0"
+};
+
void hiro::QtMenuItem::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtMenuItem *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onActivate(); break;
default: ;
@@ -164,22 +125,29 @@ void hiro::QtMenuItem::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtMenuItem::staticMetaObject = {
- { &QAction::staticMetaObject, qt_meta_stringdata_hiro__QtMenuItem.data,
- qt_meta_data_hiro__QtMenuItem, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtMenuItem::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtMenuItem::staticMetaObject = {
+ { &QAction::staticMetaObject, qt_meta_stringdata_hiro__QtMenuItem,
+ qt_meta_data_hiro__QtMenuItem, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtMenuItem::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtMenuItem::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtMenuItem::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtMenuItem.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtMenuItem))
+ return static_cast(const_cast< QtMenuItem*>(this));
return QAction::qt_metacast(_clname);
}
@@ -192,37 +160,13 @@ int hiro::QtMenuItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtMenuCheckItem_t {
- QByteArrayData data[3];
- char stringdata0[32];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtMenuCheckItem_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtMenuCheckItem_t qt_meta_stringdata_hiro__QtMenuCheckItem = {
- {
-QT_MOC_LITERAL(0, 0, 21), // "hiro::QtMenuCheckItem"
-QT_MOC_LITERAL(1, 22, 8), // "onToggle"
-QT_MOC_LITERAL(2, 31, 0) // ""
-
- },
- "hiro::QtMenuCheckItem\0onToggle\0"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtMenuCheckItem[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -232,20 +176,21 @@ static const uint qt_meta_data_hiro__QtMenuCheckItem[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
+ // slots: signature, parameters, type, tag, flags
+ 22, 33, 33, 33, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtMenuCheckItem[] = {
+ "hiro::QtMenuCheckItem\0onToggle()\0\0"
+};
+
void hiro::QtMenuCheckItem::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtMenuCheckItem *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onToggle(); break;
default: ;
@@ -254,22 +199,29 @@ void hiro::QtMenuCheckItem::qt_static_metacall(QObject *_o, QMetaObject::Call _c
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtMenuCheckItem::staticMetaObject = {
- { &QAction::staticMetaObject, qt_meta_stringdata_hiro__QtMenuCheckItem.data,
- qt_meta_data_hiro__QtMenuCheckItem, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtMenuCheckItem::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtMenuCheckItem::staticMetaObject = {
+ { &QAction::staticMetaObject, qt_meta_stringdata_hiro__QtMenuCheckItem,
+ qt_meta_data_hiro__QtMenuCheckItem, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtMenuCheckItem::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtMenuCheckItem::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtMenuCheckItem::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtMenuCheckItem.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtMenuCheckItem))
+ return static_cast(const_cast< QtMenuCheckItem*>(this));
return QAction::qt_metacast(_clname);
}
@@ -282,37 +234,13 @@ int hiro::QtMenuCheckItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtMenuRadioItem_t {
- QByteArrayData data[3];
- char stringdata0[34];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtMenuRadioItem_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtMenuRadioItem_t qt_meta_stringdata_hiro__QtMenuRadioItem = {
- {
-QT_MOC_LITERAL(0, 0, 21), // "hiro::QtMenuRadioItem"
-QT_MOC_LITERAL(1, 22, 10), // "onActivate"
-QT_MOC_LITERAL(2, 33, 0) // ""
-
- },
- "hiro::QtMenuRadioItem\0onActivate\0"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtMenuRadioItem[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -322,20 +250,21 @@ static const uint qt_meta_data_hiro__QtMenuRadioItem[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
+ // slots: signature, parameters, type, tag, flags
+ 22, 35, 35, 35, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtMenuRadioItem[] = {
+ "hiro::QtMenuRadioItem\0onActivate()\0\0"
+};
+
void hiro::QtMenuRadioItem::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtMenuRadioItem *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onActivate(); break;
default: ;
@@ -344,22 +273,29 @@ void hiro::QtMenuRadioItem::qt_static_metacall(QObject *_o, QMetaObject::Call _c
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtMenuRadioItem::staticMetaObject = {
- { &QAction::staticMetaObject, qt_meta_stringdata_hiro__QtMenuRadioItem.data,
- qt_meta_data_hiro__QtMenuRadioItem, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtMenuRadioItem::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtMenuRadioItem::staticMetaObject = {
+ { &QAction::staticMetaObject, qt_meta_stringdata_hiro__QtMenuRadioItem,
+ qt_meta_data_hiro__QtMenuRadioItem, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtMenuRadioItem::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtMenuRadioItem::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtMenuRadioItem::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtMenuRadioItem.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtMenuRadioItem))
+ return static_cast(const_cast< QtMenuRadioItem*>(this));
return QAction::qt_metacast(_clname);
}
@@ -372,37 +308,13 @@ int hiro::QtMenuRadioItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtButton_t {
- QByteArrayData data[3];
- char stringdata0[27];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtButton_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtButton_t qt_meta_stringdata_hiro__QtButton = {
- {
-QT_MOC_LITERAL(0, 0, 14), // "hiro::QtButton"
-QT_MOC_LITERAL(1, 15, 10), // "onActivate"
-QT_MOC_LITERAL(2, 26, 0) // ""
-
- },
- "hiro::QtButton\0onActivate\0"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtButton[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -412,20 +324,21 @@ static const uint qt_meta_data_hiro__QtButton[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
+ // slots: signature, parameters, type, tag, flags
+ 15, 28, 28, 28, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtButton[] = {
+ "hiro::QtButton\0onActivate()\0\0"
+};
+
void hiro::QtButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtButton *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onActivate(); break;
default: ;
@@ -434,22 +347,29 @@ void hiro::QtButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtButton::staticMetaObject = {
- { &QToolButton::staticMetaObject, qt_meta_stringdata_hiro__QtButton.data,
- qt_meta_data_hiro__QtButton, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtButton::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtButton::staticMetaObject = {
+ { &QToolButton::staticMetaObject, qt_meta_stringdata_hiro__QtButton,
+ qt_meta_data_hiro__QtButton, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtButton::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtButton::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtButton::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtButton.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtButton))
+ return static_cast(const_cast< QtButton*>(this));
return QToolButton::qt_metacast(_clname);
}
@@ -462,35 +382,13 @@ int hiro::QtButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtCanvas_t {
- QByteArrayData data[1];
- char stringdata0[15];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtCanvas_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtCanvas_t qt_meta_stringdata_hiro__QtCanvas = {
- {
-QT_MOC_LITERAL(0, 0, 14) // "hiro::QtCanvas"
-
- },
- "hiro::QtCanvas"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtCanvas[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
@@ -503,6 +401,10 @@ static const uint qt_meta_data_hiro__QtCanvas[] = {
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtCanvas[] = {
+ "hiro::QtCanvas\0"
+};
+
void hiro::QtCanvas::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
Q_UNUSED(_o);
@@ -511,55 +413,43 @@ void hiro::QtCanvas::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtCanvas::staticMetaObject = {
- { &QWidget::staticMetaObject, qt_meta_stringdata_hiro__QtCanvas.data,
- qt_meta_data_hiro__QtCanvas, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtCanvas::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtCanvas::staticMetaObject = {
+ { &QWidget::staticMetaObject, qt_meta_stringdata_hiro__QtCanvas,
+ qt_meta_data_hiro__QtCanvas, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtCanvas::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtCanvas::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtCanvas::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtCanvas.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtCanvas))
+ return static_cast(const_cast< QtCanvas*>(this));
return QWidget::qt_metacast(_clname);
}
int hiro::QtCanvas::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QWidget::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
return _id;
}
-struct qt_meta_stringdata_hiro__QtCheckButton_t {
- QByteArrayData data[4];
- char stringdata0[38];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtCheckButton_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtCheckButton_t qt_meta_stringdata_hiro__QtCheckButton = {
- {
-QT_MOC_LITERAL(0, 0, 19), // "hiro::QtCheckButton"
-QT_MOC_LITERAL(1, 20, 8), // "onToggle"
-QT_MOC_LITERAL(2, 29, 0), // ""
-QT_MOC_LITERAL(3, 30, 7) // "checked"
-
- },
- "hiro::QtCheckButton\0onToggle\0\0checked"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtCheckButton[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -569,20 +459,22 @@ static const uint qt_meta_data_hiro__QtCheckButton[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 1, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void, QMetaType::Bool, 3,
+ // slots: signature, parameters, type, tag, flags
+ 20, 35, 43, 43, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtCheckButton[] = {
+ "hiro::QtCheckButton\0onToggle(bool)\0"
+ "checked\0\0"
+};
+
void hiro::QtCheckButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtCheckButton *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onToggle((*reinterpret_cast< bool(*)>(_a[1]))); break;
default: ;
@@ -590,22 +482,29 @@ void hiro::QtCheckButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c,
}
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtCheckButton::staticMetaObject = {
- { &QToolButton::staticMetaObject, qt_meta_stringdata_hiro__QtCheckButton.data,
- qt_meta_data_hiro__QtCheckButton, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtCheckButton::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtCheckButton::staticMetaObject = {
+ { &QToolButton::staticMetaObject, qt_meta_stringdata_hiro__QtCheckButton,
+ qt_meta_data_hiro__QtCheckButton, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtCheckButton::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtCheckButton::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtCheckButton::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtCheckButton.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtCheckButton))
+ return static_cast(const_cast< QtCheckButton*>(this));
return QToolButton::qt_metacast(_clname);
}
@@ -618,37 +517,13 @@ int hiro::QtCheckButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtCheckLabel_t {
- QByteArrayData data[3];
- char stringdata0[29];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtCheckLabel_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtCheckLabel_t qt_meta_stringdata_hiro__QtCheckLabel = {
- {
-QT_MOC_LITERAL(0, 0, 18), // "hiro::QtCheckLabel"
-QT_MOC_LITERAL(1, 19, 8), // "onToggle"
-QT_MOC_LITERAL(2, 28, 0) // ""
-
- },
- "hiro::QtCheckLabel\0onToggle\0"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtCheckLabel[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -658,20 +533,21 @@ static const uint qt_meta_data_hiro__QtCheckLabel[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
+ // slots: signature, parameters, type, tag, flags
+ 19, 30, 30, 30, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtCheckLabel[] = {
+ "hiro::QtCheckLabel\0onToggle()\0\0"
+};
+
void hiro::QtCheckLabel::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtCheckLabel *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onToggle(); break;
default: ;
@@ -680,22 +556,29 @@ void hiro::QtCheckLabel::qt_static_metacall(QObject *_o, QMetaObject::Call _c, i
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtCheckLabel::staticMetaObject = {
- { &QCheckBox::staticMetaObject, qt_meta_stringdata_hiro__QtCheckLabel.data,
- qt_meta_data_hiro__QtCheckLabel, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtCheckLabel::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtCheckLabel::staticMetaObject = {
+ { &QCheckBox::staticMetaObject, qt_meta_stringdata_hiro__QtCheckLabel,
+ qt_meta_data_hiro__QtCheckLabel, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtCheckLabel::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtCheckLabel::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtCheckLabel::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtCheckLabel.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtCheckLabel))
+ return static_cast(const_cast< QtCheckLabel*>(this));
return QCheckBox::qt_metacast(_clname);
}
@@ -708,38 +591,13 @@ int hiro::QtCheckLabel::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtComboButton_t {
- QByteArrayData data[4];
- char stringdata0[37];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtComboButton_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtComboButton_t qt_meta_stringdata_hiro__QtComboButton = {
- {
-QT_MOC_LITERAL(0, 0, 19), // "hiro::QtComboButton"
-QT_MOC_LITERAL(1, 20, 8), // "onChange"
-QT_MOC_LITERAL(2, 29, 0), // ""
-QT_MOC_LITERAL(3, 30, 6) // "offset"
-
- },
- "hiro::QtComboButton\0onChange\0\0offset"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtComboButton[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -749,20 +607,22 @@ static const uint qt_meta_data_hiro__QtComboButton[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 1, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void, QMetaType::Int, 3,
+ // slots: signature, parameters, type, tag, flags
+ 20, 34, 41, 41, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtComboButton[] = {
+ "hiro::QtComboButton\0onChange(int)\0"
+ "offset\0\0"
+};
+
void hiro::QtComboButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtComboButton *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onChange((*reinterpret_cast< int(*)>(_a[1]))); break;
default: ;
@@ -770,22 +630,29 @@ void hiro::QtComboButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c,
}
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtComboButton::staticMetaObject = {
- { &QComboBox::staticMetaObject, qt_meta_stringdata_hiro__QtComboButton.data,
- qt_meta_data_hiro__QtComboButton, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtComboButton::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtComboButton::staticMetaObject = {
+ { &QComboBox::staticMetaObject, qt_meta_stringdata_hiro__QtComboButton,
+ qt_meta_data_hiro__QtComboButton, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtComboButton::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtComboButton::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtComboButton::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtComboButton.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtComboButton))
+ return static_cast(const_cast< QtComboButton*>(this));
return QComboBox::qt_metacast(_clname);
}
@@ -798,35 +665,13 @@ int hiro::QtComboButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtHexEdit_t {
- QByteArrayData data[1];
- char stringdata0[16];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtHexEdit_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtHexEdit_t qt_meta_stringdata_hiro__QtHexEdit = {
- {
-QT_MOC_LITERAL(0, 0, 15) // "hiro::QtHexEdit"
-
- },
- "hiro::QtHexEdit"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtHexEdit[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
@@ -839,6 +684,10 @@ static const uint qt_meta_data_hiro__QtHexEdit[] = {
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtHexEdit[] = {
+ "hiro::QtHexEdit\0"
+};
+
void hiro::QtHexEdit::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
Q_UNUSED(_o);
@@ -847,54 +696,43 @@ void hiro::QtHexEdit::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtHexEdit::staticMetaObject = {
- { &QTextEdit::staticMetaObject, qt_meta_stringdata_hiro__QtHexEdit.data,
- qt_meta_data_hiro__QtHexEdit, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtHexEdit::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtHexEdit::staticMetaObject = {
+ { &QTextEdit::staticMetaObject, qt_meta_stringdata_hiro__QtHexEdit,
+ qt_meta_data_hiro__QtHexEdit, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtHexEdit::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtHexEdit::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtHexEdit::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtHexEdit.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtHexEdit))
+ return static_cast(const_cast< QtHexEdit*>(this));
return QTextEdit::qt_metacast(_clname);
}
int hiro::QtHexEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QTextEdit::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
return _id;
}
-struct qt_meta_stringdata_hiro__QtHexEditScrollBar_t {
- QByteArrayData data[3];
- char stringdata0[35];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtHexEditScrollBar_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtHexEditScrollBar_t qt_meta_stringdata_hiro__QtHexEditScrollBar = {
- {
-QT_MOC_LITERAL(0, 0, 24), // "hiro::QtHexEditScrollBar"
-QT_MOC_LITERAL(1, 25, 8), // "onScroll"
-QT_MOC_LITERAL(2, 34, 0) // ""
-
- },
- "hiro::QtHexEditScrollBar\0onScroll\0"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtHexEditScrollBar[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -904,20 +742,22 @@ static const uint qt_meta_data_hiro__QtHexEditScrollBar[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
+ // slots: signature, parameters, type, tag, flags
+ 25, 36, 36, 36, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtHexEditScrollBar[] = {
+ "hiro::QtHexEditScrollBar\0onScroll()\0"
+ "\0"
+};
+
void hiro::QtHexEditScrollBar::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtHexEditScrollBar *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onScroll(); break;
default: ;
@@ -926,22 +766,29 @@ void hiro::QtHexEditScrollBar::qt_static_metacall(QObject *_o, QMetaObject::Call
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtHexEditScrollBar::staticMetaObject = {
- { &QScrollBar::staticMetaObject, qt_meta_stringdata_hiro__QtHexEditScrollBar.data,
- qt_meta_data_hiro__QtHexEditScrollBar, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtHexEditScrollBar::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtHexEditScrollBar::staticMetaObject = {
+ { &QScrollBar::staticMetaObject, qt_meta_stringdata_hiro__QtHexEditScrollBar,
+ qt_meta_data_hiro__QtHexEditScrollBar, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtHexEditScrollBar::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtHexEditScrollBar::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtHexEditScrollBar::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtHexEditScrollBar.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtHexEditScrollBar))
+ return static_cast(const_cast< QtHexEditScrollBar*>(this));
return QScrollBar::qt_metacast(_clname);
}
@@ -954,38 +801,13 @@ int hiro::QtHexEditScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void **
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtHorizontalScrollBar_t {
- QByteArrayData data[3];
- char stringdata0[38];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtHorizontalScrollBar_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtHorizontalScrollBar_t qt_meta_stringdata_hiro__QtHorizontalScrollBar = {
- {
-QT_MOC_LITERAL(0, 0, 27), // "hiro::QtHorizontalScrollBar"
-QT_MOC_LITERAL(1, 28, 8), // "onChange"
-QT_MOC_LITERAL(2, 37, 0) // ""
-
- },
- "hiro::QtHorizontalScrollBar\0onChange\0"
- ""
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtHorizontalScrollBar[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -995,20 +817,22 @@ static const uint qt_meta_data_hiro__QtHorizontalScrollBar[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
+ // slots: signature, parameters, type, tag, flags
+ 28, 39, 39, 39, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtHorizontalScrollBar[] = {
+ "hiro::QtHorizontalScrollBar\0onChange()\0"
+ "\0"
+};
+
void hiro::QtHorizontalScrollBar::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtHorizontalScrollBar *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onChange(); break;
default: ;
@@ -1017,22 +841,29 @@ void hiro::QtHorizontalScrollBar::qt_static_metacall(QObject *_o, QMetaObject::C
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtHorizontalScrollBar::staticMetaObject = {
- { &QScrollBar::staticMetaObject, qt_meta_stringdata_hiro__QtHorizontalScrollBar.data,
- qt_meta_data_hiro__QtHorizontalScrollBar, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtHorizontalScrollBar::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtHorizontalScrollBar::staticMetaObject = {
+ { &QScrollBar::staticMetaObject, qt_meta_stringdata_hiro__QtHorizontalScrollBar,
+ qt_meta_data_hiro__QtHorizontalScrollBar, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtHorizontalScrollBar::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtHorizontalScrollBar::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtHorizontalScrollBar::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtHorizontalScrollBar.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtHorizontalScrollBar))
+ return static_cast(const_cast< QtHorizontalScrollBar*>(this));
return QScrollBar::qt_metacast(_clname);
}
@@ -1045,37 +876,13 @@ int hiro::QtHorizontalScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtHorizontalSlider_t {
- QByteArrayData data[3];
- char stringdata0[35];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtHorizontalSlider_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtHorizontalSlider_t qt_meta_stringdata_hiro__QtHorizontalSlider = {
- {
-QT_MOC_LITERAL(0, 0, 24), // "hiro::QtHorizontalSlider"
-QT_MOC_LITERAL(1, 25, 8), // "onChange"
-QT_MOC_LITERAL(2, 34, 0) // ""
-
- },
- "hiro::QtHorizontalSlider\0onChange\0"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtHorizontalSlider[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -1085,20 +892,22 @@ static const uint qt_meta_data_hiro__QtHorizontalSlider[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
+ // slots: signature, parameters, type, tag, flags
+ 25, 36, 36, 36, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtHorizontalSlider[] = {
+ "hiro::QtHorizontalSlider\0onChange()\0"
+ "\0"
+};
+
void hiro::QtHorizontalSlider::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtHorizontalSlider *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onChange(); break;
default: ;
@@ -1107,22 +916,29 @@ void hiro::QtHorizontalSlider::qt_static_metacall(QObject *_o, QMetaObject::Call
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtHorizontalSlider::staticMetaObject = {
- { &QSlider::staticMetaObject, qt_meta_stringdata_hiro__QtHorizontalSlider.data,
- qt_meta_data_hiro__QtHorizontalSlider, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtHorizontalSlider::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtHorizontalSlider::staticMetaObject = {
+ { &QSlider::staticMetaObject, qt_meta_stringdata_hiro__QtHorizontalSlider,
+ qt_meta_data_hiro__QtHorizontalSlider, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtHorizontalSlider::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtHorizontalSlider::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtHorizontalSlider::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtHorizontalSlider.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtHorizontalSlider))
+ return static_cast(const_cast< QtHorizontalSlider*>(this));
return QSlider::qt_metacast(_clname);
}
@@ -1135,35 +951,13 @@ int hiro::QtHorizontalSlider::qt_metacall(QMetaObject::Call _c, int _id, void **
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtLabel_t {
- QByteArrayData data[1];
- char stringdata0[14];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtLabel_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtLabel_t qt_meta_stringdata_hiro__QtLabel = {
- {
-QT_MOC_LITERAL(0, 0, 13) // "hiro::QtLabel"
-
- },
- "hiro::QtLabel"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtLabel[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
@@ -1176,6 +970,10 @@ static const uint qt_meta_data_hiro__QtLabel[] = {
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtLabel[] = {
+ "hiro::QtLabel\0"
+};
+
void hiro::QtLabel::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
Q_UNUSED(_o);
@@ -1184,55 +982,43 @@ void hiro::QtLabel::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _i
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtLabel::staticMetaObject = {
- { &QWidget::staticMetaObject, qt_meta_stringdata_hiro__QtLabel.data,
- qt_meta_data_hiro__QtLabel, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtLabel::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtLabel::staticMetaObject = {
+ { &QWidget::staticMetaObject, qt_meta_stringdata_hiro__QtLabel,
+ qt_meta_data_hiro__QtLabel, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtLabel::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtLabel::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtLabel::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtLabel.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtLabel))
+ return static_cast(const_cast< QtLabel*>(this));
return QWidget::qt_metacast(_clname);
}
int hiro::QtLabel::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QWidget::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
return _id;
}
-struct qt_meta_stringdata_hiro__QtLineEdit_t {
- QByteArrayData data[4];
- char stringdata0[38];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtLineEdit_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtLineEdit_t qt_meta_stringdata_hiro__QtLineEdit = {
- {
-QT_MOC_LITERAL(0, 0, 16), // "hiro::QtLineEdit"
-QT_MOC_LITERAL(1, 17, 10), // "onActivate"
-QT_MOC_LITERAL(2, 28, 0), // ""
-QT_MOC_LITERAL(3, 29, 8) // "onChange"
-
- },
- "hiro::QtLineEdit\0onActivate\0\0onChange"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtLineEdit[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
2, 14, // methods
@@ -1242,22 +1028,23 @@ static const uint qt_meta_data_hiro__QtLineEdit[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 24, 2, 0x0a /* Public */,
- 3, 0, 25, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
- QMetaType::Void,
+ // slots: signature, parameters, type, tag, flags
+ 17, 30, 30, 30, 0x0a,
+ 31, 30, 30, 30, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtLineEdit[] = {
+ "hiro::QtLineEdit\0onActivate()\0\0"
+ "onChange()\0"
+};
+
void hiro::QtLineEdit::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtLineEdit *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onActivate(); break;
case 1: _t->onChange(); break;
@@ -1267,22 +1054,29 @@ void hiro::QtLineEdit::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtLineEdit::staticMetaObject = {
- { &QLineEdit::staticMetaObject, qt_meta_stringdata_hiro__QtLineEdit.data,
- qt_meta_data_hiro__QtLineEdit, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtLineEdit::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtLineEdit::staticMetaObject = {
+ { &QLineEdit::staticMetaObject, qt_meta_stringdata_hiro__QtLineEdit,
+ qt_meta_data_hiro__QtLineEdit, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtLineEdit::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtLineEdit::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtLineEdit::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtLineEdit.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtLineEdit))
+ return static_cast(const_cast< QtLineEdit*>(this));
return QLineEdit::qt_metacast(_clname);
}
@@ -1295,37 +1089,13 @@ int hiro::QtLineEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 2)
qt_static_metacall(this, _c, _id, _a);
_id -= 2;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 2)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 2;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtRadioLabel_t {
- QByteArrayData data[3];
- char stringdata0[31];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtRadioLabel_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtRadioLabel_t qt_meta_stringdata_hiro__QtRadioLabel = {
- {
-QT_MOC_LITERAL(0, 0, 18), // "hiro::QtRadioLabel"
-QT_MOC_LITERAL(1, 19, 10), // "onActivate"
-QT_MOC_LITERAL(2, 30, 0) // ""
-
- },
- "hiro::QtRadioLabel\0onActivate\0"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtRadioLabel[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -1335,20 +1105,21 @@ static const uint qt_meta_data_hiro__QtRadioLabel[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
+ // slots: signature, parameters, type, tag, flags
+ 19, 32, 32, 32, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtRadioLabel[] = {
+ "hiro::QtRadioLabel\0onActivate()\0\0"
+};
+
void hiro::QtRadioLabel::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtRadioLabel *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onActivate(); break;
default: ;
@@ -1357,22 +1128,29 @@ void hiro::QtRadioLabel::qt_static_metacall(QObject *_o, QMetaObject::Call _c, i
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtRadioLabel::staticMetaObject = {
- { &QRadioButton::staticMetaObject, qt_meta_stringdata_hiro__QtRadioLabel.data,
- qt_meta_data_hiro__QtRadioLabel, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtRadioLabel::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtRadioLabel::staticMetaObject = {
+ { &QRadioButton::staticMetaObject, qt_meta_stringdata_hiro__QtRadioLabel,
+ qt_meta_data_hiro__QtRadioLabel, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtRadioLabel::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtRadioLabel::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtRadioLabel::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtRadioLabel.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtRadioLabel))
+ return static_cast(const_cast< QtRadioLabel*>(this));
return QRadioButton::qt_metacast(_clname);
}
@@ -1385,37 +1163,13 @@ int hiro::QtRadioLabel::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtRadioButton_t {
- QByteArrayData data[3];
- char stringdata0[32];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtRadioButton_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtRadioButton_t qt_meta_stringdata_hiro__QtRadioButton = {
- {
-QT_MOC_LITERAL(0, 0, 19), // "hiro::QtRadioButton"
-QT_MOC_LITERAL(1, 20, 10), // "onActivate"
-QT_MOC_LITERAL(2, 31, 0) // ""
-
- },
- "hiro::QtRadioButton\0onActivate\0"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtRadioButton[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -1425,20 +1179,21 @@ static const uint qt_meta_data_hiro__QtRadioButton[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
+ // slots: signature, parameters, type, tag, flags
+ 20, 33, 33, 33, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtRadioButton[] = {
+ "hiro::QtRadioButton\0onActivate()\0\0"
+};
+
void hiro::QtRadioButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtRadioButton *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onActivate(); break;
default: ;
@@ -1447,22 +1202,29 @@ void hiro::QtRadioButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c,
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtRadioButton::staticMetaObject = {
- { &QToolButton::staticMetaObject, qt_meta_stringdata_hiro__QtRadioButton.data,
- qt_meta_data_hiro__QtRadioButton, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtRadioButton::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtRadioButton::staticMetaObject = {
+ { &QToolButton::staticMetaObject, qt_meta_stringdata_hiro__QtRadioButton,
+ qt_meta_data_hiro__QtRadioButton, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtRadioButton::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtRadioButton::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtRadioButton::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtRadioButton.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtRadioButton))
+ return static_cast(const_cast< QtRadioButton*>(this));
return QToolButton::qt_metacast(_clname);
}
@@ -1475,38 +1237,13 @@ int hiro::QtRadioButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtTabFrame_t {
- QByteArrayData data[4];
- char stringdata0[37];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtTabFrame_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtTabFrame_t qt_meta_stringdata_hiro__QtTabFrame = {
- {
-QT_MOC_LITERAL(0, 0, 16), // "hiro::QtTabFrame"
-QT_MOC_LITERAL(1, 17, 8), // "onChange"
-QT_MOC_LITERAL(2, 26, 0), // ""
-QT_MOC_LITERAL(3, 27, 9) // "selection"
-
- },
- "hiro::QtTabFrame\0onChange\0\0selection"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtTabFrame[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -1516,20 +1253,22 @@ static const uint qt_meta_data_hiro__QtTabFrame[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 1, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void, QMetaType::Int, 3,
+ // slots: signature, parameters, type, tag, flags
+ 17, 31, 41, 41, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtTabFrame[] = {
+ "hiro::QtTabFrame\0onChange(int)\0selection\0"
+ "\0"
+};
+
void hiro::QtTabFrame::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtTabFrame *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onChange((*reinterpret_cast< int(*)>(_a[1]))); break;
default: ;
@@ -1537,22 +1276,29 @@ void hiro::QtTabFrame::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int
}
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtTabFrame::staticMetaObject = {
- { &QTabWidget::staticMetaObject, qt_meta_stringdata_hiro__QtTabFrame.data,
- qt_meta_data_hiro__QtTabFrame, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtTabFrame::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtTabFrame::staticMetaObject = {
+ { &QTabWidget::staticMetaObject, qt_meta_stringdata_hiro__QtTabFrame,
+ qt_meta_data_hiro__QtTabFrame, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtTabFrame::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtTabFrame::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtTabFrame::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtTabFrame.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtTabFrame))
+ return static_cast(const_cast< QtTabFrame*>(this));
return QTabWidget::qt_metacast(_clname);
}
@@ -1565,46 +1311,13 @@ int hiro::QtTabFrame::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtTableView_t {
- QByteArrayData data[10];
- char stringdata0[94];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtTableView_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtTableView_t qt_meta_stringdata_hiro__QtTableView = {
- {
-QT_MOC_LITERAL(0, 0, 17), // "hiro::QtTableView"
-QT_MOC_LITERAL(1, 18, 10), // "onActivate"
-QT_MOC_LITERAL(2, 29, 0), // ""
-QT_MOC_LITERAL(3, 30, 8), // "onChange"
-QT_MOC_LITERAL(4, 39, 9), // "onContext"
-QT_MOC_LITERAL(5, 49, 6), // "onSort"
-QT_MOC_LITERAL(6, 56, 6), // "column"
-QT_MOC_LITERAL(7, 63, 8), // "onToggle"
-QT_MOC_LITERAL(8, 72, 16), // "QTreeWidgetItem*"
-QT_MOC_LITERAL(9, 89, 4) // "item"
-
- },
- "hiro::QtTableView\0onActivate\0\0onChange\0"
- "onContext\0onSort\0column\0onToggle\0"
- "QTreeWidgetItem*\0item"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtTableView[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
5, 14, // methods
@@ -1614,28 +1327,28 @@ static const uint qt_meta_data_hiro__QtTableView[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 39, 2, 0x0a /* Public */,
- 3, 0, 40, 2, 0x0a /* Public */,
- 4, 0, 41, 2, 0x0a /* Public */,
- 5, 1, 42, 2, 0x0a /* Public */,
- 7, 2, 45, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
- QMetaType::Void,
- QMetaType::Void,
- QMetaType::Void, QMetaType::Int, 6,
- QMetaType::Void, 0x80000000 | 8, QMetaType::Int, 9, 6,
+ // slots: signature, parameters, type, tag, flags
+ 18, 31, 31, 31, 0x0a,
+ 32, 31, 31, 31, 0x0a,
+ 43, 31, 31, 31, 0x0a,
+ 55, 67, 31, 31, 0x0a,
+ 74, 105, 31, 31, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtTableView[] = {
+ "hiro::QtTableView\0onActivate()\0\0"
+ "onChange()\0onContext()\0onSort(int)\0"
+ "column\0onToggle(QTreeWidgetItem*,int)\0"
+ "item,column\0"
+};
+
void hiro::QtTableView::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtTableView *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onActivate(); break;
case 1: _t->onChange(); break;
@@ -1647,22 +1360,29 @@ void hiro::QtTableView::qt_static_metacall(QObject *_o, QMetaObject::Call _c, in
}
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtTableView::staticMetaObject = {
- { &QTreeWidget::staticMetaObject, qt_meta_stringdata_hiro__QtTableView.data,
- qt_meta_data_hiro__QtTableView, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtTableView::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtTableView::staticMetaObject = {
+ { &QTreeWidget::staticMetaObject, qt_meta_stringdata_hiro__QtTableView,
+ qt_meta_data_hiro__QtTableView, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtTableView::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtTableView::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtTableView::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtTableView.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtTableView))
+ return static_cast(const_cast< QtTableView*>(this));
return QTreeWidget::qt_metacast(_clname);
}
@@ -1675,37 +1395,13 @@ int hiro::QtTableView::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 5)
qt_static_metacall(this, _c, _id, _a);
_id -= 5;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 5)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 5;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtTextEdit_t {
- QByteArrayData data[3];
- char stringdata0[27];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtTextEdit_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtTextEdit_t qt_meta_stringdata_hiro__QtTextEdit = {
- {
-QT_MOC_LITERAL(0, 0, 16), // "hiro::QtTextEdit"
-QT_MOC_LITERAL(1, 17, 8), // "onChange"
-QT_MOC_LITERAL(2, 26, 0) // ""
-
- },
- "hiro::QtTextEdit\0onChange\0"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtTextEdit[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -1715,20 +1411,21 @@ static const uint qt_meta_data_hiro__QtTextEdit[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
+ // slots: signature, parameters, type, tag, flags
+ 17, 28, 28, 28, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtTextEdit[] = {
+ "hiro::QtTextEdit\0onChange()\0\0"
+};
+
void hiro::QtTextEdit::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtTextEdit *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onChange(); break;
default: ;
@@ -1737,22 +1434,29 @@ void hiro::QtTextEdit::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtTextEdit::staticMetaObject = {
- { &QTextEdit::staticMetaObject, qt_meta_stringdata_hiro__QtTextEdit.data,
- qt_meta_data_hiro__QtTextEdit, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtTextEdit::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtTextEdit::staticMetaObject = {
+ { &QTextEdit::staticMetaObject, qt_meta_stringdata_hiro__QtTextEdit,
+ qt_meta_data_hiro__QtTextEdit, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtTextEdit::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtTextEdit::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtTextEdit::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtTextEdit.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtTextEdit))
+ return static_cast(const_cast< QtTextEdit*>(this));
return QTextEdit::qt_metacast(_clname);
}
@@ -1765,37 +1469,13 @@ int hiro::QtTextEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtVerticalScrollBar_t {
- QByteArrayData data[3];
- char stringdata0[36];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtVerticalScrollBar_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtVerticalScrollBar_t qt_meta_stringdata_hiro__QtVerticalScrollBar = {
- {
-QT_MOC_LITERAL(0, 0, 25), // "hiro::QtVerticalScrollBar"
-QT_MOC_LITERAL(1, 26, 8), // "onChange"
-QT_MOC_LITERAL(2, 35, 0) // ""
-
- },
- "hiro::QtVerticalScrollBar\0onChange\0"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtVerticalScrollBar[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -1805,20 +1485,22 @@ static const uint qt_meta_data_hiro__QtVerticalScrollBar[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
+ // slots: signature, parameters, type, tag, flags
+ 26, 37, 37, 37, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtVerticalScrollBar[] = {
+ "hiro::QtVerticalScrollBar\0onChange()\0"
+ "\0"
+};
+
void hiro::QtVerticalScrollBar::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtVerticalScrollBar *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onChange(); break;
default: ;
@@ -1827,22 +1509,29 @@ void hiro::QtVerticalScrollBar::qt_static_metacall(QObject *_o, QMetaObject::Cal
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtVerticalScrollBar::staticMetaObject = {
- { &QScrollBar::staticMetaObject, qt_meta_stringdata_hiro__QtVerticalScrollBar.data,
- qt_meta_data_hiro__QtVerticalScrollBar, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtVerticalScrollBar::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtVerticalScrollBar::staticMetaObject = {
+ { &QScrollBar::staticMetaObject, qt_meta_stringdata_hiro__QtVerticalScrollBar,
+ qt_meta_data_hiro__QtVerticalScrollBar, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtVerticalScrollBar::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtVerticalScrollBar::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtVerticalScrollBar::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtVerticalScrollBar.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtVerticalScrollBar))
+ return static_cast(const_cast< QtVerticalScrollBar*>(this));
return QScrollBar::qt_metacast(_clname);
}
@@ -1855,37 +1544,13 @@ int hiro::QtVerticalScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void *
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtVerticalSlider_t {
- QByteArrayData data[3];
- char stringdata0[33];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtVerticalSlider_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtVerticalSlider_t qt_meta_stringdata_hiro__QtVerticalSlider = {
- {
-QT_MOC_LITERAL(0, 0, 22), // "hiro::QtVerticalSlider"
-QT_MOC_LITERAL(1, 23, 8), // "onChange"
-QT_MOC_LITERAL(2, 32, 0) // ""
-
- },
- "hiro::QtVerticalSlider\0onChange\0"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtVerticalSlider[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@@ -1895,20 +1560,21 @@ static const uint qt_meta_data_hiro__QtVerticalSlider[] = {
0, // flags
0, // signalCount
- // slots: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x0a /* Public */,
-
- // slots: parameters
- QMetaType::Void,
+ // slots: signature, parameters, type, tag, flags
+ 23, 34, 34, 34, 0x0a,
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtVerticalSlider[] = {
+ "hiro::QtVerticalSlider\0onChange()\0\0"
+};
+
void hiro::QtVerticalSlider::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
QtVerticalSlider *_t = static_cast(_o);
- Q_UNUSED(_t)
switch (_id) {
case 0: _t->onChange(); break;
default: ;
@@ -1917,22 +1583,29 @@ void hiro::QtVerticalSlider::qt_static_metacall(QObject *_o, QMetaObject::Call _
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtVerticalSlider::staticMetaObject = {
- { &QSlider::staticMetaObject, qt_meta_stringdata_hiro__QtVerticalSlider.data,
- qt_meta_data_hiro__QtVerticalSlider, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtVerticalSlider::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtVerticalSlider::staticMetaObject = {
+ { &QSlider::staticMetaObject, qt_meta_stringdata_hiro__QtVerticalSlider,
+ qt_meta_data_hiro__QtVerticalSlider, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtVerticalSlider::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtVerticalSlider::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtVerticalSlider::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtVerticalSlider.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtVerticalSlider))
+ return static_cast(const_cast< QtVerticalSlider*>(this));
return QSlider::qt_metacast(_clname);
}
@@ -1945,35 +1618,13 @@ int hiro::QtVerticalSlider::qt_metacall(QMetaObject::Call _c, int _id, void **_a
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
}
return _id;
}
-struct qt_meta_stringdata_hiro__QtViewport_t {
- QByteArrayData data[1];
- char stringdata0[17];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(qt_meta_stringdata_hiro__QtViewport_t, stringdata0) + ofs \
- - idx * sizeof(QByteArrayData)) \
- )
-static const qt_meta_stringdata_hiro__QtViewport_t qt_meta_stringdata_hiro__QtViewport = {
- {
-QT_MOC_LITERAL(0, 0, 16) // "hiro::QtViewport"
-
- },
- "hiro::QtViewport"
-};
-#undef QT_MOC_LITERAL
-
static const uint qt_meta_data_hiro__QtViewport[] = {
// content:
- 7, // revision
+ 6, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
@@ -1986,6 +1637,10 @@ static const uint qt_meta_data_hiro__QtViewport[] = {
0 // eod
};
+static const char qt_meta_stringdata_hiro__QtViewport[] = {
+ "hiro::QtViewport\0"
+};
+
void hiro::QtViewport::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
Q_UNUSED(_o);
@@ -1994,29 +1649,37 @@ void hiro::QtViewport::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int
Q_UNUSED(_a);
}
-QT_INIT_METAOBJECT const QMetaObject hiro::QtViewport::staticMetaObject = {
- { &QWidget::staticMetaObject, qt_meta_stringdata_hiro__QtViewport.data,
- qt_meta_data_hiro__QtViewport, qt_static_metacall, nullptr, nullptr}
+const QMetaObjectExtraData hiro::QtViewport::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
};
+const QMetaObject hiro::QtViewport::staticMetaObject = {
+ { &QWidget::staticMetaObject, qt_meta_stringdata_hiro__QtViewport,
+ qt_meta_data_hiro__QtViewport, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &hiro::QtViewport::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
const QMetaObject *hiro::QtViewport::metaObject() const
{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *hiro::QtViewport::qt_metacast(const char *_clname)
{
- if (!_clname) return nullptr;
- if (!strcmp(_clname, qt_meta_stringdata_hiro__QtViewport.stringdata0))
- return static_cast(this);
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_hiro__QtViewport))
+ return static_cast(const_cast< QtViewport*>(this));
return QWidget::qt_metacast(_clname);
}
int hiro::QtViewport::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QWidget::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
return _id;
}
-QT_WARNING_POP
QT_END_MOC_NAMESPACE
diff --git a/hiro/qt/settings.cpp b/hiro/qt/settings.cpp
index abb316ae..26bb808d 100644
--- a/hiro/qt/settings.cpp
+++ b/hiro/qt/settings.cpp
@@ -1,7 +1,7 @@
namespace hiro {
Settings::Settings() {
- string path = {Path::userData(), "hiro/"};
+ string path = {Path::userSettings(), "hiro/"};
#if HIRO_QT==4
auto document = BML::unserialize(file::read({path, "qt4.bml"}));
#elif HIRO_QT==5
@@ -22,7 +22,7 @@ Settings::Settings() {
}
Settings::~Settings() {
- string path = {Path::userData(), "hiro/"};
+ string path = {Path::userSettings(), "hiro/"};
directory::create(path, 0755);
Markup::Node document;
diff --git a/hiro/qt/widget/canvas.cpp b/hiro/qt/widget/canvas.cpp
index 5809893d..1ba354df 100644
--- a/hiro/qt/widget/canvas.cpp
+++ b/hiro/qt/widget/canvas.cpp
@@ -22,6 +22,10 @@ auto pCanvas::minimumSize() const -> Size {
return {0, 0};
}
+auto pCanvas::setAlignment(Alignment) -> void {
+ update();
+}
+
auto pCanvas::setColor(Color color) -> void {
update();
}
@@ -132,21 +136,22 @@ auto QtCanvas::paintEvent(QPaintEvent* event) -> void {
signed width = p.qtImageWidth;
signed height = p.qtImageHeight;
auto geometry = p.pSizable::state().geometry;
+ auto alignment = p.state().alignment ? p.state().alignment : Alignment{0.5, 0.5};
if(width <= geometry.width()) {
sx = 0;
- dx = (geometry.width() - width) / 2;
+ dx = (geometry.width() - width) * alignment.horizontal();
} else {
- sx = (width - geometry.width()) / 2;
+ sx = (width - geometry.width()) * alignment.horizontal();
dx = 0;
width = geometry.width();
}
if(height <= geometry.height()) {
sy = 0;
- dy = (geometry.height() - height) / 2;
+ dy = (geometry.height() - height) * alignment.vertical();
} else {
- sy = (height - geometry.height()) / 2;
+ sy = (height - geometry.height()) * alignment.vertical();
dy = 0;
height = geometry.height();
}
diff --git a/hiro/qt/widget/canvas.hpp b/hiro/qt/widget/canvas.hpp
index 347d9075..686a1030 100644
--- a/hiro/qt/widget/canvas.hpp
+++ b/hiro/qt/widget/canvas.hpp
@@ -6,6 +6,7 @@ struct pCanvas : pWidget {
Declare(Canvas, Widget)
auto minimumSize() const -> Size;
+ auto setAlignment(Alignment) -> void;
auto setColor(Color color) -> void;
auto setDroppable(bool droppable) -> void;
auto setGeometry(Geometry geometry) -> void;
diff --git a/hiro/qt/window.cpp b/hiro/qt/window.cpp
index 2ed5a18e..a77ec068 100644
--- a/hiro/qt/window.cpp
+++ b/hiro/qt/window.cpp
@@ -78,6 +78,10 @@ auto pWindow::frameMargin() const -> Geometry {
};
}
+auto pWindow::handle() const -> uintptr_t {
+ return (uintptr_t)qtWindow->winId();
+}
+
auto pWindow::monitor() const -> uint {
//TODO
return 0;
diff --git a/hiro/qt/window.hpp b/hiro/qt/window.hpp
index 0d22e675..db5a4a18 100644
--- a/hiro/qt/window.hpp
+++ b/hiro/qt/window.hpp
@@ -10,6 +10,7 @@ struct pWindow : pObject {
auto append(sStatusBar statusBar) -> void;
auto focused() const -> bool override;
auto frameMargin() const -> Geometry;
+ auto handle() const -> uintptr_t;
auto monitor() const -> uint;
auto remove(sMenuBar menuBar) -> void;
auto remove(sSizable sizable) -> void;
diff --git a/hiro/resource/icon/action/new.png b/hiro/resource/icon/action/new-file.png
similarity index 100%
rename from hiro/resource/icon/action/new.png
rename to hiro/resource/icon/action/new-file.png
diff --git a/hiro/resource/icon/action/new-folder.png b/hiro/resource/icon/action/new-folder.png
new file mode 100644
index 00000000..628f4d50
Binary files /dev/null and b/hiro/resource/icon/action/new-folder.png differ
diff --git a/hiro/resource/icon/emblem/folder-template.png b/hiro/resource/icon/emblem/folder-template.png
new file mode 100644
index 00000000..90024447
Binary files /dev/null and b/hiro/resource/icon/emblem/folder-template.png differ
diff --git a/hiro/resource/resource.bml b/hiro/resource/resource.bml
index 44fa8631..13b94b92 100644
--- a/hiro/resource/resource.bml
+++ b/hiro/resource/resource.bml
@@ -6,7 +6,8 @@ namespace name=Icon
binary name=Close file=icon/action/close.png
binary name=FullScreen file=icon/action/full-screen.png
binary name=Mute file=icon/action/mute.png
- binary name=New file=icon/action/new.png
+ binary name=NewFile file=icon/action/new-file.png
+ binary name=NewFolder file=icon/action/new-folder.png
binary name=Open file=icon/action/open.png
binary name=Properties file=icon/action/properties.png
binary name=Quit file=icon/action/quit.png
@@ -55,6 +56,7 @@ namespace name=Icon
binary name=File file=icon/emblem/file.png
binary name=Folder file=icon/emblem/folder.png
binary name=FolderOpen file=icon/emblem/folder-open.png
+ binary name=FolderTemplate file=icon/emblem/folder-template.png
binary name=Font file=icon/emblem/font.png
binary name=Image file=icon/emblem/image.png
binary name=Markup file=icon/emblem/markup.png
diff --git a/hiro/resource/resource.cpp b/hiro/resource/resource.cpp
index 873179ec..dfc6179f 100644
--- a/hiro/resource/resource.cpp
+++ b/hiro/resource/resource.cpp
@@ -128,7 +128,7 @@ const unsigned char Mute[632] = {
4,13,209,40,149,189,61,154,122,123,169,236,238,82,45,149,216,5,255,92,0,192,188,82,47,66,120,122,218,151,51,227,
91,48,254,11,41,211,229,38,66,238,34,57,0,0,0,0,73,69,78,68,174,66,96,130,
};
-const unsigned char New[477] = {
+const unsigned char NewFile[477] = {
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,
97,0,0,0,6,98,75,71,68,0,252,0,233,0,79,52,215,177,13,0,0,0,9,112,72,89,115,0,0,11,19,0,
0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,2,18,14,38,28,211,182,25,41,0,0,1,106,73,
@@ -145,6 +145,28 @@ const unsigned char New[477] = {
123,17,134,57,120,136,124,199,193,176,165,193,217,176,29,51,169,221,177,17,114,185,28,143,129,139,227,248,67,146,36,197,
127,33,197,113,252,158,255,133,43,204,61,153,96,123,172,20,201,0,0,0,0,73,69,78,68,174,66,96,130,
};
+const unsigned char NewFolder[635] = {
+ 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,
+ 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,13,215,0,
+ 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,11,17,15,7,0,85,79,247,45,0,0,2,8,73,
+ 68,65,84,56,203,165,144,61,104,83,97,20,134,159,239,246,222,150,123,83,73,219,180,36,164,181,10,86,92,21,7,21,
+ 252,157,196,201,74,20,69,7,21,23,65,196,193,77,16,93,157,4,17,65,80,91,39,17,113,112,178,69,176,149,46,186,
+ 212,64,37,14,45,65,45,66,219,104,171,33,189,247,230,187,63,199,33,33,173,165,65,197,135,15,190,225,156,243,158,247,
+ 188,234,196,201,220,141,76,38,115,147,53,104,173,107,127,85,95,28,122,244,248,62,77,80,151,175,92,146,243,103,47,172,
+ 91,244,125,143,135,67,15,40,151,203,167,159,61,125,254,36,156,63,170,0,11,8,204,244,11,105,8,228,142,29,167,240,
+ 177,208,108,9,99,227,175,105,49,132,222,12,12,108,22,250,50,50,118,228,160,92,7,222,155,0,182,237,208,145,236,108,
+ 42,144,27,28,164,187,227,27,3,27,103,233,72,245,16,132,214,161,216,40,222,85,241,220,109,83,107,141,231,185,188,250,
+ 80,97,170,228,172,51,46,12,164,127,114,102,95,17,171,189,23,195,62,133,99,118,177,236,77,108,47,126,30,189,215,112,
+ 48,85,114,184,115,245,48,190,142,126,15,137,144,100,235,52,89,187,132,237,100,105,49,83,40,101,96,153,54,161,72,194,
+ 4,240,60,23,128,185,37,159,226,194,242,26,129,152,148,3,65,247,6,178,209,52,237,106,2,203,218,70,168,39,41,206,
+ 181,98,250,190,143,109,59,77,239,23,12,150,188,30,10,165,157,84,244,12,253,250,45,118,91,30,55,72,48,146,239,199,
+ 116,93,183,225,160,25,145,152,124,247,210,84,116,146,217,242,22,218,90,124,146,237,125,204,204,79,210,200,224,207,24,84,
+ 35,135,170,91,235,109,179,109,170,129,137,177,58,131,191,37,138,98,252,64,0,86,28,88,70,140,0,34,130,82,10,17,
+ 65,4,98,17,162,72,8,162,24,29,10,213,48,34,136,132,100,162,117,69,192,243,92,54,37,171,44,86,52,95,23,61,
+ 16,69,140,80,127,136,128,32,136,212,133,129,48,90,229,96,190,180,192,142,61,123,201,127,250,81,31,170,109,23,129,24,
+ 65,80,32,210,112,181,107,107,23,163,47,71,232,244,103,135,213,254,115,183,198,93,171,247,0,255,72,34,248,242,238,205,
+ 240,181,221,252,47,191,0,92,182,248,138,55,225,154,169,0,0,0,0,73,69,78,68,174,66,96,130,
+};
const unsigned char Open[672] = {
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,
97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13,
@@ -1159,6 +1181,22 @@ const unsigned char FolderOpen[625] = {
67,59,237,125,178,219,235,50,55,174,188,251,176,89,221,4,103,237,243,183,11,133,39,98,3,179,231,191,1,223,162,81,
163,208,43,119,152,0,0,0,0,73,69,78,68,174,66,96,130,
};
+const unsigned char FolderTemplate[429] = {
+ 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,
+ 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13,
+ 215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99,
+ 97,112,101,46,111,114,103,155,238,60,26,0,0,1,42,73,68,65,84,56,141,165,147,189,78,66,65,16,133,207,254,112,
+ 67,110,76,172,120,0,236,180,161,247,13,160,208,6,223,194,119,241,5,76,72,40,120,1,11,254,172,165,177,176,39,177,
+ 177,147,144,72,65,76,238,236,156,177,187,202,37,144,92,60,201,169,102,231,219,57,217,89,103,102,248,143,226,124,62,123,
+ 4,236,182,90,32,177,85,213,126,175,215,123,61,6,112,211,233,228,171,221,190,56,15,33,236,20,54,155,13,86,171,213,
+ 76,85,111,170,77,221,110,183,0,96,0,224,85,213,154,205,38,242,60,223,113,171,213,66,8,225,154,212,109,213,147,201,
+ 248,173,140,32,34,230,189,71,140,113,55,91,140,232,116,58,103,251,209,136,197,226,229,170,60,151,82,98,8,97,15,112,
+ 72,36,33,34,191,23,29,154,224,56,32,253,5,36,214,1,152,25,72,229,112,56,252,246,222,191,71,17,65,157,8,0,
+ 208,239,223,101,170,9,163,209,232,50,170,10,157,3,170,207,120,76,33,4,144,17,69,33,244,69,145,72,214,223,70,51,
+ 131,136,152,23,17,35,89,27,64,18,41,37,122,85,229,41,255,161,4,0,56,9,176,94,175,209,104,52,62,61,0,168,
+ 106,109,192,114,185,52,85,125,142,206,185,167,193,96,112,95,23,144,101,217,135,136,60,252,0,218,142,189,133,140,36,139,
+ 153,0,0,0,0,73,69,78,68,174,66,96,130,
+};
const unsigned char Font[627] = {
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,
97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,
diff --git a/hiro/resource/resource.hpp b/hiro/resource/resource.hpp
index 7d19155b..6ff61cf7 100644
--- a/hiro/resource/resource.hpp
+++ b/hiro/resource/resource.hpp
@@ -6,7 +6,8 @@ extern const unsigned char Bookmark[686];
extern const unsigned char Close[586];
extern const unsigned char FullScreen[650];
extern const unsigned char Mute[632];
-extern const unsigned char New[477];
+extern const unsigned char NewFile[477];
+extern const unsigned char NewFolder[635];
extern const unsigned char Open[672];
extern const unsigned char Properties[464];
extern const unsigned char Quit[799];
@@ -59,6 +60,7 @@ extern const unsigned char Binary[560];
extern const unsigned char File[741];
extern const unsigned char Folder[581];
extern const unsigned char FolderOpen[625];
+extern const unsigned char FolderTemplate[429];
extern const unsigned char Font[627];
extern const unsigned char Image[558];
extern const unsigned char Markup[709];
diff --git a/hiro/windows/application.cpp b/hiro/windows/application.cpp
index 886776aa..9f62cbe8 100644
--- a/hiro/windows/application.cpp
+++ b/hiro/windows/application.cpp
@@ -11,17 +11,17 @@ auto pApplication::modal() -> bool {
}
auto pApplication::run() -> void {
- MSG msg;
- if(Application::state().onMain) {
- while(!Application::state().quit) {
+ while(!Application::state().quit) {
+ if(Application::state().onMain) {
+ //doMain() is responsible for sleeping the thread where practical
Application::doMain();
- processEvents();
- }
- } else {
- MSG msg;
- while(GetMessage(&msg, 0, 0, 0)) {
- Application_processDialogMessage(msg);
+ if(Application::state().quit) break;
+ } else {
+ //avoid consuming 100% CPU thread usage
+ usleep(20 * 1000);
}
+ //called after doMain(), in case doMain() calls Application::quit()
+ processEvents();
}
}
diff --git a/hiro/windows/font.cpp b/hiro/windows/font.cpp
index e752d64b..4c43269a 100644
--- a/hiro/windows/font.cpp
+++ b/hiro/windows/font.cpp
@@ -26,8 +26,9 @@ auto pFont::family(const string& family) -> string {
}
auto pFont::create(const Font& font) -> HFONT {
+ static float dpi = Monitor::dpi().x();
return CreateFont(
- -(Application::scale(font.size() ? font.size() : 8) * 96.0 / 72.0 + 0.5),
+ -((font.size() ? font.size() : 8) * dpi / 72.0 + 0.5),
0, 0, 0, font.bold() ? FW_BOLD : FW_NORMAL, font.italic(), 0, 0, 0, 0, 0, 0, 0,
utf16_t(family(font.family()))
);
diff --git a/hiro/windows/header.hpp b/hiro/windows/header.hpp
index a893f8cc..f6417d49 100644
--- a/hiro/windows/header.hpp
+++ b/hiro/windows/header.hpp
@@ -7,6 +7,7 @@
#include
#include
#include