Update to v084r03 release.

(r02 was not posted to the WIP thread)

byuu says:

Internally, all color is processed with 30-bit precision. The filters
also operate at 30-bit depth.
There's a new config file setting, video.depth, which defaults to 24.
This causes the final output to downsample to 24-bit, as most will
require.
If you set it to 30-bit, the downsampling will not occur, and bsnes will
ask ruby for a 30-bit surface. If you don't have one available, you're
going to get bad colors. Or maybe even a crash with OpenGL.
I don't yet have detection code to make sure you have an appropriate
visual in place.

30-bit mode will really only work if you are running Linux, running Xorg
at Depth 30, use the OpenGL or XShm driver, have an nVidia Quadro or AMD
FireGL card with the official drivers, and have a 30-bit capable
monitor.
Lots of planning and work for very little gain here, but it's nice that
it's finally finished.

Oh, I had to change the contrast/brightness formulas a tiny bit, but
they still work and look nice.
This commit is contained in:
Tim Allen 2011-12-03 14:22:54 +11:00
parent 2cc077e12b
commit ad0805b168
145 changed files with 4653 additions and 1455 deletions

View File

@ -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)

View File

@ -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() {

433
bsnes/nall/image.hpp Executable file
View File

@ -0,0 +1,433 @@
#ifndef NALL_IMAGE_HPP
#define NALL_IMAGE_HPP
#include <nall/bmp.hpp>
#include <nall/interpolation.hpp>
#include <nall/png.hpp>
#include <nall/stdint.hpp>
#include <algorithm>
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<image>(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

59
bsnes/nall/interpolation.hpp Executable file
View File

@ -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

View File

@ -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;
}
}

View File

@ -32,6 +32,8 @@
#include <nall/string/cstring.hpp>
#include <nall/string/filename.hpp>
#include <nall/string/math.hpp>
#include <nall/string/math-fixed-point.hpp>
#include <nall/string/math-floating-point.hpp>
#include <nall/string/platform.hpp>
#include <nall/string/strl.hpp>
#include <nall/string/strpos.hpp>

View File

