mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
7786206a4f
commit
4d7bb510f2
|
@ -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
|
|
@ -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>
|
|
@ -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 |
|
@ -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 |
|
@ -1,2 +0,0 @@
|
|||
1 24 "genius.Manifest"
|
||||
2 ICON DISCARDABLE "genius.ico"
|
|
@ -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 |
|
@ -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();
|
||||
}
|
|
@ -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{¬eLayout, Size{50, 0}};
|
||||
LineEdit noteEdit{¬eLayout, Size{~0, 0}};
|
||||
HorizontalLayout lowerLayout{&layout, Size{~0, ~0}};
|
||||
Label componentLabel{&lowerLayout, Size{50, ~0}};
|
||||
TreeView componentTree{&lowerLayout, Size{~0, ~0}};
|
||||
VerticalLayout controlLayout{&lowerLayout, Size{0, ~0}};
|
||||
Button appendMemoryButton{&controlLayout, Size{80, 0}};
|
||||
Button appendOscillatorButton{&controlLayout, Size{80, 0}};
|
||||
Button modifyComponentButton{&controlLayout, Size{80, 0}};
|
||||
Button removeComponentButton{&controlLayout, Size{80, 0}};
|
||||
Widget controlSpacer{&controlLayout, Size{0, ~0}};
|
||||
Button acceptButton{&controlLayout, Size{80, 0}};
|
||||
Button cancelButton{&controlLayout, Size{80, 0}};
|
||||
};
|
||||
|
||||
struct MemoryWindow : Window {
|
||||
MemoryWindow();
|
||||
auto show(Memory = {}) -> void;
|
||||
auto accept() -> void;
|
||||
auto cancel() -> void;
|
||||
auto updateWindow() -> void;
|
||||
|
||||
private:
|
||||
bool modified = false;
|
||||
bool create = true;
|
||||
Memory memory;
|
||||
|
||||
VerticalLayout layout{this};
|
||||
HorizontalLayout infoLayout{&layout, Size{~0, 0}};
|
||||
Label typeLabel{&infoLayout, Size{80, 0}};
|
||||
ComboEdit typeEdit{&infoLayout, Size{~0, 0}};
|
||||
Label sizeLabel{&infoLayout, Size{0, 0}};
|
||||
LineEdit sizeEdit{&infoLayout, Size{~0, 0}};
|
||||
HorizontalLayout contentLayout{&layout, Size{~0, 0}};
|
||||
Label contentLabel{&contentLayout, Size{80, 0}};
|
||||
ComboEdit contentEdit{&contentLayout, Size{~0, 0}};
|
||||
HorizontalLayout manufacturerLayout{&layout, Size{~0, 0}};
|
||||
Label manufacturerLabel{&manufacturerLayout, Size{80, 0}};
|
||||
LineEdit manufacturerEdit{&manufacturerLayout, Size{~0, 0}};
|
||||
HorizontalLayout architectureLayout{&layout, Size{~0, 0}};
|
||||
Label architectureLabel{&architectureLayout, Size{80, 0}};
|
||||
LineEdit architectureEdit{&architectureLayout, Size{~0, 0}};
|
||||
HorizontalLayout identifierLayout{&layout, Size{~0, 0}};
|
||||
Label identifierLabel{&identifierLayout, Size{80, 0}};
|
||||
LineEdit identifierEdit{&identifierLayout, Size{~0, 0}};
|
||||
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
|
||||
Widget controlSpacer{&controlLayout, Size{~0, 0}};
|
||||
CheckLabel volatileOption{&controlLayout, Size{0, 0}};
|
||||
Button acceptButton{&controlLayout, Size{80, 0}};
|
||||
Button cancelButton{&controlLayout, Size{80, 0}};
|
||||
};
|
||||
|
||||
struct OscillatorWindow : Window {
|
||||
OscillatorWindow();
|
||||
auto show(Oscillator = {}) -> void;
|
||||
auto accept() -> void;
|
||||
auto cancel() -> void;
|
||||
auto updateWindow() -> void;
|
||||
|
||||
private:
|
||||
bool modified = false;
|
||||
bool create = true;
|
||||
Oscillator oscillator;
|
||||
|
||||
VerticalLayout layout{this};
|
||||
HorizontalLayout frequencyLayout{&layout, Size{~0, 0}};
|
||||
Label frequencyLabel{&frequencyLayout, Size{60, 0}};
|
||||
LineEdit frequencyEdit{&frequencyLayout, Size{~0, 0}};
|
||||
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
|
||||
Widget controlSpacer{&controlLayout, Size{~0, 0}};
|
||||
Button acceptButton{&controlLayout, Size{80, 0}};
|
||||
Button cancelButton{&controlLayout, Size{80, 0}};
|
||||
};
|
|
@ -1,2 +0,0 @@
|
|||
*.o
|
||||
*.d
|
|
@ -1 +0,0 @@
|
|||
genius
|
|
@ -31,7 +31,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "107";
|
||||
static const string Version = "107.1";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "https://byuu.org/";
|
||||
|
|
|
@ -10,6 +10,7 @@ objects += sfc-armdsp sfc-hitachidsp sfc-necdsp
|
|||
objects += sfc-epsonrtc sfc-sharprtc
|
||||
objects += sfc-spc7110 sfc-sdd1
|
||||
objects += sfc-obc1 sfc-msu1
|
||||
objects += sfc-cx4 sfc-dsp1 sfc-dsp2 sfc-dsp4 sfc-st0010
|
||||
objects += sfc-bsmemory sfc-sufamiturbo
|
||||
|
||||
obj/sfc-interface.o: sfc/interface/interface.cpp
|
||||
|
@ -49,5 +50,11 @@ obj/sfc-obc1.o: sfc/coprocessor/obc1/obc1.cpp
|
|||
|
||||
obj/sfc-msu1.o: sfc/coprocessor/msu1/msu1.cpp
|
||||
|
||||
obj/sfc-cx4.o: sfc/coprocessor/cx4/cx4.cpp
|
||||
obj/sfc-dsp1.o: sfc/coprocessor/dsp1/dsp1.cpp
|
||||
obj/sfc-dsp2.o: sfc/coprocessor/dsp2/dsp2.cpp
|
||||
obj/sfc-dsp4.o: sfc/coprocessor/dsp4/dsp4.cpp
|
||||
obj/sfc-st0010.o: sfc/coprocessor/st0010/st0010.cpp
|
||||
|
||||
obj/sfc-bsmemory.o: sfc/slot/bsmemory/bsmemory.cpp
|
||||
obj/sfc-sufamiturbo.o: sfc/slot/sufamiturbo/sufamiturbo.cpp
|
||||
|
|
|
@ -38,6 +38,12 @@ struct Cartridge {
|
|||
boolean OBC1;
|
||||
boolean MSU1;
|
||||
|
||||
boolean Cx4;
|
||||
boolean DSP1;
|
||||
boolean DSP2;
|
||||
boolean DSP4;
|
||||
boolean ST0010;
|
||||
|
||||
boolean GameBoySlot;
|
||||
boolean BSMemorySlot;
|
||||
boolean SufamiTurboSlotA;
|
||||
|
|
|
@ -406,8 +406,6 @@ auto Cartridge::loadARMDSP(Markup::Node node) -> void {
|
|||
|
||||
//processor(architecture=HG51BS169)
|
||||
auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void {
|
||||
has.HitachiDSP = true;
|
||||
|
||||
for(auto& word : hitachidsp.dataROM) word = 0x000000;
|
||||
for(auto& word : hitachidsp.dataRAM) word = 0x00;
|
||||
|
||||
|
@ -419,10 +417,6 @@ auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void {
|
|||
hitachidsp.Roms = roms; //1 or 2
|
||||
hitachidsp.Mapping = 0; //0 or 1
|
||||
|
||||
for(auto map : node.find("map")) {
|
||||
loadMap(map, {&HitachiDSP::readIO, &hitachidsp}, {&HitachiDSP::writeIO, &hitachidsp});
|
||||
}
|
||||
|
||||
if(auto memory = node["memory(type=ROM,content=Program)"]) {
|
||||
loadMemory(hitachidsp.rom, memory, File::Required);
|
||||
for(auto map : memory.find("map")) {
|
||||
|
@ -437,6 +431,19 @@ auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
if(configuration.hacks.coprocessors.hle) {
|
||||
has.Cx4 = true;
|
||||
for(auto map : node.find("map")) {
|
||||
loadMap(map, {&Cx4::read, &cx4}, {&Cx4::write, &cx4});
|
||||
}
|
||||
if(auto memory = node["memory(type=RAM,content=Data,architecture=HG51BS169)"]) {
|
||||
for(auto map : memory.find("map")) {
|
||||
loadMap(map, {&Cx4::read, &cx4}, {&Cx4::write, &cx4});
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(auto memory = node["memory(type=ROM,content=Data,architecture=HG51BS169)"]) {
|
||||
if(auto file = game.memory(memory)) {
|
||||
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read, File::Required)) {
|
||||
|
@ -455,13 +462,16 @@ auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void {
|
|||
loadMap(map, {&HitachiDSP::readDRAM, &hitachidsp}, {&HitachiDSP::writeDRAM, &hitachidsp});
|
||||
}
|
||||
}
|
||||
|
||||
has.HitachiDSP = true;
|
||||
|
||||
for(auto map : node.find("map")) {
|
||||
loadMap(map, {&HitachiDSP::readIO, &hitachidsp}, {&HitachiDSP::writeIO, &hitachidsp});
|
||||
}
|
||||
}
|
||||
|
||||
//processor(architecture=uPD7725)
|
||||
auto Cartridge::loaduPD7725(Markup::Node node) -> void {
|
||||
has.NECDSP = true;
|
||||
necdsp.revision = NECDSP::Revision::uPD7725;
|
||||
|
||||
for(auto& word : necdsp.programROM) word = 0x000000;
|
||||
for(auto& word : necdsp.dataROM) word = 0x0000;
|
||||
for(auto& word : necdsp.dataRAM) word = 0x0000;
|
||||
|
@ -472,26 +482,55 @@ auto Cartridge::loaduPD7725(Markup::Node node) -> void {
|
|||
necdsp.Frequency = 7'600'000;
|
||||
}
|
||||
|
||||
for(auto map : node.find("map")) {
|
||||
loadMap(map, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
|
||||
}
|
||||
bool failed = false;
|
||||
|
||||
if(auto memory = node["memory(type=ROM,content=Program,architecture=uPD7725)"]) {
|
||||
if(auto file = game.memory(memory)) {
|
||||
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read, File::Required)) {
|
||||
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) {
|
||||
for(auto n : range(2048)) necdsp.programROM[n] = fp->readl(3);
|
||||
}
|
||||
} else failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(auto memory = node["memory(type=ROM,content=Data,architecture=uPD7725)"]) {
|
||||
if(auto file = game.memory(memory)) {
|
||||
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read, File::Required)) {
|
||||
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) {
|
||||
for(auto n : range(1024)) necdsp.dataROM[n] = fp->readl(2);
|
||||
}
|
||||
} else failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(failed || configuration.hacks.coprocessors.hle) {
|
||||
auto manifest = BML::serialize(game.document);
|
||||
if(manifest.find("identifier: DSP1")) { //also matches DSP1B
|
||||
has.DSP1 = true;
|
||||
for(auto map : node.find("map")) {
|
||||
loadMap(map, {&DSP1::read, &dsp1}, {&DSP1::write, &dsp1});
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(manifest.find("identifier: DSP2")) {
|
||||
has.DSP2 = true;
|
||||
for(auto map : node.find("map")) {
|
||||
loadMap(map, {&DSP2::read, &dsp2}, {&DSP2::write, &dsp2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(manifest.find("identifier: DSP4")) {
|
||||
has.DSP4 = true;
|
||||
for(auto map : node.find("map")) {
|
||||
loadMap(map, {&DSP4::read, &dsp4}, {&DSP4::write, &dsp4});
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(failed) {
|
||||
//throw an error to the user
|
||||
platform->open(ID::SuperFamicom, "<DSP1-4>", File::Read, File::Required);
|
||||
return;
|
||||
}
|
||||
|
||||
if(auto memory = node["memory(type=RAM,content=Data,architecture=uPD7725)"]) {
|
||||
if(auto file = game.memory(memory)) {
|
||||
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) {
|
||||
|
@ -502,13 +541,17 @@ auto Cartridge::loaduPD7725(Markup::Node node) -> void {
|
|||
loadMap(map, {&NECDSP::readRAM, &necdsp}, {&NECDSP::writeRAM, &necdsp});
|
||||
}
|
||||
}
|
||||
|
||||
has.NECDSP = true;
|
||||
necdsp.revision = NECDSP::Revision::uPD7725;
|
||||
|
||||
for(auto map : node.find("map")) {
|
||||
loadMap(map, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
|
||||
}
|
||||
}
|
||||
|
||||
//processor(architecture=uPD96050)
|
||||
auto Cartridge::loaduPD96050(Markup::Node node) -> void {
|
||||
has.NECDSP = true;
|
||||
necdsp.revision = NECDSP::Revision::uPD96050;
|
||||
|
||||
for(auto& word : necdsp.programROM) word = 0x000000;
|
||||
for(auto& word : necdsp.dataROM) word = 0x0000;
|
||||
for(auto& word : necdsp.dataRAM) word = 0x0000;
|
||||
|
@ -519,26 +562,43 @@ auto Cartridge::loaduPD96050(Markup::Node node) -> void {
|
|||
necdsp.Frequency = 11'000'000;
|
||||
}
|
||||
|
||||
for(auto map : node.find("map")) {
|
||||
loadMap(map, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
|
||||
}
|
||||
bool failed = false;
|
||||
|
||||
if(auto memory = node["memory(type=ROM,content=Program,architecture=uPD96050)"]) {
|
||||
if(auto file = game.memory(memory)) {
|
||||
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read, File::Required)) {
|
||||
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) {
|
||||
for(auto n : range(16384)) necdsp.programROM[n] = fp->readl(3);
|
||||
}
|
||||
} else failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(auto memory = node["memory(type=ROM,content=Data,architecture=uPD96050)"]) {
|
||||
if(auto file = game.memory(memory)) {
|
||||
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read, File::Required)) {
|
||||
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) {
|
||||
for(auto n : range(2048)) necdsp.dataROM[n] = fp->readl(2);
|
||||
}
|
||||
} else failed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(failed || configuration.hacks.coprocessors.hle) {
|
||||
auto manifest = BML::serialize(game.document);
|
||||
if(manifest.find("identifier: ST010")) {
|
||||
has.ST0010 = true;
|
||||
if(auto memory = node["memory(type=RAM,content=Data,architecture=uPD96050)"]) {
|
||||
for(auto map : memory.find("map")) {
|
||||
loadMap(map, {&ST0010::read, &st0010}, {&ST0010::write, &st0010});
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(failed) {
|
||||
//throw an error to the user
|
||||
platform->open(ID::SuperFamicom, "<ST010-011>", File::Read, File::Required);
|
||||
return;
|
||||
}
|
||||
|
||||
if(auto memory = node["memory(type=RAM,content=Data,architecture=uPD96050)"]) {
|
||||
if(auto file = game.memory(memory)) {
|
||||
if(auto fp = platform->open(ID::SuperFamicom, file->name(), File::Read)) {
|
||||
|
@ -549,6 +609,13 @@ auto Cartridge::loaduPD96050(Markup::Node node) -> void {
|
|||
loadMap(map, {&NECDSP::readRAM, &necdsp}, {&NECDSP::writeRAM, &necdsp});
|
||||
}
|
||||
}
|
||||
|
||||
has.NECDSP = true;
|
||||
necdsp.revision = NECDSP::Revision::uPD96050;
|
||||
|
||||
for(auto map : node.find("map")) {
|
||||
loadMap(map, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
|
||||
}
|
||||
}
|
||||
|
||||
//rtc(manufacturer=Epson)
|
||||
|
|
|
@ -18,3 +18,9 @@
|
|||
#include <sfc/coprocessor/obc1/obc1.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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
auto ST0010::serialize(serializer& s) -> void {
|
||||
s.array(ram);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -20,6 +20,7 @@ auto Configuration::process(Markup::Node document, bool load) -> void {
|
|||
bind(boolean, "Hacks/FastPPU/NoSpriteLimit", hacks.ppuFast.noSpriteLimit);
|
||||
bind(boolean, "Hacks/FastPPU/HiresMode7", hacks.ppuFast.hiresMode7);
|
||||
bind(boolean, "Hacks/FastDSP/Enable", hacks.dspFast.enable);
|
||||
bind(boolean, "Hacks/Coprocessors/HLE", hacks.coprocessors.hle);
|
||||
bind(boolean, "Hacks/Coprocessors/DelayedSync", hacks.coprocessors.delayedSync);
|
||||
|
||||
#undef bind
|
||||
|
|
|
@ -35,6 +35,7 @@ struct Configuration {
|
|||
} dspFast;
|
||||
struct Coprocessors {
|
||||
bool delayedSync = true;
|
||||
bool hle = true;
|
||||
} coprocessors;
|
||||
} hacks;
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ struct Bus {
|
|||
|
||||
~Bus();
|
||||
|
||||
alwaysinline auto read(uint24 address, uint8 data) -> uint8;
|
||||
alwaysinline auto read(uint24 address, uint8 data = 0) -> uint8;
|
||||
alwaysinline auto write(uint24 address, uint8 data) -> void;
|
||||
|
||||
auto reset() -> void;
|
||||
|
|
|
@ -53,7 +53,8 @@ auto PPU::readOAM(uint10 address) -> uint8 {
|
|||
|
||||
auto PPU::writeOAM(uint10 address, uint8 data) -> void {
|
||||
Line::flush();
|
||||
if(!io.displayDisable && cpu.vcounter() < vdisp()) address = latch.oamAddress;
|
||||
//Uniracers 2-player mode hack
|
||||
if(!io.displayDisable && cpu.vcounter() < vdisp()) address = 0x0218; //latch.oamAddress;
|
||||
return writeObject(address, data);
|
||||
}
|
||||
|
||||
|
|
|
@ -137,8 +137,6 @@ auto PPU::Object::tilefetch() -> void {
|
|||
uint16 addr = (pos & 0xfff0) + (y & 7);
|
||||
|
||||
oamTile[n].data.bits( 0,15) = ppu.vram[addr + 0];
|
||||
ppu.step(2);
|
||||
|
||||
oamTile[n].data.bits(16,31) = ppu.vram[addr + 8];
|
||||
ppu.step(2);
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ auto PPU::main() -> void {
|
|||
step(2);
|
||||
}
|
||||
|
||||
step(14);
|
||||
step(14 + 34 * 2);
|
||||
obj.tilefetch();
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,12 @@ auto System::serializeAll(serializer& s) -> void {
|
|||
if(cartridge.has.OBC1) obc1.serialize(s);
|
||||
if(cartridge.has.MSU1) msu1.serialize(s);
|
||||
|
||||
if(cartridge.has.Cx4) cx4.serialize(s);
|
||||
if(cartridge.has.DSP1) dsp1.serialize(s);
|
||||
if(cartridge.has.DSP2) dsp2.serialize(s);
|
||||
if(cartridge.has.DSP4) dsp4.serialize(s);
|
||||
if(cartridge.has.ST0010) st0010.serialize(s);
|
||||
|
||||
if(cartridge.has.BSMemorySlot) bsmemory.serialize(s);
|
||||
if(cartridge.has.SufamiTurboSlotA) sufamiturboA.serialize(s);
|
||||
if(cartridge.has.SufamiTurboSlotB) sufamiturboB.serialize(s);
|
||||
|
|
|
@ -111,6 +111,11 @@ auto System::power(bool reset) -> void {
|
|||
if(cartridge.has.SDD1) sdd1.power();
|
||||
if(cartridge.has.OBC1) obc1.power();
|
||||
if(cartridge.has.MSU1) msu1.power();
|
||||
if(cartridge.has.Cx4) cx4.power();
|
||||
if(cartridge.has.DSP1) dsp1.power();
|
||||
if(cartridge.has.DSP2) dsp2.power();
|
||||
if(cartridge.has.DSP4) dsp4.power();
|
||||
if(cartridge.has.ST0010) st0010.power();
|
||||
if(cartridge.has.BSMemorySlot) bsmemory.power();
|
||||
if(cartridge.has.SufamiTurboSlotA) sufamiturboA.power();
|
||||
if(cartridge.has.SufamiTurboSlotB) sufamiturboB.power();
|
||||
|
|
|
@ -237,7 +237,7 @@ board: SHVC-1CB0N7S-01
|
|||
map address=00-3f,80-bf:6000-7fff size=0x2000
|
||||
map address=70-71:0000-ffff
|
||||
|
||||
board: SHVC-1CB5B-20
|
||||
board: SHVC-1CB5B-(01,20)
|
||||
processor architecture=GSU
|
||||
map address=00-3f,80-bf:3000-34ff
|
||||
memory type=ROM content=Program
|
||||
|
|
|
@ -18,10 +18,6 @@ auto locate(string name) -> string {
|
|||
return {Path::userData(), "bsnes/", name};
|
||||
}
|
||||
|
||||
auto hiro::initialize() -> void {
|
||||
Application::setName("bsnes");
|
||||
}
|
||||
|
||||
#include <nall/main.hpp>
|
||||
auto nall::main(Arguments arguments) -> void {
|
||||
settings.location = locate("settings.bml");
|
||||
|
@ -45,6 +41,7 @@ auto nall::main(Arguments arguments) -> void {
|
|||
}
|
||||
|
||||
settings.load();
|
||||
Application::setName("bsnes");
|
||||
Application::setScreenSaver(settings.general.screenSaver);
|
||||
Application::setToolTips(settings.general.toolTips);
|
||||
emulator = new SuperFamicom::Interface;
|
||||
|
|
|
@ -46,9 +46,11 @@ auto InputManager::bindHotkeys() -> void {
|
|||
hotkeys.append(InputHotkey("Fast Forward").onPress([] {
|
||||
video.setBlocking(false);
|
||||
audio.setBlocking(false);
|
||||
audio.setDynamic(false);
|
||||
}).onRelease([] {
|
||||
video.setBlocking(settings.video.blocking);
|
||||
audio.setBlocking(settings.audio.blocking);
|
||||
audio.setDynamic(settings.audio.dynamic);
|
||||
}));
|
||||
|
||||
hotkeys.append(InputHotkey("Pause Emulation").onPress([] {
|
||||
|
|
|
@ -104,7 +104,7 @@ auto Presentation::create() -> void {
|
|||
program.loadState("Quick/Redo");
|
||||
}));
|
||||
loadState.append(MenuItem().setIcon(Icon::Edit::Clear).setText("Remove All States").onActivate([&] {
|
||||
if(MessageDialog("Are you sure you want to permanently remove all quick states for this game?").setParent(*this).question() == "Yes") {
|
||||
if(MessageDialog("Are you sure you want to permanently remove all quick states for this game?").setAlignment(*this).question() == "Yes") {
|
||||
for(uint index : range(QuickStates)) program.removeState({"Quick/Slot ", 1 + index});
|
||||
program.removeState("Quick/Undo");
|
||||
program.removeState("Quick/Redo");
|
||||
|
@ -141,7 +141,7 @@ auto Presentation::create() -> void {
|
|||
.setAuthor("byuu")
|
||||
.setLicense("GPLv3")
|
||||
.setWebsite("https://byuu.org/")
|
||||
.setParent(*this)
|
||||
.setAlignment(*this)
|
||||
.show();
|
||||
});
|
||||
|
||||
|
@ -195,7 +195,7 @@ auto Presentation::create() -> void {
|
|||
setTitle({"bsnes v", Emulator::Version});
|
||||
setBackgroundColor({0, 0, 0});
|
||||
resizeWindow();
|
||||
setCentered();
|
||||
setAlignment(Alignment::Center);
|
||||
setFullScreen(startFullScreen);
|
||||
|
||||
#if defined(PLATFORM_MACOS)
|
||||
|
@ -324,7 +324,7 @@ auto Presentation::toggleFullscreenMode() -> void {
|
|||
menuBar.setVisible(true);
|
||||
if(settings.general.statusBar) layout.append(statusLayout, Size{~0, StatusHeight});
|
||||
resizeWindow();
|
||||
setCentered();
|
||||
setAlignment(Alignment::Center);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,7 +419,7 @@ auto Presentation::updateSizeMenu() -> void {
|
|||
resizeWindow();
|
||||
}));
|
||||
sizeMenu.append(MenuItem().setIcon(Icon::Place::Settings).setText("Center Window").onActivate([&] {
|
||||
setCentered();
|
||||
setAlignment(Alignment::Center);
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ auto Program::updateAudioDriver(Window parent) -> void {
|
|||
if(!audio.ready()) {
|
||||
MessageDialog({
|
||||
"Error: failed to initialize [", settings.audio.driver, "] audio driver."
|
||||
}).setParent(parent).error();
|
||||
}).setAlignment(parent).error();
|
||||
settings.audio.driver = "None";
|
||||
return updateAudioDriver(parent);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ auto Program::load() -> void {
|
|||
"Warning: this game image is unverified.\n"
|
||||
"Running it *may* be a security risk.\n\n"
|
||||
"Do you wish to run the game anyway?"
|
||||
).setParent(*presentation).question({"Always", "Yes", "No"});
|
||||
).setAlignment(*presentation).question({"Always", "Yes", "No"});
|
||||
if(response == "No") {
|
||||
emulator->unload();
|
||||
return showMessage("Game loading cancelled");
|
||||
|
|
|
@ -12,7 +12,7 @@ auto Program::updateInputDriver(Window parent) -> void {
|
|||
if(!input.ready()) {
|
||||
MessageDialog({
|
||||
"Error: failed to initialize [", settings.input.driver, "] input driver."
|
||||
}).setParent(parent).error();
|
||||
}).setAlignment(parent).error();
|
||||
settings.input.driver = "None";
|
||||
return updateInputDriver(parent);
|
||||
}
|
||||
|
|
|
@ -119,6 +119,6 @@ auto Program::applyPatchBPS(vector<uint8_t>& input, string location) -> bool {
|
|||
MessageDialog({
|
||||
error, "\n\n",
|
||||
"Please ensure you are using the correct (headerless) ROM for this patch."
|
||||
}).setParent(*presentation).error();
|
||||
}).setAlignment(*presentation).error();
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) ->
|
|||
if(MessageDialog({
|
||||
"Error: missing required data: ", name, "\n\n",
|
||||
"Would you like to view the online documentation for more information?"
|
||||
}).setParent(*presentation).error({"Yes", "No"}) == "Yes") {
|
||||
}).setAlignment(*presentation).error({"Yes", "No"}) == "Yes") {
|
||||
presentation.documentation.doActivate();
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) ->
|
|||
|
||||
auto Program::load(uint id, string name, string type, vector<string> options) -> Emulator::Platform::Load {
|
||||
BrowserDialog dialog;
|
||||
dialog.setParent(*presentation);
|
||||
dialog.setAlignment(*presentation);
|
||||
dialog.setOptions(options);
|
||||
|
||||
if(id == 1 && name == "Super Famicom" && type == "sfc") {
|
||||
|
|
|
@ -40,7 +40,7 @@ auto Program::create() -> void {
|
|||
MessageDialog(
|
||||
"Driver crash detected. Hardware drivers have been disabled.\n"
|
||||
"Please reconfigure drivers in the advanced settings panel."
|
||||
).setParent(*presentation).information();
|
||||
).setAlignment(*presentation).information();
|
||||
settings.video.driver = "None";
|
||||
settings.audio.driver = "None";
|
||||
settings.input.driver = "None";
|
||||
|
@ -90,5 +90,5 @@ auto Program::quit() -> void {
|
|||
video.reset();
|
||||
audio.reset();
|
||||
input.reset();
|
||||
Application::kill();
|
||||
Application::exit();
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ auto Program::updateVideoDriver(Window parent) -> void {
|
|||
if(!video.ready()) {
|
||||
MessageDialog({
|
||||
"Error: failed to initialize [", settings.video.driver, "] video driver."
|
||||
}).setParent(parent).error();
|
||||
}).setAlignment(parent).error();
|
||||
settings.video.driver = "None";
|
||||
return updateVideoDriver(parent);
|
||||
}
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
</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>
|
||||
<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:application>
|
||||
</assembly>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,7 @@ namespace Resource {
|
|||
extern const unsigned char Icon[3463];
|
||||
extern const unsigned char Logo[23467];
|
||||
namespace System {
|
||||
extern const char Boards[30183];
|
||||
extern const char Boards[30188];
|
||||
extern const unsigned char IPLROM[64];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ auto AudioSettings::create() -> void {
|
|||
setIcon(Icon::Device::Speaker);
|
||||
setText("Audio");
|
||||
|
||||
layout.setPadding(5);
|
||||
layout.setPadding(5_sx);
|
||||
|
||||
effectsLabel.setFont(Font().setBold()).setText("Effects");
|
||||
effectsLayout.setSize({3, 3});
|
||||
|
|
|
@ -2,7 +2,7 @@ auto DriverSettings::create() -> void {
|
|||
setIcon(Icon::Place::Settings);
|
||||
setText("Drivers");
|
||||
|
||||
layout.setPadding(5);
|
||||
layout.setPadding(5_sx);
|
||||
|
||||
videoLabel.setText("Video").setFont(Font().setBold());
|
||||
videoLayout.setSize({2, 2});
|
||||
|
@ -77,7 +77,7 @@ auto DriverSettings::create() -> void {
|
|||
presentation.speedMenu.setEnabled(!videoBlockingToggle.checked() && audioBlockingToggle.checked());
|
||||
});
|
||||
audioDynamicToggle.setText("Dynamic rate").setToolTip(
|
||||
"(OSS, XAudio drivers only)\n\n"
|
||||
"(OSS, XAudio2, waveOut drivers only)\n\n"
|
||||
"Dynamically adjusts the audio frequency by tiny amounts.\n"
|
||||
"Use this with video sync enabled, and audio sync disabled.\n\n"
|
||||
"This can produce perfectly smooth video and clean audio,\n"
|
||||
|
@ -132,7 +132,7 @@ auto DriverSettings::videoDriverChange() -> void {
|
|||
"Warning: incompatible drivers may cause bsnes to crash.\n"
|
||||
"It is highly recommended you unload your game first to be safe.\n"
|
||||
"Do you wish to proceed with the video driver change now anyway?"
|
||||
).setParent(*settingsWindow).question() == "Yes") {
|
||||
).setAlignment(*settingsWindow).question() == "Yes") {
|
||||
program.save();
|
||||
program.saveUndoState();
|
||||
settings.general.crashed = true;
|
||||
|
@ -189,7 +189,7 @@ auto DriverSettings::audioDriverChange() -> void {
|
|||
"Warning: incompatible drivers may cause bsnes to crash.\n"
|
||||
"It is highly recommended you unload your game first to be safe.\n"
|
||||
"Do you wish to proceed with the audio driver change now anyway?"
|
||||
).setParent(*settingsWindow).question() == "Yes") {
|
||||
).setAlignment(*settingsWindow).question() == "Yes") {
|
||||
program.save();
|
||||
program.saveUndoState();
|
||||
settings.general.crashed = true;
|
||||
|
@ -275,7 +275,7 @@ auto DriverSettings::inputDriverChange() -> void {
|
|||
"Warning: incompatible drivers may cause bsnes to crash.\n"
|
||||
"It is highly recommended you unload your game first to be safe.\n"
|
||||
"Do you wish to proceed with the input driver change now anyway?"
|
||||
).setParent(*settingsWindow).question() == "Yes") {
|
||||
).setAlignment(*settingsWindow).question() == "Yes") {
|
||||
program.save();
|
||||
program.saveUndoState();
|
||||
settings.general.crashed = true;
|
||||
|
|
|
@ -2,7 +2,7 @@ auto EmulatorSettings::create() -> void {
|
|||
setIcon(Icon::Action::Settings);
|
||||
setText("Emulator");
|
||||
|
||||
layout.setPadding(5);
|
||||
layout.setPadding(5_sx);
|
||||
|
||||
optionsLabel.setText("Options").setFont(Font().setBold());
|
||||
inputFocusLabel.setText("When focus is lost:");
|
||||
|
@ -60,6 +60,9 @@ auto EmulatorSettings::create() -> void {
|
|||
coprocessorsDelayedSyncOption.setText("Fast coprocessors (delayed sync)").setChecked(settings.emulator.hack.coprocessors.delayedSync).onToggle([&] {
|
||||
settings.emulator.hack.coprocessors.delayedSync = coprocessorsDelayedSyncOption.checked();
|
||||
});
|
||||
coprocessorsHLEOption.setText("Prefer HLE for coprocessors").setChecked(settings.emulator.hack.coprocessors.hle).onToggle([&] {
|
||||
settings.emulator.hack.coprocessors.hle = coprocessorsHLEOption.checked();
|
||||
});
|
||||
superFXLabel.setText("SuperFX clock speed:");
|
||||
superFXValue.setAlignment(0.5);
|
||||
superFXClock.setLength(71).setPosition((settings.emulator.hack.fastSuperFX - 100) / 10).onChange([&] {
|
||||
|
@ -75,4 +78,5 @@ auto EmulatorSettings::updateConfiguration() -> void {
|
|||
emulator->configure("Hacks/FastPPU/HiresMode7", hiresMode7.checked());
|
||||
emulator->configure("Hacks/FastDSP/Enable", fastDSPOption.checked());
|
||||
emulator->configure("Hacks/Coprocessor/DelayedSync", coprocessorsDelayedSyncOption.checked());
|
||||
emulator->configure("Hacks/Coprocessor/HLE", coprocessorsHLEOption.checked());
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ auto HotkeySettings::create() -> void {
|
|||
setIcon(Icon::Device::Keyboard);
|
||||
setText("Hotkeys");
|
||||
|
||||
layout.setPadding(5);
|
||||
layout.setPadding(5_sx);
|
||||
mappingList.setBatchable();
|
||||
mappingList.setHeadered();
|
||||
mappingList.onActivate([&] {
|
||||
|
|
|
@ -2,7 +2,7 @@ auto InputSettings::create() -> void {
|
|||
setIcon(Icon::Device::Joypad);
|
||||
setText("Input");
|
||||
|
||||
layout.setPadding(5);
|
||||
layout.setPadding(5_sx);
|
||||
portLabel.setText("Port:");
|
||||
portList.onChange([&] { reloadDevices(); });
|
||||
deviceLabel.setText("Device:");
|
||||
|
|
|
@ -2,14 +2,14 @@ auto PathSettings::create() -> void {
|
|||
setIcon(Icon::Emblem::Folder);
|
||||
setText("Paths");
|
||||
|
||||
layout.setPadding(5);
|
||||
layout.setPadding(5_sx);
|
||||
layout.setSize({4, 6});
|
||||
layout.column(0).setAlignment(1.0);
|
||||
|
||||
gamesLabel.setText("Games:");
|
||||
gamesPath.setEditable(false);
|
||||
gamesAssign.setText("Assign ...").onActivate([&] {
|
||||
if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) {
|
||||
if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
|
||||
settings.path.games = location;
|
||||
refreshPaths();
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ auto PathSettings::create() -> void {
|
|||
patchesLabel.setText("Patches:");
|
||||
patchesPath.setEditable(false);
|
||||
patchesAssign.setText("Assign ...").onActivate([&] {
|
||||
if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) {
|
||||
if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
|
||||
settings.path.patches = location;
|
||||
refreshPaths();
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ auto PathSettings::create() -> void {
|
|||
savesLabel.setText("Saves:");
|
||||
savesPath.setEditable(false);
|
||||
savesAssign.setText("Assign ...").onActivate([&] {
|
||||
if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) {
|
||||
if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
|
||||
settings.path.saves = location;
|
||||
refreshPaths();
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ auto PathSettings::create() -> void {
|
|||
cheatsLabel.setText("Cheats:");
|
||||
cheatsPath.setEditable(false);
|
||||
cheatsAssign.setText("Assign ...").onActivate([&] {
|
||||
if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) {
|
||||
if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
|
||||
settings.path.cheats = location;
|
||||
refreshPaths();
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ auto PathSettings::create() -> void {
|
|||
statesLabel.setText("States:");
|
||||
statesPath.setEditable(false);
|
||||
statesAssign.setText("Assign ...").onActivate([&] {
|
||||
if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) {
|
||||
if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
|
||||
settings.path.states = location;
|
||||
refreshPaths();
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ auto PathSettings::create() -> void {
|
|||
screenshotsLabel.setText("Screenshots:");
|
||||
screenshotsPath.setEditable(false);
|
||||
screenshotsAssign.setText("Assign ...").onActivate([&] {
|
||||
if(auto location = BrowserDialog().setParent(*settingsWindow).selectFolder()) {
|
||||
if(auto location = BrowserDialog().setAlignment(*settingsWindow).selectFolder()) {
|
||||
settings.path.screenshots = location;
|
||||
refreshPaths();
|
||||
}
|
||||
|
|
|
@ -100,6 +100,7 @@ auto Settings::process(bool load) -> void {
|
|||
bind(boolean, "Emulator/Hack/FastPPU/HiresMode7", emulator.hack.fastPPU.hiresMode7);
|
||||
bind(boolean, "Emulator/Hack/FastDSP/Enable", emulator.hack.fastDSP.enable);
|
||||
bind(boolean, "Emulator/Hack/Coprocessors/DelayedSync", emulator.hack.coprocessors.delayedSync);
|
||||
bind(boolean, "Emulator/Hack/Coprocessors/HLE", emulator.hack.coprocessors.hle);
|
||||
bind(natural, "Emulator/Hack/FastSuperFX", emulator.hack.fastSuperFX);
|
||||
bind(boolean, "Emulator/Cheats/Enable", emulator.cheats.enable);
|
||||
|
||||
|
@ -112,7 +113,7 @@ auto Settings::process(bool load) -> void {
|
|||
}
|
||||
|
||||
auto SettingsWindow::create() -> void {
|
||||
layout.setPadding(5);
|
||||
layout.setPadding(5_sx);
|
||||
panel.append(videoSettings);
|
||||
panel.append(audioSettings);
|
||||
panel.append(inputSettings);
|
||||
|
@ -123,7 +124,7 @@ auto SettingsWindow::create() -> void {
|
|||
statusBar.setFont(Font().setBold());
|
||||
|
||||
setTitle("Settings");
|
||||
setSize({600, 400});
|
||||
setSize({600_sx, 400_sx});
|
||||
setAlignment({0.0, 1.0});
|
||||
setDismissable();
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
struct Settings : Markup::Node {
|
||||
using string = nall::string;
|
||||
|
||||
auto load() -> void;
|
||||
auto save() -> void;
|
||||
auto process(bool load) -> void;
|
||||
|
@ -83,6 +85,7 @@ struct Settings : Markup::Node {
|
|||
} fastDSP;
|
||||
struct Coprocessors {
|
||||
bool delayedSync = true;
|
||||
bool hle = true;
|
||||
} coprocessors;
|
||||
uint fastSuperFX = 100;
|
||||
} hack;
|
||||
|
@ -107,15 +110,15 @@ private:
|
|||
Label colorAdjustmentLabel{&layout, Size{~0, 0}, 2};
|
||||
TableLayout colorLayout{&layout, Size{~0, 0}};
|
||||
Label luminanceLabel{&colorLayout, Size{0, 0}};
|
||||
Label luminanceValue{&colorLayout, Size{50, 0}};
|
||||
Label luminanceValue{&colorLayout, Size{50_sx, 0}};
|
||||
HorizontalSlider luminanceSlider{&colorLayout, Size{~0, 0}};
|
||||
//
|
||||
Label saturationLabel{&colorLayout, Size{0, 0}};
|
||||
Label saturationValue{&colorLayout, Size{50, 0}};
|
||||
Label saturationValue{&colorLayout, Size{50_sx, 0}};
|
||||
HorizontalSlider saturationSlider{&colorLayout, Size{~0, 0}};
|
||||
//
|
||||
Label gammaLabel{&colorLayout, Size{0, 0}};
|
||||
Label gammaValue{&colorLayout, Size{50, 0}};
|
||||
Label gammaValue{&colorLayout, Size{50_sx, 0}};
|
||||
HorizontalSlider gammaSlider{&colorLayout, Size{~0, 0}};
|
||||
};
|
||||
|
||||
|
@ -127,15 +130,15 @@ private:
|
|||
Label effectsLabel{&layout, Size{~0, 0}, 2};
|
||||
TableLayout effectsLayout{&layout, Size{~0, 0}};
|
||||
Label skewLabel{&effectsLayout, Size{0, 0}};
|
||||
Label skewValue{&effectsLayout, Size{50, 0}};
|
||||
Label skewValue{&effectsLayout, Size{50_sx, 0}};
|
||||
HorizontalSlider skewSlider{&effectsLayout, Size{~0, 0}};
|
||||
//
|
||||
Label volumeLabel{&effectsLayout, Size{0, 0}};
|
||||
Label volumeValue{&effectsLayout, Size{50, 0}};
|
||||
Label volumeValue{&effectsLayout, Size{50_sx, 0}};
|
||||
HorizontalSlider volumeSlider{&effectsLayout, Size{~0, 0}};
|
||||
//
|
||||
Label balanceLabel{&effectsLayout, Size{0, 0}};
|
||||
Label balanceValue{&effectsLayout, Size{50, 0}};
|
||||
Label balanceValue{&effectsLayout, Size{50_sx, 0}};
|
||||
HorizontalSlider balanceSlider{&effectsLayout, Size{~0, 0}};
|
||||
};
|
||||
|
||||
|
@ -168,12 +171,12 @@ private:
|
|||
ComboButton turboList{&selectionLayout, Size{0, 0}};
|
||||
TableView mappingList{&layout, Size{~0, ~0}};
|
||||
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
|
||||
Button assignMouse1{&controlLayout, Size{100, 0}};
|
||||
Button assignMouse2{&controlLayout, Size{100, 0}};
|
||||
Button assignMouse3{&controlLayout, Size{100, 0}};
|
||||
Button assignMouse1{&controlLayout, Size{100_sx, 0}};
|
||||
Button assignMouse2{&controlLayout, Size{100_sx, 0}};
|
||||
Button assignMouse3{&controlLayout, Size{100_sx, 0}};
|
||||
Widget controlSpacer{&controlLayout, Size{~0, 0}};
|
||||
Button assignButton{&controlLayout, Size{80, 0}};
|
||||
Button clearButton{&controlLayout, Size{80, 0}};
|
||||
Button assignButton{&controlLayout, Size{80_sx, 0}};
|
||||
Button clearButton{&controlLayout, Size{80_sx, 0}};
|
||||
};
|
||||
|
||||
struct HotkeySettings : TabFrameItem {
|
||||
|
@ -193,8 +196,8 @@ private:
|
|||
TableView mappingList{&layout, Size{~0, ~0}};
|
||||
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
|
||||
Widget controlSpacer{&controlLayout, Size{~0, 0}};
|
||||
Button assignButton{&controlLayout, Size{80, 0}};
|
||||
Button clearButton{&controlLayout, Size{80, 0}};
|
||||
Button assignButton{&controlLayout, Size{80_sx, 0}};
|
||||
Button clearButton{&controlLayout, Size{80_sx, 0}};
|
||||
};
|
||||
|
||||
struct PathSettings : TabFrameItem {
|
||||
|
@ -205,33 +208,33 @@ public:
|
|||
TableLayout layout{this};
|
||||
Label gamesLabel{&layout, Size{0, 0}};
|
||||
LineEdit gamesPath{&layout, Size{~0, 0}};
|
||||
Button gamesAssign{&layout, Size{80, 0}};
|
||||
Button gamesReset{&layout, Size{80, 0}};
|
||||
Button gamesAssign{&layout, Size{80_sx, 0}};
|
||||
Button gamesReset{&layout, Size{80_sx, 0}};
|
||||
//
|
||||
Label patchesLabel{&layout, Size{0, 0}};
|
||||
LineEdit patchesPath{&layout, Size{~0, 0}};
|
||||
Button patchesAssign{&layout, Size{80, 0}};
|
||||
Button patchesReset{&layout, Size{80, 0}};
|
||||
Button patchesAssign{&layout, Size{80_sx, 0}};
|
||||
Button patchesReset{&layout, Size{80_sx, 0}};
|
||||
//
|
||||
Label savesLabel{&layout, Size{0, 0}};
|
||||
LineEdit savesPath{&layout, Size{~0, 0}};
|
||||
Button savesAssign{&layout, Size{80, 0}};
|
||||
Button savesReset{&layout, Size{80, 0}};
|
||||
Button savesAssign{&layout, Size{80_sx, 0}};
|
||||
Button savesReset{&layout, Size{80_sx, 0}};
|
||||
//
|
||||
Label cheatsLabel{&layout, Size{0, 0}};
|
||||
LineEdit cheatsPath{&layout, Size{~0, 0}};
|
||||
Button cheatsAssign{&layout, Size{80, 0}};
|
||||
Button cheatsReset{&layout, Size{80, 0}};
|
||||
Button cheatsAssign{&layout, Size{80_sx, 0}};
|
||||
Button cheatsReset{&layout, Size{80_sx, 0}};
|
||||
//
|
||||
Label statesLabel{&layout, Size{0, 0}};
|
||||
LineEdit statesPath{&layout, Size{~0, 0}};
|
||||
Button statesAssign{&layout, Size{80, 0}};
|
||||
Button statesReset{&layout, Size{80, 0}};
|
||||
Button statesAssign{&layout, Size{80_sx, 0}};
|
||||
Button statesReset{&layout, Size{80_sx, 0}};
|
||||
//
|
||||
Label screenshotsLabel{&layout, Size{0, 0}};
|
||||
LineEdit screenshotsPath{&layout, Size{~0, 0}};
|
||||
Button screenshotsAssign{&layout, Size{80, 0}};
|
||||
Button screenshotsReset{&layout, Size{80, 0}};
|
||||
Button screenshotsAssign{&layout, Size{80_sx, 0}};
|
||||
Button screenshotsReset{&layout, Size{80_sx, 0}};
|
||||
};
|
||||
|
||||
struct EmulatorSettings : TabFrameItem {
|
||||
|
@ -259,10 +262,12 @@ public:
|
|||
CheckLabel noSpriteLimit{&fastPPULayout, Size{0, 0}};
|
||||
CheckLabel hiresMode7{&fastPPULayout, Size{0, 0}};
|
||||
CheckLabel fastDSPOption{&layout, Size{~0, 0}};
|
||||
CheckLabel coprocessorsDelayedSyncOption{&layout, Size{~0, 0}};
|
||||
HorizontalLayout coprocessorsLayout{&layout, Size{~0, 0}};
|
||||
CheckLabel coprocessorsDelayedSyncOption{&coprocessorsLayout, Size{0, 0}};
|
||||
CheckLabel coprocessorsHLEOption{&coprocessorsLayout, Size{0, 0}};
|
||||
HorizontalLayout superFXLayout{&layout, Size{~0, 0}};
|
||||
Label superFXLabel{&superFXLayout, Size{0, 0}};
|
||||
Label superFXValue{&superFXLayout, Size{50, 0}};
|
||||
Label superFXValue{&superFXLayout, Size{50_sx, 0}};
|
||||
HorizontalSlider superFXClock{&superFXLayout, Size{~0, 0}};
|
||||
Label hacksNote{&layout, Size{~0, 0}};
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@ auto VideoSettings::create() -> void {
|
|||
setIcon(Icon::Device::Display);
|
||||
setText("Video");
|
||||
|
||||
layout.setPadding(5);
|
||||
layout.setPadding(5_sx);
|
||||
|
||||
colorAdjustmentLabel.setFont(Font().setBold()).setText("Color Adjustment");
|
||||
colorLayout.setSize({3, 3});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
auto CheatDatabase::create() -> void {
|
||||
layout.setPadding(5);
|
||||
layout.setPadding(5_sx);
|
||||
selectAllButton.setText("Select All").onActivate([&] {
|
||||
for(auto item : cheatList.items()) item.setChecked(true);
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ auto CheatDatabase::create() -> void {
|
|||
addCheats();
|
||||
});
|
||||
|
||||
setSize({800, 400});
|
||||
setSize({800_sx, 400_sx});
|
||||
setAlignment({0.5, 1.0});
|
||||
setDismissable();
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ auto CheatDatabase::findCheats() -> void {
|
|||
return;
|
||||
}
|
||||
|
||||
MessageDialog().setParent(*toolsWindow).setText("Sorry, no cheats were found for this game.").information();
|
||||
MessageDialog().setAlignment(*toolsWindow).setText("Sorry, no cheats were found for this game.").information();
|
||||
}
|
||||
|
||||
auto CheatDatabase::addCheats() -> void {
|
||||
|
@ -51,7 +51,7 @@ auto CheatDatabase::addCheats() -> void {
|
|||
//
|
||||
|
||||
auto CheatWindow::create() -> void {
|
||||
layout.setPadding(5);
|
||||
layout.setPadding(5_sx);
|
||||
tableLayout.setSize({2, 2});
|
||||
tableLayout.cell(0).setAlignment({1.0, 0.5});
|
||||
tableLayout.cell(2).setAlignment({1.0, 0.0});
|
||||
|
@ -65,7 +65,7 @@ auto CheatWindow::create() -> void {
|
|||
acceptButton.onActivate([&] { doAccept(); });
|
||||
cancelButton.setText("Cancel").onActivate([&] { setVisible(false); });
|
||||
|
||||
setSize({400, layout.minimumSize().height() + 100});
|
||||
setSize({400_sx, layout.minimumSize().height() + 100_sx});
|
||||
setDismissable();
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ auto CheatWindow::show(Cheat cheat) -> void {
|
|||
enableOption.setChecked(cheat.enable);
|
||||
doChange();
|
||||
setTitle(!cheat.name ? "Add Cheat" : "Edit Cheat");
|
||||
setCentered(*toolsWindow);
|
||||
setAlignment(*toolsWindow);
|
||||
setVisible();
|
||||
setFocused();
|
||||
nameValue.setFocused();
|
||||
|
@ -105,7 +105,7 @@ auto CheatEditor::create() -> void {
|
|||
setIcon(Icon::Edit::Replace);
|
||||
setText("Cheat Editor");
|
||||
|
||||
layout.setPadding(5);
|
||||
layout.setPadding(5_sx);
|
||||
cheatList.setBatchable();
|
||||
cheatList.setHeadered();
|
||||
cheatList.setSortable();
|
||||
|
@ -201,7 +201,7 @@ auto CheatEditor::editCheat(Cheat cheat) -> void {
|
|||
auto CheatEditor::removeCheats() -> void {
|
||||
if(auto batched = cheatList.batched()) {
|
||||
if(MessageDialog("Are you sure you want to permanently remove the selected cheat(s)?")
|
||||
.setParent(*toolsWindow).question() == "Yes") {
|
||||
.setAlignment(*toolsWindow).question() == "Yes") {
|
||||
for(auto& item : reverse(batched)) cheats.remove(item.offset());
|
||||
cheats.sort();
|
||||
refresh();
|
||||
|
|
|
@ -2,7 +2,7 @@ auto ManifestViewer::create() -> void {
|
|||
setIcon(Icon::Emblem::Text);
|
||||
setText("Manifest Viewer");
|
||||
|
||||
layout.setPadding(5);
|
||||
layout.setPadding(5_sx);
|
||||
manifestLabel.setText("Manifest:");
|
||||
manifestOption.onChange([&] { selectManifest(); });
|
||||
manifestSpacer.setColor({192, 192, 192});
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
#include <nall/encode/bmp.hpp>
|
||||
|
||||
auto StateWindow::create() -> void {
|
||||
layout.setPadding(5);
|
||||
layout.setPadding(5_sx);
|
||||
nameLabel.setText("Name:");
|
||||
nameValue.onActivate([&] { if(acceptButton.enabled()) acceptButton.doActivate(); });
|
||||
nameValue.onChange([&] { doChange(); });
|
||||
acceptButton.onActivate([&] { doAccept(); });
|
||||
cancelButton.setText("Cancel").onActivate([&] { setVisible(false); });
|
||||
|
||||
setSize({400, layout.minimumSize().height()});
|
||||
setSize({400_sx, layout.minimumSize().height()});
|
||||
setDismissable();
|
||||
}
|
||||
|
||||
|
@ -16,7 +18,7 @@ auto StateWindow::show(string name) -> void {
|
|||
nameValue.setText(property("name"));
|
||||
doChange();
|
||||
setTitle(!property("name") ? "Add State" : "Rename State");
|
||||
setCentered(*toolsWindow);
|
||||
setAlignment(*toolsWindow);
|
||||
setVisible();
|
||||
setFocused();
|
||||
nameValue.setFocused();
|
||||
|
@ -48,7 +50,7 @@ auto StateManager::create() -> void {
|
|||
setIcon(Icon::Application::FileManager);
|
||||
setText("State Manager");
|
||||
|
||||
layout.setPadding(5);
|
||||
layout.setPadding(5_sx);
|
||||
stateLayout.setAlignment(0.0);
|
||||
stateList.setBatchable();
|
||||
stateList.setHeadered();
|
||||
|
@ -131,7 +133,7 @@ auto StateManager::modifyState(string name) -> void {
|
|||
auto StateManager::removeStates() -> void {
|
||||
if(auto batched = stateList.batched()) {
|
||||
if(MessageDialog("Are you sure you want to permanently remove the selected state(s)?")
|
||||
.setParent(*toolsWindow).question() == "Yes") {
|
||||
.setAlignment(*toolsWindow).question() == "Yes") {
|
||||
auto lock = acquire();
|
||||
for(auto& item : batched) program.removeState(item.property("name"));
|
||||
loadStates();
|
||||
|
@ -159,9 +161,18 @@ auto StateManager::updateSelection() -> void {
|
|||
if(signature == Program::State::Signature && preview) {
|
||||
uint offset = 3 * sizeof(uint) + serializer;
|
||||
auto preview = Decode::RLE<2>({saveState.data() + offset, max(offset, saveState.size()) - offset});
|
||||
image icon{0, 15, 0x8000, 0x7c00, 0x03e0, 0x001f};
|
||||
image icon{0, 16, 0x8000, 0x7c00, 0x03e0, 0x001f};
|
||||
icon.copy(preview.data(), 256 * sizeof(uint16_t), 256, 240);
|
||||
icon.transform();
|
||||
//restore the missing alpha channel
|
||||
for(uint y : range(icon.height())) {
|
||||
auto data = icon.data() + y * icon.pitch();
|
||||
for(uint x : range(icon.width())) {
|
||||
auto pixel = icon.read(data);
|
||||
icon.write(data, 0xff000000 | pixel);
|
||||
data += icon.stride();
|
||||
}
|
||||
}
|
||||
statePreview.setIcon(icon);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ ManifestViewer manifestViewer;
|
|||
ToolsWindow toolsWindow;
|
||||
|
||||
auto ToolsWindow::create() -> void {
|
||||
layout.setPadding(5);
|
||||
layout.setPadding(5_sx);
|
||||
panel.append(cheatEditor);
|
||||
panel.append(stateManager);
|
||||
panel.append(manifestViewer);
|
||||
|
@ -22,7 +22,7 @@ auto ToolsWindow::create() -> void {
|
|||
});
|
||||
|
||||
setTitle("Tools");
|
||||
setSize({720, 480});
|
||||
setSize({720_sx, 480_sx});
|
||||
setAlignment({1.0, 1.0});
|
||||
setDismissable();
|
||||
|
||||
|
|
|
@ -21,10 +21,10 @@ public:
|
|||
VerticalLayout layout{this};
|
||||
ListView cheatList{&layout, Size{~0, ~0}};
|
||||
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
|
||||
Button selectAllButton{&controlLayout, Size{100, 0}};
|
||||
Button unselectAllButton{&controlLayout, Size{100, 0}};
|
||||
Button selectAllButton{&controlLayout, Size{100_sx, 0}};
|
||||
Button unselectAllButton{&controlLayout, Size{100_sx, 0}};
|
||||
Widget spacer{&controlLayout, Size{~0, 0}};
|
||||
Button addCheatsButton{&controlLayout, Size{100, 0}};
|
||||
Button addCheatsButton{&controlLayout, Size{100_sx, 0}};
|
||||
};
|
||||
|
||||
struct CheatWindow : Window {
|
||||
|
@ -43,8 +43,8 @@ public:
|
|||
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
|
||||
Widget controlSpacer{&controlLayout, Size{~0, 0}};
|
||||
CheckLabel enableOption{&controlLayout, Size{0, 0}};
|
||||
Button acceptButton{&controlLayout, Size{80, 0}};
|
||||
Button cancelButton{&controlLayout, Size{80, 0}};
|
||||
Button acceptButton{&controlLayout, Size{80_sx, 0}};
|
||||
Button cancelButton{&controlLayout, Size{80_sx, 0}};
|
||||
};
|
||||
|
||||
struct CheatEditor : TabFrameItem {
|
||||
|
@ -63,12 +63,12 @@ public:
|
|||
VerticalLayout layout{this};
|
||||
TableView cheatList{&layout, Size{~0, ~0}};
|
||||
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
|
||||
Button findCheatsButton{&controlLayout, Size{120, 0}};
|
||||
Button findCheatsButton{&controlLayout, Size{120_sx, 0}};
|
||||
Widget spacer{&controlLayout, Size{~0, 0}};
|
||||
CheckLabel enableCheats{&controlLayout, Size{0, 0}};
|
||||
Button addButton{&controlLayout, Size{80, 0}};
|
||||
Button editButton{&controlLayout, Size{80, 0}};
|
||||
Button removeButton{&controlLayout, Size{80, 0}};
|
||||
Button addButton{&controlLayout, Size{80_sx, 0}};
|
||||
Button editButton{&controlLayout, Size{80_sx, 0}};
|
||||
Button removeButton{&controlLayout, Size{80_sx, 0}};
|
||||
};
|
||||
|
||||
struct StateWindow : Window {
|
||||
|
@ -80,12 +80,12 @@ struct StateWindow : Window {
|
|||
public:
|
||||
VerticalLayout layout{this};
|
||||
HorizontalLayout nameLayout{&layout, Size{~0, 0}};
|
||||
Label nameLabel{&nameLayout, Size{40, 0}};
|
||||
Label nameLabel{&nameLayout, Size{40_sx, 0}};
|
||||
LineEdit nameValue{&nameLayout, Size{~0, 0}};
|
||||
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
|
||||
Widget spacer{&controlLayout, Size{~0, 0}};
|
||||
Button acceptButton{&controlLayout, Size{80, 0}};
|
||||
Button cancelButton{&controlLayout, Size{80, 0}};
|
||||
Button acceptButton{&controlLayout, Size{80_sx, 0}};
|
||||
Button cancelButton{&controlLayout, Size{80_sx, 0}};
|
||||
};
|
||||
|
||||
struct StateManager : TabFrameItem, Lock {
|
||||
|
@ -117,12 +117,12 @@ public:
|
|||
Label statePreviewLabel{&previewLayout, Size{~0, 0}};
|
||||
Canvas statePreview{&previewLayout, Size{256, 224}};
|
||||
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
|
||||
Button loadButton{&controlLayout, Size{80, 0}};
|
||||
Button saveButton{&controlLayout, Size{80, 0}};
|
||||
Button loadButton{&controlLayout, Size{80_sx, 0}};
|
||||
Button saveButton{&controlLayout, Size{80_sx, 0}};
|
||||
Widget spacer{&controlLayout, Size{~0, 0}};
|
||||
Button addButton{&controlLayout, Size{80, 0}};
|
||||
Button editButton{&controlLayout, Size{80, 0}};
|
||||
Button removeButton{&controlLayout, Size{80, 0}};
|
||||
Button addButton{&controlLayout, Size{80_sx, 0}};
|
||||
Button editButton{&controlLayout, Size{80_sx, 0}};
|
||||
Button removeButton{&controlLayout, Size{80_sx, 0}};
|
||||
};
|
||||
|
||||
struct ManifestViewer : TabFrameItem {
|
||||
|
|
|
@ -5,7 +5,7 @@ ifeq ($(platform),windows)
|
|||
|
||||
ifeq ($(hiro),windows)
|
||||
hiro.flags = $(flags.cpp) -DHIRO_WINDOWS
|
||||
hiro.options = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -luxtheme -lmsimg32 -lshlwapi
|
||||
hiro.options = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -luxtheme -lmsimg32 -lshlwapi -ldwmapi
|
||||
endif
|
||||
|
||||
ifeq ($(hiro),gtk2)
|
||||
|
@ -14,7 +14,7 @@ ifeq ($(platform),windows)
|
|||
endif
|
||||
|
||||
ifeq ($(hiro),gtk3)
|
||||
hiro.flags = $(flags.cpp) -DHIRO_GTK=3 $(shell pkg-config --cflags gtk+-3.0 gtksourceview-3.0)
|
||||
hiro.flags = $(flags.cpp) -DHIRO_GTK=3 $(shell pkg-config --cflags gtk+-3.0 gtksourceview-3.0) -Wno-deprecated-declarations
|
||||
hiro.options = $(shell pkg-config --libs gtk+-3.0 gtksourceview-3.0)
|
||||
endif
|
||||
endif
|
||||
|
@ -41,12 +41,12 @@ ifneq ($(filter $(platform),linux bsd),)
|
|||
endif
|
||||
|
||||
ifeq ($(hiro),gtk3)
|
||||
hiro.flags = $(flags.cpp) -DHIRO_GTK=3 $(shell pkg-config --cflags gtk+-3.0 gtksourceview-3.0)
|
||||
hiro.flags = $(flags.cpp) -DHIRO_GTK=3 $(shell pkg-config --cflags gtk+-3.0 gtksourceview-3.0) -Wno-deprecated-declarations
|
||||
hiro.options = -lX11 $(shell pkg-config --libs gtk+-3.0 gtksourceview-3.0)
|
||||
endif
|
||||
|
||||
ifeq ($(hiro),qt4)
|
||||
moc = moc-qt4
|
||||
moc = /usr/local/lib/qt4/bin/moc
|
||||
hiro.flags = $(flags.cpp) -DHIRO_QT=4 $(shell pkg-config --cflags QtCore QtGui)
|
||||
hiro.options = -lX11 $(shell pkg-config --libs QtCore QtGui)
|
||||
endif
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
}
|
||||
|
||||
-(void) run:(NSTimer*)instance {
|
||||
if(Application::state().quit) return;
|
||||
if(hiro::Application::state().quit) return;
|
||||
|
||||
if(timer->enabled()) {
|
||||
timer->doActivate();
|
||||
|
|
|
@ -113,6 +113,10 @@ auto pCanvas::minimumSize() const -> Size {
|
|||
return {0, 0};
|
||||
}
|
||||
|
||||
auto pCanvas::setAlignment(Alignment) -> void {
|
||||
update();
|
||||
}
|
||||
|
||||
auto pCanvas::setColor(Color color) -> void {
|
||||
update();
|
||||
}
|
||||
|
@ -147,6 +151,7 @@ auto pCanvas::update() -> void {
|
|||
}
|
||||
}
|
||||
|
||||
//todo: support cases where the icon size does not match the canvas size (alignment)
|
||||
auto pCanvas::_rasterize() -> void {
|
||||
@autoreleasepool {
|
||||
int width = 0;
|
||||
|
|
|
@ -27,6 +27,7 @@ struct pCanvas : pWidget {
|
|||
Declare(Canvas, Widget)
|
||||
|
||||
auto minimumSize() const -> Size;
|
||||
auto setAlignment(Alignment) -> void;
|
||||
auto setColor(Color color) -> void;
|
||||
auto setDroppable(bool droppable) -> void;
|
||||
auto setGeometry(Geometry geometry) -> void override;
|
||||
|
|
|
@ -154,9 +154,7 @@ auto pTabFrame::_synchronizeSizable() -> void {
|
|||
int selected = tabViewItem ? [cocoaView indexOfTabViewItem:tabViewItem] : -1;
|
||||
for(auto& item : state().items) {
|
||||
item->state.selected = item->offset() == selected;
|
||||
if(auto& sizable = item->state.sizable) {
|
||||
if(auto self = sizable->self()) self->setVisible(sizable->visible(true) && item->selected());
|
||||
}
|
||||
if(auto& sizable = item->state.sizable) sizable->setVisible(item->selected());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ struct pTabFrame : pWidget {
|
|||
auto _synchronizeSizable() -> void;
|
||||
|
||||
CocoaTabFrame* cocoaTabFrame = nullptr;
|
||||
vector<CocoaTabFrameItem*> tabs;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -242,6 +242,10 @@ auto pWindow::frameMargin() const -> Geometry {
|
|||
}
|
||||
}
|
||||
|
||||
auto pWindow::handle() const -> uintptr_t {
|
||||
return (uintptr_t)cocoaWindow;
|
||||
}
|
||||
|
||||
auto pWindow::monitor() const -> uint {
|
||||
//TODO
|
||||
return 0;
|
||||
|
|
|
@ -35,6 +35,7 @@ struct pWindow : pObject {
|
|||
auto append(sStatusBar statusBar) -> void;
|
||||
auto focused() const -> bool override;
|
||||
auto frameMargin() const -> Geometry;
|
||||
auto handle() const -> uintptr_t;
|
||||
auto monitor() const -> uint;
|
||||
auto remove(sMenuBar menuBar) -> void;
|
||||
auto remove(sSizable sizable) -> void;
|
||||
|
|
|
@ -95,18 +95,24 @@
|
|||
#define Hiro_VerticalLayout
|
||||
#define Hiro_TableLayout
|
||||
|
||||
#if defined(Hiro_Timer) && defined(Hiro_Canvas)
|
||||
#define Hiro_HorizontalResizeGrip
|
||||
#define Hiro_VerticalResizeGrip
|
||||
#endif
|
||||
|
||||
#if defined(Hiro_TableView)
|
||||
#define Hiro_ListView
|
||||
#endif
|
||||
|
||||
#if defined(Hiro_Button) && defined(Hiro_Canvas) && defined(Hiro_Label)
|
||||
#define Hiro_MessageDialog
|
||||
#define Hiro_NameDialog
|
||||
#endif
|
||||
|
||||
#if defined(Hiro_Button) && defined(Hiro_ComboButton) && defined(Hiro_LineEdit) && defined(Hiro_ListView) && defined(Hiro_MessageDialog)
|
||||
#if defined(Hiro_Button) && defined(Hiro_ComboButton) && defined(Hiro_LineEdit) && defined(Hiro_ListView) && defined(Hiro_MessageDialog) && defined(Hiro_NameDialog)
|
||||
#define Hiro_BrowserDialog
|
||||
#endif
|
||||
|
||||
#if defined(Hiro_Label)
|
||||
#if defined(Hiro_Canvas) && defined(Hiro_Label)
|
||||
#define Hiro_AboutDialog
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#if defined(Hiro_Alignment)
|
||||
|
||||
const Alignment Alignment::Center = {0.5, 0.5};
|
||||
|
||||
Alignment::Alignment() {
|
||||
setAlignment(-1.0, -1.0);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
#if defined(Hiro_Application)
|
||||
|
||||
auto Application::abort() -> void {
|
||||
quit();
|
||||
::abort();
|
||||
}
|
||||
|
||||
auto Application::doMain() -> void {
|
||||
if(state().onMain) return state().onMain();
|
||||
}
|
||||
|
||||
auto Application::font() -> Font {
|
||||
return state().font;
|
||||
auto Application::exit() -> void {
|
||||
quit();
|
||||
::exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
auto Application::kill() -> void {
|
||||
quit();
|
||||
exit(EXIT_SUCCESS);
|
||||
auto Application::font() -> Font {
|
||||
return state().font;
|
||||
}
|
||||
|
||||
auto Application::locale() -> Locale& {
|
||||
|
@ -134,7 +139,6 @@ auto Application::Cocoa::onQuit(const function<void ()>& callback) -> void {
|
|||
auto Application::initialize() -> void {
|
||||
if(!state().initialized) {
|
||||
state().initialized = true;
|
||||
hiro::initialize();
|
||||
pApplication::initialize();
|
||||
pApplication::setScreenSaver(state().screenSaver);
|
||||
}
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
struct Application {
|
||||
Application() = delete;
|
||||
|
||||
static auto abort() -> void;
|
||||
static auto doMain() -> void;
|
||||
static auto exit() -> void;
|
||||
static auto font() -> Font;
|
||||
static auto kill() -> void;
|
||||
static auto locale() -> Locale&;
|
||||
static auto modal() -> bool;
|
||||
static auto name() -> string;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <nall/platform.hpp>
|
||||
#include <nall/any.hpp>
|
||||
#include <nall/chrono.hpp>
|
||||
#include <nall/directory.hpp>
|
||||
#include <nall/function.hpp>
|
||||
|
@ -17,6 +18,7 @@
|
|||
#include <nall/utility.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
|
||||
using nall::any;
|
||||
using nall::function;
|
||||
using nall::image;
|
||||
using nall::Locale;
|
||||
|
@ -31,8 +33,6 @@ using nall::vector;
|
|||
|
||||
namespace hiro {
|
||||
|
||||
auto initialize() -> void;
|
||||
|
||||
struct Font;
|
||||
struct Keyboard;
|
||||
|
||||
|
@ -158,6 +158,7 @@ struct Gradient {
|
|||
#if defined(Hiro_Alignment)
|
||||
struct Alignment {
|
||||
using type = Alignment;
|
||||
static const Alignment Center;
|
||||
|
||||
Alignment();
|
||||
Alignment(float horizontal, float vertical = 0.5);
|
||||
|
@ -408,24 +409,7 @@ struct MessageWindow {
|
|||
};
|
||||
#endif
|
||||
|
||||
struct Property {
|
||||
using type = Property;
|
||||
|
||||
Property(const string& name, const string& value = "");
|
||||
|
||||
auto operator==(const Property& source) const -> bool;
|
||||
auto operator< (const Property& source) const -> bool;
|
||||
|
||||
auto name() const -> string;
|
||||
auto setValue(const string& value = "") -> type&;
|
||||
auto value() const -> string;
|
||||
|
||||
private:
|
||||
struct State {
|
||||
string name;
|
||||
string value;
|
||||
} state;
|
||||
};
|
||||
#include "property.hpp"
|
||||
|
||||
#define Declare(Name) \
|
||||
using type = m##Name; \
|
||||
|
@ -652,47 +636,7 @@ struct mButton : mWidget {
|
|||
};
|
||||
#endif
|
||||
|
||||
#if defined(Hiro_Canvas)
|
||||
struct mCanvas : mWidget {
|
||||
Declare(Canvas)
|
||||
|
||||
auto color() const -> Color;
|
||||
auto data() -> uint32_t*;
|
||||
auto droppable() const -> bool;
|
||||
auto doDrop(vector<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
|
||||
#include "widget/canvas.hpp"
|
||||
|
||||
#if defined(Hiro_CheckButton)
|
||||
struct mCheckButton : mWidget {
|
||||
|
|
|
@ -8,4 +8,19 @@ struct Monitor {
|
|||
static auto primary() -> uint;
|
||||
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
|
||||
|
|
|
@ -249,13 +249,6 @@ auto mObject::parentWindow(bool recursive) const -> mWindow* {
|
|||
}
|
||||
#endif
|
||||
|
||||
auto mObject::property(const string& name) const -> string {
|
||||
if(auto property = state.properties.find({name})) {
|
||||
return property->value();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
auto mObject::remove() -> type& {
|
||||
signal(remove);
|
||||
return *this;
|
||||
|
@ -295,16 +288,6 @@ auto mObject::setParent(mObject* parent, int offset) -> type& {
|
|||
return *this;
|
||||
}
|
||||
|
||||
auto mObject::setProperty(const string& name, const string& value) -> type& {
|
||||
if(auto property = state.properties.find(name)) {
|
||||
if(value) property->setValue(value);
|
||||
else state.properties.remove(*property);
|
||||
} else {
|
||||
if(value) state.properties.insert({name, value});
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mObject::setVisible(bool visible) -> type& {
|
||||
state.visible = visible;
|
||||
signal(setVisible, this->visible(true));
|
||||
|
|
|
@ -33,7 +33,6 @@ struct mObject {
|
|||
auto parentTreeViewItem(bool recursive = false) const -> mTreeViewItem*;
|
||||
auto parentWidget(bool recursive = false) const -> mWidget*;
|
||||
auto parentWindow(bool recursive = false) const -> mWindow*;
|
||||
auto property(const string& name) const -> string;
|
||||
virtual auto remove() -> type&;
|
||||
virtual auto reset() -> type&;
|
||||
virtual auto setEnabled(bool enabled = true) -> type&;
|
||||
|
@ -41,10 +40,34 @@ struct mObject {
|
|||
virtual auto setFont(const Font& font = {}) -> type&;
|
||||
virtual auto setGroup(sGroup group = {}) -> type&;
|
||||
virtual auto setParent(mObject* parent = nullptr, int offset = -1) -> type&;
|
||||
virtual auto setProperty(const string& name, const string& value = "") -> type&;
|
||||
virtual auto setVisible(bool visible = true) -> type&;
|
||||
auto visible(bool recursive = false) const -> bool;
|
||||
|
||||
template<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:
|
||||
//sizeof(mObject) == 88
|
||||
struct State {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#if defined(Hiro_Property)
|
||||
|
||||
Property::Property(const string& name, const string& value) {
|
||||
Property::Property(const string& name, const any& value) {
|
||||
state.name = name;
|
||||
state.value = value;
|
||||
}
|
||||
|
@ -17,12 +17,12 @@ auto Property::name() const -> string {
|
|||
return state.name;
|
||||
}
|
||||
|
||||
auto Property::setValue(const string& value) -> type& {
|
||||
auto Property::setValue(const any& value) -> type& {
|
||||
state.value = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto Property::value() const -> string {
|
||||
auto Property::value() const -> any& {
|
||||
return state.value;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -38,12 +38,12 @@
|
|||
} \
|
||||
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 setEnabled(bool enabled = true) { return self().setEnabled(enabled), *this; } \
|
||||
auto setFocused() { return self().setFocused(), *this; } \
|
||||
auto setFont(const Font& font = {}) { return self().setFont(font), *this; } \
|
||||
auto setProperty(const string& name, const string& value = "") { return self().setProperty(name, value), *this; } \
|
||||
template<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 visible(bool recursive = false) const { return self().visible(recursive); } \
|
||||
|
||||
|
@ -210,6 +210,7 @@ struct Button : sButton {
|
|||
struct Canvas : sCanvas {
|
||||
DeclareSharedWidget(Canvas)
|
||||
|
||||
auto alignment() const { return self().alignment(); }
|
||||
auto color() const { return self().color(); }
|
||||
auto data() { return self().data(); }
|
||||
auto droppable() const { return self().droppable(); }
|
||||
|
@ -225,6 +226,7 @@ struct Canvas : sCanvas {
|
|||
auto onMouseMove(const function<void (Position)>& callback = {}) { return self().onMouseMove(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 setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; }
|
||||
auto setColor(Color color) { return self().setColor(color), *this; }
|
||||
auto setDroppable(bool droppable = true) { return self().setDroppable(droppable), *this; }
|
||||
auto setGradient(Gradient gradient = {}) { return self().setGradient(gradient), *this; }
|
||||
|
@ -761,6 +763,8 @@ struct TreeViewItem : sTreeViewItem {
|
|||
auto backgroundColor() const { return self().backgroundColor(); }
|
||||
auto checkable() const { return self().checkable(); }
|
||||
auto checked() const { return self().checked(); }
|
||||
auto collapse(bool recursive = true) { return self().collapse(recursive), *this; }
|
||||
auto expand(bool recursive = true) { return self().expand(recursive), *this; }
|
||||
auto expanded() const { return self().expanded(); }
|
||||
auto foregroundColor() const { return self().foregroundColor(); }
|
||||
auto icon() const { return self().icon(); }
|
||||
|
@ -788,10 +792,12 @@ struct TreeView : sTreeView {
|
|||
|
||||
auto append(sTreeViewItem item) { return self().append(item), *this; }
|
||||
auto backgroundColor() const { return self().backgroundColor(); }
|
||||
auto collapse(bool recursive = true) { return self().collapse(recursive), *this; }
|
||||
auto doActivate() const { return self().doActivate(); }
|
||||
auto doChange() const { return self().doChange(); }
|
||||
auto doContext() const { return self().doContext(); }
|
||||
auto doToggle(sTreeViewItem item) const { return self().doToggle(item); }
|
||||
auto expand(bool recursive = true) { return self().expand(recursive), *this; }
|
||||
auto foregroundColor() const { return self().foregroundColor(); }
|
||||
auto item(const string& path) const { return self().item(path); }
|
||||
auto itemCount() const { return self().itemCount(); }
|
||||
|
@ -908,6 +914,7 @@ struct Window : sWindow {
|
|||
auto frameGeometry() const { return self().frameGeometry(); }
|
||||
auto fullScreen() const { return self().fullScreen(); }
|
||||
auto geometry() const { return self().geometry(); }
|
||||
auto handle() const { return self().handle(); }
|
||||
auto maximized() const { return self().maximized(); }
|
||||
auto maximumSize() const { return self().maximumSize(); }
|
||||
auto menuBar() const { return self().menuBar(); }
|
||||
|
@ -926,9 +933,9 @@ struct Window : sWindow {
|
|||
auto remove(sStatusBar statusBar) { return self().remove(statusBar), *this; }
|
||||
auto reset() { return self().reset(), *this; }
|
||||
auto resizable() const { return self().resizable(); }
|
||||
auto setAlignment(Alignment alignment) { return self().setAlignment(alignment), *this; }
|
||||
auto setAlignment(Alignment alignment = Alignment::Center) { return self().setAlignment(alignment), *this; }
|
||||
auto setAlignment(sWindow relativeTo, Alignment alignment = Alignment::Center) { return self().setAlignment(relativeTo, alignment), *this; }
|
||||
auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; }
|
||||
auto setCentered(sWindow parent = {}) { return self().setCentered(parent), *this; }
|
||||
auto setDismissable(bool dismissable = true) { return self().setDismissable(dismissable), *this; }
|
||||
auto setDroppable(bool droppable = true) { return self().setDroppable(droppable), *this; }
|
||||
auto setFrameGeometry(Geometry geometry) { return self().setFrameGeometry(geometry), *this; }
|
||||
|
@ -942,6 +949,7 @@ struct Window : sWindow {
|
|||
auto setMinimumSize(Size size = {}) { return self().setMinimumSize(size), *this; }
|
||||
auto setModal(bool modal = true) { return self().setModal(modal), *this; }
|
||||
auto setPosition(Position position) { return self().setPosition(position), *this; }
|
||||
auto setPosition(sWindow relativeTo, Position position) { return self().setPosition(relativeTo, position), *this; }
|
||||
auto setResizable(bool resizable = true) { return self().setResizable(resizable), *this; }
|
||||
auto setSize(Size size) { return self().setSize(size), *this; }
|
||||
auto setTitle(const string& title = "") { return self().setTitle(title), *this; }
|
||||
|
|
|
@ -6,6 +6,10 @@ auto mCanvas::allocate() -> pObject* {
|
|||
|
||||
//
|
||||
|
||||
auto mCanvas::alignment() const -> Alignment {
|
||||
return state.alignment;
|
||||
}
|
||||
|
||||
auto mCanvas::color() const -> Color {
|
||||
return state.color;
|
||||
}
|
||||
|
@ -71,6 +75,12 @@ auto mCanvas::onMouseRelease(const function<void (Mouse::Button)>& callback) ->
|
|||
return *this;
|
||||
}
|
||||
|
||||
auto mCanvas::setAlignment(Alignment alignment) -> type& {
|
||||
state.alignment = alignment;
|
||||
signal(setAlignment, alignment);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mCanvas::setColor(Color color) -> type& {
|
||||
state.color = color;
|
||||
state.gradient = {};
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue