Update to bsnes v107.1 release.

byuu says:

Don't let the point release fool you, there are many significant changes in this
release. I will be keeping bsnes releases using a point system until the new
higan release is ready.

Changelog:

  - GUI: added high DPI support
  - GUI: fixed the state manager image preview
  - Windows: added a new waveOut driver with support for dynamic rate control
  - Windows: corrected the XAudio 2.1 dynamic rate control support [BearOso]
  - Windows: corrected the Direct3D 9.0 fullscreen exclusive window centering
  - Windows: fixed XInput controller support on Windows 10
  - SFC: added high-level emulation for the DSP1, DSP2, DSP4, ST010, and Cx4
    coprocessors
  - SFC: fixed a slight rendering glitch in the intro to Megalomania

If the coprocessor firmware is missing, bsnes will fallback on HLE where it is
supported, which is everything other than SD Gundam GX and the two Hayazashi
Nidan Morita Shougi games.

The Windows dynamic rate control works best with Direct3D in fullscreen
exclusive mode. I recommend the waveOut driver over the XAudio 2.1 driver, as it
is not possible to target a single XAudio2 version on all Windows OS releases.
The waveOut driver should work everywhere out of the box.

Note that with DRC, the synchronization source is your monitor, so you will
want to be running at 60hz (NTSC) or 50hz (PAL). If you have an adaptive sync
monitor, you should instead use the WASAPI (exclusive) or ASIO audio driver.
This commit is contained in:
Tim Allen 2019-04-09 11:16:30 +10:00
parent 7786206a4f
commit 4d7bb510f2
223 changed files with 9895 additions and 3116 deletions

View File

@ -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

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="genius" version="1.0.0.0" processorArchitecture="*"/>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
</dependentAssembly>
</dependency>
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>false</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>

View File

@ -1,8 +0,0 @@
[Desktop Entry]
Name=genius
Comment=Emulator
Exec=genius
Icon=genius
Terminal=false
Type=Application
Categories=Game;Emulator;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>org.byuu.genius</string>
<key>CFBundleDisplayName</key>
<string>genius</string>
<key>CFBundleExecutable</key>
<string>genius</string>
<key>CFBundleIconFile</key>
<string>genius.icns</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<true/>
</dict>
</plist>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,2 +0,0 @@
1 24 "genius.Manifest"
2 ICON DISCARDABLE "genius.ico"

View File

@ -1,80 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="256mm"
height="256mm"
viewBox="0 0 256 256"
version="1.1"
id="svg8"
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
sodipodi:docname="icarus.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.5"
inkscape:cx="62.34093"
inkscape:cy="560"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1028"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-41)">
<circle
id="path10"
cx="128.0"
cy="169.0"
r="120.0"
style="stroke-width:0.25;fill:#b8b8ff;fill-opacity:1" />
<g
aria-label="氷"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:260.07336426px;line-height:1.25;font-family:KaiTi;-inkscape-font-specification:KaiTi;letter-spacing:0px;word-spacing:0px;fill:#4050e0;fill-opacity:1;stroke:#4050e0;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="text818">
<path
style="fill:#4050e0;fill-opacity:1;stroke:#4050e0;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 130.80961,146.24049 q 5.07956,5.07956 14.22276,15.23868 14.22277,-13.20685 25.39779,-27.42962 12.19094,-15.23867 11.17503,-24.38187 0,-10.15912 10.15912,-4.06365 10.15911,6.09547 14.22276,12.19094 4.06364,5.07956 -2.03182,7.11138 -6.09547,1.01591 -22.35006,14.22276 -15.23867,12.19094 -32.50917,26.4137 13.20685,11.17503 23.36597,20.31823 11.17502,9.14321 24.38187,18.28641 14.22277,8.1273 27.42962,14.22276 14.22276,5.07956 21.33414,7.11139 7.11138,2.03182 -3.04773,5.07955 -9.14321,2.03183 -23.36597,3.04774 -14.22276,0 -21.33414,-2.03182 -6.09547,-3.04774 -11.17503,-8.1273 -4.06365,-5.07956 -24.38188,-27.42961 -19.30232,-23.36597 -31.49326,-39.62055 1.01591,41.65237 2.03182,64.00243 2.03183,22.35005 0,34.54099 -2.03182,12.19094 -8.12729,19.30232 -5.07956,7.11138 -8.12729,4.06365 -2.03182,-2.03183 -7.11138,-11.17503 -5.07956,-8.12729 -16.254587,-15.23867 -11.175027,-8.1273 1.015912,-5.07956 12.190935,2.03182 16.254585,2.03182 4.06365,-1.01591 6.09547,-7.11138 2.03182,-7.11138 2.03182,-46.73193 0,-40.63646 -1.01591,-77.20928 -1.01591,-37.58873 -6.09547,-45.716022 -5.07956,-9.143205 4.06365,-7.111382 10.15911,1.015912 16.25458,5.079558 7.11138,3.047735 4.06365,9.143205 -3.04774,5.079557 -4.06365,15.238673 -1.01591,10.159118 -1.01591,51.811488 z"
id="path822" />
<path
style="fill:#4050e0;fill-opacity:1;stroke:#4050e0;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 88.141325,149.28823 q 5.079558,1.01591 14.222765,7.11138 9.1432,6.09547 4.06364,10.15911 -5.07955,4.06365 -12.190935,18.28641 -6.09547,14.22276 -14.222763,25.39779 -8.127292,10.15912 -19.30232,19.30232 -11.175027,8.12729 -21.334143,12.19094 -9.143204,3.04774 -16.254585,5.07956 -6.095469,1.01591 5.079558,-6.09547 11.175027,-7.11138 21.334143,-17.2705 11.175027,-10.15911 18.286408,-21.33414 8.127293,-12.19094 11.175028,-20.31823 3.047735,-9.14321 3.047735,-14.22276 1.015911,-5.07956 -3.047735,-5.07956 -4.063646,0 -15.238674,4.06364 -10.159116,4.06365 -15.238674,6.09547 -4.063646,2.03183 -13.20685,-3.04773 -8.127293,-6.09547 2.031823,-6.09547 11.175027,-1.01591 24.381878,-5.07956 14.222762,-5.07956 17.270497,-7.11138 4.063646,-3.04773 9.143204,-2.03182 z"
id="path820" />
<path
style="fill:#4050e0;fill-opacity:1;stroke:#4050e0;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 63.759447,101.54038 q 9.143204,1.01591 18.286409,5.07956 9.143204,4.06365 11.175027,11.17503 2.031823,7.11138 -1.015912,11.17503 -3.047734,4.06364 -15.238673,-4.06365 -11.175028,-9.1432 -16.254586,-16.25459 -5.079557,-8.12729 3.047735,-7.11138 z"
id="path815" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -1,629 +0,0 @@
#include <nall/nall.hpp>
using namespace nall;
#include <hiro/hiro.hpp>
using namespace hiro;
#include "genius.hpp"
unique_pointer<ListWindow> listWindow;
unique_pointer<GameWindow> gameWindow;
unique_pointer<MemoryWindow> memoryWindow;
unique_pointer<OscillatorWindow> 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 <nall/main.hpp>
auto nall::main(Arguments) -> void {
new ListWindow;
new GameWindow;
new MemoryWindow;
new OscillatorWindow;
listWindow->setVisible();
Application::run();
}

View File

@ -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<Component> 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<Game> 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{&noteLayout, Size{50, 0}};
LineEdit noteEdit{&noteLayout, 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}};
};

View File

@ -1,2 +0,0 @@
*.o
*.d

View File

@ -1 +0,0 @@
genius

View File

@ -31,7 +31,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; static const string Name = "higan";
static const string Version = "107"; static const string Version = "107.1";
static const string Author = "byuu"; static const string Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "https://byuu.org/"; static const string Website = "https://byuu.org/";

View File

@ -10,6 +10,7 @@ objects += sfc-armdsp sfc-hitachidsp sfc-necdsp
objects += sfc-epsonrtc sfc-sharprtc objects += sfc-epsonrtc sfc-sharprtc
objects += sfc-spc7110 sfc-sdd1 objects += sfc-spc7110 sfc-sdd1
objects += sfc-obc1 sfc-msu1 objects += sfc-obc1 sfc-msu1
objects += sfc-cx4 sfc-dsp1 sfc-dsp2 sfc-dsp4 sfc-st0010
objects += sfc-bsmemory sfc-sufamiturbo objects += sfc-bsmemory sfc-sufamiturbo
obj/sfc-interface.o: sfc/interface/interface.cpp 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-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-bsmemory.o: sfc/slot/bsmemory/bsmemory.cpp
obj/sfc-sufamiturbo.o: sfc/slot/sufamiturbo/sufamiturbo.cpp obj/sfc-sufamiturbo.o: sfc/slot/sufamiturbo/sufamiturbo.cpp

View File