@ -183,8 +183,8 @@ namespace nall {
template<unsigned length = 0, char padding = ' '> inline string ldecimal(uintmax_t value);
template<unsigned length = 0, char padding = '0'> inline string hex(uintmax_t value);
template<unsigned length = 0, char padding = '0'> 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<typename... Args> inline void print(Args&&... args);

View File

@ -101,19 +101,19 @@ template<unsigned bits> struct stringify<uint_t<bits>> {
template<> struct stringify<float> {
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<double> {
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<long double> {
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

View File

@ -0,0 +1,157 @@
#ifdef NALL_STRING_INTERNAL_HPP
namespace fixedpoint {
static nall::function<intmax_t (const char *&)> 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

View File

@ -0,0 +1,149 @@
#ifdef NALL_STRING_INTERNAL_HPP
namespace floatingpoint {
static nall::function<double (const char *&)> 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

View File

@ -253,9 +253,14 @@ template<unsigned length_, char padding> 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);

View File

@ -42,7 +42,6 @@ void Input::connect(bool port, Device device) {
}
void Input::power() {
reset();
}
void Input::reset() {

View File

@ -16,7 +16,6 @@ void Scheduler::exit(ExitReason reason) {
}
void Scheduler::power() {
reset();
}
void Scheduler::reset() {

View File

@ -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<Image>(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;

View File

@ -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<pButton&>, Widget {
struct Canvas : private nall::base_from_member<pCanvas&>, Widget {
uint32_t* data();
bool setImage(const Image &image);
bool setImage(const nall::image &image);
void setSize(const Size &size);
Size size();
void update();

View File

@ -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) {

View File

@ -2,10 +2,9 @@
#define PHOENIX_HPP
#include <nall/array.hpp>
#include <nall/bmp.hpp>
#include <nall/config.hpp>
#include <nall/function.hpp>
#include <nall/png.hpp>
#include <nall/image.hpp>
#include <nall/reference_array.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>

View File

@ -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 <QObject>."
#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

View File

@ -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();

View File

@ -1,5 +1,4 @@
class Audio {
public:
struct Audio {
static const char *Handle;
static const char *Synchronize;
static const char *Frequency;

View File

@ -1,5 +1,4 @@
class Input {
public:
struct Input {
static const char *Handle;
static const char *KeyboardSupport;
static const char *MouseSupport;

View File

@ -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

View File

@ -1,6 +1,6 @@
/*
ruby
version: 0.07 (2011-08-14)
version: 0.08 (2011-11-25)
license: public domain
*/

View File

@ -82,6 +82,10 @@ using namespace nall;
#include <ruby/video/wgl.cpp>
#endif
#ifdef VIDEO_XSHM
#include <ruby/video/xshm.cpp>
#endif
#ifdef VIDEO_XV
#include <ruby/video/xv.cpp>
#endif

View File

@ -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;

View File

@ -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<unsigned>(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<unsigned>(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;

View File

@ -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.

View File

@ -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;

170
bsnes/ruby/video/xshm.cpp Executable file
View File

@ -0,0 +1,170 @@
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
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<uintptr_t>(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)
}

View File

@ -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/)

View File

@ -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

View File

@ -0,0 +1,81 @@
#include <snes/snes.hpp>
#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;
}
}

View File

@ -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;

View File

@ -19,7 +19,6 @@ void BSXCartridge::unload() {
}
void BSXCartridge::power() {
reset();
}
void BSXCartridge::reset() {

View File

@ -16,7 +16,6 @@ void BSXFlash::unload() {
}
void BSXFlash::power() {
reset();
}
void BSXFlash::reset() {

View File

@ -14,7 +14,6 @@ void BSXSatellaview::unload() {
}
void BSXSatellaview::power() {
reset();
}
void BSXSatellaview::reset() {

View File

@ -52,7 +52,6 @@ void HitachiDSP::unload() {
}
void HitachiDSP::power() {
reset();
}
void HitachiDSP::reset() {

View File

@ -41,8 +41,6 @@ void ICD2::unload() {
void ICD2::power() {
audio.coprocessor_enable(true);
audio.coprocessor_frequency(4 * 1024 * 1024);
reset();
}
void ICD2::reset() {

View File

@ -40,7 +40,6 @@ void Link::unload() {
void Link::power() {
if(link_power) link_power();
create(Link::Enter, frequency);
}
void Link::reset() {

View File

@ -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;
}
}

View File

@ -266,8 +266,6 @@ void NECDSP::power() {
regs.rp.bits(11);
regs.dp.bits(11);
}
reset();
}
void NECDSP::reset() {

View File

@ -16,7 +16,6 @@ void OBC1::unload() {
}
void OBC1::power() {
reset();
}
void OBC1::reset() {

View File

@ -128,7 +128,6 @@ void SA1::unload() {
void SA1::power() {
regs.a = regs.x = regs.y = 0x0000;
regs.s = 0x01ff;
reset();
}
void SA1::reset() {

View File

@ -22,7 +22,6 @@ void SDD1::unload() {
}
void SDD1::power() {
reset();
}
void SDD1::reset() {

View File

@ -22,7 +22,6 @@ void SPC7110::unload() {
}
void SPC7110::power() {
reset();
}
void SPC7110::reset() {

View File

@ -21,7 +21,6 @@ void SRTC::unload() {
}
void SRTC::power() {
reset();
}
void SRTC::reset() {

View File

@ -55,7 +55,6 @@ void ST0018::unload() {
}
void ST0018::power() {
reset();
}
void ST0018::reset() {

View File

@ -51,7 +51,6 @@ void SuperFX::unload() {
void SuperFX::power() {
clockmode = config.superfx.speed;
reset();
}
void SuperFX::reset() {

View File

@ -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

View File

@ -125,8 +125,6 @@ void CPU::power() {
mmio_power();
dma_power();
timing_power();
reset();
}
void CPU::reset() {

View File

@ -274,8 +274,6 @@ void DSP::power() {
voice[i].t_envx_out = 0;
voice[i].hidden_env = 0;
}
reset();
}
void DSP::reset() {

View File

@ -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() {

View File

@ -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) {

View File

@ -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 {

View File

@ -53,8 +53,6 @@ void SMP::power() {
timer0.target = 0;
timer1.target = 0;
timer2.target = 0;
reset();
}
void SMP::reset() {

View File

@ -10,10 +10,9 @@ System system;
#include <snes/scheduler/scheduler.cpp>
#include <snes/random/random.cpp>
#include <snes/video/video.cpp>
#include <snes/audio/audio.cpp>
#include <snes/input/input.cpp>
#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() {

View File

@ -42,9 +42,9 @@ private:
friend class Input;
};
#include <snes/video/video.hpp>
#include <snes/audio/audio.hpp>
#include <snes/input/input.hpp>
#include "video.hpp"
#include "audio.hpp"
#include "input.hpp"
#include <snes/config/config.hpp>
#include <snes/debugger/debugger.hpp>

View File

@ -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");

View File

@ -1,8 +1,11 @@
struct Config : public configuration {
struct Video {
string driver;
unsigned depth;
string filter;
string shader;
bool synchronize;
bool correctAspectRatio;

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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");

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -2,13 +2,12 @@
#define NALL_ARRAY_HPP
#include <stdlib.h>
#include <algorithm>
#include <initializer_list>
#include <type_traits>
#include <utility>
#include <nall/algorithm.hpp>
#include <nall/bit.hpp>
#include <nall/concept.hpp>
#include <nall/foreach.hpp>
#include <nall/utility.hpp>
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<typename U> 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<T>{ 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<T> list) : pool(0), poolsize(0), buffersize(0) {
array(std::initializer_list<T> 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<typename T> struct has_size<array<T>> { enum { value = true }; };
}
#endif

88
snesfilter/nall/atoi.hpp Executable file
View File

@ -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

View File

@ -5,8 +5,7 @@
#include <nall/stdint.hpp>
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]();

View File

@ -2,39 +2,39 @@
#define NALL_BIT_HPP
namespace nall {
template<int bits> inline unsigned uclamp(const unsigned x) {
template<int bits> 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<int bits> inline unsigned uclip(const unsigned x) {
template<int bits> constexpr inline unsigned uclip(const unsigned x) {
enum { m = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1) };
return (x & m);
}
template<int bits> inline signed sclamp(const signed x) {
template<int bits> 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<int bits> inline signed sclip(const signed x) {
template<int bits> 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<typename T> inline T lowest(const T x) {
template<typename T> constexpr inline T lowest(const T x) {
return x & -x;
}
//clear_lowest(0b1110) == 0b1100
template<typename T> inline T clear_lowest(const T x) {
template<typename T> constexpr inline T clear_lowest(const T x) {
return x & (x - 1);
}
//set_lowest(0b0101) == 0b0111
template<typename T> inline T set_lowest(const T x) {
template<typename T> constexpr inline T set_lowest(const T x) {
return x | (x + 1);
}

View File

@ -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; }
};

View File

@ -1,18 +1,56 @@
#ifndef NALL_COMPOSITOR_HPP
#define NALL_COMPOSITOR_HPP
#include <nall/detect.hpp>
#include <nall/intrinsics.hpp>
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");

View File

@ -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++) {

View File

@ -1,11 +1,12 @@
#ifndef NALL_DIRECTORY_HPP
#define NALL_DIRECTORY_HPP
#include <nall/foreach.hpp>
#include <nall/intrinsics.hpp>
#include <nall/sort.hpp>
#include <nall/string.hpp>
#include <nall/vector.hpp>
#if defined(_WIN32)
#if defined(PLATFORM_WINDOWS)
#include <nall/windows/utf8.hpp>
#else
#include <dirent.h>
@ -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

View File

@ -3,14 +3,14 @@
//dynamic linking support
#include <nall/detect.hpp>
#include <nall/intrinsics.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
#if defined(PLATFORM_X) || defined(PLATFORM_OSX)
#include <dlfcn.h>
#elif defined(PLATFORM_WIN)
#elif defined(PLATFORM_WINDOWS)
#include <windows.h>
#include <nall/windows/utf8.hpp>
#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");

View File

@ -1,6 +1,11 @@
#ifndef NALL_DSP_HPP
#define NALL_DSP_HPP
#include <algorithm>
#ifdef __SSE__
#include <xmmintrin.h>
#endif
#define NALL_DSP_INTERNAL_HPP
#include <nall/dsp/core.hpp>
#undef NALL_DSP_INTERNAL_HPP

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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<unsigned char> coeffs_mem;
// second half of ringbuffer should be copy of first half.
resample_samp_t *rb;
std::vector<unsigned char> 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<resample_coeff_t *> coeffs; // Pointers into coeff_mem.
std::vector<unsigned char> coeff_mem;
std::vector<resample_samp_t> 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<double> 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<double> 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<unsigned>(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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,7 +1,9 @@
#ifndef NALL_ENDIAN_HPP
#define NALL_ENDIAN_HPP
#if !defined(ARCH_MSB)
#include <nall/intrinsics.hpp>
#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

View File

@ -36,19 +36,19 @@ namespace nall {
public:
operator bool() const { return callback; }
R operator()(P... p) const { return (*callback)(std::forward<P>(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<typename C> function(R (C::*function)(P...), C *object) { callback = new member<C>(function, object); }
template<typename C> function(R (C::*function)(P...) const, C *object) { callback = new member<C>((R (C::*)(P...))function, object); }

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