Update to v094r01 release.

byuu says:

Changelog:
- port: various compilation fixes for OS X [kode54]
- nall: added programpath() function to return path to process binary
  [todo: need to have ethos use this function]
- ruby: XAudio2 will select default game sound device instead of first
  sound device
- ruby: DirectInput device IDs are no longer ambiguous when VID+PID are
  identical
- ruby: OpenGL won't try and terminate if it hasn't been initialized
- gb: D-pad up+down/left+right not masked in SGB mode
- sfc: rewrote ICD2 video rendering to output in real-time, work with
  cycle-based Game Boy renderer
- sfc: rewrote Bus::reduce(), reduces game loading time by about 500ms
- ethos: store save states in {game}/higan/* instead of {game}/bsnes/*
- loki: added target-loki/ (blank stub for now)
- Makefile: purge out/* on make clean
This commit is contained in:
Tim Allen 2014-01-28 21:04:58 +11:00
parent 10464b8c54
commit 04986d2bf7
32 changed files with 272 additions and 118 deletions

View File

@ -6,7 +6,8 @@ gb := gb
gba := gba
profile := accuracy
target := ethos
target := ethos
# target := loki
# options += debugger
# arch := x86
@ -77,6 +78,7 @@ flags := $(flags) $(foreach o,$(call strupper,$(options)),-D$o)
# targets
clean:
-@$(call delete,out/*)
-@$(call delete,obj/*.o)
-@$(call delete,obj/*.a)
-@$(call delete,obj/*.so)

View File

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

View File

@ -20,9 +20,12 @@ void CPU::mmio_joyp_poll() {
dpad |= interface->inputPoll(0, 0, (unsigned)Input::Left) << 1;
dpad |= interface->inputPoll(0, 0, (unsigned)Input::Right) << 0;
//D-pad pivot makes it impossible to press opposing directions at the same time
if(dpad & 4) dpad &= ~8; //disallow up+down
if(dpad & 2) dpad &= ~1; //disallow left+right
if(system.revision != System::Revision::SuperGameBoy) {
//D-pad pivot makes it impossible to press opposing directions at the same time
//however, Super Game Boy BIOS is able to set these bits together
if(dpad & 4) dpad &= ~8; //disallow up+down
if(dpad & 2) dpad &= ~1; //disallow left+right
}
status.joyp = 0x0f;
if(status.p15 == 1 && status.p14 == 1) status.joyp -= status.mlt_req;

View File

@ -8,6 +8,10 @@ void Interface::lcdScanline() {
if(hook) hook->lcdScanline();
}
void Interface::lcdOutput(uint2 color) {
if(hook) hook->lcdOutput(color);
}
void Interface::joypWrite(bool p15, bool p14) {
if(hook) hook->joypWrite(p15, p14);
}

View File

@ -29,11 +29,13 @@ struct Interface : Emulator::Interface {
//Super Game Boy bindings
struct Hook {
virtual void lcdScanline() {}
virtual void lcdOutput(uint2 color) {}
virtual void joypWrite(bool p15, bool p14) {}
};
Hook* hook = nullptr;
void lcdScanline();
void lcdOutput(uint2 color);
void joypWrite(bool p15, bool p14);
string title();

View File

@ -79,6 +79,7 @@ void PPU::dmg_run() {
uint32* output = screen + status.ly * 160 + px++;
*output = color;
interface->lcdOutput(color); //Super Game Boy notification
}
void PPU::dmg_run_bg() {

View File

@ -25,6 +25,8 @@ void PPU::main() {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
interface->lcdScanline(); //Super Game Boy notification
if(status.display_enable && status.ly < 144) {
if(status.interrupt_oam) cpu.interrupt_raise(CPU::Interrupt::Stat);
add_clocks(92);
@ -56,7 +58,6 @@ void PPU::scanline() {
if(++status.ly == 154) frame();
if(status.ly < 144) {
interface->lcdScanline(); //Super Game Boy rendering notification
system.cgb() ? cgb_scanline() : dmg_scanline();
}

View File

@ -3,6 +3,13 @@
namespace nall {
#if defined(_WIN32)
#elif defined(__APPLE__)
#include <machine/endian.h>
#else
#include <endian.h>
#endif
struct Intrinsics {
enum class Compiler : unsigned { Clang, GCC, VisualCPP, Unknown };
enum class Platform : unsigned { Windows, MacOSX, X, Unknown }; //X = Linux, BSD, etc

View File

@ -41,7 +41,7 @@ namespace Math {
#undef interface
#define dllexport __declspec(dllexport)
#else
#include <endian.h>
#include <dlfcn.h>
#include <unistd.h>
#include <pwd.h>
#define dllexport

View File

@ -201,6 +201,7 @@ template<signed precision = 0, char padchar = '0'> inline string binary(uintmax_
//platform.hpp
inline string activepath();
inline string realpath(const string& name);
inline string programpath();
inline string userpath();
inline string configpath();
inline string sharedpath();

View File

@ -22,6 +22,20 @@ string realpath(const string& name) {
return result;
}
string programpath() {
#if defined(PLATFORM_WINDOWS)
int argc = 0;
wchar_t** argv = CommandLineToArgvW(GetCommandLine(), &argc);
string argv0 = (const char*)utf8_t(argv[0]);
LocalFree(argv);
return realpath(argv0);
#else
Dl_info info;
dladdr((void*)&programpath, &info);
return realpath(info.dli_fname);
#endif
}
// /home/username/
// c:/users/username/
string userpath() {

View File

@ -8,7 +8,7 @@ namespace nall {
//generate unique GUID
inline string guid() {
random_lfsr lfsr;
LinearFeedbackShiftRegisterGenerator lfsr;
lfsr.seed(time(nullptr));
for(unsigned n = 0; n < 256; n++) lfsr();

View File

@ -1,8 +1,3 @@
/*
audio.xaudio2 (2010-08-14)
author: OV2
*/
#include "xaudio2.hpp"
#include <windows.h>
@ -132,7 +127,19 @@ public:
return false;
}
if(FAILED(hr = pXAudio2->CreateMasteringVoice( &pMasterVoice, 2, settings.frequency, 0, 0 , NULL))) {
unsigned deviceCount = 0;
pXAudio2->GetDeviceCount(&deviceCount);
if(deviceCount == 0) { term(); return false; }
unsigned deviceID = 0;
for(unsigned deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++) {
XAUDIO2_DEVICE_DETAILS deviceDetails;
memset(&deviceDetails, 0, sizeof(XAUDIO2_DEVICE_DETAILS));
pXAudio2->GetDeviceDetails(deviceIndex, &deviceDetails);
if(deviceDetails.Role & DefaultGameDevice) deviceID = deviceIndex;
}
if(FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasterVoice, 2, settings.frequency, 0, deviceID, NULL))) {
return false;
}
@ -145,7 +152,7 @@ public:
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.cbSize = 0;
if(FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wfx, XAUDIO2_VOICE_NOSRC , XAUDIO2_DEFAULT_FREQ_RATIO, this, NULL, NULL))) {
if(FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wfx, XAUDIO2_VOICE_NOSRC, XAUDIO2_DEFAULT_FREQ_RATIO, this, NULL, NULL))) {
return false;
}