@ -38,6 +38,12 @@ struct Cartridge {
boolean OBC1; boolean OBC1;
boolean MSU1; boolean MSU1;
boolean Cx4;
boolean DSP1;
boolean DSP2;
boolean DSP4;
boolean ST0010;
boolean GameBoySlot; boolean GameBoySlot;
boolean BSMemorySlot; boolean BSMemorySlot;
boolean SufamiTurboSlotA; boolean SufamiTurboSlotA;

View File

@ -406,8 +406,6 @@ auto Cartridge::loadARMDSP(Markup::Node node) -> void {
//processor(architecture=HG51BS169) //processor(architecture=HG51BS169)
auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void { auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void {
has.HitachiDSP = true;
for(auto& word : hitachidsp.dataROM) word = 0x000000; for(auto& word : hitachidsp.dataROM) word = 0x000000;
for(auto& word : hitachidsp.dataRAM) word = 0x00; 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.Roms = roms; //1 or 2
hitachidsp.Mapping = 0; //0 or 1 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)"]) { if(auto memory = node["memory(type=ROM,content=Program)"]) {
loadMemory(hitachidsp.rom, memory, File::Required); loadMemory(hitachidsp.rom, memory, File::Required);
for(auto map : memory.find("map")) { 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 memory = node["memory(type=ROM,content=Data,architecture=HG51BS169)"]) {
if(auto file = game.memory(memory)) { 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, File::Required)) {
@ -455,13 +462,16 @@ auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void {
loadMap(map, {&HitachiDSP::readDRAM, &hitachidsp}, {&HitachiDSP::writeDRAM, &hitachidsp}); 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) //processor(architecture=uPD7725)
auto Cartridge::loaduPD7725(Markup::Node node) -> void { 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.programROM) word = 0x000000;
for(auto& word : necdsp.dataROM) word = 0x0000; for(auto& word : necdsp.dataROM) word = 0x0000;
for(auto& word : necdsp.dataRAM) 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; necdsp.Frequency = 7'600'000;
} }
for(auto map : node.find("map")) { bool failed = false;
loadMap(map, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
}
if(auto memory = node["memory(type=ROM,content=Program,architecture=uPD7725)"]) { if(auto memory = node["memory(type=ROM,content=Program,architecture=uPD7725)"]) {
if(auto file = game.memory(memory)) { 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); 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 memory = node["memory(type=ROM,content=Data,architecture=uPD7725)"]) {
if(auto file = game.memory(memory)) { 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); 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, "<DSP1-4>", File::Read, File::Required);
return;
}
if(auto memory = node["memory(type=RAM,content=Data,architecture=uPD7725)"]) { if(auto memory = node["memory(type=RAM,content=Data,architecture=uPD7725)"]) {
if(auto file = game.memory(memory)) { if(auto file = game.memory(memory)) {
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) { 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}); 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) //processor(architecture=uPD96050)
auto Cartridge::loaduPD96050(Markup::Node node) -> void { 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.programROM) word = 0x000000;
for(auto& word : necdsp.dataROM) word = 0x0000; for(auto& word : necdsp.dataROM) word = 0x0000;
for(auto& word : necdsp.dataRAM) 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; necdsp.Frequency = 11'000'000;
} }
for(auto map : node.find("map")) { bool failed = false;
loadMap(map, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
}
if(auto memory = node["memory(type=ROM,content=Program,architecture=uPD96050)"]) { if(auto memory = node["memory(type=ROM,content=Program,architecture=uPD96050)"]) {
if(auto file = game.memory(memory)) { 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); 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 memory = node["memory(type=ROM,content=Data,architecture=uPD96050)"]) {
if(auto file = game.memory(memory)) { 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); 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, "<ST010-011>", File::Read, File::Required);
return;
}
if(auto memory = node["memory(type=RAM,content=Data,architecture=uPD96050)"]) { if(auto memory = node["memory(type=RAM,content=Data,architecture=uPD96050)"]) {
if(auto file = game.memory(memory)) { if(auto file = game.memory(memory)) {
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) { 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}); 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) //rtc(manufacturer=Epson)

View File

@ -18,3 +18,9 @@
#include <sfc/coprocessor/obc1/obc1.hpp> #include <sfc/coprocessor/obc1/obc1.hpp>
#include <sfc/coprocessor/msu1/msu1.hpp> #include <sfc/coprocessor/msu1/msu1.hpp>
#include <sfc/coprocessor/cx4/cx4.hpp>
#include <sfc/coprocessor/dsp1/dsp1.hpp>
#include <sfc/coprocessor/dsp2/dsp2.hpp>
#include <sfc/coprocessor/dsp4/dsp4.hpp>
#include <sfc/coprocessor/st0010/st0010.hpp>

View File

@ -0,0 +1,191 @@
#include <sfc/sfc.hpp>
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<count;i++) {
write(dest++, bus.read(src++));
}
}
void Cx4::write(uint24 addr, uint8 data) {
addr &= 0x1fff;
if(addr < 0x0c00) {
//ram
ram[addr] = data;
return;
}
if(addr < 0x1f00) {
//unmapped
return;
}
//command register
reg[addr & 0xff] = data;
if(addr == 0x1f47) {
//memory transfer
transfer_data();
return;
}
if(addr == 0x1f4f) {
//c4 command
if(reg[0x4d] == 0x0e && !(data & 0xc3)) {
//c4 test command
reg[0x80] = data >> 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);
}
}

View File

@ -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;

View File

@ -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

View File

@ -0,0 +1,251 @@
#ifdef CX4_CPP
#include <math.h>
#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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -0,0 +1,48 @@
#include <sfc/sfc.hpp>
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);
}
}
}

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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);
}

View File

@ -0,0 +1,136 @@
#include <sfc/sfc.hpp>
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;
}
}
}
}

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -0,0 +1,62 @@
#include <sfc/sfc.hpp>
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();
}
}

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,3 @@
auto ST0010::serialize(serializer& s) -> void {
s.array(ram);
}

View File

@ -0,0 +1,39 @@
#include <sfc/sfc.hpp>
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;
}
}
}

View File

@ -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;

View File

@ -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/NoSpriteLimit", hacks.ppuFast.noSpriteLimit);
bind(boolean, "Hacks/FastPPU/HiresMode7", hacks.ppuFast.hiresMode7); bind(boolean, "Hacks/FastPPU/HiresMode7", hacks.ppuFast.hiresMode7);
bind(boolean, "Hacks/FastDSP/Enable", hacks.dspFast.enable); bind(boolean, "Hacks/FastDSP/Enable", hacks.dspFast.enable);
bind(boolean, "Hacks/Coprocessors/HLE", hacks.coprocessors.hle);
bind(boolean, "Hacks/Coprocessors/DelayedSync", hacks.coprocessors.delayedSync); bind(boolean, "Hacks/Coprocessors/DelayedSync", hacks.coprocessors.delayedSync);
#undef bind #undef bind

View File

@ -35,6 +35,7 @@ struct Configuration {
} dspFast; } dspFast;
struct Coprocessors { struct Coprocessors {
bool delayedSync = true; bool delayedSync = true;
bool hle = true;
} coprocessors; } coprocessors;
} hacks; } hacks;

View File

@ -24,7 +24,7 @@ struct Bus {
~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; alwaysinline auto write(uint24 address, uint8 data) -> void;
auto reset() -> void; auto reset() -> void;

View File

@ -53,7 +53,8 @@ auto PPU::readOAM(uint10 address) -> uint8 {
auto PPU::writeOAM(uint10 address, uint8 data) -> void { auto PPU::writeOAM(uint10 address, uint8 data) -> void {
Line::flush(); 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); return writeObject(address, data);
} }

View File

@ -137,8 +137,6 @@ auto PPU::Object::tilefetch() -> void {
uint16 addr = (pos & 0xfff0) + (y & 7); uint16 addr = (pos & 0xfff0) + (y & 7);
oamTile[n].data.bits( 0,15) = ppu.vram[addr + 0]; oamTile[n].data.bits( 0,15) = ppu.vram[addr + 0];
ppu.step(2);
oamTile[n].data.bits(16,31) = ppu.vram[addr + 8]; oamTile[n].data.bits(16,31) = ppu.vram[addr + 8];
ppu.step(2); ppu.step(2);
} }

View File

@ -74,7 +74,7 @@ auto PPU::main() -> void {
step(2); step(2);
} }
step(14); step(14 + 34 * 2);
obj.tilefetch(); obj.tilefetch();
} }

View File

@ -68,6 +68,12 @@ auto System::serializeAll(serializer& s) -> void {
if(cartridge.has.OBC1) obc1.serialize(s); if(cartridge.has.OBC1) obc1.serialize(s);
if(cartridge.has.MSU1) msu1.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.BSMemorySlot) bsmemory.serialize(s);
if(cartridge.has.SufamiTurboSlotA) sufamiturboA.serialize(s); if(cartridge.has.SufamiTurboSlotA) sufamiturboA.serialize(s);
if(cartridge.has.SufamiTurboSlotB) sufamiturboB.serialize(s); if(cartridge.has.SufamiTurboSlotB) sufamiturboB.serialize(s);

View File

@ -111,6 +111,11 @@ auto System::power(bool reset) -> void {
if(cartridge.has.SDD1) sdd1.power(); if(cartridge.has.SDD1) sdd1.power();
if(cartridge.has.OBC1) obc1.power(); if(cartridge.has.OBC1) obc1.power();
if(cartridge.has.MSU1) msu1.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.BSMemorySlot) bsmemory.power();
if(cartridge.has.SufamiTurboSlotA) sufamiturboA.power(); if(cartridge.has.SufamiTurboSlotA) sufamiturboA.power();
if(cartridge.has.SufamiTurboSlotB) sufamiturboB.power(); if(cartridge.has.SufamiTurboSlotB) sufamiturboB.power();

View File

@ -237,7 +237,7 @@ board: SHVC-1CB0N7S-01
map address=00-3f,80-bf:6000-7fff size=0x2000 map address=00-3f,80-bf:6000-7fff size=0x2000
map address=70-71:0000-ffff map address=70-71:0000-ffff
board: SHVC-1CB5B-20 board: SHVC-1CB5B-(01,20)
processor architecture=GSU processor architecture=GSU
map address=00-3f,80-bf:3000-34ff map address=00-3f,80-bf:3000-34ff
memory type=ROM content=Program memory type=ROM content=Program

View File

