Update to v094r10 release.

byuu says:

This starts the tomoko UI. So far I have basic library loading and
video+audio output. Basically just enough to take the below screenshot.
(aside from Library, the menus are empty stubs.)

The .sys (system) game folders are now going under ~/Emulation/System,
to avoid needing root privileges to stick them into /usr/share. The game
library now shows all bootable media types, and the drop-down subtype is
gone. I'm going to display a separate modal dialog for loading slotted
games this time around. Much cleaner this way, less clutter.

tomoko's starting off a lot cleaner than ethos was, and I'm scaling back
the number of abstracted classes. What was Utility, Interface, etc are
now being merged all into Program. Of course, the real hell is the input
system. That has so many layers of bullshit that there's really no sane
way to write it.
This commit is contained in:
Tim Allen 2015-02-28 12:51:53 +11:00
parent a512d14628
commit 80c1c9c2ef
17 changed files with 393 additions and 33 deletions

View File

@ -6,7 +6,7 @@ gb := gb
gba := gba
profile := accuracy
target := higan
target := tomoko
# arch := x86
# console := true

View File

@ -3,7 +3,7 @@
namespace Emulator {
static const char Name[] = "higan";
static const char Version[] = "094.09";
static const char Version[] = "094.10";
static const char Author[] = "byuu";
static const char License[] = "GPLv3";
static const char Website[] = "http://byuu.org/";

1
out/.gitignore vendored
View File

@ -1 +1,2 @@
higan
tomoko

View File

@ -1,25 +0,0 @@
#include "higan.hpp"
struct Presentation : Window {
MenuBar menuBar{this};
Menu menuSystem{&menuBar};
StatusBar statusBar{this};
Presentation() {
menuSystem.setText("System");
onClose(&Application::quit);
setBackgroundColor({0, 0, 0});
setTitle({Emulator::Name, " v", Emulator::Version});
setSize({640, 480});
setCentered();
setVisible();
}
};
#include <nall/main.hpp>
auto nall::main(lstring args) -> void {
Application::setName("higan");
new Presentation;
Application::run();
}

View File

@ -1,13 +1,15 @@
name := higan
name := tomoko
processors := arm gsu hg51b lr35902 r6502 r65816 spc700 upd96050
include processor/GNUmakefile
include fc/GNUmakefile
include sfc/GNUmakefile
include gb/GNUmakefile
include gba/GNUmakefile
ui_objects := ui-higan
ui_objects := ui-tomoko ui-program
ui_objects += ui-library ui-presentation
ui_objects += ruby hiro
# platform
@ -38,16 +40,33 @@ obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/)
obj/hiro.o: hiro/hiro.cpp $(call rwildcard,hiro/)
$(compiler) $(hiroflags) -c $< -o $@
obj/ui-higan.o: $(ui)/higan.cpp $(call rwildcard,$(ui)/)
obj/ui-tomoko.o: $(ui)/tomoko.cpp $(call rwildcard,$(ui)/)
obj/ui-program.o: $(ui)/program/program.cpp $(call rwildcard,$(ui)/)
obj/ui-library.o: $(ui)/library/library.cpp $(call rwildcard,$(ui)/)
obj/ui-presentation.o: $(ui)/presentation/presentation.cpp $(call rwildcard,$(ui)/)
# build
# targets
build: $(objects)
$(strip $(compiler) -o out/$(name) $(objects) $(link))
install:
ifeq ($(shell id -un),root)
$(error "make install should not be run as root")
else ifeq ($(platform),windows)
else ifeq ($(platform),macosx)
else
cp out/$(name) $(prefix)/bin/$(name)
cp data/higan.png $(prefix)/share/icons/higan.png
cp data/higan.png $(prefix)/share/icons/$(name).png
mkdir -p ~/Emulation/System/
cp -R profile/* ~/Emulation/System/
endif
uninstall:
ifeq ($(shell id -un),root)
$(error "make uninstall should not be run as root")
else ifeq ($(platform),windows)
else ifeq ($(platform),macosx)
else
if [ -f $(prefix)/bin/$(name) ]; then rm $(prefix)/bin/$(name); fi
if [ -f $(prefix)/share/icons/higan.png ]; then rm $(prefix)/share/icons/higan.png
if [ -f $(prefix)/share/icons/$(name).png ]; then rm $(prefix)/share/icons/$(name).png; fi
endif

View File

@ -0,0 +1,35 @@
LibraryBrowser::LibraryBrowser(TabFrame& parent, Emulator::Interface::Media& media) : TabFrameItem{&parent} {
this->media = media;
setText(media.name);
layout.setMargin(5);
gameList.onActivate([&] {
libraryManager->setVisible(false);
program->loadMedia({userpath(), "Emulation/", this->media.name, "/", gameList.selected()->text(), ".", this->media.type, "/"});
});
}
auto LibraryBrowser::reload() -> void {
string path = {userpath(), "Emulation/", media.name};
directory::create(path);
gameList.reset();
gameList.append(ListViewColumn());
bool first = true;
auto folders = directory::folders(path, {"*.", media.type});
for(auto& folder : folders) {
ListViewItem item;
item.setIcon(0, Icon::Emblem::Program);
item.setText(folder.rtrim({".", media.type, "/"}));
gameList.append(item);
if(first) {
first = false;
item.setFocused();
}
}
}
auto LibraryBrowser::select() -> void {
reload();
setSelected();
gameList.setFocused();
}

View File

@ -0,0 +1,3 @@
#include "../tomoko.hpp"
#include "browser.cpp"
#include "manager.cpp"

View File

@ -0,0 +1,21 @@
struct LibraryBrowser : TabFrameItem {
LibraryBrowser(TabFrame& parent, Emulator::Interface::Media& media);
auto reload() -> void;
auto select() -> void;
Emulator::Interface::Media media;
VerticalLayout layout{this};
ListView gameList{&layout, Size{~0, ~0}};
};
struct LibraryManager : Window {
LibraryManager();
auto show(const string& type) -> void;
VerticalLayout layout{this};
TabFrame libraryFrame{&layout, Size{~0, ~0}};
vector<LibraryBrowser*> libraryBrowsers;
};
extern LibraryManager* libraryManager;

View File

@ -0,0 +1,29 @@
LibraryManager* libraryManager = nullptr;
LibraryManager::LibraryManager() {
libraryManager = this;
layout.setMargin(5);
for(auto& emulator : program->emulators) {
for(auto& media : emulator->media) {
if(media.bootable == false) continue;
auto browser = new LibraryBrowser(libraryFrame, media);
libraryBrowsers.append(browser);
}
}
setTitle("Library");
setSize({640, 800});
setPosition({0, 0});
}
auto LibraryManager::show(const string& type) -> void {
for(auto& browser : libraryBrowsers) {
if(type != browser->media.type) continue;
browser->select();
}
setVisible();
setFocused();
}

View File

@ -0,0 +1,33 @@
#include "../tomoko.hpp"
Presentation* presentation = nullptr;
Presentation::Presentation() {
presentation = this;
libraryMenu.setText("Library");
for(auto& emulator : program->emulators) {
for(auto& media : emulator->media) {
if(media.bootable == false) continue;
auto item = new MenuItem{&libraryMenu};
item->setText({media.name, " ..."}).onActivate([=] {
libraryManager->show(media.type);
});
loadBootableMedia.append(item);
}
}
superFamicomMenu.setText("Super Famicom");
settingsMenu.setText("Settings");
toolsMenu.setText("Tools");
statusBar.setFont(Font::sans(8, "Bold"));
onClose(&Application::quit);
setTitle({"tomoko v", Emulator::Version});
setResizable(false);
setSize({640, 480});
setCentered();
}

View File

@ -0,0 +1,17 @@
struct Presentation : Window {
Presentation();
MenuBar menuBar{this};
Menu libraryMenu{&menuBar};
vector<MenuItem*> loadBootableMedia;
Menu superFamicomMenu{&menuBar};
Menu settingsMenu{&menuBar};
Menu toolsMenu{&menuBar};
VerticalLayout layout{this};
Viewport viewport{&layout, Size{~0, ~0}};
StatusBar statusBar{this};
};
extern Presentation* presentation;

View File

@ -0,0 +1,78 @@
//request from emulation core to load non-volatile media folder
auto Program::loadRequest(unsigned id, string name, string type) -> void {
}
//request from emulation core to load non-volatile media file
auto Program::loadRequest(unsigned id, string path) -> void {
string location = {mediaPaths(emulator().group(id)), path};
if(!file::exists(location)) return;
mmapstream stream{location};
return emulator().load(id, stream);
}
auto Program::saveRequest(unsigned id, string path) -> void {
}
auto Program::videoColor(unsigned source, uint16 alpha, uint16 red, uint16 green, uint16 blue) -> uint32 {
alpha >>= 8;
red >>= 8;
green >>= 8;
blue >>= 8;
return alpha << 24 | red << 16 | green << 8 | blue << 0;
}
auto Program::videoRefresh(const uint32* palette, const uint32* data, unsigned pitch, unsigned width, unsigned height) -> void {
uint32* output;
unsigned length;
if(video.lock(output, length, width, height)) {
pitch >>= 2, length >>= 2;
for(auto y : range(height)) {
const uint32* sp = data + y * pitch;
uint32* dp = output + y * length;
for(auto x : range(width)) {
*dp++ = palette[*sp++];
}
}
video.unlock();
video.refresh();
}
static unsigned frameCounter = 0;
static time_t previous, current;
frameCounter++;
time(&current);
if(current != previous) {
previous = current;
presentation->statusBar.setText({"FPS: ", frameCounter});
frameCounter = 0;
}
}
auto Program::audioSample(int16 lsample, int16 rsample) -> void {
signed samples[] = {lsample, rsample};
dsp.sample(samples);
while(dsp.pending()) {
dsp.read(samples);
audio.sample(samples[0], samples[1]);
}
}
auto Program::inputPoll(unsigned port, unsigned device, unsigned input) -> int16 {
}
auto Program::inputRumble(unsigned port, unsigned device, unsigned input, bool enable) -> void {
}
auto Program::dipSettings(const Markup::Node& node) -> unsigned {
}
auto Program::path(unsigned group) -> string {
return mediaPaths(group);
}
auto Program::notify(string text) -> void {
}

View File

@ -0,0 +1,25 @@
auto Program::loadMedia(string location) -> void {
location.transform("\\", "/");
if(!directory::exists(location)) return;
string type = suffixname(location).ltrim(".");
for(auto& emulator : emulators) {
for(auto& media : emulator->media) {
if(media.bootable == false) continue;
if(media.type != type) continue;
return loadMedia(*emulator, media, location);
}
}
}
auto Program::loadMedia(Emulator::Interface& _emulator, Emulator::Interface::Media& media, const string& location) -> void {
mediaPaths(0) = {userpath(), "Emulation/System/", media.name, ".sys/"};
mediaPaths(media.id) = location;
setEmulator(_emulator);
emulator().paletteUpdate(Emulator::Interface::PaletteMode::Standard);
emulator().load(media.id);
emulator().power();
presentation->setTitle(emulator().title());
}

View File

@ -0,0 +1,80 @@
#include "../tomoko.hpp"
#include <fc/interface/interface.hpp>
#include <sfc/interface/interface.hpp>
#include <gb/interface/interface.hpp>
#include <gba/interface/interface.hpp>
#include "interface.cpp"
#include "media.cpp"
Program* program = nullptr;
Program::Program() {
program = this;
Application::onMain({&Program::main, this});
emulators.append(new Famicom::Interface);
emulators.append(new SuperFamicom::Interface);
emulators.append(new GameBoy::Interface);
emulators.append(new GameBoyAdvance::Interface);
for(auto& emulator : emulators) emulator->bind = this;
new LibraryManager;
new Presentation;
presentation->setVisible();
video.driver("XShm");
video.set(Video::Handle, presentation->viewport.handle());
video.set(Video::Synchronize, false);
if(!video.init()) { video.driver("None"); video.init(); }
audio.driver("OpenAL");
audio.set(Audio::Handle, presentation->viewport.handle());
audio.set(Audio::Synchronize, false);
audio.set(Audio::Frequency, 96000u);
audio.set(Audio::Latency, 80u);
if(!audio.init()) { audio.driver("None"); audio.init(); }
input.driver("XInput");
input.set(Input::Handle, presentation->viewport.handle());
if(!input.init()) { input.driver("None"); input.init(); }
dsp.setPrecision(16);
dsp.setBalance(0.0);
dsp.setVolume(1.0);
dsp.setFrequency(32040);
dsp.setResampler(DSP::ResampleEngine::Sinc);
dsp.setResamplerFrequency(96000);
uint32* output;
unsigned length;
if(video.lock(output, length, 640, 480)) {
for(auto y : range(480)) {
uint32* dp = output + y * (length >> 2);
for(auto x : range(640)) {
*dp++ = 0xff401010;
}
}
video.unlock();
video.refresh();
}
}
auto Program::emulator() -> Emulator::Interface& {
if(activeEmulator == nullptr) throw;
return *activeEmulator;
}
auto Program::main() -> void {
if(activeEmulator == nullptr || emulator().loaded() == false) {
audio.clear();
usleep(20 * 1000);
return;
}
emulator().run();
}
auto Program::setEmulator(Emulator::Interface& emulator) -> void {
activeEmulator = &emulator;
}

View File

@ -0,0 +1,32 @@
struct Program : Emulator::Interface::Bind {
//program.cpp
Program();
auto emulator() -> Emulator::Interface&;
auto main() -> void;
auto setEmulator(Emulator::Interface&) -> void;
//interface.cpp
auto loadRequest(unsigned id, string name, string type) -> void override;
auto loadRequest(unsigned id, string path) -> void override;
auto saveRequest(unsigned id, string path) -> void override;
auto videoColor(unsigned source, uint16 alpha, uint16 red, uint16 green, uint16 blue) -> uint32 override;
auto videoRefresh(const uint32* palette, const uint32* data, unsigned pitch, unsigned width, unsigned height) -> void override;
auto audioSample(int16 lsample, int16 rsample) -> void override;
auto inputPoll(unsigned port, unsigned device, unsigned input) -> int16 override;
auto inputRumble(unsigned port, unsigned device, unsigned input, bool enable) -> void override;
auto dipSettings(const Markup::Node& node) -> unsigned override;
auto path(unsigned group) -> string override;
auto notify(string text) -> void override;
//media.cpp
auto loadMedia(string location) -> void;
auto loadMedia(Emulator::Interface& interface, Emulator::Interface::Media& media, const string& location) -> void;
DSP dsp;
vector<Emulator::Interface*> emulators;
Emulator::Interface* activeEmulator = nullptr;
vector<string> mediaPaths;
};
extern Program* program;

8
target-tomoko/tomoko.cpp Normal file
View File

@ -0,0 +1,8 @@
#include "tomoko.hpp"
#include <nall/main.hpp>
auto nall::main(lstring args) -> void {
Application::setName("tomoko");
new Program;
Application::run();
}

View File

@ -6,3 +6,7 @@
using namespace nall;
using namespace ruby;
using namespace hiro;
#include "program/program.hpp"
#include "library/library.hpp"
#include "presentation/presentation.hpp"