Update to v078 release.

byuu says:

Finally, a new release. I have been very busy finishing up SNES box,
cartridge and PCB scanning plus cataloguing the data, however this
release still has some significant improvements.

Most notably would be randomization on startup. This will help match the
behavior of real hardware and uninitialized memory + registers. It
should help catch homebrew software that forgets to initialize things
properly. Of course, I was not able to test the complete library, so it
is possible that if I've randomized anything that should be constant,
that this could cause a regression. You can disable this randomization
for netplay or to work around any incompatibilities by editing bsnes.cfg
and setting snes.random to false.

The GUI also received some updates. Widget sizes are now computed based
on font sizes, giving it a perfectly native look (because it is native.)
I've also added a hotkey remapping screen to the input settings. Not
only can you remap inputs to controllers now, but those who did not know
the hotkey bindings can now quickly see which ones exist and what they
are mapped to.

Changelog (since v077):

- memory and most registers are now randomly initialized on power-up
- fixed auto joypad polling issue in Super Star Wars
- fixed .nec and .rtc file extensions (they were missing the dot) [krom]
- PPU/accuracy now clears overscan region on any frame when it is
  disabled
- PPU/compatibility no longer auto-blends hires pixels (use NTSC filter
  for this)
- added hotkey remapping dialog to input settings window
- added a few new hotkeys, including quick-reset
- phoenix API now auto-sizes widgets based on font sizes
- file dialog once again remembers previously selected file when
  possible