@ -18,10 +18,6 @@ auto locate(string name) -> string {
return {Path::userData(), "bsnes/", name}; return {Path::userData(), "bsnes/", name};
} }
auto hiro::initialize() -> void {
Application::setName("bsnes");
}
#include <nall/main.hpp> #include <nall/main.hpp>
auto nall::main(Arguments arguments) -> void { auto nall::main(Arguments arguments) -> void {
settings.location = locate("settings.bml"); settings.location = locate("settings.bml");
@ -45,6 +41,7 @@ auto nall::main(Arguments arguments) -> void {
} }
settings.load(); settings.load();
Application::setName("bsnes");
Application::setScreenSaver(settings.general.screenSaver); Application::setScreenSaver(settings.general.screenSaver);
Application::setToolTips(settings.general.toolTips); Application::setToolTips(settings.general.toolTips);
emulator = new SuperFamicom::Interface; emulator = new SuperFamicom::Interface;

View File

@ -46,9 +46,11 @@ auto InputManager::bindHotkeys() -> void {
hotkeys.append(InputHotkey("Fast Forward").onPress([] { hotkeys.append(InputHotkey("Fast Forward").onPress([] {
video.setBlocking(false); video.setBlocking(false);
audio.setBlocking(false); audio.setBlocking(false);
audio.setDynamic(false);
}).onRelease([] { }).onRelease([] {
video.setBlocking(settings.video.blocking); video.setBlocking(settings.video.blocking);
audio.setBlocking(settings.audio.blocking); audio.setBlocking(settings.audio.blocking);
audio.setDynamic(settings.audio.dynamic);
})); }));
hotkeys.append(InputHotkey("Pause Emulation").onPress([] { hotkeys.append(InputHotkey("Pause Emulation").onPress([] {

View File

@ -104,7 +104,7 @@ auto Presentation::create() -> void {
program.loadState("Quick/Redo"); program.loadState("Quick/Redo");
})); }));
loadState.append(MenuItem().setIcon(Icon::Edit::Clear).setText("Remove All States").onActivate([&] { 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}); for(uint index : range(QuickStates)) program.removeState({"Quick/Slot ", 1 + index});
program.removeState("Quick/Undo"); program.removeState("Quick/Undo");
program.removeState("Quick/Redo"); program.removeState("Quick/Redo");
@ -141,7 +141,7 @@ auto Presentation::create() -> void {
.setAuthor("byuu") .setAuthor("byuu")
.setLicense("GPLv3") .setLicense("GPLv3")
.setWebsite("https://byuu.org/") .setWebsite("https://byuu.org/")
.setParent(*this) .setAlignment(*this)
.show(); .show();
}); });
@ -195,7 +195,7 @@ auto Presentation::create() -> void {
setTitle({"bsnes v", Emulator::Version}); setTitle({"bsnes v", Emulator::Version});
setBackgroundColor({0, 0, 0}); setBackgroundColor({0, 0, 0});
resizeWindow(); resizeWindow();
setCentered(); setAlignment(Alignment::Center);
setFullScreen(startFullScreen); setFullScreen(startFullScreen);
#if defined(PLATFORM_MACOS) #if defined(PLATFORM_MACOS)
@ -324,7 +324,7 @@ auto Presentation::toggleFullscreenMode() -> void {
menuBar.setVisible(true); menuBar.setVisible(true);
if(settings.general.statusBar) layout.append(statusLayout, Size{~0, StatusHeight}); if(settings.general.statusBar) layout.append(statusLayout, Size{~0, StatusHeight});
resizeWindow(); resizeWindow();
setCentered(); setAlignment(Alignment::Center);
} }
} }
@ -419,7 +419,7 @@ auto Presentation::updateSizeMenu() -> void {
resizeWindow(); resizeWindow();
})); }));
sizeMenu.append(MenuItem().setIcon(Icon::Place::Settings).setText("Center Window").onActivate([&] { sizeMenu.append(MenuItem().setIcon(Icon::Place::Settings).setText("Center Window").onActivate([&] {
setCentered(); setAlignment(Alignment::Center);
})); }));
} }

View File

