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 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - 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 +#include #include #include #include diff --git a/hiro/windows/hiro.Manifest b/hiro/windows/hiro.Manifest index 5f6ac40d..2d8ba042 100644 --- a/hiro/windows/hiro.Manifest +++ b/hiro/windows/hiro.Manifest @@ -7,8 +7,9 @@ - - false + + true/pm + PerMonitorV2, PerMonitor diff --git a/hiro/windows/platform.cpp b/hiro/windows/platform.cpp index 2172ac95..f73d2df1 100644 --- a/hiro/windows/platform.cpp +++ b/hiro/windows/platform.cpp @@ -57,3 +57,4 @@ #include "widget/viewport.cpp" #include "application.cpp" +#include "settings.cpp" diff --git a/hiro/windows/platform.hpp b/hiro/windows/platform.hpp index 37cb4f89..e6990857 100644 --- a/hiro/windows/platform.hpp +++ b/hiro/windows/platform.hpp @@ -79,5 +79,6 @@ static vector windows; #include "widget/viewport.hpp" #include "application.hpp" +#include "settings.hpp" #undef Declare diff --git a/hiro/windows/settings.cpp b/hiro/windows/settings.cpp new file mode 100644 index 00000000..fd148a1a --- /dev/null +++ b/hiro/windows/settings.cpp @@ -0,0 +1,46 @@ +namespace hiro { + +Settings::Settings() { + string path = {Path::userSettings(), "hiro/"}; + auto document = BML::unserialize(file::read({path, "windows.bml"})); + + document["extendedFrameBounds/popup/x"].value(efbPopup.x); + document["extendedFrameBounds/popup/y"].value(efbPopup.y); + document["extendedFrameBounds/popup/width"].value(efbPopup.width); + document["extendedFrameBounds/popup/height"].value(efbPopup.height); + + document["extendedFrameBounds/fixed/x"].value(efbFixed.x); + document["extendedFrameBounds/fixed/y"].value(efbFixed.y); + document["extendedFrameBounds/fixed/width"].value(efbFixed.width); + document["extendedFrameBounds/fixed/height"].value(efbFixed.height); + + document["extendedFrameBounds/resizable/x"].value(efbResizable.x); + document["extendedFrameBounds/resizable/y"].value(efbResizable.y); + document["extendedFrameBounds/resizable/width"].value(efbResizable.width); + document["extendedFrameBounds/resizable/height"].value(efbResizable.height); +} + +Settings::~Settings() { + string path = {Path::userSettings(), "hiro/"}; + directory::create(path, 0755); + Markup::Node document; + + document("extendedFrameBounds/popup/x").setValue(efbPopup.x); + document("extendedFrameBounds/popup/y").setValue(efbPopup.y); + document("extendedFrameBounds/popup/width").setValue(efbPopup.width); + document("extendedFrameBounds/popup/height").setValue(efbPopup.height); + + document("extendedFrameBounds/fixed/x").setValue(efbFixed.x); + document("extendedFrameBounds/fixed/y").setValue(efbFixed.y); + document("extendedFrameBounds/fixed/width").setValue(efbFixed.width); + document("extendedFrameBounds/fixed/height").setValue(efbFixed.height); + + document("extendedFrameBounds/resizable/x").setValue(efbResizable.x); + document("extendedFrameBounds/resizable/y").setValue(efbResizable.y); + document("extendedFrameBounds/resizable/width").setValue(efbResizable.width); + document("extendedFrameBounds/resizable/height").setValue(efbResizable.height); + + file::write({path, "windows.bml"}, BML::serialize(document)); +} + +} diff --git a/hiro/windows/settings.hpp b/hiro/windows/settings.hpp new file mode 100644 index 00000000..c86af68a --- /dev/null +++ b/hiro/windows/settings.hpp @@ -0,0 +1,28 @@ +namespace hiro { + +struct Settings { + Settings(); + ~Settings(); + + //Windows 8+ draws windows with almost no visible borders + //to allow resizing the window, the OS places transparent margins around each window + //this causes AdjustFrameRect and SetWindowPos to hold values larger than the actual window + //as a result, attempts to call Window::setAlignment(Window) fail to position windows correctly + //pWindow::setVisible() attempts to compute the actual window bounds to correct Window::frameMargin() + //note: different window styles have different extended frame bounds + struct ExtendedFrameBounds { + uint x = 0; + uint y = 0; + uint width = 0; + uint height = 0; + }; + + //these are the default values for Windows 10 ... they will be updated later if they are incorrect + ExtendedFrameBounds efbPopup { 0, 0, 0, 0}; + ExtendedFrameBounds efbFixed { 2, 0, 4, 2}; + ExtendedFrameBounds efbResizable{10, 0, 20, 10}; +}; + +static Settings settings; + +} diff --git a/hiro/windows/utility.cpp b/hiro/windows/utility.cpp index ae1bdca1..04bd5c9e 100644 --- a/hiro/windows/utility.cpp +++ b/hiro/windows/utility.cpp @@ -179,9 +179,7 @@ static auto CALLBACK Shared_windowProc(WindowProc windowProc, HWND hwnd, UINT ms if(!window) return DefWindowProc(hwnd, msg, wparam, lparam); auto pWindow = window->self(); if(!pWindow) return DefWindowProc(hwnd, msg, wparam, lparam); - - if(pWindow->_modalityDisabled()) return DefWindowProc(hwnd, msg, wparam, lparam); - + switch(msg) { case WM_CTLCOLORBTN: case WM_CTLCOLOREDIT: @@ -325,7 +323,7 @@ static auto CALLBACK Shared_windowProc(WindowProc windowProc, HWND hwnd, UINT ms if(header->code == LVN_ITEMACTIVATE) { tableView->self()->onActivate(lparam); break; - } + } if(header->code == LVN_ITEMCHANGED) { tableView->self()->onChange(lparam); break; diff --git a/hiro/windows/widget/canvas.cpp b/hiro/windows/widget/canvas.cpp index f6c84e45..c45af363 100644 --- a/hiro/windows/widget/canvas.cpp +++ b/hiro/windows/widget/canvas.cpp @@ -18,6 +18,10 @@ auto pCanvas::minimumSize() const -> Size { return {0, 0}; } +auto pCanvas::setAlignment(Alignment) -> void { + update(); +} + auto pCanvas::setColor(Color color) -> void { update(); } @@ -98,21 +102,22 @@ auto pCanvas::_paint() -> void { int width = this->width; int height = this->height; auto geometry = self().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; 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/windows/widget/canvas.hpp b/hiro/windows/widget/canvas.hpp index 1753ba7f..0535694a 100644 --- a/hiro/windows/widget/canvas.hpp +++ b/hiro/windows/widget/canvas.hpp @@ -6,6 +6,7 @@ struct pCanvas : pWidget { Declare(Canvas, Widget) auto minimumSize() const -> Size override; + auto setAlignment(Alignment) -> void; auto setColor(Color color) -> void; auto setDroppable(bool droppable) -> void; auto setGeometry(Geometry geometry) -> void override; diff --git a/hiro/windows/widget/check-label.cpp b/hiro/windows/widget/check-label.cpp index d4c04527..c63ae643 100644 --- a/hiro/windows/widget/check-label.cpp +++ b/hiro/windows/widget/check-label.cpp @@ -19,7 +19,7 @@ auto pCheckLabel::destruct() -> void { auto pCheckLabel::minimumSize() const -> Size { auto size = pFont::size(self().font(true), state().text ? state().text : " "); - return {size.width() + 20, size.height() + 4}; + return {size.width() + 20_sx, size.height() + 4_sy}; } auto pCheckLabel::setChecked(bool checked) -> void { diff --git a/hiro/windows/widget/combo-button.cpp b/hiro/windows/widget/combo-button.cpp index 728a1a25..0441540e 100644 --- a/hiro/windows/widget/combo-button.cpp +++ b/hiro/windows/widget/combo-button.cpp @@ -30,7 +30,7 @@ auto pComboButton::minimumSize() const -> Size { for(auto& item : state().items) { width = max(width, pFont::size(hfont, item->state.text).width()); } - return {width + 24, pFont::size(hfont, " ").height() + 10}; + return {width + 24_sx, pFont::size(hfont, " ").height() + 10_sy}; } auto pComboButton::remove(sComboButtonItem item) -> void { diff --git a/hiro/windows/widget/frame.cpp b/hiro/windows/widget/frame.cpp index 14eb17e4..d47de4ca 100644 --- a/hiro/windows/widget/frame.cpp +++ b/hiro/windows/widget/frame.cpp @@ -28,19 +28,19 @@ auto pFrame::setEnabled(bool enabled) -> void { auto pFrame::setGeometry(Geometry geometry) -> void { bool empty = !state().text; auto size = pFont::size(hfont, state().text); + //offsets are based on the default Windows 10 theme pWidget::setGeometry({ geometry.x(), - geometry.y() - (empty ? size.height() / 2 : 0), + geometry.y() - (empty ? 6_sy : 3_sy), geometry.width(), - geometry.height() + (empty ? size.height() / 2 : 0) + geometry.height() + (empty ? 7_sy : 4_sy) }); if(auto& sizable = state().sizable) { - if(empty) size.setHeight(1); sizable->setGeometry({ - geometry.x() + 1, - geometry.y() + size.height(), - geometry.width() - 2, - geometry.height() - (size.height() + 2) + geometry.x() + 5_sx, + geometry.y() + (empty ? 5_sy : size.height()), + geometry.width() - 10_sx, + geometry.height() - (empty ? 10_sy : size.height() + 5_sy) }); } } diff --git a/hiro/windows/widget/horizontal-scroll-bar.cpp b/hiro/windows/widget/horizontal-scroll-bar.cpp index b4200b81..570df8a5 100644 --- a/hiro/windows/widget/horizontal-scroll-bar.cpp +++ b/hiro/windows/widget/horizontal-scroll-bar.cpp @@ -17,7 +17,7 @@ auto pHorizontalScrollBar::destruct() -> void { } auto pHorizontalScrollBar::minimumSize() const -> Size { - return {0, 18}; + return {0, 18_sy}; } auto pHorizontalScrollBar::setLength(unsigned length) -> void { diff --git a/hiro/windows/widget/horizontal-slider.cpp b/hiro/windows/widget/horizontal-slider.cpp index 5c578a43..63cb61ad 100644 --- a/hiro/windows/widget/horizontal-slider.cpp +++ b/hiro/windows/widget/horizontal-slider.cpp @@ -3,10 +3,14 @@ namespace hiro { auto pHorizontalSlider::construct() -> void { - hwnd = CreateWindow( - TRACKBAR_CLASS, L"", WS_CHILD | WS_TABSTOP | TBS_TRANSPARENTBKGND | TBS_NOTICKS | TBS_BOTH | TBS_HORZ, - 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 - ); + //TBS_TRANSPARENTBKGND is needed to render the transparent area of sliders properly inside TabFrame controls + //however, this flag will prevent the slider control from redrawing during vertical window resizes when not inside TabFrame controls + //this is because WM_PRINTCLIENT must be implemented in the parent window for this case + //however, WM_PRINTCLIENT is incompatible with WM_PAINT, which is how most hiro custom widgets are rendered + //as a hacky workaround, TBS_TRANSPARENTBKGND is enabled only when sliders are placed inside of TabFrame controls + auto style = WS_CHILD | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH | TBS_HORZ; + if(self().parentTabFrame(true)) style |= TBS_TRANSPARENTBKGND; + hwnd = CreateWindow(TRACKBAR_CLASS, L"", style, 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); pWidget::construct(); setLength(state().length); setPosition(state().position); @@ -17,7 +21,7 @@ auto pHorizontalSlider::destruct() -> void { } auto pHorizontalSlider::minimumSize() const -> Size { - return {0, 25}; + return {0, 25_sy}; } auto pHorizontalSlider::setLength(unsigned length) -> void { diff --git a/hiro/windows/widget/label.cpp b/hiro/windows/widget/label.cpp index 20967148..b833217c 100644 --- a/hiro/windows/widget/label.cpp +++ b/hiro/windows/widget/label.cpp @@ -2,10 +2,9 @@ namespace hiro { +//warning: WS_CLIPSIBLINGS flag will prevent Label widgets from rendering inside of Frame widgets auto pLabel::construct() -> void { - hwnd = CreateWindow(L"hiroWidget", L"", - WS_CHILD | WS_CLIPSIBLINGS, - 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); + hwnd = CreateWindow(L"hiroWidget", L"", WS_CHILD, 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); pWidget::construct(); setText(state().text); } diff --git a/hiro/windows/widget/radio-label.cpp b/hiro/windows/widget/radio-label.cpp index 2284b3d6..75197152 100644 --- a/hiro/windows/widget/radio-label.cpp +++ b/hiro/windows/widget/radio-label.cpp @@ -19,7 +19,7 @@ auto pRadioLabel::destruct() -> void { auto pRadioLabel::minimumSize() const -> Size { auto size = pFont::size(self().font(true), state().text ? state().text : " "); - return {size.width() + 20, size.height() + 4}; + return {size.width() + 20_sx, size.height() + 4_sy}; } auto pRadioLabel::setChecked() -> void { diff --git a/hiro/windows/widget/table-view.cpp b/hiro/windows/widget/table-view.cpp index d1849fc9..8e127330 100644 --- a/hiro/windows/widget/table-view.cpp +++ b/hiro/windows/widget/table-view.cpp @@ -297,6 +297,12 @@ auto pTableView::windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) - } } + //when hovering over a WC_LISTVIEW item, it will become selected after a very short pause (~200ms usually) + //this is extremely annoying; so intercept the hover event and block it to suppress the LVN_ITEMCHANGING message + if(msg == WM_MOUSEHOVER) { + return false; + } + return pWidget::windowProc(hwnd, msg, wparam, lparam); } diff --git a/hiro/windows/widget/vertical-scroll-bar.cpp b/hiro/windows/widget/vertical-scroll-bar.cpp index d2cfee70..2d9dcd90 100644 --- a/hiro/windows/widget/vertical-scroll-bar.cpp +++ b/hiro/windows/widget/vertical-scroll-bar.cpp @@ -17,7 +17,7 @@ auto pVerticalScrollBar::destruct() -> void { } auto pVerticalScrollBar::minimumSize() const -> Size { - return {18, 0}; + return {18_sx, 0}; } auto pVerticalScrollBar::setLength(unsigned length) -> void { diff --git a/hiro/windows/widget/vertical-slider.cpp b/hiro/windows/widget/vertical-slider.cpp index 980ea3f8..c1b02ff6 100644 --- a/hiro/windows/widget/vertical-slider.cpp +++ b/hiro/windows/widget/vertical-slider.cpp @@ -3,10 +3,14 @@ namespace hiro { auto pVerticalSlider::construct() -> void { - hwnd = CreateWindow( - TRACKBAR_CLASS, L"", WS_CHILD | WS_TABSTOP | TBS_TRANSPARENTBKGND | TBS_NOTICKS | TBS_BOTH | TBS_VERT, - 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 - ); + //TBS_TRANSPARENTBKGND is needed to render the transparent area of sliders properly inside TabFrame controls + //however, this flag will prevent the slider control from redrawing during vertical window resizes when not inside TabFrame controls + //this is because WM_PRINTCLIENT must be implemented in the parent window for this case + //however, WM_PRINTCLIENT is incompatible with WM_PAINT, which is how most hiro custom widgets are rendered + //as a hacky workaround, TBS_TRANSPARENTBKGND is enabled only when sliders are placed inside of TabFrame controls + auto style = WS_CHILD | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH | TBS_VERT; + if(self().parentTabFrame(true)) style |= TBS_TRANSPARENTBKGND; + hwnd = CreateWindow(TRACKBAR_CLASS, L"", style, 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); pWidget::construct(); setLength(state().length); setPosition(state().position); @@ -17,7 +21,7 @@ auto pVerticalSlider::destruct() -> void { } auto pVerticalSlider::minimumSize() const -> Size { - return {25, 0}; + return {25_sx, 0}; } auto pVerticalSlider::setLength(unsigned length) -> void { diff --git a/hiro/windows/window.cpp b/hiro/windows/window.cpp index ebc0cc2c..e56b19b7 100644 --- a/hiro/windows/window.cpp +++ b/hiro/windows/window.cpp @@ -7,9 +7,6 @@ static auto CALLBACK Window_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARA if(auto window = (mWindow*)GetWindowLongPtr(hwnd, GWLP_USERDATA)) { if(auto self = window->self()) { - if(self->_modalityDisabled()) { - return DefWindowProc(hwnd, msg, wparam, lparam); - } if(auto result = self->windowProc(hwnd, msg, wparam, lparam)) { return result(); } @@ -19,8 +16,10 @@ static auto CALLBACK Window_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARA return Shared_windowProc(DefWindowProc, hwnd, msg, wparam, lparam); } -static const uint FixedStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_BORDER | WS_CLIPCHILDREN; -static const uint ResizableStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CLIPCHILDREN; +//warning: do not add WS_CLIPCHILDREN; this will break painting of Frame ("BUTTON" BS_GROUPBOX) controls +static const uint PopupStyle = WS_POPUP; +static const uint FixedStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_BORDER; +static const uint ResizableStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME; uint pWindow::minimumStatusHeight = 0; @@ -72,7 +71,17 @@ auto pWindow::frameMargin() const -> Geometry { uint style = state().fullScreen ? 0 : state().resizable ? ResizableStyle : FixedStyle; bool menuVisible = state().menuBar && state().menuBar->visible(); AdjustWindowRect(&rc, style, menuVisible); - return {abs(rc.left), abs(rc.top), (rc.right - rc.left) - 640, (rc.bottom - rc.top) + _statusHeight() - 480}; + auto& efb = state().fullScreen ? settings.efbPopup : !state().resizable ? settings.efbFixed : settings.efbResizable; + return { + abs(rc.left) - efb.x, + abs(rc.top) - efb.y, + (rc.right - rc.left) - 640 - efb.width, + (rc.bottom - rc.top) + _statusHeight() - 480 - efb.height + }; +} + +auto pWindow::handle() const -> uintptr_t { + return (uintptr_t)hwnd; } auto pWindow::monitor() const -> uint { @@ -146,10 +155,13 @@ auto pWindow::setFullScreen(bool fullScreen) -> void { auto pWindow::setGeometry(Geometry geometry) -> void { auto lock = acquire(); Geometry margin = frameMargin(); + auto& efb = state().fullScreen ? settings.efbPopup : !state().resizable ? settings.efbFixed : settings.efbResizable; SetWindowPos( hwnd, nullptr, - geometry.x() - margin.x(), geometry.y() - margin.y(), - geometry.width() + margin.width(), geometry.height() + margin.height(), + geometry.x() - margin.x() - efb.x, + geometry.y() - margin.y() - efb.y, + geometry.width() + margin.width() + efb.width, + geometry.height() + margin.height() + efb.height, SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED ); if(auto& statusBar = state().statusBar) { @@ -185,9 +197,13 @@ auto pWindow::setModal(bool modality) -> void { if(modality) { modalIncrement(); _modalityUpdate(); - while(state().modal) { + while(!Application::state().quit && state().modal) { + if(Application::state().onMain) { + Application::doMain(); + } else { + usleep(20 * 1000); + } Application::processEvents(); - if(!Application::state().onMain) usleep(20 * 1000); } _modalityUpdate(); } else { @@ -212,6 +228,29 @@ auto pWindow::setVisible(bool visible) -> void { sizable->setGeometry(self().geometry().setPosition()); } if(!visible) self().setModal(false); + + //calculate window extended frame bounds: DwmGetWindowAttributes is only valid after the window is visible + //by then, it's too late to position the window correctly, but we can cache the results here for next time + //because GetWindowRect and DwmGetWindowAttribute returns different unit types, the hiro application *must* be DPI aware + if(visible) { + //in logical units + RECT rc; + GetWindowRect(hwnd, &rc); + + //in physical units + RECT fc; + DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &fc, sizeof(RECT)); + + //convert to offsets useful to hiro + auto& efb = state().fullScreen ? settings.efbPopup : !state().resizable ? settings.efbFixed : settings.efbResizable; + efb.x = fc.left - rc.left; + efb.y = fc.top - rc.top; + efb.width = efb.x + (rc.right - fc.right); + efb.height = efb.y + (rc.bottom - fc.bottom); + + //sanitize inputs: if the bounds are obviously nonsense, give up on trying to compensate for them + if(efb.x > 100 || efb.y > 100 || efb.width > 100 || efb.height > 100) efb = {}; + } } // @@ -230,8 +269,14 @@ auto pWindow::modalDecrement() -> void { auto pWindow::windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> maybe { if(msg == WM_CLOSE || (msg == WM_KEYDOWN && wparam == VK_ESCAPE && state().dismissable)) { - if(state().onClose) self().doClose(); - else self().setVisible(false); + if(state().onClose) { + self().doClose(); + //doClose() may end up destroying the window when terminating the application ... + //forcefully return early in said case, so that the modal check below doesn't access the destroyed pWindow object + if(Application::state().quit) return true; + } else { + self().setVisible(false); + } if(state().modal && !self().visible()) self().setModal(false); return true; } @@ -303,10 +348,11 @@ auto pWindow::_geometry() -> Geometry { GetWindowRect(hwnd, &rc); } - signed x = rc.left + margin.x(); - signed y = rc.top + margin.y(); - signed width = (rc.right - rc.left) - margin.width(); - signed height = (rc.bottom - rc.top) - margin.height(); + auto& efb = state().fullScreen ? settings.efbPopup : !state().resizable ? settings.efbFixed : settings.efbResizable; + auto x = rc.left + margin.x() + efb.x; + auto y = rc.top + margin.y() + efb.y; + auto width = (rc.right - rc.left) - margin.width() - efb.width; + auto height = (rc.bottom - rc.top) - margin.height() - efb.height; return {x, y, width, height}; } diff --git a/hiro/windows/window.hpp b/hiro/windows/window.hpp index 503ec9c7..b1082c86 100644 --- a/hiro/windows/window.hpp +++ b/hiro/windows/window.hpp @@ -14,6 +14,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/nall/GNUmakefile b/nall/GNUmakefile index 86446002..2707a959 100644 --- a/nall/GNUmakefile +++ b/nall/GNUmakefile @@ -139,8 +139,6 @@ ifeq ($(threaded),true) endif # paths -prefix := $(HOME)/.local - ifeq ($(object.path),) object.path := obj endif @@ -227,3 +225,10 @@ streq = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),,1) # function strne(source) strne = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),1,) + +# prefix +ifeq ($(platform),windows) + prefix := $(subst $([space]),\$([space]),$(strip $(call strtr,$(LOCALAPPDATA),\,/))) +else + prefix := $(HOME)/.local +endif diff --git a/nall/algorithm.hpp b/nall/algorithm.hpp index 53fb6eb0..34565f11 100644 --- a/nall/algorithm.hpp +++ b/nall/algorithm.hpp @@ -7,19 +7,19 @@ namespace nall { -template auto min(const T& t, const U& u) -> T { +template constexpr auto min(const T& t, const U& u) -> T { return t < u ? t : (T)u; } -template auto min(const T& t, const U& u, P&&... p) -> T { +template constexpr auto min(const T& t, const U& u, P&&... p) -> T { return t < u ? min(t, forward