This commit is contained in:
Tim Allen 2011-04-30 23:12:15 +10:00
parent 378b78dad7
commit 0a3d6e4c53
105 changed files with 3553 additions and 1518 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
class Interface {
public:
virtual void video_refresh(const uint16_t *data, unsigned width, unsigned height) {}
virtual void video_refresh(const uint16_t *data, bool hires, bool interlace, bool overscan) {}
virtual void audio_sample(uint16_t l_sample, uint16_t r_sample) {}
virtual void input_poll() {}
virtual int16_t input_poll(bool port, Input::Device device, unsigned index, unsigned id) { return 0; }

View File

@ -40,7 +40,7 @@ void PPU::enter() {
scanline();
add_clocks(60);
if(vcounter() <= (!regs.overscan ? 224 : 239)) {
if(vcounter() <= 239) {
for(signed pixel = -7; pixel <= 255; pixel++) {
bg1.run(1);
bg2.run(1);

View File

@ -22,6 +22,8 @@ void PPU::Screen::run() {
}
uint16 PPU::Screen::get_pixel(bool swap) {
if(ppu.regs.overscan == false && ppu.vcounter() >= 225) return 0x0000;
enum source_t { BG1, BG2, BG3, BG4, OAM, BACK };
bool color_enable[] = { regs.bg1_color_enable, regs.bg2_color_enable, regs.bg3_color_enable, regs.bg4_color_enable, regs.oam_color_enable, regs.back_color_enable };

View File

@ -1,7 +1,7 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "077.05";
static const char Version[] = "078";
static const unsigned SerializerVersion = 19;
}
}

View File

@ -56,7 +56,7 @@ void Video::update() {
uint16_t *data = (uint16_t*)ppu.output;
if(ppu.interlace() && ppu.field()) data += 512;
if(frame_hires) {
if(hires) {
//normalize line widths
for(unsigned y = 0; y < 240; y++) {
if(line_width[y] == 512) continue;
@ -67,25 +67,22 @@ void Video::update() {
}
}
system.interface->video_refresh(ppu.output, 256 << frame_hires, 240 << frame_interlace);
system.interface->video_refresh(ppu.surface, hires, ppu.interlace(), ppu.overscan());
frame_hires = false;
frame_interlace = false;
hires = false;
}
void Video::scanline() {
unsigned y = cpu.vcounter();
if(y >= 240) return;
frame_hires |= ppu.hires();
frame_interlace |= ppu.interlace();
hires |= ppu.hires();
unsigned width = (ppu.hires() == false ? 256 : 512);
line_width[y] = width;
}
void Video::init() {
frame_hires = false;
frame_interlace = false;
hires = false;
for(unsigned i = 0; i < 240; i++) line_width[i] = 256;
}

View File

@ -1,7 +1,6 @@
class Video {
private:
bool frame_hires;
bool frame_interlace;
bool hires;
unsigned line_width[240];
void update();

View File

@ -12,7 +12,11 @@ struct Interface : public SNES::Interface {
snes_input_state_t pinput_state;
string basename;
void video_refresh(const uint16_t *data, unsigned width, unsigned height) {
void video_refresh(const uint16_t *data, bool hires, bool interlace, bool overscan) {
unsigned width = hires ? 512 : 256;
unsigned height = overscan ? 224 : 239;
if(interlace) height <<= 1;
data += 9 * 1024; //skip front porch
if(pvideo_refresh) return pvideo_refresh(data, width, height);
}

View File

@ -78,24 +78,27 @@ void Filter::render(uint32_t *output, unsigned outpitch, const uint16_t *input,
}
}
void Interface::video_refresh(const uint16_t *data, unsigned width, unsigned height) {
bool interlace = SNES::ppu.interlace();
bool overscan = SNES::ppu.overscan();
//data is a 512x512x16bpp buffer, broken in two-scanline pairs (for interlace):
// 0 - 7 = front porch
// 8 = empty scanline 0
// 9 - 232 = standard scanlines 1 - 224
//233 - 247 = overscan scanlines 225-239
//248 - 255 = back porch
void Interface::video_refresh(const uint16_t *data, bool hires, bool interlace, bool overscan) {
unsigned width = hires ? 512 : 256;
unsigned height = config.video.region == 0 ? 224 : 239;
if(interlace) height <<= 1;
unsigned inpitch = interlace ? 1024 : 2048;
//always ignore blank scanline 0
data += 1024;
height -= 1 << interlace;
if(config.video.region == 0) {
//NTSC overscan compensation
height -= 15 << interlace;
if(overscan == true ) data += 7 * 1024;
if(overscan == false) data += 9 * 1024; // 0 + 224 + 0
if(overscan == true ) data += 16 * 1024; //-7 + 224 + -7
}
if(config.video.region == 1) {
//PAL underscan compensation
if(overscan == false) data -= 7 * 1024;
if(overscan == false) data += 1 * 1024; // 8 + 224 + 7
if(overscan == true ) data += 9 * 1024; // 0 + 239 + 0
}
unsigned outwidth = width, outheight = height;

View File

@ -15,7 +15,7 @@ struct Filter : public library {
};
struct Interface : public SNES::Interface {
void video_refresh(const uint16_t *data, unsigned width, unsigned height);
void video_refresh(const uint16_t *data, bool hires, bool interlace, bool overscan);
void audio_sample(uint16_t left, uint16_t right);
void input_poll();
int16_t input_poll(bool port, SNES::Input::Device device, unsigned index, unsigned id);

View File

@ -3,12 +3,12 @@
namespace nall {
template<int bits> inline unsigned uclamp(const unsigned x) {
enum { y = (1U << bits) - 1 };
enum { y = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1) };
return y + ((x - y) & -(x < y)); //min(x, y);
}
template<int bits> inline unsigned uclip(const unsigned x) {
enum { m = (1U << bits) - 1 };
enum { m = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1) };
return (x & m);
}

View File

@ -45,11 +45,11 @@ namespace nall {
void set(string s) {
switch(type) {
case boolean_t: *(bool*)data = (s == "true"); break;
case signed_t: *(signed*)data = strsigned(s); break;
case unsigned_t: *(unsigned*)data = strunsigned(s); break;
case double_t: *(double*)data = strdouble(s); break;
case string_t: s.trim("\""); *(string*)data = s; break;
case boolean_t: *(bool*)data = (s == "true"); break;
case signed_t: *(signed*)data = integer(s); break;
case unsigned_t: *(unsigned*)data = decimal(s); break;
case double_t: *(double*)data = fp(s); break;
case string_t: s.trim("\""); *(string*)data = s; break;
}
}
};

View File

@ -41,14 +41,14 @@ struct directory {
if(handle != INVALID_HANDLE_VALUE) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = utf8_t(data.cFileName);
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(string(name, "/"));
}
}
while(FindNextFile(handle, &data) != false) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = utf8_t(data.cFileName);
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(string(name, "/"));
}
}
@ -70,12 +70,12 @@ struct directory {
handle = FindFirstFile(utf16_t(path), &data);
if(handle != INVALID_HANDLE_VALUE) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
string name = utf8_t(data.cFileName);
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
while(FindNextFile(handle, &data) != false) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
string name = utf8_t(data.cFileName);
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
}

View File

@ -19,6 +19,7 @@ namespace nall {
struct library {
bool opened() const { return handle; }
bool open(const char*, const char* = "");
bool open_absolute(const char*);
void* sym(const char*);
void close();
@ -40,6 +41,12 @@ namespace nall {
return handle;
}
inline bool library::open_absolute(const char *name) {
if(handle) close();
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
return handle;
}
inline void* library::sym(const char *name) {
if(!handle) return 0;
return dlsym((void*)handle, name);
@ -58,6 +65,12 @@ namespace nall {
return handle;
}
inline bool library::open_absolute(const char *name) {
if(handle) close();
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
return handle;
}
inline void* library::sym(const char *name) {
if(!handle) return 0;
return dlsym((void*)handle, name);
@ -76,6 +89,12 @@ namespace nall {
return handle;
}
inline bool library::open_absolute(const char *name) {
if(handle) close();
handle = (uintptr_t)LoadLibraryW(utf16_t(name));
return handle;
}
inline void* library::sym(const char *name) {
if(!handle) return 0;
return (void*)GetProcAddress((HMODULE)handle, name);

View File

@ -21,7 +21,7 @@ namespace nall {
public:
enum class mode : unsigned { read, write, readwrite, writeread };
bool opened() const { return p_opened(); }
bool open() const { return p_open(); }
bool open(const char *filename, mode mode_) { return p_open(filename, mode_); }
void close() { return p_close(); }
unsigned size() const { return p_size; }
@ -42,7 +42,7 @@ namespace nall {
HANDLE p_filehandle, p_maphandle;
bool p_opened() const {
bool p_open() const {
return p_handle;
}
@ -128,7 +128,7 @@ namespace nall {
int p_fd;
bool p_opened() const {
bool p_open() const {
return p_handle;
}

View File

@ -5,8 +5,14 @@
#include <nall/concept.hpp>
#undef foreach
#define foreach(iter, object) \
#define foreach2(iter, object) foreach3(iter, object, foreach_counter)
#define foreach3(iter, object, foreach_counter) \
for(unsigned foreach_counter = 0, foreach_limit = container_size(object), foreach_once = 0, foreach_broken = 0; foreach_counter < foreach_limit && foreach_broken == 0; foreach_counter++, foreach_once = 0) \
for(auto &iter = object[foreach_counter]; foreach_once == 0 && (foreach_broken = 1); foreach_once++, foreach_broken = 0)
#define foreach_impl(...) foreach_decl(__VA_ARGS__, foreach3(__VA_ARGS__), foreach2(__VA_ARGS__), foreach_too_few_arguments)
#define foreach_decl(_1, _2, _3, N, ...) N
#define foreach(...) foreach_impl(__VA_ARGS__)
#endif

View File

@ -27,7 +27,7 @@ namespace nall {
};
template<typename L> struct lambda : container {
L object;
mutable L object;
R operator()(P... p) const { return object(std::forward<P>(p)...); }
container* copy() const { return new lambda(object); }
lambda(const L& object) : object(object) {}
@ -46,7 +46,7 @@ namespace nall {
return *this;
}
function(const function &source) { operator=(source); }
function(const function &source) : callback(0) { operator=(source); }
function() : callback(0) {}
function(void *function) : callback(0) { if(function) callback = new global((R (*)(P...))function); }
function(R (*function)(P...)) { callback = new global(function); }

View File

@ -0,0 +1,105 @@
#ifndef NALL_GAMEBOY_CARTRIDGE_HPP
#define NALL_GAMEBOY_CARTRIDGE_HPP
namespace nall {
class GameBoyCartridge {
public:
string xml;
inline GameBoyCartridge(const uint8_t *data, unsigned size);
//private:
struct Information {
string mapper;
bool ram;
bool battery;
bool rtc;
bool rumble;
unsigned romsize;
unsigned ramsize;
} info;
};
GameBoyCartridge::GameBoyCartridge(const uint8_t *romdata, unsigned romsize) {
xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
if(romsize < 0x4000) return;
info.mapper = "unknown";
info.ram = false;
info.battery = false;
info.rtc = false;
info.rumble = false;
info.romsize = 0;
info.ramsize = 0;
switch(romdata[0x0147]) {
case 0x00: info.mapper = "none"; break;
case 0x01: info.mapper = "MBC1"; break;
case 0x02: info.mapper = "MBC1"; info.ram = true; break;
case 0x03: info.mapper = "MBC1"; info.ram = true; info.battery = true; break;
case 0x05: info.mapper = "MBC2"; info.ram = true; break;
case 0x06: info.mapper = "MBC2"; info.ram = true; info.battery = true; break;
case 0x08: info.mapper = "none"; info.ram = true; break;
case 0x09: info.mapper = "MBC0"; info.ram = true; info.battery = true; break;
case 0x0b: info.mapper = "MMM01"; break;
case 0x0c: info.mapper = "MMM01"; info.ram = true; break;
case 0x0d: info.mapper = "MMM01"; info.ram = true; info.battery = true; break;
case 0x0f: info.mapper = "MBC3"; info.rtc = true; info.battery = true; break;
case 0x10: info.mapper = "MBC3"; info.rtc = true; info.ram = true; info.battery = true; break;
case 0x11: info.mapper = "MBC3"; break;
case 0x12: info.mapper = "MBC3"; info.ram = true; break;
case 0x13: info.mapper = "MBC3"; info.ram = true; info.battery = true; break;
case 0x19: info.mapper = "MBC5"; break;
case 0x1a: info.mapper = "MBC5"; info.ram = true; break;
case 0x1b: info.mapper = "MBC5"; info.ram = true; info.battery = true; break;
case 0x1c: info.mapper = "MBC5"; info.rumble = true; break;
case 0x1d: info.mapper = "MBC5"; info.rumble = true; info.ram = true; break;
case 0x1e: info.mapper = "MBC5"; info.rumble = true; info.ram = true; info.battery = true; break;
case 0xfc: break; //Pocket Camera
case 0xfd: break; //Bandai TAMA5
case 0xfe: info.mapper = "HuC3"; break;
case 0xff: info.mapper = "HuC1"; info.ram = true; info.battery = true; break;
}
switch(romdata[0x0148]) { default:
case 0x00: info.romsize = 2 * 16 * 1024; break;
case 0x01: info.romsize = 4 * 16 * 1024; break;
case 0x02: info.romsize = 8 * 16 * 1024; break;
case 0x03: info.romsize = 16 * 16 * 1024; break;
case 0x04: info.romsize = 32 * 16 * 1024; break;
case 0x05: info.romsize = 64 * 16 * 1024; break;
case 0x06: info.romsize = 128 * 16 * 1024; break;
case 0x07: info.romsize = 256 * 16 * 1024; break;
case 0x52: info.romsize = 72 * 16 * 1024; break;
case 0x53: info.romsize = 80 * 16 * 1024; break;
case 0x54: info.romsize = 96 * 16 * 1024; break;
}
switch(romdata[0x0149]) { default:
case 0x00: info.ramsize = 0 * 1024; break;
case 0x01: info.ramsize = 2 * 1024; break;
case 0x02: info.ramsize = 8 * 1024; break;
case 0x03: info.ramsize = 32 * 1024; break;
}
if(info.mapper == "MBC2") info.ramsize = 512; //512 x 4-bit
xml << "<cartridge mapper='" << info.mapper << "'";
if(info.rtc) xml << " rtc='true'";
if(info.rumble) xml << " rumble='true'";
xml << ">\n";
xml << " <rom size='" << hex(romsize) << "'/>\n"; //TODO: trust/check info.romsize?
if(info.ramsize > 0)
xml << " <ram size='" << hex(info.ramsize) << "' battery='" << info.battery << "'/>\n";
xml << "</cartridge>\n";
xml.transform("'", "\"");
}
}
#endif

View File

@ -92,7 +92,7 @@ struct Keyboard {
string s(name);
if(!strbegin(name, "KB")) return 0;
s.ltrim("KB");
unsigned id = strunsigned(s);
unsigned id = decimal(s);
auto pos = strpos(s, "::");
if(!pos) return 0;
s = substr(s, pos() + 2);
@ -189,7 +189,7 @@ struct Mouse {
string s(name);
if(!strbegin(name, "MS")) return 0;
s.ltrim("MS");
unsigned id = strunsigned(s);
unsigned id = decimal(s);
auto pos = strpos(s, "::");
if(!pos) return 0;
s = substr(s, pos() + 2);
@ -313,7 +313,7 @@ struct Joypad {
string s(name);
if(!strbegin(name, "JP")) return 0;
s.ltrim("JP");
unsigned id = strunsigned(s);
unsigned id = decimal(s);
auto pos = strpos(s, "::");
if(!pos) return 0;
s = substr(s, pos() + 2);

32
snesfilter/nall/public_cast.hpp Executable file
View File

@ -0,0 +1,32 @@
#ifndef NALL_PUBLIC_CAST_HPP
#define NALL_PUBLIC_CAST_HPP
//this is a proof-of-concept-*only* C++ access-privilege elevation exploit.
//this code is 100% legal C++, per C++98 section 14.7.2 paragraph 8:
//"access checking rules do not apply to names in explicit instantiations."
//usage example:
//struct N { typedef void (Class::*)(); };
//template class public_cast<N, &Class::Reference>;
//(class.*public_cast<N>::value);
//Class::Reference may be public, protected or private
//Class::Reference may be a function, object or variable
namespace nall {
template<typename T, typename T::type... P> struct public_cast;
template<typename T> struct public_cast<T> {
static typename T::type value;
};
template<typename T> typename T::type public_cast<T>::value;
template<typename T, typename T::type P> struct public_cast<T, P> {
static typename T::type value;
};
template<typename T, typename T::type P> typename T::type public_cast<T, P>::value = public_cast<T>::value = P;
}
#endif

View File

@ -8,12 +8,20 @@ namespace nall {
return n = (n >> 1) ^ (((n & 1) - 1) & 0xedb88320);
}
struct random_cyclic {
unsigned seed;
inline unsigned operator()() {
return seed = (seed >> 1) ^ (((seed & 1) - 1) & 0xedb88320);
struct random_lfsr {
inline void seed(unsigned seed__) {
seed_ = seed__;
}
random_cyclic() : seed(0) {}
inline unsigned operator()() {
return seed_ = (seed_ >> 1) ^ (((seed_ & 1) - 1) & 0xedb88320);
}
random_lfsr() : seed_(0) {
}
private:
unsigned seed_;
};
}

View File

@ -0,0 +1,103 @@
#ifndef NALL_REFERENCE_ARRAY_HPP
#define NALL_REFERENCE_ARRAY_HPP
#include <type_traits>
#include <nall/bit.hpp>
#include <nall/concept.hpp>
namespace nall {
template<typename T> struct reference_array {
protected:
typedef typename std::remove_reference<T>::type *Tptr;
Tptr *pool;
unsigned poolsize, buffersize;
public:
unsigned size() const { return buffersize; }
unsigned capacity() const { return poolsize; }
void reset() {
if(pool) free(pool);
pool = 0;
poolsize = 0;
buffersize = 0;
}
void reserve(unsigned newsize) {
if(newsize == poolsize) return;
pool = (Tptr*)realloc(pool, newsize * sizeof(T));
poolsize = newsize;
buffersize = min(buffersize, newsize);
}
void resize(unsigned newsize) {
if(newsize > poolsize) reserve(bit::round(newsize));
buffersize = newsize;
}
void append(const T data) {
unsigned index = buffersize++;
if(index >= poolsize) resize(index + 1);
pool[index] = &data;
}
template<typename... Args> reference_array(Args&... args) : pool(0), poolsize(0), buffersize(0) {
construct(args...);
}
~reference_array() {
reset();
}
reference_array& operator=(const reference_array &source) {
if(pool) free(pool);
buffersize = source.buffersize;
poolsize = source.poolsize;
pool = (Tptr*)malloc(sizeof(T) * poolsize);
memcpy(pool, source.pool, sizeof(T) * buffersize);
return *this;
}
reference_array& operator=(const reference_array &&source) {
if(pool) free(pool);
pool = source.pool;
poolsize = source.poolsize;
buffersize = source.buffersize;
source.pool = 0;
source.reset();
return *this;
}
inline T operator[](unsigned index) {
if(index >= buffersize) throw "reference_array[] out of bounds";
return *pool[index];
}
inline const T operator[](unsigned index) const {
if(index >= buffersize) throw "reference_array[] out of bounds";
return *pool[index];
}
private:
void construct() {
}
void construct(const reference_array &source) {
operator=(source);
}
void construct(const reference_array &&source) {
operator=(std::move(source));
}
template<typename... Args> void construct(T data, Args&... args) {
append(data);
construct(args...);
}
};
template<typename T> struct has_size<reference_array<T>> { enum { value = true }; };
}
#endif

View File

@ -1,13 +1,12 @@
#ifndef NALL_SNES_INFO_HPP
#define NALL_SNES_INFO_HPP
#ifndef NALL_SNES_CARTRIDGE_HPP
#define NALL_SNES_CARTRIDGE_HPP
namespace nall {
class snes_information {
class SNESCartridge {
public:
string xml_memory_map;
inline snes_information(const uint8_t *data, unsigned size);
string xmlMemoryMap;
inline SNESCartridge(const uint8_t *data, unsigned size);
//private:
inline void read_header(const uint8_t *data, unsigned size);
@ -106,30 +105,30 @@ public:
bool has_st018;
};
snes_information::snes_information(const uint8_t *data, unsigned size) {
SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
read_header(data, size);
string xml = "<?xml version='1.0' encoding='UTF-8'?>\n";
if(type == TypeBsx) {
xml << "<cartridge/>";
xml_memory_map = xml;
xmlMemoryMap = xml.transform("'", "\"");
return;
}
if(type == TypeSufamiTurbo) {
xml << "<cartridge/>";
xml_memory_map = xml;
xmlMemoryMap = xml.transform("'", "\"");
return;
}
if(type == TypeGameBoy) {
xml << "<cartridge rtc='" << gameboy_has_rtc(data, size) << "'>\n";
if(gameboy_ram_size(data, size) > 0) {
xml << " <ram size='" << strhex(gameboy_ram_size(data, size)) << "'/>\n";
xml << " <ram size='" << hex(gameboy_ram_size(data, size)) << "'/>\n";
}
xml << "</cartridge>\n";
xml_memory_map = xml;
xmlMemoryMap = xml.transform("'", "\"");
return;
}
@ -146,23 +145,19 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <supergameboy revision='1'>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </mmio>\n";
xml << " </supergameboy>\n";
xml << " <icd2 revision='1'>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </icd2>\n";
} else if(type == TypeSuperGameBoy2Bios) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <supergameboy revision='2'>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </mmio>\n";
xml << " </supergameboy>\n";
xml << " <icd2 revision='2'>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </icd2>\n";
} else if(has_spc7110) {
xml << " <rom>\n";
xml << " <map mode='shadow' address='00-0f:8000-ffff'/>\n";
@ -172,9 +167,9 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
xml << " <spc7110>\n";
xml << " <mcu>\n";
xml << " <map address='d0-ff:0000-ffff' offset='100000' size='" << strhex(size - 0x100000) << "'/>\n";
xml << " <map address='d0-ff:0000-ffff' offset='100000' size='" << hex(size - 0x100000) << "'/>\n";
xml << " </mcu>\n";
xml << " <ram size='" << strhex(ram_size) << "'>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='00:6000-7fff'/>\n";
xml << " <map mode='linear' address='30:6000-7fff'/>\n";
xml << " </ram>\n";
@ -199,7 +194,7 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
xml << " </rom>\n";
if(ram_size > 0) {
xml << " <ram size='" << strhex(ram_size) << "'>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
@ -220,7 +215,7 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
xml << " </rom>\n";
if(ram_size > 0) {
xml << " <ram size='" << strhex(ram_size) << "'>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
@ -238,7 +233,7 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
xml << " </rom>\n";
if(ram_size > 0) {
xml << " <ram size='" << strhex(ram_size) << "'>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
@ -253,7 +248,7 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
xml << " </rom>\n";
if(ram_size > 0) {
xml << " <ram size='" << strhex(ram_size) << "'>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
@ -271,7 +266,7 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-df:0000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram size='" << strhex(ram_size) << "'>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='00-3f:6000-7fff' size='2000'/>\n";
xml << " <map mode='linear' address='60-7f:0000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:6000-7fff' size='2000'/>\n";
@ -284,19 +279,23 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
xml << " </superfx>\n";
} else if(mapper == SA1ROM) {
xml << " <sa1>\n";
xml << " <rom>\n";
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-ff:0000-ffff'/>\n";
xml << " </rom>\n";
xml << " <mcu>\n";
xml << " <rom>\n";
xml << " <map mode='direct' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='direct' address='80-bf:8000-ffff'/>\n";
xml << " <map mode='direct' address='c0-ff:0000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram>\n";
xml << " <map mode='direct' address='00-3f:6000-7fff'/>\n";
xml << " <map mode='direct' address='80-bf:6000-7fff'/>\n";
xml << " </ram>\n";
xml << " </mcu>\n";
xml << " <iram size='800'>\n";
xml << " <map mode='linear' address='00-3f:3000-37ff'/>\n";
xml << " <map mode='linear' address='80-bf:3000-37ff'/>\n";
xml << " </iram>\n";
xml << " <bwram size='" << strhex(ram_size) << "'>\n";
xml << " <map mode='linear' address='00-3f:6000-7fff'/>\n";
xml << " <bwram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='40-4f:0000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:6000-7fff'/>\n";
xml << " </bwram>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:2200-23ff'/>\n";
@ -310,7 +309,7 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
xml << " <map mode='linear' address='80-9f:8000-ffff' offset='200000'/>\n";
xml << " <map mode='linear' address='a0-bf:8000-ffff' offset='100000'/>\n";
xml << " </rom>\n";
xml << " <ram size='" << strhex(ram_size) << "'>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
xml << " <map mode='linear' address='f0-ff:0000-7fff'/>\n";
xml << " </ram>\n";
@ -326,7 +325,7 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
xml << " <map mode='shadow' address='80-9f:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-df:0000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram size='" << strhex(ram_size) << "'>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
xml << " </ram>\n";
@ -339,11 +338,14 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
xml << " </slot>\n";
xml << " </bsx>\n";
} else if(mapper == BSXROM) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <bsx>\n";
xml << " <mcu>\n";
xml << " <map address='00-3f:8000-ffff'/>\n";
xml << " <map address='80-bf:8000-ffff'/>\n";
xml << " <map address='40-7f:0000-ffff'/>\n";
xml << " <map address='c0-ff:0000-ffff'/>\n";
xml << " <map address='20-3f:6000-7fff'/>\n";
xml << " </mcu>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:5000-5fff'/>\n";
xml << " <map address='80-bf:5000-5fff'/>\n";
@ -360,7 +362,7 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
xml << " <map mode='linear' address='20-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='a0-bf:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram>\n";
xml << " <ram size='20000'>\n";
xml << " <map mode='linear' address='60-63:8000-ffff'/>\n";
xml << " <map mode='linear' address='e0-e3:8000-ffff'/>\n";
xml << " </ram>\n";
@ -370,7 +372,7 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
xml << " <map mode='linear' address='40-5f:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-df:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram>\n";
xml << " <ram size='20000'>\n";
xml << " <map mode='linear' address='70-73:8000-ffff'/>\n";
xml << " <map mode='linear' address='f0-f3:8000-ffff'/>\n";
xml << " </ram>\n";
@ -380,10 +382,8 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
if(has_srtc) {
xml << " <srtc>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:2800-2801'/>\n";
xml << " <map address='80-bf:2800-2801'/>\n";
xml << " </mmio>\n";
xml << " <map address='00-3f:2800-2801'/>\n";
xml << " <map address='80-bf:2800-2801'/>\n";
xml << " </srtc>\n";
}
@ -401,15 +401,13 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
if(has_cx4) {
xml << " <cx4>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </mmio>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </cx4>\n";
}
if(has_dsp1) {
xml << " <necdsp program='DSP-1B'>\n";
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n";
if(dsp1_mapper == DSP1LoROM1MB) {
xml << " <dr>\n";
xml << " <map address='20-3f:8000-bfff'/>\n";
@ -442,7 +440,7 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
}
if(has_dsp2) {
xml << " <necdsp program='DSP-2'>\n";
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n";
xml << " <dr>\n";
xml << " <map address='20-3f:8000-bfff'/>\n";
xml << " <map address='a0-bf:8000-bfff'/>\n";
@ -455,7 +453,7 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
}
if(has_dsp3) {
xml << " <necdsp program='DSP-3'>\n";
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n";
xml << " <dr>\n";
xml << " <map address='20-3f:8000-bfff'/>\n";
xml << " <map address='a0-bf:8000-bfff'/>\n";
@ -468,7 +466,7 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
}
if(has_dsp4) {
xml << " <necdsp program='DSP-4'>\n";
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n";
xml << " <dr>\n";
xml << " <map address='30-3f:8000-bfff'/>\n";
xml << " <map address='b0-bf:8000-bfff'/>\n";
@ -482,46 +480,57 @@ snes_information::snes_information(const uint8_t *data, unsigned size) {
if(has_obc1) {
xml << " <obc1>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </mmio>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </obc1>\n";
}
if(has_st010) {
xml << " <setadsp program='ST-0010'>\n";
xml << " <mmio>\n";
xml << " <necdsp revision='upd96050' frequency='10000000' program='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n";
xml << " <dr>\n";
xml << " <map address='60:0000'/>\n";
xml << " <map address='e0:0000'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='60:0001'/>\n";
xml << " <map address='e0:0001'/>\n";
xml << " </sr>\n";
xml << " <dp>\n";
xml << " <map address='68-6f:0000-0fff'/>\n";
xml << " <map address='e8-ef:0000-0fff'/>\n";
xml << " </mmio>\n";
xml << " </setadsp>\n";
xml << " </dp>\n";
xml << " </necdsp>\n";
}
if(has_st011) {
//ST-0011 addresses not verified; chip is unsupported
xml << " <setadsp program='ST-0011'>\n";
xml << " <mmio>\n";
xml << " <necdsp revision='upd96050' frequency='15000000' program='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n";
xml << " <dr>\n";
xml << " <map address='60:0000'/>\n";
xml << " <map address='e0:0000'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='60:0001'/>\n";
xml << " <map address='e0:0001'/>\n";
xml << " </sr>\n";
xml << " <dp>\n";
xml << " <map address='68-6f:0000-0fff'/>\n";
xml << " <map address='e8-ef:0000-0fff'/>\n";
xml << " </mmio>\n";
xml << " </setadsp>\n";
xml << " </dp>\n";
xml << " </necdsp>\n";
}
if(has_st018) {
xml << " <setarisc program='ST-0018'>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:3800-38ff'/>\n";
xml << " <map address='80-bf:3800-38ff'/>\n";
xml << " </mmio>\n";
xml << " <map address='00-3f:3800-38ff'/>\n";
xml << " <map address='80-bf:3800-38ff'/>\n";
xml << " </setarisc>\n";
}
xml << "</cartridge>\n";
xml_memory_map = xml;
xmlMemoryMap = xml.transform("'", "\"");
}
void snes_information::read_header(const uint8_t *data, unsigned size) {
void SNESCartridge::read_header(const uint8_t *data, unsigned size) {
type = TypeUnknown;
mapper = LoROM;
dsp1_mapper = DSP1Unmapped;
@ -749,7 +758,7 @@ void snes_information::read_header(const uint8_t *data, unsigned size) {
}
}
unsigned snes_information::find_header(const uint8_t *data, unsigned size) {
unsigned SNESCartridge::find_header(const uint8_t *data, unsigned size) {
unsigned score_lo = score_header(data, size, 0x007fc0);
unsigned score_hi = score_header(data, size, 0x00ffc0);
unsigned score_ex = score_header(data, size, 0x40ffc0);
@ -764,7 +773,7 @@ unsigned snes_information::find_header(const uint8_t *data, unsigned size) {
}
}
unsigned snes_information::score_header(const uint8_t *data, unsigned size, unsigned addr) {
unsigned SNESCartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) {
if(size < addr + 64) return 0; //image too small to contain header at this location?
int score = 0;
@ -845,7 +854,7 @@ unsigned snes_information::score_header(const uint8_t *data, unsigned size, unsi
return score;
}
unsigned snes_information::gameboy_ram_size(const uint8_t *data, unsigned size) {
unsigned SNESCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) {
if(size < 512) return 0;
switch(data[0x0149]) {
case 0x00: return 0 * 1024;
@ -858,7 +867,7 @@ unsigned snes_information::gameboy_ram_size(const uint8_t *data, unsigned size)
}
}
bool snes_information::gameboy_has_rtc(const uint8_t *data, unsigned size) {
bool SNESCartridge::gameboy_has_rtc(const uint8_t *data, unsigned size) {
if(size < 512) return false;
if(data[0x0147] == 0x0f ||data[0x0147] == 0x10) return true;
return false;

458
snesfilter/nall/snes/cpu.hpp Executable file
View File

@ -0,0 +1,458 @@
#ifndef NALL_SNES_CPU_HPP
#define NALL_SNES_CPU_HPP
namespace nall {
struct SNESCPU {
enum : unsigned {
Implied, //
Constant, //#$00
AccumConstant, //#$00
IndexConstant, //#$00
Direct, //$00
DirectX, //$00,x
DirectY, //$00,y
IDirect, //($00)
IDirectX, //($00,x)
IDirectY, //($00),y
ILDirect, //[$00]
ILDirectY, //[$00],y
Address, //$0000
AddressX, //$0000,x
AddressY, //$0000,y
IAddressX, //($0000,x)
ILAddress, //[$0000]
PAddress, //PBR:$0000
PIAddress, //PBR:($0000)
Long, //$000000
LongX, //$000000,x
Stack, //$00,s
IStackY, //($00,s),y
BlockMove, //$00,$00
RelativeShort, //+/- $00
RelativeLong, //+/- $0000
};
struct OpcodeInfo {
char name[4];
unsigned mode;
};
static const OpcodeInfo opcodeInfo[256];
static unsigned getOpcodeLength(bool accum, bool index, uint8_t opcode);
static string disassemble(unsigned pc, bool accum, bool index, uint8_t opcode, uint8_t pl, uint8_t ph, uint8_t pb);
};
const SNESCPU::OpcodeInfo SNESCPU::opcodeInfo[256] = {
//0x00 - 0x0f
{ "brk", Constant },
{ "ora", IDirectX },
{ "cop", Constant },
{ "ora", Stack },
{ "tsb", Direct },
{ "ora", Direct },
{ "asl", Direct },
{ "ora", ILDirect },
{ "php", Implied },
{ "ora", AccumConstant },
{ "asl", Implied },
{ "phd", Implied },
{ "tsb", Address },
{ "ora", Address },
{ "asl", Address },
{ "ora", Long },
//0x10 - 0x1f
{ "bpl", RelativeShort },
{ "ora", IDirectY },
{ "ora", IDirect },
{ "ora", IStackY },
{ "trb", Direct },
{ "ora", DirectX },
{ "asl", DirectX },
{ "ora", ILDirectY },
{ "clc", Implied },
{ "ora", AddressY },
{ "inc", Implied },
{ "tcs", Implied },
{ "trb", Address },
{ "ora", AddressX },
{ "asl", AddressX },
{ "ora", LongX },
//0x20 - 0x2f
{ "jsr", Address },
{ "and", IDirectX },
{ "jsl", Long },
{ "and", Stack },
{ "bit", Direct },
{ "and", Direct },
{ "rol", Direct },
{ "and", ILDirect },
{ "plp", Implied },
{ "and", AccumConstant },
{ "rol", Implied },
{ "pld", Implied },
{ "bit", Address },
{ "and", Address },
{ "rol", Address },
{ "and", Long },
//0x30 - 0x3f
{ "bmi", RelativeShort },
{ "and", IDirectY },
{ "and", IDirect },
{ "and", IStackY },
{ "bit", DirectX },
{ "and", DirectX },
{ "rol", DirectX },
{ "and", ILDirectY },
{ "sec", Implied },
{ "and", AddressY },
{ "dec", Implied },
{ "tsc", Implied },
{ "bit", AddressX },
{ "and", AddressX },
{ "rol", AddressX },
{ "and", LongX },
//0x40 - 0x4f
{ "rti", Implied },
{ "eor", IDirectX },
{ "wdm", Constant },
{ "eor", Stack },
{ "mvp", BlockMove },
{ "eor", Direct },
{ "lsr", Direct },
{ "eor", ILDirect },
{ "pha", Implied },
{ "eor", AccumConstant },
{ "lsr", Implied },
{ "phk", Implied },
{ "jmp", PAddress },
{ "eor", Address },
{ "lsr", Address },
{ "eor", Long },
//0x50 - 0x5f
{ "bvc", RelativeShort },
{ "eor", IDirectY },
{ "eor", IDirect },
{ "eor", IStackY },
{ "mvn", BlockMove },
{ "eor", DirectX },
{ "lsr", DirectX },
{ "eor", ILDirectY },
{ "cli", Implied },
{ "eor", AddressY },
{ "phy", Implied },
{ "tcd", Implied },
{ "jml", Long },
{ "eor", AddressX },
{ "lsr", AddressX },
{ "eor", LongX },
//0x60 - 0x6f
{ "rts", Implied },
{ "adc", IDirectX },
{ "per", Address },
{ "adc", Stack },
{ "stz", Direct },
{ "adc", Direct },
{ "ror", Direct },
{ "adc", ILDirect },
{ "pla", Implied },
{ "adc", AccumConstant },
{ "ror", Implied },
{ "rtl", Implied },
{ "jmp", PIAddress },
{ "adc", Address },
{ "ror", Address },
{ "adc", Long },
//0x70 - 0x7f
{ "bvs", RelativeShort },
{ "adc", IDirectY },
{ "adc", IDirect },
{ "adc", IStackY },
{ "stz", DirectX },
{ "adc", DirectX },
{ "ror", DirectX },
{ "adc", ILDirectY },
{ "sei", Implied },
{ "adc", AddressY },
{ "ply", Implied },
{ "tdc", Implied },
{ "jmp", IAddressX },
{ "adc", AddressX },
{ "ror", AddressX },
{ "adc", LongX },
//0x80 - 0x8f
{ "bra", RelativeShort },
{ "sta", IDirectX },
{ "brl", RelativeLong },
{ "sta", Stack },
{ "sty", Direct },
{ "sta", Direct },
{ "stx", Direct },
{ "sta", ILDirect },
{ "dey", Implied },
{ "bit", AccumConstant },
{ "txa", Implied },
{ "phb", Implied },
{ "sty", Address },
{ "sta", Address },
{ "stx", Address },
{ "sta", Long },
//0x90 - 0x9f
{ "bcc", RelativeShort },
{ "sta", IDirectY },
{ "sta", IDirect },
{ "sta", IStackY },
{ "sty", DirectX },
{ "sta", DirectX },
{ "stx", DirectY },
{ "sta", ILDirectY },
{ "tya", Implied },
{ "sta", AddressY },
{ "txs", Implied },
{ "txy", Implied },
{ "stz", Address },
{ "sta", AddressX },
{ "stz", AddressX },
{ "sta", LongX },
//0xa0 - 0xaf
{ "ldy", IndexConstant },
{ "lda", IDirectX },
{ "ldx", IndexConstant },
{ "lda", Stack },
{ "ldy", Direct },
{ "lda", Direct },
{ "ldx", Direct },
{ "lda", ILDirect },
{ "tay", Implied },
{ "lda", AccumConstant },
{ "tax", Implied },
{ "plb", Implied },
{ "ldy", Address },
{ "lda", Address },
{ "ldx", Address },
{ "lda", Long },
//0xb0 - 0xbf
{ "bcs", RelativeShort },
{ "lda", IDirectY },
{ "lda", IDirect },
{ "lda", IStackY },
{ "ldy", DirectX },
{ "lda", DirectX },
{ "ldx", DirectY },
{ "lda", ILDirectY },
{ "clv", Implied },
{ "lda", AddressY },
{ "tsx", Implied },
{ "tyx", Implied },
{ "ldy", AddressX },
{ "lda", AddressX },
{ "ldx", AddressY },
{ "lda", LongX },
//0xc0 - 0xcf
{ "cpy", IndexConstant },
{ "cmp", IDirectX },
{ "rep", Constant },
{ "cmp", Stack },
{ "cpy", Direct },
{ "cmp", Direct },
{ "dec", Direct },
{ "cmp", ILDirect },
{ "iny", Implied },
{ "cmp", AccumConstant },
{ "dex", Implied },
{ "wai", Implied },
{ "cpy", Address },
{ "cmp", Address },
{ "dec", Address },
{ "cmp", Long },
//0xd0 - 0xdf
{ "bne", RelativeShort },
{ "cmp", IDirectY },
{ "cmp", IDirect },
{ "cmp", IStackY },
{ "pei", IDirect },
{ "cmp", DirectX },
{ "dec", DirectX },
{ "cmp", ILDirectY },
{ "cld", Implied },
{ "cmp", AddressY },
{ "phx", Implied },
{ "stp", Implied },
{ "jmp", ILAddress },
{ "cmp", AddressX },
{ "dec", AddressX },
{ "cmp", LongX },
//0xe0 - 0xef
{ "cpx", IndexConstant },
{ "sbc", IDirectX },
{ "sep", Constant },
{ "sbc", Stack },
{ "cpx", Direct },
{ "sbc", Direct },
{ "inc", Direct },
{ "sbc", ILDirect },
{ "inx", Implied },
{ "sbc", AccumConstant },
{ "nop", Implied },
{ "xba", Implied },
{ "cpx", Address },
{ "sbc", Address },
{ "inc", Address },
{ "sbc", Long },
//0xf0 - 0xff
{ "beq", RelativeShort },
{ "sbc", IDirectY },
{ "sbc", IDirect },
{ "sbc", IStackY },
{ "pea", Address },
{ "sbc", DirectX },
{ "inc", DirectX },
{ "sbc", ILDirectY },
{ "sed", Implied },
{ "sbc", AddressY },
{ "plx", Implied },
{ "xce", Implied },
{ "jsr", IAddressX },
{ "sbc", AddressX },
{ "inc", AddressX },
{ "sbc", LongX },
};
inline unsigned SNESCPU::getOpcodeLength(bool accum, bool index, uint8_t opcode) {
switch(opcodeInfo[opcode].mode) { default:
case Implied: return 1;
case Constant: return 2;
case AccumConstant: return 3 - accum;
case IndexConstant: return 3 - index;
case Direct: return 2;
case DirectX: return 2;
case DirectY: return 2;
case IDirect: return 2;
case IDirectX: return 2;
case IDirectY: return 2;
case ILDirect: return 2;
case ILDirectY: return 2;
case Address: return 3;
case AddressX: return 3;
case AddressY: return 3;
case IAddressX: return 3;
case ILAddress: return 3;
case PAddress: return 3;
case PIAddress: return 3;
case Long: return 4;
case LongX: return 4;
case Stack: return 2;
case IStackY: return 2;
case BlockMove: return 3;
case RelativeShort: return 2;
case RelativeLong: return 3;
}
}
inline string SNESCPU::disassemble(unsigned pc, bool accum, bool index, uint8_t opcode, uint8_t pl, uint8_t ph, uint8_t pb) {
string name = opcodeInfo[opcode].name;
unsigned mode = opcodeInfo[opcode].mode;
if(mode == Implied) return name;
if(mode == Constant) return { name, " #$", hex<2>(pl) };
if(mode == AccumConstant) return { name, " #$", accum ? "" : hex<2>(ph), hex<2>(pl) };
if(mode == IndexConstant) return { name, " #$", index ? "" : hex<2>(ph), hex<2>(pl) };
if(mode == Direct) return { name, " $", hex<2>(pl) };
if(mode == DirectX) return { name, " $", hex<2>(pl), ",x" };
if(mode == DirectY) return { name, " $", hex<2>(pl), ",y" };
if(mode == IDirect) return { name, " ($", hex<2>(pl), ")" };
if(mode == IDirectX) return { name, " ($", hex<2>(pl), ",x)" };
if(mode == IDirectY) return { name, " ($", hex<2>(pl), "),y" };
if(mode == ILDirect) return { name, " [$", hex<2>(pl), "]" };
if(mode == ILDirectY) return { name, " [$", hex<2>(pl), "],y" };
if(mode == Address) return { name, " $", hex<2>(ph), hex<2>(pl) };
if(mode == AddressX) return { name, " $", hex<2>(ph), hex<2>(pl), ",x" };
if(mode == AddressY) return { name, " $", hex<2>(ph), hex<2>(pl), ",y" };
if(mode == IAddressX) return { name, " ($", hex<2>(ph), hex<2>(pl), ",x)" };
if(mode == ILAddress) return { name, " [$", hex<2>(ph), hex<2>(pl), "]" };
if(mode == PAddress) return { name, " $", hex<2>(ph), hex<2>(pl) };
if(mode == PIAddress) return { name, " ($", hex<2>(ph), hex<2>(pl), ")" };
if(mode == Long) return { name, " $", hex<2>(pb), hex<2>(ph), hex<2>(pl) };
if(mode == LongX) return { name, " $", hex<2>(pb), hex<2>(ph), hex<2>(pl), ",x" };
if(mode == Stack) return { name, " $", hex<2>(pl), ",s" };
if(mode == IStackY) return { name, " ($", hex<2>(pl), ",s),y" };
if(mode == BlockMove) return { name, " $", hex<2>(ph), ",$", hex<2>(pl) };
if(mode == RelativeShort) {
unsigned addr = (pc + 2) + (int8_t)(pl << 0);
return { name, " $", hex<4>(addr) };
}
if(mode == RelativeLong) {
unsigned addr = (pc + 3) + (int16_t)((ph << 8) + (pl << 0));
return { name, " $", hex<4>(addr) };
}
return "";
}
}
#endif

639
snesfilter/nall/snes/smp.hpp Executable file
View File

@ -0,0 +1,639 @@
#ifndef NALL_SNES_SMP_HPP
#define NALL_SNES_SMP_HPP
namespace nall {
struct SNESSMP {
enum : unsigned {
Implied, //
TVector, //0
Direct, //$00
DirectRelative, //$00,+/-$00
ADirect, //a,$00
AAbsolute, //a,$0000
AIX, //a,(x)
AIDirectX, //a,($00+x)
AConstant, //a,#$00
DirectDirect, //$00,$00
CAbsoluteBit, //c,$0000:0
Absolute, //$0000
P, //p
AbsoluteA, //$0000,a
Relative, //+/-$00
ADirectX, //a,$00+x
AAbsoluteX, //a,$0000+x
AAbsoluteY, //a,$0000+y
AIDirectY, //a,($00)+y
DirectConstant, //$00,#$00
IXIY, //(x),(y)
DirectX, //$00+x
A, //a
X, //x
XAbsolute, //x,$0000
IAbsoluteX, //($0000+x)
CNAbsoluteBit, //c,!$0000:0
XDirect, //x,$00
PVector, //$ff00
YaDirect, //ya,$00
XA, //x,a
YAbsolute, //y,$0000
Y, //y
AX, //a,x
YDirect, //y,$00
YConstant, //y,#$00
XSp, //x,sp
YaX, //ya,x
IXPA, //(x)+,a
SpX, //sp,x
AIXP, //a,(x)+
DirectA, //$00,a
IXA, //(x),a
IDirectXA, //($00+x),a
XConstant, //x,#$00
AbsoluteX, //$0000,x
AbsoluteBitC, //$0000:0,c
DirectY, //$00,y
AbsoluteY, //$0000,y
Ya, //ya
DirectXA, //$00+x,a
AbsoluteXA, //$0000+x,a
AbsoluteYA, //$0000+y,a
IDirectYA, //($00)+y,a
DirectYX, //$00+y,x
DirectYa, //$00,ya
DirectXY, //$00+x,y
AY, //a,y
DirectXRelative, //$00+x,+/-$00
XDirectY, //x,$00+y
YDirectX, //y,$00+x
YA, //y,a
YRelative, //y,+/-$00
};
struct OpcodeInfo {
char name[6];
unsigned mode;
};
static const OpcodeInfo opcodeInfo[256];
static unsigned getOpcodeLength(uint8_t opcode);
static string disassemble(uint16_t pc, uint8_t opcode, uint8_t pl, uint8_t ph);
static string disassemble(uint16_t pc, bool p, uint8_t opcode, uint8_t pl, uint8_t ph);
};
const SNESSMP::OpcodeInfo SNESSMP::opcodeInfo[256] = {
//0x00 - 0x0f
{ "nop ", Implied },
{ "tcall", TVector },
{ "set0 ", Direct },
{ "bbs0 ", DirectRelative },
{ "or ", ADirect },
{ "or ", AAbsolute },
{ "or ", AIX },
{ "or ", AIDirectX },
{ "or ", AConstant },
{ "or ", DirectDirect },
{ "or1 ", CAbsoluteBit },
{ "asl ", Direct },
{ "asl ", Absolute },
{ "push ", P },
{ "tset ", AbsoluteA },
{ "brk ", Implied },
//0x10 - 0x1f
{ "bpl ", Relative },
{ "tcall", TVector },
{ "clr0 ", Direct },
{ "bbc0 ", DirectRelative },
{ "or ", ADirectX },
{ "or ", AAbsoluteX },
{ "or ", AAbsoluteY },
{ "or ", AIDirectY },
{ "or ", DirectConstant },
{ "or ", IXIY },
{ "decw ", Direct },
{ "asl ", DirectX },
{ "asl ", A },
{ "dec ", X },
{ "cmp ", XAbsolute },
{ "jmp ", IAbsoluteX },
//0x20 - 0x2f
{ "clrp ", Implied },
{ "tcall", TVector },
{ "set1 ", Direct },
{ "bbs1 ", DirectRelative },
{ "and ", ADirect },
{ "and ", AAbsolute },
{ "and ", AIX },
{ "and ", AIDirectX },
{ "and ", AConstant },
{ "and ", DirectDirect },
{ "or1 ", CNAbsoluteBit },
{ "rol ", Direct },
{ "rol ", Absolute },
{ "push ", A },
{ "cbne ", DirectRelative },
{ "bra ", Relative },
//0x30 - 0x3f
{ "bmi ", Relative },
{ "tcall", TVector },
{ "clr1 ", Direct },
{ "bbc1 ", DirectRelative },
{ "and ", ADirectX },
{ "and ", AAbsoluteX },
{ "and ", AAbsoluteY },
{ "and ", AIDirectY },
{ "and ", DirectConstant },
{ "and ", IXIY },
{ "incw ", Direct },
{ "rol ", DirectX },
{ "rol ", A },
{ "inc ", X },
{ "cmp ", XDirect },
{ "call ", Absolute },
//0x40 - 0x4f
{ "setp ", Implied },
{ "tcall", TVector },
{ "set2 ", Direct },
{ "bbs2 ", DirectRelative },
{ "eor ", ADirect },
{ "eor ", AAbsolute },
{ "eor ", AIX },
{ "eor ", AIDirectX },
{ "eor ", AConstant },
{ "eor ", DirectDirect },
{ "and1 ", CAbsoluteBit },
{ "lsr ", Direct },
{ "lsr ", Absolute },
{ "push ", X },
{ "tclr ", AbsoluteA },
{ "pcall", PVector },
//0x50 - 0x5f
{ "bvc ", Relative },
{ "tcall", TVector },
{ "clr2 ", Direct },
{ "bbc2 ", DirectRelative },
{ "eor ", ADirectX },
{ "eor ", AAbsoluteX },
{ "eor ", AAbsoluteY },
{ "eor ", AIDirectY },
{ "eor ", DirectConstant },
{ "eor ", IXIY },
{ "cmpw ", YaDirect },
{ "lsr ", DirectX },
{ "lsr ", A },
{ "mov ", XA },
{ "cmp ", YAbsolute },
{ "jmp ", Absolute },
//0x60 - 0x6f
{ "clrc ", Implied },
{ "tcall", TVector },
{ "set3 ", Direct },
{ "bbs3 ", DirectRelative },
{ "cmp ", ADirect },
{ "cmp ", AAbsolute },
{ "cmp ", AIX },
{ "cmp ", AIDirectX },
{ "cmp ", AConstant },
{ "cmp ", DirectDirect },
{ "and1 ", CNAbsoluteBit },
{ "ror ", Direct },
{ "ror ", Absolute },
{ "push ", Y },
{ "dbnz ", DirectRelative },
{ "ret ", Implied },
//0x70 - 0x7f
{ "bvs ", Relative },
{ "tcall", TVector },
{ "clr3 ", Direct },
{ "bbc3 ", DirectRelative },
{ "cmp ", ADirectX },
{ "cmp ", AAbsoluteX },
{ "cmp ", AAbsoluteY },
{ "cmp ", AIDirectY },
{ "cmp ", DirectConstant },
{ "cmp ", IXIY },
{ "addw ", YaDirect },
{ "ror ", DirectX },
{ "ror ", A },
{ "mov ", AX },
{ "cmp ", YDirect },
{ "reti ", Implied },
//0x80 - 0x8f
{ "setc ", Implied },
{ "tcall", TVector },
{ "set4 ", Direct },
{ "bbs4 ", DirectRelative },
{ "adc ", ADirect },
{ "adc ", AAbsolute },
{ "adc ", AIX },
{ "adc ", AIDirectX },
{ "adc ", AConstant },
{ "adc ", DirectDirect },
{ "eor1 ", CAbsoluteBit },
{ "dec ", Direct },
{ "dec ", Absolute },
{ "mov ", YConstant },
{ "pop ", P },
{ "mov ", DirectConstant },
//0x90 - 0x9f
{ "bcc ", Relative },
{ "tcall", TVector },
{ "clr4 ", Direct },
{ "bbc4 ", DirectRelative },
{ "adc ", ADirectX },
{ "adc ", AAbsoluteX },
{ "adc ", AAbsoluteY },
{ "adc ", AIDirectY },
{ "adc ", DirectRelative },
{ "adc ", IXIY },
{ "subw ", YaDirect },
{ "dec ", DirectX },
{ "dec ", A },
{ "mov ", XSp },
{ "div ", YaX },
{ "xcn ", A },
//0xa0 - 0xaf
{ "ei ", Implied },
{ "tcall", TVector },
{ "set5 ", Direct },
{ "bbs5 ", DirectRelative },
{ "sbc ", ADirect },
{ "sbc ", AAbsolute },
{ "sbc ", AIX },
{ "sbc ", AIDirectX },
{ "sbc ", AConstant },
{ "sbc ", DirectDirect },
{ "mov1 ", CAbsoluteBit },
{ "inc ", Direct },
{ "inc ", Absolute },
{ "cmp ", YConstant },
{ "pop ", A },
{ "mov ", IXPA },
//0xb0 - 0xbf
{ "bcs ", Relative },
{ "tcall", TVector },
{ "clr5 ", Direct },
{ "bbc5 ", DirectRelative },
{ "sbc ", ADirectX },
{ "sbc ", AAbsoluteX },
{ "sbc ", AAbsoluteY },
{ "sbc ", AIDirectY },
{ "sbc ", DirectConstant },
{ "sbc ", IXIY },
{ "movw ", YaDirect },
{ "inc ", DirectX },
{ "inc ", A },
{ "mov ", SpX },
{ "das ", A },
{ "mov ", AIXP },
//0xc0 - 0xcf
{ "di ", Implied },
{ "tcall", TVector },
{ "set6 ", Direct },
{ "bbs6 ", DirectRelative },
{ "mov ", DirectA },
{ "mov ", AbsoluteA },
{ "mov ", IXA },
{ "mov ", IDirectXA },
{ "cmp ", XConstant },
{ "mov ", AbsoluteX },
{ "mov1 ", AbsoluteBitC },
{ "mov ", DirectY },
{ "mov ", AbsoluteY },
{ "mov ", XConstant },
{ "pop ", X },
{ "mul ", Ya },
//0xd0 - 0xdf
{ "bne ", Relative },
{ "tcall", TVector },
{ "clr6 ", Relative },
{ "bbc6 ", DirectRelative },
{ "mov ", DirectXA },
{ "mov ", AbsoluteXA },
{ "mov ", AbsoluteYA },
{ "mov ", IDirectYA },
{ "mov ", DirectX },
{ "mov ", DirectYX },
{ "movw ", DirectYa },
{ "mov ", DirectXY },
{ "dec ", Y },
{ "mov ", AY },
{ "cbne ", DirectXRelative },
{ "daa ", A },
//0xe0 - 0xef
{ "clrv ", Implied },
{ "tcall", TVector },
{ "set7 ", Direct },
{ "bbs7 ", DirectRelative },
{ "mov ", ADirect },
{ "mov ", AAbsolute },
{ "mov ", AIX },
{ "mov ", AIDirectX },
{ "mov ", AConstant },
{ "mov ", XAbsolute },
{ "not1 ", CAbsoluteBit },
{ "mov ", YDirect },
{ "mov ", YAbsolute },
{ "notc ", Implied },
{ "pop ", Y },
{ "sleep", Implied },
//0xf0 - 0xff
{ "beq ", Relative },
{ "tcall", TVector },
{ "clr7 ", Direct },
{ "bbc7 ", DirectRelative },
{ "mov ", ADirectX },
{ "mov ", AAbsoluteX },
{ "mov ", AAbsoluteY },
{ "mov ", AIDirectY },
{ "mov ", XDirect },
{ "mov ", XDirectY },
{ "mov ", DirectDirect },
{ "mov ", YDirectX },
{ "inc ", Y },
{ "mov ", YA },
{ "dbz ", YRelative },
{ "stop ", Implied },
};
inline unsigned SNESSMP::getOpcodeLength(uint8_t opcode) {
switch(opcodeInfo[opcode].mode) { default:
case Implied: return 1; //
case TVector: return 1; //0
case Direct: return 2; //$00
case DirectRelative: return 3; //$00,+/-$00
case ADirect: return 2; //a,$00
case AAbsolute: return 3; //a,$0000
case AIX: return 1; //a,(x)
case AIDirectX: return 2; //a,($00+x)
case AConstant: return 2; //a,#$00
case DirectDirect: return 3; //$00,$00
case CAbsoluteBit: return 3; //c,$0000:0
case Absolute: return 3; //$0000
case P: return 1; //p
case AbsoluteA: return 3; //$0000,a
case Relative: return 2; //+/-$00
case ADirectX: return 2; //a,$00+x
case AAbsoluteX: return 3; //a,$0000+x
case AAbsoluteY: return 3; //a,$0000+y
case AIDirectY: return 2; //a,($00)+y
case DirectConstant: return 3; //$00,#$00
case IXIY: return 1; //(x),(y)
case DirectX: return 2; //$00+x
case A: return 1; //a
case X: return 1; //x
case XAbsolute: return 3; //x,$0000
case IAbsoluteX: return 3; //($0000+x)
case CNAbsoluteBit: return 3; //c,!$0000:0
case XDirect: return 2; //x,$00
case PVector: return 2; //$ff00
case YaDirect: return 2; //ya,$00
case XA: return 1; //x,a
case YAbsolute: return 3; //y,$0000
case Y: return 1; //y
case AX: return 1; //a,x
case YDirect: return 2; //y,$00
case YConstant: return 2; //y,#$00
case XSp: return 1; //x,sp
case YaX: return 1; //ya,x
case IXPA: return 1; //(x)+,a
case SpX: return 1; //sp,x
case AIXP: return 1; //a,(x)+
case DirectA: return 2; //$00,a
case IXA: return 1; //(x),a
case IDirectXA: return 2; //($00+x),a
case XConstant: return 2; //x,#$00
case AbsoluteX: return 3; //$0000,x
case AbsoluteBitC: return 3; //$0000:0,c
case DirectY: return 2; //$00,y
case AbsoluteY: return 3; //$0000,y
case Ya: return 1; //ya
case DirectXA: return 2; //$00+x,a
case AbsoluteXA: return 3; //$0000+x,a
case AbsoluteYA: return 3; //$0000+y,a
case IDirectYA: return 2; //($00)+y,a
case DirectYX: return 2; //$00+y,x
case DirectYa: return 2; //$00,ya
case DirectXY: return 2; //$00+x,y
case AY: return 1; //a,y
case DirectXRelative: return 3; //$00+x,+/-$00
case XDirectY: return 2; //x,$00+y
case YDirectX: return 2; //y,$00+x
case YA: return 1; //y,a
case YRelative: return 2; //y,+/-$00
}
}
inline string SNESSMP::disassemble(uint16_t pc, uint8_t opcode, uint8_t pl, uint8_t ph) {
string name = opcodeInfo[opcode].name;
unsigned mode = opcodeInfo[opcode].mode;
unsigned pa = (ph << 8) + pl;
if(mode == Implied) return name;
if(mode == TVector) return { name, " ", opcode >> 4 };
if(mode == Direct) return { name, " $", hex<2>(pl) };
if(mode == DirectRelative) return { name, " $", hex<2>(pl), ",$", hex<4>(pc + 3 + (int8_t)ph) };
if(mode == ADirect) return { name, " a,$", hex<2>(pl) };
if(mode == AAbsolute) return { name, " a,$", hex<4>(pa) };
if(mode == AIX) return { name, "a,(x)" };
if(mode == AIDirectX) return { name, " a,($", hex<2>(pl), "+x)" };
if(mode == AConstant) return { name, " a,#$", hex<2>(pl) };
if(mode == DirectDirect) return { name, " $", hex<2>(ph), ",$", hex<2>(pl) };
if(mode == CAbsoluteBit) return { name, " c,$", hex<4>(pa & 0x1fff), ":", pa >> 13 };
if(mode == Absolute) return { name, " $", hex<4>(pa) };
if(mode == P) return { name, " p" };
if(mode == AbsoluteA) return { name, " $", hex<4>(pa), ",a" };
if(mode == Relative) return { name, " $", hex<4>(pc + 2 + (int8_t)pl) };
if(mode == ADirectX) return { name, " a,$", hex<2>(pl), "+x" };
if(mode == AAbsoluteX) return { name, " a,$", hex<4>(pa), "+x" };
if(mode == AAbsoluteY) return { name, " a,$", hex<4>(pa), "+y" };
if(mode == AIDirectY) return { name, " a,($", hex<2>(pl), ")+y" };
if(mode == DirectConstant) return { name, " $", hex<2>(ph), ",#$", hex<2>(pl) };
if(mode == IXIY) return { name, " (x),(y)" };
if(mode == DirectX) return { name, " $", hex<2>(pl), "+x" };
if(mode == A) return { name, " a" };
if(mode == X) return { name, " x" };
if(mode == XAbsolute) return { name, " x,$", hex<4>(pa) };
if(mode == IAbsoluteX) return { name, " ($", hex<4>(pa), "+x)" };
if(mode == CNAbsoluteBit) return { name, " c,!$", hex<4>(pa & 0x1fff), ":", pa >> 13 };
if(mode == XDirect) return { name, " x,$", hex<2>(pl) };
if(mode == PVector) return { name, " $ff", hex<2>(pl) };
if(mode == YaDirect) return { name, " ya,$", hex<2>(pl) };
if(mode == XA) return { name, " x,a" };
if(mode == YAbsolute) return { name, " y,$", hex<4>(pa) };
if(mode == Y) return { name, " y" };
if(mode == AX) return { name, " a,x" };
if(mode == YDirect) return { name, " y,$", hex<2>(pl) };
if(mode == YConstant) return { name, " y,#$", hex<2>(pl) };
if(mode == XSp) return { name, " x,sp" };
if(mode == YaX) return { name, " ya,x" };
if(mode == IXPA) return { name, " (x)+,a" };
if(mode == SpX) return { name, " sp,x" };
if(mode == AIXP) return { name, " a,(x)+" };
if(mode == DirectA) return { name, " $", hex<2>(pl), ",a" };
if(mode == IXA) return { name, " (x),a" };
if(mode == IDirectXA) return { name, " ($", hex<2>(pl), "+x),a" };
if(mode == XConstant) return { name, " x,#$", hex<2>(pl) };
if(mode == AbsoluteX) return { name, " $", hex<4>(pa), ",x" };
if(mode == AbsoluteBitC) return { name, " $", hex<4>(pa & 0x1fff), ":", pa >> 13, ",c" };
if(mode == DirectY) return { name, " $", hex<2>(pl), ",y" };
if(mode == AbsoluteY) return { name, " $", hex<4>(pa), ",y" };
if(mode == Ya) return { name, " ya" };
if(mode == DirectXA) return { name, " $", hex<2>(pl), "+x,a" };
if(mode == AbsoluteXA) return { name, " $", hex<4>(pa), "+x,a" };
if(mode == AbsoluteYA) return { name, " $", hex<4>(pa), "+y,a" };
if(mode == IDirectYA) return { name, " ($", hex<2>(pl), ")+y,a" };
if(mode == DirectYX) return { name, " $", hex<2>(pl), "+y,x" };
if(mode == DirectYa) return { name, " $", hex<2>(pl), ",ya" };
if(mode == DirectXY) return { name, " $", hex<2>(pl), "+x,y" };
if(mode == AY) return { name, " a,y" };
if(mode == DirectXRelative) return { name, " $", hex<2>(pl), ",$", hex<4>(pc + 3 + (int8_t)ph) };
if(mode == XDirectY) return { name, " x,$", hex<2>(pl), "+y" };
if(mode == YDirectX) return { name, " y,$", hex<2>(pl), "+x" };
if(mode == YA) return { name, " y,a" };
if(mode == YRelative) return { name, " y,$", hex<4>(pc + 2 + (int8_t)pl) };
return "";
}
inline string SNESSMP::disassemble(uint16_t pc, bool p, uint8_t opcode, uint8_t pl, uint8_t ph) {
string name = opcodeInfo[opcode].name;
unsigned mode = opcodeInfo[opcode].mode;
unsigned pdl = (p << 8) + pl;
unsigned pdh = (p << 8) + ph;
unsigned pa = (ph << 8) + pl;
if(mode == Implied) return name;
if(mode == TVector) return { name, " ", opcode >> 4 };
if(mode == Direct) return { name, " $", hex<3>(pdl) };
if(mode == DirectRelative) return { name, " $", hex<3>(pdl), ",$", hex<4>(pc + 3 + (int8_t)ph) };
if(mode == ADirect) return { name, " a,$", hex<3>(pdl) };
if(mode == AAbsolute) return { name, " a,$", hex<4>(pa) };
if(mode == AIX) return { name, "a,(x)" };
if(mode == AIDirectX) return { name, " a,($", hex<3>(pdl), "+x)" };
if(mode == AConstant) return { name, " a,#$", hex<2>(pl) };
if(mode == DirectDirect) return { name, " $", hex<3>(pdh), ",$", hex<3>(pdl) };
if(mode == CAbsoluteBit) return { name, " c,$", hex<4>(pa & 0x1fff), ":", pa >> 13 };
if(mode == Absolute) return { name, " $", hex<4>(pa) };
if(mode == P) return { name, " p" };
if(mode == AbsoluteA) return { name, " $", hex<4>(pa), ",a" };
if(mode == Relative) return { name, " $", hex<4>(pc + 2 + (int8_t)pl) };
if(mode == ADirectX) return { name, " a,$", hex<3>(pdl), "+x" };
if(mode == AAbsoluteX) return { name, " a,$", hex<4>(pa), "+x" };
if(mode == AAbsoluteY) return { name, " a,$", hex<4>(pa), "+y" };
if(mode == AIDirectY) return { name, " a,($", hex<3>(pdl), ")+y" };
if(mode == DirectConstant) return { name, " $", hex<3>(pdh), ",#$", hex<2>(pl) };
if(mode == IXIY) return { name, " (x),(y)" };
if(mode == DirectX) return { name, " $", hex<3>(pdl), "+x" };
if(mode == A) return { name, " a" };
if(mode == X) return { name, " x" };
if(mode == XAbsolute) return { name, " x,$", hex<4>(pa) };
if(mode == IAbsoluteX) return { name, " ($", hex<4>(pa), "+x)" };
if(mode == CNAbsoluteBit) return { name, " c,!$", hex<4>(pa & 0x1fff), ":", pa >> 13 };
if(mode == XDirect) return { name, " x,$", hex<3>(pdl) };
if(mode == PVector) return { name, " $ff", hex<2>(pl) };
if(mode == YaDirect) return { name, " ya,$", hex<3>(pdl) };
if(mode == XA) return { name, " x,a" };
if(mode == YAbsolute) return { name, " y,$", hex<4>(pa) };
if(mode == Y) return { name, " y" };
if(mode == AX) return { name, " a,x" };
if(mode == YDirect) return { name, " y,$", hex<3>(pdl) };
if(mode == YConstant) return { name, " y,#$", hex<2>(pl) };
if(mode == XSp) return { name, " x,sp" };
if(mode == YaX) return { name, " ya,x" };
if(mode == IXPA) return { name, " (x)+,a" };
if(mode == SpX) return { name, " sp,x" };
if(mode == AIXP) return { name, " a,(x)+" };
if(mode == DirectA) return { name, " $", hex<3>(pdl), ",a" };
if(mode == IXA) return { name, " (x),a" };
if(mode == IDirectXA) return { name, " ($", hex<3>(pdl), "+x),a" };
if(mode == XConstant) return { name, " x,#$", hex<2>(pl) };
if(mode == AbsoluteX) return { name, " $", hex<4>(pa), ",x" };
if(mode == AbsoluteBitC) return { name, " $", hex<4>(pa & 0x1fff), ":", pa >> 13, ",c" };
if(mode == DirectY) return { name, " $", hex<3>(pdl), ",y" };
if(mode == AbsoluteY) return { name, " $", hex<4>(pa), ",y" };
if(mode == Ya) return { name, " ya" };
if(mode == DirectXA) return { name, " $", hex<3>(pdl), "+x,a" };
if(mode == AbsoluteXA) return { name, " $", hex<4>(pa), "+x,a" };
if(mode == AbsoluteYA) return { name, " $", hex<4>(pa), "+y,a" };
if(mode == IDirectYA) return { name, " ($", hex<3>(pdl), ")+y,a" };
if(mode == DirectYX) return { name, " $", hex<3>(pdl), "+y,x" };
if(mode == DirectYa) return { name, " $", hex<3>(pdl), ",ya" };
if(mode == DirectXY) return { name, " $", hex<3>(pdl), "+x,y" };
if(mode == AY) return { name, " a,y" };
if(mode == DirectXRelative) return { name, " $", hex<3>(pdl), ",$", hex<4>(pc + 3 + (int8_t)ph) };
if(mode == XDirectY) return { name, " x,$", hex<3>(pdl), "+y" };
if(mode == YDirectX) return { name, " y,$", hex<3>(pdl), "+x" };
if(mode == YA) return { name, " y,a" };
if(mode == YRelative) return { name, " y,$", hex<4>(pc + 2 + (int8_t)pl) };
return "";
}
}
#endif

View File

@ -12,20 +12,18 @@
namespace nall {
class string;
template<typename T> inline string to_string(T);
template<typename T> inline const char* to_string(T);
class string {
public:
inline void reserve(unsigned);
inline string& assign(const char*);
inline string& append(const char*);
inline string& append(bool);
inline string& append(signed int value);
inline string& append(unsigned int value);
inline string& append(double value);
template<typename... Args> inline string& assign(Args&&... args);
template<typename... Args> inline string& append(Args&&... args);
inline string& assign_(const char*);
inline string& append_(const char*);
inline bool readfile(const char*);
inline bool readfile(const string&);
inline string& replace (const char*, const char*);
inline string& qreplace(const char*, const char*);
@ -113,11 +111,11 @@ namespace nall {
inline char* strlower(char *str);
inline char* strupper(char *str);
inline char* strtr(char *dest, const char *before, const char *after);
inline uintmax_t strhex (const char *str);
inline intmax_t strsigned (const char *str);
inline uintmax_t strunsigned(const char *str);
inline uintmax_t strbin (const char *str);
inline double strdouble (const char *str);
inline uintmax_t hex (const char *str);
inline intmax_t integer(const char *str);
inline uintmax_t decimal(const char *str);
inline uintmax_t binary (const char *str);
inline double fp (const char *str);
//math.hpp
inline bool strint (const char *str, int &result);
@ -145,12 +143,17 @@ namespace nall {
inline unsigned strlcpy(string &dest, const char *src, unsigned length);
inline unsigned strlcat(string &dest, const char *src, unsigned length);
inline string substr(const char *src, unsigned start = 0, unsigned length = 0);
template<unsigned length = 0, char padding = '0'> inline string strhex(uintmax_t value);
template<unsigned length = 0, char padding = '0'> inline string strsigned(intmax_t value);
template<unsigned length = 0, char padding = '0'> inline string strunsigned(uintmax_t value);
template<unsigned length = 0, char padding = '0'> inline string strbin(uintmax_t value);
inline unsigned strdouble(char *str, double value);
inline string strdouble(double value);
inline string integer(intmax_t value);
template<unsigned length = 0> inline string linteger(intmax_t value);
template<unsigned length = 0> inline string rinteger(intmax_t value);
inline string decimal(uintmax_t value);
template<unsigned length = 0> inline string ldecimal(uintmax_t value);
template<unsigned length = 0> inline string rdecimal(uintmax_t value);
template<unsigned length = 0> inline string hex(uintmax_t value);
template<unsigned length = 0> inline string binary(uintmax_t value);
inline unsigned fp(char *str, double value);
inline string fp(double value);
//variadic.hpp
template<typename... Args> inline void print(Args&&... args);

View File

@ -4,14 +4,14 @@
namespace nall {
//this is needed, as C++0x does not support explicit template specialization inside classes
template<> inline string to_string<bool> (bool v) { return v ? "true" : "false"; }
template<> inline string to_string<signed int> (signed int v) { return strsigned(v); }
template<> inline string to_string<unsigned int> (unsigned int v) { return strunsigned(v); }
template<> inline string to_string<double> (double v) { return strdouble(v); }
template<> inline string to_string<char*> (char *v) { return v; }
template<> inline string to_string<const char*> (const char *v) { return v; }
template<> inline string to_string<string> (string v) { return v; }
template<> inline string to_string<const string&>(const string &v) { return v; }
template<> inline const char* to_string<bool> (bool v) { return v ? "true" : "false"; }
template<> inline const char* to_string<signed int> (signed int v) { static char temp[256]; snprintf(temp, 255, "%+d", v); return temp; }
template<> inline const char* to_string<unsigned int> (unsigned int v) { static char temp[256]; snprintf(temp, 255, "%u", v); return temp; }
template<> inline const char* to_string<double> (double v) { static char temp[256]; snprintf(temp, 255, "%f", v); return temp; }
template<> inline const char* to_string<char*> (char *v) { return v; }
template<> inline const char* to_string<const char*> (const char *v) { return v; }
template<> inline const char* to_string<string> (string v) { return v; }
template<> inline const char* to_string<const string&>(const string &v) { return v; }
template<typename T> string& string::operator= (T value) { return assign(to_string<T>(value)); }
template<typename T> string& string::operator<<(T value) { return append(to_string<T>(value)); }
@ -22,8 +22,8 @@ template<typename T> lstring& lstring::operator<<(T value) {
}
#if defined(QSTRING_H)
template<> inline string to_string<QString>(QString v) { return v.toUtf8().constData(); }
template<> inline string to_string<const QString&>(const QString &v) { return v.toUtf8().constData(); }
template<> inline const char* to_string<QString>(QString v) { return v.toUtf8().constData(); }
template<> inline const char* to_string<const QString&>(const QString &v) { return v.toUtf8().constData(); }
string::operator QString() const { return QString::fromUtf8(*this); }
#endif

View File

@ -40,7 +40,7 @@ char* strtr(char *dest, const char *before, const char *after) {
return dest;
}
uintmax_t strhex(const char *str) {
uintmax_t hex(const char *str) {
if(!str) return 0;
uintmax_t result = 0;
@ -60,13 +60,16 @@ uintmax_t strhex(const char *str) {
return result;
}
intmax_t strsigned(const char *str) {
intmax_t integer(const char *str) {
if(!str) return 0;
intmax_t result = 0;
bool negate = false;
//check for negation
if(*str == '-') {
//check for sign
if(*str == '+') {
negate = false;
str++;
} else if(*str == '-') {
negate = true;
str++;
}
@ -81,7 +84,7 @@ intmax_t strsigned(const char *str) {
return !negate ? result : -result;
}
uintmax_t strunsigned(const char *str) {
uintmax_t decimal(const char *str) {
if(!str) return 0;
uintmax_t result = 0;
@ -95,7 +98,7 @@ uintmax_t strunsigned(const char *str) {
return result;
}
uintmax_t strbin(const char *str) {
uintmax_t binary(const char *str) {
if(!str) return 0;
uintmax_t result = 0;
@ -113,39 +116,8 @@ uintmax_t strbin(const char *str) {
return result;
}
double strdouble(const char *str) {
if(!str) return 0.0;
bool negate = false;
//check for negation
if(*str == '-') {
negate = true;
str++;
}
intmax_t result_integral = 0;
while(*str) {
uint8_t x = *str++;
if(x >= '0' && x <= '9') x -= '0';
else if(x == '.' || x == ',') break; //break loop and read fractional part
else return (double)result_integral; //invalid value, assume no fractional part
result_integral = result_integral * 10 + x;
}
intmax_t result_fractional = 0;
while(*str) {
uint8_t x = *str++;
if(x >= '0' && x <= '9') x -= '0';
else break; //stop at first invalid character
result_fractional = result_fractional * 10 + x;
}
//calculate fractional portion
double result = (double)result_fractional;
while((uintmax_t)result > 0) result /= 10.0;
result += (double)result_integral;
return !negate ? result : -result;
double fp(const char *str) {
return atof(str);
}
}

View File

@ -3,6 +3,15 @@
namespace nall {
static void istring(string &output) {
}
template<typename T, typename... Args>
static void istring(string &output, const T &value, Args&&... args) {
output.append_(to_string(value));
istring(output, std::forward<Args>(args)...);
}
void string::reserve(unsigned size_) {
if(size_ > size) {
size = size_;
@ -11,25 +20,31 @@ void string::reserve(unsigned size_) {
}
}
string& string::assign(const char *s) {
template<typename... Args> string& string::assign(Args&&... args) {
*data = 0;
istring(*this, std::forward<Args>(args)...);
return *this;
}
template<typename... Args> string& string::append(Args&&... args) {
istring(*this, std::forward<Args>(args)...);
return *this;
}
string& string::assign_(const char *s) {
unsigned length = strlen(s);
reserve(length);
strcpy(data, s);
return *this;
}
string& string::append(const char *s) {
string& string::append_(const char *s) {
unsigned length = strlen(data) + strlen(s);
reserve(length);
strcat(data, s);
return *this;
}
string& string::append(bool value) { append(value ? "true" : "false"); return *this; }
string& string::append(signed int value) { append(strsigned(value)); return *this; }
string& string::append(unsigned int value) { append(strunsigned(value)); return *this; }
string& string::append(double value) { append(strdouble(value)); return *this; }
string::operator const char*() const {
return data;
}
@ -64,15 +79,6 @@ string& string::operator=(string &&source) {
return *this;
}
static void istring(string &output) {
}
template<typename T, typename... Args>
static void istring(string &output, const T &value, Args&&... args) {
output.append(value);
istring(output, std::forward<Args>(args)...);
}
template<typename... Args> string::string(Args&&... args) {
size = 64;
data = (char*)malloc(size + 1);
@ -95,7 +101,7 @@ string::~string() {
if(data) free(data);
}
bool string::readfile(const char *filename) {
bool string::readfile(const string &filename) {
assign("");
#if !defined(_WIN32)

View File

@ -3,15 +3,15 @@
namespace nall {
string realpath(const char *name) {
string currentpath() {
char path[PATH_MAX];
if(::realpath(name, path)) {
if(::getcwd(path)) {
string result(path);
result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/");
return result;
}
return "";
return "./";
}
string userpath() {
@ -22,18 +22,17 @@ string userpath() {
if(result.endswith("/") == false) result.append("/");
return result;
}
return "";
return currentpath();
}
string currentpath() {
string realpath(const char *name) {
char path[PATH_MAX];
if(::getcwd(path)) {
if(::realpath(name, path)) {
string result(path);
result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/");
return result;
}
return "";
return userpath();
}
}

View File

@ -27,104 +27,202 @@ string substr(const char *src, unsigned start, unsigned length) {
/* arithmetic <> string */
template<unsigned length, char padding> string strhex(uintmax_t value) {
string output;
unsigned offset = 0;
//render string backwards, as we do not know its length yet
do {
unsigned n = value & 15;
output[offset++] = n < 10 ? '0' + n : 'a' + n - 10;
value >>= 4;
} while(value);
while(offset < length) output[offset++] = padding;
output[offset--] = 0;
//reverse the string in-place
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
char temp = output[i];
output[i] = output[offset - i];
output[offset - i] = temp;
}
return output;
}
template<unsigned length, char padding> string strsigned(intmax_t value) {
string output;
unsigned offset = 0;
string integer(intmax_t value) {
bool negative = value < 0;
if(negative) value = abs(value);
do {
unsigned n = value % 10;
output[offset++] = '0' + n;
value /= 10;
} while(value);
while(offset < length) output[offset++] = padding;
if(negative) output[offset++] = '-';
output[offset--] = 0;
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
char temp = output[i];
output[i] = output[offset - i];
output[offset - i] = temp;
}
return output;
}
template<unsigned length, char padding> string strunsigned(uintmax_t value) {
string output;
unsigned offset = 0;
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
output[offset++] = '0' + n;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size++] = negative ? '-' : '+';
buffer[size] = 0;
while(offset < length) output[offset++] = padding;
output[offset--] = 0;
char result[size + 1];
memset(result, '0', size);
result[size] = 0;
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
char temp = output[i];
output[i] = output[offset - i];
output[offset - i] = temp;
for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) {
result[x] = buffer[y];
}
return output;
return (const char*)result;
}
template<unsigned length, char padding> string strbin(uintmax_t value) {
string output;
unsigned offset = 0;
template<unsigned length_> string linteger(intmax_t value) {
bool negative = value < 0;
if(negative) value = abs(value);
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size++] = negative ? '-' : '+';
buffer[size] = 0;
unsigned length = (length_ == 0 ? size : length_);
char result[length + 1];
memset(result, ' ', length);
result[length] = 0;
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
result[x] = buffer[y];
}
return (const char*)result;
}
template<unsigned length_> string rinteger(intmax_t value) {
bool negative = value < 0;
if(negative) value = abs(value);
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size++] = negative ? '-' : '+';
buffer[size] = 0;
unsigned length = (length_ == 0 ? size : length_);
char result[length + 1];
memset(result, ' ', length);
result[length] = 0;
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
result[x] = buffer[y];
}
return (const char*)result;
}
string decimal(uintmax_t value) {
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size] = 0;
char result[size + 1];
memset(result, '0', size);
result[size] = 0;
for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) {
result[x] = buffer[y];
}
return (const char*)result;
}
template<unsigned length_> string ldecimal(uintmax_t value) {
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size] = 0;
unsigned length = (length_ == 0 ? size : length_);
char result[length + 1];
memset(result, ' ', length);
result[length] = 0;
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
result[x] = buffer[y];
}
return (const char*)result;
}
template<unsigned length_> string rdecimal(uintmax_t value) {
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size] = 0;
unsigned length = (length_ == 0 ? size : length_);
char result[length + 1];
memset(result, ' ', length);
result[length] = 0;
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
result[x] = buffer[y];
}
return (const char*)result;
}
template<unsigned length_> string hex(uintmax_t value) {
char buffer[64];
unsigned size = 0;
do {
unsigned n = value & 15;
buffer[size++] = n < 10 ? '0' + n : 'a' + n - 10;
value >>= 4;
} while(value);
unsigned length = (length_ == 0 ? size : length_);
char result[length + 1];
memset(result, '0', length);
result[length] = 0;
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
result[x] = buffer[y];
}
return (const char*)result;
}
template<unsigned length_> string binary(uintmax_t value) {
char buffer[256];
unsigned size = 0;
do {
unsigned n = value & 1;
output[offset++] = '0' + n;
buffer[size++] = '0' + n;
value >>= 1;
} while(value);
while(offset < length) output[offset++] = padding;
output[offset--] = 0;
unsigned length = (length_ == 0 ? size : length_);
char result[length + 1];
memset(result, '0', length);
result[length] = 0;
for(unsigned i = 0; i < (offset + 1) >> 1; i++) {
char temp = output[i];
output[i] = output[offset - i];
output[offset - i] = temp;
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
result[x] = buffer[y];
}
return output;
return (const char*)result;
}
//using sprintf is certainly not the most ideal method to convert
//a double to a string ... but attempting to parse a double by
//hand, digit-by-digit, results in subtle rounding errors.
unsigned strdouble(char *str, double value) {
unsigned fp(char *str, double value) {
char buffer[256];
sprintf(buffer, "%f", value);
@ -145,10 +243,10 @@ unsigned strdouble(char *str, double value) {
return length + 1;
}
string strdouble(double value) {
string fp(double value) {
string temp;
temp.reserve(strdouble(0, value));
strdouble(temp(), value);
temp.reserve(fp(0, value));
fp(temp(), value);
return temp;
}

View File

@ -8,84 +8,110 @@
namespace nall {
template<unsigned bits> class uint_t {
private:
enum { bytes = (bits + 7) >> 3 }; //minimum number of bytes needed to store value
typedef typename static_if<
sizeof(int) >= bytes,
unsigned int,
typename static_if<
sizeof(long) >= bytes,
unsigned long,
typename static_if<
sizeof(long long) >= bytes,
unsigned long long,
void
>::type
>::type
>::type T;
static_assert(!std::is_same<T, void>::value, "");
T data;
unsigned data;
public:
inline operator T() const { return data; }
inline T operator ++(int) { T r = data; data = uclip<bits>(data + 1); return r; }
inline T operator --(int) { T r = data; data = uclip<bits>(data - 1); return r; }
inline T operator ++() { return data = uclip<bits>(data + 1); }
inline T operator --() { return data = uclip<bits>(data - 1); }
inline T operator =(const T i) { return data = uclip<bits>(i); }
inline T operator |=(const T i) { return data = uclip<bits>(data | i); }
inline T operator ^=(const T i) { return data = uclip<bits>(data ^ i); }
inline T operator &=(const T i) { return data = uclip<bits>(data & i); }
inline T operator<<=(const T i) { return data = uclip<bits>(data << i); }
inline T operator>>=(const T i) { return data = uclip<bits>(data >> i); }
inline T operator +=(const T i) { return data = uclip<bits>(data + i); }
inline T operator -=(const T i) { return data = uclip<bits>(data - i); }
inline T operator *=(const T i) { return data = uclip<bits>(data * i); }
inline T operator /=(const T i) { return data = uclip<bits>(data / i); }
inline T operator %=(const T i) { return data = uclip<bits>(data % i); }
inline operator unsigned() const { return data; }
inline unsigned operator ++(int) { unsigned r = data; data = uclip<bits>(data + 1); return r; }
inline unsigned operator --(int) { unsigned r = data; data = uclip<bits>(data - 1); return r; }
inline unsigned operator ++() { return data = uclip<bits>(data + 1); }
inline unsigned operator --() { return data = uclip<bits>(data - 1); }
inline unsigned operator =(const unsigned i) { return data = uclip<bits>(i); }
inline unsigned operator |=(const unsigned i) { return data = uclip<bits>(data | i); }
inline unsigned operator ^=(const unsigned i) { return data = uclip<bits>(data ^ i); }
inline unsigned operator &=(const unsigned i) { return data = uclip<bits>(data & i); }
inline unsigned operator<<=(const unsigned i) { return data = uclip<bits>(data << i); }
inline unsigned operator>>=(const unsigned i) { return data = uclip<bits>(data >> i); }
inline unsigned operator +=(const unsigned i) { return data = uclip<bits>(data + i); }
inline unsigned operator -=(const unsigned i) { return data = uclip<bits>(data - i); }
inline unsigned operator *=(const unsigned i) { return data = uclip<bits>(data * i); }
inline unsigned operator /=(const unsigned i) { return data = uclip<bits>(data / i); }
inline unsigned operator %=(const unsigned i) { return data = uclip<bits>(data % i); }
inline uint_t() : data(0) {}
inline uint_t(const T i) : data(uclip<bits>(i)) {}
inline uint_t(const unsigned i) : data(uclip<bits>(i)) {}
};
template<unsigned bits> class int_t {
private:
enum { bytes = (bits + 7) >> 3 }; //minimum number of bytes needed to store value
typedef typename static_if<
sizeof(int) >= bytes,
signed int,
typename static_if<
sizeof(long) >= bytes,
signed long,
typename static_if<
sizeof(long long) >= bytes,
signed long long,
void
>::type
>::type
>::type T;
static_assert(!std::is_same<T, void>::value, "");
T data;
signed data;
public:
inline operator T() const { return data; }
inline T operator ++(int) { T r = data; data = sclip<bits>(data + 1); return r; }
inline T operator --(int) { T r = data; data = sclip<bits>(data - 1); return r; }
inline T operator ++() { return data = sclip<bits>(data + 1); }
inline T operator --() { return data = sclip<bits>(data - 1); }
inline T operator =(const T i) { return data = sclip<bits>(i); }
inline T operator |=(const T i) { return data = sclip<bits>(data | i); }
inline T operator ^=(const T i) { return data = sclip<bits>(data ^ i); }
inline T operator &=(const T i) { return data = sclip<bits>(data & i); }
inline T operator<<=(const T i) { return data = sclip<bits>(data << i); }
inline T operator>>=(const T i) { return data = sclip<bits>(data >> i); }
inline T operator +=(const T i) { return data = sclip<bits>(data + i); }
inline T operator -=(const T i) { return data = sclip<bits>(data - i); }
inline T operator *=(const T i) { return data = sclip<bits>(data * i); }
inline T operator /=(const T i) { return data = sclip<bits>(data / i); }
inline T operator %=(const T i) { return data = sclip<bits>(data % i); }
inline operator signed() const { return data; }
inline signed operator ++(int) { signed r = data; data = sclip<bits>(data + 1); return r; }
inline signed operator --(int) { signed r = data; data = sclip<bits>(data - 1); return r; }
inline signed operator ++() { return data = sclip<bits>(data + 1); }
inline signed operator --() { return data = sclip<bits>(data - 1); }
inline signed operator =(const signed i) { return data = sclip<bits>(i); }
inline signed operator |=(const signed i) { return data = sclip<bits>(data | i); }
inline signed operator ^=(const signed i) { return data = sclip<bits>(data ^ i); }
inline signed operator &=(const signed i) { return data = sclip<bits>(data & i); }
inline signed operator<<=(const signed i) { return data = sclip<bits>(data << i); }
inline signed operator>>=(const signed i) { return data = sclip<bits>(data >> i); }
inline signed operator +=(const signed i) { return data = sclip<bits>(data + i); }
inline signed operator -=(const signed i) { return data = sclip<bits>(data - i); }
inline signed operator *=(const signed i) { return data = sclip<bits>(data * i); }
inline signed operator /=(const signed i) { return data = sclip<bits>(data / i); }
inline signed operator %=(const signed i) { return data = sclip<bits>(data % i); }
inline int_t() : data(0) {}
inline int_t(const T i) : data(sclip<bits>(i)) {}
inline int_t(const signed i) : data(sclip<bits>(i)) {}
};
class varuint_t {
private:
unsigned data;
unsigned mask;
public:
inline operator unsigned() const { return data; }
inline unsigned operator ++(int) { unsigned r = data; data = (data + 1) & mask; return r; }
inline unsigned operator --(int) { unsigned r = data; data = (data - 1) & mask; return r; }
inline unsigned operator ++() { return data = (data + 1) & mask; }
inline unsigned operator --() { return data = (data - 1) & mask; }
inline unsigned operator =(const unsigned i) { return data = (i) & mask; }
inline unsigned operator |=(const unsigned i) { return data = (data | i) & mask; }
inline unsigned operator ^=(const unsigned i) { return data = (data ^ i) & mask; }
inline unsigned operator &=(const unsigned i) { return data = (data & i) & mask; }
inline unsigned operator<<=(const unsigned i) { return data = (data << i) & mask; }
inline unsigned operator>>=(const unsigned i) { return data = (data >> i) & mask; }
inline unsigned operator +=(const unsigned i) { return data = (data + i) & mask; }
inline unsigned operator -=(const unsigned i) { return data = (data - i) & mask; }
inline unsigned operator *=(const unsigned i) { return data = (data * i) & mask; }
inline unsigned operator /=(const unsigned i) { return data = (data / i) & mask; }
inline unsigned operator %=(const unsigned i) { return data = (data % i) & mask; }
inline void bits(unsigned bits) { mask = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1); data &= mask; }
inline varuint_t() : data(0), mask(~0U) {}
inline varuint_t(const unsigned i) : data(i), mask(~0U) {}
};
class varuintmax_t {
private:
uintmax_t data;
uintmax_t mask;
public:
inline operator uintmax_t() const { return data; }
inline uintmax_t operator ++(int) { uintmax_t r = data; data = (data + 1) & mask; return r; }
inline uintmax_t operator --(int) { uintmax_t r = data; data = (data - 1) & mask; return r; }
inline uintmax_t operator ++() { return data = (data + 1) & mask; }
inline uintmax_t operator --() { return data = (data - 1) & mask; }
inline uintmax_t operator =(const uintmax_t i) { return data = (i) & mask; }
inline uintmax_t operator |=(const uintmax_t i) { return data = (data | i) & mask; }
inline uintmax_t operator ^=(const uintmax_t i) { return data = (data ^ i) & mask; }
inline uintmax_t operator &=(const uintmax_t i) { return data = (data & i) & mask; }
inline uintmax_t operator<<=(const uintmax_t i) { return data = (data << i) & mask; }
inline uintmax_t operator>>=(const uintmax_t i) { return data = (data >> i) & mask; }
inline uintmax_t operator +=(const uintmax_t i) { return data = (data + i) & mask; }
inline uintmax_t operator -=(const uintmax_t i) { return data = (data - i) & mask; }
inline uintmax_t operator *=(const uintmax_t i) { return data = (data * i) & mask; }
inline uintmax_t operator /=(const uintmax_t i) { return data = (data / i) & mask; }
inline uintmax_t operator %=(const uintmax_t i) { return data = (data % i) & mask; }
inline void bits(unsigned bits) { mask = (1ULL << (bits - 1)) + ((1ULL << (bits - 1)) - 1); data &= mask; }
inline varuintmax_t() : data(0), mask(~0ULL) {}
inline varuintmax_t(const uintmax_t i) : data(i), mask(~0ULL) {}
};
}

View File

@ -46,7 +46,7 @@ namespace nall {
void reserve(unsigned newsize) {
newsize = bit::round(newsize); //round to nearest power of two (for amortized growth)
T *poolcopy = (T*)malloc(newsize * sizeof(T));
T *poolcopy = (T*)calloc(newsize, sizeof(T));
for(unsigned i = 0; i < min(objectsize, newsize); i++) new(poolcopy + i) T(pool[i]);
for(unsigned i = 0; i < objectsize; i++) pool[i].~T();
free(pool);

View File

@ -1,4 +1,4 @@
g++-4.5 -std=gnu++0x -I. -O3 -fomit-frame-pointer -c phoenix/phoenix.cpp `pkg-config --cflags gtk+-2.0` -DPHOENIX_GTK
g++-4.5 -std=gnu++0x -I. -O3 -fomit-frame-pointer -c snespurify.cpp -DPHOENIX_GTK
g++-4.5 -s -o snespurify snespurify.o phoenix.o `pkg-config --libs gtk+-2.0` -lX11
g++-4.5 -s -o snespurify-gtk snespurify.o phoenix.o `pkg-config --libs gtk+-2.0` -lX11
rm *.o

View File

@ -1,5 +1,5 @@
moc -i -o phoenix/qt/qt.moc phoenix/qt/qt.moc.hpp
g++-4.5 -std=gnu++0x -I. -O3 -fomit-frame-pointer -c phoenix/phoenix.cpp `pkg-config --cflags QtCore QtGui` -DPHOENIX_QT
g++-4.5 -std=gnu++0x -I. -O3 -fomit-frame-pointer -c snespurify.cpp -DPHOENIX_QT
g++-4.5 -s -o snespurify snespurify.o phoenix.o `pkg-config --libs QtCore QtGui`
g++-4.5 -s -o snespurify-qt snespurify.o phoenix.o `pkg-config --libs QtCore QtGui`
rm *.o

View File

@ -2,6 +2,5 @@ windres phoenix/windows/phoenix.rc phoenix-resource.o
g++ -std=gnu++0x -I. -O3 -fomit-frame-pointer -c phoenix/phoenix.cpp -DPHOENIX_WINDOWS
g++ -std=gnu++0x -I. -O3 -fomit-frame-pointer -c snespurify.cpp -DPHOENIX_WINDOWS
g++ -mwindows -s -o snespurify snespurify.o phoenix.o phoenix-resource.o -lkernel32 -luser32 -lgdi32 -ladvapi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32
upx --best snespurify.exe
@pause
@del *.o

View File

@ -41,14 +41,14 @@ struct directory {
if(handle != INVALID_HANDLE_VALUE) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = utf8_t(data.cFileName);
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(string(name, "/"));
}
}
while(FindNextFile(handle, &data) != false) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = utf8_t(data.cFileName);
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(string(name, "/"));
}
}
@ -70,12 +70,12 @@ struct directory {
handle = FindFirstFile(utf16_t(path), &data);
if(handle != INVALID_HANDLE_VALUE) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
string name = utf8_t(data.cFileName);
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
while(FindNextFile(handle, &data) != false) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
string name = utf8_t(data.cFileName);
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
}

View File

@ -21,7 +21,7 @@ namespace nall {
public:
enum class mode : unsigned { read, write, readwrite, writeread };
bool opened() const { return p_opened(); }
bool open() const { return p_open(); }
bool open(const char *filename, mode mode_) { return p_open(filename, mode_); }
void close() { return p_close(); }
unsigned size() const { return p_size; }
@ -42,7 +42,7 @@ namespace nall {
HANDLE p_filehandle, p_maphandle;
bool p_opened() const {
bool p_open() const {
return p_handle;
}
@ -128,7 +128,7 @@ namespace nall {
int p_fd;
bool p_opened() const {
bool p_open() const {
return p_handle;
}

View File

@ -8,12 +8,20 @@ namespace nall {
return n = (n >> 1) ^ (((n & 1) - 1) & 0xedb88320);
}
struct random_cyclic {
unsigned seed;
inline unsigned operator()() {
return seed = (seed >> 1) ^ (((seed & 1) - 1) & 0xedb88320);
struct random_lfsr {
inline void seed(unsigned seed__) {
seed_ = seed__;
}
random_cyclic() : seed(0) {}
inline unsigned operator()() {
return seed_ = (seed_ >> 1) ^ (((seed_ & 1) - 1) & 0xedb88320);
}
random_lfsr() : seed_(0) {
}
private:
unsigned seed_;
};
}

View File

@ -362,7 +362,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
xml << " <map mode='linear' address='20-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='a0-bf:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram>\n";
xml << " <ram size='20000'>\n";
xml << " <map mode='linear' address='60-63:8000-ffff'/>\n";
xml << " <map mode='linear' address='e0-e3:8000-ffff'/>\n";
xml << " </ram>\n";
@ -372,7 +372,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
xml << " <map mode='linear' address='40-5f:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-df:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram>\n";
xml << " <ram size='20000'>\n";
xml << " <map mode='linear' address='70-73:8000-ffff'/>\n";
xml << " <map mode='linear' address='f0-f3:8000-ffff'/>\n";
xml << " </ram>\n";

View File

@ -12,18 +12,16 @@
namespace nall {
class string;
template<typename T> inline string to_string(T);
template<typename T> inline const char* to_string(T);
class string {
public:
inline void reserve(unsigned);
inline string& assign(const char*);
inline string& append(const char*);
inline string& append(bool);
inline string& append(signed int value);
inline string& append(unsigned int value);
inline string& append(double value);
template<typename... Args> inline string& assign(Args&&... args);
template<typename... Args> inline string& append(Args&&... args);
inline string& assign_(const char*);
inline string& append_(const char*);
inline bool readfile(const string&);

View File

@ -4,14 +4,14 @@
namespace nall {
//this is needed, as C++0x does not support explicit template specialization inside classes
template<> inline string to_string<bool> (bool v) { return v ? "true" : "false"; }
template<> inline string to_string<signed int> (signed int v) { return integer(v); }
template<> inline string to_string<unsigned int> (unsigned int v) { return decimal(v); }
template<> inline string to_string<double> (double v) { return fp(v); }
template<> inline string to_string<char*> (char *v) { return v; }
template<> inline string to_string<const char*> (const char *v) { return v; }
template<> inline string to_string<string> (string v) { return v; }
template<> inline string to_string<const string&>(const string &v) { return v; }
template<> inline const char* to_string<bool> (bool v) { return v ? "true" : "false"; }
template<> inline const char* to_string<signed int> (signed int v) { static char temp[256]; snprintf(temp, 255, "%+d", v); return temp; }
template<> inline const char* to_string<unsigned int> (unsigned int v) { static char temp[256]; snprintf(temp, 255, "%u", v); return temp; }
template<> inline const char* to_string<double> (double v) { static char temp[256]; snprintf(temp, 255, "%f", v); return temp; }
template<> inline const char* to_string<char*> (char *v) { return v; }
template<> inline const char* to_string<const char*> (const char *v) { return v; }
template<> inline const char* to_string<string> (string v) { return v; }
template<> inline const char* to_string<const string&>(const string &v) { return v; }
template<typename T> string& string::operator= (T value) { return assign(to_string<T>(value)); }
template<typename T> string& string::operator<<(T value) { return append(to_string<T>(value)); }
@ -22,8 +22,8 @@ template<typename T> lstring& lstring::operator<<(T value) {
}
#if defined(QSTRING_H)
template<> inline string to_string<QString>(QString v) { return v.toUtf8().constData(); }
template<> inline string to_string<const QString&>(const QString &v) { return v.toUtf8().constData(); }
template<> inline const char* to_string<QString>(QString v) { return v.toUtf8().constData(); }
template<> inline const char* to_string<const QString&>(const QString &v) { return v.toUtf8().constData(); }
string::operator QString() const { return QString::fromUtf8(*this); }
#endif

View File

@ -117,38 +117,7 @@ uintmax_t binary(const char *str) {
}
double fp(const char *str) {
if(!str) return 0.0;
bool negate = false;
//check for negation
if(*str == '-') {
negate = true;
str++;
}
intmax_t result_integral = 0;
while(*str) {
uint8_t x = *str++;
if(x >= '0' && x <= '9') x -= '0';
else if(x == '.' || x == ',') break; //break loop and read fractional part
else return (double)result_integral; //invalid value, assume no fractional part
result_integral = result_integral * 10 + x;
}
intmax_t result_fractional = 0;
while(*str) {
uint8_t x = *str++;
if(x >= '0' && x <= '9') x -= '0';
else break; //stop at first invalid character
result_fractional = result_fractional * 10 + x;
}
//calculate fractional portion
double result = (double)result_fractional;
while((uintmax_t)result > 0) result /= 10.0;
result += (double)result_integral;
return !negate ? result : -result;
return atof(str);
}
}

View File

@ -3,6 +3,15 @@
namespace nall {
static void istring(string &output) {
}
template<typename T, typename... Args>
static void istring(string &output, const T &value, Args&&... args) {
output.append_(to_string(value));
istring(output, std::forward<Args>(args)...);
}
void string::reserve(unsigned size_) {
if(size_ > size) {
size = size_;
@ -11,25 +20,31 @@ void string::reserve(unsigned size_) {
}
}
string& string::assign(const char *s) {
template<typename... Args> string& string::assign(Args&&... args) {
*data = 0;
istring(*this, std::forward<Args>(args)...);
return *this;
}
template<typename... Args> string& string::append(Args&&... args) {
istring(*this, std::forward<Args>(args)...);
return *this;
}
string& string::assign_(const char *s) {
unsigned length = strlen(s);
reserve(length);
strcpy(data, s);
return *this;
}
string& string::append(const char *s) {
string& string::append_(const char *s) {
unsigned length = strlen(data) + strlen(s);
reserve(length);
strcat(data, s);
return *this;
}
string& string::append(bool value) { append(value ? "true" : "false"); return *this; }
string& string::append(signed int value) { append(integer(value)); return *this; }
string& string::append(unsigned int value) { append(decimal(value)); return *this; }
string& string::append(double value) { append(fp(value)); return *this; }
string::operator const char*() const {
return data;
}
@ -64,15 +79,6 @@ string& string::operator=(string &&source) {
return *this;
}
static void istring(string &output) {
}
template<typename T, typename... Args>
static void istring(string &output, const T &value, Args&&... args) {
output.append(value);
istring(output, std::forward<Args>(args)...);
}
template<typename... Args> string::string(Args&&... args) {
size = 64;
data = (char*)malloc(size + 1);

View File

@ -3,15 +3,15 @@
namespace nall {
string realpath(const char *name) {
string currentpath() {
char path[PATH_MAX];
if(::realpath(name, path)) {
if(::getcwd(path)) {
string result(path);
result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/");
return result;
}
return "";
return "./";
}
string userpath() {
@ -22,18 +22,17 @@ string userpath() {
if(result.endswith("/") == false) result.append("/");
return result;
}
return "";
return currentpath();
}
string currentpath() {
string realpath(const char *name) {
char path[PATH_MAX];
if(::getcwd(path)) {
if(::realpath(name, path)) {
string result(path);
result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/");
return result;
}
return "";
return userpath();
}
}

View File

@ -26,6 +26,7 @@ void OS::processEvents() { return pOS::processEvents(); }
void OS::quit() { return pOS::quit(); }
void OS::initialize() { static bool initialized = false; if(initialized == false) { initialized = true; return pOS::initialize(); } }
Geometry Font::geometry(const string &text) { return p.geometry(text); }
void Font::setBold(bool bold) { state.bold = bold; return p.setBold(bold); }
void Font::setFamily(const string &family) { state.family = family; return p.setFamily(family); }
void Font::setItalic(bool italic) { state.italic = italic; return p.setItalic(italic); }
@ -80,13 +81,15 @@ void CheckItem::setChecked(bool checked) { state.checked = checked; return p.set
void CheckItem::setText(const string &text) { state.text = text; return p.setText(text); }
CheckItem::CheckItem() : state(*new State), base_from_member<pCheckItem&>(*new pCheckItem(*this)), Action(base_from_member<pCheckItem&>::value), p(base_from_member<pCheckItem&>::value) { p.constructor(); }
void RadioItem::group_(const reference_array<RadioItem&> &list) { foreach(item, list) item.p.setGroup(item.state.group = list); if(list.size()) list[0].setChecked(); }
void RadioItem::group(const reference_array<RadioItem&> &list) { foreach(item, list) item.p.setGroup(item.state.group = list); if(list.size()) list[0].setChecked(); }
bool RadioItem::checked() { return p.checked(); }
void RadioItem::setChecked() { foreach(item, state.group) item.state.checked = false; state.checked = true; return p.setChecked(); }
void RadioItem::setText(const string &text) { state.text = text; return p.setText(text); }
RadioItem::RadioItem() : state(*new State), base_from_member<pRadioItem&>(*new pRadioItem(*this)), Action(base_from_member<pRadioItem&>::value), p(base_from_member<pRadioItem&>::value) { p.constructor(); }
bool Widget::enabled() { return state.enabled; }
Font& Widget::font() { return p.font(); }
Geometry Widget::minimumGeometry() { return p.minimumGeometry(); }
void Widget::setEnabled(bool enabled) { state.enabled = enabled; return p.setEnabled(enabled); }
void Widget::setFocused() { return p.setFocused(); }
void Widget::setFont(Font &font) { state.font = &font; return p.setFont(font); }
@ -99,6 +102,10 @@ Widget::Widget(pWidget &p) : state(*new State), p(p) { p.constructor(); }
void Button::setText(const string &text) { state.text = text; return p.setText(text); }
Button::Button() : state(*new State), base_from_member<pButton&>(*new pButton(*this)), Widget(base_from_member<pButton&>::value), p(base_from_member<pButton&>::value) { p.constructor(); }
uint32_t* Canvas::buffer() { return p.buffer(); }
void Canvas::update() { return p.update(); }
Canvas::Canvas() : base_from_member<pCanvas&>(*new pCanvas(*this)), Widget(base_from_member<pCanvas&>::value), p(base_from_member<pCanvas&>::value) { p.constructor(); }
bool CheckBox::checked() { return p.checked(); }
void CheckBox::setChecked(bool checked) { state.checked = checked; return p.setChecked(checked); }
void CheckBox::setText(const string &text) { state.text = text; return p.setText(text); }
@ -148,7 +155,7 @@ ListView::ListView() : state(*new State), base_from_member<pListView&>(*new pLis
void ProgressBar::setPosition(unsigned position) { state.position = position; return p.setPosition(position); }
ProgressBar::ProgressBar() : state(*new State), base_from_member<pProgressBar&>(*new pProgressBar(*this)), Widget(base_from_member<pProgressBar&>::value), p(base_from_member<pProgressBar&>::value) { p.constructor(); }
void RadioBox::group_(const reference_array<RadioBox&> &list) { foreach(item, list) item.p.setGroup(item.state.group = list); if(list.size()) list[0].setChecked(); }
void RadioBox::group(const reference_array<RadioBox&> &list) { foreach(item, list) item.p.setGroup(item.state.group = list); if(list.size()) list[0].setChecked(); }
bool RadioBox::checked() { return p.checked(); }
void RadioBox::setChecked() { foreach(item, state.group) item.state.checked = false; state.checked = true; return p.setChecked(); }
void RadioBox::setText(const string &text) { state.text = text; return p.setText(text); }

View File

@ -16,6 +16,7 @@ struct pRadioItem;
struct pLayout;
struct pWidget;
struct pButton;
struct pCanvas;
struct pCheckBox;
struct pComboBox;
struct pHexEdit;
@ -29,6 +30,11 @@ struct pTextEdit;
struct pVerticalSlider;
struct pViewport;
enum : unsigned {
MaximumSize = ~0u,
MinimumSize = 0u,
};
struct Geometry {
signed x, y;
unsigned width, height;
@ -63,6 +69,7 @@ private:
};
struct Font : Object {
Geometry geometry(const nall::string &text);
void setBold(bool bold = true);
void setFamily(const nall::string &family);
void setItalic(bool italic = true);
@ -179,7 +186,8 @@ struct CheckItem : private nall::base_from_member<pCheckItem&>, Action {
};
struct RadioItem : private nall::base_from_member<pRadioItem&>, Action {
template<typename... Args> static void group(Args&... args) { group_({ args... }); }
template<typename... Args> static void group(Args&... args) { group({ args... }); }
static void group(const nall::reference_array<RadioItem&> &list);
nall::function<void ()> onTick;
@ -191,19 +199,18 @@ struct RadioItem : private nall::base_from_member<pRadioItem&>, Action {
struct State;
State &state;
pRadioItem &p;
private:
static void group_(const nall::reference_array<RadioItem&> &list);
};
struct Layout : Object {
virtual void setGeometry(Geometry &geometry) = 0;
virtual void setGeometry(const Geometry &geometry) = 0;
virtual void setParent(Window &parent) = 0;
virtual void setVisible(bool visible = true) = 0;
};
struct Widget : Object {
bool enabled();
Font& font();
Geometry minimumGeometry();
void setEnabled(bool enabled = true);
void setFocused();
void setFont(Font &font);
@ -229,6 +236,14 @@ struct Button : private nall::base_from_member<pButton&>, Widget {
pButton &p;
};
struct Canvas : private nall::base_from_member<pCanvas&>, Widget {
uint32_t* buffer();
void update();
Canvas();
pCanvas &p;
};
struct CheckBox : private nall::base_from_member<pCheckBox&>, Widget {
nall::function<void ()> onTick;
@ -348,7 +363,8 @@ struct ProgressBar : private nall::base_from_member<pProgressBar&>, Widget {
};
struct RadioBox : private nall::base_from_member<pRadioBox&>, Widget {
template<typename... Args> static void group(Args&... args) { group_({ args... }); }
template<typename... Args> static void group(Args&... args) { group({ args... }); }
static void group(const nall::reference_array<RadioBox&> &list);
nall::function<void ()> onTick;
@ -360,9 +376,6 @@ struct RadioBox : private nall::base_from_member<pRadioBox&>, Widget {
struct State;
State &state;
pRadioBox &p;
private:
static void group_(const nall::reference_array<RadioBox&> &list);
};
struct TextEdit : private nall::base_from_member<pTextEdit&>, Widget {

View File

@ -9,7 +9,7 @@ void FixedLayout::append(Widget &widget, const Geometry &geometry) {
children.append({ &widget, geometry });
}
void FixedLayout::setGeometry(Geometry &geometry) {
void FixedLayout::setGeometry(const Geometry &geometry) {
}
void FixedLayout::setVisible(bool visible) {

View File

@ -1,6 +1,6 @@
struct FixedLayout : Layout {
void append(Widget &widget, const Geometry &geometry);
void setGeometry(Geometry &geometry);
void setGeometry(const Geometry &geometry);
void setParent(Window &parent);
void setVisible(bool visible);
FixedLayout();

View File

@ -1,77 +1,130 @@
void HorizontalLayout::setParent(Window &parent) {
foreach(child, children) {
if(child.layout) child.layout->setParent(parent);
if(child.widget) parent.append(*child.widget);
}
}
void HorizontalLayout::append(VerticalLayout &layout, unsigned width, unsigned height, unsigned spacing) {
layout.width = width;
layout.height = height;
children.append({ &layout, 0, width, height, spacing });
void HorizontalLayout::append(VerticalLayout &layout, unsigned spacing) {
children.append({ &layout, 0, MinimumSize, MinimumSize, spacing });
}
void HorizontalLayout::append(Widget &widget, unsigned width, unsigned height, unsigned spacing) {
children.append({ 0, &widget, width, height, spacing });
}
void HorizontalLayout::setGeometry(Geometry &geometry) {
geometry.x += margin;
geometry.y += margin;
geometry.width -= margin * 2;
geometry.height -= margin * 2;
Geometry HorizontalLayout::minimumGeometry() {
unsigned width = 0, height = 0;
unsigned geometryWidth = width ? width : geometry.width;
unsigned geometryHeight = height ? height : geometry.height;
Geometry baseGeometry = geometry;
linear_vector<HorizontalLayout::Children> children = this->children;
unsigned minimumWidth = 0;
foreach(child, children) minimumWidth += child.width + child.spacing;
unsigned autosizeWidgets = 0;
foreach(child, children) {
if(child.width == 0) autosizeWidgets++;
}
foreach(child, children) {
if(child.width == 0) child.width = (geometryWidth - minimumWidth) / autosizeWidgets;
if(child.height == 0) child.height = geometryHeight;
width += child.spacing;
if(child.width == MinimumSize || child.width == MaximumSize) {
if(child.layout) width += child.layout->minimumGeometry().width;
if(child.widget) width += child.widget->minimumGeometry().width;
continue;
}
width += child.width;
}
unsigned maxHeight = 0;
foreach(child, children) {
maxHeight = max(maxHeight, child.height);
if(child.height == MinimumSize || child.height == MaximumSize) {
if(child.layout) height = max(height, child.layout->minimumGeometry().height);
if(child.widget) height = max(height, child.widget->minimumGeometry().height);
continue;
}
height = max(height, child.height);
}
return { 0, 0, margin * 2 + width, margin * 2 + height };
}
Geometry HorizontalLayout::minimumLayoutGeometry() {
unsigned width = 0, height = 0;
bool maximumWidth = false;
bool maximumHeight = false;
foreach(child, children) {
if(child.width == MaximumSize) {
maximumWidth = true;
break;
}
if(child.width == MinimumSize) {
if(child.layout) width += child.layout->minimumGeometry().width;
if(child.widget) width += child.widget->minimumGeometry().width;
continue;
}
width += child.width;
}
foreach(child, children) {
if(child.height == MaximumSize) {
maximumHeight = true;
break;
}
if(child.height == MinimumSize) {
if(child.layout) height = max(height, child.layout->minimumGeometry().height);
if(child.widget) height = max(height, child.widget->minimumGeometry().height);
continue;
}
height = max(height, child.height);
}
return { 0, 0, maximumWidth ? MaximumSize : margin * 2 + width, maximumHeight ? MaximumSize : margin * 2 + height };
}
void HorizontalLayout::setGeometry(const Geometry &containerGeometry) {
auto children = this->children;
foreach(child, children) {
if(child.layout) {
child.layout->setGeometry(geometry);
geometry.x += child.spacing;
geometry.width -= child.spacing;
geometry.y = baseGeometry.y;
geometry.height = baseGeometry.height;
child.width = child.layout->minimumLayoutGeometry().width;
child.height = child.layout->minimumLayoutGeometry().height;
}
if(child.widget) {
child.widget->setGeometry({ geometry.x, geometry.y, child.width, child.height });
geometry.x += child.width + child.spacing;
geometry.width -= child.width + child.spacing;
if(child.width == MinimumSize) child.width = child.widget->minimumGeometry().width;
if(child.height == MinimumSize) child.height = child.widget->minimumGeometry().height;
}
}
geometry.y += maxHeight;
geometry.height -= maxHeight;
Geometry geometry = containerGeometry;
geometry.x += margin;
geometry.y += margin;
geometry.width -= margin * 2;
geometry.height -= margin * 2;
unsigned minimumWidth = 0, maximumWidthCounter = 0;
foreach(child, children) {
if(child.width == MaximumSize) maximumWidthCounter++;
if(child.width != MaximumSize) minimumWidth += child.width;
minimumWidth += child.spacing;
}
foreach(child, children) {
if(child.width == MaximumSize) child.width = (geometry.width - minimumWidth) / maximumWidthCounter;
if(child.height == MaximumSize) child.height = geometry.height;
}
unsigned maximumHeight = 0;
foreach(child, children) maximumHeight = max(maximumHeight, child.height);
foreach(child, children) {
unsigned pivot = (maximumHeight - child.height) / 2;
Geometry childGeometry = { geometry.x, geometry.y + pivot, child.width, child.height };
if(child.layout) child.layout->setGeometry(childGeometry);
if(child.widget) child.widget->setGeometry(childGeometry);
geometry.x += child.width + child.spacing;
geometry.width -= child.width + child.spacing;
}
}
void HorizontalLayout::setMargin(unsigned margin_) {
margin = margin_;
void HorizontalLayout::setMargin(unsigned margin) {
this->margin = margin;
}
unsigned HorizontalLayout::minimumWidth() {
unsigned width = margin * 2;
foreach(child, children) width += child.width + child.spacing;
return width;
void HorizontalLayout::setParent(Window &parent) {
foreach(child, children) {
if(child.layout) child.layout->setParent(parent);
if(child.widget) parent.append(*child.widget);
}
}
void HorizontalLayout::setVisible(bool visible) {
@ -83,6 +136,4 @@ void HorizontalLayout::setVisible(bool visible) {
HorizontalLayout::HorizontalLayout() {
margin = 0;
width = 0;
height = 0;
}

View File

@ -1,10 +1,11 @@
struct VerticalLayout;
struct HorizontalLayout : public Layout {
void append(VerticalLayout &layout, unsigned width, unsigned height, unsigned spacing = 0);
void append(VerticalLayout &layout, unsigned spacing = 0);
void append(Widget &widget, unsigned width, unsigned height, unsigned spacing = 0);
unsigned minimumWidth();
void setGeometry(Geometry &geometry);
Geometry minimumLayoutGeometry();
Geometry minimumGeometry();
void setGeometry(const Geometry &geometry);
void setMargin(unsigned margin);
void setParent(Window &parent);
void setVisible(bool visible);
@ -12,8 +13,6 @@ struct HorizontalLayout : public Layout {
//private:
unsigned margin;
unsigned width;
unsigned height;
struct Children {
VerticalLayout *layout;
Widget *widget;

View File

@ -1,77 +1,130 @@
void VerticalLayout::setParent(Window &parent) {
foreach(child, children) {
if(child.layout) child.layout->setParent(parent);
if(child.widget) parent.append(*child.widget);
}
}
void VerticalLayout::append(HorizontalLayout &layout, unsigned width, unsigned height, unsigned spacing) {
layout.width = width;
layout.height = height;
children.append({ &layout, 0, width, height, spacing });
void VerticalLayout::append(HorizontalLayout &layout, unsigned spacing) {
children.append({ &layout, 0, MinimumSize, MinimumSize, spacing });
}
void VerticalLayout::append(Widget &widget, unsigned width, unsigned height, unsigned spacing) {
children.append({ 0, &widget, width, height, spacing });
}
void VerticalLayout::setGeometry(Geometry &geometry) {
geometry.x += margin;
geometry.y += margin;
geometry.width -= margin * 2;
geometry.height -= margin * 2;
Geometry VerticalLayout::minimumGeometry() {
unsigned width = 0, height = 0;
unsigned geometryWidth = width ? width : geometry.width;
unsigned geometryHeight = height ? height : geometry.height;
Geometry baseGeometry = geometry;
linear_vector<VerticalLayout::Children> children = this->children;
unsigned minimumHeight = 0;
foreach(child, children) minimumHeight += child.height + child.spacing;
unsigned autosizeWidgets = 0;
foreach(child, children) {
if(child.height == 0) autosizeWidgets++;
}
foreach(child, children) {
if(child.width == 0) child.width = geometryWidth;
if(child.height == 0) child.height = (geometryHeight - minimumHeight) / autosizeWidgets;
if(child.width == MinimumSize || child.width == MaximumSize) {
if(child.layout) width = max(width, child.layout->minimumGeometry().width);
if(child.widget) width = max(width, child.widget->minimumGeometry().width);
continue;
}
width = max(width, child.width);
}
unsigned maxWidth = 0;
foreach(child, children) {
maxWidth = max(maxWidth, child.width);
height += child.spacing;
if(child.height == MinimumSize || child.height == MaximumSize) {
if(child.layout) height += child.layout->minimumGeometry().height;
if(child.widget) height += child.widget->minimumGeometry().height;
continue;
}
height += child.height;
}
return { 0, 0, margin * 2 + width, margin * 2 + height };
}
Geometry VerticalLayout::minimumLayoutGeometry() {
unsigned width = 0, height = 0;
bool maximumWidth = false;
bool maximumHeight = false;
foreach(child, children) {
if(child.width == MaximumSize) {
maximumWidth = true;
break;
}
if(child.width == MinimumSize) {
if(child.layout) width = max(width, child.layout->minimumGeometry().width);
if(child.widget) width = max(width, child.widget->minimumGeometry().width);
continue;
}
width = max(width, child.width);
}
foreach(child, children) {
if(child.height == MaximumSize) {
maximumHeight = true;
break;
}
if(child.height == MinimumSize) {
if(child.layout) height += child.layout->minimumGeometry().height;
if(child.widget) height += child.widget->minimumGeometry().height;
continue;
}
height += child.height;
}
return { 0, 0, maximumWidth ? MaximumSize : margin * 2 + width, maximumHeight ? MaximumSize : margin * 2 + height };
}
void VerticalLayout::setGeometry(const Geometry &containerGeometry) {
auto children = this->children;
foreach(child, children) {
if(child.layout) {
child.layout->setGeometry(geometry);
geometry.x = baseGeometry.x;
geometry.width = baseGeometry.width;
geometry.y += child.spacing;
geometry.height -= child.spacing;
child.width = child.layout->minimumLayoutGeometry().width;
child.height = child.layout->minimumLayoutGeometry().height;
}
if(child.widget) {
child.widget->setGeometry({ geometry.x, geometry.y, child.width, child.height });
geometry.y += child.height + child.spacing;
geometry.height -= child.height + child.spacing;
if(child.width == MinimumSize) child.width = child.widget->minimumGeometry().width;
if(child.height == MinimumSize) child.height = child.widget->minimumGeometry().height;
}
}
geometry.x += maxWidth;
geometry.width -= maxWidth;
Geometry geometry = containerGeometry;
geometry.x += margin;
geometry.y += margin;
geometry.width -= margin * 2;
geometry.height -= margin * 2;
unsigned minimumHeight = 0, maximumHeightCounter = 0;
foreach(child, children) {
if(child.height == MaximumSize) maximumHeightCounter++;
if(child.height != MaximumSize) minimumHeight += child.height;
minimumHeight += child.spacing;
}
foreach(child, children) {
if(child.width == MaximumSize) child.width = geometry.width;
if(child.height == MaximumSize) child.height = (geometry.height - minimumHeight) / maximumHeightCounter;
}
unsigned maximumWidth = 0;
foreach(child, children) maximumWidth = max(maximumWidth, child.width);
foreach(child, children) {
unsigned pivot = 0; //(maximumWidth - child.width) / 2;
Geometry childGeometry = { geometry.x + pivot, geometry.y, child.width, child.height };
if(child.layout) child.layout->setGeometry(childGeometry);
if(child.widget) child.widget->setGeometry(childGeometry);
geometry.y += child.height + child.spacing;
geometry.height -= child.height + child.spacing;
}
}
void VerticalLayout::setMargin(unsigned margin_) {
margin = margin_;
void VerticalLayout::setMargin(unsigned margin) {
this->margin = margin;
}
unsigned VerticalLayout::minimumHeight() {
unsigned height = margin * 2;
foreach(child, children) height += child.height + child.spacing;
return height;
void VerticalLayout::setParent(Window &parent) {
foreach(child, children) {
if(child.layout) child.layout->setParent(parent);
if(child.widget) parent.append(*child.widget);
}
}
void VerticalLayout::setVisible(bool visible) {
@ -83,6 +136,4 @@ void VerticalLayout::setVisible(bool visible) {
VerticalLayout::VerticalLayout() {
margin = 0;
width = 0;
height = 0;
}

View File

@ -1,10 +1,11 @@
struct HorizontalLayout;
struct VerticalLayout : public Layout {
void append(HorizontalLayout &layout, unsigned width, unsigned height, unsigned spacing = 0);
void append(HorizontalLayout &layout, unsigned spacing = 0);
void append(Widget &widget, unsigned width, unsigned height, unsigned spacing = 0);
unsigned minimumHeight();
void setGeometry(Geometry &geometry);
Geometry minimumGeometry();
Geometry minimumLayoutGeometry();
void setGeometry(const Geometry &geometry);
void setMargin(unsigned margin);
void setParent(Window &parent);
void setVisible(bool visible);
@ -12,8 +13,6 @@ struct VerticalLayout : public Layout {
//private:
unsigned margin;
unsigned width;
unsigned height;
struct Children {
HorizontalLayout *layout;
Widget *widget;

View File

@ -1,3 +1,11 @@
Geometry pFont::geometry(const string &text) {
pango_layout_set_font_description(gtkLayout, gtkFont);
pango_layout_set_text(gtkLayout, text, -1);
int width = 0, height = 0;
pango_layout_get_pixel_size(gtkLayout, &width, &height);
return { 0, 0, width, height };
}
void pFont::setBold(bool bold) {
pango_font_description_set_weight(gtkFont, bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
}
@ -19,4 +27,6 @@ void pFont::setUnderline(bool underline) {
void pFont::constructor() {
gtkFont = pango_font_description_new();
PangoContext *context = gdk_pango_context_get_for_screen(gdk_screen_get_default());
gtkLayout = pango_layout_new(context);
}

View File

@ -14,6 +14,7 @@
#include "widget/widget.cpp"
#include "widget/button.cpp"
#include "widget/canvas.cpp"
#include "widget/check-box.cpp"
#include "widget/combo-box.cpp"
#include "widget/hex-edit.cpp"
@ -27,6 +28,8 @@
#include "widget/vertical-slider.cpp"
#include "widget/viewport.cpp"
Font pOS::defaultFont;
Geometry pOS::availableGeometry() {
//TODO: is there a GTK+ function for this?
//should return desktopGeometry() sans panels, toolbars, docks, etc.

View File

@ -26,6 +26,8 @@ struct pObject {
};
struct pOS : public pObject {
static Font defaultFont;
static Geometry availableGeometry();
static Geometry desktopGeometry();
static string fileLoad(Window &parent, const string &path, const lstring &filter);
@ -42,7 +44,9 @@ struct pOS : public pObject {
struct pFont : public pObject {
Font &font;
PangoFontDescription *gtkFont;
PangoLayout *gtkLayout;
Geometry geometry(const string &text);
void setBold(bool bold);
void setFamily(const string &family);
void setItalic(bool italic);
@ -164,10 +168,12 @@ struct pWidget : public pObject {
pWindow *parentWindow;
bool enabled();
Font& font();
virtual Geometry minimumGeometry();
void setEnabled(bool enabled);
virtual void setFocused();
virtual void setFont(Font &font);
void setGeometry(const Geometry &geometry);
virtual void setGeometry(const Geometry &geometry);
void setVisible(bool visible);
pWidget(Widget &widget) : widget(widget) {}
@ -177,16 +183,32 @@ struct pWidget : public pObject {
struct pButton : public pWidget {
Button &button;
Geometry minimumGeometry();
void setText(const string &text);
pButton(Button &button) : pWidget(button), button(button) {}
void constructor();
};
struct pCanvas : public pWidget {
Canvas &canvas;
uint32_t *bufferRGB;
uint32_t *bufferBGR;
uint32_t* buffer();
void setGeometry(const Geometry &geometry);
void update();
pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {}
void constructor();
void redraw();
};
struct pCheckBox : public pWidget {
CheckBox &checkBox;
bool checked();
Geometry minimumGeometry();
void setChecked(bool checked);
void setText(const string &text);
@ -199,6 +221,7 @@ struct pComboBox : public pWidget {
unsigned itemCounter;
void append(const string &text);
Geometry minimumGeometry();
void reset();
unsigned selection();
void setSelection(unsigned row);
@ -234,6 +257,7 @@ struct pHexEdit : public pWidget {
struct pHorizontalSlider : public pWidget {
HorizontalSlider &horizontalSlider;
Geometry minimumGeometry();
unsigned position();
void setLength(unsigned length);
void setPosition(unsigned position);
@ -245,6 +269,7 @@ struct pHorizontalSlider : public pWidget {
struct pLabel : public pWidget {
Label &label;
Geometry minimumGeometry();
void setText(const string &text);
pLabel(Label &label) : pWidget(label), label(label) {}
@ -254,6 +279,7 @@ struct pLabel : public pWidget {
struct pLineEdit : public pWidget {
LineEdit &lineEdit;
Geometry minimumGeometry();
void setEditable(bool editable);
void setText(const string &text);
string text();
@ -297,6 +323,7 @@ struct pListView : public pWidget {
struct pProgressBar : public pWidget {
ProgressBar &progressBar;
Geometry minimumGeometry();
void setPosition(unsigned position);
pProgressBar(ProgressBar &progressBar) : pWidget(progressBar), progressBar(progressBar) {}
@ -307,6 +334,7 @@ struct pRadioBox : public pWidget {
RadioBox &radioBox;
bool checked();
Geometry minimumGeometry();
void setChecked();
void setGroup(const reference_array<RadioBox&> &group);
void setText(const string &text);
@ -333,6 +361,7 @@ struct pTextEdit : public pWidget {
struct pVerticalSlider : public pWidget {
VerticalSlider &verticalSlider;
Geometry minimumGeometry();
unsigned position();
void setLength(unsigned length);
void setPosition(unsigned position);

View File

@ -2,6 +2,12 @@ static void Button_tick(Button *self) {
if(self->onTick) self->onTick();
}
Geometry pButton::minimumGeometry() {
Font &font = pWidget::font();
Geometry geometry = font.geometry(button.state.text);
return { 0, 0, geometry.width + 24, geometry.height + 14 };
}
void pButton::setText(const string &text) {
gtk_button_set_label(GTK_BUTTON(gtkWidget), text);
}

View File

@ -0,0 +1,59 @@
static void Canvas_expose(pCanvas *self) {
self->redraw();
}
uint32_t* pCanvas::buffer() {
return bufferRGB;
}
void pCanvas::setGeometry(const Geometry &geometry) {
delete[] bufferRGB;
delete[] bufferBGR;
bufferRGB = new uint32_t[geometry.width * geometry.height]();
bufferBGR = new uint32_t[geometry.width * geometry.height]();
pWidget::setGeometry(geometry);
update();
}
void pCanvas::update() {
if(gtk_widget_get_realized(gtkWidget) == false) return;
GdkRectangle rect;
rect.x = 0;
rect.y = 0;
rect.width = gtkWidget->allocation.width;
rect.height = gtkWidget->allocation.height;
gdk_window_invalidate_rect(gtkWidget->window, &rect, true);
}
void pCanvas::constructor() {
bufferRGB = new uint32_t[256 * 256]();
bufferBGR = new uint32_t[256 * 256]();
gtkWidget = gtk_drawing_area_new();
GdkColor color;
color.pixel = color.red = color.green = color.blue = 0;
gtk_widget_modify_bg(gtkWidget, GTK_STATE_NORMAL, &color);
gtk_widget_set_double_buffered(gtkWidget, false);
gtk_widget_add_events(gtkWidget, GDK_EXPOSURE_MASK);
g_signal_connect_swapped(G_OBJECT(gtkWidget), "expose_event", G_CALLBACK(Canvas_expose), (gpointer)this);
}
void pCanvas::redraw() {
if(gtk_widget_get_realized(gtkWidget) == false) return;
uint32_t *rgb = bufferRGB, *bgr = bufferBGR;
for(unsigned y = gtkWidget->allocation.height; y; y--) {
for(unsigned x = gtkWidget->allocation.width; x; x--) {
uint32_t pixel = *rgb++;
*bgr++ = ((pixel << 16) & 0xff0000) | (pixel & 0x00ff00) | ((pixel >> 16) & 0x0000ff);
}
}
gdk_draw_rgb_32_image(
gtkWidget->window,
gtkWidget->style->fg_gc[GTK_WIDGET_STATE(gtkWidget)],
0, 0, gtkWidget->allocation.width, gtkWidget->allocation.height,
GDK_RGB_DITHER_NONE, (guchar*)bufferBGR, sizeof(uint32_t) * gtkWidget->allocation.width
);
}

View File

@ -6,6 +6,12 @@ bool pCheckBox::checked() {
return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtkWidget));
}
Geometry pCheckBox::minimumGeometry() {
Font &font = pWidget::font();
Geometry geometry = font.geometry(checkBox.state.text);
return { 0, 0, geometry.width + 28, geometry.height + 4 };
}
void pCheckBox::setChecked(bool checked) {
locked = true;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), checked);

View File

@ -7,6 +7,15 @@ void pComboBox::append(const string &text) {
if(itemCounter++ == 0) setSelection(0);
}
Geometry pComboBox::minimumGeometry() {
Font &font = pWidget::font();
unsigned maximumWidth = 0;
foreach(item, comboBox.state.text) maximumWidth = max(maximumWidth, font.geometry(item).width);
Geometry geometry = font.geometry(" ");
return { 0, 0, maximumWidth + 44, geometry.height + 10 };
}
void pComboBox::reset() {
locked = true;
for(signed n = itemCounter - 1; n >= 0; n--) {

View File

@ -4,6 +4,10 @@ static void HorizontalSlider_change(HorizontalSlider *self) {
if(self->onChange) self->onChange();
}
Geometry pHorizontalSlider::minimumGeometry() {
return { 0, 0, 0, 20 };
}
unsigned pHorizontalSlider::position() {
return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget));
}

View File

@ -1,3 +1,9 @@
Geometry pLabel::minimumGeometry() {
Font &font = pWidget::font();
Geometry geometry = font.geometry(label.state.text);
return { 0, 0, geometry.width, geometry.height };
}
void pLabel::setText(const string &text) {
gtk_label_set_text(GTK_LABEL(gtkWidget), text);
}

View File

@ -6,6 +6,12 @@ static void LineEdit_change(LineEdit *self) {
if(self->p.locked == false && self->onChange) self->onChange();
}
Geometry pLineEdit::minimumGeometry() {
Font &font = pWidget::font();
Geometry geometry = font.geometry(lineEdit.state.text);
return { 0, 0, geometry.width + 10, geometry.height + 10 };
}
void pLineEdit::setEditable(bool editable) {
gtk_entry_set_editable(GTK_ENTRY(gtkWidget), editable);
}

View File

@ -1,3 +1,7 @@
Geometry pProgressBar::minimumGeometry() {
return { 0, 0, 0, 25 };
}
void pProgressBar::setPosition(unsigned position) {
position = position <= 100 ? position : 0;
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtkWidget), (double)position / 100.0);

View File

@ -6,6 +6,12 @@ bool pRadioBox::checked() {
return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtkWidget));
}
Geometry pRadioBox::minimumGeometry() {
Font &font = pWidget::font();
Geometry geometry = font.geometry(radioBox.state.text);
return { 0, 0, geometry.width + 28, geometry.height + 4 };
}
void pRadioBox::setChecked() {
locked = true;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), true);

View File

@ -4,6 +4,10 @@ static void VerticalSlider_change(VerticalSlider *self) {
if(self->onChange) self->onChange();
}
Geometry pVerticalSlider::minimumGeometry() {
return { 0, 0, 20, 0 };
}
unsigned pVerticalSlider::position() {
return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget));
}

View File

@ -6,6 +6,15 @@ static void Widget_setFont(GtkWidget *widget, gpointer font) {
}
}
Font& pWidget::font() {
if(widget.state.font) return *widget.state.font;
return pOS::defaultFont;
}
Geometry pWidget::minimumGeometry() {
return { 0, 0, 0, 0 };
}
bool pWidget::enabled() {
return gtk_widget_get_sensitive(gtkWidget);
}

View File

@ -362,7 +362,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
xml << " <map mode='linear' address='20-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='a0-bf:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram>\n";
xml << " <ram size='20000'>\n";
xml << " <map mode='linear' address='60-63:8000-ffff'/>\n";
xml << " <map mode='linear' address='e0-e3:8000-ffff'/>\n";
xml << " </ram>\n";
@ -372,7 +372,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
xml << " <map mode='linear' address='40-5f:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-df:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram>\n";
xml << " <ram size='20000'>\n";
xml << " <map mode='linear' address='70-73:8000-ffff'/>\n";
xml << " <map mode='linear' address='f0-f3:8000-ffff'/>\n";
xml << " </ram>\n";

View File

@ -12,18 +12,16 @@
namespace nall {
class string;
template<typename T> inline string to_string(T);
template<typename T> inline const char* to_string(T);
class string {
public:
inline void reserve(unsigned);
inline string& assign(const char*);
inline string& append(const char*);
inline string& append(bool);
inline string& append(signed int value);
inline string& append(unsigned int value);
inline string& append(double value);
template<typename... Args> inline string& assign(Args&&... args);
template<typename... Args> inline string& append(Args&&... args);
inline string& assign_(const char*);
inline string& append_(const char*);
inline bool readfile(const string&);

View File

@ -4,14 +4,14 @@
namespace nall {
//this is needed, as C++0x does not support explicit template specialization inside classes
template<> inline string to_string<bool> (bool v) { return v ? "true" : "false"; }
template<> inline string to_string<signed int> (signed int v) { return integer(v); }
template<> inline string to_string<unsigned int> (unsigned int v) { return decimal(v); }
template<> inline string to_string<double> (double v) { return fp(v); }
template<> inline string to_string<char*> (char *v) { return v; }
template<> inline string to_string<const char*> (const char *v) { return v; }
template<> inline string to_string<string> (string v) { return v; }
template<> inline string to_string<const string&>(const string &v) { return v; }
template<> inline const char* to_string<bool> (bool v) { return v ? "true" : "false"; }
template<> inline const char* to_string<signed int> (signed int v) { static char temp[256]; snprintf(temp, 255, "%+d", v); return temp; }
template<> inline const char* to_string<unsigned int> (unsigned int v) { static char temp[256]; snprintf(temp, 255, "%u", v); return temp; }
template<> inline const char* to_string<double> (double v) { static char temp[256]; snprintf(temp, 255, "%f", v); return temp; }
template<> inline const char* to_string<char*> (char *v) { return v; }
template<> inline const char* to_string<const char*> (const char *v) { return v; }
template<> inline const char* to_string<string> (string v) { return v; }
template<> inline const char* to_string<const string&>(const string &v) { return v; }
template<typename T> string& string::operator= (T value) { return assign(to_string<T>(value)); }
template<typename T> string& string::operator<<(T value) { return append(to_string<T>(value)); }
@ -22,8 +22,8 @@ template<typename T> lstring& lstring::operator<<(T value) {
}
#if defined(QSTRING_H)
template<> inline string to_string<QString>(QString v) { return v.toUtf8().constData(); }
template<> inline string to_string<const QString&>(const QString &v) { return v.toUtf8().constData(); }
template<> inline const char* to_string<QString>(QString v) { return v.toUtf8().constData(); }
template<> inline const char* to_string<const QString&>(const QString &v) { return v.toUtf8().constData(); }
string::operator QString() const { return QString::fromUtf8(*this); }
#endif

View File

@ -117,38 +117,7 @@ uintmax_t binary(const char *str) {
}
double fp(const char *str) {
if(!str) return 0.0;
bool negate = false;
//check for negation
if(*str == '-') {
negate = true;
str++;
}
intmax_t result_integral = 0;
while(*str) {
uint8_t x = *str++;
if(x >= '0' && x <= '9') x -= '0';
else if(x == '.' || x == ',') break; //break loop and read fractional part
else return (double)result_integral; //invalid value, assume no fractional part
result_integral = result_integral * 10 + x;
}
intmax_t result_fractional = 0;
while(*str) {
uint8_t x = *str++;
if(x >= '0' && x <= '9') x -= '0';
else break; //stop at first invalid character
result_fractional = result_fractional * 10 + x;
}
//calculate fractional portion
double result = (double)result_fractional;
while((uintmax_t)result > 0) result /= 10.0;
result += (double)result_integral;
return !negate ? result : -result;
return atof(str);
}
}

View File

@ -3,6 +3,15 @@
namespace nall {
static void istring(string &output) {
}
template<typename T, typename... Args>
static void istring(string &output, const T &value, Args&&... args) {
output.append_(to_string(value));
istring(output, std::forward<Args>(args)...);
}
void string::reserve(unsigned size_) {
if(size_ > size) {
size = size_;
@ -11,25 +20,31 @@ void string::reserve(unsigned size_) {
}
}
string& string::assign(const char *s) {
template<typename... Args> string& string::assign(Args&&... args) {
*data = 0;
istring(*this, std::forward<Args>(args)...);
return *this;
}
template<typename... Args> string& string::append(Args&&... args) {
istring(*this, std::forward<Args>(args)...);
return *this;
}
string& string::assign_(const char *s) {
unsigned length = strlen(s);
reserve(length);
strcpy(data, s);
return *this;
}
string& string::append(const char *s) {
string& string::append_(const char *s) {
unsigned length = strlen(data) + strlen(s);
reserve(length);
strcat(data, s);
return *this;
}
string& string::append(bool value) { append(value ? "true" : "false"); return *this; }
string& string::append(signed int value) { append(integer(value)); return *this; }
string& string::append(unsigned int value) { append(decimal(value)); return *this; }
string& string::append(double value) { append(fp(value)); return *this; }
string::operator const char*() const {
return data;
}
@ -64,15 +79,6 @@ string& string::operator=(string &&source) {
return *this;
}
static void istring(string &output) {
}
template<typename T, typename... Args>
static void istring(string &output, const T &value, Args&&... args) {
output.append(value);
istring(output, std::forward<Args>(args)...);
}
template<typename... Args> string::string(Args&&... args) {
size = 64;
data = (char*)malloc(size + 1);

View File

@ -3,15 +3,15 @@
namespace nall {
string realpath(const char *name) {
string currentpath() {
char path[PATH_MAX];
if(::realpath(name, path)) {
if(::getcwd(path)) {
string result(path);
result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/");
return result;
}
return "";
return "./";
}
string userpath() {
@ -22,18 +22,17 @@ string userpath() {
if(result.endswith("/") == false) result.append("/");
return result;
}
return "";
return currentpath();
}
string currentpath() {
string realpath(const char *name) {
char path[PATH_MAX];
if(::getcwd(path)) {
if(::realpath(name, path)) {
string result(path);
result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/");
return result;
}
return "";
return userpath();
}
}

View File

@ -28,7 +28,7 @@ void pAction::setFont(Font &font) {
void pAction::setVisible(bool visible) {
if(dynamic_cast<Menu*>(&action)) {
((Menu&)action).p.qtMenu->setVisible(visible);
((Menu&)action).p.qtMenu->menuAction()->setVisible(visible);
} else if(dynamic_cast<Separator*>(&action)) {
((Separator&)action).p.qtAction->setVisible(visible);
} else if(dynamic_cast<Item*>(&action)) {

View File

@ -1,3 +1,17 @@
Geometry pFont::geometry(const string &text) {
QFontMetrics metrics(*qtFont);
lstring lines;
lines.split("\n", text);
unsigned maxWidth = 0;
foreach(line, lines) {
maxWidth = max(maxWidth, metrics.width(line));
}
return { 0, 0, maxWidth, metrics.height() * lines.size() };
}
void pFont::setBold(bool bold) { update(); }
void pFont::setFamily(const string &family) { update(); }
void pFont::setItalic(bool italic) { update(); }

View File

@ -15,6 +15,7 @@
#include "widget/widget.cpp"
#include "widget/button.cpp"
#include "widget/canvas.cpp"
#include "widget/check-box.cpp"
#include "widget/combo-box.cpp"
#include "widget/hex-edit.cpp"
@ -29,6 +30,7 @@
#include "widget/viewport.cpp"
QApplication *pOS::application = 0;
Font pOS::defaultFont;
Geometry pOS::availableGeometry() {
QRect rect = QApplication::desktop()->availableGeometry();

View File

@ -1,8 +1,8 @@
/****************************************************************************
** Meta object code from reading C++ file 'qt.moc.hpp'
**
** Created: Fri Feb 25 04:49:31 2011
** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2)
** Created: Tue Mar 29 11:11:59 2011
** by: The Qt Meta Object Compiler version 62 (Qt 4.7.0)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
@ -10,7 +10,7 @@
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'qt.moc.hpp' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 62
#error "This file was generated using the moc from 4.6.2. It"
#error "This file was generated using the moc from 4.7.0. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif
@ -19,7 +19,7 @@ QT_BEGIN_MOC_NAMESPACE
static const uint qt_meta_data_pWindow[] = {
// content:
4, // revision
5, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
@ -70,7 +70,7 @@ int pWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_pItem[] = {
// content:
4, // revision
5, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -131,7 +131,7 @@ int pItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_pCheckItem[] = {
// content:
4, // revision
5, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -192,7 +192,7 @@ int pCheckItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_pRadioItem[] = {
// content:
4, // revision
5, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -253,7 +253,7 @@ int pRadioItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_pButton[] = {
// content:
4, // revision
5, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -311,10 +311,61 @@ int pButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
}
return _id;
}
static const uint qt_meta_data_pCanvas[] = {
// content:
5, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
0 // eod
};
static const char qt_meta_stringdata_pCanvas[] = {
"pCanvas\0"
};
const QMetaObject pCanvas::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_pCanvas,
qt_meta_data_pCanvas, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &pCanvas::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *pCanvas::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *pCanvas::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_pCanvas))
return static_cast<void*>(const_cast< pCanvas*>(this));
if (!strcmp(_clname, "pWidget"))
return static_cast< pWidget*>(const_cast< pCanvas*>(this));
return QObject::qt_metacast(_clname);
}
int pCanvas::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
return _id;
}
static const uint qt_meta_data_pCheckBox[] = {
// content:
4, // revision
5, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -375,7 +426,7 @@ int pCheckBox::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_pComboBox[] = {
// content:
4, // revision
5, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -436,7 +487,7 @@ int pComboBox::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_pHexEdit[] = {
// content:
4, // revision
5, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -497,7 +548,7 @@ int pHexEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_pHorizontalSlider[] = {
// content:
4, // revision
5, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -558,7 +609,7 @@ int pHorizontalSlider::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_pLineEdit[] = {
// content:
4, // revision
5, // revision
0, // classname
0, 0, // classinfo
2, 14, // methods
@ -621,7 +672,7 @@ int pLineEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_pListView[] = {
// content:
4, // revision
5, // revision
0, // classname
0, 0, // classinfo
3, 14, // methods
@ -687,7 +738,7 @@ int pListView::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_pRadioBox[] = {
// content:
4, // revision
5, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -748,7 +799,7 @@ int pRadioBox::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_pTextEdit[] = {
// content:
4, // revision
5, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -809,7 +860,7 @@ int pTextEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_pVerticalSlider[] = {
// content:
4, // revision
5, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods

View File

@ -25,6 +25,7 @@ struct pObject {
struct pOS : public pObject {
static QApplication *application;
static Font defaultFont;
static Geometry availableGeometry();
static Geometry desktopGeometry();
@ -43,6 +44,7 @@ struct pFont : public pObject {
Font &font;
QFont *qtFont;
Geometry geometry(const string &text);
void setBold(bool bold);
void setFamily(const string &family);
void setItalic(bool italic);
@ -193,10 +195,12 @@ struct pWidget : public pObject {
Widget &widget;
QWidget *qtWidget;
Font& font();
virtual Geometry minimumGeometry();
void setEnabled(bool enabled);
void setFocused();
void setFont(Font &font);
void setGeometry(const Geometry &geometry);
virtual void setGeometry(const Geometry &geometry);
void setVisible(bool visible);
pWidget(Widget &widget) : widget(widget) {}
@ -210,6 +214,7 @@ public:
Button &button;
QPushButton *qtButton;
Geometry minimumGeometry();
void setText(const string &text);
pButton(Button &button) : pWidget(button), button(button) {}
@ -219,6 +224,28 @@ public slots:
void onTick();
};
struct pCanvas : public QObject, public pWidget {
Q_OBJECT
public:
Canvas &canvas;
QImage *qtImage;
struct QtCanvas : public QWidget {
pCanvas &self;
void paintEvent(QPaintEvent*);
QtCanvas(pCanvas &self);
} *qtCanvas;
uint32_t* buffer();
void setGeometry(const Geometry &geometry);
void update();
pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {}
void constructor();
public slots:
};
struct pCheckBox : public QObject, public pWidget {
Q_OBJECT
@ -227,6 +254,7 @@ public:
QCheckBox *qtCheckBox;
bool checked();
Geometry minimumGeometry();
void setChecked(bool checked);
void setText(const string &text);
@ -245,6 +273,7 @@ public:
QComboBox *qtComboBox;
void append(const string &text);
Geometry minimumGeometry();
void reset();
unsigned selection();
void setSelection(unsigned row);
@ -291,6 +320,7 @@ public:
HorizontalSlider &horizontalSlider;
QSlider *qtSlider;
Geometry minimumGeometry();
unsigned position();
void setLength(unsigned length);
void setPosition(unsigned position);
@ -306,6 +336,7 @@ struct pLabel : public pWidget {
Label &label;
QLabel *qtLabel;
Geometry minimumGeometry();
void setText(const string &text);
pLabel(Label &label) : pWidget(label), label(label) {}
@ -319,6 +350,7 @@ public:
LineEdit &lineEdit;
QLineEdit *qtLineEdit;
Geometry minimumGeometry();
void setEditable(bool editable);
void setText(const string &text);
string text();
@ -365,6 +397,7 @@ struct pProgressBar : public pWidget {
ProgressBar &progressBar;
QProgressBar *qtProgressBar;
Geometry minimumGeometry();
void setPosition(unsigned position);
pProgressBar(ProgressBar &progressBar) : pWidget(progressBar), progressBar(progressBar) {}
@ -380,6 +413,7 @@ public:
QButtonGroup *qtGroup;
bool checked();
Geometry minimumGeometry();
void setChecked();
void setGroup(const reference_array<RadioBox&> &group);
void setText(const string &text);
@ -418,6 +452,7 @@ public:
VerticalSlider &verticalSlider;
QSlider *qtSlider;
Geometry minimumGeometry();
unsigned position();
void setLength(unsigned length);
void setPosition(unsigned position);

View File

@ -1,3 +1,9 @@
Geometry pButton::minimumGeometry() {
Font &font = this->font();
Geometry geometry = font.geometry(button.state.text);
return { 0, 0, geometry.width + 20, geometry.height + 12 };
}
void pButton::setText(const string &text) {
qtButton->setText(QString::fromUtf8(text));
}

View File

@ -0,0 +1,27 @@
uint32_t* pCanvas::buffer() {
return (uint32_t*)qtImage->bits();
}
void pCanvas::setGeometry(const Geometry &geometry) {
qtImage = new QImage(geometry.width, geometry.height, QImage::Format_RGB32);
qtImage->fill(0);
update();
pWidget::setGeometry(geometry);
}
void pCanvas::update() {
qtCanvas->update();
}
void pCanvas::constructor() {
qtWidget = qtCanvas = new QtCanvas(*this);
qtImage = new QImage(256, 256, QImage::Format_RGB32);
}
void pCanvas::QtCanvas::paintEvent(QPaintEvent *event) {
QPainter painter(self.qtCanvas);
painter.drawImage(0, 0, *self.qtImage);
}
pCanvas::QtCanvas::QtCanvas(pCanvas &self) : self(self) {
}

View File

@ -2,6 +2,12 @@ bool pCheckBox::checked() {
return qtCheckBox->isChecked();
}
Geometry pCheckBox::minimumGeometry() {
Font &font = this->font();
Geometry geometry = font.geometry(checkBox.state.text);
return { 0, 0, geometry.width + 26, geometry.height + 6 };
}
void pCheckBox::setChecked(bool checked) {
locked = true;
qtCheckBox->setChecked(checked);

View File

@ -2,6 +2,14 @@ void pComboBox::append(const string &text) {
qtComboBox->addItem(QString::fromUtf8(text));
}
Geometry pComboBox::minimumGeometry() {
Font &font = this->font();
unsigned maximumWidth = 0;
foreach(text, comboBox.state.text) maximumWidth = max(maximumWidth, font.geometry(text).width);
Geometry geometry = font.geometry(" ");
return { 0, 0, maximumWidth + 32, geometry.height + 12 };
}
void pComboBox::reset() {
while(qtComboBox->count()) qtComboBox->removeItem(0);
}

View File

@ -1,3 +1,7 @@
Geometry pHorizontalSlider::minimumGeometry() {
return { 0, 0, 0, 20 };
}
unsigned pHorizontalSlider::position() {
return qtSlider->value();
}

View File

@ -1,3 +1,9 @@
Geometry pLabel::minimumGeometry() {
Font &font = this->font();
Geometry geometry = font.geometry(label.state.text);
return { 0, 0, geometry.width, geometry.height };
}
void pLabel::setText(const string &text) {
qtLabel->setText(QString::fromUtf8(text));
}

View File

@ -1,3 +1,9 @@
Geometry pLineEdit::minimumGeometry() {
Font &font = this->font();
Geometry geometry = font.geometry(lineEdit.state.text);
return { 0, 0, geometry.width + 12, geometry.height + 12 };
}
void pLineEdit::setEditable(bool editable) {
qtLineEdit->setReadOnly(!editable);
}

View File

@ -1,3 +1,7 @@
Geometry pProgressBar::minimumGeometry() {
return { 0, 0, 0, 25 };
}
void pProgressBar::setPosition(unsigned position) {
qtProgressBar->setValue(position);
}

View File

@ -2,6 +2,12 @@ bool pRadioBox::checked() {
return qtRadioBox->isChecked();
}
Geometry pRadioBox::minimumGeometry() {
Font &font = this->font();
Geometry geometry = font.geometry(radioBox.state.text);
return { 0, 0, geometry.width + 26, geometry.height + 6 };
}
void pRadioBox::setChecked() {
locked = true;
foreach(item, radioBox.state.group) {

View File

@ -1,3 +1,7 @@
Geometry pVerticalSlider::minimumGeometry() {
return { 0, 0, 20, 0 };
}
unsigned pVerticalSlider::position() {
return qtSlider->value();
}

View File

@ -1,3 +1,12 @@
Font& pWidget::font() {
if(widget.state.font) return *widget.state.font;
return pOS::defaultFont;
}
Geometry pWidget::minimumGeometry() {
return { 0, 0, 0, 0 };
}
void pWidget::setEnabled(bool enabled) {
qtWidget->setEnabled(enabled);
}

View File

@ -6,6 +6,19 @@ static HFONT Font_createFont(const string &family, unsigned size, bool bold, boo
);
}
Geometry pFont::geometry(const string &text) {
HDC hdc = GetDC(0);
SelectObject(hdc, hfont);
RECT rc = { 0, 0, 0, 0 };
DrawText(hdc, utf16_t(text), -1, &rc, DT_CALCRECT);
ReleaseDC(0, hdc);
return { 0, 0, rc.right, rc.bottom };
}
unsigned pFont::height() {
return geometry(" ").height;
}
void pFont::setBold(bool bold) {
if(hfont) { DeleteObject(hfont); hfont = 0; }
hfont = Font_createFont(font.state.family, font.state.size, font.state.bold, font.state.italic, font.state.underline);
@ -32,5 +45,5 @@ void pFont::setUnderline(bool underline) {
}
void pFont::constructor() {
hfont = 0;
hfont = Font_createFont("Tahoma", 8, false, false, false);
}

View File

@ -1,3 +1,9 @@
Geometry pButton::minimumGeometry() {
Font &font = this->font();
Geometry geometry = font.geometry(button.state.text);
return { 0, 0, geometry.width + 20, font.p.height() + 10 };
}
void pButton::setText(const string &text) {
SetWindowText(hwnd, utf16_t(text));
}

View File

@ -0,0 +1,54 @@
static LRESULT CALLBACK Canvas_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
if(msg == WM_PAINT) {
Object *object = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(object && dynamic_cast<Canvas*>(object)) {
Canvas &canvas = (Canvas&)*object;
canvas.update();
}
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
uint32_t* pCanvas::buffer() {
return bufferRGB;
}
void pCanvas::setGeometry(const Geometry &geometry) {
delete[] bufferRGB;
bufferRGB = new uint32_t[geometry.width * geometry.height]();
pWidget::setGeometry(geometry);
update();
}
void pCanvas::update() {
RECT rc;
GetClientRect(hwnd, &rc);
unsigned width = rc.right, height = rc.bottom;
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biHeight = -height; //GDI stores bitmaps upside now; negative height flips bitmap
bmi.bmiHeader.biSizeImage = sizeof(uint32_t) * width * height;
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
SetDIBitsToDevice(ps.hdc, 0, 0, width, height, 0, 0, 0, height, (void*)bufferRGB, &bmi, DIB_RGB_COLORS);
EndPaint(hwnd, &ps);
InvalidateRect(hwnd, 0, false);
}
void pCanvas::constructor() {
bufferRGB = new uint32_t[256 * 256]();
setParent(Window::None);
}
void pCanvas::setParent(Window &parent) {
if(hwnd) DestroyWindow(hwnd);
hwnd = CreateWindow(L"phoenix_canvas", L"", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&canvas);
}

View File

@ -2,6 +2,12 @@ bool pCheckBox::checked() {
return SendMessage(hwnd, BM_GETCHECK, 0, 0);
}
Geometry pCheckBox::minimumGeometry() {
Font &font = this->font();
Geometry geometry = font.geometry(checkBox.state.text);
return { 0, 0, geometry.width + 20, font.p.height() + 4 };
}
void pCheckBox::setChecked(bool checked) {
SendMessage(hwnd, BM_SETCHECK, (WPARAM)checked, 0);
}

View File

@ -3,6 +3,13 @@ void pComboBox::append(const string &text) {
if(SendMessage(hwnd, CB_GETCOUNT, 0, 0) == 1) setSelection(0);
}
Geometry pComboBox::minimumGeometry() {
Font &font = this->font();
unsigned maximumWidth = 0;
foreach(text, comboBox.state.text) maximumWidth = max(maximumWidth, font.geometry(text).width);
return { 0, 0, maximumWidth + 24, font.p.height() + 10 };
}
void pComboBox::reset() {
SendMessage(hwnd, CB_RESETCONTENT, 0, 0);
}

View File

@ -1,3 +1,7 @@
Geometry pHorizontalSlider::minimumGeometry() {
return { 0, 0, 0, 25 };
}
unsigned pHorizontalSlider::position() {
return SendMessage(hwnd, TBM_GETPOS, 0, 0);
}

View File

@ -1,3 +1,9 @@
Geometry pLabel::minimumGeometry() {
Font &font = this->font();
Geometry geometry = font.geometry(label.state.text);
return { 0, 0, geometry.width, geometry.height };
}
void pLabel::setText(const string &text) {
SetWindowText(hwnd, utf16_t(text));
InvalidateRect(hwnd, 0, false);

View File

@ -1,3 +1,9 @@
Geometry pLineEdit::minimumGeometry() {
Font &font = this->font();
Geometry geometry = font.geometry(lineEdit.state.text);
return { 0, 0, geometry.width + 12, font.p.height() + 10 };
}
void pLineEdit::setEditable(bool editable) {
SendMessage(hwnd, EM_SETREADONLY, editable == false, 0);
}
@ -13,7 +19,7 @@ string pLineEdit::text() {
wchar_t text[length + 1];
GetWindowText(hwnd, text, length + 1);
text[length] = 0;
return utf8_t(text);
return (const char*)utf8_t(text);
}
void pLineEdit::constructor() {

View File

@ -1,3 +1,7 @@
Geometry pProgressBar::minimumGeometry() {
return { 0, 0, 0, 23 };
}
void pProgressBar::setPosition(unsigned position) {
SendMessage(hwnd, PBM_SETPOS, (WPARAM)position, 0);
}

View File

@ -2,6 +2,12 @@ bool pRadioBox::checked() {
return SendMessage(hwnd, BM_GETCHECK, 0, 0);
}
Geometry pRadioBox::minimumGeometry() {
Font &font = this->font();
Geometry geometry = font.geometry(radioBox.state.text);
return { 0, 0, geometry.width + 20, font.p.height() + 4 };
}
void pRadioBox::setChecked() {
foreach(item, radioBox.state.group) {
SendMessage(item.p.hwnd, BM_SETCHECK, (WPARAM)(&item == &radioBox), 0);

View File

@ -29,7 +29,7 @@ string pTextEdit::text() {
wchar_t buffer[length + 1];
GetWindowText(hwnd, buffer, length + 1);
buffer[length] = 0;
string text = utf8_t(buffer);
string text = (const char*)utf8_t(buffer);
text.replace("\r", "");
return text;
}

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