@ -16,7 +16,7 @@ auto Program::updateAudioDriver(Window parent) -> void {
if(!audio.ready()) { if(!audio.ready()) {
MessageDialog({ MessageDialog({
"Error: failed to initialize [", settings.audio.driver, "] audio driver." "Error: failed to initialize [", settings.audio.driver, "] audio driver."
}).setParent(parent).error(); }).setAlignment(parent).error();
settings.audio.driver = "None"; settings.audio.driver = "None";
return updateAudioDriver(parent); return updateAudioDriver(parent);
} }

View File

@ -18,7 +18,7 @@ auto Program::load() -> void {
"Warning: this game image is unverified.\n" "Warning: this game image is unverified.\n"
"Running it *may* be a security risk.\n\n" "Running it *may* be a security risk.\n\n"
"Do you wish to run the game anyway?" "Do you wish to run the game anyway?"
).setParent(*presentation).question({"Always", "Yes", "No"}); ).setAlignment(*presentation).question({"Always", "Yes", "No"});
if(response == "No") { if(response == "No") {
emulator->unload(); emulator->unload();
return showMessage("Game loading cancelled"); return showMessage("Game loading cancelled");

View File

@ -12,7 +12,7 @@ auto Program::updateInputDriver(Window parent) -> void {
if(!input.ready()) { if(!input.ready()) {
MessageDialog({ MessageDialog({
"Error: failed to initialize [", settings.input.driver, "] input driver." "Error: failed to initialize [", settings.input.driver, "] input driver."
}).setParent(parent).error(); }).setAlignment(parent).error();
settings.input.driver = "None"; settings.input.driver = "None";
return updateInputDriver(parent); return updateInputDriver(parent);
} }

View File

@ -119,6 +119,6 @@ auto Program::applyPatchBPS(vector<uint8_t>& input, string location) -> bool {
MessageDialog({ MessageDialog({
error, "\n\n", error, "\n\n",
"Please ensure you are using the correct (headerless) ROM for this patch." "Please ensure you are using the correct (headerless) ROM for this patch."
}).setParent(*presentation).error(); }).setAlignment(*presentation).error();
return false; return false;
} }

View File

@ -91,7 +91,7 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) ->
if(MessageDialog({ if(MessageDialog({
"Error: missing required data: ", name, "\n\n", "Error: missing required data: ", name, "\n\n",
"Would you like to view the online documentation for more information?" "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(); 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<string> options) -> Emulator::Platform::Load { auto Program::load(uint id, string name, string type, vector<string> options) -> Emulator::Platform::Load {
BrowserDialog dialog; BrowserDialog dialog;
dialog.setParent(*presentation); dialog.setAlignment(*presentation);
dialog.setOptions(options); dialog.setOptions(options);
if(id == 1 && name == "Super Famicom" && type == "sfc") { if(id == 1 && name == "Super Famicom" && type == "sfc") {

View File

@ -40,7 +40,7 @@ auto Program::create() -> void {
MessageDialog( MessageDialog(
"Driver crash detected. Hardware drivers have been disabled.\n" "Driver crash detected. Hardware drivers have been disabled.\n"
"Please reconfigure drivers in the advanced settings panel." "Please reconfigure drivers in the advanced settings panel."
).setParent(*presentation).information(); ).setAlignment(*presentation).information();
settings.video.driver = "None"; settings.video.driver = "None";
settings.audio.driver = "None"; settings.audio.driver = "None";
settings.input.driver = "None"; settings.input.driver = "None";
@ -90,5 +90,5 @@ auto Program::quit() -> void {
video.reset(); video.reset();
audio.reset(); audio.reset();
input.reset(); input.reset();
Application::kill(); Application::exit();
} }

View File

@ -24,7 +24,7 @@ auto Program::updateVideoDriver(Window parent) -> void {
if(!video.ready()) { if(!video.ready()) {
MessageDialog({ MessageDialog({
"Error: failed to initialize [", settings.video.driver, "] video driver." "Error: failed to initialize [", settings.video.driver, "] video driver."
}).setParent(parent).error(); }).setAlignment(parent).error();
settings.video.driver = "None"; settings.video.driver = "None";
return updateVideoDriver(parent); return updateVideoDriver(parent);
} }

View File

@ -7,8 +7,9 @@
</dependentAssembly> </dependentAssembly>
</dependency> </dependency>
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"> <asmv3:windowsSettings>
<dpiAware>false</dpiAware> <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
</asmv3:windowsSettings> </asmv3:windowsSettings>
</asmv3:application> </asmv3:application>
</assembly> </assembly>

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@ namespace Resource {
extern const unsigned char Icon[3463]; extern const unsigned char Icon[3463];
extern const unsigned char Logo[23467]; extern const unsigned char Logo[23467];
namespace System { namespace System {
extern const char Boards[30183]; extern const char Boards[30188];
extern const unsigned char IPLROM[64]; extern const unsigned char IPLROM[64];
} }
} }

View File

@ -2,7 +2,7 @@ auto AudioSettings::create() -> void {
setIcon(Icon::Device::Speaker); setIcon(Icon::Device::Speaker);
setText("Audio"); setText("Audio");
layout.setPadding(5); layout.setPadding(5_sx);
effectsLabel.setFont(Font().setBold()).setText("Effects"); effectsLabel.setFont(Font().setBold()).setText("Effects");
effectsLayout.setSize({3, 3}); effectsLayout.setSize({3, 3});

View File

@ -2,7 +2,7 @@ auto DriverSettings::create() -> void {
setIcon(Icon::Place::Settings); setIcon(Icon::Place::Settings);
setText("Drivers"); setText("Drivers");
layout.setPadding(5); layout.setPadding(5_sx);
videoLabel.setText("Video").setFont(Font().setBold()); videoLabel.setText("Video").setFont(Font().setBold());
videoLayout.setSize({2, 2}); videoLayout.setSize({2, 2});
@ -77,7 +77,7 @@ auto DriverSettings::create() -> void {
presentation.speedMenu.setEnabled(!videoBlockingToggle.checked() && audioBlockingToggle.checked()); presentation.speedMenu.setEnabled(!videoBlockingToggle.checked() && audioBlockingToggle.checked());
}); });
audioDynamicToggle.setText("Dynamic rate").setToolTip( 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" "Dynamically adjusts the audio frequency by tiny amounts.\n"
"Use this with video sync enabled, and audio sync disabled.\n\n" "Use this with video sync enabled, and audio sync disabled.\n\n"
"This can produce perfectly smooth video and clean audio,\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" "Warning: incompatible drivers may cause bsnes to crash.\n"
"It is highly recommended you unload your game first to be safe.\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?" "Do you wish to proceed with the video driver change now anyway?"
).setParent(*settingsWindow).question() == "Yes") { ).setAlignment(*settingsWindow).question() == "Yes") {
program.save(); program.save();
program.saveUndoState(); program.saveUndoState();
settings.general.crashed = true; settings.general.crashed = true;
@ -189,7 +189,7 @@ auto DriverSettings::audioDriverChange() -> void {
"Warning: incompatible drivers may cause bsnes to crash.\n" "Warning: incompatible drivers may cause bsnes to crash.\n"
"It is highly recommended you unload your game first to be safe.\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?" "Do you wish to proceed with the audio driver change now anyway?"
).setParent(*settingsWindow).question() == "Yes") { ).setAlignment(*settingsWindow).question() == "Yes") {
program.save(); program.save();
program.saveUndoState(); program.saveUndoState();
settings.general.crashed = true; settings.general.crashed = true;
@ -275,7 +275,7 @@ auto DriverSettings::inputDriverChange() -> void {
"Warning: incompatible drivers may cause bsnes to crash.\n" "Warning: incompatible drivers may cause bsnes to crash.\n"
"It is highly recommended you unload your game first to be safe.\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?" "Do you wish to proceed with the input driver change now anyway?"
).setParent(*settingsWindow).question() == "Yes") { ).setAlignment(*settingsWindow).question() == "Yes") {
program.save(); program.save();
program.saveUndoState(); program.saveUndoState();
settings.general.crashed = true; settings.general.crashed = true;

View File

@ -2,7 +2,7 @@ auto EmulatorSettings::create() -> void {
setIcon(Icon::Action::Settings); setIcon(Icon::Action::Settings);
setText("Emulator"); setText("Emulator");
layout.setPadding(5); layout.setPadding(5_sx);
optionsLabel.setText("Options").setFont(Font().setBold()); optionsLabel.setText("Options").setFont(Font().setBold());
inputFocusLabel.setText("When focus is lost:"); 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([&] { coprocessorsDelayedSyncOption.setText("Fast coprocessors (delayed sync)").setChecked(settings.emulator.hack.coprocessors.delayedSync).onToggle([&] {
settings.emulator.hack.coprocessors.delayedSync = coprocessorsDelayedSyncOption.checked(); 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:"); superFXLabel.setText("SuperFX clock speed:");
superFXValue.setAlignment(0.5); superFXValue.setAlignment(0.5);
superFXClock.setLength(71).setPosition((settings.emulator.hack.fastSuperFX - 100) / 10).onChange([&] { 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/FastPPU/HiresMode7", hiresMode7.checked());
emulator->configure("Hacks/FastDSP/Enable", fastDSPOption.checked()); emulator->configure("Hacks/FastDSP/Enable", fastDSPOption.checked());
emulator->configure("Hacks/Coprocessor/DelayedSync", coprocessorsDelayedSyncOption.checked()); emulator->configure("Hacks/Coprocessor/DelayedSync", coprocessorsDelayedSyncOption.checked());
emulator->configure("Hacks/Coprocessor/HLE", coprocessorsHLEOption.checked());
} }

View File

@ -2,7 +2,7 @@ auto HotkeySettings::create() -> void {
setIcon(Icon::Device::Keyboard); setIcon(Icon::Device::Keyboard);
setText("Hotkeys"); setText("Hotkeys");
layout.setPadding(5); layout.setPadding(5_sx);
mappingList.setBatchable(); mappingList.setBatchable();
mappingList.setHeadered(); mappingList.setHeadered();
mappingList.onActivate([&] { mappingList.onActivate([&] {

View File

@ -2,7 +2,7 @@ auto InputSettings::create() -> void {
setIcon(Icon::Device::Joypad); setIcon(Icon::Device::Joypad);
setText("Input"); setText("Input");
layout.setPadding(5); layout.setPadding(5_sx);
portLabel.setText("Port:"); portLabel.setText("Port:");
portList.onChange([&] { reloadDevices(); }); portList.onChange([&] { reloadDevices(); });
deviceLabel.setText("Device:"); deviceLabel.setText("Device:");

View File

@ -2,14 +2,14 @@ auto PathSettings::create() -> void {
setIcon(Icon::Emblem::Folder); setIcon(Icon::Emblem::Folder);
setText("Paths"); setText("Paths");
layout.setPadding(5); layout.setPadding(5_sx);
layout.setSize({4, 6}); layout.setSize({4, 6});
layout.column(0).setAlignment(1.0); layout.column(0).setAlignment(1.0);
gamesLabel.setText("Games:"); gamesLabel.setText("Games:");
gamesPath.setEditable(false); gamesPath.setEditable(false);
gamesAssign.setText("Assign ...").onActivate([&] { gamesAssign.setText("Assign ...").onActivate([&] {
if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) { if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
settings.path.games = location; settings.path.games = location;
refreshPaths(); refreshPaths();
} }
@ -22,7 +22,7 @@ auto PathSettings::create() -> void {
patchesLabel.setText("Patches:"); patchesLabel.setText("Patches:");
patchesPath.setEditable(false); patchesPath.setEditable(false);
patchesAssign.setText("Assign ...").onActivate([&] { patchesAssign.setText("Assign ...").onActivate([&] {
if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) { if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
settings.path.patches = location; settings.path.patches = location;
refreshPaths(); refreshPaths();
} }
@ -35,7 +35,7 @@ auto PathSettings::create() -> void {
savesLabel.setText("Saves:"); savesLabel.setText("Saves:");
savesPath.setEditable(false); savesPath.setEditable(false);
savesAssign.setText("Assign ...").onActivate([&] { savesAssign.setText("Assign ...").onActivate([&] {
if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) { if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
settings.path.saves = location; settings.path.saves = location;
refreshPaths(); refreshPaths();
} }
@ -48,7 +48,7 @@ auto PathSettings::create() -> void {
cheatsLabel.setText("Cheats:"); cheatsLabel.setText("Cheats:");
cheatsPath.setEditable(false); cheatsPath.setEditable(false);
cheatsAssign.setText("Assign ...").onActivate([&] { cheatsAssign.setText("Assign ...").onActivate([&] {
if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) { if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
settings.path.cheats = location; settings.path.cheats = location;
refreshPaths(); refreshPaths();
} }
@ -61,7 +61,7 @@ auto PathSettings::create() -> void {
statesLabel.setText("States:"); statesLabel.setText("States:");
statesPath.setEditable(false); statesPath.setEditable(false);
statesAssign.setText("Assign ...").onActivate([&] { statesAssign.setText("Assign ...").onActivate([&] {
if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) { if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
settings.path.states = location; settings.path.states = location;
refreshPaths(); refreshPaths();
} }
@ -74,7 +74,7 @@ auto PathSettings::create() -> void {
screenshotsLabel.setText("Screenshots:"); screenshotsLabel.setText("Screenshots:");
screenshotsPath.setEditable(false); screenshotsPath.setEditable(false);
screenshotsAssign.setText("Assign ...").onActivate([&] { screenshotsAssign.setText("Assign ...").onActivate([&] {
if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) { if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
settings.path.screenshots = location; settings.path.screenshots = location;
refreshPaths(); refreshPaths();
} }

View File

@ -100,6 +100,7 @@ auto Settings::process(bool load) -> void {
bind(boolean, "Emulator/Hack/FastPPU/HiresMode7", emulator.hack.fastPPU.hiresMode7); bind(boolean, "Emulator/Hack/FastPPU/HiresMode7", emulator.hack.fastPPU.hiresMode7);
bind(boolean, "Emulator/Hack/FastDSP/Enable", emulator.hack.fastDSP.enable); 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/DelayedSync", emulator.hack.coprocessors.delayedSync);
bind(boolean, "Emulator/Hack/Coprocessors/HLE", emulator.hack.coprocessors.hle);
bind(natural, "Emulator/Hack/FastSuperFX", emulator.hack.fastSuperFX); bind(natural, "Emulator/Hack/FastSuperFX", emulator.hack.fastSuperFX);
bind(boolean, "Emulator/Cheats/Enable", emulator.cheats.enable); bind(boolean, "Emulator/Cheats/Enable", emulator.cheats.enable);
@ -112,7 +113,7 @@ auto Settings::process(bool load) -> void {
} }
auto SettingsWindow::create() -> void { auto SettingsWindow::create() -> void {
layout.setPadding(5); layout.setPadding(5_sx);
panel.append(videoSettings); panel.append(videoSettings);
panel.append(audioSettings); panel.append(audioSettings);
panel.append(inputSettings); panel.append(inputSettings);
@ -123,7 +124,7 @@ auto SettingsWindow::create() -> void {
statusBar.setFont(Font().setBold()); statusBar.setFont(Font().setBold());
setTitle("Settings"); setTitle("Settings");
setSize({600, 400}); setSize({600_sx, 400_sx});
setAlignment({0.0, 1.0}); setAlignment({0.0, 1.0});
setDismissable(); setDismissable();

View File

@ -1,4 +1,6 @@
struct Settings : Markup::Node { struct Settings : Markup::Node {
using string = nall::string;
auto load() -> void; auto load() -> void;
auto save() -> void; auto save() -> void;
auto process(bool load) -> void; auto process(bool load) -> void;
@ -83,6 +85,7 @@ struct Settings : Markup::Node {
} fastDSP; } fastDSP;
struct Coprocessors { struct Coprocessors {
bool delayedSync = true; bool delayedSync = true;
bool hle = true;
} coprocessors; } coprocessors;
uint fastSuperFX = 100; uint fastSuperFX = 100;
} hack; } hack;
@ -107,15 +110,15 @@ private:
Label colorAdjustmentLabel{&layout, Size{~0, 0}, 2}; Label colorAdjustmentLabel{&layout, Size{~0, 0}, 2};
TableLayout colorLayout{&layout, Size{~0, 0}}; TableLayout colorLayout{&layout, Size{~0, 0}};
Label luminanceLabel{&colorLayout, 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}}; HorizontalSlider luminanceSlider{&colorLayout, Size{~0, 0}};
// //
Label saturationLabel{&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}}; HorizontalSlider saturationSlider{&colorLayout, Size{~0, 0}};
// //
Label gammaLabel{&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}}; HorizontalSlider gammaSlider{&colorLayout, Size{~0, 0}};
}; };
@ -127,15 +130,15 @@ private:
Label effectsLabel{&layout, Size{~0, 0}, 2}; Label effectsLabel{&layout, Size{~0, 0}, 2};
TableLayout effectsLayout{&layout, Size{~0, 0}}; TableLayout effectsLayout{&layout, Size{~0, 0}};
Label skewLabel{&effectsLayout, 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}}; HorizontalSlider skewSlider{&effectsLayout, Size{~0, 0}};
// //
Label volumeLabel{&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}}; HorizontalSlider volumeSlider{&effectsLayout, Size{~0, 0}};
// //
Label balanceLabel{&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}}; HorizontalSlider balanceSlider{&effectsLayout, Size{~0, 0}};
}; };
@ -168,12 +171,12 @@ private:
ComboButton turboList{&selectionLayout, Size{0, 0}}; ComboButton turboList{&selectionLayout, Size{0, 0}};
TableView mappingList{&layout, Size{~0, ~0}}; TableView mappingList{&layout, Size{~0, ~0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}}; HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Button assignMouse1{&controlLayout, Size{100, 0}}; Button assignMouse1{&controlLayout, Size{100_sx, 0}};
Button assignMouse2{&controlLayout, Size{100, 0}}; Button assignMouse2{&controlLayout, Size{100_sx, 0}};
Button assignMouse3{&controlLayout, Size{100, 0}}; Button assignMouse3{&controlLayout, Size{100_sx, 0}};
Widget controlSpacer{&controlLayout, Size{~0, 0}}; Widget controlSpacer{&controlLayout, Size{~0, 0}};
Button assignButton{&controlLayout, Size{80, 0}}; Button assignButton{&controlLayout, Size{80_sx, 0}};
Button clearButton{&controlLayout, Size{80, 0}}; Button clearButton{&controlLayout, Size{80_sx, 0}};
}; };
struct HotkeySettings : TabFrameItem { struct HotkeySettings : TabFrameItem {
@ -193,8 +196,8 @@ private:
TableView mappingList{&layout, Size{~0, ~0}}; TableView mappingList{&layout, Size{~0, ~0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}}; HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Widget controlSpacer{&controlLayout, Size{~0, 0}}; Widget controlSpacer{&controlLayout, Size{~0, 0}};
Button assignButton{&controlLayout, Size{80, 0}}; Button assignButton{&controlLayout, Size{80_sx, 0}};
Button clearButton{&controlLayout, Size{80, 0}}; Button clearButton{&controlLayout, Size{80_sx, 0}};
}; };
struct PathSettings : TabFrameItem { struct PathSettings : TabFrameItem {
@ -205,33 +208,33 @@ public:
TableLayout layout{this}; TableLayout layout{this};
Label gamesLabel{&layout, Size{0, 0}}; Label gamesLabel{&layout, Size{0, 0}};
LineEdit gamesPath{&layout, Size{~0, 0}}; LineEdit gamesPath{&layout, Size{~0, 0}};
Button gamesAssign{&layout, Size{80, 0}}; Button gamesAssign{&layout, Size{80_sx, 0}};
Button gamesReset{&layout, Size{80, 0}}; Button gamesReset{&layout, Size{80_sx, 0}};
// //
Label patchesLabel{&layout, Size{0, 0}}; Label patchesLabel{&layout, Size{0, 0}};
LineEdit patchesPath{&layout, Size{~0, 0}}; LineEdit patchesPath{&layout, Size{~0, 0}};
Button patchesAssign{&layout, Size{80, 0}}; Button patchesAssign{&layout, Size{80_sx, 0}};
Button patchesReset{&layout, Size{80, 0}}; Button patchesReset{&layout, Size{80_sx, 0}};
// //
Label savesLabel{&layout, Size{0, 0}}; Label savesLabel{&layout, Size{0, 0}};
LineEdit savesPath{&layout, Size{~0, 0}}; LineEdit savesPath{&layout, Size{~0, 0}};
Button savesAssign{&layout, Size{80, 0}}; Button savesAssign{&layout, Size{80_sx, 0}};
Button savesReset{&layout, Size{80, 0}}; Button savesReset{&layout, Size{80_sx, 0}};
// //
Label cheatsLabel{&layout, Size{0, 0}}; Label cheatsLabel{&layout, Size{0, 0}};
LineEdit cheatsPath{&layout, Size{~0, 0}}; LineEdit cheatsPath{&layout, Size{~0, 0}};
Button cheatsAssign{&layout, Size{80, 0}}; Button cheatsAssign{&layout, Size{80_sx, 0}};
Button cheatsReset{&layout, Size{80, 0}}; Button cheatsReset{&layout, Size{80_sx, 0}};
// //
Label statesLabel{&layout, Size{0, 0}}; Label statesLabel{&layout, Size{0, 0}};
LineEdit statesPath{&layout, Size{~0, 0}}; LineEdit statesPath{&layout, Size{~0, 0}};
Button statesAssign{&layout, Size{80, 0}}; Button statesAssign{&layout, Size{80_sx, 0}};
Button statesReset{&layout, Size{80, 0}}; Button statesReset{&layout, Size{80_sx, 0}};
// //
Label screenshotsLabel{&layout, Size{0, 0}}; Label screenshotsLabel{&layout, Size{0, 0}};
LineEdit screenshotsPath{&layout, Size{~0, 0}}; LineEdit screenshotsPath{&layout, Size{~0, 0}};
Button screenshotsAssign{&layout, Size{80, 0}}; Button screenshotsAssign{&layout, Size{80_sx, 0}};
Button screenshotsReset{&layout, Size{80, 0}}; Button screenshotsReset{&layout, Size{80_sx, 0}};
}; };
struct EmulatorSettings : TabFrameItem { struct EmulatorSettings : TabFrameItem {
@ -259,10 +262,12 @@ public:
CheckLabel noSpriteLimit{&fastPPULayout, Size{0, 0}}; CheckLabel noSpriteLimit{&fastPPULayout, Size{0, 0}};
CheckLabel hiresMode7{&fastPPULayout, Size{0, 0}}; CheckLabel hiresMode7{&fastPPULayout, Size{0, 0}};
CheckLabel fastDSPOption{&layout, 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}}; HorizontalLayout superFXLayout{&layout, Size{~0, 0}};
Label superFXLabel{&superFXLayout, 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}}; HorizontalSlider superFXClock{&superFXLayout, Size{~0, 0}};
Label hacksNote{&layout, Size{~0, 0}}; Label hacksNote{&layout, Size{~0, 0}};
}; };

View File

@ -2,7 +2,7 @@ auto VideoSettings::create() -> void {
setIcon(Icon::Device::Display); setIcon(Icon::Device::Display);
setText("Video"); setText("Video");
layout.setPadding(5); layout.setPadding(5_sx);
colorAdjustmentLabel.setFont(Font().setBold()).setText("Color Adjustment"); colorAdjustmentLabel.setFont(Font().setBold()).setText("Color Adjustment");
colorLayout.setSize({3, 3}); colorLayout.setSize({3, 3});

View File

@ -1,5 +1,5 @@
auto CheatDatabase::create() -> void { auto CheatDatabase::create() -> void {
layout.setPadding(5); layout.setPadding(5_sx);
selectAllButton.setText("Select All").onActivate([&] { selectAllButton.setText("Select All").onActivate([&] {
for(auto item : cheatList.items()) item.setChecked(true); for(auto item : cheatList.items()) item.setChecked(true);
}); });
@ -10,7 +10,7 @@ auto CheatDatabase::create() -> void {
addCheats(); addCheats();
}); });
setSize({800, 400}); setSize({800_sx, 400_sx});
setAlignment({0.5, 1.0}); setAlignment({0.5, 1.0});
setDismissable(); setDismissable();
} }
@ -36,7 +36,7 @@ auto CheatDatabase::findCheats() -> void {
return; 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 { auto CheatDatabase::addCheats() -> void {
@ -51,7 +51,7 @@ auto CheatDatabase::addCheats() -> void {
// //
auto CheatWindow::create() -> void { auto CheatWindow::create() -> void {
layout.setPadding(5); layout.setPadding(5_sx);
tableLayout.setSize({2, 2}); tableLayout.setSize({2, 2});
tableLayout.cell(0).setAlignment({1.0, 0.5}); tableLayout.cell(0).setAlignment({1.0, 0.5});
tableLayout.cell(2).setAlignment({1.0, 0.0}); tableLayout.cell(2).setAlignment({1.0, 0.0});
@ -65,7 +65,7 @@ auto CheatWindow::create() -> void {
acceptButton.onActivate([&] { doAccept(); }); acceptButton.onActivate([&] { doAccept(); });
cancelButton.setText("Cancel").onActivate([&] { setVisible(false); }); cancelButton.setText("Cancel").onActivate([&] { setVisible(false); });
setSize({400, layout.minimumSize().height() + 100}); setSize({400_sx, layout.minimumSize().height() + 100_sx});
setDismissable(); setDismissable();
} }
@ -75,7 +75,7 @@ auto CheatWindow::show(Cheat cheat) -> void {
enableOption.setChecked(cheat.enable); enableOption.setChecked(cheat.enable);
doChange(); doChange();
setTitle(!cheat.name ? "Add Cheat" : "Edit Cheat"); setTitle(!cheat.name ? "Add Cheat" : "Edit Cheat");
setCentered(*toolsWindow); setAlignment(*toolsWindow);
setVisible(); setVisible();
setFocused(); setFocused();
nameValue.setFocused(); nameValue.setFocused();
@ -105,7 +105,7 @@ auto CheatEditor::create() -> void {
setIcon(Icon::Edit::Replace); setIcon(Icon::Edit::Replace);
setText("Cheat Editor"); setText("Cheat Editor");
layout.setPadding(5); layout.setPadding(5_sx);
cheatList.setBatchable(); cheatList.setBatchable();
cheatList.setHeadered(); cheatList.setHeadered();
cheatList.setSortable(); cheatList.setSortable();
@ -201,7 +201,7 @@ auto CheatEditor::editCheat(Cheat cheat) -> void {
auto CheatEditor::removeCheats() -> void { auto CheatEditor::removeCheats() -> void {
if(auto batched = cheatList.batched()) { if(auto batched = cheatList.batched()) {
if(MessageDialog("Are you sure you want to permanently remove the selected cheat(s)?") 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()); for(auto& item : reverse(batched)) cheats.remove(item.offset());
cheats.sort(); cheats.sort();
refresh(); refresh();

View File

@ -2,7 +2,7 @@ auto ManifestViewer::create() -> void {
setIcon(Icon::Emblem::Text); setIcon(Icon::Emblem::Text);
setText("Manifest Viewer"); setText("Manifest Viewer");
layout.setPadding(5); layout.setPadding(5_sx);
manifestLabel.setText("Manifest:"); manifestLabel.setText("Manifest:");
manifestOption.onChange([&] { selectManifest(); }); manifestOption.onChange([&] { selectManifest(); });
manifestSpacer.setColor({192, 192, 192}); manifestSpacer.setColor({192, 192, 192});

View File

@ -1,12 +1,14 @@
#include <nall/encode/bmp.hpp>
auto StateWindow::create() -> void { auto StateWindow::create() -> void {
layout.setPadding(5); layout.setPadding(5_sx);
nameLabel.setText("Name:"); nameLabel.setText("Name:");
nameValue.onActivate([&] { if(acceptButton.enabled()) acceptButton.doActivate(); }); nameValue.onActivate([&] { if(acceptButton.enabled()) acceptButton.doActivate(); });
nameValue.onChange([&] { doChange(); }); nameValue.onChange([&] { doChange(); });
acceptButton.onActivate([&] { doAccept(); }); acceptButton.onActivate([&] { doAccept(); });
cancelButton.setText("Cancel").onActivate([&] { setVisible(false); }); cancelButton.setText("Cancel").onActivate([&] { setVisible(false); });
setSize({400, layout.minimumSize().height()}); setSize({400_sx, layout.minimumSize().height()});
setDismissable(); setDismissable();
} }
@ -16,7 +18,7 @@ auto StateWindow::show(string name) -> void {
nameValue.setText(property("name")); nameValue.setText(property("name"));
doChange(); doChange();
setTitle(!property("name") ? "Add State" : "Rename State"); setTitle(!property("name") ? "Add State" : "Rename State");
setCentered(*toolsWindow); setAlignment(*toolsWindow);
setVisible(); setVisible();
setFocused(); setFocused();
nameValue.setFocused(); nameValue.setFocused();
@ -48,7 +50,7 @@ auto StateManager::create() -> void {
setIcon(Icon::Application::FileManager); setIcon(Icon::Application::FileManager);
setText("State Manager"); setText("State Manager");
layout.setPadding(5); layout.setPadding(5_sx);
stateLayout.setAlignment(0.0); stateLayout.setAlignment(0.0);
stateList.setBatchable(); stateList.setBatchable();
stateList.setHeadered(); stateList.setHeadered();
@ -131,7 +133,7 @@ auto StateManager::modifyState(string name) -> void {
auto StateManager::removeStates() -> void { auto StateManager::removeStates() -> void {
if(auto batched = stateList.batched()) { if(auto batched = stateList.batched()) {
if(MessageDialog("Are you sure you want to permanently remove the selected state(s)?") 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(); auto lock = acquire();
for(auto& item : batched) program.removeState(item.property("name")); for(auto& item : batched) program.removeState(item.property("name"));
loadStates(); loadStates();
@ -159,9 +161,18 @@ auto StateManager::updateSelection() -> void {
if(signature == Program::State::Signature && preview) { if(signature == Program::State::Signature && preview) {
uint offset = 3 * sizeof(uint) + serializer; uint offset = 3 * sizeof(uint) + serializer;
auto preview = Decode::RLE<2>({saveState.data() + offset, max(offset, saveState.size()) - offset}); 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.copy(preview.data(), 256 * sizeof(uint16_t), 256, 240);
icon.transform(); 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); statePreview.setIcon(icon);
} }
} }

View File

@ -11,7 +11,7 @@ ManifestViewer manifestViewer;
ToolsWindow toolsWindow; ToolsWindow toolsWindow;
auto ToolsWindow::create() -> void { auto ToolsWindow::create() -> void {
layout.setPadding(5); layout.setPadding(5_sx);
panel.append(cheatEditor); panel.append(cheatEditor);
panel.append(stateManager); panel.append(stateManager);
panel.append(manifestViewer); panel.append(manifestViewer);
@ -22,7 +22,7 @@ auto ToolsWindow::create() -> void {
}); });
setTitle("Tools"); setTitle("Tools");
setSize({720, 480}); setSize({720_sx, 480_sx});
setAlignment({1.0, 1.0}); setAlignment({1.0, 1.0});
setDismissable(); setDismissable();

View File

@ -21,10 +21,10 @@ public:
VerticalLayout layout{this}; VerticalLayout layout{this};
ListView cheatList{&layout, Size{~0, ~0}}; ListView cheatList{&layout, Size{~0, ~0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}}; HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Button selectAllButton{&controlLayout, Size{100, 0}}; Button selectAllButton{&controlLayout, Size{100_sx, 0}};
Button unselectAllButton{&controlLayout, Size{100, 0}}; Button unselectAllButton{&controlLayout, Size{100_sx, 0}};
Widget spacer{&controlLayout, Size{~0, 0}}; Widget spacer{&controlLayout, Size{~0, 0}};
Button addCheatsButton{&controlLayout, Size{100, 0}}; Button addCheatsButton{&controlLayout, Size{100_sx, 0}};
}; };
struct CheatWindow : Window { struct CheatWindow : Window {
@ -43,8 +43,8 @@ public:
HorizontalLayout controlLayout{&layout, Size{~0, 0}}; HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Widget controlSpacer{&controlLayout, Size{~0, 0}}; Widget controlSpacer{&controlLayout, Size{~0, 0}};
CheckLabel enableOption{&controlLayout, Size{0, 0}}; CheckLabel enableOption{&controlLayout, Size{0, 0}};
Button acceptButton{&controlLayout, Size{80, 0}}; Button acceptButton{&controlLayout, Size{80_sx, 0}};
Button cancelButton{&controlLayout, Size{80, 0}}; Button cancelButton{&controlLayout, Size{80_sx, 0}};
}; };
struct CheatEditor : TabFrameItem { struct CheatEditor : TabFrameItem {
@ -63,12 +63,12 @@ public:
VerticalLayout layout{this}; VerticalLayout layout{this};
TableView cheatList{&layout, Size{~0, ~0}}; TableView cheatList{&layout, Size{~0, ~0}};
HorizontalLayout controlLayout{&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}}; Widget spacer{&controlLayout, Size{~0, 0}};
CheckLabel enableCheats{&controlLayout, Size{0, 0}}; CheckLabel enableCheats{&controlLayout, Size{0, 0}};
Button addButton{&controlLayout, Size{80, 0}}; Button addButton{&controlLayout, Size{80_sx, 0}};
Button editButton{&controlLayout, Size{80, 0}}; Button editButton{&controlLayout, Size{80_sx, 0}};
Button removeButton{&controlLayout, Size{80, 0}}; Button removeButton{&controlLayout, Size{80_sx, 0}};
}; };
struct StateWindow : Window { struct StateWindow : Window {
@ -80,12 +80,12 @@ struct StateWindow : Window {
public: public:
VerticalLayout layout{this}; VerticalLayout layout{this};
HorizontalLayout nameLayout{&layout, Size{~0, 0}}; 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}}; LineEdit nameValue{&nameLayout, Size{~0, 0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}}; HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Widget spacer{&controlLayout, Size{~0, 0}}; Widget spacer{&controlLayout, Size{~0, 0}};
Button acceptButton{&controlLayout, Size{80, 0}}; Button acceptButton{&controlLayout, Size{80_sx, 0}};
Button cancelButton{&controlLayout, Size{80, 0}}; Button cancelButton{&controlLayout, Size{80_sx, 0}};
}; };
struct StateManager : TabFrameItem, Lock { struct StateManager : TabFrameItem, Lock {
@ -117,12 +117,12 @@ public:
Label statePreviewLabel{&previewLayout, Size{~0, 0}}; Label statePreviewLabel{&previewLayout, Size{~0, 0}};
Canvas statePreview{&previewLayout, Size{256, 224}}; Canvas statePreview{&previewLayout, Size{256, 224}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}}; HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Button loadButton{&controlLayout, Size{80, 0}}; Button loadButton{&controlLayout, Size{80_sx, 0}};
Button saveButton{&controlLayout, Size{80, 0}}; Button saveButton{&controlLayout, Size{80_sx, 0}};
Widget spacer{&controlLayout, Size{~0, 0}}; Widget spacer{&controlLayout, Size{~0, 0}};
Button addButton{&controlLayout, Size{80, 0}}; Button addButton{&controlLayout, Size{80_sx, 0}};
Button editButton{&controlLayout, Size{80, 0}}; Button editButton{&controlLayout, Size{80_sx, 0}};
Button removeButton{&controlLayout, Size{80, 0}}; Button removeButton{&controlLayout, Size{80_sx, 0}};
}; };
struct ManifestViewer : TabFrameItem { struct ManifestViewer : TabFrameItem {

View File

@ -5,7 +5,7 @@ ifeq ($(platform),windows)
ifeq ($(hiro),windows) ifeq ($(hiro),windows)
hiro.flags = $(flags.cpp) -DHIRO_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 endif
ifeq ($(hiro),gtk2) ifeq ($(hiro),gtk2)
@ -14,7 +14,7 @@ ifeq ($(platform),windows)
endif endif
ifeq ($(hiro),gtk3) 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) hiro.options = $(shell pkg-config --libs gtk+-3.0 gtksourceview-3.0)
endif endif
endif endif
@ -41,12 +41,12 @@ ifneq ($(filter $(platform),linux bsd),)
endif endif
ifeq ($(hiro),gtk3) 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) hiro.options = -lX11 $(shell pkg-config --libs gtk+-3.0 gtksourceview-3.0)
endif endif
ifeq ($(hiro),qt4) 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.flags = $(flags.cpp) -DHIRO_QT=4 $(shell pkg-config --cflags QtCore QtGui)
hiro.options = -lX11 $(shell pkg-config --libs QtCore QtGui) hiro.options = -lX11 $(shell pkg-config --libs QtCore QtGui)
endif endif

View File

@ -28,7 +28,7 @@
} }
-(void) run:(NSTimer*)instance { -(void) run:(NSTimer*)instance {
if(Application::state().quit) return; if(hiro::Application::state().quit) return;
if(timer->enabled()) { if(timer->enabled()) {
timer->doActivate(); timer->doActivate();

View File

@ -113,6 +113,10 @@ auto pCanvas::minimumSize() const -> Size {
return {0, 0}; return {0, 0};
} }
auto pCanvas::setAlignment(Alignment) -> void {
update();
}
auto pCanvas::setColor(Color color) -> void { auto pCanvas::setColor(Color color) -> void {
update(); 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 { auto pCanvas::_rasterize() -> void {
@autoreleasepool { @autoreleasepool {
int width = 0; int width = 0;

View File

@ -27,6 +27,7 @@ struct pCanvas : pWidget {
Declare(Canvas, Widget) Declare(Canvas, Widget)
auto minimumSize() const -> Size; auto minimumSize() const -> Size;
auto setAlignment(Alignment) -> void;
auto setColor(Color color) -> void; auto setColor(Color color) -> void;
auto setDroppable(bool droppable) -> void; auto setDroppable(bool droppable) -> void;
auto setGeometry(Geometry geometry) -> void override; auto setGeometry(Geometry geometry) -> void override;

View File

@ -154,9 +154,7 @@ auto pTabFrame::_synchronizeSizable() -> void {
int selected = tabViewItem ? [cocoaView indexOfTabViewItem:tabViewItem] : -1; int selected = tabViewItem ? [cocoaView indexOfTabViewItem:tabViewItem] : -1;
for(auto& item : state().items) { for(auto& item : state().items) {
item->state.selected = item->offset() == selected; item->state.selected = item->offset() == selected;
if(auto& sizable = item->state.sizable) { if(auto& sizable = item->state.sizable) sizable->setVisible(item->selected());
if(auto self = sizable->self()) self->setVisible(sizable->visible(true) && item->selected());
}
} }
} }
} }

View File

@ -34,7 +34,6 @@ struct pTabFrame : pWidget {
auto _synchronizeSizable() -> void; auto _synchronizeSizable() -> void;
CocoaTabFrame* cocoaTabFrame = nullptr; CocoaTabFrame* cocoaTabFrame = nullptr;
vector<CocoaTabFrameItem*> tabs;
}; };
} }

View File

@ -242,6 +242,10 @@ auto pWindow::frameMargin() const -> Geometry {
} }
} }
auto pWindow::handle() const -> uintptr_t {
return (uintptr_t)cocoaWindow;
}
auto pWindow::monitor() const -> uint { auto pWindow::monitor() const -> uint {
//TODO //TODO
return 0; return 0;

View File

@ -35,6 +35,7 @@ struct pWindow : pObject {
auto append(sStatusBar statusBar) -> void; auto append(sStatusBar statusBar) -> void;
auto focused() const -> bool override; auto focused() const -> bool override;
auto frameMargin() const -> Geometry; auto frameMargin() const -> Geometry;
auto handle() const -> uintptr_t;
auto monitor() const -> uint; auto monitor() const -> uint;
auto remove(sMenuBar menuBar) -> void; auto remove(sMenuBar menuBar) -> void;
auto remove(sSizable sizable) -> void; auto remove(sSizable sizable) -> void;

View File

@ -95,18 +95,24 @@
#define Hiro_VerticalLayout #define Hiro_VerticalLayout
#define Hiro_TableLayout #define Hiro_TableLayout
#if defined(Hiro_Timer) && defined(Hiro_Canvas)
#define Hiro_HorizontalResizeGrip
#define Hiro_VerticalResizeGrip
#endif
#if defined(Hiro_TableView) #if defined(Hiro_TableView)
#define Hiro_ListView #define Hiro_ListView
#endif #endif
#if defined(Hiro_Button) && defined(Hiro_Canvas) && defined(Hiro_Label) #if defined(Hiro_Button) && defined(Hiro_Canvas) && defined(Hiro_Label)
#define Hiro_MessageDialog #define Hiro_MessageDialog
#define Hiro_NameDialog
#endif #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 #define Hiro_BrowserDialog
#endif #endif
#if defined(Hiro_Label) #if defined(Hiro_Canvas) && defined(Hiro_Label)
#define Hiro_AboutDialog #define Hiro_AboutDialog
#endif #endif

View File

@ -1,5 +1,7 @@
#if defined(Hiro_Alignment) #if defined(Hiro_Alignment)
const Alignment Alignment::Center = {0.5, 0.5};
Alignment::Alignment() { Alignment::Alignment() {
setAlignment(-1.0, -1.0); setAlignment(-1.0, -1.0);
} }

View File

@ -1,16 +1,21 @@
#if defined(Hiro_Application) #if defined(Hiro_Application)
auto Application::abort() -> void {
quit();
::abort();
}
auto Application::doMain() -> void { auto Application::doMain() -> void {
if(state().onMain) return state().onMain(); if(state().onMain) return state().onMain();
} }
auto Application::font() -> Font { auto Application::exit() -> void {
return state().font; quit();
::exit(EXIT_SUCCESS);
} }
auto Application::kill() -> void { auto Application::font() -> Font {
quit(); return state().font;
exit(EXIT_SUCCESS);
} }
auto Application::locale() -> Locale& { auto Application::locale() -> Locale& {
@ -134,7 +139,6 @@ auto Application::Cocoa::onQuit(const function<void ()>& callback) -> void {
auto Application::initialize() -> void { auto Application::initialize() -> void {
if(!state().initialized) { if(!state().initialized) {
state().initialized = true; state().initialized = true;
hiro::initialize();
pApplication::initialize(); pApplication::initialize();
pApplication::setScreenSaver(state().screenSaver); pApplication::setScreenSaver(state().screenSaver);
} }

View File

@ -2,9 +2,10 @@
struct Application { struct Application {
Application() = delete; Application() = delete;
static auto abort() -> void;
static auto doMain() -> void; static auto doMain() -> void;
static auto exit() -> void;
static auto font() -> Font; static auto font() -> Font;
static auto kill() -> void;
static auto locale() -> Locale&; static auto locale() -> Locale&;
static auto modal() -> bool; static auto modal() -> bool;
static auto name() -> string; static auto name() -> string;

View File

@ -1,4 +1,5 @@
#include <nall/platform.hpp> #include <nall/platform.hpp>
#include <nall/any.hpp>
#include <nall/chrono.hpp> #include <nall/chrono.hpp>
#include <nall/directory.hpp> #include <nall/directory.hpp>
#include <nall/function.hpp> #include <nall/function.hpp>
@ -17,6 +18,7 @@
#include <nall/utility.hpp> #include <nall/utility.hpp>
#include <nall/vector.hpp> #include <nall/vector.hpp>
using nall::any;
using nall::function; using nall::function;
using nall::image; using nall::image;
using nall::Locale; using nall::Locale;
@ -31,8 +33,6 @@ using nall::vector;
namespace hiro { namespace hiro {
auto initialize() -> void;
struct Font; struct Font;
struct Keyboard; struct Keyboard;
@ -158,6 +158,7 @@ struct Gradient {
#if defined(Hiro_Alignment) #if defined(Hiro_Alignment)
struct Alignment { struct Alignment {
using type = Alignment; using type = Alignment;
static const Alignment Center;
Alignment(); Alignment();
Alignment(float horizontal, float vertical = 0.5); Alignment(float horizontal, float vertical = 0.5);
@ -408,24 +409,7 @@ struct MessageWindow {
}; };
#endif #endif
struct Property { #include "property.hpp"
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;
};
#define Declare(Name) \ #define Declare(Name) \
using type = m##Name; \ using type = m##Name; \
@ -652,47 +636,7 @@ struct mButton : mWidget {
}; };
#endif #endif
#if defined(Hiro_Canvas) #include "widget/canvas.hpp"
struct mCanvas : mWidget {
Declare(Canvas)
auto color() const -> Color;
auto data() -> uint32_t*;
auto droppable() const -> bool;
auto doDrop(vector<string> 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<void (vector<string>)>& callback = {}) -> type&;
auto onMouseLeave(const function<void ()>& callback = {}) -> type&;
auto onMouseMove(const function<void (Position)>& callback = {}) -> type&;
auto onMousePress(const function<void (Mouse::Button)>& callback = {}) -> type&;
auto onMouseRelease(const function<void (Mouse::Button)>& 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<void (vector<string>)> onDrop;
function<void ()> onMouseLeave;
function<void (Position)> onMouseMove;
function<void (Mouse::Button)> onMousePress;
function<void (Mouse::Button)> onMouseRelease;
} state;
};
#endif
#if defined(Hiro_CheckButton) #if defined(Hiro_CheckButton)
struct mCheckButton : mWidget { struct mCheckButton : mWidget {

View File

@ -8,4 +8,19 @@ struct Monitor {
static auto primary() -> uint; static auto primary() -> uint;
static auto workspace(maybe<uint> monitor = nothing) -> Geometry; static auto workspace(maybe<uint> 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 #endif

View File

@ -249,13 +249,6 @@ auto mObject::parentWindow(bool recursive) const -> mWindow* {
} }
#endif #endif
auto mObject::property(const string& name) const -> string {
if(auto property = state.properties.find({name})) {
return property->value();
}
return {};
}
auto mObject::remove() -> type& { auto mObject::remove() -> type& {
signal(remove); signal(remove);
return *this; return *this;
@ -295,16 +288,6 @@ auto mObject::setParent(mObject* parent, int offset) -> type& {
return *this; 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& { auto mObject::setVisible(bool visible) -> type& {
state.visible = visible; state.visible = visible;
signal(setVisible, this->visible(true)); signal(setVisible, this->visible(true));

View File

@ -33,7 +33,6 @@ struct mObject {
auto parentTreeViewItem(bool recursive = false) const -> mTreeViewItem*; auto parentTreeViewItem(bool recursive = false) const -> mTreeViewItem*;
auto parentWidget(bool recursive = false) const -> mWidget*; auto parentWidget(bool recursive = false) const -> mWidget*;
auto parentWindow(bool recursive = false) const -> mWindow*; auto parentWindow(bool recursive = false) const -> mWindow*;
auto property(const string& name) const -> string;
virtual auto remove() -> type&; virtual auto remove() -> type&;
virtual auto reset() -> type&; virtual auto reset() -> type&;
virtual auto setEnabled(bool enabled = true) -> type&; virtual auto setEnabled(bool enabled = true) -> type&;
@ -41,10 +40,34 @@ struct mObject {
virtual auto setFont(const Font& font = {}) -> type&; virtual auto setFont(const Font& font = {}) -> type&;
virtual auto setGroup(sGroup group = {}) -> type&; virtual auto setGroup(sGroup group = {}) -> type&;
virtual auto setParent(mObject* parent = nullptr, int offset = -1) -> 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&; virtual auto setVisible(bool visible = true) -> type&;
auto visible(bool recursive = false) const -> bool; auto visible(bool recursive = false) const -> bool;
template<typename T = string> auto property(const string& name) const -> T {
if(auto property = state.properties.find(name)) {
if(property->value().is<T>()) return property->value().get<T>();
}
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<T>(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<typename T = string, typename U = string> auto setProperty(const string& name, const U& value) -> type& {
if constexpr(std::is_same_v<T, string> && !std::is_same_v<U, string>) {
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: //private:
//sizeof(mObject) == 88 //sizeof(mObject) == 88
struct State { struct State {

View File

@ -1,6 +1,6 @@
#if defined(Hiro_Property) #if defined(Hiro_Property)
Property::Property(const string& name, const string& value) { Property::Property(const string& name, const any& value) {
state.name = name; state.name = name;
state.value = value; state.value = value;
} }
@ -17,12 +17,12 @@ auto Property::name() const -> string {
return state.name; return state.name;
} }
auto Property::setValue(const string& value) -> type& { auto Property::setValue(const any& value) -> type& {
state.value = value; state.value = value;
return *this; return *this;
} }
auto Property::value() const -> string { auto Property::value() const -> any& {
return state.value; return state.value;
} }

20
hiro/core/property.hpp Normal file
View File

@ -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

View File

@ -38,12 +38,12 @@
} \ } \
return Object(); \ return Object(); \
} \ } \
auto property(const string& name) const { return self().property(name); } \ template<typename T = string> auto property(const string& name) const { return self().property<T>(name); } \
auto remove() { return self().remove(), *this; } \ auto remove() { return self().remove(), *this; } \
auto setEnabled(bool enabled = true) { return self().setEnabled(enabled), *this; } \ auto setEnabled(bool enabled = true) { return self().setEnabled(enabled), *this; } \
auto setFocused() { return self().setFocused(), *this; } \ auto setFocused() { return self().setFocused(), *this; } \
auto setFont(const Font& font = {}) { return self().setFont(font), *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<typename T = string, typename U = string> auto setProperty(const string& name, const U& value = {}) { return self().setProperty<T, U>(name, value), *this; } \
auto setVisible(bool visible = true) { return self().setVisible(visible), *this; } \ auto setVisible(bool visible = true) { return self().setVisible(visible), *this; } \
auto visible(bool recursive = false) const { return self().visible(recursive); } \ auto visible(bool recursive = false) const { return self().visible(recursive); } \
@ -210,6 +210,7 @@ struct Button : sButton {
struct Canvas : sCanvas { struct Canvas : sCanvas {
DeclareSharedWidget(Canvas) DeclareSharedWidget(Canvas)
auto alignment() const { return self().alignment(); }
auto color() const { return self().color(); } auto color() const { return self().color(); }
auto data() { return self().data(); } auto data() { return self().data(); }
auto droppable() const { return self().droppable(); } auto droppable() const { return self().droppable(); }
@ -225,6 +226,7 @@ struct Canvas : sCanvas {
auto onMouseMove(const function<void (Position)>& callback = {}) { return self().onMouseMove(callback), *this; } auto onMouseMove(const function<void (Position)>& callback = {}) { return self().onMouseMove(callback), *this; }
auto onMousePress(const function<void (Mouse::Button)>& callback = {}) { return self().onMousePress(callback), *this; } auto onMousePress(const function<void (Mouse::Button)>& callback = {}) { return self().onMousePress(callback), *this; }
auto onMouseRelease(const function<void (Mouse::Button)>& callback = {}) { return self().onMouseRelease(callback), *this; } auto onMouseRelease(const function<void (Mouse::Button)>& 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 setColor(Color color) { return self().setColor(color), *this; }
auto setDroppable(bool droppable = true) { return self().setDroppable(droppable), *this; } auto setDroppable(bool droppable = true) { return self().setDroppable(droppable), *this; }
auto setGradient(Gradient gradient = {}) { return self().setGradient(gradient), *this; } auto setGradient(Gradient gradient = {}) { return self().setGradient(gradient), *this; }
@ -761,6 +763,8 @@ struct TreeViewItem : sTreeViewItem {
auto backgroundColor() const { return self().backgroundColor(); } auto backgroundColor() const { return self().backgroundColor(); }
auto checkable() const { return self().checkable(); } auto checkable() const { return self().checkable(); }
auto checked() const { return self().checked(); } 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 expanded() const { return self().expanded(); }
auto foregroundColor() const { return self().foregroundColor(); } auto foregroundColor() const { return self().foregroundColor(); }
auto icon() const { return self().icon(); } auto icon() const { return self().icon(); }
@ -788,10 +792,12 @@ struct TreeView : sTreeView {
auto append(sTreeViewItem item) { return self().append(item), *this; } auto append(sTreeViewItem item) { return self().append(item), *this; }
auto backgroundColor() const { return self().backgroundColor(); } auto backgroundColor() const { return self().backgroundColor(); }
auto collapse(bool recursive = true) { return self().collapse(recursive), *this; }
auto doActivate() const { return self().doActivate(); } auto doActivate() const { return self().doActivate(); }
auto doChange() const { return self().doChange(); } auto doChange() const { return self().doChange(); }
auto doContext() const { return self().doContext(); } auto doContext() const { return self().doContext(); }
auto doToggle(sTreeViewItem item) const { return self().doToggle(item); } 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 foregroundColor() const { return self().foregroundColor(); }
auto item(const string& path) const { return self().item(path); } auto item(const string& path) const { return self().item(path); }
auto itemCount() const { return self().itemCount(); } auto itemCount() const { return self().itemCount(); }
@ -908,6 +914,7 @@ struct Window : sWindow {
auto frameGeometry() const { return self().frameGeometry(); } auto frameGeometry() const { return self().frameGeometry(); }
auto fullScreen() const { return self().fullScreen(); } auto fullScreen() const { return self().fullScreen(); }
auto geometry() const { return self().geometry(); } auto geometry() const { return self().geometry(); }
auto handle() const { return self().handle(); }
auto maximized() const { return self().maximized(); } auto maximized() const { return self().maximized(); }
auto maximumSize() const { return self().maximumSize(); } auto maximumSize() const { return self().maximumSize(); }
auto menuBar() const { return self().menuBar(); } auto menuBar() const { return self().menuBar(); }
@ -926,9 +933,9 @@ struct Window : sWindow {
auto remove(sStatusBar statusBar) { return self().remove(statusBar), *this; } auto remove(sStatusBar statusBar) { return self().remove(statusBar), *this; }
auto reset() { return self().reset(), *this; } auto reset() { return self().reset(), *this; }
auto resizable() const { return self().resizable(); } 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 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 setDismissable(bool dismissable = true) { return self().setDismissable(dismissable), *this; }
auto setDroppable(bool droppable = true) { return self().setDroppable(droppable), *this; } auto setDroppable(bool droppable = true) { return self().setDroppable(droppable), *this; }
auto setFrameGeometry(Geometry geometry) { return self().setFrameGeometry(geometry), *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 setMinimumSize(Size size = {}) { return self().setMinimumSize(size), *this; }
auto setModal(bool modal = true) { return self().setModal(modal), *this; } auto setModal(bool modal = true) { return self().setModal(modal), *this; }
auto setPosition(Position position) { return self().setPosition(position), *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 setResizable(bool resizable = true) { return self().setResizable(resizable), *this; }
auto setSize(Size size) { return self().setSize(size), *this; } auto setSize(Size size) { return self().setSize(size), *this; }
auto setTitle(const string& title = "") { return self().setTitle(title), *this; } auto setTitle(const string& title = "") { return self().setTitle(title), *this; }

View File

@ -6,6 +6,10 @@ auto mCanvas::allocate() -> pObject* {
// //
auto mCanvas::alignment() const -> Alignment {
return state.alignment;
}
auto mCanvas::color() const -> Color { auto mCanvas::color() const -> Color {
return state.color; return state.color;
} }
@ -71,6 +75,12 @@ auto mCanvas::onMouseRelease(const function<void (Mouse::Button)>& callback) ->
return *this; return *this;
} }
auto mCanvas::setAlignment(Alignment alignment) -> type& {
state.alignment = alignment;
signal(setAlignment, alignment);
return *this;
}
auto mCanvas::setColor(Color color) -> type& { auto mCanvas::setColor(Color color) -> type& {
state.color = color; state.color = color;
state.gradient = {}; state.gradient = {};

View File

@ -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<string> 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<void (vector<string>)>& callback = {}) -> type&;
auto onMouseLeave(const function<void ()>& callback = {}) -> type&;
auto onMouseMove(const function<void (Position)>& callback = {}) -> type&;
auto onMousePress(const function<void (Mouse::Button)>& callback = {}) -> type&;
auto onMouseRelease(const function<void (Mouse::Button)>& 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<void (vector<string>)> onDrop;
function<void ()> onMouseLeave;
function<void (Position)> onMouseMove;
function<void (Mouse::Button)> onMousePress;
function<void (Mouse::Button)> onMouseRelease;
} state;
};
#endif

Some files were not shown because too many files have changed in this diff Show More