(p)...) : min(u, forward

(p)...); } -template auto max(const T& t, const U& u) -> T { +template constexpr auto max(const T& t, const U& u) -> T { return t > u ? t : (T)u; } -template auto max(const T& t, const U& u, P&&... p) -> T { +template constexpr auto max(const T& t, const U& u, P&&... p) -> T { return t > u ? max(t, forward

(p)...) : max(u, forward

(p)...); } diff --git a/nall/arguments.hpp b/nall/arguments.hpp index 1c8b4e71..6fb706d1 100644 --- a/nall/arguments.hpp +++ b/nall/arguments.hpp @@ -137,7 +137,7 @@ inline auto Arguments::take(string_view name) -> bool { inline auto Arguments::take(string_view name, bool& argument) -> bool { for(uint index : range(arguments.size())) { - if(arguments[index].match(name) && arguments.size() >= index + if(arguments[index].match(name) && arguments.size() > index + 1 && (arguments[index + 1] == "true" || arguments[index + 1] == "false")) { arguments.remove(index); argument = arguments.take(index) == "true"; @@ -149,7 +149,7 @@ inline auto Arguments::take(string_view name, bool& argument) -> bool { inline auto Arguments::take(string_view name, string& argument) -> bool { for(uint index : range(arguments.size())) { - if(arguments[index].match(name) && arguments.size() >= index) { + if(arguments[index].match(name) && arguments.size() > index + 1) { arguments.remove(index); argument = arguments.take(index); return true; diff --git a/nall/directory.hpp b/nall/directory.hpp index ebb12078..3abc20db 100644 --- a/nall/directory.hpp +++ b/nall/directory.hpp @@ -21,6 +21,7 @@ namespace nall { struct directory : inode { directory() = delete; + static auto copy(const string& source, const string& target) -> bool; //recursive static auto create(const string& pathname, uint permissions = 0755) -> bool; //recursive static auto remove(const string& pathname) -> bool; //recursive static auto exists(const string& pathname) -> bool; @@ -28,6 +29,7 @@ struct directory : inode { static auto folders(const string& pathname, const string& pattern = "*") -> vector { auto folders = directory::ufolders(pathname, pattern); folders.sort(); + for(auto& folder : folders) folder.append("/"); //must append after sorting return folders; } @@ -39,8 +41,9 @@ struct directory : inode { static auto contents(const string& pathname, const string& pattern = "*") -> vector { auto folders = directory::ufolders(pathname); //pattern search of contents should only filter files - auto files = directory::ufiles(pathname, pattern); folders.sort(); + for(auto& folder : folders) folder.append("/"); //must append after sorting + auto files = directory::ufiles(pathname, pattern); files.sort(); for(auto& file : files) folders.append(file); return folders; @@ -49,6 +52,7 @@ struct directory : inode { static auto ifolders(const string& pathname, const string& pattern = "*") -> vector { auto folders = ufolders(pathname, pattern); folders.isort(); + for(auto& folder : folders) folder.append("/"); //must append after sorting return folders; } @@ -60,8 +64,9 @@ struct directory : inode { static auto icontents(const string& pathname, const string& pattern = "*") -> vector { auto folders = directory::ufolders(pathname); //pattern search of contents should only filter files - auto files = directory::ufiles(pathname, pattern); folders.isort(); + for(auto& folder : folders) folder.append("/"); //must append after sorting + auto files = directory::ufiles(pathname, pattern); files.isort(); for(auto& file : files) folders.append(file); return folders; @@ -151,6 +156,18 @@ private: static auto ufiles(const string& pathname, const string& pattern = "*") -> vector; }; +inline auto directory::copy(const string& source, const string& target) -> bool { + bool result = true; + if(!directory::create(target)) return result = false; + for(auto& name : directory::folders(source)) { + if(!directory::copy({source, name}, {target, name})) result = false; + } + for(auto& name : directory::files(source)) { + if(!file::copy({source, name}, {target, name})) result = false; + } + return result; +} + #if defined(PLATFORM_WINDOWS) inline auto directory::create(const string& pathname, uint permissions) -> bool { string path; @@ -219,7 +236,6 @@ private: } FindClose(handle); } - for(auto& name : list) name.append("/"); //must append after sorting return list; } @@ -305,7 +321,6 @@ private: } closedir(dp); } - for(auto& name : list) name.append("/"); //must append after sorting return list; } diff --git a/nall/http/response.hpp b/nall/http/response.hpp index eee06bc4..a0667bb6 100644 --- a/nall/http/response.hpp +++ b/nall/http/response.hpp @@ -121,7 +121,7 @@ auto Response::body(const function& callback) const } else if(hasData()) { if(!callback(data().data(), data().size())) return false; } else if(hasFile()) { - filemap map(file(), filemap::mode::read); + file_map map(file(), file_map::mode::read); if(!callback(map.data(), map.size())) return false; } else if(hasText()) { if(!callback(text().data(), text().size())) return false; diff --git a/nall/image.hpp b/nall/image.hpp index f42f6a27..3124e73e 100644 --- a/nall/image.hpp +++ b/nall/image.hpp @@ -86,6 +86,7 @@ struct image { inline auto impose(blend mode, uint targetX, uint targetY, image source, uint x, uint y, uint width, uint height) -> void; //utility.hpp + inline auto shrink(uint64_t transparentColor = 0) -> void; inline auto crop(uint x, uint y, uint width, uint height) -> bool; inline auto alphaBlend(uint64_t alphaColor) -> void; inline auto alphaMultiply() -> void; diff --git a/nall/image/blend.hpp b/nall/image/blend.hpp index 13d2ba3c..298d6e17 100644 --- a/nall/image/blend.hpp +++ b/nall/image/blend.hpp @@ -5,7 +5,6 @@ namespace nall { auto image::impose(blend mode, unsigned targetX, unsigned targetY, image source, unsigned sourceX, unsigned sourceY, unsigned sourceWidth, unsigned sourceHeight) -> void { source.transform(_endian, _depth, _alpha.mask(), _red.mask(), _green.mask(), _blue.mask()); - #pragma omp parallel for for(unsigned y = 0; y < sourceHeight; y++) { const uint8_t* sp = source._data + source.pitch() * (sourceY + y) + source.stride() * sourceX; uint8_t* dp = _data + pitch() * (targetY + y) + stride() * targetX; diff --git a/nall/image/scale.hpp b/nall/image/scale.hpp index 451acd3d..3ea63d1f 100644 --- a/nall/image/scale.hpp +++ b/nall/image/scale.hpp @@ -27,7 +27,6 @@ auto image::scaleLinearWidth(unsigned outputWidth) -> void { unsigned outputPitch = outputWidth * stride(); uint64_t xstride = ((uint64_t)(_width - 1) << 32) / max(1u, outputWidth - 1); - #pragma omp parallel for for(unsigned y = 0; y < _height; y++) { uint64_t xfraction = 0; @@ -63,7 +62,6 @@ auto image::scaleLinearHeight(unsigned outputHeight) -> void { uint8_t* outputData = allocate(_width, outputHeight, stride()); uint64_t ystride = ((uint64_t)(_height - 1) << 32) / max(1u, outputHeight - 1); - #pragma omp parallel for for(unsigned x = 0; x < _width; x++) { uint64_t yfraction = 0; @@ -102,7 +100,6 @@ auto image::scaleLinear(unsigned outputWidth, unsigned outputHeight) -> void { uint64_t xstride = ((uint64_t)(_width - 1) << 32) / max(1u, outputWidth - 1); uint64_t ystride = ((uint64_t)(_height - 1) << 32) / max(1u, outputHeight - 1); - #pragma omp parallel for for(unsigned y = 0; y < outputHeight; y++) { uint64_t yfraction = ystride * y; uint64_t xfraction = 0; @@ -147,7 +144,6 @@ auto image::scaleNearest(unsigned outputWidth, unsigned outputHeight) -> void { uint64_t xstride = ((uint64_t)_width << 32) / outputWidth; uint64_t ystride = ((uint64_t)_height << 32) / outputHeight; - #pragma omp parallel for for(unsigned y = 0; y < outputHeight; y++) { uint64_t yfraction = ystride * y; uint64_t xfraction = 0; diff --git a/nall/image/utility.hpp b/nall/image/utility.hpp index 50278c70..7c0ddd45 100644 --- a/nall/image/utility.hpp +++ b/nall/image/utility.hpp @@ -2,6 +2,71 @@ namespace nall { +//scan all four sides of the image for fully transparent pixels, and then crop them +//imagine an icon centered on a transparent background: this function removes the bordering +//this certainly won't win any speed awards, but nall::image is meant to be correct and simple, not fast +auto image::shrink(uint64_t transparentColor) -> void { + //top + { uint padding = 0; + for(uint y : range(_height)) { + const uint8_t* sp = _data + pitch() * y; + bool found = false; + for(uint x : range(_width)) { + if(read(sp) != transparentColor) { found = true; break; } + sp += stride(); + } + if(found) break; + padding++; + } + crop(0, padding, _width, _height - padding); + } + + //bottom + { uint padding = 0; + for(uint y : reverse(range(_height))) { + const uint8_t* sp = _data + pitch() * y; + bool found = false; + for(uint x : range(_width)) { + if(read(sp) != transparentColor) { found = true; break; } + sp += stride(); + } + if(found) break; + padding++; + } + crop(0, 0, _width, _height - padding); + } + + //left + { uint padding = 0; + for(uint x : range(_width)) { + const uint8_t* sp = _data + stride() * x; + bool found = false; + for(uint y : range(_height)) { + if(read(sp) != transparentColor) { found = true; break; } + sp += pitch(); + } + if(found) break; + padding++; + } + crop(padding, 0, _width - padding, _height); + } + + //right + { uint padding = 0; + for(uint x : reverse(range(_width))) { + const uint8_t* sp = _data + stride() * x; + bool found = false; + for(uint y : range(_height)) { + if(read(sp) != transparentColor) { found = true; break; } + sp += pitch(); + } + if(found) break; + padding++; + } + crop(0, 0, _width - padding, _height); + } +} + auto image::crop(unsigned outputX, unsigned outputY, unsigned outputWidth, unsigned outputHeight) -> bool { if(outputX + outputWidth > _width) return false; if(outputY + outputHeight > _height) return false; @@ -9,7 +74,6 @@ auto image::crop(unsigned outputX, unsigned outputY, unsigned outputWidth, unsig uint8_t* outputData = allocate(outputWidth, outputHeight, stride()); unsigned outputPitch = outputWidth * stride(); - #pragma omp parallel for for(unsigned y = 0; y < outputHeight; y++) { const uint8_t* sp = _data + pitch() * (outputY + y) + stride() * outputX; uint8_t* dp = outputData + outputPitch * y; @@ -32,7 +96,6 @@ auto image::alphaBlend(uint64_t alphaColor) -> void { uint64_t alphaG = (alphaColor & _green.mask()) >> _green.shift(); uint64_t alphaB = (alphaColor & _blue.mask() ) >> _blue.shift(); - #pragma omp parallel for for(unsigned y = 0; y < _height; y++) { uint8_t* dp = _data + pitch() * y; for(unsigned x = 0; x < _width; x++) { @@ -58,7 +121,6 @@ auto image::alphaBlend(uint64_t alphaColor) -> void { auto image::alphaMultiply() -> void { unsigned divisor = (1 << _alpha.depth()) - 1; - #pragma omp parallel for for(unsigned y = 0; y < _height; y++) { uint8_t* dp = _data + pitch() * y; for(unsigned x = 0; x < _width; x++) { @@ -89,7 +151,6 @@ auto image::transform(bool outputEndian, unsigned outputDepth, uint64_t outputAl image output(outputEndian, outputDepth, outputAlphaMask, outputRedMask, outputGreenMask, outputBlueMask); output.allocate(_width, _height); - #pragma omp parallel for for(unsigned y = 0; y < _height; y++) { const uint8_t* sp = _data + pitch() * y; uint8_t* dp = output._data + output.pitch() * y; diff --git a/nall/inode.hpp b/nall/inode.hpp index c5c4037b..89bebb24 100644 --- a/nall/inode.hpp +++ b/nall/inode.hpp @@ -31,6 +31,16 @@ struct inode { return access(name, X_OK) == 0; } + static auto hidden(const string& name) -> bool { + #if defined(PLATFORM_WINDOWS) + auto attributes = GetFileAttributes(utf16_t(name)); + return attributes & FILE_ATTRIBUTE_HIDDEN; + #else + //todo: is this really the best way to do this? stat doesn't have S_ISHIDDEN ... + return name.split("/").last().beginsWith("."); + #endif + } + static auto mode(const string& name) -> uint { struct stat data{}; stat(name, &data); diff --git a/nall/instance.hpp b/nall/instance.hpp new file mode 100644 index 00000000..a3cbcedc --- /dev/null +++ b/nall/instance.hpp @@ -0,0 +1,39 @@ +#pragma once + +namespace nall { + +template +struct Instance { + ~Instance() { + destruct(); + } + + auto operator()() -> T& { + return instance.object; + } + + template + auto construct(P&&... p) { + if(constructed) return; + constructed = true; + new((void*)(&instance.object)) T(forward

(p)...); + } + + auto destruct() -> void { + if(!constructed) return; + constructed = false; + instance.object.~T(); + } + +private: + bool constructed = false; + union Union { + Union() {} + ~Union() {} + + T object; + char storage[sizeof(T)]; + } instance; +}; + +} diff --git a/nall/iterator.hpp b/nall/iterator.hpp index 52f8eda1..6c2625e9 100644 --- a/nall/iterator.hpp +++ b/nall/iterator.hpp @@ -3,47 +3,51 @@ namespace nall { template struct iterator { - iterator(T* self, uint64_t offset) : self(self), offset(offset) {} - auto operator*() -> T& { return self[offset]; } - auto operator!=(const iterator& source) const -> bool { return offset != source.offset; } - auto operator++() -> iterator& { return offset++, *this; } + iterator(T* self, uint64_t offset) : _self(self), _offset(offset) {} + auto operator*() -> T& { return _self[_offset]; } + auto operator!=(const iterator& source) const -> bool { return _offset != source._offset; } + auto operator++() -> iterator& { return _offset++, *this; } + auto offset() const -> uint64_t { return _offset; } private: - T* self; - uint64_t offset; + T* _self; + uint64_t _offset; }; template struct iterator_const { - iterator_const(const T* self, uint64_t offset) : self(self), offset(offset) {} - auto operator*() -> const T& { return self[offset]; } - auto operator!=(const iterator_const& source) const -> bool { return offset != source.offset; } - auto operator++() -> iterator_const& { return offset++, *this; } + iterator_const(const T* self, uint64_t offset) : _self(self), _offset(offset) {} + auto operator*() -> const T& { return _self[_offset]; } + auto operator!=(const iterator_const& source) const -> bool { return _offset != source._offset; } + auto operator++() -> iterator_const& { return _offset++, *this; } + auto offset() const -> uint64_t { return _offset; } private: - const T* self; - uint64_t offset; + const T* _self; + uint64_t _offset; }; template struct reverse_iterator { - reverse_iterator(T* self, uint64_t offset) : self(self), offset(offset) {} - auto operator*() -> T& { return self[offset]; } - auto operator!=(const reverse_iterator& source) const -> bool { return offset != source.offset; } - auto operator++() -> reverse_iterator& { return offset--, *this; } + reverse_iterator(T* self, uint64_t offset) : _self(self), _offset(offset) {} + auto operator*() -> T& { return _self[_offset]; } + auto operator!=(const reverse_iterator& source) const -> bool { return _offset != source._offset; } + auto operator++() -> reverse_iterator& { return _offset--, *this; } + auto offset() const -> uint64_t { return _offset; } private: - T* self; - uint64_t offset; + T* _self; + uint64_t _offset; }; template struct reverse_iterator_const { - reverse_iterator_const(const T* self, uint64_t offset) : self(self), offset(offset) {} - auto operator*() -> const T& { return self[offset]; } - auto operator!=(const reverse_iterator_const& source) const -> bool { return offset != source.offset; } - auto operator++() -> reverse_iterator_const& { return offset--, *this; } + reverse_iterator_const(const T* self, uint64_t offset) : _self(self), _offset(offset) {} + auto operator*() -> const T& { return _self[_offset]; } + auto operator!=(const reverse_iterator_const& source) const -> bool { return _offset != source._offset; } + auto operator++() -> reverse_iterator_const& { return _offset--, *this; } + auto offset() const -> uint64_t { return _offset; } private: - const T* self; - uint64_t offset; + const T* _self; + uint64_t _offset; }; //std::rbegin(), std::rend() is missing from GCC 4.9; which I still target @@ -55,13 +59,13 @@ template auto rbegin(T& self) { return self.rbegin(); } template auto rend(T& self) { return self.rend(); } template struct reverse_wrapper { - T self; + auto begin() { return rbegin(_self); } + auto end() { return rend(_self); } - auto begin() { return rbegin(self); } - auto end() { return rend(self); } + auto begin() const { return rbegin(_self); } + auto end() const { return rend(_self); } - auto begin() const { return rbegin(self); } - auto end() const { return rend(self); } + T _self; }; template auto reverse(T& object) -> reverse_wrapper { diff --git a/nall/main.hpp b/nall/main.hpp index c90f7f0f..24642b61 100644 --- a/nall/main.hpp +++ b/nall/main.hpp @@ -12,11 +12,28 @@ namespace nall { CoInitialize(0); WSAData wsaData{0}; WSAStartup(MAKEWORD(2, 2), &wsaData); - _setmode(_fileno(stdin), O_BINARY); + _setmode(_fileno(stdin ), O_BINARY); _setmode(_fileno(stdout), O_BINARY); _setmode(_fileno(stderr), O_BINARY); #endif - return main(move(Arguments{argc, argv})), EXIT_SUCCESS; + + main(move(Arguments{argc, argv})); + + //when a program is running, input on the terminal queues in stdin + //when terminating the program, the shell proceeds to try and execute all stdin data + //this is annoying behavior: this code tries to minimize the impact as much as it can + //we can flush all of stdin up to the last line feed, preventing spurious commands from executing + //however, even with setvbuf(_IONBF), we can't stop the last line from echoing to the terminal + #if !defined(PLATFORM_WINDOWS) + auto flags = fcntl(fileno(stdin), F_GETFL, 0); + fcntl(fileno(stdin), F_SETFL, flags | O_NONBLOCK); //don't allow read() to block when empty + char buffer[4096], data = false; + while(read(fileno(stdin), buffer, sizeof(buffer)) > 0) data = true; + fcntl(fileno(stdin), F_SETFL, flags); //restore original flags for the terminal + if(data) putchar('\r'); //ensures PS1 is printed at the start of the line + #endif + + return EXIT_SUCCESS; } } diff --git a/nall/nall.hpp b/nall/nall.hpp index e3720883..e823d629 100644 --- a/nall/nall.hpp +++ b/nall/nall.hpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -50,7 +51,6 @@ #include #include #include -#include #include #include #include @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include diff --git a/nall/path.hpp b/nall/path.hpp index 9e4369fe..5506f7f0 100644 --- a/nall/path.hpp +++ b/nall/path.hpp @@ -75,10 +75,13 @@ inline auto desktop(string_view name = {}) -> string { return {user(), "Desktop/", name}; } -// /home/username/.local/share/ +//todo: MacOS uses the same location for userData() and userSettings() +//... is there a better option here? + +// /home/username/.config/ // ~/Library/Application Support/ // c:/users/username/appdata/roaming/ -inline auto userData() -> string { +inline auto userSettings() -> string { #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; SHGetFolderPathW(nullptr, CSIDL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path); @@ -87,6 +90,25 @@ inline auto userData() -> string { #elif defined(PLATFORM_MACOS) string result = {Path::user(), "Library/Application Support/"}; #else + string result = {Path::user(), ".config/"}; + #endif + if(!result) result = "."; + if(!result.endsWith("/")) result.append("/"); + return result; +} + +// /home/username/.local/share/ +// ~/Library/Application Support/ +// c:/users/username/appdata/local/ +inline auto userData() -> string { + #if defined(PLATFORM_WINDOWS) + wchar_t path[PATH_MAX] = L""; + SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path); + string result = (const char*)utf8_t(path); + result.transform("\\", "/"); + #elif defined(PLATFORM_MACOS) + string result = {Path::user(), "Library/Application Support/"}; + #else string result = {Path::user(), ".local/share/"}; #endif if(!result) result = "."; diff --git a/nall/platform.hpp b/nall/platform.hpp index d16c4392..7049d496 100644 --- a/nall/platform.hpp +++ b/nall/platform.hpp @@ -120,4 +120,5 @@ namespace Math { #define unreachable throw #endif +#define export $export #define register $register diff --git a/nall/primitives.hpp b/nall/primitives.hpp index a1fc8fd4..bd7a2820 100644 --- a/nall/primitives.hpp +++ b/nall/primitives.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include diff --git a/nall/primitives/boolean.hpp b/nall/primitives/boolean.hpp index 78cbee87..0426a370 100644 --- a/nall/primitives/boolean.hpp +++ b/nall/primitives/boolean.hpp @@ -8,6 +8,7 @@ struct Boolean { inline Boolean() : data(false) {} template inline Boolean(const T& value) : data(value) {} + explicit inline Boolean(const char* value) { data = !strcmp(value, "true"); } inline operator bool() const { return data; } template inline auto& operator=(const T& value) { data = value; return *this; } diff --git a/nall/primitives/integer.hpp b/nall/primitives/integer.hpp index c61c9fe1..cff015da 100644 --- a/nall/primitives/integer.hpp +++ b/nall/primitives/integer.hpp @@ -18,6 +18,7 @@ template struct Integer { inline Integer() : data(0) {} template inline Integer(Integer value) { data = mask(value); } template inline Integer(const T& value) { data = mask(value); } + explicit inline Integer(const char* value) { data = mask(toInteger(value)); } inline operator stype() const { return data; } @@ -43,7 +44,7 @@ template struct Integer { inline auto bit(int index) -> BitRange { return {(utype&)data, index, index}; } inline auto byte(int index) -> BitRange { return {(utype&)data, index * 8 + 0, index * 8 + 7}; } - inline auto bits(int lo, int hi) const -> const BitRange { return {(utype&)*this, lo, lo}; } + inline auto bits(int lo, int hi) const -> const BitRange { return {(utype&)*this, lo, hi}; } inline auto bit(int index) const -> const BitRange { return {(utype&)*this, index, index}; } inline auto byte(int index) const -> const BitRange { return {(utype&)*this, index * 8 + 0, index * 8 + 7}; } diff --git a/nall/primitives/natural.hpp b/nall/primitives/natural.hpp index b609c5e7..0ad4abcf 100644 --- a/nall/primitives/natural.hpp +++ b/nall/primitives/natural.hpp @@ -16,6 +16,7 @@ template struct Natural { inline Natural() : data(0) {} template inline Natural(Natural value) { data = mask(value); } template inline Natural(const T& value) { data = mask(value); } + explicit inline Natural(const char* value) { data = mask(toNatural(value)); } inline operator utype() const { return data; } diff --git a/nall/primitives/real.hpp b/nall/primitives/real.hpp index 1a5fe21e..0145363a 100644 --- a/nall/primitives/real.hpp +++ b/nall/primitives/real.hpp @@ -13,6 +13,7 @@ template struct Real { inline Real() : data(0.0) {} template inline Real(Real value) : data((ftype)value) {} template inline Real(const T& value) : data((ftype)value) {} + explicit inline Real(const char* value) : data((ftype)toReal(value)) {} inline operator ftype() const { return data; } diff --git a/nall/property.hpp b/nall/property.hpp deleted file mode 100644 index 5f6dbe4c..00000000 --- a/nall/property.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -namespace nall { - -template struct property { - property() = default; - property(const T& value) : value(value) {} - - operator T&() { return value; } //direct assignment - auto operator->() -> T* { return &value; } //class-member access - - operator const T&() const { return value; } - auto operator()() const -> const T& { return value; } - auto get() const -> const T& { return value; } - - auto operator=(const T& value) -> T& { return this->value = value; } - auto set(const T& value) -> T& { return this->value = value; } - - T value; -}; - -template struct functional_property { - functional_property( - const function& getter = {}, - const function& setter = {}, - const T& value = {} - ) { - getter ? this->getter = getter : this->getter = [](const T& self) -> R { return self; }; - setter ? this->setter = setter : this->setter = [](T& self, const T& value) -> R { return self = value; }; - this->setter(this->value, value); - } - - operator R() const { return getter(value); } - auto operator()() const -> R { return getter(value); } - auto get() const -> R { return getter(value); } - - auto operator=(const T& value) -> R { return setter(this->value, value); } - auto set(const T& value) -> R { return setter(this->value, value); } - - T value; - function getter; - function setter; -}; - -template struct virtual_property { - virtual_property( - const function& getter = {}, - const function& setter = {}, - const T& value = {} - ) { - this->getter = getter; - this->setter = setter; - if(this->setter) this->setter(value); - } - - operator R() const { return getter(); } - auto operator()() const -> R { return getter(); } - auto get() const -> R { return getter(); } - - auto operator=(const T& value) -> R { return setter(value); } - auto set(const T& value) -> R { return setter(value); } - - function getter; - function setter; -}; - -} diff --git a/nall/set.hpp b/nall/set.hpp index 1376edef..733bf843 100644 --- a/nall/set.hpp +++ b/nall/set.hpp @@ -35,6 +35,7 @@ template struct set { ~set() { reset(); } auto operator=(const set& source) -> set& { + if(this == &source) return *this; reset(); copy(root, source.root); nodes = source.nodes; @@ -42,6 +43,7 @@ template struct set { } auto operator=(set&& source) -> set& { + if(this == &source) return *this; root = source.root; nodes = source.nodes; source.root = nullptr; diff --git a/nall/shared-pointer.hpp b/nall/shared-pointer.hpp index f35c9f2d..d7d1e0d8 100644 --- a/nall/shared-pointer.hpp +++ b/nall/shared-pointer.hpp @@ -21,9 +21,15 @@ struct shared_pointer_manager { template struct shared_pointer; template struct shared_pointer_weak; +template struct shared_pointer_this; +struct shared_pointer_this_base{}; template struct shared_pointer { + template static auto create(P&&... p) { + return shared_pointer{new T{forward

(p)...}}; + } + using type = T; shared_pointer_manager* manager = nullptr; @@ -86,6 +92,9 @@ struct shared_pointer { if(source) { manager = new shared_pointer_manager((void*)source); manager->strong++; + if constexpr(is_base_of_v) { + source->weak = *this; + } } return *this; } @@ -257,11 +266,22 @@ struct shared_pointer_weak { } }; +template +struct shared_pointer_this : shared_pointer_this_base { + shared_pointer_weak weak; + auto shared() -> shared_pointer { return weak; } + auto shared() const -> shared_pointer { return weak; } +}; + +template +auto shared_pointer_make(P&&... p) -> shared_pointer { + return shared_pointer{new T{forward

(p)...}}; +} + template struct shared_pointer_new : shared_pointer { - template - shared_pointer_new(P&&... p) : shared_pointer(new T(forward

(p)...)) { - } + shared_pointer_new(const shared_pointer& source) : shared_pointer(source) {} + template shared_pointer_new(P&&... p) : shared_pointer(new T(forward

(p)...)) {} }; } diff --git a/nall/string.hpp b/nall/string.hpp index dd2d6244..45e900ec 100644 --- a/nall/string.hpp +++ b/nall/string.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -133,6 +134,9 @@ protected: public: inline string(); + inline string(string& source) : string() { operator=(source); } + inline string(const string& source) : string() { operator=(source); } + inline string(string&& source) : string() { operator=(move(source)); } template inline auto get() -> T*; template inline auto data() const -> const T*; template auto size() const -> uint { return _size / sizeof(T); } @@ -172,15 +176,13 @@ public: auto operator> (string_view source) const -> bool { return compare(source) > 0; } auto operator>=(string_view source) const -> bool { return compare(source) >= 0; } - string(const string& source) : string() { operator=(source); } - string(string&& source) : string() { operator=(move(source)); } - auto begin() -> char* { return &get()[0]; } auto end() -> char* { return &get()[size()]; } auto begin() const -> const char* { return &data()[0]; } auto end() const -> const char* { return &data()[size()]; } //atoi.hpp + inline auto boolean() const -> bool; inline auto integer() const -> intmax; inline auto natural() const -> uintmax; inline auto hex() const -> uintmax; @@ -193,11 +195,11 @@ public: template inline auto prepend(const T&, P&&...) -> type&; template inline auto prepend(const nall::string_format&, P&&...) -> type&; inline auto prepend() -> type&; - template inline auto _prepend(const stringify&) -> string&; + template inline auto _prepend(const stringify&) -> type&; template inline auto append(const T&, P&&...) -> type&; template inline auto append(const nall::string_format&, P&&...) -> type&; inline auto append() -> type&; - template inline auto _append(const stringify&) -> string&; + template inline auto _append(const stringify&) -> type&; inline auto length() const -> uint; //find.hpp diff --git a/nall/string/atoi.hpp b/nall/string/atoi.hpp index 23feb32f..11dafbc9 100644 --- a/nall/string/atoi.hpp +++ b/nall/string/atoi.hpp @@ -2,6 +2,10 @@ namespace nall { +auto string::boolean() const -> bool { + return equals("true"); +} + auto string::integer() const -> intmax { return toInteger(data()); } diff --git a/nall/string/markup/find.hpp b/nall/string/markup/find.hpp index 8af6abaf..0901b0d1 100644 --- a/nall/string/markup/find.hpp +++ b/nall/string/markup/find.hpp @@ -5,7 +5,7 @@ namespace nall::Markup { auto ManagedNode::_evaluate(string query) const -> bool { if(!query) return true; - for(auto& rule : query.replace(" ", "").split(",")) { + for(auto& rule : query.split(",")) { enum class Comparator : uint { ID, EQ, NE, LT, LE, GT, GE }; auto comparator = Comparator::ID; if(rule.match("*!=*")) comparator = Comparator::NE; diff --git a/nall/string/markup/node.hpp b/nall/string/markup/node.hpp index d8df5049..4113df81 100644 --- a/nall/string/markup/node.hpp +++ b/nall/string/markup/node.hpp @@ -46,31 +46,39 @@ protected: struct Node { Node() : shared(new ManagedNode) {} Node(const SharedNode& source) : shared(source ? source : new ManagedNode) {} - Node(const string& name) : shared(new ManagedNode(name)) {} - Node(const string& name, const string& value) : shared(new ManagedNode(name, value)) {} + Node(const nall::string& name) : shared(new ManagedNode(name)) {} + Node(const nall::string& name, const nall::string& value) : shared(new ManagedNode(name, value)) {} auto unique() const -> bool { return shared.unique(); } auto clone() const -> Node { return shared->clone(); } auto copy(Node source) -> void { return shared->copy(source.shared); } explicit operator bool() const { return shared->_name || shared->_children; } - auto name() const -> string { return shared->_name; } - auto value() const -> string { return shared->_value; } + auto name() const -> nall::string { return shared->_name; } + auto value() const -> nall::string { return shared->_value; } - auto text() const -> string { return value().strip(); } + auto value(nall::string& target) const -> bool { if(shared) target = string(); return (bool)shared; } + auto value(bool& target) const -> bool { if(shared) target = boolean(); return (bool)shared; } + auto value(int& target) const -> bool { if(shared) target = integer(); return (bool)shared; } + auto value(uint& target) const -> bool { if(shared) target = natural(); return (bool)shared; } + auto value(double& target) const -> bool { if(shared) target = real(); return (bool)shared; } + + auto text() const -> nall::string { return value().strip(); } + auto string() const -> nall::string { return value().strip(); } auto boolean() const -> bool { return text() == "true"; } auto integer() const -> intmax { return text().integer(); } auto natural() const -> uintmax { return text().natural(); } auto real() const -> double { return text().real(); } - auto text(const string& fallback) const -> string { return bool(*this) ? text() : fallback; } + auto text(const nall::string& fallback) const -> nall::string { return bool(*this) ? text() : fallback; } + auto string(const nall::string& fallback) const -> nall::string { return bool(*this) ? string() : fallback; } auto boolean(bool fallback) const -> bool { return bool(*this) ? boolean() : fallback; } auto integer(intmax fallback) const -> intmax { return bool(*this) ? integer() : fallback; } auto natural(uintmax fallback) const -> uintmax { return bool(*this) ? natural() : fallback; } auto real(double fallback) const -> double { return bool(*this) ? real() : fallback; } - auto setName(const string& name = "") -> Node& { shared->_name = name; return *this; } - auto setValue(const string& value = "") -> Node& { shared->_value = value; return *this; } + auto setName(const nall::string& name = "") -> Node& { shared->_name = name; return *this; } + auto setValue(const nall::string& value = "") -> Node& { shared->_value = value; return *this; } auto reset() -> void { shared->_children.reset(); } auto size() const -> uint { return shared->_children.size(); } @@ -102,7 +110,7 @@ struct Node { } auto sort(function comparator = [](auto x, auto y) { - return string::compare(x.shared->_name, y.shared->_name) < 0; + return nall::string::compare(x.shared->_name, y.shared->_name) < 0; }) -> void { nall::sort(shared->_children.data(), shared->_children.size(), [&](auto x, auto y) { return comparator(x, y); //this call converts SharedNode objects to Node objects @@ -114,9 +122,9 @@ struct Node { return shared->_children[position]; } - auto operator[](const string& path) const -> Node { return shared->_lookup(path); } - auto operator()(const string& path) -> Node { return shared->_create(path); } - auto find(const string& query) const -> vector { return shared->_find(query); } + auto operator[](const nall::string& path) const -> Node { return shared->_lookup(path); } + auto operator()(const nall::string& path) -> Node { return shared->_create(path); } + auto find(const nall::string& query) const -> vector { return shared->_find(query); } struct iterator { auto operator*() -> Node { return {source.shared->_children[position]}; } diff --git a/nall/string/transform/dml.hpp b/nall/string/transform/dml.hpp index 42f3215d..aa170c2d 100644 --- a/nall/string/transform/dml.hpp +++ b/nall/string/transform/dml.hpp @@ -213,8 +213,8 @@ inline auto DML::markup(const string& s) -> string { boolean deletion; boolean code; - uint link, linkBase; - uint embed, embedBase; + natural link, linkBase; + natural embed, embedBase; for(uint n = 0; n < s.size();) { char a = s[n]; diff --git a/nall/traits.hpp b/nall/traits.hpp index 0263b86f..e2607687 100644 --- a/nall/traits.hpp +++ b/nall/traits.hpp @@ -21,6 +21,7 @@ namespace nall { using std::initializer_list; using std::is_array; using std::is_base_of; + using std::is_base_of_v; using std::is_function; using std::is_integral; using std::is_integral_v; diff --git a/nall/unique-pointer.hpp b/nall/unique-pointer.hpp index fa6b141f..bd91843c 100644 --- a/nall/unique-pointer.hpp +++ b/nall/unique-pointer.hpp @@ -4,9 +4,13 @@ namespace nall { template struct unique_pointer { + template static auto create(P&&... p) { + return unique_pointer{new T{forward

(p)...}}; + } + using type = T; T* pointer = nullptr; - function void> deleter; + function deleter; unique_pointer(const unique_pointer&) = delete; auto operator=(const unique_pointer&) -> unique_pointer& = delete; diff --git a/nall/variant.hpp b/nall/variant.hpp new file mode 100644 index 00000000..b08e3359 --- /dev/null +++ b/nall/variant.hpp @@ -0,0 +1,148 @@ +#pragma once + +namespace nall { + +template struct variant_size { + static constexpr uint size = max(sizeof(T), variant_size::size); +}; + +template struct variant_size { + static constexpr uint size = sizeof(T); +}; + +template struct variant_index { + static constexpr uint index = is_same_v ? Index : variant_index::index; +}; + +template struct variant_index { + static constexpr uint index = is_same_v ? Index : 0; +}; + +template struct variant_copy { + constexpr variant_copy(uint index, uint assigned, void* target, void* source) { + if(index == assigned) new(target) T(*((T*)source)); + else variant_copy(index + 1, assigned, target, source); + } +}; + +template struct variant_copy { + constexpr variant_copy(uint index, uint assigned, void* target, void* source) { + if(index == assigned) new(target) T(*((T*)source)); + } +}; + +template struct variant_move { + constexpr variant_move(uint index, uint assigned, void* target, void* source) { + if(index == assigned) new(target) T(move(*((T*)source))); + else variant_move(index + 1, assigned, target, source); + } +}; + +template struct variant_move { + constexpr variant_move(uint index, uint assigned, void* target, void* source) { + if(index == assigned) new(target) T(move(*((T*)source))); + } +}; + +template struct variant_destruct { + constexpr variant_destruct(uint index, uint assigned, void* data) { + if(index == assigned) ((T*)data)->~T(); + else variant_destruct(index + 1, assigned, data); + } +}; + +template struct variant_destruct { + constexpr variant_destruct(uint index, uint assigned, void* data) { + if(index == assigned) ((T*)data)->~T(); + } +}; + +template struct variant_equals { + constexpr auto operator()(uint index, uint assigned) const -> bool { + if(index == assigned) return is_same_v; + return variant_equals()(index + 1, assigned); + } +}; + +template struct variant_equals { + constexpr auto operator()(uint index, uint assigned) const -> bool { + if(index == assigned) return is_same_v; + return false; + } +}; + +template struct variant final { //final as destructor is not virtual + variant() : assigned(0) {} + variant(const variant& source) { operator=(source); } + variant(variant&& source) { operator=(move(source)); } + template variant(const T& value) { operator=(value); } + template variant(T&& value) { operator=(move(value)); } + ~variant() { reset(); } + + explicit operator bool() const { return assigned; } + template explicit constexpr operator T&() { return get(); } + template explicit constexpr operator const T&() const { return get(); } + + template constexpr auto is() const -> bool { + return variant_equals()(1, assigned); + } + + template constexpr auto get() -> T& { + static_assert(variant_index<1, T, P...>::index, "type not in variant"); + struct variant_bad_cast{}; + if(!is()) throw variant_bad_cast{}; + return *((T*)data); + } + + template constexpr auto get() const -> const T& { + static_assert(variant_index<1, T, P...>::index, "type not in variant"); + struct variant_bad_cast{}; + if(!is()) throw variant_bad_cast{}; + return *((const T*)data); + } + + template constexpr auto get(const T& fallback) const -> const T& { + if(!is()) return fallback; + return *((const T*)data); + } + + auto reset() -> void { + if(assigned) variant_destruct(1, assigned, (void*)data); + assigned = 0; + } + + auto& operator=(const variant& source) { + reset(); + if(assigned = source.assigned) variant_copy(1, source.assigned, (void*)data, (void*)source.data); + return *this; + } + + auto& operator=(variant&& source) { + reset(); + if(assigned = source.assigned) variant_move(1, source.assigned, (void*)data, (void*)source.data); + source.assigned = 0; + return *this; + } + + template auto& operator=(const T& value) { + static_assert(variant_index<1, T, P...>::index, "type not in variant"); + reset(); + new((void*)&data) T(value); + assigned = variant_index<1, T, P...>::index; + return *this; + } + + template auto& operator=(T&& value) { + static_assert(variant_index<1, T, P...>::index, "type not in variant"); + reset(); + new((void*)&data) T(move(value)); + assigned = variant_index<1, T, P...>::index; + return *this; + } + +private: + alignas(P...) char data[variant_size::size]; + uint assigned; +}; + +} diff --git a/nall/vector.hpp b/nall/vector.hpp index 7e557d6a..fda0e4f2 100644 --- a/nall/vector.hpp +++ b/nall/vector.hpp @@ -16,11 +16,6 @@ namespace nall { -template struct vector_iterator; -template struct vector_iterator_const; -template struct vector_reverse_iterator; -template struct vector_reverse_iterator_const; - template struct vector_base { using type = vector_base; @@ -100,6 +95,19 @@ struct vector_base { auto removeRight(uint64_t length = 1) -> void; auto removeLast(uint64_t length = 1) -> void { return removeRight(length); } auto remove(uint64_t offset, uint64_t length = 1) -> void; + struct RemoveWhere { + RemoveWhere(type& source) : self(source) {} + auto operator==(const T& value) -> type&; + auto operator!=(const T& value) -> type&; + auto operator< (const T& value) -> type&; + auto operator<=(const T& value) -> type&; + auto operator> (const T& value) -> type&; + auto operator>=(const T& value) -> type&; + private: + type& self; + template auto remove(const T& value) -> type&; + }; + auto removeWhere() -> RemoveWhere { return RemoveWhere{*this}; } auto takeLeft() -> T; auto takeFirst() -> T { return move(takeLeft()); } @@ -127,6 +135,32 @@ struct vector_base { auto find(const function& comparator) -> maybe; auto find(const T& value) const -> maybe; auto findSorted(const T& value) const -> maybe; + struct FindWhere { + FindWhere(type& source) : self(source) {} + auto operator==(const T& value) -> vector_base>; + auto operator!=(const T& value) -> vector_base>; + auto operator< (const T& value) -> vector_base>; + auto operator<=(const T& value) -> vector_base>; + auto operator> (const T& value) -> vector_base>; + auto operator>=(const T& value) -> vector_base>; + private: + type& self; + template auto find(const T& value) -> vector_base>; + }; + auto findWhere() { return FindWhere{*this}; } + struct FindWhereConst { + FindWhereConst(const type& source) : self(source) {} + auto operator==(const T& value) const -> vector_base>; + auto operator!=(const T& value) const -> vector_base>; + auto operator< (const T& value) const -> vector_base>; + auto operator<=(const T& value) const -> vector_base>; + auto operator> (const T& value) const -> vector_base>; + auto operator>=(const T& value) const -> vector_base>; + private: + const type& self; + template auto find(const T& value) const -> vector_base>; + }; + auto findWhere() const { return FindWhereConst{*this}; } auto foreach(const function& callback) -> void; auto foreach(const function& callback) -> void; @@ -137,6 +171,10 @@ protected: uint64_t _right = 0; //number of allocated elements free on the right of pool }; +template auto removeWhere(vector_base& source) { return source.removeWhere(); } +template auto findWhere(vector_base& source) { return source.findWhere(); } +template auto findWhere(const vector_base& source) { return source.findWhere(); } + } #define vector vector_base diff --git a/nall/vector/iterator.hpp b/nall/vector/iterator.hpp index 6c8aee70..67afb01a 100644 --- a/nall/vector/iterator.hpp +++ b/nall/vector/iterator.hpp @@ -6,6 +6,7 @@ template struct vector_iterator { vector_iterator(vector& self, uint64_t offset) : self(self), offset(offset) {} auto operator*() -> T& { return self.operator[](offset); } + auto operator->() -> T* { return self.operator[](offset); } auto operator!=(const vector_iterator& source) const -> bool { return offset != source.offset; } auto operator++() -> vector_iterator& { return offset++, *this; } @@ -18,6 +19,7 @@ template struct vector_iterator_const { vector_iterator_const(const vector& self, uint64_t offset) : self(self), offset(offset) {} auto operator*() -> const T& { return self.operator[](offset); } + auto operator->() -> T* { return self.operator[](offset); } auto operator!=(const vector_iterator_const& source) const -> bool { return offset != source.offset; } auto operator++() -> vector_iterator_const& { return offset++, *this; } @@ -30,6 +32,7 @@ template struct vector_reverse_iterator { vector_reverse_iterator(vector& self, uint64_t offset) : self(self), offset(offset) {} auto operator*() -> T& { return self.operator[](offset); } + auto operator->() -> T* { return self.operator[](offset); } auto operator!=(const vector_reverse_iterator& source) const -> bool { return offset != source.offset; } auto operator++() -> vector_reverse_iterator& { return offset--, *this; } @@ -42,6 +45,7 @@ template struct vector_reverse_iterator_const { vector_reverse_iterator_const(const vector& self, uint64_t offset) : self(self), offset(offset) {} auto operator*() -> const T& { return self.operator[](offset); } + auto operator->() -> T* { return self.operator[](offset); } auto operator!=(const vector_reverse_iterator_const& source) const -> bool { return offset != source.offset; } auto operator++() -> vector_reverse_iterator_const& { return offset--, *this; } diff --git a/nall/vector/modify.hpp b/nall/vector/modify.hpp index 4c034205..9e5a6324 100644 --- a/nall/vector/modify.hpp +++ b/nall/vector/modify.hpp @@ -101,6 +101,25 @@ template auto vector::remove(uint64_t offset, uint64_t length) -> _size -= length; } +template auto vector::RemoveWhere::operator==(const T& value) -> type& { return remove>(value); } +template auto vector::RemoveWhere::operator!=(const T& value) -> type& { return remove>(value); } +template auto vector::RemoveWhere::operator< (const T& value) -> type& { return remove>(value); } +template auto vector::RemoveWhere::operator<=(const T& value) -> type& { return remove>(value); } +template auto vector::RemoveWhere::operator> (const T& value) -> type& { return remove>(value); } +template auto vector::RemoveWhere::operator>=(const T& value) -> type& { return remove>(value); } + +template template auto vector::RemoveWhere::remove(const T& value) -> type& { + auto source = self.begin(); + auto target = self.begin(); + while(source != self.end()) { + if(source != target) *target = move(*source); + if(!Compare()(*target, value)) ++target; + ++source; + } + self.resize(target.offset()); + return self; +} + // template auto vector::takeLeft() -> T { diff --git a/nall/vector/utility.hpp b/nall/vector/utility.hpp index 635f52ee..0e6ce87b 100644 --- a/nall/vector/utility.hpp +++ b/nall/vector/utility.hpp @@ -36,6 +36,36 @@ template auto vector::findSorted(const T& value) const -> maybe auto vector::FindWhere::operator==(const T& value) -> vector> { return move(find>(value)); } +template auto vector::FindWhere::operator!=(const T& value) -> vector> { return move(find>(value)); } +template auto vector::FindWhere::operator< (const T& value) -> vector> { return move(find>(value)); } +template auto vector::FindWhere::operator<=(const T& value) -> vector> { return move(find>(value)); } +template auto vector::FindWhere::operator> (const T& value) -> vector> { return move(find>(value)); } +template auto vector::FindWhere::operator>=(const T& value) -> vector> { return move(find>(value)); } + +template template auto vector::FindWhere::find(const T& value) -> vector> { + vector> found; + for(auto iterator = self.begin(); iterator != self.end(); ++iterator) { + if(Compare()(*iterator, value)) found.append(iterator); + } + return move(found); +} + +template auto vector::FindWhereConst::operator==(const T& value) const -> vector> { return move(find>(value)); } +template auto vector::FindWhereConst::operator!=(const T& value) const -> vector> { return move(find>(value)); } +template auto vector::FindWhereConst::operator< (const T& value) const -> vector> { return move(find>(value)); } +template auto vector::FindWhereConst::operator<=(const T& value) const -> vector> { return move(find>(value)); } +template auto vector::FindWhereConst::operator> (const T& value) const -> vector> { return move(find>(value)); } +template auto vector::FindWhereConst::operator>=(const T& value) const -> vector> { return move(find>(value)); } + +template template auto vector::FindWhereConst::find(const T& value) const -> vector> { + vector> found; + for(auto iterator = self.begin(); iterator != self.end(); ++iterator) { + if(Compare()(*iterator, value)) found.append(iterator); + } + return move(found); +} + template auto vector::foreach(const function& callback) -> void { for(uint64_t n : range(size())) callback(_pool[n]); } diff --git a/nall/vfs/memory/file.hpp b/nall/vfs/memory/file.hpp index e55584a8..0c864e8f 100644 --- a/nall/vfs/memory/file.hpp +++ b/nall/vfs/memory/file.hpp @@ -1,5 +1,8 @@ #pragma once +#include +#include + namespace nall::vfs::memory { struct file : vfs::file { @@ -11,6 +14,22 @@ struct file : vfs::file { return instance; } + static auto open(string location, bool decompress = false) -> shared_pointer { + auto instance = shared_pointer{new file}; + if(decompress && location.iendsWith(".zip")) { + Decode::ZIP archive; + if(archive.open(location) && archive.file.size() == 1) { + auto memory = archive.extract(archive.file.first()); + instance->_open(memory.data(), memory.size()); + return instance; + } + } + auto memory = nall::file::read(location); + instance->_open(memory.data(), memory.size()); + return instance; + } + + auto data() const -> const uint8_t* { return _data; } auto size() const -> uintmax override { return _size; } auto offset() const -> uintmax override { return _offset; } diff --git a/nall/xorg/guard.hpp b/nall/xorg/guard.hpp index a58eb04e..38111936 100644 --- a/nall/xorg/guard.hpp +++ b/nall/xorg/guard.hpp @@ -6,6 +6,8 @@ #define Display XlibDisplay #define Screen XlibScreen #define Window XlibWindow +#define Above XlibAbove +#define Below XlibBelow #else #undef NALL_XORG_GUARD_HPP @@ -15,6 +17,8 @@ #undef Display #undef Screen #undef Window +#undef Above +#undef Below #ifndef NALL_XORG_GUARD_CONSTANTS #define NALL_XORG_GUARD_CONSTANTS diff --git a/ruby/GNUmakefile b/ruby/GNUmakefile index c7531aa2..01d5ce64 100644 --- a/ruby/GNUmakefile +++ b/ruby/GNUmakefile @@ -1,7 +1,7 @@ ifeq ($(ruby),) ifeq ($(platform),windows) ruby += video.wgl video.direct3d video.directdraw video.gdi - ruby += audio.asio audio.wasapi audio.xaudio2 audio.directsound + ruby += audio.asio audio.wasapi audio.xaudio2 audio.directsound audio.waveout ruby += input.windows else ifeq ($(platform),macos) ruby += video.cgl @@ -42,6 +42,7 @@ ruby.options += $(if $(findstring audio.directsound,$(ruby)),-ldsound -luuid) ruby.options += $(if $(findstring audio.pulseaudio,$(ruby)),-lpulse) ruby.options += $(if $(findstring audio.pulseaudiosimple,$(ruby)),-lpulse-simple) ruby.options += $(if $(findstring audio.wasapi,$(ruby)),-lavrt -luuid) +ruby.options += $(if $(findstring audio.waveout,$(ruby)),-lwinmm) ruby.options += $(if $(findstring audio.xaudio2,$(ruby)),-lole32) ruby.options += $(if $(findstring input.sdl,$(ruby)),$(shell sdl2-config --libs)) diff --git a/ruby/audio/audio.cpp b/ruby/audio/audio.cpp index c5f4a749..5364c0b9 100644 --- a/ruby/audio/audio.cpp +++ b/ruby/audio/audio.cpp @@ -34,6 +34,10 @@ #include #endif +#if defined(AUDIO_WAVEOUT) + #include +#endif + #if defined(AUDIO_XAUDIO2) #include #endif @@ -174,6 +178,10 @@ auto Audio::create(string driver) -> bool { if(driver == "WASAPI") self.instance = new AudioWASAPI(*this); #endif + #if defined(AUDIO_WAVEOUT) + if(driver == "waveOut") self.instance = new AudioWaveOut(*this); + #endif + #if defined(AUDIO_XAUDIO2) if(driver == "XAudio 2.1") self.instance = new AudioXAudio2(*this); #endif @@ -202,6 +210,10 @@ auto Audio::hasDrivers() -> vector { "DirectSound 7.0", #endif + #if defined(AUDIO_WAVEOUT) + "waveOut", + #endif + #if defined(AUDIO_ALSA) "ALSA", #endif @@ -238,6 +250,8 @@ auto Audio::optimalDriver() -> string { return "XAudio 2.1"; #elif defined(AUDIO_DIRECTSOUND) return "DirectSound 7.0"; + #elif defined(AUDIO_WAVEOUT) + return "waveOut"; #elif defined(AUDIO_ALSA) return "ALSA"; #elif defined(AUDIO_OSS) @@ -256,7 +270,9 @@ auto Audio::optimalDriver() -> string { } auto Audio::safestDriver() -> string { - #if defined(AUDIO_DIRECTSOUND) + #if defined(AUDIO_WAVEOUT) + return "waveOut"; + #elif defined(AUDIO_DIRECTSOUND) return "DirectSound 7.0"; #elif defined(AUDIO_WASAPI) return "WASAPI"; diff --git a/ruby/audio/waveout.cpp b/ruby/audio/waveout.cpp new file mode 100644 index 00000000..4041190d --- /dev/null +++ b/ruby/audio/waveout.cpp @@ -0,0 +1,134 @@ +#include + +auto CALLBACK waveOutCallback(HWAVEOUT handle, UINT message, DWORD_PTR userData, DWORD_PTR, DWORD_PTR) -> void; + +struct AudioWaveOut : AudioDriver { + AudioWaveOut& self = *this; + AudioWaveOut(Audio& super) : AudioDriver(super) {} + ~AudioWaveOut() { terminate(); } + + auto create() -> bool override { + super.setChannels(2); + super.setFrequency(44100); + super.setLatency(0); + return initialize(); + } + + auto driver() -> string override { return "waveOut"; } + auto ready() -> bool override { return true; } + + auto hasDevices() -> vector override { + vector devices{"Default"}; + for(uint index : range(waveOutGetNumDevs())) { + WAVEOUTCAPS caps{}; + if(waveOutGetDevCaps(index, &caps, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR) { + devices.append((const char*)utf8_t(caps.szPname)); + } + } + return devices; + } + + auto hasBlocking() -> bool override { return true; } + auto hasDynamic() -> bool override { return true; } + auto hasFrequencies() -> vector override { return {44100}; } + auto hasLatencies() -> vector override { return {0}; } + + auto setBlocking(bool blocking) -> bool override { return true; } + auto setDynamic(bool dynamic) -> bool override { initialize(); return true; } + + auto clear() -> void override { + for(auto& header : headers) { + memory::fill(header.lpData, frameCount * 4); + } + } + + auto level() -> double override { + return (double)((blockQueue * frameCount) + frameIndex) / (blockCount * frameCount); + } + + auto output(const double samples[]) -> void override { + uint16_t lsample = sclamp<16>(samples[0] * 32767.0); + uint16_t rsample = sclamp<16>(samples[1] * 32767.0); + + auto block = (uint32_t*)headers[blockIndex].lpData; + block[frameIndex] = lsample << 0 | rsample << 16; + + if(++frameIndex >= frameCount) { + frameIndex = 0; + if(self.dynamic) { + while(waveOutWrite(handle, &headers[blockIndex], sizeof(WAVEHDR)) == WAVERR_STILLPLAYING); + InterlockedIncrement(&blockQueue); + } else while(true) { + auto result = waveOutWrite(handle, &headers[blockIndex], sizeof(WAVEHDR)); + if(!self.blocking || result != WAVERR_STILLPLAYING) break; + InterlockedIncrement(&blockQueue); + } + if(++blockIndex >= blockCount) { + blockIndex = 0; + } + } + } + +private: + auto initialize() -> bool { + terminate(); + + auto deviceIndex = hasDevices().find(self.device); + if(!deviceIndex) deviceIndex = 0; + + WAVEFORMATEX format{}; + format.wFormatTag = WAVE_FORMAT_PCM; + format.nChannels = 2; + format.nSamplesPerSec = 44100; + format.nBlockAlign = 4; + format.wBitsPerSample = 16; + format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; + format.cbSize = 0; //not sizeof(WAVEFORMAT); size of extra information after WAVEFORMATEX + //-1 = default; 0+ = specific device; subtract -1 as hasDevices() includes "Default" entry + waveOutOpen(&handle, (int)*deviceIndex - 1, &format, (DWORD_PTR)waveOutCallback, (DWORD_PTR)this, CALLBACK_FUNCTION); + + headers.resize(blockCount); + for(auto& header : headers) { + memory::fill(&header, sizeof(WAVEHDR)); + header.lpData = (LPSTR)LocalAlloc(LMEM_FIXED, frameCount * 4); + header.dwBufferLength = frameCount * 4; + waveOutPrepareHeader(handle, &header, sizeof(WAVEHDR)); + } + + frameIndex = 0; + blockIndex = 0; + blockQueue = 0; + + waveOutSetVolume(handle, 0xffff'ffff); //100% volume (65535 left, 65535 right) + waveOutRestart(handle); + return true; + } + + auto terminate() -> void { + if(!handle) return; + waveOutPause(handle); + waveOutReset(handle); + for(auto& header : headers) { + waveOutUnprepareHeader(handle, &header, sizeof(WAVEHDR)); + LocalFree(header.lpData); + } + waveOutClose(handle); + handle = nullptr; + headers.reset(); + } + + HWAVEOUT handle = nullptr; + vector headers; + const uint frameCount = 512; + const uint blockCount = 32; + uint frameIndex = 0; + uint blockIndex = 0; + +public: + LONG blockQueue = 0; +}; + +auto CALLBACK waveOutCallback(HWAVEOUT handle, UINT message, DWORD_PTR userData, DWORD_PTR, DWORD_PTR) -> void { + auto instance = (AudioWaveOut*)userData; + if(instance->blockQueue > 0) InterlockedDecrement(&instance->blockQueue); +} diff --git a/ruby/audio/xaudio2.cpp b/ruby/audio/xaudio2.cpp index 74d36847..614ae5eb 100644 --- a/ruby/audio/xaudio2.cpp +++ b/ruby/audio/xaudio2.cpp @@ -20,7 +20,7 @@ struct AudioXAudio2 : AudioDriver, public IXAudio2VoiceCallback { auto ready() -> bool override { return self.isReady; } auto hasBlocking() -> bool override { return true; } - auto hasDynamic() -> bool override { return false; } + auto hasDynamic() -> bool override { return true; } auto hasDevices() -> vector override { vector devices; @@ -52,13 +52,13 @@ struct AudioXAudio2 : AudioDriver, public IXAudio2VoiceCallback { self.sourceVoice->Start(0); } -/*auto level() -> double override { + auto level() -> double override { XAUDIO2_VOICE_STATE state{}; self.sourceVoice->GetState(&state); - uint level = state.BuffersQueued * self.period - state.SamplesPlayed % self.period; + uint level = state.BuffersQueued * self.period + buffers[self.index].size() - state.SamplesPlayed % self.period; uint limit = Buffers * self.period; - return (double)(limit - level) / limit; - }*/ + return (double)level / limit; + } auto output(const double samples[]) -> void override { uint32_t frame = 0; diff --git a/ruby/input/joypad/xinput.cpp b/ruby/input/joypad/xinput.cpp index dccc0343..126faffd 100644 --- a/ruby/input/joypad/xinput.cpp +++ b/ruby/input/joypad/xinput.cpp @@ -104,6 +104,7 @@ struct InputJoypadXInput { auto initialize() -> bool { if(!libxinput) libxinput = LoadLibraryA("xinput1_3.dll"); + if(!libxinput) libxinput = LoadLibraryA("xinput1_4.dll"); if(!libxinput) return false; //XInputGetStateEx is an undocumented function; but is required to get the state of the guide button