diff --git a/bsnes/Makefile b/bsnes/Makefile index ec15feae..bfeef843 100755 --- a/bsnes/Makefile +++ b/bsnes/Makefile @@ -12,7 +12,7 @@ ui := ui # compiler c := $(compiler) -std=gnu99 cpp := $(subst cc,++,$(compiler)) -std=gnu++0x -flags := -O3 -fomit-frame-pointer -I. +flags := -I. -O3 -fomit-frame-pointer link := objects := libco @@ -29,8 +29,6 @@ endif # platform ifeq ($(platform),x) - # tree vectorization causes code generation errors with Linux/GCC 4.6.1 - flags += -fno-tree-vectorize link += -s -ldl -lX11 -lXext else ifeq ($(platform),osx) else ifeq ($(platform),win) diff --git a/bsnes/nall/compositor.hpp b/bsnes/nall/compositor.hpp index ff6a6ea6..6b9245f6 100755 --- a/bsnes/nall/compositor.hpp +++ b/bsnes/nall/compositor.hpp @@ -8,11 +8,49 @@ namespace nall { struct compositor { inline static bool enabled(); inline static bool enable(bool status); + + #if defined(PLATFORM_X) + enum class Compositor : unsigned { Unknown, Metacity, Xfwm4 }; + inline static Compositor detect(); + + inline static bool enabled_metacity(); + inline static bool enable_metacity(bool status); + + inline static bool enabled_xfwm4(); + inline static bool enable_xfwm4(bool status); + #endif }; #if defined(PLATFORM_X) -bool compositor::enabled() { +//Metacity + +bool compositor::enabled_metacity() { + FILE *fp = popen("gconftool-2 --get /apps/metacity/general/compositing_manager", "r"); + if(fp == 0) return false; + + char buffer[512]; + if(fgets(buffer, sizeof buffer, fp) == 0) return false; + + if(!memcmp(buffer, "true", 4)) return true; + return false; +} + +bool compositor::enable_metacity(bool status) { + FILE *fp; + if(status) { + fp = popen("gconftool-2 --set --type bool /apps/metacity/general/compositing_manager true", "r"); + } else { + fp = popen("gconftool-2 --set --type bool /apps/metacity/general/compositing_manager false", "r"); + } + if(fp == 0) return false; + pclose(fp); + return true; +} + +//Xfwm4 + +bool compositor::enabled_xfwm4() { FILE *fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing'", "r"); if(fp == 0) return false; @@ -23,7 +61,7 @@ bool compositor::enabled() { return false; } -bool compositor::enable(bool status) { +bool compositor::enable_xfwm4(bool status) { FILE *fp; if(status) { fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'true'", "r"); @@ -35,6 +73,41 @@ bool compositor::enable(bool status) { return true; } +//General + +compositor::Compositor compositor::detect() { + Compositor result = Compositor::Unknown; + + FILE *fp; + char buffer[512]; + + fp = popen("pidof metacity", "r"); + if(fp && fgets(buffer, sizeof buffer, fp)) result = Compositor::Metacity; + pclose(fp); + + fp = popen("pidof xfwm4", "r"); + if(fp && fgets(buffer, sizeof buffer, fp)) result = Compositor::Xfwm4; + pclose(fp); + + return result; +} + +bool compositor::enabled() { + switch(detect()) { + case Compositor::Metacity: return enabled_metacity(); + case Compositor::Xfwm4: return enabled_xfwm4(); + default: return false; + } +} + +bool compositor::enable(bool status) { + switch(detect()) { + case Compositor::Metacity: return enable_metacity(status); + case Compositor::Xfwm4: return enable_xfwm4(status); + default: return false; + } +} + #elif defined(PLATFORM_WINDOWS) bool compositor::enabled() { diff --git a/bsnes/nall/image.hpp b/bsnes/nall/image.hpp new file mode 100755 index 00000000..c79655eb --- /dev/null +++ b/bsnes/nall/image.hpp @@ -0,0 +1,433 @@ +#ifndef NALL_IMAGE_HPP +#define NALL_IMAGE_HPP + +#include +#include +#include +#include +#include + +namespace nall { + +struct image { + uint8_t *data; + unsigned width; + unsigned height; + unsigned pitch; + + bool endian; //0 = little, 1 = big + unsigned depth; + unsigned stride; + + struct Channel { + uint64_t mask; + unsigned depth; + unsigned shift; + } alpha, red, green, blue; + + typedef double (*interpolation)(double, double, double, double, double); + static inline unsigned bitDepth(uint64_t color); + static inline unsigned bitShift(uint64_t color); + static inline uint64_t normalize(uint64_t color, unsigned sourceDepth, unsigned targetDepth); + + inline image& operator=(const image &source); + inline image& operator=(image &&source); + inline image(const image &source); + inline image(image &&source); + inline image(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask); + inline ~image(); + + inline uint64_t read(const uint8_t *data) const; + inline void write(uint8_t *data, uint64_t value) const; + + inline void free(); + inline void allocate(unsigned width, unsigned height); + inline bool load(const string &filename); + inline void scale(unsigned width, unsigned height, interpolation op); + inline void transform(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask); + inline void alphaBlend(uint64_t alphaColor); + +protected: + inline uint64_t interpolate(double mu, const uint64_t *s, interpolation op); + inline void scaleX(unsigned width, interpolation op); + inline void scaleY(unsigned height, interpolation op); + inline bool loadBMP(const string &filename); + inline bool loadPNG(const string &filename); +}; + +//static + +unsigned image::bitDepth(uint64_t color) { + unsigned depth = 0; + if(color) while((color & 1) == 0) color >>= 1; + while((color & 1) == 1) { color >>= 1; depth++; } + return depth; +} + +unsigned image::bitShift(uint64_t color) { + unsigned shift = 0; + if(color) while((color & 1) == 0) { color >>= 1; shift++; } + return shift; +} + +uint64_t image::normalize(uint64_t color, unsigned sourceDepth, unsigned targetDepth) { + while(sourceDepth < targetDepth) { + color = (color << sourceDepth) | color; + sourceDepth += sourceDepth; + } + if(targetDepth < sourceDepth) color >>= (sourceDepth - targetDepth); + return color; +} + +//public + +image& image::operator=(const image &source) { + free(); + + width = source.width; + height = source.height; + pitch = source.pitch; + + endian = source.endian; + stride = source.stride; + + alpha = source.alpha; + red = source.red; + green = source.green; + blue = source.blue; + + data = new uint8_t[width * height * stride]; + memcpy(data, source.data, width * height * stride); + return *this; +} + +image& image::operator=(image &&source) { + width = source.width; + height = source.height; + pitch = source.pitch; + + endian = source.endian; + stride = source.stride; + + alpha = source.alpha; + red = source.red; + green = source.green; + blue = source.blue; + + data = source.data; + source.data = nullptr; + return *this; +} + +image::image(const image &source) : data(nullptr) { + operator=(source); +} + +image::image(image &&source) : data(nullptr) { + operator=(std::forward(source)); +} + +image::image(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask) : data(nullptr) { + width = 0, height = 0, pitch = 0; + + this->endian = endian; + this->depth = depth; + this->stride = (depth / 8) + ((depth & 7) > 0); + + alpha.mask = alphaMask, red.mask = redMask, green.mask = greenMask, blue.mask = blueMask; + alpha.depth = bitDepth(alpha.mask), alpha.shift = bitShift(alpha.mask); + red.depth = bitDepth(red.mask), red.shift = bitShift(red.mask); + green.depth = bitDepth(green.mask), green.shift = bitShift(green.mask); + blue.depth = bitDepth(blue.mask), blue.shift = bitShift(blue.mask); +} + +image::~image() { + free(); +} + +uint64_t image::read(const uint8_t *data) const { + uint64_t result = 0; + if(endian == 0) { + for(signed n = stride - 1; n >= 0; n--) result = (result << 8) | data[n]; + } else { + for(signed n = 0; n < stride; n++) result = (result << 8) | data[n]; + } + return result; +} + +void image::write(uint8_t *data, uint64_t value) const { + if(endian == 0) { + for(signed n = 0; n < stride; n++) { data[n] = value; value >>= 8; } + } else { + for(signed n = stride - 1; n >= 0; n--) { data[n] = value; value >>= 8; } + } +} + +void image::free() { + if(data) delete[] data; + data = nullptr; +} + +void image::allocate(unsigned width, unsigned height) { + free(); + data = new uint8_t[width * height * stride](); + pitch = width * stride; + this->width = width; + this->height = height; +} + +bool image::load(const string &filename) { + if(loadBMP(filename) == true) return true; + if(loadPNG(filename) == true) return true; + return false; +} + +void image::scale(unsigned outputWidth, unsigned outputHeight, interpolation op) { + scaleX(outputWidth, op); + scaleY(outputHeight, op); +} + +void image::transform(bool outputEndian, unsigned outputDepth, uint64_t outputAlphaMask, uint64_t outputRedMask, uint64_t outputGreenMask, uint64_t outputBlueMask) { + image output(outputEndian, outputDepth, outputAlphaMask, outputRedMask, outputGreenMask, outputBlueMask); + output.allocate(width, height); + + #pragma omp parallel for + for(unsigned y = 0; y < height; y++) { + uint8_t *dp = output.data + output.pitch * y; + uint8_t *sp = data + pitch * y; + for(unsigned x = 0; x < width; x++) { + uint64_t color = read(sp); + sp += stride; + + uint64_t a = (color & alpha.mask) >> alpha.shift; + uint64_t r = (color & red.mask) >> red.shift; + uint64_t g = (color & green.mask) >> green.shift; + uint64_t b = (color & blue.mask) >> blue.shift; + + a = normalize(a, alpha.depth, output.alpha.depth); + r = normalize(r, red.depth, output.red.depth); + g = normalize(g, green.depth, output.green.depth); + b = normalize(b, blue.depth, output.blue.depth); + + output.write(dp, (a << output.alpha.shift) + (r << output.red.shift) + (g << output.green.shift) + (b << output.blue.shift)); + dp += output.stride; + } + } + + operator=(std::move(output)); +} + +void image::alphaBlend(uint64_t alphaColor) { + uint64_t alphaR = (alphaColor & red.mask) >> red.shift; + uint64_t alphaG = (alphaColor & green.mask) >> green.shift; + uint64_t alphaB = (alphaColor & blue.mask) >> blue.shift; + + #pragma omp parallel for + for(unsigned y = 0; y < height; y++) { + uint8_t *dp = data + pitch * y; + for(unsigned x = 0; x < width; x++) { + uint64_t color = read(dp); + + uint64_t colorA = (color & alpha.mask) >> alpha.shift; + uint64_t colorR = (color & red.mask) >> red.shift; + uint64_t colorG = (color & green.mask) >> green.shift; + uint64_t colorB = (color & blue.mask) >> blue.shift; + double alphaScale = (double)colorA / (double)((1 << alpha.depth) - 1); + + colorA = (1 << alpha.depth) - 1; + colorR = (colorR * alphaScale) + (alphaR * (1.0 - alphaScale)); + colorG = (colorG * alphaScale) + (alphaG * (1.0 - alphaScale)); + colorB = (colorB * alphaScale) + (alphaB * (1.0 - alphaScale)); + + write(dp, (colorA << alpha.shift) + (colorR << red.shift) + (colorG << green.shift) + (colorB << blue.shift)); + dp += stride; + } + } +} + +//protected + +uint64_t image::interpolate(double mu, const uint64_t *s, double (*op)(double, double, double, double, double)) { + uint64_t aa = (s[0] & alpha.mask) >> alpha.shift, ar = (s[0] & red.mask) >> red.shift, + ag = (s[0] & green.mask) >> green.shift, ab = (s[0] & blue.mask) >> blue.shift; + uint64_t ba = (s[1] & alpha.mask) >> alpha.shift, br = (s[1] & red.mask) >> red.shift, + bg = (s[1] & green.mask) >> green.shift, bb = (s[1] & blue.mask) >> blue.shift; + uint64_t ca = (s[2] & alpha.mask) >> alpha.shift, cr = (s[2] & red.mask) >> red.shift, + cg = (s[2] & green.mask) >> green.shift, cb = (s[2] & blue.mask) >> blue.shift; + uint64_t da = (s[3] & alpha.mask) >> alpha.shift, dr = (s[3] & red.mask) >> red.shift, + dg = (s[3] & green.mask) >> green.shift, db = (s[3] & blue.mask) >> blue.shift; + + int64_t A = op(mu, aa, ba, ca, da); + int64_t R = op(mu, ar, br, cr, dr); + int64_t G = op(mu, ag, bg, cg, dg); + int64_t B = op(mu, ab, bb, cb, db); + + A = max(0, min(A, (1 << alpha.depth) - 1)); + R = max(0, min(R, (1 << red.depth) - 1)); + G = max(0, min(G, (1 << green.depth) - 1)); + B = max(0, min(B, (1 << blue.depth) - 1)); + + return (A << alpha.shift) + (R << red.shift) + (G << green.shift) + (B << blue.shift); +} + +void image::scaleX(unsigned outputWidth, interpolation op) { + uint8_t *outputData = new uint8_t[outputWidth * height * stride]; + unsigned outputPitch = outputWidth * stride; + double step = (double)width / (double)outputWidth; + + #pragma omp parallel for + for(unsigned y = 0; y < height; y++) { + uint8_t *dp = outputData + outputPitch * y; + uint8_t *sp = data + pitch * y; + + double fraction = 0.0; + uint64_t s[4] = { read(sp), read(sp), read(sp), read(sp) }; + + for(unsigned x = 0; x < width; x++) { + if(sp >= data + pitch * height) break; + s[0] = s[1]; + s[1] = s[2]; + s[2] = s[3]; + s[3] = read(sp); + + while(fraction <= 1.0) { + if(dp >= outputData + outputPitch * height) break; + write(dp, interpolate(fraction, (const uint64_t*)&s, op)); + dp += stride; + fraction += step; + } + + sp += stride; + fraction -= 1.0; + } + } + + free(); + data = outputData; + width = outputWidth; + pitch = width * stride; +} + +void image::scaleY(unsigned outputHeight, interpolation op) { + uint8_t *outputData = new uint8_t[width * outputHeight * stride]; + double step = (double)height / (double)outputHeight; + + #pragma omp parallel for + for(unsigned x = 0; x < width; x++) { + uint8_t *dp = outputData + stride * x; + uint8_t *sp = data + stride * x; + + double fraction = 0.0; + uint64_t s[4] = { read(sp), read(sp), read(sp), read(sp) }; + + for(unsigned y = 0; y < height; y++) { + if(sp >= data + pitch * height) break; + s[0] = s[1]; + s[1] = s[2]; + s[2] = s[3]; + s[3] = read(sp); + + while(fraction <= 1.0) { + if(dp >= outputData + pitch * outputHeight) break; + write(dp, interpolate(fraction, (const uint64_t*)&s, op)); + dp += pitch; + fraction += step; + } + + sp += pitch; + fraction -= 1.0; + } + } + + free(); + data = outputData; + height = outputHeight; +} + +bool image::loadBMP(const string &filename) { + uint32_t *outputData; + unsigned outputWidth, outputHeight; + if(bmp::read(filename, outputData, outputWidth, outputHeight) == false) return false; + + allocate(outputWidth, outputHeight); + const uint32_t *sp = outputData; + uint8_t *dp = data; + + for(unsigned y = 0; y < outputHeight; y++) { + for(unsigned x = 0; x < outputWidth; x++) { + uint32_t color = *sp++; + uint64_t a = normalize((uint8_t)(color >> 24), 8, alpha.depth); + uint64_t r = normalize((uint8_t)(color >> 16), 8, red.depth); + uint64_t g = normalize((uint8_t)(color >> 8), 8, green.depth); + uint64_t b = normalize((uint8_t)(color >> 0), 8, blue.depth); + write(dp, (a << alpha.shift) + (r << red.shift) + (g << green.shift) + (b << blue.shift)); + dp += stride; + } + } + + delete[] outputData; + return true; +} + +bool image::loadPNG(const string &filename) { + png source; + if(source.decode(filename) == false) return false; + + allocate(source.info.width, source.info.height); + const uint8_t *sp = source.data; + uint8_t *dp = data; + + auto decode = [&]() -> uint64_t { + uint64_t p, r, g, b, a; + + switch(source.info.colorType) { + case 0: //L + r = g = b = source.readbits(sp); + a = (1 << source.info.bitDepth) - 1; + break; + case 2: //R,G,B + r = source.readbits(sp); + g = source.readbits(sp); + b = source.readbits(sp); + a = (1 << source.info.bitDepth) - 1; + break; + case 3: //P + p = source.readbits(sp); + r = source.info.palette[p][0]; + g = source.info.palette[p][1]; + b = source.info.palette[p][2]; + a = (1 << source.info.bitDepth) - 1; + break; + case 4: //L,A + r = g = b = source.readbits(sp); + a = source.readbits(sp); + break; + case 6: //R,G,B,A + r = source.readbits(sp); + g = source.readbits(sp); + b = source.readbits(sp); + a = source.readbits(sp); + break; + } + + a = normalize(a, source.info.bitDepth, alpha.depth); + r = normalize(r, source.info.bitDepth, red.depth); + g = normalize(g, source.info.bitDepth, green.depth); + b = normalize(b, source.info.bitDepth, blue.depth); + + return (a << alpha.shift) + (r << red.shift) + (g << green.shift) + (b << blue.shift); + }; + + for(unsigned y = 0; y < height; y++) { + for(unsigned x = 0; x < width; x++) { + write(dp, decode()); + dp += stride; + } + } + + return true; +} + +} + +#endif diff --git a/bsnes/nall/interpolation.hpp b/bsnes/nall/interpolation.hpp new file mode 100755 index 00000000..46a09a49 --- /dev/null +++ b/bsnes/nall/interpolation.hpp @@ -0,0 +1,59 @@ +#ifndef NALL_INTERPOLATION_HPP +#define NALL_INTERPOLATION_HPP + +namespace nall { + +struct Interpolation { + static inline double Nearest(double mu, double a, double b, double c, double d) { + return (mu < 0.5 ? c : d); + } + + static inline double Sublinear(double mu, double a, double b, double c, double d) { + mu = ((mu - 0.5) * 2.0) + 0.5; + if(mu < 0) mu = 0; + if(mu > 1) mu = 1; + return c * (1.0 - mu) + d * mu; + } + + static inline double Linear(double mu, double a, double b, double c, double d) { + return c * (1.0 - mu) + d * mu; + } + + static inline double Cosine(double mu, double a, double b, double c, double d) { + mu = (1.0 - cos(mu * 3.14159265)) / 2.0; + return c * (1.0 - mu) + d * mu; + } + + static inline double Cubic(double mu, double a, double b, double c, double d) { + double A = d - c - a + b; + double B = a - b - A; + double C = c - a; + double D = b; + return A * (mu * mu * mu) + B * (mu * mu) + C * mu + D; + } + + static inline double Hermite(double mu1, double a, double b, double c, double d) { + const double tension = 0.0; //-1 = low, 0 = normal, +1 = high + const double bias = 0.0; //-1 = left, 0 = even, +1 = right + double mu2, mu3, m0, m1, a0, a1, a2, a3; + + mu2 = mu1 * mu1; + mu3 = mu2 * mu1; + + m0 = (b - a) * (1.0 + bias) * (1.0 - tension) / 2.0; + m0 += (c - b) * (1.0 - bias) * (1.0 - tension) / 2.0; + m1 = (c - b) * (1.0 + bias) * (1.0 - tension) / 2.0; + m1 += (d - c) * (1.0 - bias) * (1.0 - tension) / 2.0; + + a0 = +2 * mu3 - 3 * mu2 + 1; + a1 = mu3 - 2 * mu2 + mu1; + a2 = mu3 - mu2; + a3 = -2 * mu3 + 3 * mu2; + + return (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c); + } +}; + +} + +#endif diff --git a/bsnes/nall/png.hpp b/bsnes/nall/png.hpp index a39c85c5..4b474724 100755 --- a/bsnes/nall/png.hpp +++ b/bsnes/nall/png.hpp @@ -10,9 +10,12 @@ namespace nall { struct png { - uint32_t *data; - unsigned size; - + //colorType: + //0 = L + //2 = R,G,B + //3 = P + //4 = L,A + //6 = R,G,B,A struct Info { unsigned width; unsigned height; @@ -28,13 +31,14 @@ struct png { uint8_t palette[256][3]; } info; - uint8_t *rawData; - unsigned rawSize; + uint8_t *data; + unsigned size; inline bool decode(const string &filename); inline bool decode(const uint8_t *sourceData, unsigned sourceSize); - inline void transform(); - inline void alphaTransform(uint32_t rgb = 0xffffff); + inline unsigned readbits(const uint8_t *&data); + unsigned bitpos; + inline png(); inline ~png(); @@ -46,16 +50,11 @@ protected: IEND = 0x49454e44, }; - unsigned bitpos; - inline unsigned interlace(unsigned pass, unsigned index); inline unsigned inflateSize(); inline bool deinterlace(const uint8_t *&inputData, unsigned pass); inline bool filter(uint8_t *outputData, const uint8_t *inputData, unsigned width, unsigned height); inline unsigned read(const uint8_t *data, unsigned length); - inline unsigned decode(const uint8_t *&data); - inline unsigned readbits(const uint8_t *&data); - inline unsigned scale(unsigned n); }; bool png::decode(const string &filename) { @@ -146,14 +145,14 @@ bool png::decode(const uint8_t *sourceData, unsigned sourceSize) { return false; } - rawSize = info.width * info.height * info.bytesPerPixel; - rawData = new uint8_t[rawSize]; + size = info.width * info.height * info.bytesPerPixel; + data = new uint8_t[size]; if(info.interlaceMethod == 0) { - if(filter(rawData, interlacedData, info.width, info.height) == false) { + if(filter(data, interlacedData, info.width, info.height) == false) { delete[] interlacedData; - delete[] rawData; - rawData = 0; + delete[] data; + data = 0; return false; } } else { @@ -161,8 +160,8 @@ bool png::decode(const uint8_t *sourceData, unsigned sourceSize) { for(unsigned pass = 0; pass < 7; pass++) { if(deinterlace(passData, pass) == false) { delete[] interlacedData; - delete[] rawData; - rawData = 0; + delete[] data; + data = 0; return false; } } @@ -216,7 +215,7 @@ bool png::deinterlace(const uint8_t *&inputData, unsigned pass) { const uint8_t *rd = outputData; for(unsigned y = yo; y < info.height; y += yd) { - uint8_t *wr = rawData + y * info.pitch; + uint8_t *wr = data + y * info.pitch; for(unsigned x = xo; x < info.width; x += xd) { for(unsigned b = 0; b < info.bytesPerPixel; b++) { wr[x * info.bytesPerPixel + b] = *rd++; @@ -298,42 +297,6 @@ unsigned png::read(const uint8_t *data, unsigned length) { return result; } -unsigned png::decode(const uint8_t *&data) { - unsigned p, r, g, b, a; - - switch(info.colorType) { - case 0: //L - r = g = b = scale(readbits(data)); - a = 0xff; - break; - case 2: //R,G,B - r = scale(readbits(data)); - g = scale(readbits(data)); - b = scale(readbits(data)); - a = 0xff; - break; - case 3: //P - p = readbits(data); - r = info.palette[p][0]; - g = info.palette[p][1]; - b = info.palette[p][2]; - a = 0xff; - break; - case 4: //L,A - r = g = b = scale(readbits(data)); - a = scale(readbits(data)); - break; - case 6: //R,G,B,A - r = scale(readbits(data)); - g = scale(readbits(data)); - b = scale(readbits(data)); - a = scale(readbits(data)); - break; - } - - return (a << 24) | (r << 16) | (g << 8) | (b << 0); -} - unsigned png::readbits(const uint8_t *&data) { unsigned result = 0; switch(info.bitDepth) { @@ -363,62 +326,12 @@ unsigned png::readbits(const uint8_t *&data) { return result; } -unsigned png::scale(unsigned n) { - switch(info.bitDepth) { - case 1: return n ? 0xff : 0x00; - case 2: return n * 0x55; - case 4: return n * 0x11; - case 8: return n; - case 16: return n >> 8; - } - return 0; -} - -void png::transform() { - if(data) delete[] data; - data = new uint32_t[info.width * info.height]; - +png::png() : data(nullptr) { bitpos = 0; - const uint8_t *rd = rawData; - for(unsigned y = 0; y < info.height; y++) { - uint32_t *wr = data + y * info.width; - for(unsigned x = 0; x < info.width; x++) { - wr[x] = decode(rd); - } - } -} - -void png::alphaTransform(uint32_t rgb) { - transform(); - - uint8_t ir = rgb >> 16; - uint8_t ig = rgb >> 8; - uint8_t ib = rgb >> 0; - - uint32_t *p = data; - for(unsigned y = 0; y < info.height; y++) { - for(unsigned x = 0; x < info.width; x++) { - uint32_t pixel = *p; - uint8_t a = pixel >> 24; - uint8_t r = pixel >> 16; - uint8_t g = pixel >> 8; - uint8_t b = pixel >> 0; - - r = (r * a) + (ir * (255 - a)) >> 8; - g = (g * a) + (ig * (255 - a)) >> 8; - b = (b * a) + (ib * (255 - a)) >> 8; - - *p++ = (255 << 24) | (r << 16) | (g << 8) | (b << 0); - } - } -} - -png::png() : data(nullptr), rawData(nullptr) { } png::~png() { if(data) delete[] data; - if(rawData) delete[] rawData; } } diff --git a/bsnes/nall/string.hpp b/bsnes/nall/string.hpp index 884e31e8..288424bc 100755 --- a/bsnes/nall/string.hpp +++ b/bsnes/nall/string.hpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/bsnes/nall/string/base.hpp b/bsnes/nall/string/base.hpp index 33ff1c7a..97000bef 100755 --- a/bsnes/nall/string/base.hpp +++ b/bsnes/nall/string/base.hpp @@ -183,8 +183,8 @@ namespace nall { template inline string ldecimal(uintmax_t value); template inline string hex(uintmax_t value); template inline string binary(uintmax_t value); - inline unsigned fp(char *str, double value); - inline string fp(double value); + inline unsigned fp(char *str, long double value); + inline string fp(long double value); //variadic.hpp template inline void print(Args&&... args); diff --git a/bsnes/nall/string/cast.hpp b/bsnes/nall/string/cast.hpp index 12f525ad..7c7e276b 100755 --- a/bsnes/nall/string/cast.hpp +++ b/bsnes/nall/string/cast.hpp @@ -101,19 +101,19 @@ template struct stringify> { template<> struct stringify { char data[256]; operator const char*() const { return data; } - stringify(float value) { snprintf(data, 255, "%f", value); } + stringify(float value) { fp(data, value); } }; template<> struct stringify { char data[256]; operator const char*() const { return data; } - stringify(double value) { snprintf(data, 255, "%f", value); } + stringify(double value) { fp(data, value); } }; template<> struct stringify { char data[256]; operator const char*() const { return data; } - stringify(long double value) { snprintf(data, 255, "%Lf", value); } + stringify(long double value) { fp(data, value); } }; // strings diff --git a/bsnes/nall/string/math-fixed-point.hpp b/bsnes/nall/string/math-fixed-point.hpp new file mode 100755 index 00000000..744621d1 --- /dev/null +++ b/bsnes/nall/string/math-fixed-point.hpp @@ -0,0 +1,157 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace fixedpoint { + +static nall::function eval_fallback; + +static intmax_t eval_integer(const char *& s) { + if(!*s) throw "unrecognized integer"; + intmax_t value = 0, x = *s, y = *(s + 1); + + //hexadecimal + if(x == '0' && (y == 'X' || y == 'x')) { + s += 2; + while(true) { + if(*s >= '0' && *s <= '9') { value = value * 16 + (*s++ - '0'); continue; } + if(*s >= 'A' && *s <= 'F') { value = value * 16 + (*s++ - 'A' + 10); continue; } + if(*s >= 'a' && *s <= 'f') { value = value * 16 + (*s++ - 'a' + 10); continue; } + return value; + } + } + + //binary + if(x == '0' && (y == 'B' || y == 'b')) { + s += 2; + while(true) { + if(*s == '0' || *s == '1') { value = value * 2 + (*s++ - '0'); continue; } + return value; + } + } + + //octal (or decimal '0') + if(x == '0') { + s += 1; + while(true) { + if(*s >= '0' && *s <= '7') { value = value * 8 + (*s++ - '0'); continue; } + return value; + } + } + + //decimal + if(x >= '0' && x <= '9') { + while(true) { + if(*s >= '0' && *s <= '9') { value = value * 10 + (*s++ - '0'); continue; } + return value; + } + } + + //char + if(x == '\'' && y != '\'') { + s += 1; + while(true) { + value = value * 256 + *s++; + if(*s == '\'') { s += 1; return value; } + if(!*s) throw "mismatched char"; + } + } + + throw "unrecognized integer"; +} + +static intmax_t eval(const char *&s, int depth = 0) { + while(*s == ' ' || *s == '\t') s++; //trim whitespace + if(!*s) throw "unrecognized token"; + intmax_t value = 0, x = *s, y = *(s + 1); + + if(*s == '(') { + value = eval(++s, 1); + if(*s++ != ')') throw "mismatched group"; + } + + else if(x == '!') value = !eval(++s, 13); + else if(x == '~') value = ~eval(++s, 13); + else if(x == '+') value = +eval(++s, 13); + else if(x == '-') value = -eval(++s, 13); + + else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s); + + else if(eval_fallback) value = eval_fallback(s); //optional user-defined syntax parsing + + else throw "unrecognized token"; + + while(true) { + while(*s == ' ' || *s == '\t') s++; //trim whitespace + if(!*s) break; + x = *s, y = *(s + 1); + + if(depth >= 13) break; + if(x == '*') { value *= eval(++s, 13); continue; } + if(x == '/') { intmax_t result = eval(++s, 13); if(result == 0) throw "division by zero"; value /= result; continue; } + if(x == '%') { intmax_t result = eval(++s, 13); if(result == 0) throw "division by zero"; value %= result; continue; } + + if(depth >= 12) break; + if(x == '+') { value += eval(++s, 12); continue; } + if(x == '-') { value -= eval(++s, 12); continue; } + + if(depth >= 11) break; + if(x == '<' && y == '<') { value <<= eval(++++s, 11); continue; } + if(x == '>' && y == '>') { value >>= eval(++++s, 11); continue; } + + if(depth >= 10) break; + if(x == '<' && y == '=') { value = value <= eval(++++s, 10); continue; } + if(x == '>' && y == '=') { value = value >= eval(++++s, 10); continue; } + if(x == '<') { value = value < eval(++s, 10); continue; } + if(x == '>') { value = value > eval(++s, 10); continue; } + + if(depth >= 9) break; + if(x == '=' && y == '=') { value = value == eval(++++s, 9); continue; } + if(x == '!' && y == '=') { value = value != eval(++++s, 9); continue; } + + if(depth >= 8) break; + if(x == '&' && y != '&') { value = value & eval(++s, 8); continue; } + + if(depth >= 7) break; + if(x == '^' && y != '^') { value = value ^ eval(++s, 7); continue; } + + if(depth >= 6) break; + if(x == '|' && y != '|') { value = value | eval(++s, 6); continue; } + + if(depth >= 5) break; + if(x == '&' && y == '&') { value = eval(++++s, 5) && value; continue; } + + if(depth >= 4) break; + if(x == '^' && y == '^') { value = (!eval(++++s, 4) != !value); continue; } + + if(depth >= 3) break; + if(x == '|' && y == '|') { value = eval(++++s, 3) || value; continue; } + + if(x == '?') { + intmax_t lhs = eval(++s, 2); + if(*s != ':') throw "mismatched ternary"; + intmax_t rhs = eval(++s, 2); + value = value ? lhs : rhs; + continue; + } + if(depth >= 2) break; + + if(depth > 0 && x == ')') break; + + throw "unrecognized token"; + } + + return value; +} + +static bool eval(const char *s, intmax_t &result) { + try { + result = eval(s); + return true; + } catch(const char*) { + result = 0; + return false; + } +} + +} + +#endif diff --git a/bsnes/nall/string/math-floating-point.hpp b/bsnes/nall/string/math-floating-point.hpp new file mode 100755 index 00000000..85680aad --- /dev/null +++ b/bsnes/nall/string/math-floating-point.hpp @@ -0,0 +1,149 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace floatingpoint { + +static nall::function eval_fallback; + +static double eval_integer(const char *&s) { + if(!*s) throw "unrecognized integer"; + intmax_t value = 0, radix = 0, x = *s, y = *(s + 1); + + //hexadecimal + if(x == '0' && (y == 'X' || y == 'x')) { + s += 2; + while(true) { + if(*s >= '0' && *s <= '9') { value = value * 16 + (*s++ - '0'); continue; } + if(*s >= 'A' && *s <= 'F') { value = value * 16 + (*s++ - 'A' + 10); continue; } + if(*s >= 'a' && *s <= 'f') { value = value * 16 + (*s++ - 'a' + 10); continue; } + return value; + } + } + + //binary + if(x == '0' && (y == 'B' || y == 'b')) { + s += 2; + while(true) { + if(*s == '0' || *s == '1') { value = value * 2 + (*s++ - '0'); continue; } + return value; + } + } + + //octal (or decimal '0') + if(x == '0' && y != '.') { + s += 1; + while(true) { + if(*s >= '0' && *s <= '7') { value = value * 8 + (*s++ - '0'); continue; } + return value; + } + } + + //decimal + if(x >= '0' && x <= '9') { + while(true) { + if(*s >= '0' && *s <= '9') { value = value * 10 + (*s++ - '0'); continue; } + if(*s == '.') { s++; break; } + return value; + } + //floating-point + while(true) { + if(*s >= '0' && *s <= '9') { radix = radix * 10 + (*s++ - '0'); continue; } + return atof(nall::string{ nall::decimal(value), ".", nall::decimal(radix) }); + } + } + + //char + if(x == '\'' && y != '\'') { + s += 1; + while(true) { + value = value * 256 + *s++; + if(*s == '\'') { s += 1; return value; } + if(!*s) throw "mismatched char"; + } + } + + throw "unrecognized integer"; +} + +static double eval(const char *&s, int depth = 0) { + while(*s == ' ' || *s == '\t') s++; //trim whitespace + if(!*s) throw "unrecognized token"; + double value = 0, x = *s, y = *(s + 1); + + if(*s == '(') { + value = eval(++s, 1); + if(*s++ != ')') throw "mismatched group"; + } + + else if(x == '!') value = !eval(++s, 9); + else if(x == '+') value = +eval(++s, 9); + else if(x == '-') value = -eval(++s, 9); + + else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s); + + else if(eval_fallback) value = eval_fallback(s); //optional user-defined syntax parsing + + else throw "unrecognized token"; + + while(true) { + while(*s == ' ' || *s == '\t') s++; //trim whitespace + if(!*s) break; + x = *s, y = *(s + 1); + + if(depth >= 9) break; + if(x == '*') { value *= eval(++s, 9); continue; } + if(x == '/') { double result = eval(++s, 9); if(result == 0.0) throw "division by zero"; value /= result; continue; } + + if(depth >= 8) break; + if(x == '+') { value += eval(++s, 8); continue; } + if(x == '-') { value -= eval(++s, 8); continue; } + + if(depth >= 7) break; + if(x == '<' && y == '=') { value = value <= eval(++++s, 7); continue; } + if(x == '>' && y == '=') { value = value >= eval(++++s, 7); continue; } + if(x == '<') { value = value < eval(++s, 7); continue; } + if(x == '>') { value = value > eval(++s, 7); continue; } + + if(depth >= 6) break; + if(x == '=' && y == '=') { value = value == eval(++++s, 6); continue; } + if(x == '!' && y == '=') { value = value != eval(++++s, 6); continue; } + + if(depth >= 5) break; + if(x == '&' && y == '&') { value = eval(++++s, 5) && value; continue; } + + if(depth >= 4) break; + if(x == '^' && y == '^') { value = (!eval(++++s, 4) != !value); continue; } + + if(depth >= 3) break; + if(x == '|' && y == '|') { value = eval(++++s, 3) || value; continue; } + + if(x == '?') { + double lhs = eval(++s, 2); + if(*s != ':') throw "mismatched ternary"; + double rhs = eval(++s, 2); + value = value ? lhs : rhs; + continue; + } + if(depth >= 2) break; + + if(depth > 0 && x == ')') break; + + throw "unrecognized token"; + } + + return value; +} + +static bool eval(const char *s, double &result) { + try { + result = eval(s); + return true; + } catch(const char*e) { +printf("%s\n", e); + result = 0; + return false; + } +} + +} + +#endif diff --git a/bsnes/nall/string/utility.hpp b/bsnes/nall/string/utility.hpp index e5aa0d11..2212688b 100755 --- a/bsnes/nall/string/utility.hpp +++ b/bsnes/nall/string/utility.hpp @@ -253,9 +253,14 @@ template string binary(uintmax_t value) { //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 fp(char *str, double value) { +unsigned fp(char *str, long double value) { char buffer[256]; - sprintf(buffer, "%f", value); + #ifdef _WIN32 + //Windows C-runtime does not support long double via sprintf() + sprintf(buffer, "%f", (double)value); + #else + sprintf(buffer, "%Lf", value); + #endif //remove excess 0's in fraction (2.500000 -> 2.5) for(char *p = buffer; *p; p++) { @@ -274,7 +279,7 @@ unsigned fp(char *str, double value) { return length + 1; } -string fp(double value) { +string fp(long double value) { string temp; temp.reserve(fp(0, value)); fp(temp(), value); diff --git a/bsnes/nes/input/input.cpp b/bsnes/nes/input/input.cpp index d85fc93d..c1fd7de1 100755 --- a/bsnes/nes/input/input.cpp +++ b/bsnes/nes/input/input.cpp @@ -42,7 +42,6 @@ void Input::connect(bool port, Device device) { } void Input::power() { - reset(); } void Input::reset() { diff --git a/bsnes/nes/scheduler/scheduler.cpp b/bsnes/nes/scheduler/scheduler.cpp index eca5857d..9beca699 100755 --- a/bsnes/nes/scheduler/scheduler.cpp +++ b/bsnes/nes/scheduler/scheduler.cpp @@ -16,7 +16,6 @@ void Scheduler::exit(ExitReason reason) { } void Scheduler::power() { - reset(); } void Scheduler::reset() { diff --git a/bsnes/phoenix/core/core.cpp b/bsnes/phoenix/core/core.cpp index 0426ba10..fb21bdf4 100755 --- a/bsnes/phoenix/core/core.cpp +++ b/bsnes/phoenix/core/core.cpp @@ -27,85 +27,6 @@ Font::Font(const string &description): description(description) { } -//Image -//===== - -bool Image::load(const string &filename, const Color &alpha) { - if(data) { delete[] data; data = nullptr; } - - file fp; - if(fp.open(filename, file::mode::read) == false) return false; - uint8_t d0 = fp.read(); - uint8_t d1 = fp.read(); - uint8_t d2 = fp.read(); - uint8_t d3 = fp.read(); - fp.close(); - - if(d0 == 'B' && d1 == 'M') { - bmp::read(filename, data, width, height); - } - - if(d0 == 0x89 && d1 == 'P' && d2 == 'N' && d3 == 'G') { - png image; - if(image.decode(filename)) { - image.alphaTransform((alpha.red << 16) + (alpha.green << 8) + (alpha.blue << 0)); - width = image.info.width, height = image.info.height; - data = new uint32_t[width * height]; - memcpy(data, image.data, width * height * sizeof(uint32_t)); - } - } - - return data; -} - -void Image::load(const uint32_t *data, const Size &size) { - if(data) { delete[] data; data = nullptr; } - width = size.width, height = size.height; - this->data = new uint32_t[width * height]; - memcpy(this->data, data, width * height * sizeof(uint32_t)); -} - -Image& Image::operator=(const Image &source) { - if(this == &source) return *this; - if(data) { delete[] data; data = nullptr; } - if(source.data == nullptr) return *this; - width = source.width, height = source.height; - data = new uint32_t[width * height]; - memcpy(data, source.data, width * height * sizeof(uint32_t)); - return *this; -} - -Image& Image::operator=(Image &&source) { - if(this == &source) return *this; - if(data) { delete[] data; data = nullptr; } - data = source.data, width = source.width, height = source.height; - source.data = nullptr; - return *this; -} - -Image::Image() : data(nullptr) { -} - -Image::Image(const string &filename, const Color &alpha) : data(nullptr) { - load(filename, alpha); -} - -Image::Image(const uint32_t *data, const Size &size) { - load(data, size); -} - -Image::Image(const Image &source) : data(nullptr) { - operator=(source); -} - -Image::Image(Image &&source) : data(nullptr) { - operator=(std::forward(source)); -} - -Image::~Image() { - if(data) delete[] data; -} - //Object //====== @@ -739,7 +660,7 @@ uint32_t* Canvas::data() { return state.data; } -bool Canvas::setImage(const Image &image) { +bool Canvas::setImage(const nall::image &image) { if(image.data == nullptr || image.width == 0 || image.height == 0) return false; state.width = image.width; state.height = image.height; diff --git a/bsnes/phoenix/core/core.hpp b/bsnes/phoenix/core/core.hpp index d75b1efc..5d419112 100755 --- a/bsnes/phoenix/core/core.hpp +++ b/bsnes/phoenix/core/core.hpp @@ -72,21 +72,6 @@ struct Font { Font(const nall::string &description = ""); }; -struct Image { - uint32_t *data; - unsigned width, height; - bool load(const nall::string &filename, const Color &alpha = Color{255, 255, 255}); - void load(const uint32_t *data, const Size &size); - Image& operator=(const Image &source); - Image& operator=(Image &&source); - Image(); - Image(const nall::string &filename, const Color &alpha = Color{255, 255, 255}); - Image(const uint32_t *data, const Size &size); - Image(const Image &source); - Image(Image &&source); - ~Image(); -}; - struct Object { Object(pObject &p); Object& operator=(const Object&) = delete; @@ -330,7 +315,7 @@ struct Button : private nall::base_from_member, Widget { struct Canvas : private nall::base_from_member, Widget { uint32_t* data(); - bool setImage(const Image &image); + bool setImage(const nall::image &image); void setSize(const Size &size); Size size(); void update(); diff --git a/bsnes/phoenix/gtk/widget/hex-edit.cpp b/bsnes/phoenix/gtk/widget/hex-edit.cpp index 9187d33f..9c0dbdef 100755 --- a/bsnes/phoenix/gtk/widget/hex-edit.cpp +++ b/bsnes/phoenix/gtk/widget/hex-edit.cpp @@ -130,17 +130,17 @@ bool pHexEdit::keyPress(unsigned scancode) { unsigned cursorY = position / lineWidth; unsigned cursorX = position % lineWidth; - if(scancode == GDK_KEY_Home) { + if(scancode == GDK_Home) { setCursorPosition(cursorY * lineWidth + 10); return true; } - if(scancode == GDK_KEY_End) { + if(scancode == GDK_End) { setCursorPosition(cursorY * lineWidth + 10 + (hexEdit.state.columns * 3 - 1)); return true; } - if(scancode == GDK_KEY_Up) { + if(scancode == GDK_Up) { if(cursorY != 0) return false; signed newOffset = hexEdit.state.offset - hexEdit.state.columns; @@ -151,7 +151,7 @@ bool pHexEdit::keyPress(unsigned scancode) { return true; } - if(scancode == GDK_KEY_Down) { + if(scancode == GDK_Down) { if(cursorY != hexEdit.state.rows - 1) return false; signed newOffset = hexEdit.state.offset + hexEdit.state.columns; @@ -162,7 +162,7 @@ bool pHexEdit::keyPress(unsigned scancode) { return true; } - if(scancode == GDK_KEY_Page_Up) { + if(scancode == GDK_Page_Up) { signed newOffset = hexEdit.state.offset - hexEdit.state.columns * hexEdit.state.rows; if(newOffset >= 0) { hexEdit.setOffset(newOffset); @@ -173,7 +173,7 @@ bool pHexEdit::keyPress(unsigned scancode) { return true; } - if(scancode == GDK_KEY_Page_Down) { + if(scancode == GDK_Page_Down) { signed newOffset = hexEdit.state.offset + hexEdit.state.columns * hexEdit.state.rows; for(unsigned n = 0; n < hexEdit.state.rows; n++) { if(newOffset + hexEdit.state.columns * hexEdit.state.rows - (hexEdit.state.columns - 1) <= hexEdit.state.length) { diff --git a/bsnes/phoenix/phoenix.hpp b/bsnes/phoenix/phoenix.hpp index 24ffa185..543ff18b 100755 --- a/bsnes/phoenix/phoenix.hpp +++ b/bsnes/phoenix/phoenix.hpp @@ -2,10 +2,9 @@ #define PHOENIX_HPP #include -#include #include #include -#include +#include #include #include #include diff --git a/bsnes/phoenix/qt/platform.moc b/bsnes/phoenix/qt/platform.moc index b542700e..9df32e50 100755 --- a/bsnes/phoenix/qt/platform.moc +++ b/bsnes/phoenix/qt/platform.moc @@ -1,8 +1,8 @@ /**************************************************************************** ** Meta object code from reading C++ file 'platform.moc.hpp' ** -** Created: Wed Nov 9 02:07:41 2011 -** by: The Qt Meta Object Compiler version 62 (Qt 4.7.0) +** Created: Tue Nov 29 20:27:15 2011 +** by: The Qt Meta Object Compiler version 62 (Qt 4.6.3) ** ** WARNING! All changes made in this file will be lost! *****************************************************************************/ @@ -10,7 +10,7 @@ #if !defined(Q_MOC_OUTPUT_REVISION) #error "The header file 'platform.moc.hpp' doesn't include ." #elif Q_MOC_OUTPUT_REVISION != 62 -#error "This file was generated using the moc from 4.7.0. It" +#error "This file was generated using the moc from 4.6.3. 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_pTimer[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 1, 14, // methods @@ -80,7 +80,7 @@ int pTimer::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pWindow[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 0, 0, // methods @@ -131,7 +131,7 @@ int pWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pItem[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 1, 14, // methods @@ -192,7 +192,7 @@ int pItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pCheckItem[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 1, 14, // methods @@ -253,7 +253,7 @@ int pCheckItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pRadioItem[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 1, 14, // methods @@ -314,7 +314,7 @@ int pRadioItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pButton[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 1, 14, // methods @@ -375,7 +375,7 @@ int pButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pCanvas[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 0, 0, // methods @@ -426,7 +426,7 @@ int pCanvas::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pCheckBox[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 1, 14, // methods @@ -487,7 +487,7 @@ int pCheckBox::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pComboBox[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 1, 14, // methods @@ -548,7 +548,7 @@ int pComboBox::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pHexEdit[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 1, 14, // methods @@ -609,7 +609,7 @@ int pHexEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pHorizontalScrollBar[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 1, 14, // methods @@ -670,7 +670,7 @@ int pHorizontalScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pHorizontalSlider[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 1, 14, // methods @@ -731,7 +731,7 @@ int pHorizontalSlider::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pLineEdit[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 2, 14, // methods @@ -794,7 +794,7 @@ int pLineEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pListView[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 3, 14, // methods @@ -861,7 +861,7 @@ int pListView::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pRadioBox[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 1, 14, // methods @@ -922,7 +922,7 @@ int pRadioBox::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pTextEdit[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 1, 14, // methods @@ -983,7 +983,7 @@ int pTextEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pVerticalScrollBar[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 1, 14, // methods @@ -1044,7 +1044,7 @@ int pVerticalScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void **_a) static const uint qt_meta_data_pVerticalSlider[] = { // content: - 5, // revision + 4, // revision 0, // classname 0, 0, // classinfo 1, 14, // methods diff --git a/bsnes/phoenix/qt/widget/canvas.cpp b/bsnes/phoenix/qt/widget/canvas.cpp index 4adc54e5..560e43a3 100755 --- a/bsnes/phoenix/qt/widget/canvas.cpp +++ b/bsnes/phoenix/qt/widget/canvas.cpp @@ -1,6 +1,6 @@ void pCanvas::setSize(const Size &size) { delete qtImage; - qtImage = new QImage(size.width, size.height, QImage::Format_RGB32); + qtImage = new QImage(size.width, size.height, QImage::Format_ARGB32); } void pCanvas::update() { @@ -10,7 +10,7 @@ void pCanvas::update() { void pCanvas::constructor() { qtWidget = qtCanvas = new QtCanvas(*this); - qtImage = new QImage(canvas.state.width, canvas.state.height, QImage::Format_RGB32); + qtImage = new QImage(canvas.state.width, canvas.state.height, QImage::Format_ARGB32); memcpy(qtImage->bits(), canvas.state.data, canvas.state.width * canvas.state.height * sizeof(uint32_t)); pWidget::synchronizeState(); diff --git a/bsnes/ruby/audio.hpp b/bsnes/ruby/audio.hpp index 45ae96ef..b28ed6d0 100755 --- a/bsnes/ruby/audio.hpp +++ b/bsnes/ruby/audio.hpp @@ -1,5 +1,4 @@ -class Audio { -public: +struct Audio { static const char *Handle; static const char *Synchronize; static const char *Frequency; diff --git a/bsnes/ruby/input.hpp b/bsnes/ruby/input.hpp index 5334c4da..827f9876 100755 --- a/bsnes/ruby/input.hpp +++ b/bsnes/ruby/input.hpp @@ -1,5 +1,4 @@ -class Input { -public: +struct Input { static const char *Handle; static const char *KeyboardSupport; static const char *MouseSupport; diff --git a/bsnes/ruby/ruby.cpp b/bsnes/ruby/ruby.cpp index 1a002006..0e142882 100755 --- a/bsnes/ruby/ruby.cpp +++ b/bsnes/ruby/ruby.cpp @@ -14,6 +14,7 @@ InputInterface input; const char *Video::Handle = "Handle"; const char *Video::Synchronize = "Synchronize"; +const char *Video::Depth = "Depth"; const char *Video::Filter = "Filter"; const char *Video::Shader = "Shader"; const char *Video::FragmentShader = "FragmentShader"; @@ -58,6 +59,10 @@ void VideoInterface::driver(const char *driver) { else if(!strcmp(driver, "OpenGL")) p = new VideoWGL(); #endif + #ifdef VIDEO_XSHM + else if(!strcmp(driver, "XShm")) p = new VideoXShm(); + #endif + #ifdef VIDEO_XV else if(!strcmp(driver, "X-Video")) p = new VideoXv(); #endif @@ -75,6 +80,8 @@ const char* VideoInterface::default_driver() { return "DirectDraw"; #elif defined(VIDEO_GDI) return "GDI"; + #elif defined(VIDEO_XSHM) + return "XShm"; #elif defined(VIDEO_QTOPENGL) return "Qt-OpenGL"; #elif defined(VIDEO_QTRASTER) @@ -126,6 +133,10 @@ const char* VideoInterface::driver_list() { "X-Video;" #endif + #if defined(VIDEO_XSHM) + "XShm;" + #endif + #if defined(VIDEO_QTRASTER) "Qt-Raster;" #endif diff --git a/bsnes/ruby/ruby.hpp b/bsnes/ruby/ruby.hpp index a8b08227..e0d5a690 100755 --- a/bsnes/ruby/ruby.hpp +++ b/bsnes/ruby/ruby.hpp @@ -1,6 +1,6 @@ /* ruby - version: 0.07 (2011-08-14) + version: 0.08 (2011-11-25) license: public domain */ diff --git a/bsnes/ruby/ruby_impl.cpp b/bsnes/ruby/ruby_impl.cpp index aca0e7af..d4b6c19e 100755 --- a/bsnes/ruby/ruby_impl.cpp +++ b/bsnes/ruby/ruby_impl.cpp @@ -82,6 +82,10 @@ using namespace nall; #include #endif +#ifdef VIDEO_XSHM + #include +#endif + #ifdef VIDEO_XV #include #endif diff --git a/bsnes/ruby/video.hpp b/bsnes/ruby/video.hpp index c79c5531..b71970c3 100755 --- a/bsnes/ruby/video.hpp +++ b/bsnes/ruby/video.hpp @@ -1,7 +1,7 @@ -class Video { -public: +struct Video { static const char *Handle; static const char *Synchronize; + static const char *Depth; static const char *Filter; static const char *Shader; static const char *FragmentShader; diff --git a/bsnes/ruby/video/glx.cpp b/bsnes/ruby/video/glx.cpp index 661703f0..40c9e038 100755 --- a/bsnes/ruby/video/glx.cpp +++ b/bsnes/ruby/video/glx.cpp @@ -27,11 +27,6 @@ namespace ruby { -//returns true once window is mapped (created and displayed onscreen) -static Bool glx_wait_for_map_notify(Display *d, XEvent *e, char *arg) { - return (e->type == MapNotify) && (e->xmap.window == (Window)arg); -} - class pVideoGLX : public OpenGL { public: int (*glSwapInterval)(int); @@ -52,15 +47,18 @@ public: struct { Window handle; bool synchronize; + unsigned depth; unsigned filter; unsigned width; unsigned height; + unsigned format; } settings; bool cap(const string& name) { if(name == Video::Handle) return true; if(name == Video::Synchronize) return true; + if(name == Video::Depth) return true; if(name == Video::Filter) return true; if(name == Video::Shader) return true; if(name == Video::FragmentShader) return true; @@ -71,6 +69,7 @@ public: any get(const string& name) { if(name == Video::Handle) return (uintptr_t)settings.handle; if(name == Video::Synchronize) return settings.synchronize; + if(name == Video::Depth) return settings.depth; if(name == Video::Filter) return settings.filter; return false; } @@ -89,6 +88,19 @@ public: } } + if(name == Video::Depth) { + unsigned depth = any_cast(value); + switch(depth) { + case 15u: ibpp = 2; iformat = GL_UNSIGNED_SHORT_1_5_5_5_REV; break; + case 16u: ibpp = 2; iformat = GL_UNSIGNED_SHORT_5_6_5_REV; break; + case 24u: ibpp = 4; iformat = GL_UNSIGNED_INT_8_8_8_8_REV; break; + case 30u: ibpp = 4; iformat = GL_UNSIGNED_INT_2_10_10_10_REV; break; + default: return false; + } + settings.depth = depth; + return true; + } + if(name == Video::Filter) { settings.filter = any_cast(value); return true; @@ -159,8 +171,21 @@ public: //let GLX determine the best Visual to use for GL output; provide a few hints //note: some video drivers will override double buffering attribute - int attributelist[] = { GLX_RGBA, GLX_DOUBLEBUFFER, None }; - XVisualInfo *vi = glXChooseVisual(display, screen, attributelist); + int attributeList[] = { + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DOUBLEBUFFER, True, + GLX_RED_SIZE, (settings.depth / 3), + GLX_GREEN_SIZE, (settings.depth / 3) + (settings.depth % 3), + GLX_BLUE_SIZE, (settings.depth / 3), + None, + }; + + int fbCount; + GLXFBConfig *fbConfig = glXChooseFBConfig(display, screen, attributeList, &fbCount); + if(fbCount == 0) return false; + + XVisualInfo *vi = glXGetVisualFromFBConfig(display, fbConfig[0]); //Window settings.handle has already been realized, most likely with DefaultVisual. //GLX requires that the GL output window has the same Visual as the GLX context. @@ -170,16 +195,19 @@ public: XSetWindowAttributes attributes; attributes.colormap = colormap; attributes.border_pixel = 0; - attributes.event_mask = StructureNotifyMask; xwindow = XCreateWindow(display, /* parent = */ settings.handle, /* x = */ 0, /* y = */ 0, window_attributes.width, window_attributes.height, /* border_width = */ 0, vi->depth, InputOutput, vi->visual, - CWColormap | CWBorderPixel | CWEventMask, &attributes); + CWColormap | CWBorderPixel, &attributes); XSetWindowBackground(display, xwindow, /* color = */ 0); XMapWindow(display, xwindow); - XEvent event; + XFlush(display); + //window must be realized (appear onscreen) before we make the context current - XIfEvent(display, &event, glx_wait_for_map_notify, (char*)xwindow); + while(XPending(display)) { + XEvent event; + XNextEvent(display, &event); + } glxcontext = glXCreateContext(display, vi, /* sharelist = */ 0, /* direct = */ GL_TRUE); glXMakeCurrent(display, glxwindow = xwindow, glxcontext); @@ -224,6 +252,10 @@ public: pVideoGLX() : glSwapInterval(0) { settings.handle = 0; settings.synchronize = false; + settings.depth = 24u; + + iformat = GL_UNSIGNED_INT_8_8_8_8_REV; + ibpp = 4; xwindow = 0; colormap = 0; glxcontext = 0; diff --git a/bsnes/ruby/video/opengl.hpp b/bsnes/ruby/video/opengl.hpp index a606c752..e780d0fe 100755 --- a/bsnes/ruby/video/opengl.hpp +++ b/bsnes/ruby/video/opengl.hpp @@ -34,7 +34,7 @@ public: bool shader_support; uint32_t *buffer; - unsigned iwidth, iheight; + unsigned iwidth, iheight, iformat, ibpp; void resize(unsigned width, unsigned height) { if(gltexture == 0) glGenTextures(1, &gltexture); @@ -46,18 +46,18 @@ public: glBindTexture(GL_TEXTURE_2D, gltexture); glPixelStorei(GL_UNPACK_ROW_LENGTH, iwidth); glTexImage2D(GL_TEXTURE_2D, - /* mip-map level = */ 0, /* internal format = */ GL_RGBA, + /* mip-map level = */ 0, /* internal format = */ GL_RGB10_A2, iwidth, iheight, /* border = */ 0, /* format = */ GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8_REV, buffer); + iformat, buffer); } bool lock(uint32_t *&data, unsigned &pitch) { - pitch = iwidth * sizeof(uint32_t); + pitch = iwidth * ibpp; return data = buffer; } void clear() { - memset(buffer, 0, iwidth * iheight * sizeof(uint32_t)); + memset(buffer, 0, iwidth * iheight * ibpp); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glFlush(); @@ -96,7 +96,7 @@ public: glPixelStorei(GL_UNPACK_ROW_LENGTH, iwidth); glTexSubImage2D(GL_TEXTURE_2D, /* mip-map level = */ 0, /* x = */ 0, /* y = */ 0, - inwidth, inheight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer); + inwidth, inheight, GL_BGRA, iformat, buffer); //OpenGL projection sets 0,0 as *bottom-left* of screen. //therefore, below vertices flip image to support top-left source. diff --git a/bsnes/ruby/video/wgl.cpp b/bsnes/ruby/video/wgl.cpp index ce5d6be7..5d3765d0 100755 --- a/bsnes/ruby/video/wgl.cpp +++ b/bsnes/ruby/video/wgl.cpp @@ -141,6 +141,8 @@ public: settings.synchronize = false; settings.filter = 0; + iformat = GL_UNSIGNED_INT_8_8_8_8_REV; + ibpp = 4; window = 0; wglcontext = 0; glwindow = 0; diff --git a/bsnes/ruby/video/xshm.cpp b/bsnes/ruby/video/xshm.cpp new file mode 100755 index 00000000..35433b2a --- /dev/null +++ b/bsnes/ruby/video/xshm.cpp @@ -0,0 +1,170 @@ +#include +#include + +namespace ruby { + +struct pVideoXShm { + struct { + Display *display; + int screen; + Visual *visual; + int depth; + Window window; + + XShmSegmentInfo shmInfo; + XImage *image; + uint32_t *buffer; + unsigned width, height; + } device; + + struct { + uintptr_t handle; + + uint32_t *buffer; + unsigned width, height; + } settings; + + bool cap(const string &name) { + if(name == Video::Handle) return true; + return false; + } + + any get(const string& name) { + if(name == Video::Handle) return settings.handle; + } + + bool set(const string& name, const any& value) { + if(name == Video::Handle) { + settings.handle = any_cast(value); + return true; + } + return false; + } + + bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) { + if(settings.buffer == nullptr || settings.width != width || settings.height != height) { + if(settings.buffer) delete[] settings.buffer; + settings.width = width, settings.height = height; + settings.buffer = new uint32_t[width * height](); + } + + data = settings.buffer; + pitch = settings.width * sizeof(uint32_t); + return true; + } + + void unlock() { + } + + void clear() { + if(settings.buffer == nullptr) return; + memset(settings.buffer, 0, settings.width * settings.height * sizeof(uint32_t)); + refresh(); + } + + void refresh() { + if(settings.buffer == nullptr) return; + size(); + + float xRatio = (float)settings.width / (float)device.width; + float yRatio = (float)settings.height / (float)device.height; + float yStep = 0; + for(unsigned y = 0; y < device.height; y++) { + uint32_t *sp = settings.buffer + (unsigned)yStep * settings.width; + uint32_t *dp = device.buffer + y * device.width; + yStep += yRatio; + float xStep = 0; + for(unsigned x = 0; x < device.width; x++) { + uint32_t color = sp[(unsigned)xStep]; + xStep += xRatio; + *dp++ = ((color >> 20) & 0x000003ff) | ((color) & 0x000ffc00) | ((color << 20) & 0x3ff00000); + } + } + + GC gc = XCreateGC(device.display, device.window, 0, 0); + XShmPutImage( + device.display, device.window, gc, device.image, + 0, 0, 0, 0, device.width, device.height, False + ); + XFreeGC(device.display, gc); + XFlush(device.display); + } + + bool init() { + device.display = XOpenDisplay(0); + device.screen = DefaultScreen(device.display); + device.visual = DefaultVisual(device.display, device.screen); + device.depth = DefaultDepth(device.display, device.screen); + + XSetWindowAttributes attributes; + attributes.border_pixel = 0; + device.window = XCreateWindow(device.display, (Window)settings.handle, + 0, 0, 256, 256, + 0, device.depth, InputOutput, device.visual, + CWBorderPixel, &attributes + ); + XSetWindowBackground(device.display, device.window, 0); + XMapWindow(device.display, device.window); + XFlush(device.display); + + while(XPending(device.display)) { + XEvent event; + XNextEvent(device.display, &event); + } + + if(size() == false) return false; + return true; + } + + void term() { + free(); + } + + pVideoXShm() { + device.buffer = nullptr; + + settings.buffer = nullptr; + } + + ~pVideoXShm() { + term(); + } + +//internal: + bool size() { + XWindowAttributes windowAttributes; + XGetWindowAttributes(device.display, settings.handle, &windowAttributes); + + if(device.buffer && device.width == windowAttributes.width && device.height == windowAttributes.height) return true; + device.width = windowAttributes.width, device.height = windowAttributes.height; + XResizeWindow(device.display, device.window, device.width, device.height); + free(); + + //create + device.shmInfo.shmid = shmget(IPC_PRIVATE, device.width * device.height * sizeof(uint32_t), IPC_CREAT | 0777); + if(device.shmInfo.shmid < 0) return false; + + device.shmInfo.shmaddr = (char*)shmat(device.shmInfo.shmid, 0, 0); + device.shmInfo.readOnly = False; + XShmAttach(device.display, &device.shmInfo); + device.buffer = (uint32_t*)device.shmInfo.shmaddr; + device.image = XShmCreateImage(device.display, device.visual, device.depth, + ZPixmap, device.shmInfo.shmaddr, &device.shmInfo, device.width, device.height + ); + + return true; + } + + void free() { + if(device.buffer == nullptr) return; + device.buffer = nullptr; + XShmDetach(device.display, &device.shmInfo); + XDestroyImage(device.image); + shmdt(device.shmInfo.shmaddr); + shmctl(device.shmInfo.shmid, IPC_RMID, 0); + } +}; + +DeclareVideo(XShm) + +} diff --git a/bsnes/snes/Makefile b/bsnes/snes/Makefile index a1a3ef33..2b26fe25 100755 --- a/bsnes/snes/Makefile +++ b/bsnes/snes/Makefile @@ -26,12 +26,10 @@ else ifeq ($(profile),performance) snessmp := $(snes)/alt/smp snesdsp := $(snes)/alt/dsp snesppu := $(snes)/alt/ppu-performance -else - $(error Unknown profile: $(profile)) endif obj/snes-interface.o : $(snes)/interface/interface.cpp $(call rwildcard,$(snes)/interface) -obj/snes-system.o : $(snes)/system/system.cpp $(call rwildcard,$(snes)/system/) $(call rwildcard,$(snes)/video/) $(call rwildcard,$(snes)/audio/) $(call rwildcard,$(snes)/input/) +obj/snes-system.o : $(snes)/system/system.cpp $(call rwildcard,$(snes)/system/) obj/snes-controller.o: $(snes)/controller/controller.cpp $(call rwildcard,$(snes)/controller/) obj/snes-memory.o : $(snes)/memory/memory.cpp $(call rwildcard,$(snes)/memory/) obj/snes-cpucore.o : $(snes)/cpu/core/core.cpp $(call rwildcard,$(snes)/cpu/core/) diff --git a/bsnes/snes/alt/ppu-parallel/mmio.cpp b/bsnes/snes/alt/ppu-parallel/mmio.cpp new file mode 100755 index 00000000..8abfb74e --- /dev/null +++ b/bsnes/snes/alt/ppu-parallel/mmio.cpp @@ -0,0 +1,14 @@ +#ifdef PPU_CPP + +bool PPU::display_disable() const { return r[0x00] & 0x80; } +unsigned PPU::display_brightness() const { return r[0x00] & 0x0f; } + +uint8 PPU::mmio_read(unsigned addr) { + return cpu.regs.mdr; +} + +void PPU::mmio_write(unsigned addr, uint8 data) { + r[addr & 0x3f] = data; +} + +#endif diff --git a/bsnes/snes/alt/ppu-parallel/ppu.cpp b/bsnes/snes/alt/ppu-parallel/ppu.cpp new file mode 100755 index 00000000..1c3dcb70 --- /dev/null +++ b/bsnes/snes/alt/ppu-parallel/ppu.cpp @@ -0,0 +1,81 @@ +#include + +#define PPU_CPP +namespace SNES { + +#include "mmio.cpp" +PPU ppu; + +void PPU::latch_counters() { +} + +bool PPU::interlace() const { + return false; +} + +bool PPU::overscan() const { + return false; +} + +bool PPU::hires() const { + return false; +} + +void PPU::enter() { + scanline(); + clock += lineclocks(); + tick(lineclocks()); +} + +void PPU::scanline() { + if(vcounter() == 0) return frame(); + if(vcounter() > 224) return; +} + +void PPU::frame() { +} + +void PPU::enable() { + bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, { &PPU::mmio_read, this }, { &PPU::mmio_write, this }); + bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, { &PPU::mmio_read, this }, { &PPU::mmio_write, this }); +} + +void PPU::power() { + for(unsigned n = 0; n < 512 * 480; n++) output[n] = rand() & ((1 << 19) - 1); + + for(auto &n : vram) n = 0; + for(auto &n : oam) n = 0; + for(auto &n : cgram) n = 0; + for(auto &n : r) n = 0; + reset(); +} + +void PPU::reset() { + PPUcounter::reset(); +} + +void PPUcounter::serialize(serializer &s) { + s.integer(status.interlace); + s.integer(status.field); + s.integer(status.vcounter); + s.integer(status.hcounter); + + s.array(history.field); + s.array(history.vcounter); + s.array(history.hcounter); + s.integer(history.index); +} + +void PPU::serialize(serializer &s) { +} + +PPU::PPU() { + surface = new uint32[512 * 512]; + output = surface + 16 * 512; +} + +PPU::~PPU() { + delete[] surface; +} + +} diff --git a/bsnes/snes/alt/ppu-parallel/ppu.hpp b/bsnes/snes/alt/ppu-parallel/ppu.hpp new file mode 100755 index 00000000..3a47d33d --- /dev/null +++ b/bsnes/snes/alt/ppu-parallel/ppu.hpp @@ -0,0 +1,40 @@ +struct PPU : public Processor, public PPUcounter { + uint8 vram[64 * 1024]; + uint8 oam[544]; + uint8 cgram[512]; + uint8 r[64]; + + enum : bool { Threaded = false }; + + void latch_counters(); + bool interlace() const; + bool overscan() const; + bool hires() const; + + void enter(); + void enable(); + void power(); + void reset(); + + void scanline(); + void frame(); + + void serialize(serializer&); + PPU(); + ~PPU(); + +private: + uint32 *surface; + uint32 *output; + + //mmio.cpp + alwaysinline bool display_disable() const; + alwaysinline unsigned display_brightness() const; + + uint8 mmio_read(unsigned addr); + void mmio_write(unsigned addr, uint8 data); + + friend class Video; +}; + +extern PPU ppu; diff --git a/bsnes/snes/chip/bsx/cartridge/cartridge.cpp b/bsnes/snes/chip/bsx/cartridge/cartridge.cpp index ade0f11d..f76682f0 100755 --- a/bsnes/snes/chip/bsx/cartridge/cartridge.cpp +++ b/bsnes/snes/chip/bsx/cartridge/cartridge.cpp @@ -19,7 +19,6 @@ void BSXCartridge::unload() { } void BSXCartridge::power() { - reset(); } void BSXCartridge::reset() { diff --git a/bsnes/snes/chip/bsx/flash/flash.cpp b/bsnes/snes/chip/bsx/flash/flash.cpp index 316f55c2..17b525b6 100755 --- a/bsnes/snes/chip/bsx/flash/flash.cpp +++ b/bsnes/snes/chip/bsx/flash/flash.cpp @@ -16,7 +16,6 @@ void BSXFlash::unload() { } void BSXFlash::power() { - reset(); } void BSXFlash::reset() { diff --git a/bsnes/snes/chip/bsx/satellaview/satellaview.cpp b/bsnes/snes/chip/bsx/satellaview/satellaview.cpp index 7bfd13fb..386fb628 100755 --- a/bsnes/snes/chip/bsx/satellaview/satellaview.cpp +++ b/bsnes/snes/chip/bsx/satellaview/satellaview.cpp @@ -14,7 +14,6 @@ void BSXSatellaview::unload() { } void BSXSatellaview::power() { - reset(); } void BSXSatellaview::reset() { diff --git a/bsnes/snes/chip/hitachidsp/hitachidsp.cpp b/bsnes/snes/chip/hitachidsp/hitachidsp.cpp index 62f4bfa2..1042267e 100755 --- a/bsnes/snes/chip/hitachidsp/hitachidsp.cpp +++ b/bsnes/snes/chip/hitachidsp/hitachidsp.cpp @@ -52,7 +52,6 @@ void HitachiDSP::unload() { } void HitachiDSP::power() { - reset(); } void HitachiDSP::reset() { diff --git a/bsnes/snes/chip/icd2/icd2.cpp b/bsnes/snes/chip/icd2/icd2.cpp index c8a82df3..e28769f4 100755 --- a/bsnes/snes/chip/icd2/icd2.cpp +++ b/bsnes/snes/chip/icd2/icd2.cpp @@ -41,8 +41,6 @@ void ICD2::unload() { void ICD2::power() { audio.coprocessor_enable(true); audio.coprocessor_frequency(4 * 1024 * 1024); - - reset(); } void ICD2::reset() { diff --git a/bsnes/snes/chip/link/link.cpp b/bsnes/snes/chip/link/link.cpp index a5736933..1891f72e 100755 --- a/bsnes/snes/chip/link/link.cpp +++ b/bsnes/snes/chip/link/link.cpp @@ -40,7 +40,6 @@ void Link::unload() { void Link::power() { if(link_power) link_power(); - create(Link::Enter, frequency); } void Link::reset() { diff --git a/bsnes/snes/chip/msu1/msu1.cpp b/bsnes/snes/chip/msu1/msu1.cpp index af19acea..71700e60 100755 --- a/bsnes/snes/chip/msu1/msu1.cpp +++ b/bsnes/snes/chip/msu1/msu1.cpp @@ -60,8 +60,6 @@ void MSU1::unload() { void MSU1::power() { audio.coprocessor_enable(true); audio.coprocessor_frequency(44100.0); - - reset(); } void MSU1::reset() { @@ -78,60 +76,39 @@ void MSU1::reset() { } uint8 MSU1::mmio_read(unsigned addr) { - addr &= 0xffff; - - if(addr == 0x2000) { + switch(addr & 7) { + case 0: return (mmio.data_busy << 7) | (mmio.audio_busy << 6) | (mmio.audio_repeat << 5) | (mmio.audio_play << 4) | (Revision << 0); - } - - if(addr == 0x2001) { + case 1: if(mmio.data_busy) return 0x00; mmio.data_offset++; if(datafile.open()) return datafile.read(); return 0x00; + case 2: return 'S'; + case 3: return '-'; + case 4: return 'M'; + case 5: return 'S'; + case 6: return 'U'; + case 7: return '0' + Revision; } - - if(addr == 0x2002) return 'S'; - if(addr == 0x2003) return '-'; - if(addr == 0x2004) return 'M'; - if(addr == 0x2005) return 'S'; - if(addr == 0x2006) return 'U'; - if(addr == 0x2007) return '0' + Revision; - - return 0x00; + throw; } void MSU1::mmio_write(unsigned addr, uint8 data) { - addr &= 0xffff; - - if(addr == 0x2000) { - mmio.data_offset = (mmio.data_offset & 0xffffff00) | (data << 0); - } - - if(addr == 0x2001) { - mmio.data_offset = (mmio.data_offset & 0xffff00ff) | (data << 8); - } - - if(addr == 0x2002) { - mmio.data_offset = (mmio.data_offset & 0xff00ffff) | (data << 16); - } - - if(addr == 0x2003) { - mmio.data_offset = (mmio.data_offset & 0x00ffffff) | (data << 24); + switch(addr & 7) { + case 0: mmio.data_offset = (mmio.data_offset & 0xffffff00) | (data << 0); break; + case 1: mmio.data_offset = (mmio.data_offset & 0xffff00ff) | (data << 8); break; + case 2: mmio.data_offset = (mmio.data_offset & 0xff00ffff) | (data << 16); break; + case 3: mmio.data_offset = (mmio.data_offset & 0x00ffffff) | (data << 24); if(datafile.open()) datafile.seek(mmio.data_offset); mmio.data_busy = false; - } - - if(addr == 0x2004) { - mmio.audio_track = (mmio.audio_track & 0xff00) | (data << 0); - } - - if(addr == 0x2005) { - mmio.audio_track = (mmio.audio_track & 0x00ff) | (data << 8); + break; + case 4: mmio.audio_track = (mmio.audio_track & 0xff00) | (data << 0); + case 5: mmio.audio_track = (mmio.audio_track & 0x00ff) | (data << 8); if(audiofile.open()) audiofile.close(); if(audiofile.open(interface->path(Cartridge::Slot::Base, { "-", (unsigned)mmio.audio_track, ".pcm" }), file::mode::read)) { uint32 header = audiofile.readm(4); @@ -145,15 +122,14 @@ void MSU1::mmio_write(unsigned addr, uint8 data) { mmio.audio_busy = false; mmio.audio_repeat = false; mmio.audio_play = false; - } - - if(addr == 0x2006) { + break; + case 6: mmio.audio_volume = data; - } - - if(addr == 0x2007) { + break; + case 7: mmio.audio_repeat = data & 2; mmio.audio_play = data & 1; + break; } } diff --git a/bsnes/snes/chip/necdsp/necdsp.cpp b/bsnes/snes/chip/necdsp/necdsp.cpp index 0a07d1dc..04974a00 100755 --- a/bsnes/snes/chip/necdsp/necdsp.cpp +++ b/bsnes/snes/chip/necdsp/necdsp.cpp @@ -266,8 +266,6 @@ void NECDSP::power() { regs.rp.bits(11); regs.dp.bits(11); } - - reset(); } void NECDSP::reset() { diff --git a/bsnes/snes/chip/obc1/obc1.cpp b/bsnes/snes/chip/obc1/obc1.cpp index 6cfc11f3..8d7d3376 100755 --- a/bsnes/snes/chip/obc1/obc1.cpp +++ b/bsnes/snes/chip/obc1/obc1.cpp @@ -16,7 +16,6 @@ void OBC1::unload() { } void OBC1::power() { - reset(); } void OBC1::reset() { diff --git a/bsnes/snes/chip/sa1/sa1.cpp b/bsnes/snes/chip/sa1/sa1.cpp index 9620e4f9..71c6310a 100755 --- a/bsnes/snes/chip/sa1/sa1.cpp +++ b/bsnes/snes/chip/sa1/sa1.cpp @@ -128,7 +128,6 @@ void SA1::unload() { void SA1::power() { regs.a = regs.x = regs.y = 0x0000; regs.s = 0x01ff; - reset(); } void SA1::reset() { diff --git a/bsnes/snes/chip/sdd1/sdd1.cpp b/bsnes/snes/chip/sdd1/sdd1.cpp index 054f6e31..c9b8b1c4 100755 --- a/bsnes/snes/chip/sdd1/sdd1.cpp +++ b/bsnes/snes/chip/sdd1/sdd1.cpp @@ -22,7 +22,6 @@ void SDD1::unload() { } void SDD1::power() { - reset(); } void SDD1::reset() { diff --git a/bsnes/snes/chip/spc7110/spc7110.cpp b/bsnes/snes/chip/spc7110/spc7110.cpp index 835ddbb6..d2dc640b 100755 --- a/bsnes/snes/chip/spc7110/spc7110.cpp +++ b/bsnes/snes/chip/spc7110/spc7110.cpp @@ -22,7 +22,6 @@ void SPC7110::unload() { } void SPC7110::power() { - reset(); } void SPC7110::reset() { diff --git a/bsnes/snes/chip/srtc/srtc.cpp b/bsnes/snes/chip/srtc/srtc.cpp index 1dd8f86e..1b2fd2aa 100755 --- a/bsnes/snes/chip/srtc/srtc.cpp +++ b/bsnes/snes/chip/srtc/srtc.cpp @@ -21,7 +21,6 @@ void SRTC::unload() { } void SRTC::power() { - reset(); } void SRTC::reset() { diff --git a/bsnes/snes/chip/st0018/st0018.cpp b/bsnes/snes/chip/st0018/st0018.cpp index aefb278b..ee13e385 100755 --- a/bsnes/snes/chip/st0018/st0018.cpp +++ b/bsnes/snes/chip/st0018/st0018.cpp @@ -55,7 +55,6 @@ void ST0018::unload() { } void ST0018::power() { - reset(); } void ST0018::reset() { diff --git a/bsnes/snes/chip/superfx/superfx.cpp b/bsnes/snes/chip/superfx/superfx.cpp index fba0ff25..52060fa2 100755 --- a/bsnes/snes/chip/superfx/superfx.cpp +++ b/bsnes/snes/chip/superfx/superfx.cpp @@ -51,7 +51,6 @@ void SuperFX::unload() { void SuperFX::power() { clockmode = config.superfx.speed; - reset(); } void SuperFX::reset() { diff --git a/bsnes/snes/config/config.cpp b/bsnes/snes/config/config.cpp index 3fcb72e0..701af94c 100755 --- a/bsnes/snes/config/config.cpp +++ b/bsnes/snes/config/config.cpp @@ -7,7 +7,7 @@ Configuration::Configuration() { controller_port2 = Input::Device::Joypad; expansion_port = System::ExpansionPortDevice::BSX; region = System::Region::Autodetect; - random = false; //true; + random = true; cpu.version = 2; cpu.ntsc_frequency = 21477272; //315 / 88 * 6000000 diff --git a/bsnes/snes/cpu/cpu.cpp b/bsnes/snes/cpu/cpu.cpp index 4e83429f..f6ae9754 100755 --- a/bsnes/snes/cpu/cpu.cpp +++ b/bsnes/snes/cpu/cpu.cpp @@ -125,8 +125,6 @@ void CPU::power() { mmio_power(); dma_power(); timing_power(); - - reset(); } void CPU::reset() { diff --git a/bsnes/snes/dsp/dsp.cpp b/bsnes/snes/dsp/dsp.cpp index 4811269b..cd8818c6 100755 --- a/bsnes/snes/dsp/dsp.cpp +++ b/bsnes/snes/dsp/dsp.cpp @@ -274,8 +274,6 @@ void DSP::power() { voice[i].t_envx_out = 0; voice[i].hidden_env = 0; } - - reset(); } void DSP::reset() { diff --git a/bsnes/snes/ppu/ppu.cpp b/bsnes/snes/ppu/ppu.cpp index ec213664..8545175f 100755 --- a/bsnes/snes/ppu/ppu.cpp +++ b/bsnes/snes/ppu/ppu.cpp @@ -98,8 +98,6 @@ void PPU::power() { for(auto &n : vram) n = random(0x00); for(auto &n : oam) n = random(0x00); for(auto &n : cgram) n = random(0x00); - - reset(); } void PPU::reset() { diff --git a/bsnes/snes/smp/core/algorithms.cpp b/bsnes/snes/smp/core/algorithms.cpp index cbc31bea..69504cdf 100755 --- a/bsnes/snes/smp/core/algorithms.cpp +++ b/bsnes/snes/smp/core/algorithms.cpp @@ -94,13 +94,7 @@ uint8 SMPcore::op_ror(uint8 x) { } uint8 SMPcore::op_sbc(uint8 x, uint8 y) { - int r = x - y - !regs.p.c; - regs.p.n = r & 0x80; - regs.p.v = (x ^ y) & (x ^ r) & 0x80; - regs.p.h = !((x ^ y ^ r) & 0x10); - regs.p.z = (uint8)r == 0; - regs.p.c = r >= 0; - return r; + return op_adc(x, ~y); } uint8 SMPcore::op_st(uint8 x, uint8 y) { diff --git a/bsnes/snes/smp/core/registers.hpp b/bsnes/snes/smp/core/registers.hpp index 8a4916fc..48aa92c8 100755 --- a/bsnes/snes/smp/core/registers.hpp +++ b/bsnes/snes/smp/core/registers.hpp @@ -24,18 +24,20 @@ struct word_t { }; inline operator unsigned() const { return w; } - inline unsigned operator=(unsigned data) { w = data; return w; } + inline unsigned operator=(unsigned data) { return w = data; } inline unsigned operator++() { return ++w; } inline unsigned operator--() { return --w; } + inline unsigned operator++(int) { unsigned data = w++; return data; } inline unsigned operator--(int) { unsigned data = w--; return data; } - inline unsigned operator|=(unsigned data) { w |= data; return w; } - inline unsigned operator^=(unsigned data) { w ^= data; return w; } - inline unsigned operator&=(unsigned data) { w &= data; return w; } - inline unsigned operator+=(unsigned data) { w += data; return w; } - inline unsigned operator-=(unsigned data) { w -= data; return w; } + inline unsigned operator+=(unsigned data) { return w += data;; } + inline unsigned operator-=(unsigned data) { return w -= data;; } + + inline unsigned operator|=(unsigned data) { return w |= data; } + inline unsigned operator^=(unsigned data) { return w ^= data; } + inline unsigned operator&=(unsigned data) { return w &= data; } }; struct regs_t { diff --git a/bsnes/snes/smp/smp.cpp b/bsnes/snes/smp/smp.cpp index d01f6ffc..90806245 100755 --- a/bsnes/snes/smp/smp.cpp +++ b/bsnes/snes/smp/smp.cpp @@ -53,8 +53,6 @@ void SMP::power() { timer0.target = 0; timer1.target = 0; timer2.target = 0; - - reset(); } void SMP::reset() { diff --git a/bsnes/snes/audio/audio.cpp b/bsnes/snes/system/audio.cpp similarity index 100% rename from bsnes/snes/audio/audio.cpp rename to bsnes/snes/system/audio.cpp diff --git a/bsnes/snes/audio/audio.hpp b/bsnes/snes/system/audio.hpp similarity index 100% rename from bsnes/snes/audio/audio.hpp rename to bsnes/snes/system/audio.hpp diff --git a/bsnes/snes/input/input.cpp b/bsnes/snes/system/input.cpp similarity index 100% rename from bsnes/snes/input/input.cpp rename to bsnes/snes/system/input.cpp diff --git a/bsnes/snes/input/input.hpp b/bsnes/snes/system/input.hpp similarity index 100% rename from bsnes/snes/input/input.hpp rename to bsnes/snes/system/input.hpp diff --git a/bsnes/snes/system/system.cpp b/bsnes/snes/system/system.cpp index 68818109..c19a7c51 100755 --- a/bsnes/snes/system/system.cpp +++ b/bsnes/snes/system/system.cpp @@ -10,10 +10,9 @@ System system; #include #include -#include -#include -#include - +#include "video.cpp" +#include "audio.cpp" +#include "input.cpp" #include "serialization.cpp" void System::run() { @@ -181,17 +180,7 @@ void System::power() { if(cartridge.has_msu1()) msu1.power(); if(cartridge.has_link()) link.power(); - if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&icd2); - if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx); - if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1); - if(cartridge.has_necdsp()) cpu.coprocessors.append(&necdsp); - if(cartridge.has_hitachidsp()) cpu.coprocessors.append(&hitachidsp); - if(cartridge.has_msu1()) cpu.coprocessors.append(&msu1); - if(cartridge.has_link()) cpu.coprocessors.append(&link); - - scheduler.init(); - input.connect(0, config.controller_port1); - input.connect(1, config.controller_port2); + reset(); } void System::reset() { diff --git a/bsnes/snes/system/system.hpp b/bsnes/snes/system/system.hpp index 3d8d6e77..f5046e35 100755 --- a/bsnes/snes/system/system.hpp +++ b/bsnes/snes/system/system.hpp @@ -42,9 +42,9 @@ private: friend class Input; }; -#include -#include -#include +#include "video.hpp" +#include "audio.hpp" +#include "input.hpp" #include #include diff --git a/bsnes/snes/video/video.cpp b/bsnes/snes/system/video.cpp similarity index 100% rename from bsnes/snes/video/video.cpp rename to bsnes/snes/system/video.cpp diff --git a/bsnes/snes/video/video.hpp b/bsnes/snes/system/video.hpp similarity index 100% rename from bsnes/snes/video/video.hpp rename to bsnes/snes/system/video.hpp diff --git a/bsnes/ui/config/config.cpp b/bsnes/ui/config/config.cpp index d8f46b62..2d8e5579 100755 --- a/bsnes/ui/config/config.cpp +++ b/bsnes/ui/config/config.cpp @@ -3,6 +3,7 @@ Config *config = 0; Config::Config() { attach(video.driver = "", "Video::Driver"); + attach(video.depth = 24u, "Video::Depth"); attach(video.filter = "None", "Video::Filter"); attach(video.shader = "Blur", "Video::Shader"); attach(video.synchronize = true, "Video::Synchronize"); diff --git a/bsnes/ui/config/config.hpp b/bsnes/ui/config/config.hpp index a20041bd..71e8881f 100755 --- a/bsnes/ui/config/config.hpp +++ b/bsnes/ui/config/config.hpp @@ -1,8 +1,11 @@ struct Config : public configuration { struct Video { string driver; + unsigned depth; + string filter; string shader; + bool synchronize; bool correctAspectRatio; diff --git a/bsnes/ui/interface/gameboy/gameboy.cpp b/bsnes/ui/interface/gameboy/gameboy.cpp index dc26ec6e..f9282d23 100755 --- a/bsnes/ui/interface/gameboy/gameboy.cpp +++ b/bsnes/ui/interface/gameboy/gameboy.cpp @@ -28,7 +28,7 @@ bool InterfaceGameBoy::loadCartridge(GameBoy::System::Revision revision, const s } GameBoy::interface = this; - GameBoy::video.generate(GameBoy::Video::Format::RGB24); + GameBoy::video.generate(GameBoy::Video::Format::RGB30); interface->loadCartridge(::Interface::Mode::GameBoy); return true; } diff --git a/bsnes/ui/interface/interface.cpp b/bsnes/ui/interface/interface.cpp index 3c714e97..bae5cb61 100755 --- a/bsnes/ui/interface/interface.cpp +++ b/bsnes/ui/interface/interface.cpp @@ -231,7 +231,7 @@ void Interface::videoRefresh(const uint32_t *input, unsigned inputPitch, unsigne uint32_t *dp = output + y * outputPitch; for(unsigned x = 0; x < width; x++) { uint32_t color = *sp++; - *dp++ = (palette[color >> 16] << 16) + (palette[color >> 8] << 8) + (palette[color >> 0] << 0); + *dp++ = palette((color >> 20) & 1023, (color >> 10) & 1023, (color >> 0) & 1023); } } diff --git a/bsnes/ui/interface/nes/nes.cpp b/bsnes/ui/interface/nes/nes.cpp index 611656d8..e8c50963 100755 --- a/bsnes/ui/interface/nes/nes.cpp +++ b/bsnes/ui/interface/nes/nes.cpp @@ -45,7 +45,7 @@ bool InterfaceNES::loadCartridge(const string &filename) { } interface->loadCartridge(::Interface::Mode::NES); - NES::video.generate(NES::Video::Format::RGB24); + NES::video.generate(NES::Video::Format::RGB30); return true; } diff --git a/bsnes/ui/interface/palette.cpp b/bsnes/ui/interface/palette.cpp index c030dd62..0fba0406 100755 --- a/bsnes/ui/interface/palette.cpp +++ b/bsnes/ui/interface/palette.cpp @@ -1,7 +1,7 @@ Palette palette; -uint8_t Palette::operator[](uint8_t n) { - return color[n]; +unsigned Palette::operator()(unsigned r, unsigned g, unsigned b) const { + return red[r] + green[g] + blue[b]; } /* 5-bit -> 8-bit @@ -13,35 +13,38 @@ const uint8_t Palette::gammaRamp[32] = { }; */ -uint8_t Palette::contrastAdjust(uint8_t input) { - signed contrast = config->video.contrast - 100; - signed result = input - contrast + (2 * contrast * input + 127) / 255; - return max(0, min(255, result)); -} - -uint8_t Palette::brightnessAdjust(uint8_t input) { - signed brightness = config->video.brightness - 100; - signed result = input + brightness; - return max(0, min(255, result)); -} - -uint8_t Palette::gammaAdjust(uint8_t input) { - signed result = (signed)(pow(((double)input / 255.0), (double)config->video.gamma / 100.0) * 255.0 + 0.5); - return max(0, min(255, result)); -} - void Palette::update() { double exponent = 1.0 + (double)config->video.gamma * 0.01; - for(unsigned n = 0; n < 256; n++) { - unsigned result = (n < 128 ? 127 * pow(((double)n / 127), exponent) : n); + for(unsigned n = 0; n < 1024; n++) { + unsigned result = (n < 512 ? 511 * pow(((double)n / 511), exponent) : n); color[n] = result; } - for(unsigned n = 0; n < 256; n++) { - color[n] = contrastAdjust(color[n]); + double contrast = config->video.contrast * 0.01; + for(unsigned n = 0; n < 1024; n++) { + signed result = color[n] * contrast; + color[n] = max(0, min(1023, result)); } - for(unsigned n = 0; n < 256; n++) { - color[n] = brightnessAdjust(color[n]); + signed brightness = (config->video.brightness - 100) * 4; + for(unsigned n = 0; n < 1024; n++) { + signed result = color[n] + brightness; + color[n] = max(0, min(1023, result)); + } + + if(config->video.depth == 30) { + for(unsigned n = 0; n < 1024; n++) { + red[n] = color[n] << 20; + green[n] = color[n] << 10; + blue[n] = color[n] << 0; + } + } + + if(config->video.depth == 24) { + for(unsigned n = 0; n < 1024; n++) { + red[n] = (color[n] >> 2) << 16; + green[n] = (color[n] >> 2) << 8; + blue[n] = (color[n] >> 2) << 0; + } } } diff --git a/bsnes/ui/interface/palette.hpp b/bsnes/ui/interface/palette.hpp index c8f8a19f..c9072623 100755 --- a/bsnes/ui/interface/palette.hpp +++ b/bsnes/ui/interface/palette.hpp @@ -1,13 +1,10 @@ struct Palette { - alwaysinline uint8_t operator[](uint8_t color); - - uint8_t contrastAdjust(uint8_t); - uint8_t brightnessAdjust(uint8_t); - uint8_t gammaAdjust(uint8_t); + alwaysinline unsigned operator()(unsigned r, unsigned g, unsigned b) const; void update(); private: - uint32_t color[256]; + uint32_t color[1024]; + uint32_t red[1024], green[1024], blue[1024]; }; extern Palette palette; diff --git a/bsnes/ui/interface/snes/snes.cpp b/bsnes/ui/interface/snes/snes.cpp index 51d444db..07eb263b 100755 --- a/bsnes/ui/interface/snes/snes.cpp +++ b/bsnes/ui/interface/snes/snes.cpp @@ -51,7 +51,7 @@ bool InterfaceSNES::loadCartridge(const string &basename) { loadMemory(); interface->loadCartridge(::Interface::Mode::SNES); - SNES::video.generate(SNES::Video::Format::RGB24); + SNES::video.generate(SNES::Video::Format::RGB30); return true; } @@ -80,7 +80,7 @@ bool InterfaceSNES::loadSatellaviewSlottedCartridge(const string &basename, cons loadMemory(); interface->loadCartridge(::Interface::Mode::SNES); - SNES::video.generate(SNES::Video::Format::RGB24); + SNES::video.generate(SNES::Video::Format::RGB30); return true; } @@ -109,7 +109,7 @@ bool InterfaceSNES::loadSatellaviewCartridge(const string &basename, const strin loadMemory(); interface->loadCartridge(::Interface::Mode::SNES); - SNES::video.generate(SNES::Video::Format::RGB24); + SNES::video.generate(SNES::Video::Format::RGB30); return true; } @@ -143,7 +143,7 @@ bool InterfaceSNES::loadSufamiTurboCartridge(const string &basename, const strin loadMemory(); interface->loadCartridge(::Interface::Mode::SNES); - SNES::video.generate(SNES::Video::Format::RGB24); + SNES::video.generate(SNES::Video::Format::RGB30); return true; } @@ -176,7 +176,7 @@ bool InterfaceSNES::loadSuperGameBoyCartridge(const string &basename, const stri loadMemory(); interface->loadCartridge(::Interface::Mode::SNES); - SNES::video.generate(SNES::Video::Format::RGB24); + SNES::video.generate(SNES::Video::Format::RGB30); return true; } diff --git a/bsnes/ui/main.cpp b/bsnes/ui/main.cpp index 59bac117..1bf6c33a 100755 --- a/bsnes/ui/main.cpp +++ b/bsnes/ui/main.cpp @@ -27,12 +27,13 @@ void Application::run() { } Application::Application(int argc, char **argv) { - title = "bsnes v084.01"; + title = "bsnes v084.03"; application = this; quit = false; pause = false; autopause = false; + { char path[PATH_MAX]; auto unused = ::realpath(argv[0], path); @@ -46,6 +47,7 @@ Application::Application(int argc, char **argv) { } mkdir(userpath, 0755); } + config = new Config; interface = new Interface; inputManager = new InputManager; @@ -76,6 +78,7 @@ Application::Application(int argc, char **argv) { video.driver(config->video.driver); video.set(Video::Handle, mainWindow->viewport.handle()); video.set(Video::Synchronize, config->video.synchronize); + video.set(Video::Depth, config->video.depth); if(video.init() == false) { MessageWindow::critical(*mainWindow, { "Failed to initialize ", config->video.driver, " video driver." }); video.driver("None"); diff --git a/snesfilter/HQ2x/HQ2x.cpp b/snesfilter/HQ2x/HQ2x.cpp index 46f88c15..4d19d872 100755 --- a/snesfilter/HQ2x/HQ2x.cpp +++ b/snesfilter/HQ2x/HQ2x.cpp @@ -34,13 +34,14 @@ const uint8_t hqTable[256] = { 4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14, }; -static uint16_t rgb555(uint32_t C) { - return ((C >> 9) & 0x7c00) + ((C >> 6) & 0x03e0) + ((C >> 3) & 0x001f); +static uint16_t rgb15(uint32_t C) { + return ((C >> 15) & 0x7c00) + ((C >> 10) & 0x03e0) + ((C >> 5) & 0x001f); } -static uint32_t rgb888(uint16_t C) { - return ((C & 0x7c00) << 9) + ((C & 0x03e0) << 6) + ((C & 0x001f) << 3) - + ((C & 0x7000) << 4) + ((C & 0x0380) << 1) + ((C & 0x001c) >> 2); +static uint32_t rgb30(uint16_t C) { + return ((C & 0x7c00) << 15) + ((C & 0x7c00) << 10) + + ((C & 0x03e0) << 10) + ((C & 0x03e0) << 5) + + ((C & 0x001f) << 5) + ((C & 0x001f) << 0); } static void initialize() { @@ -51,11 +52,13 @@ static void initialize() { yuvTable = new uint32_t[32768]; for(unsigned i = 0; i < 32768; i++) { - uint32_t C = rgb888(i); + uint8_t R = (i >> 10) & 31; + uint8_t G = (i >> 5) & 31; + uint8_t B = (i >> 0) & 31; - double r = (uint8_t)(C >> 16); - double g = (uint8_t)(C >> 8); - double b = (uint8_t)(C >> 0); + double r = (R << 3) | (R >> 2); + double g = (G << 3) | (G >> 2); + double b = (B << 3) | (B >> 2); double y = (r + g + b) * (0.25f * (63.5f / 48.0f)); double u = ((r - b) * 0.25f + 128.0f) * (7.5f / 7.0f); @@ -173,15 +176,15 @@ dllexport void filter_render( *out1++ = 0; *out1++ = 0; for(unsigned x = 1; x < width - 1; x++) { - uint16_t A = rgb555(*(in - prevline - 1)); - uint16_t B = rgb555(*(in - prevline + 0)); - uint16_t C = rgb555(*(in - prevline + 1)); - uint16_t D = rgb555(*(in - 1)); - uint16_t E = rgb555(*(in + 0)); - uint16_t F = rgb555(*(in + 1)); - uint16_t G = rgb555(*(in + nextline - 1)); - uint16_t H = rgb555(*(in + nextline + 0)); - uint16_t I = rgb555(*(in + nextline + 1)); + uint16_t A = rgb15(*(in - prevline - 1)); + uint16_t B = rgb15(*(in - prevline + 0)); + uint16_t C = rgb15(*(in - prevline + 1)); + uint16_t D = rgb15(*(in - 1)); + uint16_t E = rgb15(*(in + 0)); + uint16_t F = rgb15(*(in + 1)); + uint16_t G = rgb15(*(in + nextline - 1)); + uint16_t H = rgb15(*(in + nextline + 0)); + uint16_t I = rgb15(*(in + nextline + 1)); uint32_t e = yuvTable[E] + diff_offset; uint8_t pattern; @@ -194,10 +197,10 @@ dllexport void filter_render( pattern |= diff(e, H) << 6; pattern |= diff(e, I) << 7; - *(out0 + 0) = rgb888(blend(hqTable[pattern], E, A, B, D, F, H)); pattern = rotate[pattern]; - *(out0 + 1) = rgb888(blend(hqTable[pattern], E, C, F, B, H, D)); pattern = rotate[pattern]; - *(out1 + 1) = rgb888(blend(hqTable[pattern], E, I, H, F, D, B)); pattern = rotate[pattern]; - *(out1 + 0) = rgb888(blend(hqTable[pattern], E, G, D, H, B, F)); + *(out0 + 0) = rgb30(blend(hqTable[pattern], E, A, B, D, F, H)); pattern = rotate[pattern]; + *(out0 + 1) = rgb30(blend(hqTable[pattern], E, C, F, B, H, D)); pattern = rotate[pattern]; + *(out1 + 1) = rgb30(blend(hqTable[pattern], E, I, H, F, D, B)); pattern = rotate[pattern]; + *(out1 + 0) = rgb30(blend(hqTable[pattern], E, G, D, H, B, F)); in++; out0 += 2; diff --git a/snesfilter/LQ2x/LQ2x.cpp b/snesfilter/LQ2x/LQ2x.cpp index f5696266..29d17cff 100755 --- a/snesfilter/LQ2x/LQ2x.cpp +++ b/snesfilter/LQ2x/LQ2x.cpp @@ -17,6 +17,7 @@ dllexport void filter_render( const uint32_t *input, unsigned inputPitch, unsigned width, unsigned height ) { + enum : unsigned { Mask = (1 << 20) | (1 << 10) | (1 << 0) }; outputPitch >>= 2, inputPitch >>= 2; #pragma omp parallel for @@ -36,10 +37,10 @@ dllexport void filter_render( uint32_t E = *(in++ + nextline); if(A != E && B != D) { - *out0++ = (A == B ? C + A - ((C ^ A) & 0x010101) >> 1 : C); - *out0++ = (A == D ? C + A - ((C ^ A) & 0x010101) >> 1 : C); - *out1++ = (E == B ? C + E - ((C ^ E) & 0x010101) >> 1 : C); - *out1++ = (E == D ? C + E - ((C ^ E) & 0x010101) >> 1 : C); + *out0++ = (A == B ? C + A - ((C ^ A) & Mask) >> 1 : C); + *out0++ = (A == D ? C + A - ((C ^ A) & Mask) >> 1 : C); + *out1++ = (E == B ? C + E - ((C ^ E) & Mask) >> 1 : C); + *out1++ = (E == D ? C + E - ((C ^ E) & Mask) >> 1 : C); } else { *out0++ = C; *out0++ = C; diff --git a/snesfilter/Makefile b/snesfilter/Makefile index 1a29918a..24875c36 100755 --- a/snesfilter/Makefile +++ b/snesfilter/Makefile @@ -2,12 +2,12 @@ include nall/Makefile c := $(compiler) -std=gnu99 cpp := $(subst cc,++,$(compiler)) -std=gnu++0x -flags := -fPIC -O3 -I. -Iobj -fomit-frame-pointer +flags := -fPIC -I. -Iobj -O3 -fomit-frame-pointer link := -s objects := ifeq ($(platform),x) - flags += -fopenmp +# flags += -fopenmp endif objects += out/Pixellate2x.filter diff --git a/snesfilter/Phosphor3x/Phosphor3x.cpp b/snesfilter/Phosphor3x/Phosphor3x.cpp index 817fc9be..69480e8c 100755 --- a/snesfilter/Phosphor3x/Phosphor3x.cpp +++ b/snesfilter/Phosphor3x/Phosphor3x.cpp @@ -17,6 +17,7 @@ dllexport void filter_render( const uint32_t *input, unsigned inputPitch, unsigned width, unsigned height ) { + enum : unsigned { Mask = (1022 << 20) + (1022 << 10) + (1022 << 0) }; outputPitch >>= 2, inputPitch >>= 2; #pragma omp parallel for @@ -31,27 +32,27 @@ dllexport void filter_render( uint32_t B = *in; uint32_t C = (x == width - 1 ? 0 : *(in + 1)); - uint8_t Ar = A >> 16, Ag = A >> 8, Ab = A >> 0; - uint8_t Br = B >> 16, Bg = B >> 8, Bb = B >> 0; - uint8_t Cr = C >> 16, Cg = C >> 8, Cb = C >> 0; + unsigned Ar = (A >> 20) & 1023, Ag = (A >> 10) & 1023, Ab = (A >> 0) & 1023; + unsigned Br = (B >> 20) & 1023, Bg = (B >> 10) & 1023, Bb = (B >> 0) & 1023; + unsigned Cr = (C >> 20) & 1023, Cg = (C >> 10) & 1023, Cb = (C >> 0) & 1023; - A = ((Br >> 0) << 16) + ((Bg >> 1) << 8) + ((Ab >> 1) << 0); - B = ((Br >> 1) << 16) + ((Bg >> 0) << 8) + ((Bb >> 1) << 0); - C = ((Cr >> 1) << 16) + ((Bg >> 1) << 8) + ((Bb >> 0) << 0); + A = ((Br >> 0) << 20) + ((Bg >> 1) << 10) + ((Ab >> 1) << 0); + B = ((Br >> 1) << 20) + ((Bg >> 0) << 10) + ((Bb >> 1) << 0); + C = ((Cr >> 1) << 20) + ((Bg >> 1) << 10) + ((Bb >> 0) << 0); in++; *out0++ = A; *out1++ = A; - *out2++ = (A & 0xf8f8f8) >> 1; + *out2++ = (A & Mask) >> 1; *out0++ = B; *out1++ = B; - *out2++ = (B & 0xf8f8f8) >> 1; + *out2++ = (B & Mask) >> 1; *out0++ = C; *out1++ = C; - *out2++ = (C & 0xf8f8f8) >> 1; + *out2++ = (C & Mask) >> 1; } } } diff --git a/snesfilter/Scanline/Scanline-Light.cpp b/snesfilter/Scanline/Scanline-Light.cpp index f38b8ef9..5ce4e1b9 100755 --- a/snesfilter/Scanline/Scanline-Light.cpp +++ b/snesfilter/Scanline/Scanline-Light.cpp @@ -16,6 +16,7 @@ dllexport void filter_render( const uint32_t *input, unsigned inputPitch, unsigned width, unsigned height ) { + enum : unsigned { Mask = (1022 << 20) | (1022 << 10) | (1022 << 0) }; outputPitch >>= 2, inputPitch >>= 2; #pragma omp parallel for @@ -26,7 +27,7 @@ dllexport void filter_render( for(unsigned x = 0; x < width; x++) { *out0++ = *in; - *out1++ = (*in++ & 0xf8f8f8) >> 1; + *out1++ = (*in++ & Mask) >> 1; } } } diff --git a/snesfilter/nall/Makefile b/snesfilter/nall/Makefile index 9a93bd23..a542beeb 100755 --- a/snesfilter/nall/Makefile +++ b/snesfilter/nall/Makefile @@ -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 @@ -32,9 +35,9 @@ ifeq ($(compiler),) ifeq ($(platform),win) compiler := gcc else ifeq ($(platform),osx) - compiler := gcc-mp-4.5 + compiler := gcc-mp-4.6 else - compiler := gcc-4.5 + compiler := gcc-4.6 endif endif diff --git a/snesfilter/nall/array.hpp b/snesfilter/nall/array.hpp index e1fb1fcb..4847a297 100755 --- a/snesfilter/nall/array.hpp +++ b/snesfilter/nall/array.hpp @@ -2,13 +2,12 @@ #define NALL_ARRAY_HPP #include +#include #include #include #include #include #include -#include -#include #include namespace nall { @@ -26,7 +25,7 @@ namespace nall { void reset() { if(pool) free(pool); - pool = 0; + pool = nullptr; poolsize = 0; buffersize = 0; } @@ -54,21 +53,14 @@ namespace nall { operator[](buffersize) = data; } + void append(const T data[], unsigned length) { + for(unsigned n = 0; n < length; n++) operator[](buffersize) = data[n]; + } + void remove() { if(size > 0) resize(size - 1); //remove last element only } - template void insert(unsigned index, const U list) { - unsigned listsize = container_size(list); - resize(buffersize + listsize); - memmove(pool + index + listsize, pool + index, (buffersize - index) * sizeof(T)); - foreach(item, list) pool[index++] = item; - } - - void insert(unsigned index, const T item) { - insert(index, array{ item }); - } - void remove(unsigned index, unsigned count = 1) { for(unsigned i = index; count + i < buffersize; i++) { pool[i] = pool[count + i]; @@ -86,10 +78,10 @@ namespace nall { memset(pool, 0, buffersize * sizeof(T)); } - array() : pool(0), poolsize(0), buffersize(0) { + array() : pool(nullptr), poolsize(0), buffersize(0) { } - array(std::initializer_list list) : pool(0), poolsize(0), buffersize(0) { + array(std::initializer_list list) : pool(nullptr), poolsize(0), buffersize(0) { for(const T *p = list.begin(); p != list.end(); ++p) append(*p); } @@ -107,7 +99,7 @@ namespace nall { return *this; } - array(const array &source) : pool(0), poolsize(0), buffersize(0) { + array(const array &source) : pool(nullptr), poolsize(0), buffersize(0) { operator=(source); } @@ -117,12 +109,12 @@ namespace nall { pool = source.pool; poolsize = source.poolsize; buffersize = source.buffersize; - source.pool = 0; + source.pool = nullptr; source.reset(); return *this; } - array(array &&source) : pool(0), poolsize(0), buffersize(0) { + array(array &&source) : pool(nullptr), poolsize(0), buffersize(0) { operator=(std::move(source)); } @@ -144,8 +136,6 @@ namespace nall { const T* begin() const { return &pool[0]; } const T* end() const { return &pool[buffersize]; } }; - - template struct has_size> { enum { value = true }; }; } #endif diff --git a/snesfilter/nall/atoi.hpp b/snesfilter/nall/atoi.hpp new file mode 100755 index 00000000..cec3e72d --- /dev/null +++ b/snesfilter/nall/atoi.hpp @@ -0,0 +1,88 @@ +#ifndef NALL_ATOI_HPP +#define NALL_ATOI_HPP + +namespace nall { + +//note: this header is intended to form the base for user-defined literals; +//once they are supported by GCC. eg: +//unsigned operator "" b(const char *s) { return binary(s); } +//-> signed data = 1001b; +//(0b1001 is nicer, but is not part of the C++ standard) + +constexpr inline uintmax_t binary_(const char *s, uintmax_t sum = 0) { + return ( + *s == '0' || *s == '1' ? binary_(s + 1, (sum << 1) | *s - '0') : + sum + ); +} + +constexpr inline uintmax_t octal_(const char *s, uintmax_t sum = 0) { + return ( + *s >= '0' && *s <= '7' ? octal_(s + 1, (sum << 3) | *s - '0') : + sum + ); +} + +constexpr inline uintmax_t decimal_(const char *s, uintmax_t sum = 0) { + return ( + *s >= '0' && *s <= '9' ? decimal_(s + 1, (sum * 10) + *s - '0') : + sum + ); +} + +constexpr inline uintmax_t hex_(const char *s, uintmax_t sum = 0) { + return ( + *s >= 'A' && *s <= 'F' ? hex_(s + 1, (sum << 4) | *s - 'A' + 10) : + *s >= 'a' && *s <= 'f' ? hex_(s + 1, (sum << 4) | *s - 'a' + 10) : + *s >= '0' && *s <= '9' ? hex_(s + 1, (sum << 4) | *s - '0') : + sum + ); +} + +// + +constexpr inline uintmax_t binary(const char *s) { + return ( + *s == '0' && *(s + 1) == 'B' ? binary_(s + 2) : + *s == '0' && *(s + 1) == 'b' ? binary_(s + 2) : + *s == '%' ? binary_(s + 1) : + binary_(s) + ); +} + +constexpr inline uintmax_t octal(const char *s) { + return ( + octal_(s) + ); +} + +constexpr inline intmax_t integer(const char *s) { + return ( + *s == '+' ? +decimal_(s + 1) : + *s == '-' ? -decimal_(s + 1) : + decimal_(s) + ); +} + +constexpr inline uintmax_t decimal(const char *s) { + return ( + decimal_(s) + ); +} + +constexpr inline uintmax_t hex(const char *s) { + return ( + *s == '0' && *(s + 1) == 'X' ? hex_(s + 2) : + *s == '0' && *(s + 1) == 'x' ? hex_(s + 2) : + *s == '$' ? hex_(s + 1) : + hex_(s) + ); +} + +inline double fp(const char *s) { + return atof(s); +} + +} + +#endif diff --git a/snesfilter/nall/base64.hpp b/snesfilter/nall/base64.hpp index ee59c1be..a0afd8b1 100755 --- a/snesfilter/nall/base64.hpp +++ b/snesfilter/nall/base64.hpp @@ -5,8 +5,7 @@ #include namespace nall { - class base64 { - public: + struct base64 { static bool encode(char *&output, const uint8_t* input, unsigned inlength) { output = new char[inlength * 8 / 6 + 6](); diff --git a/snesfilter/nall/bit.hpp b/snesfilter/nall/bit.hpp index ca6ea29a..67a35ad6 100755 --- a/snesfilter/nall/bit.hpp +++ b/snesfilter/nall/bit.hpp @@ -2,39 +2,39 @@ #define NALL_BIT_HPP namespace nall { - template inline unsigned uclamp(const unsigned x) { + template constexpr inline unsigned uclamp(const unsigned x) { enum { y = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1) }; return y + ((x - y) & -(x < y)); //min(x, y); } - template inline unsigned uclip(const unsigned x) { + template constexpr inline unsigned uclip(const unsigned x) { enum { m = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1) }; return (x & m); } - template inline signed sclamp(const signed x) { + template constexpr inline signed sclamp(const signed x) { enum { b = 1U << (bits - 1), m = (1U << (bits - 1)) - 1 }; return (x > m) ? m : (x < -b) ? -b : x; } - template inline signed sclip(const signed x) { + template constexpr inline signed sclip(const signed x) { enum { b = 1U << (bits - 1), m = (1U << bits) - 1 }; return ((x & m) ^ b) - b; } namespace bit { //lowest(0b1110) == 0b0010 - template inline T lowest(const T x) { + template constexpr inline T lowest(const T x) { return x & -x; } //clear_lowest(0b1110) == 0b1100 - template inline T clear_lowest(const T x) { + template constexpr inline T clear_lowest(const T x) { return x & (x - 1); } //set_lowest(0b0101) == 0b0111 - template inline T set_lowest(const T x) { + template constexpr inline T set_lowest(const T x) { return x | (x + 1); } diff --git a/snesfilter/nall/bps/delta.hpp b/snesfilter/nall/bps/delta.hpp index a3af047c..6cee56a3 100755 --- a/snesfilter/nall/bps/delta.hpp +++ b/snesfilter/nall/bps/delta.hpp @@ -24,7 +24,7 @@ protected: struct Node { unsigned offset; Node *next; - inline Node() : offset(0), next(0) {} + inline Node() : offset(0), next(nullptr) {} inline ~Node() { if(next) delete next; } }; diff --git a/snesfilter/nall/compositor.hpp b/snesfilter/nall/compositor.hpp index 6d5c46c9..6b9245f6 100755 --- a/snesfilter/nall/compositor.hpp +++ b/snesfilter/nall/compositor.hpp @@ -1,18 +1,56 @@ #ifndef NALL_COMPOSITOR_HPP #define NALL_COMPOSITOR_HPP -#include +#include namespace nall { struct compositor { inline static bool enabled(); inline static bool enable(bool status); + + #if defined(PLATFORM_X) + enum class Compositor : unsigned { Unknown, Metacity, Xfwm4 }; + inline static Compositor detect(); + + inline static bool enabled_metacity(); + inline static bool enable_metacity(bool status); + + inline static bool enabled_xfwm4(); + inline static bool enable_xfwm4(bool status); + #endif }; #if defined(PLATFORM_X) -bool compositor::enabled() { +//Metacity + +bool compositor::enabled_metacity() { + FILE *fp = popen("gconftool-2 --get /apps/metacity/general/compositing_manager", "r"); + if(fp == 0) return false; + + char buffer[512]; + if(fgets(buffer, sizeof buffer, fp) == 0) return false; + + if(!memcmp(buffer, "true", 4)) return true; + return false; +} + +bool compositor::enable_metacity(bool status) { + FILE *fp; + if(status) { + fp = popen("gconftool-2 --set --type bool /apps/metacity/general/compositing_manager true", "r"); + } else { + fp = popen("gconftool-2 --set --type bool /apps/metacity/general/compositing_manager false", "r"); + } + if(fp == 0) return false; + pclose(fp); + return true; +} + +//Xfwm4 + +bool compositor::enabled_xfwm4() { FILE *fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing'", "r"); if(fp == 0) return false; @@ -23,7 +61,7 @@ bool compositor::enabled() { return false; } -bool compositor::enable(bool status) { +bool compositor::enable_xfwm4(bool status) { FILE *fp; if(status) { fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'true'", "r"); @@ -35,7 +73,42 @@ bool compositor::enable(bool status) { return true; } -#elif defined(PLATFORM_WIN) +//General + +compositor::Compositor compositor::detect() { + Compositor result = Compositor::Unknown; + + FILE *fp; + char buffer[512]; + + fp = popen("pidof metacity", "r"); + if(fp && fgets(buffer, sizeof buffer, fp)) result = Compositor::Metacity; + pclose(fp); + + fp = popen("pidof xfwm4", "r"); + if(fp && fgets(buffer, sizeof buffer, fp)) result = Compositor::Xfwm4; + pclose(fp); + + return result; +} + +bool compositor::enabled() { + switch(detect()) { + case Compositor::Metacity: return enabled_metacity(); + case Compositor::Xfwm4: return enabled_xfwm4(); + default: return false; + } +} + +bool compositor::enable(bool status) { + switch(detect()) { + case Compositor::Metacity: return enable_metacity(status); + case Compositor::Xfwm4: return enable_xfwm4(status); + default: return false; + } +} + +#elif defined(PLATFORM_WINDOWS) bool compositor::enabled() { HMODULE module = GetModuleHandleW(L"dwmapi"); diff --git a/snesfilter/nall/config.hpp b/snesfilter/nall/config.hpp index 99aaee08..0c6602df 100755 --- a/snesfilter/nall/config.hpp +++ b/snesfilter/nall/config.hpp @@ -70,7 +70,7 @@ namespace nall { else list[n].type = unknown_t; } - virtual bool load(const char *filename) { + virtual bool load(const string &filename) { string data; if(data.readfile(filename) == true) { data.replace("\r", ""); @@ -100,7 +100,7 @@ namespace nall { } } - virtual bool save(const char *filename) const { + virtual bool save(const string &filename) const { file fp; if(fp.open(filename, file::mode::write)) { for(unsigned i = 0; i < list.size(); i++) { diff --git a/snesfilter/nall/directory.hpp b/snesfilter/nall/directory.hpp index 7fbc15f4..31ca1e05 100755 --- a/snesfilter/nall/directory.hpp +++ b/snesfilter/nall/directory.hpp @@ -1,11 +1,12 @@ #ifndef NALL_DIRECTORY_HPP #define NALL_DIRECTORY_HPP -#include +#include #include #include +#include -#if defined(_WIN32) +#if defined(PLATFORM_WINDOWS) #include #else #include @@ -22,7 +23,7 @@ struct directory { static lstring contents(const string &pathname, const string &pattern = "*"); }; -#if defined(_WIN32) +#if defined(PLATFORM_WINDOWS) inline bool directory::exists(const string &pathname) { DWORD result = GetFileAttributes(utf16_t(pathname)); if(result == INVALID_FILE_ATTRIBUTES) return false; @@ -56,7 +57,7 @@ struct directory { FindClose(handle); } if(list.size() > 0) sort(&list[0], list.size()); - foreach(name, list) name.append("/"); //must append after sorting + for(auto &name : list) name.append("/"); //must append after sorting return list; } @@ -89,7 +90,7 @@ struct directory { inline lstring directory::contents(const string &pathname, const string &pattern) { lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files lstring files = directory::files(pathname, pattern); - foreach(file, files) folders.append(file); + for(auto &file : files) folders.append(file); return folders; } #else @@ -116,7 +117,7 @@ struct directory { closedir(dp); } if(list.size() > 0) sort(&list[0], list.size()); - foreach(name, list) name.append("/"); //must append after sorting + for(auto &name : list) name.append("/"); //must append after sorting return list; } @@ -142,7 +143,7 @@ struct directory { inline lstring directory::contents(const string &pathname, const string &pattern) { lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files lstring files = directory::files(pathname, pattern); - foreach(file, files) folders.append(file); + for(auto &file : files) folders.append(file); return folders; } #endif diff --git a/snesfilter/nall/dl.hpp b/snesfilter/nall/dl.hpp index c697958c..3bd7d4d2 100755 --- a/snesfilter/nall/dl.hpp +++ b/snesfilter/nall/dl.hpp @@ -3,14 +3,14 @@ //dynamic linking support -#include +#include #include #include #include #if defined(PLATFORM_X) || defined(PLATFORM_OSX) #include -#elif defined(PLATFORM_WIN) +#elif defined(PLATFORM_WINDOWS) #include #include #endif @@ -81,7 +81,7 @@ namespace nall { dlclose((void*)handle); handle = 0; } - #elif defined(PLATFORM_WIN) + #elif defined(PLATFORM_WINDOWS) inline bool library::open(const char *name, const char *path) { if(handle) close(); string filepath(path, *path && !strend(path, "/") && !strend(path, "\\") ? "\\" : "", name, ".dll"); diff --git a/snesfilter/nall/dsp.hpp b/snesfilter/nall/dsp.hpp index 009c8b6c..a2400ec7 100755 --- a/snesfilter/nall/dsp.hpp +++ b/snesfilter/nall/dsp.hpp @@ -1,6 +1,11 @@ #ifndef NALL_DSP_HPP #define NALL_DSP_HPP +#include +#ifdef __SSE__ + #include +#endif + #define NALL_DSP_INTERNAL_HPP #include #undef NALL_DSP_INTERNAL_HPP diff --git a/snesfilter/nall/dsp/core.hpp b/snesfilter/nall/dsp/core.hpp index a4c58c38..a5b967b1 100755 --- a/snesfilter/nall/dsp/core.hpp +++ b/snesfilter/nall/dsp/core.hpp @@ -5,24 +5,40 @@ namespace nall { +//precision: can be float, double or long double +#define real float + +struct DSP; + +struct Resampler { + DSP &dsp; + real frequency; + + virtual void setFrequency() = 0; + virtual void clear() = 0; + virtual void sample() = 0; + Resampler(DSP &dsp) : dsp(dsp) {} +}; + struct DSP { - enum class Resampler : unsigned { - Point, + enum class ResampleEngine : unsigned { + Nearest, Linear, Cosine, Cubic, Hermite, Average, + Sinc, }; inline void setChannels(unsigned channels); inline void setPrecision(unsigned precision); - inline void setFrequency(double frequency); //inputFrequency - inline void setVolume(double volume); - inline void setBalance(double balance); + inline void setFrequency(real frequency); //inputFrequency + inline void setVolume(real volume); + inline void setBalance(real balance); - inline void setResampler(Resampler resampler); - inline void setResamplerFrequency(double frequency); //outputFrequency + inline void setResampler(ResampleEngine resamplingEngine); + inline void setResamplerFrequency(real frequency); //outputFrequency inline void sample(signed channel[]); inline bool pending(); @@ -33,33 +49,28 @@ struct DSP { inline ~DSP(); protected: + friend class ResampleNearest; + friend class ResampleLinear; + friend class ResampleCosine; + friend class ResampleCubic; + friend class ResampleAverage; + friend class ResampleHermite; + friend class ResampleSinc; + struct Settings { unsigned channels; unsigned precision; - double frequency; - double volume; - double balance; + real frequency; + real volume; + real balance; + //internal - double intensity; + real intensity; + real intensityInverse; } settings; - struct ResamplerSettings { - Resampler engine; - double frequency; - //internal - double fraction; - double step; - } resampler; - - inline void resamplerRun(); - inline void resamplerWrite(double channel[]); - - inline void resamplePoint(); - inline void resampleLinear(); - inline void resampleCosine(); - inline void resampleCubic(); - inline void resampleHermite(); - inline void resampleAverage(); + Resampler *resampler; + inline void write(real channel[]); #include "buffer.hpp" Buffer buffer; @@ -70,14 +81,21 @@ protected: inline signed clamp(const unsigned bits, const signed x); }; +#include "resample/nearest.hpp" +#include "resample/linear.hpp" +#include "resample/cosine.hpp" +#include "resample/cubic.hpp" +#include "resample/hermite.hpp" +#include "resample/average.hpp" +#include "resample/sinc.hpp" #include "settings.hpp" void DSP::sample(signed channel[]) { for(unsigned c = 0; c < settings.channels; c++) { - buffer.write(c) = (double)channel[c] / settings.intensity; + buffer.write(c) = (real)channel[c] * settings.intensityInverse; } buffer.wroffset++; - resamplerRun(); + resampler->sample(); } bool DSP::pending() { @@ -94,31 +112,13 @@ void DSP::read(signed channel[]) { output.rdoffset++; } -void DSP::resamplerRun() { - switch(resampler.engine) { - case Resampler::Point: return resamplePoint(); - case Resampler::Linear: return resampleLinear(); - case Resampler::Cosine: return resampleCosine(); - case Resampler::Cubic: return resampleCubic(); - case Resampler::Hermite: return resampleHermite(); - case Resampler::Average: return resampleAverage(); - } -} - -void DSP::resamplerWrite(double channel[]) { +void DSP::write(real channel[]) { for(unsigned c = 0; c < settings.channels; c++) { output.write(c) = channel[c]; } output.wroffset++; } -#include "resample/point.hpp" -#include "resample/linear.hpp" -#include "resample/cosine.hpp" -#include "resample/cubic.hpp" -#include "resample/hermite.hpp" -#include "resample/average.hpp" - void DSP::adjustVolume() { for(unsigned c = 0; c < settings.channels; c++) { output.read(c) *= settings.volume; @@ -138,25 +138,30 @@ signed DSP::clamp(const unsigned bits, const signed x) { } void DSP::clear() { - resampler.fraction = 0.0; buffer.clear(); output.clear(); + resampler->clear(); } DSP::DSP() { + setResampler(ResampleEngine::Hermite); + setResamplerFrequency(44100.0); + setChannels(2); setPrecision(16); setFrequency(44100.0); setVolume(1.0); setBalance(0.0); - setResampler(Resampler::Hermite); - setResamplerFrequency(44100.0); + clear(); } DSP::~DSP() { + if(resampler) delete resampler; } +#undef real + } #endif diff --git a/snesfilter/nall/dsp/resample/average.hpp b/snesfilter/nall/dsp/resample/average.hpp index c5cdbca3..867b13bf 100755 --- a/snesfilter/nall/dsp/resample/average.hpp +++ b/snesfilter/nall/dsp/resample/average.hpp @@ -1,31 +1,72 @@ #ifdef NALL_DSP_INTERNAL_HPP -void DSP::resampleAverage() { +struct ResampleAverage : Resampler { + inline void setFrequency(); + inline void clear(); + inline void sample(); + inline void sampleLinear(); + ResampleAverage(DSP &dsp) : Resampler(dsp) {} + + real fraction; + real step; +}; + +void ResampleAverage::setFrequency() { + fraction = 0.0; + step = dsp.settings.frequency / frequency; +} + +void ResampleAverage::clear() { + fraction = 0.0; +} + +void ResampleAverage::sample() { //can only average if input frequency >= output frequency - if(resampler.step < 1.0) return resampleHermite(); + if(step < 1.0) return sampleLinear(); - resampler.fraction += 1.0; + fraction += 1.0; - double scalar = 1.0; - if(resampler.fraction > resampler.step) scalar = 1.0 - (resampler.fraction - resampler.step); + real scalar = 1.0; + if(fraction > step) scalar = 1.0 - (fraction - step); - for(unsigned c = 0; c < settings.channels; c++) { - output.write(c) += buffer.read(c) * scalar; + for(unsigned c = 0; c < dsp.settings.channels; c++) { + dsp.output.write(c) += dsp.buffer.read(c) * scalar; } - if(resampler.fraction >= resampler.step) { - for(unsigned c = 0; c < settings.channels; c++) { - output.write(c) /= resampler.step; + if(fraction >= step) { + for(unsigned c = 0; c < dsp.settings.channels; c++) { + dsp.output.write(c) /= step; } - output.wroffset++; + dsp.output.wroffset++; - resampler.fraction -= resampler.step; - for(unsigned c = 0; c < settings.channels; c++) { - output.write(c) = buffer.read(c) * resampler.fraction; + fraction -= step; + for(unsigned c = 0; c < dsp.settings.channels; c++) { + dsp.output.write(c) = dsp.buffer.read(c) * fraction; } } - buffer.rdoffset++; + dsp.buffer.rdoffset++; +} + +void ResampleAverage::sampleLinear() { + while(fraction <= 1.0) { + real channel[dsp.settings.channels]; + + for(unsigned n = 0; n < dsp.settings.channels; n++) { + real a = dsp.buffer.read(n, -1); + real b = dsp.buffer.read(n, -0); + + real mu = fraction; + + channel[n] = a * (1.0 - mu) + b * mu; + } + + dsp.write(channel); + fraction += step; + } + + dsp.buffer.rdoffset++; + fraction -= 1.0; } #endif diff --git a/snesfilter/nall/dsp/resample/cosine.hpp b/snesfilter/nall/dsp/resample/cosine.hpp index 5405b7f3..3363d5f6 100755 --- a/snesfilter/nall/dsp/resample/cosine.hpp +++ b/snesfilter/nall/dsp/resample/cosine.hpp @@ -1,25 +1,44 @@ #ifdef NALL_DSP_INTERNAL_HPP -void DSP::resampleCosine() { - while(resampler.fraction <= 1.0) { - double channel[settings.channels]; +struct ResampleCosine : Resampler { + inline void setFrequency(); + inline void clear(); + inline void sample(); + ResampleCosine(DSP &dsp) : Resampler(dsp) {} - for(unsigned n = 0; n < settings.channels; n++) { - double a = buffer.read(n, -1); - double b = buffer.read(n, -0); + real fraction; + real step; +}; - double mu = resampler.fraction; +void ResampleCosine::setFrequency() { + fraction = 0.0; + step = dsp.settings.frequency / frequency; +} + +void ResampleCosine::clear() { + fraction = 0.0; +} + +void ResampleCosine::sample() { + while(fraction <= 1.0) { + real channel[dsp.settings.channels]; + + for(unsigned n = 0; n < dsp.settings.channels; n++) { + real a = dsp.buffer.read(n, -1); + real b = dsp.buffer.read(n, -0); + + real mu = fraction; mu = (1.0 - cos(mu * 3.14159265)) / 2.0; channel[n] = a * (1.0 - mu) + b * mu; } - resamplerWrite(channel); - resampler.fraction += resampler.step; + dsp.write(channel); + fraction += step; } - buffer.rdoffset++; - resampler.fraction -= 1.0; + dsp.buffer.rdoffset++; + fraction -= 1.0; } #endif diff --git a/snesfilter/nall/dsp/resample/cubic.hpp b/snesfilter/nall/dsp/resample/cubic.hpp index 71e3766f..bc4cc955 100755 --- a/snesfilter/nall/dsp/resample/cubic.hpp +++ b/snesfilter/nall/dsp/resample/cubic.hpp @@ -1,31 +1,50 @@ #ifdef NALL_DSP_INTERNAL_HPP -void DSP::resampleCubic() { - while(resampler.fraction <= 1.0) { - double channel[settings.channels]; +struct ResampleCubic : Resampler { + inline void setFrequency(); + inline void clear(); + inline void sample(); + ResampleCubic(DSP &dsp) : Resampler(dsp) {} - for(unsigned n = 0; n < settings.channels; n++) { - double a = buffer.read(n, -3); - double b = buffer.read(n, -2); - double c = buffer.read(n, -1); - double d = buffer.read(n, -0); + real fraction; + real step; +}; - double mu = resampler.fraction; +void ResampleCubic::setFrequency() { + fraction = 0.0; + step = dsp.settings.frequency / frequency; +} - double A = d - c - a + b; - double B = a - b - A; - double C = c - a; - double D = b; +void ResampleCubic::clear() { + fraction = 0.0; +} + +void ResampleCubic::sample() { + while(fraction <= 1.0) { + real channel[dsp.settings.channels]; + + for(unsigned n = 0; n < dsp.settings.channels; n++) { + real a = dsp.buffer.read(n, -3); + real b = dsp.buffer.read(n, -2); + real c = dsp.buffer.read(n, -1); + real d = dsp.buffer.read(n, -0); + + real mu = fraction; + + real A = d - c - a + b; + real B = a - b - A; + real C = c - a; + real D = b; channel[n] = A * (mu * 3) + B * (mu * 2) + C * mu + D; } - resamplerWrite(channel); - resampler.fraction += resampler.step; + dsp.write(channel); + fraction += step; } - buffer.rdoffset++; - resampler.fraction -= 1.0; + dsp.buffer.rdoffset++; + fraction -= 1.0; } #endif diff --git a/snesfilter/nall/dsp/resample/hermite.hpp b/snesfilter/nall/dsp/resample/hermite.hpp index 6eed087d..0cc9ba0e 100755 --- a/snesfilter/nall/dsp/resample/hermite.hpp +++ b/snesfilter/nall/dsp/resample/hermite.hpp @@ -1,21 +1,40 @@ #ifdef NALL_DSP_INTERNAL_HPP -void DSP::resampleHermite() { - while(resampler.fraction <= 1.0) { - double channel[settings.channels]; +struct ResampleHermite : Resampler { + inline void setFrequency(); + inline void clear(); + inline void sample(); + ResampleHermite(DSP &dsp) : Resampler(dsp) {} - for(unsigned n = 0; n < settings.channels; n++) { - double a = buffer.read(n, -3); - double b = buffer.read(n, -2); - double c = buffer.read(n, -1); - double d = buffer.read(n, -0); + real fraction; + real step; +}; - const double tension = 0.0; //-1 = low, 0 = normal, +1 = high - const double bias = 0.0; //-1 = left, 0 = even, +1 = right +void ResampleHermite::setFrequency() { + fraction = 0.0; + step = dsp.settings.frequency / frequency; +} - double mu1, mu2, mu3, m0, m1, a0, a1, a2, a3; +void ResampleHermite::clear() { + fraction = 0.0; +} - mu1 = resampler.fraction; +void ResampleHermite::sample() { + while(fraction <= 1.0) { + real channel[dsp.settings.channels]; + + for(unsigned n = 0; n < dsp.settings.channels; n++) { + real a = dsp.buffer.read(n, -3); + real b = dsp.buffer.read(n, -2); + real c = dsp.buffer.read(n, -1); + real d = dsp.buffer.read(n, -0); + + const real tension = 0.0; //-1 = low, 0 = normal, +1 = high + const real bias = 0.0; //-1 = left, 0 = even, +1 = right + + real mu1, mu2, mu3, m0, m1, a0, a1, a2, a3; + + mu1 = fraction; mu2 = mu1 * mu1; mu3 = mu2 * mu1; @@ -32,12 +51,12 @@ void DSP::resampleHermite() { channel[n] = (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c); } - resamplerWrite(channel); - resampler.fraction += resampler.step; + dsp.write(channel); + fraction += step; } - buffer.rdoffset++; - resampler.fraction -= 1.0; + dsp.buffer.rdoffset++; + fraction -= 1.0; } #endif diff --git a/snesfilter/nall/dsp/resample/lib/sinc.hpp b/snesfilter/nall/dsp/resample/lib/sinc.hpp new file mode 100755 index 00000000..3e953679 --- /dev/null +++ b/snesfilter/nall/dsp/resample/lib/sinc.hpp @@ -0,0 +1,600 @@ +// If these types are changed to anything other than "float", you should comment out the SSE detection directives below +// so that the SSE code is not used. + +typedef float resample_coeff_t; // note: sizeof(resample_coeff_t) must be == to a power of 2, and not larger than 16 +typedef float resample_samp_t; + + +// ...but don't comment this single RESAMPLE_SSEREGPARM define out when disabling SSE. +#define RESAMPLE_SSEREGPARM + +#if defined(__SSE__) + #define SINCRESAMPLE_USE_SSE 1 + #ifndef __x86_64__ + #undef RESAMPLE_SSEREGPARM + #define RESAMPLE_SSEREGPARM __attribute__((sseregparm)) + #endif +#else + // TODO: altivec here +#endif + +namespace ResampleUtility +{ + inline void kaiser_window(double* io, int count, double beta); + inline void gen_sinc(double* out, int size, double cutoff, double kaiser); + inline void gen_sinc_os(double* out, int size, double cutoff, double kaiser); + inline void normalize(double* io, int size, double gain = 1.0); + + inline void* make_aligned(void* ptr, unsigned boundary); // boundary must be a power of 2 +} + +class SincResampleHR +{ + private: + + inline void Init(unsigned ratio_arg, double desired_bandwidth, double beta, double d); + + inline void write(resample_samp_t sample) RESAMPLE_SSEREGPARM; + inline resample_samp_t read(void) RESAMPLE_SSEREGPARM; + inline bool output_avail(void); + + private: + + inline resample_samp_t mac(const resample_samp_t *wave, const resample_coeff_t *coeff, unsigned count); + + unsigned ratio; + unsigned num_convolutions; + + resample_coeff_t *coeffs; + std::vector coeffs_mem; + + // second half of ringbuffer should be copy of first half. + resample_samp_t *rb; + std::vector rb_mem; + + signed rb_readpos; + signed rb_writepos; + signed rb_in; + signed rb_eff_size; + + friend class SincResample; +}; + +class SincResample +{ + public: + + enum + { + QUALITY_LOW = 0, + QUALITY_MEDIUM = 2, + QUALITY_HIGH = 4 + }; + + inline SincResample(double input_rate, double output_rate, double desired_bandwidth, unsigned quality = QUALITY_HIGH); + + inline void write(resample_samp_t sample) RESAMPLE_SSEREGPARM; + inline resample_samp_t read(void) RESAMPLE_SSEREGPARM; + inline bool output_avail(void); + + private: + + inline void Init(double input_rate, double output_rate, double desired_bandwidth, double beta, double d, unsigned pn_nume, unsigned phases_min); + + inline resample_samp_t mac(const resample_samp_t *wave, const resample_coeff_t *coeffs_a, const resample_coeff_t *coeffs_b, const double ffract, unsigned count) RESAMPLE_SSEREGPARM; + + unsigned num_convolutions; + unsigned num_phases; + + unsigned step_int; + double step_fract; + + double input_pos_fract; + + + std::vector coeffs; // Pointers into coeff_mem. + std::vector coeff_mem; + + + std::vector rb; // second half should be copy of first half. + signed rb_readpos; + signed rb_writepos; + signed rb_in; + + bool hr_used; + SincResampleHR hr; +}; + + +// +// Code: +// +//#include "resample.hpp" + +#if 0 +namespace bit +{ + inline unsigned round(unsigned x) { + if((x & (x - 1)) == 0) return x; + while(x & (x - 1)) x &= x - 1; + return x << 1; + } +} +#endif + +void SincResampleHR::Init(unsigned ratio_arg, double desired_bandwidth, double beta, double d) +{ + const unsigned align_boundary = 16; + std::vector coeffs_tmp; + double cutoff; // 1.0 = f/2 + + ratio = ratio_arg; + + //num_convolutions = ((unsigned)ceil(d / ((1.0 - desired_bandwidth) / ratio)) + 1) &~ 1; // round up to be even + num_convolutions = ((unsigned)ceil(d / ((1.0 - desired_bandwidth) / ratio)) | 1); + + cutoff = (1.0 / ratio) - (d / num_convolutions); + +//printf("%d %d %.20f\n", ratio, num_convolutions, cutoff); + assert(num_convolutions > ratio); + + + // Generate windowed sinc of POWER + coeffs_tmp.resize(num_convolutions); + //ResampleUtility::gen_sinc(&coeffs_tmp[0], num_convolutions, cutoff, beta); + ResampleUtility::gen_sinc_os(&coeffs_tmp[0], num_convolutions, cutoff, beta); + ResampleUtility::normalize(&coeffs_tmp[0], num_convolutions); + + // Copy from coeffs_tmp to coeffs~ + // We multiply many coefficients at a time in the mac loop, so make sure the last few that don't really + // exist are allocated, zero'd mem. + + coeffs_mem.resize(((num_convolutions + 7) &~ 7) * sizeof(resample_coeff_t) + (align_boundary - 1)); + coeffs = (resample_coeff_t *)ResampleUtility::make_aligned(&coeffs_mem[0], align_boundary); + + + for(unsigned i = 0; i < num_convolutions; i++) + coeffs[i] = coeffs_tmp[i]; + + rb_eff_size = nall::bit::round(num_convolutions * 2) >> 1; + rb_readpos = 0; + rb_writepos = 0; + rb_in = 0; + + rb_mem.resize(rb_eff_size * 2 * sizeof(resample_samp_t) + (align_boundary - 1)); + rb = (resample_samp_t *)ResampleUtility::make_aligned(&rb_mem[0], align_boundary); +} + + +inline bool SincResampleHR::output_avail(void) +{ + return(rb_in >= (signed)num_convolutions); +} + +inline void SincResampleHR::write(resample_samp_t sample) +{ + assert(!output_avail()); + + rb[rb_writepos] = sample; + rb[rb_writepos + rb_eff_size] = sample; + rb_writepos = (rb_writepos + 1) & (rb_eff_size - 1); + rb_in++; +} + +resample_samp_t SincResampleHR::mac(const resample_samp_t *wave, const resample_coeff_t *coeff, unsigned count) +{ +#if SINCRESAMPLE_USE_SSE + __m128 accum_veca[2] = { _mm_set1_ps(0), _mm_set1_ps(0) }; + + resample_samp_t accum; + + for(unsigned c = 0; c < count; c += 8) + { + for(unsigned i = 0; i < 2; i++) + { + __m128 co[2]; + __m128 w[2]; + + co[i] = _mm_load_ps(&coeff[c + i * 4]); + w[i] = _mm_load_ps(&wave[c + i * 4]); + + w[i] = _mm_mul_ps(w[i], co[i]); + + accum_veca[i] = _mm_add_ps(w[i], accum_veca[i]); + } + } + + __m128 accum_vec = _mm_add_ps(accum_veca[0], accum_veca[1]); //_mm_add_ps(_mm_add_ps(accum_veca[0], accum_veca[1]), _mm_add_ps(accum_veca[2], accum_veca[3])); + + accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (3 << 0) | (2 << 2) | (1 << 4) | (0 << 6))); + accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (1 << 0) | (0 << 2) | (1 << 4) | (0 << 6))); + + _mm_store_ss(&accum, accum_vec); + + return accum; +#else + resample_samp_t accum[4] = { 0, 0, 0, 0 }; + + for(unsigned c = 0; c < count; c+= 4) + { + accum[0] += wave[c + 0] * coeff[c + 0]; + accum[1] += wave[c + 1] * coeff[c + 1]; + accum[2] += wave[c + 2] * coeff[c + 2]; + accum[3] += wave[c + 3] * coeff[c + 3]; + } + + return (accum[0] + accum[1]) + (accum[2] + accum[3]); // don't mess with parentheses(assuming compiler doesn't already, which it may... + +#endif +} + + +resample_samp_t SincResampleHR::read(void) +{ + assert(output_avail()); + resample_samp_t ret; + + ret = mac(&rb[rb_readpos], &coeffs[0], num_convolutions); + + rb_readpos = (rb_readpos + ratio) & (rb_eff_size - 1); + rb_in -= ratio; + + return ret; +} + + +SincResample::SincResample(double input_rate, double output_rate, double desired_bandwidth, unsigned quality) +{ + const struct + { + double beta; + double d; + unsigned pn_nume; + unsigned phases_min; + } qtab[5] = + { + { 5.658, 3.62, 4096, 4 }, + { 6.764, 4.32, 8192, 4 }, + { 7.865, 5.0, 16384, 8 }, + { 8.960, 5.7, 32768, 16 }, + { 10.056, 6.4, 65536, 32 } + }; + + // Sanity checks + assert(ceil(input_rate) > 0); + assert(ceil(output_rate) > 0); + assert(ceil(input_rate / output_rate) <= 1024); + assert(ceil(output_rate / input_rate) <= 1024); + + // The simplistic number-of-phases calculation code doesn't work well enough for when desired_bandwidth is close to 1.0 and when + // upsampling. + assert(desired_bandwidth >= 0.25 && desired_bandwidth < 0.96); + assert(quality >= 0 && quality <= 4); + + hr_used = false; + +#if 1 + // Round down to the nearest multiple of 4(so wave buffer remains aligned) + // It also adjusts the effective intermediate sampling rate up slightly, so that the upper frequencies below f/2 + // aren't overly attenuated so much. In the future, we might want to do an FFT or something to choose the intermediate rate more accurately + // to virtually eliminate over-attenuation. + unsigned ioratio_rd = (unsigned)floor(input_rate / (output_rate * (1.0 + (1.0 - desired_bandwidth) / 2) )) & ~3; + + if(ioratio_rd >= 8) + { + hr.Init(ioratio_rd, desired_bandwidth, qtab[quality].beta, qtab[quality].d); //10.056, 6.4); + hr_used = true; + + input_rate /= ioratio_rd; + } +#endif + + Init(input_rate, output_rate, desired_bandwidth, qtab[quality].beta, qtab[quality].d, qtab[quality].pn_nume, qtab[quality].phases_min); +} + +void SincResample::Init(double input_rate, double output_rate, double desired_bandwidth, double beta, double d, unsigned pn_nume, unsigned phases_min) +{ + const unsigned max_mult_atatime = 8; // multiply "granularity". must be power of 2. + const unsigned max_mult_minus1 = (max_mult_atatime - 1); + const unsigned conv_alignment_bytes = 16; // must be power of 2 + const double input_to_output_ratio = input_rate / output_rate; + const double output_to_input_ratio = output_rate / input_rate; + double cutoff; // 1.0 = input_rate / 2 + std::vector coeff_init_buffer; + + // Round up num_convolutions to be even. + if(output_rate > input_rate) + num_convolutions = ((unsigned)ceil(d / (1.0 - desired_bandwidth)) + 1) & ~1; + else + num_convolutions = ((unsigned)ceil(d / (output_to_input_ratio * (1.0 - desired_bandwidth))) + 1) & ~1; + + if(output_rate > input_rate) // Upsampling + cutoff = desired_bandwidth; + else // Downsampling + cutoff = output_to_input_ratio * desired_bandwidth; + + // Round up to be even. + num_phases = (std::max(pn_nume / num_convolutions, phases_min) + 1) &~1; + + // Adjust cutoff to account for the multiple phases. + cutoff = cutoff / num_phases; + + assert((num_convolutions & 1) == 0); + assert((num_phases & 1) == 0); + +// fprintf(stderr, "num_convolutions=%u, num_phases=%u, total expected coeff byte size=%lu\n", num_convolutions, num_phases, +// (long)((num_phases + 2) * ((num_convolutions + max_mult_minus1) & ~max_mult_minus1) * sizeof(float) + conv_alignment_bytes)); + + coeff_init_buffer.resize(num_phases * num_convolutions); + + coeffs.resize(num_phases + 1 + 1); + + coeff_mem.resize((num_phases + 1 + 1) * ((num_convolutions + max_mult_minus1) &~ max_mult_minus1) * sizeof(resample_coeff_t) + conv_alignment_bytes); + + // Assign aligned pointers into coeff_mem + { + resample_coeff_t *base_ptr = (resample_coeff_t *)ResampleUtility::make_aligned(&coeff_mem[0], conv_alignment_bytes); + + for(unsigned phase = 0; phase < (num_phases + 1 + 1); phase++) + { + coeffs[phase] = base_ptr + (((num_convolutions + max_mult_minus1) & ~max_mult_minus1) * phase); + } + } + + ResampleUtility::gen_sinc(&coeff_init_buffer[0], num_phases * num_convolutions, cutoff, beta); + ResampleUtility::normalize(&coeff_init_buffer[0], num_phases * num_convolutions, num_phases); + + // Reorder coefficients to allow for more efficient convolution. + for(int phase = -1; phase < ((int)num_phases + 1); phase++) + { + for(int conv = 0; conv < (int)num_convolutions; conv++) + { + double coeff; + + if(phase == -1 && conv == 0) + coeff = 0; + else if(phase == (int)num_phases && conv == ((int)num_convolutions - 1)) + coeff = 0; + else + coeff = coeff_init_buffer[conv * num_phases + phase]; + + coeffs[phase + 1][conv] = coeff; + } + } + + // Free a bit of mem + coeff_init_buffer.resize(0); + + step_int = floor(input_to_output_ratio); + step_fract = input_to_output_ratio - step_int; + + input_pos_fract = 0; + + // Do NOT use rb.size() later in the code, since it'll include the padding. + // We should only need one "max_mult_minus1" here, not two, since it won't matter if it over-reads(due to doing "max_mult_atatime" multiplications at a time + // rather than just 1, in which case this over-read wouldn't happen), from the first half into the duplicated half, + // since those corresponding coefficients will be zero anyway; this is just to handle the case of reading off the end of the duplicated half to + // prevent illegal memory accesses. + rb.resize(num_convolutions * 2 + max_mult_minus1); + + rb_readpos = 0; + rb_writepos = 0; + rb_in = 0; +} + +resample_samp_t SincResample::mac(const resample_samp_t *wave, const resample_coeff_t *coeffs_a, const resample_coeff_t *coeffs_b, const double ffract, unsigned count) +{ + resample_samp_t accum = 0; +#if SINCRESAMPLE_USE_SSE + __m128 accum_vec_a[2] = { _mm_set1_ps(0), _mm_set1_ps(0) }; + __m128 accum_vec_b[2] = { _mm_set1_ps(0), _mm_set1_ps(0) }; + + for(unsigned c = 0; c < count; c += 8) //8) //4) + { + __m128 coeff_a[2]; + __m128 coeff_b[2]; + __m128 w[2]; + __m128 result_a[2], result_b[2]; + + for(unsigned i = 0; i < 2; i++) + { + coeff_a[i] = _mm_load_ps(&coeffs_a[c + (i * 4)]); + coeff_b[i] = _mm_load_ps(&coeffs_b[c + (i * 4)]); + w[i] = _mm_loadu_ps(&wave[c + (i * 4)]); + + result_a[i] = _mm_mul_ps(coeff_a[i], w[i]); + result_b[i] = _mm_mul_ps(coeff_b[i], w[i]); + + accum_vec_a[i] = _mm_add_ps(result_a[i], accum_vec_a[i]); + accum_vec_b[i] = _mm_add_ps(result_b[i], accum_vec_b[i]); + } + } + + __m128 accum_vec, av_a, av_b; + __m128 mult_a_vec = _mm_set1_ps(1.0 - ffract); + __m128 mult_b_vec = _mm_set1_ps(ffract); + + av_a = _mm_mul_ps(mult_a_vec, /*accum_vec_a[0]);*/ _mm_add_ps(accum_vec_a[0], accum_vec_a[1])); + av_b = _mm_mul_ps(mult_b_vec, /*accum_vec_b[0]);*/ _mm_add_ps(accum_vec_b[0], accum_vec_b[1])); + + accum_vec = _mm_add_ps(av_a, av_b); + + accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (3 << 0) | (2 << 2) | (1 << 4) | (0 << 6))); + accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (1 << 0) | (0 << 2) | (1 << 4) | (0 << 6))); + + _mm_store_ss(&accum, accum_vec); +#else + resample_coeff_t mult_a = 1.0 - ffract; + resample_coeff_t mult_b = ffract; + + for(unsigned c = 0; c < count; c += 4) + { + accum += wave[c + 0] * (coeffs_a[c + 0] * mult_a + coeffs_b[c + 0] * mult_b); + accum += wave[c + 1] * (coeffs_a[c + 1] * mult_a + coeffs_b[c + 1] * mult_b); + accum += wave[c + 2] * (coeffs_a[c + 2] * mult_a + coeffs_b[c + 2] * mult_b); + accum += wave[c + 3] * (coeffs_a[c + 3] * mult_a + coeffs_b[c + 3] * mult_b); + } +#endif + + return accum; +} + +inline bool SincResample::output_avail(void) +{ + return(rb_in >= (int)num_convolutions); +} + +resample_samp_t SincResample::read(void) +{ + assert(output_avail()); + double phase = input_pos_fract * num_phases - 0.5; + signed phase_int = (signed)floor(phase); + double phase_fract = phase - phase_int; + unsigned phase_a = num_phases - 1 - phase_int; + unsigned phase_b = phase_a - 1; + resample_samp_t ret; + + ret = mac(&rb[rb_readpos], &coeffs[phase_a + 1][0], &coeffs[phase_b + 1][0], phase_fract, num_convolutions); + + unsigned int_increment = step_int; + + input_pos_fract += step_fract; + int_increment += floor(input_pos_fract); + input_pos_fract -= floor(input_pos_fract); + + rb_readpos = (rb_readpos + int_increment) % num_convolutions; + rb_in -= int_increment; + + return ret; +} + +inline void SincResample::write(resample_samp_t sample) +{ + assert(!output_avail()); + + if(hr_used) + { + hr.write(sample); + + if(hr.output_avail()) + { + sample = hr.read(); + } + else + { + return; + } + } + + rb[rb_writepos + 0 * num_convolutions] = sample; + rb[rb_writepos + 1 * num_convolutions] = sample; + rb_writepos = (rb_writepos + 1) % num_convolutions; + rb_in++; +} + +void ResampleUtility::kaiser_window( double* io, int count, double beta) +{ + int const accuracy = 24; //16; //12; + + double* end = io + count; + + double beta2 = beta * beta * (double) -0.25; + double to_fract = beta2 / ((double) count * count); + double i = 0; + double rescale = 0; // Doesn't need an initializer, to shut up gcc + + for ( ; io < end; ++io, i += 1 ) + { + double x = i * i * to_fract - beta2; + double u = x; + double k = x + 1; + + double n = 2; + do + { + u *= x / (n * n); + n += 1; + k += u; + } + while ( k <= u * (1 << accuracy) ); + + if ( !i ) + rescale = 1 / k; // otherwise values get large + + *io *= k * rescale; + } +} + +void ResampleUtility::gen_sinc(double* out, int size, double cutoff, double kaiser) +{ + assert( size % 2 == 0 ); // size must be even + + int const half_size = size / 2; + double* const mid = &out [half_size]; + + // Generate right half of sinc + for ( int i = 0; i < half_size; i++ ) + { + double angle = (i * 2 + 1) * (M_PI / 2); + mid [i] = sin( angle * cutoff ) / angle; + } + + kaiser_window( mid, half_size, kaiser ); + + // Mirror for left half + for ( int i = 0; i < half_size; i++ ) + out [i] = mid [half_size - 1 - i]; +} + +void ResampleUtility::gen_sinc_os(double* out, int size, double cutoff, double kaiser) +{ + assert( size % 2 == 1); // size must be odd + + for(int i = 0; i < size; i++) + { + if(i == (size / 2)) + out[i] = 2 * M_PI * (cutoff / 2); //0.078478; //1.0; //sin(2 * M_PI * (cutoff / 2) * (i - size / 2)) / (i - (size / 2)); + else + out[i] = sin(2 * M_PI * (cutoff / 2) * (i - size / 2)) / (i - (size / 2)); + +// out[i] *= 0.3635819 - 0.4891775 * cos(2 * M_PI * i / (size - 1)) + 0.1365995 * cos(4 * M_PI * i / (size - 1)) - 0.0106411 * cos(6 * M_PI * i / (size - 1)); +//0.42 - 0.5 * cos(2 * M_PI * i / (size - 1)) + 0.08 * cos(4 * M_PI * i / (size - 1)); + +// printf("%d %f\n", i, out[i]); + } + + kaiser_window(&out[size / 2], size / 2 + 1, kaiser); + + // Mirror for left half + for ( int i = 0; i < size / 2; i++ ) + out [i] = out [size - 1 - i]; + +} + +void ResampleUtility::normalize(double* io, int size, double gain) +{ + double sum = 0; + for ( int i = 0; i < size; i++ ) + sum += io [i]; + + double scale = gain / sum; + for ( int i = 0; i < size; i++ ) + io [i] *= scale; +} + +void* ResampleUtility::make_aligned(void* ptr, unsigned boundary) +{ + unsigned char* null_ptr = (unsigned char *)NULL; + unsigned char* uc_ptr = (unsigned char *)ptr; + + uc_ptr += (boundary - ((uc_ptr - null_ptr) & (boundary - 1))) & (boundary - 1); + + //while((uc_ptr - null_ptr) & (boundary - 1)) + // uc_ptr++; + + //printf("%16llx %16llx\n", (unsigned long long)ptr, (unsigned long long)uc_ptr); + + assert((uc_ptr - (unsigned char *)ptr) < boundary && (uc_ptr >= (unsigned char *)ptr)); + + return uc_ptr; +} diff --git a/snesfilter/nall/dsp/resample/linear.hpp b/snesfilter/nall/dsp/resample/linear.hpp index 3dbda6a0..3c2dc9e6 100755 --- a/snesfilter/nall/dsp/resample/linear.hpp +++ b/snesfilter/nall/dsp/resample/linear.hpp @@ -1,24 +1,43 @@ #ifdef NALL_DSP_INTERNAL_HPP -void DSP::resampleLinear() { - while(resampler.fraction <= 1.0) { - double channel[settings.channels]; +struct ResampleLinear : Resampler { + inline void setFrequency(); + inline void clear(); + inline void sample(); + ResampleLinear(DSP &dsp) : Resampler(dsp) {} - for(unsigned n = 0; n < settings.channels; n++) { - double a = buffer.read(n, -1); - double b = buffer.read(n, -0); + real fraction; + real step; +}; - double mu = resampler.fraction; +void ResampleLinear::setFrequency() { + fraction = 0.0; + step = dsp.settings.frequency / frequency; +} + +void ResampleLinear::clear() { + fraction = 0.0; +} + +void ResampleLinear::sample() { + while(fraction <= 1.0) { + real channel[dsp.settings.channels]; + + for(unsigned n = 0; n < dsp.settings.channels; n++) { + real a = dsp.buffer.read(n, -1); + real b = dsp.buffer.read(n, -0); + + real mu = fraction; channel[n] = a * (1.0 - mu) + b * mu; } - resamplerWrite(channel); - resampler.fraction += resampler.step; + dsp.write(channel); + fraction += step; } - buffer.rdoffset++; - resampler.fraction -= 1.0; + dsp.buffer.rdoffset++; + fraction -= 1.0; } #endif diff --git a/snesfilter/nall/dsp/resample/nearest.hpp b/snesfilter/nall/dsp/resample/nearest.hpp new file mode 100755 index 00000000..14b401eb --- /dev/null +++ b/snesfilter/nall/dsp/resample/nearest.hpp @@ -0,0 +1,43 @@ +#ifdef NALL_DSP_INTERNAL_HPP + +struct ResampleNearest : Resampler { + inline void setFrequency(); + inline void clear(); + inline void sample(); + ResampleNearest(DSP &dsp) : Resampler(dsp) {} + + real fraction; + real step; +}; + +void ResampleNearest::setFrequency() { + fraction = 0.0; + step = dsp.settings.frequency / frequency; +} + +void ResampleNearest::clear() { + fraction = 0.0; +} + +void ResampleNearest::sample() { + while(fraction <= 1.0) { + real channel[dsp.settings.channels]; + + for(unsigned n = 0; n < dsp.settings.channels; n++) { + real a = dsp.buffer.read(n, -1); + real b = dsp.buffer.read(n, -0); + + real mu = fraction; + + channel[n] = mu < 0.5 ? a : b; + } + + dsp.write(channel); + fraction += step; + } + + dsp.buffer.rdoffset++; + fraction -= 1.0; +} + +#endif diff --git a/snesfilter/nall/dsp/resample/sinc.hpp b/snesfilter/nall/dsp/resample/sinc.hpp new file mode 100755 index 00000000..a77a1eeb --- /dev/null +++ b/snesfilter/nall/dsp/resample/sinc.hpp @@ -0,0 +1,54 @@ +#ifdef NALL_DSP_INTERNAL_HPP + +#include "lib/sinc.hpp" + +struct ResampleSinc : Resampler { + inline void setFrequency(); + inline void clear(); + inline void sample(); + inline ResampleSinc(DSP &dsp); + +private: + inline void remakeSinc(); + SincResample *sinc_resampler[8]; +}; + +void ResampleSinc::setFrequency() { + remakeSinc(); +} + +void ResampleSinc::clear() { + remakeSinc(); +} + +void ResampleSinc::sample() { + for(unsigned c = 0; c < dsp.settings.channels; c++) { + sinc_resampler[c]->write(dsp.buffer.read(c)); + } + + if(sinc_resampler[0]->output_avail()) { + do { + for(unsigned c = 0; c < dsp.settings.channels; c++) { + dsp.output.write(c) = sinc_resampler[c]->read(); + } + dsp.output.wroffset++; + } while(sinc_resampler[0]->output_avail()); + } + + dsp.buffer.rdoffset++; +} + +ResampleSinc::ResampleSinc(DSP &dsp) : Resampler(dsp) { + for(unsigned n = 0; n < 8; n++) sinc_resampler[n] = 0; +} + +void ResampleSinc::remakeSinc() { + assert(dsp.settings.channels < 8); + + for(unsigned c = 0; c < dsp.settings.channels; c++) { + if(sinc_resampler[c]) delete sinc_resampler[c]; + sinc_resampler[c] = new SincResample(dsp.settings.frequency, frequency, 0.85, SincResample::QUALITY_HIGH); + } +} + +#endif diff --git a/snesfilter/nall/dsp/settings.hpp b/snesfilter/nall/dsp/settings.hpp index dc422e39..3a8f24c6 100755 --- a/snesfilter/nall/dsp/settings.hpp +++ b/snesfilter/nall/dsp/settings.hpp @@ -10,30 +10,41 @@ void DSP::setChannels(unsigned channels) { void DSP::setPrecision(unsigned precision) { settings.precision = precision; settings.intensity = 1 << (settings.precision - 1); + settings.intensityInverse = 1.0 / settings.intensity; } -void DSP::setFrequency(double frequency) { +void DSP::setFrequency(real frequency) { settings.frequency = frequency; - resampler.fraction = 0; - resampler.step = settings.frequency / resampler.frequency; + resampler->setFrequency(); } -void DSP::setVolume(double volume) { +void DSP::setVolume(real volume) { settings.volume = volume; } -void DSP::setBalance(double balance) { +void DSP::setBalance(real balance) { settings.balance = balance; } -void DSP::setResampler(Resampler engine) { - resampler.engine = engine; +void DSP::setResampler(ResampleEngine engine) { + if(resampler) delete resampler; + + switch(engine) { + case ResampleEngine::Nearest: resampler = new ResampleNearest(*this); return; + case ResampleEngine::Linear: resampler = new ResampleLinear (*this); return; + case ResampleEngine::Cosine: resampler = new ResampleCosine (*this); return; + case ResampleEngine::Cubic: resampler = new ResampleCubic (*this); return; + case ResampleEngine::Hermite: resampler = new ResampleHermite(*this); return; + case ResampleEngine::Average: resampler = new ResampleAverage(*this); return; + case ResampleEngine::Sinc: resampler = new ResampleSinc (*this); return; + } + + throw; } -void DSP::setResamplerFrequency(double frequency) { - resampler.frequency = frequency; - resampler.fraction = 0; - resampler.step = settings.frequency / resampler.frequency; +void DSP::setResamplerFrequency(real frequency) { + resampler->frequency = frequency; + resampler->setFrequency(); } #endif diff --git a/snesfilter/nall/endian.hpp b/snesfilter/nall/endian.hpp index 40d15633..1f834b5b 100755 --- a/snesfilter/nall/endian.hpp +++ b/snesfilter/nall/endian.hpp @@ -1,7 +1,9 @@ #ifndef NALL_ENDIAN_HPP #define NALL_ENDIAN_HPP -#if !defined(ARCH_MSB) +#include + +#if defined(ENDIAN_LSB) //little-endian: uint8_t[] { 0x01, 0x02, 0x03, 0x04 } == 0x04030201 #define order_lsb2(a,b) a,b #define order_lsb3(a,b,c) a,b,c @@ -17,7 +19,7 @@ #define order_msb6(a,b,c,d,e,f) f,e,d,c,b,a #define order_msb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a #define order_msb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a -#else +#elif defined(ENDIAN_MSB) //big-endian: uint8_t[] { 0x01, 0x02, 0x03, 0x04 } == 0x01020304 #define order_lsb2(a,b) b,a #define order_lsb3(a,b,c) c,b,a @@ -33,6 +35,8 @@ #define order_msb6(a,b,c,d,e,f) a,b,c,d,e,f #define order_msb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g #define order_msb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h +#else + #error "Unknown endian. Please specify in nall/intrinsics.hpp" #endif #endif diff --git a/snesfilter/nall/function.hpp b/snesfilter/nall/function.hpp index 35b76881..ca574b8c 100755 --- a/snesfilter/nall/function.hpp +++ b/snesfilter/nall/function.hpp @@ -36,19 +36,19 @@ namespace nall { public: operator bool() const { return callback; } R operator()(P... p) const { return (*callback)(std::forward

(p)...); } - void reset() { if(callback) { delete callback; callback = 0; } } + void reset() { if(callback) { delete callback; callback = nullptr; } } function& operator=(const function &source) { if(this != &source) { - if(callback) { delete callback; callback = 0; } + if(callback) { delete callback; callback = nullptr; } if(source.callback) callback = source.callback->copy(); } return *this; } - 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(const function &source) : callback(nullptr) { operator=(source); } + function() : callback(nullptr) {} + function(void *function) : callback(nullptr) { if(function) callback = new global((R (*)(P...))function); } function(R (*function)(P...)) { callback = new global(function); } template function(R (C::*function)(P...), C *object) { callback = new member(function, object); } template function(R (C::*function)(P...) const, C *object) { callback = new member((R (C::*)(P...))function, object); } diff --git a/snesfilter/nall/gameboy/cartridge.hpp b/snesfilter/nall/gameboy/cartridge.hpp index af04e0bb..19ff065d 100755 --- a/snesfilter/nall/gameboy/cartridge.hpp +++ b/snesfilter/nall/gameboy/cartridge.hpp @@ -5,7 +5,7 @@ namespace nall { class GameBoyCartridge { public: - string xml; + string markup; inline GameBoyCartridge(uint8_t *data, unsigned size); //private: @@ -22,7 +22,7 @@ public: }; GameBoyCartridge::GameBoyCartridge(uint8_t *romdata, unsigned romsize) { - xml = "\n"; + markup = ""; if(romsize < 0x4000) return; info.mapper = "unknown"; @@ -100,18 +100,15 @@ GameBoyCartridge::GameBoyCartridge(uint8_t *romdata, unsigned romsize) { if(info.mapper == "MBC2") info.ramsize = 512; //512 x 4-bit - xml.append("\n"); + markup.append("cartridge mapper=", info.mapper); + if(info.rtc) markup.append(" rtc"); + if(info.rumble) markup.append(" rumble"); + markup.append("\n"); - xml.append(" \n"); //TODO: trust/check info.romsize? + markup.append("\t" "rom size=", hex(romsize), "\n"); //TODO: trust/check info.romsize? if(info.ramsize > 0) - xml.append(" \n"); - - xml.append("\n"); - xml.transform("'", "\""); + markup.append("\t" "ram size=", hex(info.ramsize), info.battery ? " non-volatile\n" : "\n"); } } diff --git a/snesfilter/nall/gzip.hpp b/snesfilter/nall/gzip.hpp index 635d3277..8f5d206b 100755 --- a/snesfilter/nall/gzip.hpp +++ b/snesfilter/nall/gzip.hpp @@ -75,7 +75,7 @@ bool gzip::decompress(const uint8_t *data, unsigned size) { return inflate(this->data, this->size, data + p, size - p - 8); } -gzip::gzip() : data(0) { +gzip::gzip() : data(nullptr) { } gzip::~gzip() { diff --git a/snesfilter/nall/image.hpp b/snesfilter/nall/image.hpp new file mode 100755 index 00000000..c79655eb --- /dev/null +++ b/snesfilter/nall/image.hpp @@ -0,0 +1,433 @@ +#ifndef NALL_IMAGE_HPP +#define NALL_IMAGE_HPP + +#include +#include +#include +#include +#include + +namespace nall { + +struct image { + uint8_t *data; + unsigned width; + unsigned height; + unsigned pitch; + + bool endian; //0 = little, 1 = big + unsigned depth; + unsigned stride; + + struct Channel { + uint64_t mask; + unsigned depth; + unsigned shift; + } alpha, red, green, blue; + + typedef double (*interpolation)(double, double, double, double, double); + static inline unsigned bitDepth(uint64_t color); + static inline unsigned bitShift(uint64_t color); + static inline uint64_t normalize(uint64_t color, unsigned sourceDepth, unsigned targetDepth); + + inline image& operator=(const image &source); + inline image& operator=(image &&source); + inline image(const image &source); + inline image(image &&source); + inline image(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask); + inline ~image(); + + inline uint64_t read(const uint8_t *data) const; + inline void write(uint8_t *data, uint64_t value) const; + + inline void free(); + inline void allocate(unsigned width, unsigned height); + inline bool load(const string &filename); + inline void scale(unsigned width, unsigned height, interpolation op); + inline void transform(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask); + inline void alphaBlend(uint64_t alphaColor); + +protected: + inline uint64_t interpolate(double mu, const uint64_t *s, interpolation op); + inline void scaleX(unsigned width, interpolation op); + inline void scaleY(unsigned height, interpolation op); + inline bool loadBMP(const string &filename); + inline bool loadPNG(const string &filename); +}; + +//static + +unsigned image::bitDepth(uint64_t color) { + unsigned depth = 0; + if(color) while((color & 1) == 0) color >>= 1; + while((color & 1) == 1) { color >>= 1; depth++; } + return depth; +} + +unsigned image::bitShift(uint64_t color) { + unsigned shift = 0; + if(color) while((color & 1) == 0) { color >>= 1; shift++; } + return shift; +} + +uint64_t image::normalize(uint64_t color, unsigned sourceDepth, unsigned targetDepth) { + while(sourceDepth < targetDepth) { + color = (color << sourceDepth) | color; + sourceDepth += sourceDepth; + } + if(targetDepth < sourceDepth) color >>= (sourceDepth - targetDepth); + return color; +} + +//public + +image& image::operator=(const image &source) { + free(); + + width = source.width; + height = source.height; + pitch = source.pitch; + + endian = source.endian; + stride = source.stride; + + alpha = source.alpha; + red = source.red; + green = source.green; + blue = source.blue; + + data = new uint8_t[width * height * stride]; + memcpy(data, source.data, width * height * stride); + return *this; +} + +image& image::operator=(image &&source) { + width = source.width; + height = source.height; + pitch = source.pitch; + + endian = source.endian; + stride = source.stride; + + alpha = source.alpha; + red = source.red; + green = source.green; + blue = source.blue; + + data = source.data; + source.data = nullptr; + return *this; +} + +image::image(const image &source) : data(nullptr) { + operator=(source); +} + +image::image(image &&source) : data(nullptr) { + operator=(std::forward(source)); +} + +image::image(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask) : data(nullptr) { + width = 0, height = 0, pitch = 0; + + this->endian = endian; + this->depth = depth; + this->stride = (depth / 8) + ((depth & 7) > 0); + + alpha.mask = alphaMask, red.mask = redMask, green.mask = greenMask, blue.mask = blueMask; + alpha.depth = bitDepth(alpha.mask), alpha.shift = bitShift(alpha.mask); + red.depth = bitDepth(red.mask), red.shift = bitShift(red.mask); + green.depth = bitDepth(green.mask), green.shift = bitShift(green.mask); + blue.depth = bitDepth(blue.mask), blue.shift = bitShift(blue.mask); +} + +image::~image() { + free(); +} + +uint64_t image::read(const uint8_t *data) const { + uint64_t result = 0; + if(endian == 0) { + for(signed n = stride - 1; n >= 0; n--) result = (result << 8) | data[n]; + } else { + for(signed n = 0; n < stride; n++) result = (result << 8) | data[n]; + } + return result; +} + +void image::write(uint8_t *data, uint64_t value) const { + if(endian == 0) { + for(signed n = 0; n < stride; n++) { data[n] = value; value >>= 8; } + } else { + for(signed n = stride - 1; n >= 0; n--) { data[n] = value; value >>= 8; } + } +} + +void image::free() { + if(data) delete[] data; + data = nullptr; +} + +void image::allocate(unsigned width, unsigned height) { + free(); + data = new uint8_t[width * height * stride](); + pitch = width * stride; + this->width = width; + this->height = height; +} + +bool image::load(const string &filename) { + if(loadBMP(filename) == true) return true; + if(loadPNG(filename) == true) return true; + return false; +} + +void image::scale(unsigned outputWidth, unsigned outputHeight, interpolation op) { + scaleX(outputWidth, op); + scaleY(outputHeight, op); +} + +void image::transform(bool outputEndian, unsigned outputDepth, uint64_t outputAlphaMask, uint64_t outputRedMask, uint64_t outputGreenMask, uint64_t outputBlueMask) { + image output(outputEndian, outputDepth, outputAlphaMask, outputRedMask, outputGreenMask, outputBlueMask); + output.allocate(width, height); + + #pragma omp parallel for + for(unsigned y = 0; y < height; y++) { + uint8_t *dp = output.data + output.pitch * y; + uint8_t *sp = data + pitch * y; + for(unsigned x = 0; x < width; x++) { + uint64_t color = read(sp); + sp += stride; + + uint64_t a = (color & alpha.mask) >> alpha.shift; + uint64_t r = (color & red.mask) >> red.shift; + uint64_t g = (color & green.mask) >> green.shift; + uint64_t b = (color & blue.mask) >> blue.shift; + + a = normalize(a, alpha.depth, output.alpha.depth); + r = normalize(r, red.depth, output.red.depth); + g = normalize(g, green.depth, output.green.depth); + b = normalize(b, blue.depth, output.blue.depth); + + output.write(dp, (a << output.alpha.shift) + (r << output.red.shift) + (g << output.green.shift) + (b << output.blue.shift)); + dp += output.stride; + } + } + + operator=(std::move(output)); +} + +void image::alphaBlend(uint64_t alphaColor) { + uint64_t alphaR = (alphaColor & red.mask) >> red.shift; + uint64_t alphaG = (alphaColor & green.mask) >> green.shift; + uint64_t alphaB = (alphaColor & blue.mask) >> blue.shift; + + #pragma omp parallel for + for(unsigned y = 0; y < height; y++) { + uint8_t *dp = data + pitch * y; + for(unsigned x = 0; x < width; x++) { + uint64_t color = read(dp); + + uint64_t colorA = (color & alpha.mask) >> alpha.shift; + uint64_t colorR = (color & red.mask) >> red.shift; + uint64_t colorG = (color & green.mask) >> green.shift; + uint64_t colorB = (color & blue.mask) >> blue.shift; + double alphaScale = (double)colorA / (double)((1 << alpha.depth) - 1); + + colorA = (1 << alpha.depth) - 1; + colorR = (colorR * alphaScale) + (alphaR * (1.0 - alphaScale)); + colorG = (colorG * alphaScale) + (alphaG * (1.0 - alphaScale)); + colorB = (colorB * alphaScale) + (alphaB * (1.0 - alphaScale)); + + write(dp, (colorA << alpha.shift) + (colorR << red.shift) + (colorG << green.shift) + (colorB << blue.shift)); + dp += stride; + } + } +} + +//protected + +uint64_t image::interpolate(double mu, const uint64_t *s, double (*op)(double, double, double, double, double)) { + uint64_t aa = (s[0] & alpha.mask) >> alpha.shift, ar = (s[0] & red.mask) >> red.shift, + ag = (s[0] & green.mask) >> green.shift, ab = (s[0] & blue.mask) >> blue.shift; + uint64_t ba = (s[1] & alpha.mask) >> alpha.shift, br = (s[1] & red.mask) >> red.shift, + bg = (s[1] & green.mask) >> green.shift, bb = (s[1] & blue.mask) >> blue.shift; + uint64_t ca = (s[2] & alpha.mask) >> alpha.shift, cr = (s[2] & red.mask) >> red.shift, + cg = (s[2] & green.mask) >> green.shift, cb = (s[2] & blue.mask) >> blue.shift; + uint64_t da = (s[3] & alpha.mask) >> alpha.shift, dr = (s[3] & red.mask) >> red.shift, + dg = (s[3] & green.mask) >> green.shift, db = (s[3] & blue.mask) >> blue.shift; + + int64_t A = op(mu, aa, ba, ca, da); + int64_t R = op(mu, ar, br, cr, dr); + int64_t G = op(mu, ag, bg, cg, dg); + int64_t B = op(mu, ab, bb, cb, db); + + A = max(0, min(A, (1 << alpha.depth) - 1)); + R = max(0, min(R, (1 << red.depth) - 1)); + G = max(0, min(G, (1 << green.depth) - 1)); + B = max(0, min(B, (1 << blue.depth) - 1)); + + return (A << alpha.shift) + (R << red.shift) + (G << green.shift) + (B << blue.shift); +} + +void image::scaleX(unsigned outputWidth, interpolation op) { + uint8_t *outputData = new uint8_t[outputWidth * height * stride]; + unsigned outputPitch = outputWidth * stride; + double step = (double)width / (double)outputWidth; + + #pragma omp parallel for + for(unsigned y = 0; y < height; y++) { + uint8_t *dp = outputData + outputPitch * y; + uint8_t *sp = data + pitch * y; + + double fraction = 0.0; + uint64_t s[4] = { read(sp), read(sp), read(sp), read(sp) }; + + for(unsigned x = 0; x < width; x++) { + if(sp >= data + pitch * height) break; + s[0] = s[1]; + s[1] = s[2]; + s[2] = s[3]; + s[3] = read(sp); + + while(fraction <= 1.0) { + if(dp >= outputData + outputPitch * height) break; + write(dp, interpolate(fraction, (const uint64_t*)&s, op)); + dp += stride; + fraction += step; + } + + sp += stride; + fraction -= 1.0; + } + } + + free(); + data = outputData; + width = outputWidth; + pitch = width * stride; +} + +void image::scaleY(unsigned outputHeight, interpolation op) { + uint8_t *outputData = new uint8_t[width * outputHeight * stride]; + double step = (double)height / (double)outputHeight; + + #pragma omp parallel for + for(unsigned x = 0; x < width; x++) { + uint8_t *dp = outputData + stride * x; + uint8_t *sp = data + stride * x; + + double fraction = 0.0; + uint64_t s[4] = { read(sp), read(sp), read(sp), read(sp) }; + + for(unsigned y = 0; y < height; y++) { + if(sp >= data + pitch * height) break; + s[0] = s[1]; + s[1] = s[2]; + s[2] = s[3]; + s[3] = read(sp); + + while(fraction <= 1.0) { + if(dp >= outputData + pitch * outputHeight) break; + write(dp, interpolate(fraction, (const uint64_t*)&s, op)); + dp += pitch; + fraction += step; + } + + sp += pitch; + fraction -= 1.0; + } + } + + free(); + data = outputData; + height = outputHeight; +} + +bool image::loadBMP(const string &filename) { + uint32_t *outputData; + unsigned outputWidth, outputHeight; + if(bmp::read(filename, outputData, outputWidth, outputHeight) == false) return false; + + allocate(outputWidth, outputHeight); + const uint32_t *sp = outputData; + uint8_t *dp = data; + + for(unsigned y = 0; y < outputHeight; y++) { + for(unsigned x = 0; x < outputWidth; x++) { + uint32_t color = *sp++; + uint64_t a = normalize((uint8_t)(color >> 24), 8, alpha.depth); + uint64_t r = normalize((uint8_t)(color >> 16), 8, red.depth); + uint64_t g = normalize((uint8_t)(color >> 8), 8, green.depth); + uint64_t b = normalize((uint8_t)(color >> 0), 8, blue.depth); + write(dp, (a << alpha.shift) + (r << red.shift) + (g << green.shift) + (b << blue.shift)); + dp += stride; + } + } + + delete[] outputData; + return true; +} + +bool image::loadPNG(const string &filename) { + png source; + if(source.decode(filename) == false) return false; + + allocate(source.info.width, source.info.height); + const uint8_t *sp = source.data; + uint8_t *dp = data; + + auto decode = [&]() -> uint64_t { + uint64_t p, r, g, b, a; + + switch(source.info.colorType) { + case 0: //L + r = g = b = source.readbits(sp); + a = (1 << source.info.bitDepth) - 1; + break; + case 2: //R,G,B + r = source.readbits(sp); + g = source.readbits(sp); + b = source.readbits(sp); + a = (1 << source.info.bitDepth) - 1; + break; + case 3: //P + p = source.readbits(sp); + r = source.info.palette[p][0]; + g = source.info.palette[p][1]; + b = source.info.palette[p][2]; + a = (1 << source.info.bitDepth) - 1; + break; + case 4: //L,A + r = g = b = source.readbits(sp); + a = source.readbits(sp); + break; + case 6: //R,G,B,A + r = source.readbits(sp); + g = source.readbits(sp); + b = source.readbits(sp); + a = source.readbits(sp); + break; + } + + a = normalize(a, source.info.bitDepth, alpha.depth); + r = normalize(r, source.info.bitDepth, red.depth); + g = normalize(g, source.info.bitDepth, green.depth); + b = normalize(b, source.info.bitDepth, blue.depth); + + return (a << alpha.shift) + (r << red.shift) + (g << green.shift) + (b << blue.shift); + }; + + for(unsigned y = 0; y < height; y++) { + for(unsigned x = 0; x < width; x++) { + write(dp, decode()); + dp += stride; + } + } + + return true; +} + +} + +#endif diff --git a/snesfilter/nall/inflate.hpp b/snesfilter/nall/inflate.hpp index c989e3f1..cbbf6d29 100755 --- a/snesfilter/nall/inflate.hpp +++ b/snesfilter/nall/inflate.hpp @@ -199,17 +199,17 @@ inline int codes(state *s, huffman *lencode, huffman *distcode) { symbol = decode(s, distcode); if(symbol < 0) return symbol; dist = dists[symbol] + bits(s, dext[symbol]); -#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR + #ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR if(dist > s->outcnt) return -11; -#endif + #endif if(s->out != 0) { if(s->outcnt + len > s->outlen) return 1; while(len--) { s->out[s->outcnt] = -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR + #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR dist > s->outcnt ? 0 : -#endif + #endif s->out[s->outcnt - dist]; s->outcnt++; } diff --git a/snesfilter/nall/interpolation.hpp b/snesfilter/nall/interpolation.hpp new file mode 100755 index 00000000..46a09a49 --- /dev/null +++ b/snesfilter/nall/interpolation.hpp @@ -0,0 +1,59 @@ +#ifndef NALL_INTERPOLATION_HPP +#define NALL_INTERPOLATION_HPP + +namespace nall { + +struct Interpolation { + static inline double Nearest(double mu, double a, double b, double c, double d) { + return (mu < 0.5 ? c : d); + } + + static inline double Sublinear(double mu, double a, double b, double c, double d) { + mu = ((mu - 0.5) * 2.0) + 0.5; + if(mu < 0) mu = 0; + if(mu > 1) mu = 1; + return c * (1.0 - mu) + d * mu; + } + + static inline double Linear(double mu, double a, double b, double c, double d) { + return c * (1.0 - mu) + d * mu; + } + + static inline double Cosine(double mu, double a, double b, double c, double d) { + mu = (1.0 - cos(mu * 3.14159265)) / 2.0; + return c * (1.0 - mu) + d * mu; + } + + static inline double Cubic(double mu, double a, double b, double c, double d) { + double A = d - c - a + b; + double B = a - b - A; + double C = c - a; + double D = b; + return A * (mu * mu * mu) + B * (mu * mu) + C * mu + D; + } + + static inline double Hermite(double mu1, double a, double b, double c, double d) { + const double tension = 0.0; //-1 = low, 0 = normal, +1 = high + const double bias = 0.0; //-1 = left, 0 = even, +1 = right + double mu2, mu3, m0, m1, a0, a1, a2, a3; + + mu2 = mu1 * mu1; + mu3 = mu2 * mu1; + + m0 = (b - a) * (1.0 + bias) * (1.0 - tension) / 2.0; + m0 += (c - b) * (1.0 - bias) * (1.0 - tension) / 2.0; + m1 = (c - b) * (1.0 + bias) * (1.0 - tension) / 2.0; + m1 += (d - c) * (1.0 - bias) * (1.0 - tension) / 2.0; + + a0 = +2 * mu3 - 3 * mu2 + 1; + a1 = mu3 - 2 * mu2 + mu1; + a2 = mu3 - mu2; + a3 = -2 * mu3 + 3 * mu2; + + return (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c); + } +}; + +} + +#endif diff --git a/snesfilter/nall/intrinsics.hpp b/snesfilter/nall/intrinsics.hpp new file mode 100755 index 00000000..413ef593 --- /dev/null +++ b/snesfilter/nall/intrinsics.hpp @@ -0,0 +1,63 @@ +#ifndef NALL_INTRINSICS_HPP +#define NALL_INTRINSICS_HPP + +struct Intrinsics { + enum class Compiler : unsigned { GCC, VisualC, Unknown }; + enum class Platform : unsigned { X, OSX, Windows, Unknown }; + enum class Endian : unsigned { LSB, MSB, Unknown }; + + static inline Compiler compiler(); + static inline Platform platform(); + static inline Endian endian(); +}; + +/* Compiler detection */ + +#if defined(__GNUC__) + #define COMPILER_GCC + Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::GCC; } +#elif defined(_MSC_VER) + #define COMPILER_VISUALC + Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::VisualC; } +#else + #warning "unable to detect compiler" + #define COMPILER_UNKNOWN + Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::Unknown; } +#endif + +/* Platform detection */ + +#if defined(linux) || defined(__sun__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) + #define PLATFORM_X + Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::X; } +#elif defined(__APPLE__) + #define PLATFORM_OSX + Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::OSX; } +#elif defined(_WIN32) + #define PLATFORM_WINDOWS + #define PLATFORM_WIN + Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::Windows; } +#else + #warning "unable to detect platform" + #define PLATFORM_UNKNOWN + Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::Unknown; } +#endif + +/* Endian detection */ + +#if defined(__i386__) || defined(__amd64__) || defined(_M_IX86) || defined(_M_AMD64) + #define ENDIAN_LSB + #define ARCH_LSB + Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::LSB; } +#elif defined(__powerpc__) || defined(_M_PPC) || defined(__BIG_ENDIAN__) + #define ENDIAN_MSB + #define ARCH_MSB + Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::MSB; } +#else + #warning "unable to detect endian" + #define ENDIAN_UNKNOWN + #define ARCH_UNKNOWN + Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::Unknown; } +#endif + +#endif diff --git a/snesfilter/nall/ips.hpp b/snesfilter/nall/ips.hpp index 87c7de25..3071d038 100755 --- a/snesfilter/nall/ips.hpp +++ b/snesfilter/nall/ips.hpp @@ -76,7 +76,7 @@ bool ips::apply() { } delete[] data; - data = 0; + data = nullptr; return false; } @@ -96,7 +96,7 @@ bool ips::modify(const string &filename) { return file::read(filename, modifyData, modifySize); } -ips::ips() : data(0), sourceData(0), modifyData(0) { +ips::ips() : data(nullptr), sourceData(nullptr), modifyData(nullptr) { } ips::~ips() { diff --git a/snesfilter/nall/lzss.hpp b/snesfilter/nall/lzss.hpp index 147e1e62..fb3e0ba6 100755 --- a/snesfilter/nall/lzss.hpp +++ b/snesfilter/nall/lzss.hpp @@ -25,7 +25,7 @@ protected: struct Node { unsigned offset; Node *next; - inline Node() : offset(0), next(0) {} + inline Node() : offset(0), next(nullptr) {} inline ~Node() { if(next) delete next; } } *tree[65536]; @@ -34,7 +34,7 @@ protected: unsigned sourceSize; public: - inline lzss() : sourceData(0), sourceSize(0) {} + inline lzss() : sourceData(nullptr), sourceSize(0) {} }; void lzss::source(const uint8_t *data, unsigned size) { diff --git a/snesfilter/nall/platform.hpp b/snesfilter/nall/platform.hpp index 539b2345..f3e4b3f5 100755 --- a/snesfilter/nall/platform.hpp +++ b/snesfilter/nall/platform.hpp @@ -104,6 +104,8 @@ SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, fp); strcpy(path, nall::utf8_t(fp)); for(unsigned n = 0; path[n]; n++) if(path[n] == '\\') path[n] = '/'; + unsigned length = strlen(path); + if(path[length] != '/') strcpy(path + length, "/"); return path; } @@ -112,6 +114,8 @@ _wgetcwd(fp, _MAX_PATH); strcpy(path, nall::utf8_t(fp)); for(unsigned n = 0; path[n]; n++) if(path[n] == '\\') path[n] = '/'; + unsigned length = strlen(path); + if(path[length] != '/') strcpy(path + length, "/"); return path; } #else diff --git a/snesfilter/nall/png.hpp b/snesfilter/nall/png.hpp index 025044b2..4b474724 100755 --- a/snesfilter/nall/png.hpp +++ b/snesfilter/nall/png.hpp @@ -10,9 +10,12 @@ namespace nall { struct png { - uint32_t *data; - unsigned size; - + //colorType: + //0 = L + //2 = R,G,B + //3 = P + //4 = L,A + //6 = R,G,B,A struct Info { unsigned width; unsigned height; @@ -28,13 +31,14 @@ struct png { uint8_t palette[256][3]; } info; - uint8_t *rawData; - unsigned rawSize; + uint8_t *data; + unsigned size; inline bool decode(const string &filename); inline bool decode(const uint8_t *sourceData, unsigned sourceSize); - inline void transform(); - inline void alphaTransform(uint32_t rgb = 0xffffff); + inline unsigned readbits(const uint8_t *&data); + unsigned bitpos; + inline png(); inline ~png(); @@ -46,16 +50,11 @@ protected: IEND = 0x49454e44, }; - unsigned bitpos; - inline unsigned interlace(unsigned pass, unsigned index); inline unsigned inflateSize(); inline bool deinterlace(const uint8_t *&inputData, unsigned pass); inline bool filter(uint8_t *outputData, const uint8_t *inputData, unsigned width, unsigned height); inline unsigned read(const uint8_t *data, unsigned length); - inline unsigned decode(const uint8_t *&data); - inline unsigned readbits(const uint8_t *&data); - inline unsigned scale(unsigned n); }; bool png::decode(const string &filename) { @@ -146,14 +145,14 @@ bool png::decode(const uint8_t *sourceData, unsigned sourceSize) { return false; } - rawSize = info.width * info.height * info.bytesPerPixel; - rawData = new uint8_t[rawSize]; + size = info.width * info.height * info.bytesPerPixel; + data = new uint8_t[size]; if(info.interlaceMethod == 0) { - if(filter(rawData, interlacedData, info.width, info.height) == false) { + if(filter(data, interlacedData, info.width, info.height) == false) { delete[] interlacedData; - delete[] rawData; - rawData = 0; + delete[] data; + data = 0; return false; } } else { @@ -161,8 +160,8 @@ bool png::decode(const uint8_t *sourceData, unsigned sourceSize) { for(unsigned pass = 0; pass < 7; pass++) { if(deinterlace(passData, pass) == false) { delete[] interlacedData; - delete[] rawData; - rawData = 0; + delete[] data; + data = 0; return false; } } @@ -216,7 +215,7 @@ bool png::deinterlace(const uint8_t *&inputData, unsigned pass) { const uint8_t *rd = outputData; for(unsigned y = yo; y < info.height; y += yd) { - uint8_t *wr = rawData + y * info.pitch; + uint8_t *wr = data + y * info.pitch; for(unsigned x = xo; x < info.width; x += xd) { for(unsigned b = 0; b < info.bytesPerPixel; b++) { wr[x * info.bytesPerPixel + b] = *rd++; @@ -298,42 +297,6 @@ unsigned png::read(const uint8_t *data, unsigned length) { return result; } -unsigned png::decode(const uint8_t *&data) { - unsigned p, r, g, b, a; - - switch(info.colorType) { - case 0: //L - r = g = b = scale(readbits(data)); - a = 0xff; - break; - case 2: //R,G,B - r = scale(readbits(data)); - g = scale(readbits(data)); - b = scale(readbits(data)); - a = 0xff; - break; - case 3: //P - p = readbits(data); - r = info.palette[p][0]; - g = info.palette[p][1]; - b = info.palette[p][2]; - a = 0xff; - break; - case 4: //L,A - r = g = b = scale(readbits(data)); - a = scale(readbits(data)); - break; - case 6: //R,G,B,A - r = scale(readbits(data)); - g = scale(readbits(data)); - b = scale(readbits(data)); - a = scale(readbits(data)); - break; - } - - return (a << 24) | (r << 16) | (g << 8) | (b << 0); -} - unsigned png::readbits(const uint8_t *&data) { unsigned result = 0; switch(info.bitDepth) { @@ -363,62 +326,12 @@ unsigned png::readbits(const uint8_t *&data) { return result; } -unsigned png::scale(unsigned n) { - switch(info.bitDepth) { - case 1: return n ? 0xff : 0x00; - case 2: return n * 0x55; - case 4: return n * 0x11; - case 8: return n; - case 16: return n >> 8; - } - return 0; -} - -void png::transform() { - if(data) delete[] data; - data = new uint32_t[info.width * info.height]; - +png::png() : data(nullptr) { bitpos = 0; - const uint8_t *rd = rawData; - for(unsigned y = 0; y < info.height; y++) { - uint32_t *wr = data + y * info.width; - for(unsigned x = 0; x < info.width; x++) { - wr[x] = decode(rd); - } - } -} - -void png::alphaTransform(uint32_t rgb) { - transform(); - - uint8_t ir = rgb >> 16; - uint8_t ig = rgb >> 8; - uint8_t ib = rgb >> 0; - - uint32_t *p = data; - for(unsigned y = 0; y < info.height; y++) { - for(unsigned x = 0; x < info.width; x++) { - uint32_t pixel = *p; - uint8_t a = pixel >> 24; - uint8_t r = pixel >> 16; - uint8_t g = pixel >> 8; - uint8_t b = pixel >> 0; - - r = (r * a) + (ir * (255 - a)) >> 8; - g = (g * a) + (ig * (255 - a)) >> 8; - b = (b * a) + (ib * (255 - a)) >> 8; - - *p++ = (255 << 24) | (r << 16) | (g << 8) | (b << 0); - } - } -} - -png::png() : data(0), rawData(0) { } png::~png() { if(data) delete[] data; - if(rawData) delete[] rawData; } } diff --git a/snesfilter/nall/priorityqueue.hpp b/snesfilter/nall/priorityqueue.hpp index 7104e791..443eac21 100755 --- a/snesfilter/nall/priorityqueue.hpp +++ b/snesfilter/nall/priorityqueue.hpp @@ -12,7 +12,7 @@ namespace nall { //priority queue implementation using binary min-heap array; //does not require normalize() function. //O(1) find (tick) - //O(log n) insert (enqueue) + //O(log n) append (enqueue) //O(log n) remove (dequeue) template class priority_queue { public: diff --git a/snesfilter/nall/property.hpp b/snesfilter/nall/property.hpp index 6fd33acd..665afcad 100755 --- a/snesfilter/nall/property.hpp +++ b/snesfilter/nall/property.hpp @@ -22,7 +22,7 @@ // readwrite y; //}; -//return types are const T& (byref) instead fo T (byval) to avoid major speed +//return types are const T& (byref) instead of T (byval) to avoid major speed //penalties for objects with expensive copy constructors //operator-> provides access to underlying object type: diff --git a/snesfilter/nall/reference_array.hpp b/snesfilter/nall/reference_array.hpp index 77d06d86..7c915090 100755 --- a/snesfilter/nall/reference_array.hpp +++ b/snesfilter/nall/reference_array.hpp @@ -1,15 +1,17 @@ #ifndef NALL_REFERENCE_ARRAY_HPP #define NALL_REFERENCE_ARRAY_HPP +#include #include #include -#include namespace nall { template struct reference_array { + struct exception_out_of_bounds{}; + protected: - typedef typename std::remove_reference::type *Tptr; - Tptr *pool; + typedef typename std::remove_reference::type type_t; + type_t **pool; unsigned poolsize, buffersize; public: @@ -18,7 +20,7 @@ namespace nall { void reset() { if(pool) free(pool); - pool = 0; + pool = nullptr; poolsize = 0; buffersize = 0; } @@ -26,7 +28,7 @@ namespace nall { void reserve(unsigned newsize) { if(newsize == poolsize) return; - pool = (Tptr*)realloc(pool, newsize * sizeof(T)); + pool = (type_t**)realloc(pool, sizeof(type_t*) * newsize); poolsize = newsize; buffersize = min(buffersize, newsize); } @@ -36,7 +38,14 @@ namespace nall { buffersize = newsize; } - bool append(const T data) { + template + bool append(type_t& data, Args&&... args) { + bool result = append(data); + append(std::forward(args)...); + return result; + } + + bool append(type_t& data) { for(unsigned index = 0; index < buffersize; index++) { if(pool[index] == &data) return false; } @@ -47,7 +56,7 @@ namespace nall { return true; } - bool remove(const T data) { + bool remove(type_t& data) { for(unsigned index = 0; index < buffersize; index++) { if(pool[index] == &data) { for(unsigned i = index; i < buffersize - 1; i++) pool[i] = pool[i + 1]; @@ -58,7 +67,7 @@ namespace nall { return false; } - template reference_array(Args&... args) : pool(0), poolsize(0), buffersize(0) { + template reference_array(Args&... args) : pool(nullptr), poolsize(0), buffersize(0) { construct(args...); } @@ -70,8 +79,8 @@ namespace nall { if(pool) free(pool); buffersize = source.buffersize; poolsize = source.poolsize; - pool = (Tptr*)malloc(sizeof(T) * poolsize); - memcpy(pool, source.pool, sizeof(T) * buffersize); + pool = (type_t**)malloc(sizeof(type_t*) * poolsize); + memcpy(pool, source.pool, sizeof(type_t*) * buffersize); return *this; } @@ -80,21 +89,37 @@ namespace nall { pool = source.pool; poolsize = source.poolsize; buffersize = source.buffersize; - source.pool = 0; + source.pool = nullptr; source.reset(); return *this; } - inline T operator[](unsigned index) { - if(index >= buffersize) throw "reference_array[] out of bounds"; + inline type_t& operator[](unsigned index) { + if(index >= buffersize) throw exception_out_of_bounds(); return *pool[index]; } - inline const T operator[](unsigned index) const { - if(index >= buffersize) throw "reference_array[] out of bounds"; + inline type_t& operator[](unsigned index) const { + if(index >= buffersize) throw exception_out_of_bounds(); return *pool[index]; } + //iteration + struct iterator { + bool operator!=(const iterator &source) const { return index != source.index; } + type_t& operator*() { return array.operator[](index); } + iterator& operator++() { index++; return *this; } + iterator(const reference_array &array, unsigned index) : array(array), index(index) {} + private: + const reference_array &array; + unsigned index; + }; + + iterator begin() { return iterator(*this, 0); } + iterator end() { return iterator(*this, buffersize); } + const iterator begin() const { return iterator(*this, 0); } + const iterator end() const { return iterator(*this, buffersize); } + private: void construct() { } @@ -112,8 +137,6 @@ namespace nall { construct(args...); } }; - - template struct has_size> { enum { value = true }; }; } #endif diff --git a/snesfilter/nall/snes/cartridge.hpp b/snesfilter/nall/snes/cartridge.hpp index 6847ba3a..cac3fb1a 100755 --- a/snesfilter/nall/snes/cartridge.hpp +++ b/snesfilter/nall/snes/cartridge.hpp @@ -3,10 +3,10 @@ namespace nall { -class SNESCartridge { +class SnesCartridge { public: - string xmlMemoryMap; - inline SNESCartridge(const uint8_t *data, unsigned size); + string markup; + inline SnesCartridge(const uint8_t *data, unsigned size); //private: inline void read_header(const uint8_t *data, unsigned size); @@ -105,436 +105,346 @@ public: bool has_st018; }; -SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { +#define T "\t" + +SnesCartridge::SnesCartridge(const uint8_t *data, unsigned size) { read_header(data, size); - string xml = "\n"; + string xml; + markup = ""; if(type == TypeBsx) { - xml.append(""); - xmlMemoryMap = xml.transform("'", "\""); + markup.append("cartridge"); return; } if(type == TypeSufamiTurbo) { - xml.append(""); - xmlMemoryMap = xml.transform("'", "\""); + markup.append("cartridge"); return; } if(type == TypeGameBoy) { - xml.append("\n"); + markup.append("cartridge rtc=", gameboy_has_rtc(data, size), "\n"); if(gameboy_ram_size(data, size) > 0) { - xml.append(" \n"); + markup.append(T "ram size=0x", hex(gameboy_ram_size(data, size)), "\n"); } - xml.append("\n"); - xmlMemoryMap = xml.transform("'", "\""); return; } - xml.append("\n"); + markup.append("cartridge region=", region == NTSC ? "NTSC\n" : "PAL\n"); if(type == TypeSuperGameBoy1Bios) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "rom\n"); + markup.append(T T "map mode=linear address=00-7f:8000-ffff\n"); + markup.append(T T "map mode=linear address=80-ff:8000-ffff\n"); + markup.append(T "icd2 revision=1\n"); + markup.append(T T "map address=00-3f:6000-7fff\n"); + markup.append(T T "map address=80-bf:6000-7fff\n"); } else if(type == TypeSuperGameBoy2Bios) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "rom\n"); + markup.append(T T "map mode=linear address=00-7f:8000-ffff\n"); + markup.append(T T "map mode=linear address=80-ff:8000-ffff\n"); + markup.append(T "icd2 revision=1\n"); + markup.append(T T "map address=00-3f:6000-7fff\n"); + markup.append(T T "map address=80-bf:6000-7fff\n"); } else if(has_cx4) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "hitachidsp model=HG51B169 frequency=20000000 firmware=cx4.bin sha256=ae8d4d1961b93421ff00b3caa1d0f0ce7783e749772a3369c36b3dbf0d37ef18\n"); + markup.append(T T "rom\n"); + markup.append(T T T "map mode=linear address=00-7f:8000-ffff\n"); + markup.append(T T T "map mode=linear address=80-ff:8000-ffff\n"); + markup.append(T T "mmio\n"); + markup.append(T T T "map address=00-3f:6000-7fff\n"); + markup.append(T T T "map address=80-bf:6000-7fff\n"); } else if(has_spc7110) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "rom\n"); + markup.append(T T "map mode=shadow address=00-0f:8000-ffff\n"); + markup.append(T T "map mode=shadow address=80-bf:8000-ffff\n"); + markup.append(T T "map mode=linear address=c0-cf:0000-ffff\n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "spc7110\n"); + markup.append(T T "mcu\n"); + markup.append(T T T "map address=d0-ff:0000-ffff offset=0x100000 size=0x", hex(size - 0x100000), "\n"); + markup.append(T T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T T "map mode=linear address=00:6000-7fff\n"); + markup.append(T T T "map mode=linear address=30:6000-7fff\n"); + markup.append(T T "mmio\n"); + markup.append(T T T "map address=00-3f:4800-483f\n"); + markup.append(T T T "map address=80-bf:4800-483f\n"); if(has_spc7110rtc) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T T "rtc\n"); + markup.append(T T T "map address=00-3f:4840-4842\n"); + markup.append(T T T "map address=80-bf:4840-4842\n"); } - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T T "dcu\n"); + markup.append(T T T "map address=50:0000-ffff\n"); } else if(mapper == LoROM) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "rom\n"); + markup.append(T T "map mode=linear address=00-7f:8000-ffff\n"); + markup.append(T T "map mode=linear address=80-ff:8000-ffff\n"); if(ram_size > 0) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T "map mode=linear address=20-3f:6000-7fff\n"); + markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n"); if((rom_size > 0x200000) || (ram_size > 32 * 1024)) { - xml.append(" \n"); - xml.append(" \n"); + markup.append(T T "map mode=linear address=70-7f:0000-7fff\n"); + markup.append(T T "map mode=linear address=f0-ff:0000-7fff\n"); } else { - xml.append(" \n"); - xml.append(" \n"); + markup.append(T T "map mode=linear address=70-7f:0000-ffff\n"); + markup.append(T T "map mode=linear address=f0-ff:0000-ffff\n"); } - xml.append(" \n"); } } else if(mapper == HiROM) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "rom\n"); + markup.append(T T "map mode=shadow address=00-3f:8000-ffff\n"); + markup.append(T T "map mode=linear address=40-7f:0000-ffff\n"); + markup.append(T T "map mode=shadow address=80-bf:8000-ffff\n"); + markup.append(T T "map mode=linear address=c0-ff:0000-ffff\n"); if(ram_size > 0) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T "map mode=linear address=20-3f:6000-7fff\n"); + markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n"); if((rom_size > 0x200000) || (ram_size > 32 * 1024)) { - xml.append(" \n"); + markup.append(T T "map mode=linear address=70-7f:0000-7fff\n"); } else { - xml.append(" \n"); + markup.append(T T "map mode=linear address=70-7f:0000-ffff\n"); } - xml.append(" \n"); } } else if(mapper == ExLoROM) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "rom\n"); + markup.append(T T "map mode=linear address=00-3f:8000-ffff\n"); + markup.append(T T "map mode=linear address=40-7f:0000-ffff\n"); + markup.append(T T "map mode=linear address=80-bf:8000-ffff\n"); if(ram_size > 0) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T "map mode=linear address=20-3f:6000-7fff\n"); + markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n"); + markup.append(T T "map mode=linear address=70-7f:0000-7fff\n"); } } else if(mapper == ExHiROM) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "rom\n"); + markup.append(T T "map mode=shadow address=00-3f:8000-ffff offset=0x400000\n"); + markup.append(T T "map mode=linear address=40-7f:0000-ffff offset=0x400000\n"); + markup.append(T T "map mode=shadow address=80-bf:8000-ffff offset=0x000000\n"); + markup.append(T T "map mode=linear address=c0-ff:0000-ffff offset=0x000000\n"); if(ram_size > 0) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T "map mode=linear address=20-3f:6000-7fff\n"); + markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n"); if((rom_size > 0x200000) || (ram_size > 32 * 1024)) { - xml.append(" \n"); + markup.append(T T "map mode=linear address=70-7f:0000-7fff\n"); } else { - xml.append(" \n"); + markup.append(T T "map mode=linear address=70-7f:0000-ffff\n"); } - xml.append(" \n"); } } else if(mapper == SuperFXROM) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "superfx revision=2\n"); + markup.append(T T "rom\n"); + markup.append(T T T "map mode=linear address=00-3f:8000-ffff\n"); + markup.append(T T T "map mode=linear address=40-5f:0000-ffff\n"); + markup.append(T T T "map mode=linear address=80-bf:8000-ffff\n"); + markup.append(T T T "map mode=linear address=c0-df:0000-ffff\n"); + markup.append(T T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T T "map mode=linear address=00-3f:6000-7fff size=0x2000\n"); + markup.append(T T T "map mode=linear address=60-7f:0000-ffff\n"); + markup.append(T T T "map mode=linear address=80-bf:6000-7fff size=0x2000\n"); + markup.append(T T T "map mode=linear address=e0-ff:0000-ffff\n"); + markup.append(T T "mmio\n"); + markup.append(T T T "map address=00-3f:3000-32ff\n"); + markup.append(T T T "map address=80-bf:3000-32ff\n"); } else if(mapper == SA1ROM) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "sa1\n"); + markup.append(T T "mcu\n"); + markup.append(T T T "rom\n"); + markup.append(T T T T "map mode=direct address=00-3f:8000-ffff\n"); + markup.append(T T T T "map mode=direct address=80-bf:8000-ffff\n"); + markup.append(T T T T "map mode=direct address=c0-ff:0000-ffff\n"); + markup.append(T T T "ram\n"); + markup.append(T T T T "map mode=direct address=00-3f:6000-7fff\n"); + markup.append(T T T T "map mode=direct address=80-bf:6000-7fff\n"); + markup.append(T T "iram size=0x800\n"); + markup.append(T T T "map mode=linear address=00-3f:3000-37ff\n"); + markup.append(T T T "map mode=linear address=80-bf:3000-37ff\n"); + markup.append(T T "bwram size=0x", hex(ram_size), "\n"); + markup.append(T T T "map mode=linear address=40-4f:0000-ffff\n"); + markup.append(T T "mmio\n"); + markup.append(T T T "map address=00-3f:2200-23ff\n"); + markup.append(T T T "map address=80-bf:2200-23ff\n"); } else if(mapper == BSCLoROM) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "rom\n"); + markup.append(T T "map mode=linear address=00-1f:8000-ffff offset=0x000000\n"); + markup.append(T T "map mode=linear address=20-3f:8000-ffff offset=0x100000\n"); + markup.append(T T "map mode=linear address=80-9f:8000-ffff offset=0x200000\n"); + markup.append(T T "map mode=linear address=a0-bf:8000-ffff offset=0x100000\n"); + markup.append(T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T "map mode=linear address=70-7f:0000-7fff\n"); + markup.append(T T "map mode=linear address=f0-ff:0000-7fff\n"); + markup.append(T "bsx\n"); + markup.append(T T "slot\n"); + markup.append(T T T "map mode=linear address=c0-ef:0000-ffff\n"); } else if(mapper == BSCHiROM) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "rom\n"); + markup.append(T T "map mode=shadow address=00-1f:8000-ffff\n"); + markup.append(T T "map mode=linear address=40-5f:0000-ffff\n"); + markup.append(T T "map mode=shadow address=80-9f:8000-ffff\n"); + markup.append(T T "map mode=linear address=c0-df:0000-ffff\n"); + markup.append(T "ram size=0x", hex(ram_size), "\n"); + markup.append(T T "map mode=linear address=20-3f:6000-7fff\n"); + markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n"); + markup.append(T "bsx\n"); + markup.append(T T "slot\n"); + markup.append(T T T "map mode=shadow address=20-3f:8000-ffff\n"); + markup.append(T T T "map mode=linear address=60-7f:0000-ffff\n"); + markup.append(T T T "map mode=shadow address=a0-bf:8000-ffff\n"); + markup.append(T T T "map mode=linear address=e0-ff:0000-ffff\n"); } else if(mapper == BSXROM) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "bsx\n"); + markup.append(T T "mcu\n"); + markup.append(T T T "map address=00-3f:8000-ffff\n"); + markup.append(T T T "map address=80-bf:8000-ffff\n"); + markup.append(T T T "map address=40-7f:0000-ffff\n"); + markup.append(T T T "map address=c0-ff:0000-ffff\n"); + markup.append(T T T "map address=20-3f:6000-7fff\n"); + markup.append(T T "mmio\n"); + markup.append(T T T "map address=00-3f:5000-5fff\n"); + markup.append(T T T "map address=80-bf:5000-5fff\n"); } else if(mapper == STROM) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "rom\n"); + markup.append(T T "map mode=linear address=00-1f:8000-ffff\n"); + markup.append(T T "map mode=linear address=80-9f:8000-ffff\n"); + markup.append(T "sufamiturbo\n"); + markup.append(T T "slot id=A\n"); + markup.append(T T T "rom\n"); + markup.append(T T T T "map mode=linear address=20-3f:8000-ffff\n"); + markup.append(T T T T "map mode=linear address=a0-bf:8000-ffff\n"); + markup.append(T T T "ram size=0x20000\n"); + markup.append(T T T T "map mode=linear address=60-63:8000-ffff\n"); + markup.append(T T T T "map mode=linear address=e0-e3:8000-ffff\n"); + markup.append(T T "slot id=B\n"); + markup.append(T T T "rom\n"); + markup.append(T T T T "map mode=linear address=40-5f:8000-ffff\n"); + markup.append(T T T T "map mode=linear address=c0-df:8000-ffff\n"); + markup.append(T T T "ram size=0x20000\n"); + markup.append(T T T T "map mode=linear address=70-73:8000-ffff\n"); + markup.append(T T T T "map mode=linear address=f0-f3:8000-ffff\n"); } if(has_srtc) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "srtc\n"); + markup.append(T T "map address=00-3f:2800-2801\n"); + markup.append(T T "map address=80-bf:2800-2801\n"); } if(has_sdd1) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "sdd1\n"); + markup.append(T T "mcu\n"); + markup.append(T T T "map address=c0-ff:0000-ffff\n"); + markup.append(T T "mmio\n"); + markup.append(T T T "map address=00-3f:4800-4807\n"); + markup.append(T T T "map address=80-bf:4800-4807\n"); } if(has_dsp1) { - xml.append(" \n"); + markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp1b.bin sha256=4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c\n"); if(dsp1_mapper == DSP1LoROM1MB) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T T "dr\n"); + markup.append(T T T "map address=20-3f:8000-bfff\n"); + markup.append(T T T "map address=a0-bf:8000-bfff\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=20-3f:c000-ffff\n"); + markup.append(T T T "map address=a0-bf:c000-ffff\n"); } else if(dsp1_mapper == DSP1LoROM2MB) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T T "dr\n"); + markup.append(T T T "map address=60-6f:0000-3fff\n"); + markup.append(T T T "map address=e0-ef:0000-3fff\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=60-6f:4000-7fff\n"); + markup.append(T T T "map address=e0-ef:4000-7fff\n"); } else if(dsp1_mapper == DSP1HiROM) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T T "dr\n"); + markup.append(T T T "map address=00-1f:6000-6fff\n"); + markup.append(T T T "map address=80-9f:6000-6fff\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=00-1f:7000-7fff\n"); + markup.append(T T T "map address=80-9f:7000-7fff\n"); } - xml.append(" \n"); } if(has_dsp2) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp2.bin sha256=5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1\n"); + markup.append(T T "dr\n"); + markup.append(T T T "map address=20-3f:8000-bfff\n"); + markup.append(T T T "map address=a0-bf:8000-bfff\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=20-3f:c000-ffff\n"); + markup.append(T T T "map address=a0-bf:c000-ffff\n"); } if(has_dsp3) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp3.bin sha256=2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90\n"); + markup.append(T T "dr\n"); + markup.append(T T T "map address=20-3f:8000-bfff\n"); + markup.append(T T T "map address=a0-bf:8000-bfff\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=20-3f:c000-ffff\n"); + markup.append(T T T "map address=a0-bf:c000-ffff\n"); } if(has_dsp4) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp4.bin sha256=63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a\n"); + markup.append(T T "dr\n"); + markup.append(T T T "map address=30-3f:8000-bfff\n"); + markup.append(T T T "map address=b0-bf:8000-bfff\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=30-3f:c000-ffff\n"); + markup.append(T T T "map address=b0-bf:c000-ffff\n"); } if(has_obc1) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "obc1\n"); + markup.append(T T "map address=00-3f:6000-7fff\n"); + markup.append(T T "map address=80-bf:6000-7fff\n"); } if(has_st010) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "necdsp model=uPD96050 frequency=10000000 firmware=st0010.bin sha256=55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e\n"); + markup.append(T T "dr\n"); + markup.append(T T T "map address=60:0000\n"); + markup.append(T T T "map address=e0:0000\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=60:0001\n"); + markup.append(T T T "map address=e0:0001\n"); + markup.append(T T "dp\n"); + markup.append(T T T "map address=68-6f:0000-0fff\n"); + markup.append(T T T "map address=e8-ef:0000-0fff\n"); } if(has_st011) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "necdsp model=uPD96050 frequency=15000000 firmware=st0011.bin sha256=651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e\n"); + markup.append(T T "dr\n"); + markup.append(T T T "map address=60:0000\n"); + markup.append(T T T "map address=e0:0000\n"); + markup.append(T T "sr\n"); + markup.append(T T T "map address=60:0001\n"); + markup.append(T T T "map address=e0:0001\n"); + markup.append(T T "dp\n"); + markup.append(T T T "map address=68-6f:0000-0fff\n"); + markup.append(T T T "map address=e8-ef:0000-0fff\n"); } if(has_st018) { - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); - xml.append(" \n"); + markup.append(T "setarisc firmware=ST-0018\n"); + markup.append(T T "map address=00-3f:3800-38ff\n"); + markup.append(T T "map address=80-bf:3800-38ff\n"); } - - xml.append("\n"); - xmlMemoryMap = xml.transform("'", "\""); } -void SNESCartridge::read_header(const uint8_t *data, unsigned size) { +#undef T + +void SnesCartridge::read_header(const uint8_t *data, unsigned size) { type = TypeUnknown; mapper = LoROM; dsp1_mapper = DSP1Unmapped; @@ -762,7 +672,7 @@ void SNESCartridge::read_header(const uint8_t *data, unsigned size) { } } -unsigned SNESCartridge::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); @@ -777,7 +687,7 @@ unsigned SNESCartridge::find_header(const uint8_t *data, unsigned size) { } } -unsigned SNESCartridge::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; @@ -858,7 +768,7 @@ unsigned SNESCartridge::score_header(const uint8_t *data, unsigned size, unsigne return score; } -unsigned SNESCartridge::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; @@ -871,7 +781,7 @@ unsigned SNESCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) { } } -bool SNESCartridge::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; diff --git a/snesfilter/nall/stack.hpp b/snesfilter/nall/stack.hpp index a4aacfa7..fe8e16a1 100755 --- a/snesfilter/nall/stack.hpp +++ b/snesfilter/nall/stack.hpp @@ -1,7 +1,6 @@ #ifndef NALL_STACK_HPP #define NALL_STACK_HPP -#include #include namespace nall { @@ -22,8 +21,6 @@ namespace nall { return linear_vector::operator[](linear_vector::size() - 1); } }; - - template struct has_size> { enum { value = true }; }; } #endif diff --git a/snesfilter/nall/string.hpp b/snesfilter/nall/string.hpp index 91bee596..288424bc 100755 --- a/snesfilter/nall/string.hpp +++ b/snesfilter/nall/string.hpp @@ -1,20 +1,39 @@ #ifndef NALL_STRING_HPP #define NALL_STRING_HPP +#include +#include +#include +#include + +#include #include + #include +#include +#include #include #include +#include #include +#include +#include +#include + +#define NALL_STRING_INTERNAL_HPP #include +#include #include #include #include #include #include +#include #include #include +#include +#include #include #include #include @@ -23,12 +42,9 @@ #include #include #include +#include #include #include - -namespace nall { - template<> struct has_length { enum { value = true }; }; - template<> struct has_size { enum { value = true }; }; -} +#undef NALL_STRING_INTERNAL_HPP #endif diff --git a/snesfilter/nall/string/base.hpp b/snesfilter/nall/string/base.hpp index 86c42c20..97000bef 100755 --- a/snesfilter/nall/string/base.hpp +++ b/snesfilter/nall/string/base.hpp @@ -1,23 +1,27 @@ -#ifndef NALL_STRING_BASE_HPP -#define NALL_STRING_BASE_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#ifdef NALL_STRING_INTERNAL_HPP namespace nall { - class string; - class lstring; + struct cstring; + struct string; + struct lstring; template inline const char* to_string(T); - class string { - public: + struct cstring { + inline operator const char*() const; + inline unsigned length() const; + inline bool operator==(const char*) const; + inline bool operator!=(const char*) const; + inline optional position(const char *key) const; + inline optional iposition(const char *key) const; + inline cstring& operator=(const char *data); + inline cstring(const char *data); + inline cstring(); + + protected: + const char *data; + }; + + struct string { inline void reserve(unsigned); template inline string& assign(Args&&... args); @@ -32,6 +36,11 @@ namespace nall { inline unsigned length() const; + template inline lstring split(const char*) const; + template inline lstring isplit(const char*) const; + template inline lstring qsplit(const char*) const; + template inline lstring iqsplit(const char*) const; + inline bool equals(const char*) const; inline bool iequals(const char*) const; @@ -77,6 +86,11 @@ namespace nall { inline string(string&&); inline ~string(); + inline char* begin() { return &data[0]; } + inline char* end() { return &data[length()]; } + inline const char* begin() const { return &data[0]; } + inline const char* end() const { return &data[length()]; } + //internal functions inline string& assign_(const char*); inline string& append_(const char*); @@ -93,10 +107,7 @@ namespace nall { #endif }; - class lstring : public linear_vector { - public: - template inline lstring& operator<<(T value); - + struct lstring : vector { inline optional find(const char*) const; template inline lstring& split(const char*, const char*); template inline lstring& isplit(const char*, const char*); @@ -106,8 +117,8 @@ namespace nall { inline bool operator==(const lstring&) const; inline bool operator!=(const lstring&) const; - lstring(); - lstring(std::initializer_list); + inline lstring(); + inline lstring(std::initializer_list); protected: template inline lstring& usplit(const char*, const char*); @@ -117,8 +128,6 @@ namespace nall { inline char chrlower(char c); inline char chrupper(char c); inline int istrcmp(const char *str1, const char *str2); - inline bool wildcard(const char *str, const char *pattern); - inline bool iwildcard(const char *str, const char *pattern); inline bool strbegin(const char *str, const char *key); inline bool istrbegin(const char *str, const char *key); inline bool strend(const char *str, const char *key); @@ -130,11 +139,6 @@ namespace nall { inline char* qstrlower(char *str); inline char* qstrupper(char *str); inline char* strtr(char *dest, const char *before, const char *after); - 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); @@ -170,17 +174,24 @@ namespace nall { inline string substr(const char *src, unsigned start = 0, unsigned length = ~0u); inline string sha256(const uint8_t *data, unsigned size); + inline char* integer(char *result, intmax_t value); + inline char* decimal(char *result, uintmax_t value); + template inline string integer(intmax_t value); template inline string linteger(intmax_t value); template inline string decimal(uintmax_t value); template inline string ldecimal(uintmax_t value); template inline string hex(uintmax_t value); template inline string binary(uintmax_t value); - inline unsigned fp(char *str, double value); - inline string fp(double value); + inline unsigned fp(char *str, long double value); + inline string fp(long double value); //variadic.hpp template inline void print(Args&&... args); + + //wildcard.hpp + inline bool wildcard(const char *str, const char *pattern); + inline bool iwildcard(const char *str, const char *pattern); }; #endif diff --git a/snesfilter/nall/string/bml.hpp b/snesfilter/nall/string/bml.hpp new file mode 100755 index 00000000..4f8139cc --- /dev/null +++ b/snesfilter/nall/string/bml.hpp @@ -0,0 +1,151 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +//BML v1.0 parser +//revision 0.05 + +namespace nall { +namespace BML { + +inline static string indent(const char *s, unsigned depth) { + array output; + do { + for(unsigned n = 0; n < depth; n++) output.append('\t'); + do output.append(*s); while(*s && *s++ != '\n'); + } while(*s); + return output.get(); +} + +struct Node { + cstring name; + cstring value; + +private: + linear_vector children; + + inline bool valid(char p) const { //A-Za-z0-9-. + return p - 'A' < 26u | p - 'a' < 26u | p - '0' < 10u | p - '-' < 2u; + } + + inline unsigned parseDepth(char *&p) { + while(*p == '\n' || *p == '#') { + while(*p != '\n') *p++ = 0; + *p++ = 0; //'\n' + } + unsigned depth = 0; + while(p[depth] == '\t') depth++; + return depth; + } + + inline void parseName(char *&p) { + if(valid(*p) == false) throw "Missing node name"; + name = p; + while(valid(*p)) p++; + } + + inline void parseValue(char *&p) { + char terminal = *p == ':' ? '\n' : ' '; //':' or '=' + *p++ = 0; + value = p; + while(*p && *p != terminal && *p != '\n') p++; + } + + inline void parseBlock(char *&p, unsigned depth) { + value = p; + char *w = p; + while(parseDepth(p) > depth) { + p += depth + 1; + while(*p && *p != '\n') *w++ = *p++; + if(*p && *p != '\n') throw "Multi-line value missing line feed"; + *w++ = *p; + } + *(w - 1) = 0; //'\n' + } + + inline void parseLine(char *&p) { + unsigned depth = parseDepth(p); + while(*p == '\t') p++; + + parseName(p); + bool multiLine = *p == '~'; + if(multiLine) *p++ = 0; + else if(*p == ':' || *p == '=') parseValue(p); + if(*p && *p != ' ' && *p != '\n') throw "Invalid character encountered"; + + while(*p == ' ') { + *p++ = 0; + Node node; + node.parseName(p); + if(*p == ':' || *p == '=') node.parseValue(p); + if(*p && *p != ' ' && *p != '\n') throw "Invalid character after node"; + if(*p == '\n') *p++ = 0; + children.append(node); + } + + if(multiLine) return parseBlock(p, depth); + + while(parseDepth(p) > depth) { + Node node; + node.parseLine(p); + children.append(node); + } + } + + inline void parse(char *&p) { + while(*p) { + Node node; + node.parseLine(p); + children.append(node); + } + } + +public: + inline Node& operator[](const char *name) { + for(auto &node : children) { + if(node.name == name) return node; + } + static Node node; + node.name = nullptr; + return node; + } + + inline bool exists() const { return name; } + unsigned size() const { return children.size(); } + Node* begin() { return children.begin(); } + Node* end() { return children.end(); } + const Node* begin() const { return children.begin(); } + const Node* end() const { return children.end(); } + inline Node() : name(""), value("") {} + friend class Document; +}; + +struct Document : Node { + cstring error; + + inline bool load(const char *document) { + if(document == nullptr) return false; + this->document = strdup(document); + char *p = this->document; + try { + this->error = nullptr; + parse(p); + } catch(const char *error) { + this->error = error; + free(this->document); + this->document = nullptr; + children.reset(); + return false; + } + return true; + } + + inline Document(const char *document = "") : document(nullptr), error(nullptr) { if(*document) load(document); } + inline ~Document() { if(document) free(document); } + +private: + char *document; +}; + +} +} + +#endif diff --git a/snesfilter/nall/string/bsv.hpp b/snesfilter/nall/string/bsv.hpp index d4b919e0..d9415d53 100755 --- a/snesfilter/nall/string/bsv.hpp +++ b/snesfilter/nall/string/bsv.hpp @@ -1,74 +1,75 @@ -#ifndef NALL_STRING_BSV_HPP -#define NALL_STRING_BSV_HPP +#ifdef NALL_STRING_INTERNAL_HPP -//BSV parser -//version 0.01 +//BSV v1.0 parser +//revision 0.02 namespace nall { -inline string bsv_decode(const char *input) { - string output; - unsigned offset = 0; - while(*input) { - //illegal characters - if(*input == '}' ) return ""; - if(*input == '\r') return ""; - if(*input == '\n') return ""; +struct BSV { + static inline string decode(const char *input) { + string output; + unsigned offset = 0; + while(*input) { + //illegal characters + if(*input == '}' ) return ""; + if(*input == '\r') return ""; + if(*input == '\n') return ""; - //normal characters - if(*input != '{') { output[offset++] = *input++; continue; } + //normal characters + if(*input != '{') { output[offset++] = *input++; continue; } - //entities - if(strbegin(input, "{lf}")) { output[offset++] = '\n'; input += 4; continue; } - if(strbegin(input, "{lb}")) { output[offset++] = '{'; input += 4; continue; } - if(strbegin(input, "{rb}")) { output[offset++] = '}'; input += 4; continue; } + //entities + if(strbegin(input, "{lf}")) { output[offset++] = '\n'; input += 4; continue; } + if(strbegin(input, "{lb}")) { output[offset++] = '{'; input += 4; continue; } + if(strbegin(input, "{rb}")) { output[offset++] = '}'; input += 4; continue; } - //illegal entities - return ""; + //illegal entities + return ""; + } + output[offset] = 0; + return output; } - output[offset] = 0; - return output; -} -inline string bsv_encode(const char *input) { - string output; - unsigned offset = 0; - while(*input) { - //illegal characters - if(*input == '\r') return ""; + static inline string encode(const char *input) { + string output; + unsigned offset = 0; + while(*input) { + //illegal characters + if(*input == '\r') return ""; - if(*input == '\n') { - output[offset++] = '{'; - output[offset++] = 'l'; - output[offset++] = 'f'; - output[offset++] = '}'; - input++; - continue; + if(*input == '\n') { + output[offset++] = '{'; + output[offset++] = 'l'; + output[offset++] = 'f'; + output[offset++] = '}'; + input++; + continue; + } + + if(*input == '{') { + output[offset++] = '{'; + output[offset++] = 'l'; + output[offset++] = 'b'; + output[offset++] = '}'; + input++; + continue; + } + + if(*input == '}') { + output[offset++] = '{'; + output[offset++] = 'r'; + output[offset++] = 'b'; + output[offset++] = '}'; + input++; + continue; + } + + output[offset++] = *input++; } - - if(*input == '{') { - output[offset++] = '{'; - output[offset++] = 'l'; - output[offset++] = 'b'; - output[offset++] = '}'; - input++; - continue; - } - - if(*input == '}') { - output[offset++] = '{'; - output[offset++] = 'r'; - output[offset++] = 'b'; - output[offset++] = '}'; - input++; - continue; - } - - output[offset++] = *input++; + output[offset] = 0; + return output; } - output[offset] = 0; - return output; -} +}; } diff --git a/snesfilter/nall/string/cast.hpp b/snesfilter/nall/string/cast.hpp index 2d010bfa..7c7e276b 100755 --- a/snesfilter/nall/string/cast.hpp +++ b/snesfilter/nall/string/cast.hpp @@ -1,31 +1,185 @@ -#ifndef NALL_STRING_CAST_HPP -#define NALL_STRING_CAST_HPP +#ifdef NALL_STRING_INTERNAL_HPP namespace nall { -//this is needed, as C++0x does not support explicit template specialization inside classes -template<> inline const char* to_string (bool v) { return v ? "true" : "false"; } -template<> inline const char* to_string (signed int v) { static char temp[256]; snprintf(temp, 255, "%+d", v); return temp; } -template<> inline const char* to_string (unsigned int v) { static char temp[256]; snprintf(temp, 255, "%u", v); return temp; } -template<> inline const char* to_string (intmax_t v) { static char temp[256]; snprintf(temp, 255, "%+lld", (long long)v); return temp; } -template<> inline const char* to_string (uintmax_t v) { static char temp[256]; snprintf(temp, 255, "%llu", (unsigned long long)v); return temp; } -template<> inline const char* to_string (double v) { static char temp[256]; snprintf(temp, 255, "%f", v); return temp; } -template<> inline const char* to_string (char *v) { return v; } -template<> inline const char* to_string (const char *v) { return v; } -template<> inline const char* to_string (string v) { return v; } -template<> inline const char* to_string(const string &v) { return v; } +//convert any (supported) type to a const char* without constructing a new nall::string +//this is used inside istring(...) to build nall::string values +template struct stringify; -template lstring& lstring::operator<<(T value) { - operator[](size()).assign(to_string(value)); - return *this; -} +// base types + +template<> struct stringify { + bool value; + operator const char*() const { return value ? "true" : "false"; } + stringify(bool value) : value(value) {} +}; + +template<> struct stringify { + char data[256]; + operator const char*() const { return data; } + stringify(char value) { integer(data, value); } +}; + +// signed integers + +template<> struct stringify { + char data[256]; + operator const char*() const { return data; } + stringify(signed char value) { integer(data, value); } +}; + +template<> struct stringify { + char data[256]; + operator const char*() const { return data; } + stringify(signed short value) { integer(data, value); } +}; + +template<> struct stringify { + char data[256]; + operator const char*() const { return data; } + stringify(signed int value) { integer(data, value); } +}; + +template<> struct stringify { + char data[256]; + operator const char*() const { return data; } + stringify(signed long value) { integer(data, value); } +}; + +template<> struct stringify { + char data[256]; + operator const char*() const { return data; } + stringify(signed long long value) { integer(data, value); } +}; + +template struct stringify> { + char data[256]; + operator const char*() const { return data; } + stringify(int_t value) { integer(data, value); } +}; + +// unsigned integers + +template<> struct stringify { + char data[256]; + operator const char*() const { return data; } + stringify(unsigned char value) { decimal(data, value); } +}; + +template<> struct stringify { + char data[256]; + operator const char*() const { return data; } + stringify(unsigned short value) { decimal(data, value); } +}; + +template<> struct stringify { + char data[256]; + operator const char*() const { return data; } + stringify(unsigned int value) { decimal(data, value); } +}; + +template<> struct stringify { + char data[256]; + operator const char*() const { return data; } + stringify(unsigned long value) { decimal(data, value); } +}; + +template<> struct stringify { + char data[256]; + operator const char*() const { return data; } + stringify(unsigned long long value) { decimal(data, value); } +}; + +template struct stringify> { + char data[256]; + operator const char*() const { return data; } + stringify(uint_t value) { decimal(data, value); } +}; + +// floating-point + +template<> struct stringify { + char data[256]; + operator const char*() const { return data; } + stringify(float value) { fp(data, value); } +}; + +template<> struct stringify { + char data[256]; + operator const char*() const { return data; } + stringify(double value) { fp(data, value); } +}; + +template<> struct stringify { + char data[256]; + operator const char*() const { return data; } + stringify(long double value) { fp(data, value); } +}; + +// strings + +template<> struct stringify { + const char *value; + operator const char*() const { return value; } + stringify(char *value) : value(value) {} +}; + +template<> struct stringify { + const char *value; + operator const char*() const { return value; } + stringify(const char *value) : value(value) {} +}; + +template<> struct stringify { + const string &value; + operator const char*() const { return value; } + stringify(const string &value) : value(value) {} +}; + +template<> struct stringify { + const string &value; + operator const char*() const { return value; } + stringify(const string &value) : value(value) {} +}; + +template<> struct stringify { + const char *value; + operator const char*() const { return value; } + stringify(const cstring &value) : value(value) {} +}; + +template<> struct stringify { + const char *value; + operator const char*() const { return value; } + stringify(const cstring &value) : value(value) {} +}; #if defined(QSTRING_H) -template<> inline const char* to_string(QString v) { return v.toUtf8().constData(); } -template<> inline const char* to_string(const QString &v) { return v.toUtf8().constData(); } -string::operator QString() const { return QString::fromUtf8(*this); } + +template<> struct stringify { + const QString &value; + operator const char*() const { return value.toUtf8().constData(); } + stringify(const QString &value) : value(value) {} +}; + +template<> struct stringify { + const QString &value; + operator const char*() const { return value.toUtf8().constData(); } + stringify(const QString &value) : value(value) {} +}; + +string::operator QString() const { + return QString::fromUtf8(*this); +} + #endif +// + +template stringify make_string(T value) { + return stringify(std::forward(value)); +} + } #endif diff --git a/snesfilter/nall/string/compare.hpp b/snesfilter/nall/string/compare.hpp index ad311d74..941c8e67 100755 --- a/snesfilter/nall/string/compare.hpp +++ b/snesfilter/nall/string/compare.hpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_COMPARE_HPP -#define NALL_STRING_COMPARE_HPP +#ifdef NALL_STRING_INTERNAL_HPP namespace nall { @@ -19,46 +18,6 @@ int istrcmp(const char *str1, const char *str2) { return (int)chrlower(*str1) - (int)chrlower(*str2); } -bool wildcard(const char *s, const char *p) { - const char *cp = 0, *mp = 0; - while(*s && *p != '*') { - if(*p != '?' && *s != *p) return false; - p++, s++; - } - while(*s) { - if(*p == '*') { - if(!*++p) return true; - mp = p, cp = s + 1; - } else if(*p == '?' || *p == *s) { - p++, s++; - } else { - p = mp, s = cp++; - } - } - while(*p == '*') p++; - return !*p; -} - -bool iwildcard(const char *s, const char *p) { - const char *cp = 0, *mp = 0; - while(*s && *p != '*') { - if(*p != '?' && chrlower(*s) != chrlower(*p)) return false; - p++, s++; - } - while(*s) { - if(*p == '*') { - if(!*++p) return true; - mp = p, cp = s + 1; - } else if(*p == '?' || chrlower(*p) == chrlower(*s)) { - p++, s++; - } else { - p = mp, s = cp++; - } - } - while(*p == '*') p++; - return !*p; -} - bool strbegin(const char *str, const char *key) { int i, ssl = strlen(str), ksl = strlen(key); diff --git a/snesfilter/nall/string/convert.hpp b/snesfilter/nall/string/convert.hpp index 3dd487f6..f5a2a780 100755 --- a/snesfilter/nall/string/convert.hpp +++ b/snesfilter/nall/string/convert.hpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_CONVERT_HPP -#define NALL_STRING_CONVERT_HPP +#ifdef NALL_STRING_INTERNAL_HPP namespace nall { @@ -60,86 +59,6 @@ char* strtr(char *dest, const char *before, const char *after) { return dest; } -uintmax_t hex(const char *str) { - if(!str) return 0; - uintmax_t result = 0; - - //skip hex identifiers 0x and $, if present - if(*str == '0' && (*(str + 1) == 'X' || *(str + 1) == 'x')) str += 2; - else if(*str == '$') str++; - - while(*str) { - uint8_t x = *str++; - if(x >= '0' && x <= '9') x -= '0'; - else if(x >= 'A' && x <= 'F') x -= 'A' - 10; - else if(x >= 'a' && x <= 'f') x -= 'a' - 10; - else break; //stop at first invalid character - result = result * 16 + x; - } - - return result; -} - -intmax_t integer(const char *str) { - if(!str) return 0; - intmax_t result = 0; - bool negate = false; - - //check for sign - if(*str == '+') { - negate = false; - str++; - } else if(*str == '-') { - negate = true; - str++; - } - - while(*str) { - uint8_t x = *str++; - if(x >= '0' && x <= '9') x -= '0'; - else break; //stop at first invalid character - result = result * 10 + x; - } - - return !negate ? result : -result; -} - -uintmax_t decimal(const char *str) { - if(!str) return 0; - uintmax_t result = 0; - - while(*str) { - uint8_t x = *str++; - if(x >= '0' && x <= '9') x -= '0'; - else break; //stop at first invalid character - result = result * 10 + x; - } - - return result; -} - -uintmax_t binary(const char *str) { - if(!str) return 0; - uintmax_t result = 0; - - //skip bin identifiers 0b and %, if present - if(*str == '0' && (*(str + 1) == 'B' || *(str + 1) == 'b')) str += 2; - else if(*str == '%') str++; - - while(*str) { - uint8_t x = *str++; - if(x == '0' || x == '1') x -= '0'; - else break; //stop at first invalid character - result = result * 2 + x; - } - - return result; -} - -double fp(const char *str) { - return atof(str); -} - } #endif diff --git a/snesfilter/nall/string/core.hpp b/snesfilter/nall/string/core.hpp index e2af4eea..5ae2bd48 100755 --- a/snesfilter/nall/string/core.hpp +++ b/snesfilter/nall/string/core.hpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_CORE_HPP -#define NALL_STRING_CORE_HPP +#ifdef NALL_STRING_INTERNAL_HPP namespace nall { @@ -8,7 +7,7 @@ static void istring(string &output) { template static void istring(string &output, const T &value, Args&&... args) { - output.append_(to_string(value)); + output.append_(make_string(value)); istring(output, std::forward(args)...); } @@ -76,7 +75,7 @@ string& string::operator=(string &&source) { if(data) free(data); size = source.size; data = source.data; - source.data = 0; + source.data = nullptr; source.size = 0; return *this; } @@ -98,7 +97,7 @@ string::string(string &&source) { if(&source == this) return; size = source.size; data = source.data; - source.data = 0; + source.data = nullptr; } string::~string() { @@ -152,9 +151,7 @@ inline lstring::lstring() { } inline lstring::lstring(std::initializer_list list) { - for(const string *s = list.begin(); s != list.end(); ++s) { - operator<<(*s); - } + for(auto &data : list) append(data); } } diff --git a/snesfilter/nall/string/cstring.hpp b/snesfilter/nall/string/cstring.hpp new file mode 100755 index 00000000..13b508ff --- /dev/null +++ b/snesfilter/nall/string/cstring.hpp @@ -0,0 +1,21 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +//const string: +//bind a const char* pointer to an object that has various testing functionality; +//yet lacks the memory allocation and modification functionality of the string class + +namespace nall { + +cstring::operator const char*() const { return data; } +unsigned cstring::length() const { return strlen(data); } +bool cstring::operator==(const char *s) const { return !strcmp(data, s); } +bool cstring::operator!=(const char *s) const { return strcmp(data, s); } +optional cstring::position (const char *key) const { return strpos(data, key); } +optional cstring::iposition(const char *key) const { return istrpos(data, key); } +cstring& cstring::operator=(const char *data) { this->data = data; return *this; } +cstring::cstring(const char *data) : data(data) {} +cstring::cstring() : data("") {} + +} + +#endif diff --git a/snesfilter/nall/string/filename.hpp b/snesfilter/nall/string/filename.hpp index 93d605ae..6dea67fc 100755 --- a/snesfilter/nall/string/filename.hpp +++ b/snesfilter/nall/string/filename.hpp @@ -1,5 +1,4 @@ -#ifndef NALL_FILENAME_HPP -#define NALL_FILENAME_HPP +#ifdef NALL_STRING_INTERNAL_HPP namespace nall { diff --git a/snesfilter/nall/string/math-fixed-point.hpp b/snesfilter/nall/string/math-fixed-point.hpp new file mode 100755 index 00000000..744621d1 --- /dev/null +++ b/snesfilter/nall/string/math-fixed-point.hpp @@ -0,0 +1,157 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace fixedpoint { + +static nall::function eval_fallback; + +static intmax_t eval_integer(const char *& s) { + if(!*s) throw "unrecognized integer"; + intmax_t value = 0, x = *s, y = *(s + 1); + + //hexadecimal + if(x == '0' && (y == 'X' || y == 'x')) { + s += 2; + while(true) { + if(*s >= '0' && *s <= '9') { value = value * 16 + (*s++ - '0'); continue; } + if(*s >= 'A' && *s <= 'F') { value = value * 16 + (*s++ - 'A' + 10); continue; } + if(*s >= 'a' && *s <= 'f') { value = value * 16 + (*s++ - 'a' + 10); continue; } + return value; + } + } + + //binary + if(x == '0' && (y == 'B' || y == 'b')) { + s += 2; + while(true) { + if(*s == '0' || *s == '1') { value = value * 2 + (*s++ - '0'); continue; } + return value; + } + } + + //octal (or decimal '0') + if(x == '0') { + s += 1; + while(true) { + if(*s >= '0' && *s <= '7') { value = value * 8 + (*s++ - '0'); continue; } + return value; + } + } + + //decimal + if(x >= '0' && x <= '9') { + while(true) { + if(*s >= '0' && *s <= '9') { value = value * 10 + (*s++ - '0'); continue; } + return value; + } + } + + //char + if(x == '\'' && y != '\'') { + s += 1; + while(true) { + value = value * 256 + *s++; + if(*s == '\'') { s += 1; return value; } + if(!*s) throw "mismatched char"; + } + } + + throw "unrecognized integer"; +} + +static intmax_t eval(const char *&s, int depth = 0) { + while(*s == ' ' || *s == '\t') s++; //trim whitespace + if(!*s) throw "unrecognized token"; + intmax_t value = 0, x = *s, y = *(s + 1); + + if(*s == '(') { + value = eval(++s, 1); + if(*s++ != ')') throw "mismatched group"; + } + + else if(x == '!') value = !eval(++s, 13); + else if(x == '~') value = ~eval(++s, 13); + else if(x == '+') value = +eval(++s, 13); + else if(x == '-') value = -eval(++s, 13); + + else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s); + + else if(eval_fallback) value = eval_fallback(s); //optional user-defined syntax parsing + + else throw "unrecognized token"; + + while(true) { + while(*s == ' ' || *s == '\t') s++; //trim whitespace + if(!*s) break; + x = *s, y = *(s + 1); + + if(depth >= 13) break; + if(x == '*') { value *= eval(++s, 13); continue; } + if(x == '/') { intmax_t result = eval(++s, 13); if(result == 0) throw "division by zero"; value /= result; continue; } + if(x == '%') { intmax_t result = eval(++s, 13); if(result == 0) throw "division by zero"; value %= result; continue; } + + if(depth >= 12) break; + if(x == '+') { value += eval(++s, 12); continue; } + if(x == '-') { value -= eval(++s, 12); continue; } + + if(depth >= 11) break; + if(x == '<' && y == '<') { value <<= eval(++++s, 11); continue; } + if(x == '>' && y == '>') { value >>= eval(++++s, 11); continue; } + + if(depth >= 10) break; + if(x == '<' && y == '=') { value = value <= eval(++++s, 10); continue; } + if(x == '>' && y == '=') { value = value >= eval(++++s, 10); continue; } + if(x == '<') { value = value < eval(++s, 10); continue; } + if(x == '>') { value = value > eval(++s, 10); continue; } + + if(depth >= 9) break; + if(x == '=' && y == '=') { value = value == eval(++++s, 9); continue; } + if(x == '!' && y == '=') { value = value != eval(++++s, 9); continue; } + + if(depth >= 8) break; + if(x == '&' && y != '&') { value = value & eval(++s, 8); continue; } + + if(depth >= 7) break; + if(x == '^' && y != '^') { value = value ^ eval(++s, 7); continue; } + + if(depth >= 6) break; + if(x == '|' && y != '|') { value = value | eval(++s, 6); continue; } + + if(depth >= 5) break; + if(x == '&' && y == '&') { value = eval(++++s, 5) && value; continue; } + + if(depth >= 4) break; + if(x == '^' && y == '^') { value = (!eval(++++s, 4) != !value); continue; } + + if(depth >= 3) break; + if(x == '|' && y == '|') { value = eval(++++s, 3) || value; continue; } + + if(x == '?') { + intmax_t lhs = eval(++s, 2); + if(*s != ':') throw "mismatched ternary"; + intmax_t rhs = eval(++s, 2); + value = value ? lhs : rhs; + continue; + } + if(depth >= 2) break; + + if(depth > 0 && x == ')') break; + + throw "unrecognized token"; + } + + return value; +} + +static bool eval(const char *s, intmax_t &result) { + try { + result = eval(s); + return true; + } catch(const char*) { + result = 0; + return false; + } +} + +} + +#endif diff --git a/snesfilter/nall/string/math-floating-point.hpp b/snesfilter/nall/string/math-floating-point.hpp new file mode 100755 index 00000000..85680aad --- /dev/null +++ b/snesfilter/nall/string/math-floating-point.hpp @@ -0,0 +1,149 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace floatingpoint { + +static nall::function eval_fallback; + +static double eval_integer(const char *&s) { + if(!*s) throw "unrecognized integer"; + intmax_t value = 0, radix = 0, x = *s, y = *(s + 1); + + //hexadecimal + if(x == '0' && (y == 'X' || y == 'x')) { + s += 2; + while(true) { + if(*s >= '0' && *s <= '9') { value = value * 16 + (*s++ - '0'); continue; } + if(*s >= 'A' && *s <= 'F') { value = value * 16 + (*s++ - 'A' + 10); continue; } + if(*s >= 'a' && *s <= 'f') { value = value * 16 + (*s++ - 'a' + 10); continue; } + return value; + } + } + + //binary + if(x == '0' && (y == 'B' || y == 'b')) { + s += 2; + while(true) { + if(*s == '0' || *s == '1') { value = value * 2 + (*s++ - '0'); continue; } + return value; + } + } + + //octal (or decimal '0') + if(x == '0' && y != '.') { + s += 1; + while(true) { + if(*s >= '0' && *s <= '7') { value = value * 8 + (*s++ - '0'); continue; } + return value; + } + } + + //decimal + if(x >= '0' && x <= '9') { + while(true) { + if(*s >= '0' && *s <= '9') { value = value * 10 + (*s++ - '0'); continue; } + if(*s == '.') { s++; break; } + return value; + } + //floating-point + while(true) { + if(*s >= '0' && *s <= '9') { radix = radix * 10 + (*s++ - '0'); continue; } + return atof(nall::string{ nall::decimal(value), ".", nall::decimal(radix) }); + } + } + + //char + if(x == '\'' && y != '\'') { + s += 1; + while(true) { + value = value * 256 + *s++; + if(*s == '\'') { s += 1; return value; } + if(!*s) throw "mismatched char"; + } + } + + throw "unrecognized integer"; +} + +static double eval(const char *&s, int depth = 0) { + while(*s == ' ' || *s == '\t') s++; //trim whitespace + if(!*s) throw "unrecognized token"; + double value = 0, x = *s, y = *(s + 1); + + if(*s == '(') { + value = eval(++s, 1); + if(*s++ != ')') throw "mismatched group"; + } + + else if(x == '!') value = !eval(++s, 9); + else if(x == '+') value = +eval(++s, 9); + else if(x == '-') value = -eval(++s, 9); + + else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s); + + else if(eval_fallback) value = eval_fallback(s); //optional user-defined syntax parsing + + else throw "unrecognized token"; + + while(true) { + while(*s == ' ' || *s == '\t') s++; //trim whitespace + if(!*s) break; + x = *s, y = *(s + 1); + + if(depth >= 9) break; + if(x == '*') { value *= eval(++s, 9); continue; } + if(x == '/') { double result = eval(++s, 9); if(result == 0.0) throw "division by zero"; value /= result; continue; } + + if(depth >= 8) break; + if(x == '+') { value += eval(++s, 8); continue; } + if(x == '-') { value -= eval(++s, 8); continue; } + + if(depth >= 7) break; + if(x == '<' && y == '=') { value = value <= eval(++++s, 7); continue; } + if(x == '>' && y == '=') { value = value >= eval(++++s, 7); continue; } + if(x == '<') { value = value < eval(++s, 7); continue; } + if(x == '>') { value = value > eval(++s, 7); continue; } + + if(depth >= 6) break; + if(x == '=' && y == '=') { value = value == eval(++++s, 6); continue; } + if(x == '!' && y == '=') { value = value != eval(++++s, 6); continue; } + + if(depth >= 5) break; + if(x == '&' && y == '&') { value = eval(++++s, 5) && value; continue; } + + if(depth >= 4) break; + if(x == '^' && y == '^') { value = (!eval(++++s, 4) != !value); continue; } + + if(depth >= 3) break; + if(x == '|' && y == '|') { value = eval(++++s, 3) || value; continue; } + + if(x == '?') { + double lhs = eval(++s, 2); + if(*s != ':') throw "mismatched ternary"; + double rhs = eval(++s, 2); + value = value ? lhs : rhs; + continue; + } + if(depth >= 2) break; + + if(depth > 0 && x == ')') break; + + throw "unrecognized token"; + } + + return value; +} + +static bool eval(const char *s, double &result) { + try { + result = eval(s); + return true; + } catch(const char*e) { +printf("%s\n", e); + result = 0; + return false; + } +} + +} + +#endif diff --git a/snesfilter/nall/string/math.hpp b/snesfilter/nall/string/math.hpp index d4bc9d25..8356e162 100755 --- a/snesfilter/nall/string/math.hpp +++ b/snesfilter/nall/string/math.hpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_MATH_HPP -#define NALL_STRING_MATH_HPP +#ifdef NALL_STRING_INTERNAL_HPP namespace nall { @@ -87,8 +86,8 @@ static int eval(const char *&s, int depth = 0) { if(depth >= 13) break; if(x == '*') { value *= eval(++s, 13); continue; } - if(x == '/') { value /= eval(++s, 13); continue; } - if(x == '%') { value %= eval(++s, 13); continue; } + if(x == '/') { int result = eval(++s, 13); if(result == 0) throw "division_by_zero"; value /= result; continue; } + if(x == '%') { int result = eval(++s, 13); if(result == 0) throw "division_by_zero"; value %= result; continue; } if(depth >= 12) break; if(x == '+') { value += eval(++s, 12); continue; } diff --git a/snesfilter/nall/string/platform.hpp b/snesfilter/nall/string/platform.hpp index 0deda430..83a5fbae 100755 --- a/snesfilter/nall/string/platform.hpp +++ b/snesfilter/nall/string/platform.hpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_PLATFORM_HPP -#define NALL_STRING_PLATFORM_HPP +#ifdef NALL_STRING_INTERNAL_HPP namespace nall { diff --git a/snesfilter/nall/string/replace.hpp b/snesfilter/nall/string/replace.hpp index 7c7a09d4..2bd1412f 100755 --- a/snesfilter/nall/string/replace.hpp +++ b/snesfilter/nall/string/replace.hpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_REPLACE_HPP -#define NALL_STRING_REPLACE_HPP +#ifdef NALL_STRING_INTERNAL_HPP namespace nall { diff --git a/snesfilter/nall/string/split.hpp b/snesfilter/nall/string/split.hpp index 1644401b..bb12a91b 100755 --- a/snesfilter/nall/string/split.hpp +++ b/snesfilter/nall/string/split.hpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_SPLIT_HPP -#define NALL_STRING_SPLIT_HPP +#ifdef NALL_STRING_INTERNAL_HPP namespace nall { @@ -8,14 +7,13 @@ template 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(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; @@ -24,7 +22,7 @@ template lstring& lstring::usplit } } - operator[](counter) = base; + append(base); return *this; } diff --git a/snesfilter/nall/string/strl.hpp b/snesfilter/nall/string/strl.hpp index 84c841fa..44f6d6f7 100755 --- a/snesfilter/nall/string/strl.hpp +++ b/snesfilter/nall/string/strl.hpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_STRL_HPP -#define NALL_STRING_STRL_HPP +#ifdef NALL_STRING_INTERNAL_HPP namespace nall { diff --git a/snesfilter/nall/string/strpos.hpp b/snesfilter/nall/string/strpos.hpp index 3b28923e..fe563a6c 100755 --- a/snesfilter/nall/string/strpos.hpp +++ b/snesfilter/nall/string/strpos.hpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_STRPOS_HPP -#define NALL_STRING_STRPOS_HPP +#ifdef NALL_STRING_INTERNAL_HPP //usage example: //if(auto position = strpos(str, key)) print(position(), "\n"); diff --git a/snesfilter/nall/string/trim.hpp b/snesfilter/nall/string/trim.hpp index d1f15ee1..ba049d71 100755 --- a/snesfilter/nall/string/trim.hpp +++ b/snesfilter/nall/string/trim.hpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_TRIM_HPP -#define NALL_STRING_TRIM_HPP +#ifdef NALL_STRING_INTERNAL_HPP namespace nall { diff --git a/snesfilter/nall/string/utility.hpp b/snesfilter/nall/string/utility.hpp index 13faaf64..2212688b 100755 --- a/snesfilter/nall/string/utility.hpp +++ b/snesfilter/nall/string/utility.hpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_UTILITY_HPP -#define NALL_STRING_UTILITY_HPP +#ifdef NALL_STRING_INTERNAL_HPP namespace nall { @@ -65,15 +64,51 @@ string sha256(const uint8_t *data, unsigned size) { sha256_final(&sha); sha256_hash(&sha, hash); string result; - foreach(byte, hash) result.append(hex<2>(byte)); + for(auto &byte : hash) result.append(hex<2>(byte)); return result; } -/* arithmetic <> string */ +/* cast.hpp arithmetic -> string */ + +char* integer(char *result, intmax_t value) { + bool negative = value < 0; + if(negative) value = -value; + + char buffer[64]; + unsigned size = 0; + + do { + unsigned n = value % 10; + buffer[size++] = '0' + n; + value /= 10; + } while(value); + buffer[size++] = negative ? '-' : '+'; + + for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) result[x] = buffer[y]; + result[size] = 0; + return result; +} + +char* decimal(char *result, uintmax_t value) { + char buffer[64]; + unsigned size = 0; + + do { + unsigned n = value % 10; + buffer[size++] = '0' + n; + value /= 10; + } while(value); + + for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) result[x] = buffer[y]; + result[size] = 0; + return result; +} + +/* general-purpose arithmetic -> string */ template string integer(intmax_t value) { bool negative = value < 0; - if(negative) value = abs(value); + if(negative) value = -value; char buffer[64]; unsigned size = 0; @@ -100,7 +135,7 @@ template string integer(intmax_t value) { template string linteger(intmax_t value) { bool negative = value < 0; - if(negative) value = abs(value); + if(negative) value = -value; char buffer[64]; unsigned size = 0; @@ -218,9 +253,14 @@ template string binary(uintmax_t value) { //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 fp(char *str, double value) { +unsigned fp(char *str, long double value) { char buffer[256]; - sprintf(buffer, "%f", value); + #ifdef _WIN32 + //Windows C-runtime does not support long double via sprintf() + sprintf(buffer, "%f", (double)value); + #else + sprintf(buffer, "%Lf", value); + #endif //remove excess 0's in fraction (2.500000 -> 2.5) for(char *p = buffer; *p; p++) { @@ -239,7 +279,7 @@ unsigned fp(char *str, double value) { return length + 1; } -string fp(double value) { +string fp(long double value) { string temp; temp.reserve(fp(0, value)); fp(temp(), value); diff --git a/snesfilter/nall/string/variadic.hpp b/snesfilter/nall/string/variadic.hpp index 6c027fc8..c43bfe86 100755 --- a/snesfilter/nall/string/variadic.hpp +++ b/snesfilter/nall/string/variadic.hpp @@ -1,5 +1,4 @@ -#ifndef NALL_STRING_VARIADIC_HPP -#define NALL_STRING_VARIADIC_HPP +#ifdef NALL_STRING_INTERNAL_HPP namespace nall { diff --git a/snesfilter/nall/string/wildcard.hpp b/snesfilter/nall/string/wildcard.hpp new file mode 100755 index 00000000..9d2359d5 --- /dev/null +++ b/snesfilter/nall/string/wildcard.hpp @@ -0,0 +1,78 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +bool wildcard(const char *s, const char *p) { + const char *cp = 0, *mp = 0; + while(*s && *p != '*') { + if(*p != '?' && *s != *p) return false; + p++, s++; + } + while(*s) { + if(*p == '*') { + if(!*++p) return true; + mp = p, cp = s + 1; + } else if(*p == '?' || *p == *s) { + p++, s++; + } else { + p = mp, s = cp++; + } + } + while(*p == '*') p++; + return !*p; +} + +bool iwildcard(const char *s, const char *p) { + const char *cp = 0, *mp = 0; + while(*s && *p != '*') { + if(*p != '?' && chrlower(*s) != chrlower(*p)) return false; + p++, s++; + } + while(*s) { + if(*p == '*') { + if(!*++p) return true; + mp = p, cp = s + 1; + } else if(*p == '?' || chrlower(*p) == chrlower(*s)) { + p++, s++; + } else { + p = mp, s = cp++; + } + } + while(*p == '*') p++; + return !*p; +} + +inline bool tokenize(const char *s, const char *p) { + while(*s) { + if(*p == '*') { + while(*s) if(tokenize(s++, p + 1)) return true; + return !*++p; + } + if(*s++ != *p++) return false; + } + while(*p == '*') p++; + return !*p; +} + +inline bool tokenize(lstring &list, const char *s, const char *p) { + while(*s) { + if(*p == '*') { + const char *b = s; + while(*s) { + if(tokenize(list, s++, p + 1)) { + list.prepend(substr(b, 0, --s - b)); + return true; + } + } + list.prepend(b); + return !*++p; + } + if(*s++ != *p++) return false; + } + while(*p == '*') { list.prepend(s); p++; } + return !*p; +} + +} + +#endif diff --git a/snesfilter/nall/string/wrapper.hpp b/snesfilter/nall/string/wrapper.hpp index a28c1ced..c02d5396 100755 --- a/snesfilter/nall/string/wrapper.hpp +++ b/snesfilter/nall/string/wrapper.hpp @@ -1,10 +1,14 @@ -#ifndef NALL_STRING_WRAPPER_HPP -#define NALL_STRING_WRAPPER_HPP +#ifdef NALL_STRING_INTERNAL_HPP namespace nall { unsigned string::length() const { return strlen(data); } +template lstring string::split(const char *key) const { lstring result; result.split(key, data); return result; } +template lstring string::isplit(const char *key) const { lstring result; result.isplit(key, data); return result; } +template lstring string::qsplit(const char *key) const { lstring result; result.qsplit(key, data); return result; } +template lstring string::iqsplit(const char *key) const { lstring result; result.iqsplit(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); } diff --git a/snesfilter/nall/string/xml.hpp b/snesfilter/nall/string/xml.hpp index 47653786..069639b0 100755 --- a/snesfilter/nall/string/xml.hpp +++ b/snesfilter/nall/string/xml.hpp @@ -1,8 +1,7 @@ -#ifndef NALL_STRING_XML_HPP -#define NALL_STRING_XML_HPP +#ifdef NALL_STRING_INTERNAL_HPP -//XML subset parser -//version 0.05 +//XML v1.0 subset parser +//revision 0.05 namespace nall { diff --git a/snesfilter/nall/test/cc.sh b/snesfilter/nall/test/cc.sh index d084a256..142a1b0c 100755 --- a/snesfilter/nall/test/cc.sh +++ b/snesfilter/nall/test/cc.sh @@ -1,2 +1,2 @@ -g++-4.5 -std=gnu++0x -g -o test test.cpp -I../.. -#g++-4.5 -std=gnu++0x -O3 -fomit-frame-pointer -s -o test test.cpp -I../.. +g++-4.6 -std=gnu++0x -g -o test test.cpp -I../.. +#g++-4.6 -std=gnu++0x -O3 -fomit-frame-pointer -s -o test test.cpp -I../.. diff --git a/snesfilter/nall/test/document.bml b/snesfilter/nall/test/document.bml new file mode 100755 index 00000000..25773f2c --- /dev/null +++ b/snesfilter/nall/test/document.bml @@ -0,0 +1,14 @@ +# bml version=1.0 +cartridge=SNES region=NTSC origin:United States + title:The Legend of Zelda: A Link to the Past + empty-line~ + description~ language:English + Gannon has kidnapped princess Zelda. + Help Link rescue her!! + pcb:SHVC-1A3M-30 + rom + map mode=linear address=00-3f:8000-ffff + map mode=linear address=80-bf:8000-ffff + ram battery + map mode=linear address=70-7f:0000-7fff + map mode=linear address=f0-ff:0000-7fff diff --git a/snesfilter/nall/test/test b/snesfilter/nall/test/test index 56b80ee4..d12c2b37 100755 Binary files a/snesfilter/nall/test/test and b/snesfilter/nall/test/test differ diff --git a/snesfilter/nall/test/test.cpp b/snesfilter/nall/test/test.cpp index 3449661a..e2613b20 100755 --- a/snesfilter/nall/test/test.cpp +++ b/snesfilter/nall/test/test.cpp @@ -3,19 +3,19 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include +#include #include #include +#include #include #include #include @@ -42,9 +42,49 @@ #include using namespace nall; -int main(int main, char **argv) { - lstring a = { "hey", "hi" }, b = { "hey", "hi" }; - print(a == b, "\n"); +int main() { + image x(0, 64, 65535ull << 48, 65535ull << 32, 65535ull << 16, 65535ull << 0); + x.allocate(4, 1); + + uint64_t *data = (uint64_t*)x.data; + data[0] = 0xffffffffffffffffull; + data[1] = 0x0000ffff00000000ull; + data[2] = 0x00000000ffff0000ull; + data[3] = 0x000000000000ffffull; + + x.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); + + uint32_t *output = (uint32_t*)x.data; + print(hex<8>(output[0]), "\n"); + print(hex<8>(output[1]), "\n"); + print(hex<8>(output[2]), "\n"); + print(hex<8>(output[3]), "\n"); return 0; } + +/* +int main(int argc, char **argv) { + string text; + text.readfile("document.bml"); + BML::Document document(text); + if(document.error) print(document.error, "\n"); + + for(auto &a : document) { + print("", a.name, ":", a.value, ";\n"); + for(auto &b : a) { + print(" ", b.name, ":", b.value, ";\n"); + for(auto &c : b) { + print(" ", c.name, ":", c.value, ";\n"); + for(auto &d : c) { + print(" ", d.name, ":", d.value, ";\n"); + } + } + } + } + +//print(document["cartridge"]["title"].value, "\n"); + + return 0; +} +*/ diff --git a/snesfilter/nall/utility.hpp b/snesfilter/nall/utility.hpp index 374b5469..ff8d8bee 100755 --- a/snesfilter/nall/utility.hpp +++ b/snesfilter/nall/utility.hpp @@ -21,6 +21,7 @@ namespace nall { }; template class optional { + public: bool valid; T value; public: diff --git a/snesfilter/nall/vector.hpp b/snesfilter/nall/vector.hpp index f98eb375..1af16d29 100755 --- a/snesfilter/nall/vector.hpp +++ b/snesfilter/nall/vector.hpp @@ -1,17 +1,131 @@ #ifndef NALL_VECTOR_HPP #define NALL_VECTOR_HPP +#include #include #include #include #include #include #include -#include -#include #include namespace nall { + template 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 + void append(const T& data, Args&&... args) { + append(data); + append(std::forward(args)...); + } + + void append(const T& data) { + if(objectsize + 1 > poolsize) reserve(objectsize + 1); + new(pool + objectsize++) T(data); + } + + void prepend(const T& data) { + append(data); + for(unsigned n = objectsize - 1; n; n--) swap(pool[n], pool[n - 1]); + } + + 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 list) : pool(nullptr), poolsize(0), objectsize(0) { + for(auto &data : list) append(data); + } + + ~vector() { + reset(); + } + }; + //linear_vector //memory: O(capacity * 2) // @@ -24,7 +138,7 @@ namespace nall { //if objects hold memory address references to themselves (introspection), a //valid copy constructor will be needed to keep pointers valid. - template class linear_vector { + template struct linear_vector { protected: T *pool; unsigned poolsize, objectsize; @@ -38,7 +152,7 @@ namespace nall { for(unsigned i = 0; i < objectsize; i++) pool[i].~T(); free(pool); } - pool = 0; + pool = nullptr; poolsize = 0; objectsize = 0; } @@ -77,7 +191,7 @@ namespace nall { template void insert(unsigned index, const U list) { linear_vector merged; for(unsigned i = 0; i < index; i++) merged.append(pool[i]); - foreach(item, list) merged.append(item); + for(auto &item : list) merged.append(item); for(unsigned i = index; i < objectsize; i++) merged.append(pool[i]); operator=(merged); } @@ -94,10 +208,10 @@ namespace nall { else resize(objectsize - count); } - linear_vector() : pool(0), poolsize(0), objectsize(0) { + linear_vector() : pool(nullptr), poolsize(0), objectsize(0) { } - linear_vector(std::initializer_list list) : pool(0), poolsize(0), objectsize(0) { + linear_vector(std::initializer_list list) : pool(nullptr), poolsize(0), objectsize(0) { for(const T *p = list.begin(); p != list.end(); ++p) append(*p); } @@ -114,7 +228,7 @@ namespace nall { return *this; } - linear_vector(const linear_vector &source) : pool(0), poolsize(0), objectsize(0) { + linear_vector(const linear_vector &source) : pool(nullptr), poolsize(0), objectsize(0) { operator=(source); } @@ -124,12 +238,12 @@ namespace nall { pool = source.pool; poolsize = source.poolsize; objectsize = source.objectsize; - source.pool = 0; + source.pool = nullptr; source.reset(); return *this; } - linear_vector(linear_vector &&source) : pool(0), poolsize(0), objectsize(0) { + linear_vector(linear_vector &&source) : pool(nullptr), poolsize(0), objectsize(0) { operator=(std::move(source)); } @@ -161,7 +275,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 class pointer_vector { + template struct pointer_vector { protected: T **pool; unsigned poolsize, objectsize; @@ -175,7 +289,7 @@ namespace nall { for(unsigned i = 0; i < objectsize; i++) { if(pool[i]) delete pool[i]; } free(pool); } - pool = 0; + pool = nullptr; poolsize = 0; objectsize = 0; } @@ -211,7 +325,7 @@ namespace nall { template void insert(unsigned index, const U list) { pointer_vector merged; for(unsigned i = 0; i < index; i++) merged.append(*pool[i]); - foreach(item, list) merged.append(item); + for(auto &item : list) merged.append(item); for(unsigned i = index; i < objectsize; i++) merged.append(*pool[i]); operator=(merged); } @@ -228,10 +342,10 @@ namespace nall { else resize(objectsize - count); } - pointer_vector() : pool(0), poolsize(0), objectsize(0) { + pointer_vector() : pool(nullptr), poolsize(0), objectsize(0) { } - pointer_vector(std::initializer_list list) : pool(0), poolsize(0), objectsize(0) { + pointer_vector(std::initializer_list list) : pool(nullptr), poolsize(0), objectsize(0) { for(const T *p = list.begin(); p != list.end(); ++p) append(*p); } @@ -248,7 +362,7 @@ namespace nall { return *this; } - pointer_vector(const pointer_vector &source) : pool(0), poolsize(0), objectsize(0) { + pointer_vector(const pointer_vector &source) : pool(nullptr), poolsize(0), objectsize(0) { operator=(source); } @@ -258,12 +372,12 @@ namespace nall { pool = source.pool; poolsize = source.poolsize; objectsize = source.objectsize; - source.pool = 0; + source.pool = nullptr; source.reset(); return *this; } - pointer_vector(pointer_vector &&source) : pool(0), poolsize(0), objectsize(0) { + pointer_vector(pointer_vector &&source) : pool(nullptr), poolsize(0), objectsize(0) { operator=(std::move(source)); } @@ -284,18 +398,17 @@ namespace nall { bool operator!=(const iterator &source) const { return index != source.index; } T& operator*() { return vector.operator[](index); } iterator& operator++() { index++; return *this; } - iterator(pointer_vector &vector, unsigned index) : vector(vector), index(index) {} + iterator(const pointer_vector &vector, unsigned index) : vector(vector), index(index) {} private: - pointer_vector &vector; + const pointer_vector &vector; unsigned index; }; iterator begin() { return iterator(*this, 0); } iterator end() { return iterator(*this, objectsize); } + const iterator begin() const { return iterator(*this, 0); } + const iterator end() const { return iterator(*this, objectsize); } }; - - template struct has_size> { enum { value = true }; }; - template struct has_size> { enum { value = true }; }; } #endif