mirror of https://github.com/bsnes-emu/bsnes.git
Update to v083r01 release.
byuu says: This adds Bisqwit's NES palette generation code: http://nesdev.parodius.com/bbs/viewtopic.php?p=85060#85060 I set the saturation to 2.0 to closer match the existing "bright" palette, although it still has a greater contrast range (some colors are darker.) The gamma ramp option works now. Like SNES, best to also set gamma to 0.8 afterward. Once I think of a good way to expose the saturation/hue settings, I'll do so. I've also merged in the updated nall. Adds Cygwin uname check, and replaces linear_vector with vector in lstring and the GUI.
This commit is contained in:
parent
7fa8ad755d
commit
13ac6104e3
|
@ -19,6 +19,9 @@ ifeq ($(platform),)
|
|||
ifeq ($(uname),)
|
||||
platform := win
|
||||
delete = del $(subst /,\,$1)
|
||||
else ifneq ($(findstring CYGWIN,$(uname)),)
|
||||
platform := win
|
||||
delete = del $(subst /,\,$1)
|
||||
else ifneq ($(findstring Darwin,$(uname)),)
|
||||
platform := osx
|
||||
delete = rm -f $1
|
||||
|
|
|
@ -36,6 +36,11 @@ namespace nall {
|
|||
|
||||
inline unsigned length() const;
|
||||
|
||||
template<unsigned Limit = 0> inline lstring split(const char*) const;
|
||||
template<unsigned Limit = 0> inline lstring isplit(const char*) const;
|
||||
template<unsigned Limit = 0> inline lstring qsplit(const char*) const;
|
||||
template<unsigned Limit = 0> inline lstring iqsplit(const char*) const;
|
||||
|
||||
inline bool equals(const char*) const;
|
||||
inline bool iequals(const char*) const;
|
||||
|
||||
|
@ -102,9 +107,7 @@ namespace nall {
|
|||
#endif
|
||||
};
|
||||
|
||||
struct lstring : public linear_vector<string> {
|
||||
template<typename T> inline lstring& operator<<(T value);
|
||||
|
||||
struct lstring : vector<string> {
|
||||
inline optional<unsigned> find(const char*) const;
|
||||
template<unsigned Limit = 0> inline lstring& split(const char*, const char*);
|
||||
template<unsigned Limit = 0> inline lstring& isplit(const char*, const char*);
|
||||
|
|
|
@ -16,11 +16,6 @@ template<> inline const char* to_string<const string&> (const string &v) { retu
|
|||
template<> inline const char* to_string<cstring> (cstring v) { return v; }
|
||||
template<> inline const char* to_string<const cstring&>(const cstring &v) { return v; }
|
||||
|
||||
template<typename T> lstring& lstring::operator<<(T value) {
|
||||
operator[](size()).assign(to_string<T>(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if defined(QSTRING_H)
|
||||
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(); }
|
||||
|
|
|
@ -151,9 +151,7 @@ inline lstring::lstring() {
|
|||
}
|
||||
|
||||
inline lstring::lstring(std::initializer_list<string> list) {
|
||||
for(const string *s = list.begin(); s != list.end(); ++s) {
|
||||
operator<<(*s);
|
||||
}
|
||||
for(auto &data : list) append(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,14 +7,13 @@ template<unsigned Limit, bool Insensitive, bool Quoted> lstring& lstring::usplit
|
|||
if(!key || !*key) return *this;
|
||||
|
||||
const char *p = base;
|
||||
unsigned counter = 0;
|
||||
|
||||
while(*p) {
|
||||
if(Limit) if(counter >= Limit) break;
|
||||
if(Limit) if(size() >= Limit) break;
|
||||
if(quoteskip<Quoted>(p)) continue;
|
||||
for(unsigned n = 0;; n++) {
|
||||
if(key[n] == 0) {
|
||||
strlcpy(operator[](counter++), base, (unsigned)(p - base + 1));
|
||||
append(substr(base, 0, p - base));
|
||||
p += n;
|
||||
base = p;
|
||||
break;
|
||||
|
@ -23,7 +22,7 @@ template<unsigned Limit, bool Insensitive, bool Quoted> lstring& lstring::usplit
|
|||
}
|
||||
}
|
||||
|
||||
operator[](counter) = base;
|
||||
append(base);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,11 @@ namespace nall {
|
|||
|
||||
unsigned string::length() const { return strlen(data); }
|
||||
|
||||
template<unsigned limit> lstring string::split(const char *key) const { lstring result; result.split<limit>(key, data); return result; }
|
||||
template<unsigned limit> lstring string::isplit(const char *key) const { lstring result; result.isplit<limit>(key, data); return result; }
|
||||
template<unsigned limit> lstring string::qsplit(const char *key) const { lstring result; result.qsplit<limit>(key, data); return result; }
|
||||
template<unsigned limit> lstring string::iqsplit(const char *key) const { lstring result; result.iqsplit<limit>(key, data); return result; }
|
||||
|
||||
bool string::equals(const char *str) const { return !strcmp(data, str); }
|
||||
bool string::iequals(const char *str) const { return !istrcmp(data, str); }
|
||||
|
||||
|
|
|
@ -11,6 +11,116 @@
|
|||
#include <nall/utility.hpp>
|
||||
|
||||
namespace nall {
|
||||
template<typename T> struct vector {
|
||||
struct exception_out_of_bounds{};
|
||||
|
||||
protected:
|
||||
T *pool;
|
||||
unsigned poolsize;
|
||||
unsigned objectsize;
|
||||
|
||||
public:
|
||||
unsigned size() const { return objectsize; }
|
||||
unsigned capacity() const { return poolsize; }
|
||||
|
||||
void reset() {
|
||||
if(pool) {
|
||||
for(unsigned n = 0; n < objectsize; n++) pool[n].~T();
|
||||
free(pool);
|
||||
}
|
||||
pool = nullptr;
|
||||
poolsize = 0;
|
||||
objectsize = 0;
|
||||
}
|
||||
|
||||
void reserve(unsigned size) {
|
||||
size = bit::round(size); //amortize growth
|
||||
T *copy = (T*)calloc(size, sizeof(T));
|
||||
for(unsigned n = 0; n < min(size, objectsize); n++) new(copy + n) T(pool[n]);
|
||||
for(unsigned n = 0; n < objectsize; n++) pool[n].~T();
|
||||
free(pool);
|
||||
pool = copy;
|
||||
poolsize = size;
|
||||
objectsize = min(size, objectsize);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void append(const T& data, Args&&... args) {
|
||||
append(data);
|
||||
append(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void append(const T& data) {
|
||||
if(objectsize + 1 > poolsize) reserve(objectsize + 1);
|
||||
new(pool + objectsize++) T(data);
|
||||
}
|
||||
|
||||
void remove(unsigned index, unsigned count = 1) {
|
||||
for(unsigned n = index; count + n < objectsize; n++) {
|
||||
pool[n] = pool[count + n];
|
||||
}
|
||||
objectsize = (count + index >= objectsize) ? index : objectsize - count;
|
||||
}
|
||||
|
||||
//access
|
||||
inline T& operator[](unsigned position) {
|
||||
if(position >= objectsize) throw exception_out_of_bounds();
|
||||
return pool[position];
|
||||
}
|
||||
|
||||
inline const T& operator[](unsigned position) const {
|
||||
if(position >= objectsize) throw exception_out_of_bounds();
|
||||
return pool[position];
|
||||
}
|
||||
|
||||
inline const T& operator()(unsigned position, const T& data) const {
|
||||
if(position >= objectsize) return data;
|
||||
return pool[position];
|
||||
}
|
||||
|
||||
//iteration
|
||||
T* begin() { return &pool[0]; }
|
||||
T* end() { return &pool[objectsize]; }
|
||||
const T* begin() const { return &pool[0]; }
|
||||
const T* end() const { return &pool[objectsize]; }
|
||||
|
||||
//copy
|
||||
inline vector& operator=(const vector &source) {
|
||||
reset();
|
||||
reserve(source.capacity());
|
||||
for(auto &data : source) append(data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
vector(const vector &source) : pool(nullptr), poolsize(0), objectsize(0) {
|
||||
operator=(source);
|
||||
}
|
||||
|
||||
//move
|
||||
inline vector& operator=(vector &&source) {
|
||||
reset();
|
||||
pool = source.pool, poolsize = source.poolsize, objectsize = source.objectsize;
|
||||
source.pool = nullptr, source.poolsize = 0, source.objectsize = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
vector(vector &&source) : pool(nullptr), poolsize(0), objectsize(0) {
|
||||
operator=(std::move(source));
|
||||
}
|
||||
|
||||
//construction
|
||||
vector() : pool(nullptr), poolsize(0), objectsize(0) {
|
||||
}
|
||||
|
||||
vector(std::initializer_list<T> list) : pool(nullptr), poolsize(0), objectsize(0) {
|
||||
for(auto &data : list) append(data);
|
||||
}
|
||||
|
||||
~vector() {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
//linear_vector
|
||||
//memory: O(capacity * 2)
|
||||
//
|
||||
|
@ -23,7 +133,7 @@ namespace nall {
|
|||
//if objects hold memory address references to themselves (introspection), a
|
||||
//valid copy constructor will be needed to keep pointers valid.
|
||||
|
||||
template<typename T> class linear_vector {
|
||||
template<typename T> struct linear_vector {
|
||||
protected:
|
||||
T *pool;
|
||||
unsigned poolsize, objectsize;
|
||||
|
@ -160,7 +270,7 @@ namespace nall {
|
|||
//by guaranteeing that the base memory address of each objects never changes,
|
||||
//this avoids the need for an object to have a valid copy constructor.
|
||||
|
||||
template<typename T> class pointer_vector {
|
||||
template<typename T> struct pointer_vector {
|
||||
protected:
|
||||
T **pool;
|
||||
unsigned poolsize, objectsize;
|
||||
|
|
|
@ -130,7 +130,7 @@ struct CheckBox::State {
|
|||
|
||||
struct ComboBox::State {
|
||||
unsigned selection;
|
||||
linear_vector<string> text;
|
||||
vector<string> text;
|
||||
|
||||
State() {
|
||||
selection = 0;
|
||||
|
@ -191,7 +191,7 @@ struct ListView::State {
|
|||
bool headerVisible;
|
||||
bool selected;
|
||||
unsigned selection;
|
||||
linear_vector<lstring> text;
|
||||
vector<lstring> text;
|
||||
|
||||
State() {
|
||||
checkable = false;
|
||||
|
|
|
@ -10,12 +10,15 @@ PangoFontDescription* pFont::create(const string &description) {
|
|||
part.split(",", description);
|
||||
for(auto &item : part) item.trim(" ");
|
||||
|
||||
string family = part[0];
|
||||
unsigned size = decimal(part[1]);
|
||||
bool bold = part[2].position("Bold");
|
||||
bool italic = part[2].position("Italic");
|
||||
if(family == "") family = "Sans";
|
||||
if(size == 0) size = 8;
|
||||
string family = "Sans";
|
||||
unsigned size = 8u;
|
||||
bool bold = false;
|
||||
bool italic = false;
|
||||
|
||||
if(part[0] != "") family = part[0];
|
||||
if(part.size() >= 2) size = decimal(part[1]);
|
||||
if(part.size() >= 3) bold = part[2].position("Bold");
|
||||
if(part.size() >= 3) italic = part[2].position("Italic");
|
||||
|
||||
PangoFontDescription *font = pango_font_description_new();
|
||||
pango_font_description_set_family(font, family);
|
||||
|
|
|
@ -7,13 +7,18 @@ QFont pFont::create(const string &description) {
|
|||
part.split(",", description);
|
||||
for(auto &item : part) item.trim(" ");
|
||||
|
||||
string name = part[0] != "" ? part[0] : "Sans";
|
||||
unsigned size = part.size() >= 2 ? decimal(part[1]) : 8u;
|
||||
bool bold = part[2].position("Bold");
|
||||
bool italic = part[2].position("Italic");
|
||||
string family = "Sans";
|
||||
unsigned size = 8u;
|
||||
bool bold = false;
|
||||
bool italic = false;
|
||||
|
||||
if(part[0] != "") family = part[0];
|
||||
if(part.size() >= 2) size = decimal(part[1]);
|
||||
if(part.size() >= 3) bold = part[2].position("Bold");
|
||||
if(part.size() >= 3) italic = part[2].position("Italic");
|
||||
|
||||
QFont qtFont;
|
||||
qtFont.setFamily(name);
|
||||
qtFont.setFamily(family);
|
||||
qtFont.setPointSize(size);
|
||||
if(bold) qtFont.setBold(true);
|
||||
if(italic) qtFont.setItalic(true);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/****************************************************************************
|
||||
** Meta object code from reading C++ file 'platform.moc.hpp'
|
||||
**
|
||||
** Created: Tue Sep 27 01:00:52 2011
|
||||
** Created: Tue Oct 11 18:59:15 2011
|
||||
** by: The Qt Meta Object Compiler version 62 (Qt 4.7.0)
|
||||
**
|
||||
** WARNING! All changes made in this file will be lost!
|
||||
|
|
|
@ -10,12 +10,15 @@ HFONT pFont::create(const string &description) {
|
|||
part.split(",", description);
|
||||
for(auto &item : part) item.trim(" ");
|
||||
|
||||
string family = part[0];
|
||||
unsigned size = decimal(part[1]);
|
||||
bool bold = part[2].position("Bold");
|
||||
bool italic = part[2].position("Italic");
|
||||
if(family == "") family = "Tahoma";
|
||||
if(size == 0) size = 8;
|
||||
string family = "Sans";
|
||||
unsigned size = 8u;
|
||||
bool bold = false;
|
||||
bool italic = false;
|
||||
|
||||
if(part[0] != "") family = part[0];
|
||||
if(part.size() >= 2) size = decimal(part[1]);
|
||||
if(part.size() >= 3) bold = part[2].position("Bold");
|
||||
if(part.size() >= 3) italic = part[2].position("Italic");
|
||||
|
||||
return CreateFont(
|
||||
-(size * 96.0 / 72.0 + 0.5),
|
||||
|
|
|
@ -41,12 +41,12 @@ FileBrowser::FileBrowser() {
|
|||
|
||||
fileList.onActivate = openButton.onTick = { &FileBrowser::fileListActivate, this };
|
||||
|
||||
filterModes[Mode::Default ] = { "Default", "", { "*" } };
|
||||
filterModes[Mode::NES ] = { "NES", "", { "*.fc", "*.nes" } };
|
||||
filterModes[Mode::SNES ] = { "SNES", "", { "*.sfc" } };
|
||||
filterModes[Mode::GameBoy ] = { "GameBoy", "", { "*.gb", "*.gbc" } };
|
||||
filterModes[Mode::Satellaview] = { "Satellaview", "", { "*.bs" } };
|
||||
filterModes[Mode::SufamiTurbo] = { "SufamiTurbo", "", { "*.st" } };
|
||||
filterModes.append({ "Default", "", { "*" } });
|
||||
filterModes.append({ "NES", "", { "*.fc", "*.nes" } });
|
||||
filterModes.append({ "SNES", "", { "*.sfc" } });
|
||||
filterModes.append({ "GameBoy", "", { "*.gb", "*.gbc" } });
|
||||
filterModes.append({ "Satellaview", "", { "*.bs" } });
|
||||
filterModes.append({ "SufamiTurbo", "", { "*.st" } });
|
||||
mode = &filterModes[Mode::Default];
|
||||
|
||||
for(auto &mode : filterModes) config.attach(mode.path, mode.name);
|
||||
|
|
|
@ -22,7 +22,7 @@ private:
|
|||
string path;
|
||||
lstring filter;
|
||||
} *mode;
|
||||
linear_vector<FilterMode> filterModes;
|
||||
vector<FilterMode> filterModes;
|
||||
|
||||
lstring fileNameList;
|
||||
function<void (string)> callback;
|
||||
|
|
|
@ -114,26 +114,59 @@ int16_t InterfaceNES::inputPoll(bool port, unsigned device, unsigned id) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
InterfaceNES::InterfaceNES() {
|
||||
unsigned base_palette[] = {
|
||||
0x7c7c7c, 0x0000fc, 0x0000bc, 0x4428bc,
|
||||
0x940084, 0xa80020, 0xa81000, 0x881400,
|
||||
0x503000, 0x007800, 0x006800, 0x005800,
|
||||
0x004058, 0x000000, 0x000000, 0x000000,
|
||||
0xbcbcbc, 0x0078f8, 0x0058f8, 0x6844fc,
|
||||
0xd800cc, 0xe40058, 0xf83800, 0xe45c10,
|
||||
0xac7c00, 0x00b800, 0x00a800, 0x00a844,
|
||||
0x008888, 0x000000, 0x000000, 0x000000,
|
||||
0xf8f8f8, 0x3cbcfc, 0x6888fc, 0x9878f8,
|
||||
0xf878f8, 0xf85898, 0xf87858, 0xfca044,
|
||||
0xf8b800, 0xb8f818, 0x58d854, 0x58f898,
|
||||
0x00e8d8, 0x787878, 0x000000, 0x000000,
|
||||
0xfcfcfc, 0xa4e4fc, 0xb8b8b8, 0xd8d8f8,
|
||||
0xf8b8f8, 0xf8a4c0, 0xf0d0b0, 0xfce0a8,
|
||||
0xf8d878, 0xd8f878, 0xb8f8b8, 0xb8f8d8,
|
||||
0x00fcfc, 0xf8d8f8, 0x000000, 0x000000,
|
||||
//
|
||||
|
||||
//n = BGRCCCCCC (BGR=emphasis bits; C=color)
|
||||
unsigned InterfaceNES::paletteColor(
|
||||
unsigned n, double saturation, double hue,
|
||||
double contrast, double brightness, double gamma
|
||||
) {
|
||||
signed color = (n & 0x0f), level = color < 0xe ? (n >> 4) & 3 : 1;
|
||||
|
||||
static const double black = 0.518, white = 1.962, attenuation = 0.746;
|
||||
static const double levels[8] = {
|
||||
0.350, 0.518, 0.962, 1.550,
|
||||
1.094, 1.506, 1.962, 1.962,
|
||||
};
|
||||
memcpy(palette, base_palette, sizeof base_palette);
|
||||
|
||||
double lo_and_hi[2] = {
|
||||
levels[level + 4 * (color == 0x0)],
|
||||
levels[level + 4 * (color < 0xd)],
|
||||
};
|
||||
|
||||
double y = 0.0, i = 0.0, q = 0.0;
|
||||
auto wave = [](signed p, signed color) { return (color + p + 8) % 12 < 6; };
|
||||
for(signed p = 0; p < 12; p++) {
|
||||
double spot = lo_and_hi[wave(p, color)];
|
||||
|
||||
if(((n & 0x040) && wave(p, 12))
|
||||
|| ((n & 0x080) && wave(p, 4))
|
||||
|| ((n & 0x100) && wave(p, 8))
|
||||
) spot *= attenuation;
|
||||
|
||||
double v = (spot - black) / (white - black);
|
||||
|
||||
v = (v - 0.5) * contrast + 0.5;
|
||||
v *= brightness / 12.0;
|
||||
|
||||
y += v;
|
||||
i += v * std::cos((3.141592653 / 6.0) * (p + hue));
|
||||
q += v * std::sin((3.141592653 / 6.0) * (p + hue));
|
||||
}
|
||||
|
||||
i *= saturation;
|
||||
q *= saturation;
|
||||
|
||||
auto gammaAdjust = [=](double f) { return f < 0.0 ? 0.0 : std::pow(f, 2.2 / gamma); };
|
||||
return (uclamp<8>(255.0 * gammaAdjust(y + 0.946882 * i + 0.623557 * q)) << 16)
|
||||
+ (uclamp<8>(255.0 * gammaAdjust(y + -0.274788 * i + -0.635691 * q)) << 8)
|
||||
+ (uclamp<8>(255.0 * gammaAdjust(y + -1.108545 * i + 1.709007 * q)) << 0);
|
||||
}
|
||||
|
||||
InterfaceNES::InterfaceNES() {
|
||||
for(unsigned n = 0; n < 512; n++) {
|
||||
palette[n] = paletteColor(n, 2.0);
|
||||
}
|
||||
|
||||
for(unsigned e = 1; e < 8; e++) {
|
||||
static const double rfactor[8] = { 1.000, 1.239, 0.794, 1.019, 0.905, 1.023, 0.741, 0.750 };
|
||||
|
|
|
@ -15,4 +15,8 @@ struct InterfaceNES : NES::Interface {
|
|||
|
||||
private:
|
||||
unsigned palette[512];
|
||||
unsigned paletteColor(
|
||||
unsigned color, double saturation = 1.0, double hue = 0.0,
|
||||
double contrast = 1.0, double brightness = 1.0, double gamma = 1.8
|
||||
);
|
||||
};
|
||||
|
|
|
@ -49,7 +49,7 @@ Application::Application(int argc, char **argv) {
|
|||
inputManager = new InputManager;
|
||||
utility = new Utility;
|
||||
|
||||
title = "bsnes v083";
|
||||
title = "bsnes v083.01";
|
||||
|
||||
string fontFamily = Intrinsics::platform() == Intrinsics::Platform::Windows ? "Tahoma, " : "Sans, ";
|
||||
normalFont = { fontFamily, "8" };
|
||||
|
|
|
@ -4,7 +4,7 @@ struct WindowManager {
|
|||
string name;
|
||||
string geometry;
|
||||
};
|
||||
linear_vector<WindowList> windowList;
|
||||
vector<WindowList> windowList;
|
||||
|
||||
void append(Window *window, const string &name);
|
||||
|
||||
|
|
Loading…
Reference in New Issue