View File

@ -35,18 +35,21 @@ struct pInputCarbon {
group.input[inputID].value = value;
}
void poll(vector<HID::Device*>& devices) {
vector<HID::Device*> poll() {
vector<HID::Device*> devices;
KeyMap keymap;
GetKeys(keymap);
uint8_t* buffer = (uint8_t*)keymap;
unsigned inputID = 0;
for(auto& key : keys) {
bool value = buffer[key.id >> 3] & (1 << (key.id & 7)));
bool value = buffer[key.id >> 3] & (1 << (key.id & 7));
assign(kb.hid, HID::Keyboard::GroupID::Button, inputID++, value);
}
devices.append(&kb.hid);
return devices;
}
bool rumble(uint64_t id, bool enable) {

View File

@ -107,13 +107,9 @@ struct InputJoypadDirectInput {
Joypad jp;
jp.vendorID = instance->guidProduct.Data1 >> 0;
jp.productID = instance->guidProduct.Data1 >> 16;
jp.isXInputDevice = false;
if(auto device = rawinput.find(jp.vendorID, jp.productID)) {
jp.pathID = crc32_calculate((const uint8_t*)device().path.data(), device().path.size());
jp.hid.id = (uint64_t)jp.pathID << 32 | jp.vendorID << 16 | jp.productID << 0;
jp.isXInputDevice = device().isXInputDevice;
} else {
//this should never occur
return DIENUM_CONTINUE;
}
//Microsoft has intentionally imposed artificial restrictions on XInput devices when used with DirectInput
@ -133,6 +129,17 @@ struct InputJoypadDirectInput {
device->EnumObjects(DirectInput_EnumJoypadEffectsCallback, (void*)this, DIDFT_FFACTUATOR);
jp.hid.rumble = effects > 0;
DIPROPGUIDANDPATH property;
memset(&property, 0, sizeof(DIPROPGUIDANDPATH));
property.diph.dwSize = sizeof(DIPROPGUIDANDPATH);
property.diph.dwHeaderSize = sizeof(DIPROPHEADER);
property.diph.dwObj = 0;
property.diph.dwHow = DIPH_DEVICE;
device->GetProperty(DIPROP_GUIDANDPATH, &property.diph);
string devicePath = (const char*)utf8_t(property.wszPath);
jp.pathID = crc32_calculate((const uint8_t*)devicePath.data(), devicePath.size());
jp.hid.id = (uint64_t)jp.pathID << 32 | jp.vendorID << 16 | jp.productID << 0;
if(jp.hid.rumble) {
//disable auto-centering spring for rumble support
DIPROPDWORD property;

View File

@ -15,13 +15,12 @@ namespace ruby {
namespace ruby {
struct pVideoCGL : OpenGL {
RubyVideoCGL* view;
RubyVideoCGL* view = nullptr;
struct {
NSView* handle;
bool synchronize;
unsigned filter;
NSView* handle = nullptr;
bool synchronize = false;
unsigned filter = 0;
string shader;
} settings;
@ -157,14 +156,6 @@ struct pVideoCGL : OpenGL {
}
}
pVideoCGL() {
view = nil;
settings.handle = nil;
settings.synchronize = false;
settings.filter = 0;
}
~pVideoCGL() {
term();
}

View File

@ -200,11 +200,13 @@ bool OpenGL::init() {
glrLinkProgram(program);
shader(nullptr);
return true;
return initialized = true;
}
void OpenGL::term() {
if(initialized == false) return;
shader(nullptr); //release shader resources (eg frame[] history)
OpenGLSurface::release();
if(buffer) { delete[] buffer; buffer = nullptr; }
initialized = false;
}

View File

@ -79,6 +79,7 @@ struct OpenGL : OpenGLProgram {
Setting(const string& name, const string& value) : name(name), value(value) {}
};
set<Setting> settings;
bool initialized = false;
void shader(const char* pathname);
void allocateHistory(unsigned size);

View File

@ -52,20 +52,19 @@ void ICD2::power() {
void ICD2::reset() {
create(ICD2::Enter, cpu.frequency / 5);
r6000_ly = 0x00;
r6000_row = 0x00;
r6003 = 0x00;
r6004 = 0xff;
r6005 = 0xff;
r6006 = 0xff;
r6007 = 0xff;
for(auto& r : r7000) r = 0x00;
r7800 = 0x0000;
mlt_req = 0;
for(auto& n : lcd.buffer) n = 0;
for(auto& n : lcd.output) n = 0;
lcd.row = 0;
for(auto& n : output) n = 0xff;
read_bank = 0;
read_addr = 0;
write_bank = 0;
write_addr = 0;
packetsize = 0;
joyp_id = 3;

View File

@ -16,8 +16,8 @@ struct ICD2 : Emulator::Interface::Bind, GameBoy::Interface::Hook, Coprocessor {
void serialize(serializer&);
private:
Emulator::Interface::Bind* bind;
GameBoy::Interface::Hook* hook;
Emulator::Interface::Bind* bind = nullptr;
GameBoy::Interface::Hook* hook = nullptr;
#include "interface/interface.hpp"
#include "mmio/mmio.hpp"
};

View File

@ -1,13 +1,20 @@
#ifdef ICD2_CPP
//called on rendered lines 0-143 (not on Vblank lines 144-153)
void ICD2::lcdScanline() {
if(GameBoy::ppu.status.ly > 143) return; //Vblank
if((GameBoy::ppu.status.ly & 7) == 0) {
lcd.row = (lcd.row + 1) & 3;
write_bank = (write_bank + 1) & 3;
write_addr = 0;
}
}
unsigned offset = (lcd.row * 160 * 8) + ((GameBoy::ppu.status.ly & 7) * 160);
memcpy(lcd.buffer + offset, GameBoy::ppu.screen + GameBoy::ppu.status.ly * 160, 160 * sizeof(uint32));
void ICD2::lcdOutput(uint2 color) {
unsigned y = write_addr / 160;
unsigned x = write_addr % 160;
unsigned addr = write_bank * 512 + y * 2 + x / 8 * 16;
output[addr + 0] = (output[addr + 0] << 1) | (bool)(color & 1);
output[addr + 1] = (output[addr + 1] << 1) | (bool)(color & 2);
write_addr = (write_addr + 1) % 1280;
}
void ICD2::joypWrite(bool p15, bool p14) {

View File

@ -1,4 +1,5 @@
void lcdScanline();
void lcdOutput(uint2 color);
void joypWrite(bool p15, bool p14);
uint32_t videoColor(unsigned source, uint16_t red, uint16_t green, uint16_t blue);

View File

@ -1,27 +1,12 @@
#ifdef ICD2_CPP
//convert linear pixel data to 2bpp planar tiledata
void ICD2::render(const uint32* source) {
memset(lcd.output, 0x00, 320 * sizeof(uint16));
for(unsigned y = 0; y < 8; y++) {
for(unsigned x = 0; x < 160; x++) {
unsigned pixel = *source++;
unsigned addr = y * 2 + (x / 8 * 16);
lcd.output[addr + 0] |= ((pixel & 1) >> 0) << (7 - (x & 7));
lcd.output[addr + 1] |= ((pixel & 2) >> 1) << (7 - (x & 7));
}
}
}
uint8 ICD2::read(unsigned addr) {
addr &= 0xffff;
//LY counter
if(addr == 0x6000) {
r6000_ly = GameBoy::ppu.status.ly;
r6000_row = lcd.row;
return r6000_ly;
unsigned y = min(143u, GameBoy::ppu.status.ly);
return (y & ~7) | write_bank;
}
//command ready port
@ -47,8 +32,8 @@ uint8 ICD2::read(unsigned addr) {
//VRAM port
if(addr == 0x7800) {
uint8 data = lcd.output[r7800];
r7800 = (r7800 + 1) % 320;
uint8 data = output[read_bank * 512 + read_addr];
read_addr = (read_addr + 1) & 511;
return data;
}
@ -60,12 +45,8 @@ void ICD2::write(unsigned addr, uint8 data) {
//VRAM port
if(addr == 0x6001) {
r6001 = data;
r7800 = 0;
unsigned offset = (r6000_row - (4 - (r6001 - (r6000_ly & 3)))) & 3;
render(lcd.buffer + offset * 160 * 8);
read_bank = data & 3;
read_addr = 0;
return;
}

View File

@ -1,19 +1,13 @@
void render(const uint32* source);
uint8 r6000_ly; //SGB BIOS' cache of LY
uint8 r6000_row; //SGB BIOS' cache of ROW
uint8 r6001; //VRAM conversion
uint8 r6003; //control port
uint8 r6004; //joypad 1
uint8 r6005; //joypad 2
uint8 r6006; //joypad 3
uint8 r6007; //joypad 4
uint8 r7000[16]; //JOYP packet data
unsigned r7800; //VRAM offset
uint8 mlt_req; //number of active joypads
struct LCD {
uint32 buffer[4 * 160 * 8]; //four tile rows of linear video data
uint16 output[320]; //one tile row of 2bpp video data
unsigned row; //active ICD2 rendering tile row
} lcd;
uint8 output[4 * 512];
unsigned read_bank;
unsigned read_addr;
unsigned write_bank;
unsigned write_addr;

View File

@ -18,21 +18,19 @@ void ICD2::serialize(serializer& s) {
s.integer(bitdata);
s.integer(bitoffset);
s.integer(r6000_ly);
s.integer(r6000_row);
s.integer(r6001);
s.integer(r6003);
s.integer(r6004);
s.integer(r6005);
s.integer(r6006);
s.integer(r6007);
s.array(r7000);
s.integer(r7800);
s.integer(mlt_req);
s.array(lcd.buffer);
s.array(lcd.output);
s.integer(lcd.row);
s.array(output);
s.integer(read_bank);
s.integer(read_addr);
s.integer(write_bank);
s.integer(write_addr);
}
#endif

View File

@ -56,31 +56,28 @@ MappedRAM::MappedRAM() : data_(nullptr), size_(0), write_protect_(false) {}
//Bus
unsigned Bus::mirror(unsigned addr, unsigned size) {
if(size == 0) return 0;
unsigned base = 0;
if(size) {
unsigned mask = 1 << 23;
while(addr >= size) {
while(!(addr & mask)) mask >>= 1;
addr -= mask;
if(size > mask) {
size -= mask;
base += mask;
}
mask >>= 1;
unsigned mask = 1 << 23;
while(addr >= size) {
while(!(addr & mask)) mask >>= 1;
addr -= mask;
if(size > mask) {
size -= mask;
base += mask;
}
base += addr;
mask >>= 1;
}
return base;
return base + addr;
}
unsigned Bus::reduce(unsigned addr, unsigned mask) {
unsigned result = 0, length = 0;
for(unsigned n = 0; n < 24; n++) {
unsigned bit = 1 << n;
if(mask & bit) continue;
result |= (bool)(addr & bit) << length++;
while(mask) {
unsigned bits = (mask & -mask) - 1;
addr = ((addr >> 1) & ~bits) | (addr & bits);
mask = (mask & (mask - 1)) >> 1;
}
return result;
return addr;
}
uint8 Bus::read(unsigned addr) {

View File

@ -12,7 +12,7 @@
namespace SuperFamicom {
namespace Info {
static const char Name[] = "bsnes";
static const unsigned SerializerVersion = 27;
static const unsigned SerializerVersion = 28;
}
}

View File

@ -54,10 +54,10 @@ obj/ui-general.o: $(ui)/general/general.cpp $(call rwildcard,$(ui)/)
obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/)
obj/ui-tools.o: $(ui)/tools/tools.cpp $(call rwildcard,$(ui)/)
obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/*)
obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/)
$(compiler) $(rubyflags) -c $< -o $@
obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/*)
obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/)
$(compiler) $(phoenixflags) -c $< -o $@
obj/resource.o: $(ui)/resource.rc
@ -99,7 +99,6 @@ else
sudo install -D -m 755 out/$(name) $(DESTDIR)$(prefix)/bin/$(name)
sudo install -D -m 644 data/$(name).png $(DESTDIR)$(prefix)/share/pixmaps/$(name).png
sudo install -D -m 644 data/$(name).desktop $(DESTDIR)$(prefix)/share/applications/$(name).desktop
sudo mkdir -p /usr/share/$(name)
sudo cp -R profile/* /usr/share/$(name)
sudo cp data/cheats.bml /usr/share/$(name)/cheats.bml

View File

@ -89,7 +89,7 @@ void Utility::load() {
presentation->setTitle(system().title());
cheatEditor->load({pathname[0], "cheats.bml"});
stateManager->load({pathname[0], "bsnes/states.bsa"}, 1);
stateManager->load({pathname[0], "higan/states.bsa"}, 1);
synchronizeDSP();
@ -104,7 +104,7 @@ void Utility::unload() {
if(tracerEnable) tracerToggle();
cheatEditor->save({pathname[0], "cheats.bml"});
stateManager->save({pathname[0], "bsnes/states.bsa"}, 1);
stateManager->save({pathname[0], "higan/states.bsa"}, 1);
system().unload();
path.reset();
@ -125,14 +125,14 @@ void Utility::saveState(unsigned slot) {
if(program->active == nullptr) return;
serializer s = system().serialize();
if(s.size() == 0) return;
directory::create({pathname[0], "bsnes/"});
if(file::write({pathname[0], "bsnes/state-", slot, ".bsa"}, s.data(), s.size()) == false);
directory::create({pathname[0], "higan/"});
if(file::write({pathname[0], "higan/state-", slot, ".bsa"}, s.data(), s.size()) == false);
showMessage({"Saved to slot ", slot});
}
void Utility::loadState(unsigned slot) {
if(program->active == nullptr) return;
auto memory = file::read({pathname[0], "bsnes/state-", slot, ".bsa"});
auto memory = file::read({pathname[0], "higan/state-", slot, ".bsa"});
if(memory.size() == 0) return showMessage({"Unable to locate slot ", slot, " state"});
serializer s(memory.data(), memory.size());
if(system().unserialize(s) == false) return showMessage({"Slot ", slot, " state incompatible"});

65
target-loki/Makefile Normal file
View File

@ -0,0 +1,65 @@
name := loki
processors := arm gsu hg51b lr35902 r65816 spc700 upd96050
include processor/Makefile
include sfc/Makefile
include gb/Makefile
ui_objects := ui-loki
ui_objects += phoenix
ui_objects += $(if $(call streq,$(platform),windows),resource)
include phoenix/Makefile
link += $(phoenixlink)
objects := $(ui_objects) $(objects)
objects := $(patsubst %,obj/%.o,$(objects))
obj/ui-loki.o: $(ui)/loki.cpp $(call rwildcard,$(ui)/)
obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/)
$(compiler) $(phoenixflags) -c $< -o $@
obj/resource.o: $(ui)/resource.rc
ifeq ($(arch),win32)
windres --target=pe-i386 $(ui)/resource.rc obj/resource.o
else
windres $(ui)/resource.rc obj/resource.o
endif
build: $(objects)
ifeq ($(platform),windows)
$(strip $(compiler) -shared -o out/phoenix.dll obj/phoenix.o $(phoenixlink))
$(strip $(compiler) -o out/$(name) $(subst obj/phoenix.o,,$(objects)) $(link) -Lout -lphoenix)
else ifeq ($(platform),macosx)
if [ -d out/$(name).app ]; then rm -r out/$(name).app; fi
mkdir out/$(name).app
mkdir out/$(name).app/Contents
mkdir out/$(name).app/Contents/MacOS
mkdir out/$(name).app/Contents/Resources
cp data/Info.plist out/$(name).app/Contents/Info.plist
$(strip $(compiler) -o out/$(name).app/Contents/MacOS/$(name) $(objects) $(link))
else
$(strip $(compiler) -o out/$(name) $(objects) $(link))
endif
install:
ifeq ($(platform),windows)
else ifeq ($(platform),macosx)
sudo mkdir -p /Library/Application\ Support/$(name)
sudo cp -R profile/* /Library/Application\ Support/$(name)
sudo chmod -R 777 /Library/Application\ Support/$(name)
else
sudo install -D -m 755 out/$(name) $(DESTDIR)$(prefix)/bin/$(name)
sudo mkdir -p /usr/share/$(name)
sudo cp -R profile/* /usr/share/$(name)
sudo chmod -R 777 /usr/share/$(name)
endif
uninstall:
ifeq ($(platform),windows)
else ifeq ($(platform),macosx)
else
sudo rm $(DESTDIR)$(prefix)/bin/$(name)
endif

38
target-loki/loki.cpp Normal file
View File

@ -0,0 +1,38 @@
#include "loki.hpp"
Program* program = nullptr;
DSP dspaudio;
string Program::path(string name) {
string path = {basepath, name};
if(file::exists(path) || directory::exists(path)) return path;
path = {userpath, name};
if(file::exists(path) || directory::exists(path)) return path;
path = {sharedpath, name};
if(file::exists(path) || directory::exists(path)) return path;
return {userpath, name};
}
void Program::main() {
}
Program::Program(int argc, char** argv) {
program = this;
basepath = nall::programpath();
userpath = {nall::configpath(), "loki/"};
sharedpath = {nall::sharedpath(), "loki/"};
directory::create(userpath);
}
int main(int argc, char** argv) {
#if defined(PLATFORM_WINDOWS)
utf8_args(argc, argv);
#endif
Application::setName("loki");
new Program(argc, argv);
delete program;
return 0;
}

29
target-loki/loki.hpp Normal file
View File

@ -0,0 +1,29 @@
#include <emulator/emulator.hpp>
#include <nall/platform.hpp>
#include <nall/config.hpp>
#include <nall/directory.hpp>
#include <nall/dsp.hpp>
#include <nall/invoke.hpp>
#include <nall/map.hpp>
#include <nall/stream/file.hpp>
#include <nall/stream/memory.hpp>
#include <nall/stream/mmap.hpp>
#include <nall/stream/vector.hpp>
using namespace nall;
#include <phoenix/phoenix.hpp>
using namespace phoenix;
struct Program {
string basepath;
string userpath;
string sharedpath;
string path(string name);
void main();
Program(int argc, char** argv);
};
extern Program* program;
extern DSP dspaudio;