summaryrefslogtreecommitdiffstats
path: root/src/libnr
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnr')
-rw-r--r--src/libnr/nr-compose-reference.cpp266
-rw-r--r--src/libnr/nr-compose-reference.h69
-rw-r--r--src/libnr/nr-compose-test.h451
3 files changed, 786 insertions, 0 deletions
diff --git a/src/libnr/nr-compose-reference.cpp b/src/libnr/nr-compose-reference.cpp
new file mode 100644
index 000000000..b952939ed
--- /dev/null
+++ b/src/libnr/nr-compose-reference.cpp
@@ -0,0 +1,266 @@
+
+// This is a reference implementation of the compositing functions in nr-compose.cpp.
+
+#include "nr-compose-reference.h"
+
+#define NR_RGBA32_R(v) (unsigned char) (((v) >> 24) & 0xff)
+#define NR_RGBA32_G(v) (unsigned char) (((v) >> 16) & 0xff)
+#define NR_RGBA32_B(v) (unsigned char) (((v) >> 8) & 0xff)
+#define NR_RGBA32_A(v) (unsigned char) ((v) & 0xff)
+
+static inline unsigned int DIV_ROUND(unsigned int v, unsigned int divisor) { return (v+divisor/2)/divisor; }
+
+static unsigned int pixelSize[] = { 1, 3, 4, 4 };
+
+// Computes :
+// dc' = (1 - alpha*sa) * dc + alpha*sc
+// da' = 1 - (1 - alpha*sa) * (1 - da)
+// Assuming premultiplied color values
+template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat, PIXEL_FORMAT foregroundFormat>
+static void composePixel(unsigned char *d, const unsigned char *s, unsigned int alpha);
+
+template<> static void composePixel<R8G8B8, R8G8B8, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
+ d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + alpha*s[3]*s[0], 255*255);
+ d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + alpha*s[3]*s[1], 255*255);
+ d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + alpha*s[3]*s[2], 255*255);
+}
+
+template<> static void composePixel<R8G8B8, R8G8B8, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
+ d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + 255*alpha*s[0], 255*255);
+ d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + 255*alpha*s[1], 255*255);
+ d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + 255*alpha*s[2], 255*255);
+}
+
+template<> static void composePixel<R8G8B8A8N, EMPTY, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
+ unsigned int newa = 255*255 - (255*255 - alpha*s[3]);
+ d[0] = s[0];//newa == 0 ? 0 : DIV_ROUND(alpha*s[3]*s[0], newa);
+ d[1] = s[1];//newa == 0 ? 0 : DIV_ROUND(alpha*s[3]*s[1], newa);
+ d[2] = s[2];//newa == 0 ? 0 : DIV_ROUND(alpha*s[3]*s[2], newa);
+ d[3] = DIV_ROUND(newa, 255);
+}
+
+template<> static void composePixel<R8G8B8A8N, EMPTY, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
+ unsigned int newa = 255*255 - (255*255 - alpha*s[3]);
+ d[0] = s[3] == 0 ? 0 : DIV_ROUND(255*s[0], s[3]);//newa == 0 ? 0 : DIV_ROUND(255*alpha*s[0], newa);
+ d[1] = s[3] == 0 ? 0 : DIV_ROUND(255*s[1], s[3]);//newa == 0 ? 0 : DIV_ROUND(255*alpha*s[1], newa);
+ d[2] = s[3] == 0 ? 0 : DIV_ROUND(255*s[2], s[3]);//newa == 0 ? 0 : DIV_ROUND(255*alpha*s[2], newa);
+ d[3] = DIV_ROUND(newa, 255);
+}
+
+template<> static void composePixel<R8G8B8A8N, R8G8B8A8N, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
+ if ( d[3] == 0 ) {
+ composePixel<R8G8B8A8N, EMPTY, R8G8B8A8N>(d, s, alpha);
+ } else if ( alpha*s[3] == 0 ) {
+ /* NOP */
+ } else {
+ unsigned int newa = 255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]);
+ d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[0] + 255 * alpha*s[3]*s[0], newa);
+ d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[1] + 255 * alpha*s[3]*s[1], newa);
+ d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[2] + 255 * alpha*s[3]*s[2], newa);
+ d[3] = DIV_ROUND(newa, 255*255);
+ }
+}
+
+template<> static void composePixel<R8G8B8A8N, R8G8B8A8N, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
+ if ( d[3] == 0 ) {
+ composePixel<R8G8B8A8N, EMPTY, R8G8B8A8P>(d, s, alpha);
+ } else if ( alpha*s[3] == 0 ) {
+ /* NOP */
+ } else {
+ unsigned int newa = 255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]);
+ d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[0] + 255*255 * alpha*s[0], newa);
+ d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[1] + 255*255 * alpha*s[1], newa);
+ d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[2] + 255*255 * alpha*s[2], newa);
+ d[3] = DIV_ROUND(newa, 255*255);
+ }
+}
+
+template<> static void composePixel<R8G8B8A8P, EMPTY, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
+ d[0] = DIV_ROUND(alpha*s[3]*s[0], 255*255);
+ d[1] = DIV_ROUND(alpha*s[3]*s[1], 255*255);
+ d[2] = DIV_ROUND(alpha*s[3]*s[2], 255*255);
+ d[3] = DIV_ROUND(255*255 - (255*255 - alpha*s[3]), 255);
+}
+
+template<> static void composePixel<R8G8B8A8P, EMPTY, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
+ d[0] = DIV_ROUND(alpha*s[0], 255);
+ d[1] = DIV_ROUND(alpha*s[1], 255);
+ d[2] = DIV_ROUND(alpha*s[2], 255);
+ d[3] = DIV_ROUND(255*255 - (255*255 - alpha*s[3]), 255);
+}
+
+template<> static void composePixel<R8G8B8A8P, R8G8B8A8P, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
+ d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + alpha*s[3]*s[0], 255*255);
+ d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + alpha*s[3]*s[1], 255*255);
+ d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + alpha*s[3]*s[2], 255*255);
+ d[3] = DIV_ROUND(255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]), 255*255);
+}
+
+template<> static void composePixel<R8G8B8A8P, R8G8B8A8P, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
+ d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + 255 * alpha*s[0], 255*255);
+ d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + 255 * alpha*s[1], 255*255);
+ d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + 255 * alpha*s[2], 255*255);
+ d[3] = DIV_ROUND(255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]), 255*255);
+}
+
+
+// composeAlpha, iterates over all pixels and applies composePixel to each of them
+template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat, PIXEL_FORMAT foregroundFormat>
+static void composeAlpha(unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) {
+ for(int y=0; y<h; y++) {
+ unsigned char* d = px;
+ const unsigned char* s = spx;
+ for(int x=0; x<w; x++) {
+ composePixel<resultFormat, backgroundFormat, foregroundFormat>(d, s, alpha);
+ d += pixelSize[resultFormat];
+ s += pixelSize[foregroundFormat];
+ }
+ px += rs;
+ spx += srs;
+ }
+}
+
+template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat, PIXEL_FORMAT foregroundFormat>
+static void composeMask(unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) {
+ for(int y=0; y<h; y++) {
+ unsigned char* d = px;
+ const unsigned char* s = spx;
+ const unsigned char* m = mpx;
+ for(int x=0; x<w; x++) {
+ composePixel<resultFormat, backgroundFormat, foregroundFormat>(d, s, *m);
+ d += pixelSize[resultFormat];
+ s += pixelSize[foregroundFormat];
+ m += 1;
+ }
+ px += rs;
+ spx += srs;
+ mpx += mrs;
+ }
+}
+
+template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat>
+static void composeColor(unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba) {
+ const unsigned char rgba_array[4] = {NR_RGBA32_R(rgba), NR_RGBA32_G(rgba), NR_RGBA32_B(rgba), NR_RGBA32_A(rgba)};
+ for(int y=0; y<h; y++) {
+ unsigned char* d = px;
+ const unsigned char* m = mpx;
+ for(int x=0; x<w; x++) {
+ composePixel<resultFormat, backgroundFormat, R8G8B8A8N>(d, rgba_array, *m);
+ d += pixelSize[resultFormat];
+ m += 1;
+ }
+ px += rs;
+ mpx += mrs;
+ }
+}
+
+/* FINAL DST SRC */
+
+void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) {
+ composeAlpha<R8G8B8A8N, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha);
+}
+
+void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) {
+ composeAlpha<R8G8B8A8N, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha);
+}
+
+void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) {
+ composeAlpha<R8G8B8A8P, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha);
+}
+
+void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) {
+ composeAlpha<R8G8B8A8P, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha);
+}
+
+
+void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) {
+ composeAlpha<R8G8B8A8N, R8G8B8A8N, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha);
+}
+
+void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) {
+ composeAlpha<R8G8B8A8N, R8G8B8A8N, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha);
+}
+
+void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) {
+ composeAlpha<R8G8B8A8P, R8G8B8A8P, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha);
+}
+
+void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) {
+ composeAlpha<R8G8B8A8P, R8G8B8A8P, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha);
+}
+
+/* FINAL DST SRC MASK */
+
+void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) {
+ composeMask<R8G8B8A8N, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, mpx, mrs);
+}
+
+void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) {
+ composeMask<R8G8B8A8N, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, mpx, mrs);
+}
+
+void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) {
+ composeMask<R8G8B8A8P, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, mpx, mrs);
+}
+
+void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) {
+ composeMask<R8G8B8A8P, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, mpx, mrs);
+}
+
+
+void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8_ref (unsigned char *p, int w, int h, int rs, const unsigned char *s, int srs, const unsigned char *m, int mrs) {
+ composeMask<R8G8B8A8N, R8G8B8A8N, R8G8B8A8N>(p, w, h, rs, s, srs, m, mrs);
+}
+
+void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8_ref (unsigned char *p, int w, int h, int rs, const unsigned char *s, int srs, const unsigned char *m, int mrs) {
+ composeMask<R8G8B8A8N, R8G8B8A8N, R8G8B8A8P>(p, w, h, rs, s, srs, m, mrs);
+}
+
+void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8_ref (unsigned char *p, int w, int h, int rs, const unsigned char *s, int srs, const unsigned char *m, int mrs) {
+ composeMask<R8G8B8A8P, R8G8B8A8P, R8G8B8A8N>(p, w, h, rs, s, srs, m, mrs);
+}
+
+void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8_ref (unsigned char *p, int w, int h, int rs, const unsigned char *s, int srs, const unsigned char *m, int mrs) {
+ composeMask<R8G8B8A8P, R8G8B8A8P, R8G8B8A8P>(p, w, h, rs, s, srs, m, mrs);
+}
+
+/* FINAL DST MASK COLOR */
+
+void nr_R8G8B8A8_N_EMPTY_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba) {
+ composeColor<R8G8B8A8N, EMPTY>(px, w, h, rs, mpx, mrs, rgba);
+}
+
+void nr_R8G8B8A8_P_EMPTY_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba) {
+ composeColor<R8G8B8A8P, EMPTY>(px, w, h, rs, mpx, mrs, rgba);
+}
+
+
+void nr_R8G8B8_R8G8B8_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba) {
+ composeColor<R8G8B8, R8G8B8>(px, w, h, rs, spx, srs, rgba);
+}
+
+void nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba) {
+ composeColor<R8G8B8A8N, R8G8B8A8N>(px, w, h, rs, spx, srs, rgba);
+}
+
+void nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba) {
+ composeColor<R8G8B8A8P, R8G8B8A8P>(px, w, h, rs, spx, srs, rgba);
+}
+
+/* RGB */
+
+void nr_R8G8B8_R8G8B8_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) {
+ composeAlpha<R8G8B8, R8G8B8, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha);
+}
+
+void nr_R8G8B8_R8G8B8_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) {
+ composeAlpha<R8G8B8, R8G8B8, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha);
+}
+
+void nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) {
+ composeMask<R8G8B8, R8G8B8, R8G8B8A8P>(px, w, h, rs, spx, srs, mpx, mrs);
+}
+
+void nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) {
+ composeMask<R8G8B8, R8G8B8, R8G8B8A8N>(px, w, h, rs, spx, srs, mpx, mrs);
+}
diff --git a/src/libnr/nr-compose-reference.h b/src/libnr/nr-compose-reference.h
new file mode 100644
index 000000000..8d004a135
--- /dev/null
+++ b/src/libnr/nr-compose-reference.h
@@ -0,0 +1,69 @@
+#ifndef __NR_COMPOSE_REFERENCE_H__
+#define __NR_COMPOSE_REFERENCE_H__
+
+// Based on nr-pixblock.h
+typedef enum {
+ A8 = 0,
+ R8G8B8,
+ R8G8B8A8N,
+ R8G8B8A8P,
+ EMPTY = -1
+} PIXEL_FORMAT;
+
+/* FINAL DST SRC */
+
+void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+
+void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+
+/* FINAL DST SRC MASK */
+
+void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs,
+ const unsigned char *spx, int srs,
+ const unsigned char *mpx, int mrs);
+void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs,
+ const unsigned char *spx, int srs,
+ const unsigned char *mpx, int mrs);
+void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs,
+ const unsigned char *spx, int srs,
+ const unsigned char *mpx, int mrs);
+void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs,
+ const unsigned char *spx, int srs,
+ const unsigned char *mpx, int mrs);
+
+void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8_ref (unsigned char *p, int w, int h, int rs,
+ const unsigned char *s, int srs,
+ const unsigned char *m, int mrs);
+void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8_ref (unsigned char *p, int w, int h, int rs,
+ const unsigned char *s, int srs,
+ const unsigned char *m, int mrs);
+void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8_ref (unsigned char *p, int w, int h, int rs,
+ const unsigned char *s, int srs,
+ const unsigned char *m, int mrs);
+void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8_ref (unsigned char *p, int w, int h, int rs,
+ const unsigned char *s, int srs,
+ const unsigned char *m, int mrs);
+
+/* FINAL DST MASK COLOR */
+
+void nr_R8G8B8A8_N_EMPTY_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba);
+void nr_R8G8B8A8_P_EMPTY_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba);
+
+void nr_R8G8B8_R8G8B8_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba);
+void nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba);
+void nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba);
+
+/* RGB */
+
+void nr_R8G8B8_R8G8B8_R8G8B8A8_P_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+void nr_R8G8B8_R8G8B8_R8G8B8A8_N_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
+void nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs);
+void nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8_ref (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs);
+
+#endif//__NR_COMPOSE_REFERENCE_H__
diff --git a/src/libnr/nr-compose-test.h b/src/libnr/nr-compose-test.h
new file mode 100644
index 000000000..5b0d129c7
--- /dev/null
+++ b/src/libnr/nr-compose-test.h
@@ -0,0 +1,451 @@
+
+#include <cxxtest/TestSuite.h>
+
+#include "nr-compose.h"
+#include "nr-compose-reference.h"
+#include <glib.h>
+#include <memory.h>
+#include <stdlib.h>
+
+static inline unsigned int DIV_ROUND(unsigned int v, unsigned int divisor) { return (v+divisor/2)/divisor; }
+static inline unsigned char NR_PREMUL_111(unsigned int c, unsigned int a) { return static_cast<unsigned char>(DIV_ROUND(c*a, 255)); }
+
+template<PIXEL_FORMAT format>
+static int IMGCMP(const unsigned char* a, const unsigned char* b, size_t n) { return memcmp(a, b, n); }
+
+template<>
+static int IMGCMP<R8G8B8A8N>(const unsigned char* a, const unsigned char* b, size_t n)
+{
+ // If two pixels each have their alpha channel set to zero they're equivalent
+ // Note that this doesn't work for premultiplied values, as their color values should
+ // be zero when alpha is zero.
+ int cr = 0;
+ while(n && cr == 0) {
+ if ( a[3] != 0 || b[3] != 0 ) {
+ cr = memcmp(a, b, 4);
+ }
+ a+=4;
+ b+=4;
+ n-=4;
+ }
+ return cr;
+}
+
+class NrComposeTest : public CxxTest::TestSuite {
+private:
+ int const w, h;
+
+ unsigned char* const dst_rgba_n_org;
+ unsigned char* const dst_rgba_p_org;
+ unsigned char* const dst_rgb_org;
+
+ unsigned char* const dst1_rgba;
+ unsigned char* const dst2_rgba;
+ unsigned char* const src_rgba_n;
+ unsigned char* const src_rgba_p;
+ unsigned char* const dst1_rgb;
+ unsigned char* const dst2_rgb;
+ unsigned char* const src_rgb;
+ unsigned char* const mask;
+
+ static unsigned int const alpha_vals[7];
+ static unsigned int const rgb_vals[3];
+
+public:
+ NrComposeTest() :
+ w(13),
+ h(5),
+
+ dst_rgba_n_org(new unsigned char[w*h*4]),
+ dst_rgba_p_org(new unsigned char[w*h*4]),
+ dst_rgb_org(new unsigned char[w*h*3]),
+
+ dst1_rgba(new unsigned char[w*h*4]),
+ dst2_rgba(new unsigned char[w*h*4]),
+ src_rgba_n(new unsigned char[w*h*4]),
+ src_rgba_p(new unsigned char[w*h*4]),
+ dst1_rgb(new unsigned char[w*h*3]),
+ dst2_rgb(new unsigned char[w*h*3]),
+ src_rgb(new unsigned char[w*h*3]),
+ mask(new unsigned char[w*h])
+ {
+ srand(23874683); // It shouldn't really matter what this is, as long as it's always the same (to be reproducible)
+
+ for(int y=0; y<h; y++) {
+ for(int x=0; x<w; x++) {
+ dst_rgba_n_org[(x+y*w)*4+3] = 255*rand()/RAND_MAX;
+ dst_rgba_p_org[(x+y*w)*4+3] = 255*rand()/RAND_MAX;
+ src_rgba_n[(x+y*w)*4+3] = 255*rand()/RAND_MAX;
+ src_rgba_p[(x+y*w)*4+3] = 255*rand()/RAND_MAX;
+ for(int i=0; i<3; i++) {
+ dst_rgba_n_org[(x+y*w)*4+i] = 255*rand()/RAND_MAX;
+ dst_rgba_p_org[(x+y*w)*4+i] = NR_PREMUL_111(255*rand()/RAND_MAX, dst_rgba_p_org[(x+y*w)*4+3]);
+ src_rgba_n[(x+y*w)*4+i] = 255*rand()/RAND_MAX;
+ src_rgba_p[(x+y*w)*4+i] = NR_PREMUL_111(255*rand()/RAND_MAX, src_rgba_p[(x+y*w)*4+3]);
+ dst_rgb_org[(x+y*w)*3+i] = 255*rand()/RAND_MAX;
+ }
+ mask[x+y*w] = 255*rand()/RAND_MAX;
+ }
+ }
+ }
+ virtual ~NrComposeTest()
+ {
+ delete[] dst_rgba_n_org;
+ delete[] dst_rgba_p_org;
+ delete[] dst_rgb_org;
+
+ delete[] dst1_rgba;
+ delete[] dst2_rgba;
+ delete[] src_rgba_n;
+ delete[] src_rgba_p;
+ delete[] dst1_rgb;
+ delete[] dst2_rgb;
+ delete[] src_rgb;
+ delete[] mask;
+ }
+
+ // FINAL DST SRC
+
+ void testnr_R8G8B8A8_N_EMPTY_R8G8B8A8_N()
+ {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int alpha = alpha_vals[i];
+ char msg[40];
+ sprintf(msg, "alpha = %u", alpha);
+ memcpy(dst1_rgba, dst_rgba_n_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_n_org, w*h*4);
+ nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N(dst1_rgba, w, h, w*4, src_rgba_n, w*4, alpha);
+ nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, alpha);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+ }
+
+ void testnr_R8G8B8A8_N_EMPTY_R8G8B8A8_P()
+ {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int alpha = alpha_vals[i];
+ char msg[40];
+ sprintf(msg, "alpha = %u", alpha);
+ memcpy(dst1_rgba, dst_rgba_n_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_n_org, w*h*4);
+ nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P(dst1_rgba, w, h, w*4, src_rgba_p, w*4, alpha);
+ nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, alpha);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+ }
+
+ void testnr_R8G8B8A8_P_EMPTY_R8G8B8A8_N()
+ {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int alpha = alpha_vals[i];
+ char msg[40];
+ sprintf(msg, "alpha = %u", alpha);
+ memcpy(dst1_rgba, dst_rgba_p_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_p_org, w*h*4);
+ nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N(dst1_rgba, w, h, w*4, src_rgba_n, w*4, alpha);
+ nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, alpha);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+ }
+
+ void testnr_R8G8B8A8_P_EMPTY_R8G8B8A8_P()
+ {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int alpha = alpha_vals[i];
+ char msg[40];
+ sprintf(msg, "alpha = %u", alpha);
+ memcpy(dst1_rgba, dst_rgba_p_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_p_org, w*h*4);
+ nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P(dst1_rgba, w, h, w*4, src_rgba_p, w*4, alpha);
+ nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, alpha);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+ }
+
+ void testnr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N()
+ {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int alpha = alpha_vals[i];
+ char msg[40];
+ sprintf(msg, "alpha = %u", alpha);
+ memcpy(dst1_rgba, dst_rgba_n_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_n_org, w*h*4);
+ nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N(dst1_rgba, w, h, w*4, src_rgba_n, w*4, alpha);
+ nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, alpha);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+ }
+
+ void testnr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P()
+ {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int alpha = alpha_vals[i];
+ char msg[40];
+ sprintf(msg, "alpha = %u", alpha);
+ memcpy(dst1_rgba, dst_rgba_n_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_n_org, w*h*4);
+ nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P(dst1_rgba, w, h, w*4, src_rgba_p, w*4, alpha);
+ nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, alpha);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+ }
+
+ void testnr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N()
+ {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int alpha = alpha_vals[i];
+ char msg[40];
+ sprintf(msg, "alpha = %u", alpha);
+ memcpy(dst1_rgba, dst_rgba_p_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_p_org, w*h*4);
+ nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N(dst1_rgba, w, h, w*4, src_rgba_n, w*4, alpha);
+ nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, alpha);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+ }
+
+ void testnr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P()
+ {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int alpha = alpha_vals[i];
+ char msg[40];
+ sprintf(msg, "alpha = %u", alpha);
+ memcpy(dst1_rgba, dst_rgba_p_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_p_org, w*h*4);
+ nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P(dst1_rgba, w, h, w*4, src_rgba_p, w*4, alpha);
+ nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, alpha);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+ }
+
+ // FINAL DST SRC MASK
+
+ void testnr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8()
+ {
+ memcpy(dst1_rgba, dst_rgba_n_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_n_org, w*h*4);
+ nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8(dst1_rgba, w, h, w*4, src_rgba_n, w*4, mask, w);
+ nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, mask, w);
+ TS_ASSERT( IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+
+ void testnr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8()
+ {
+ memcpy(dst1_rgba, dst_rgba_n_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_n_org, w*h*4);
+ nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8(dst1_rgba, w, h, w*4, src_rgba_p, w*4, mask, w);
+ nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, mask, w);
+ TS_ASSERT( IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+
+ void testnr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8()
+ {
+ memcpy(dst1_rgba, dst_rgba_p_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_p_org, w*h*4);
+ nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8(dst1_rgba, w, h, w*4, src_rgba_n, w*4, mask, w);
+ nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, mask, w);
+ TS_ASSERT( IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+
+ void testnr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8()
+ {
+ memcpy(dst1_rgba, dst_rgba_p_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_p_org, w*h*4);
+ nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8(dst1_rgba, w, h, w*4, src_rgba_p, w*4, mask, w);
+ nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, mask, w);
+ TS_ASSERT( IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+
+ void testnr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8()
+ {
+ memcpy(dst1_rgba, dst_rgba_n_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_n_org, w*h*4);
+ nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8(dst1_rgba, w, h, w*4, src_rgba_n, w*4, mask, w);
+ nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, mask, w);
+ TS_ASSERT( IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+
+ void testnr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8()
+ {
+ memcpy(dst1_rgba, dst_rgba_n_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_n_org, w*h*4);
+ nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8(dst1_rgba, w, h, w*4, src_rgba_p, w*4, mask, w);
+ nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, mask, w);
+ TS_ASSERT( IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+
+ void testnr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8()
+ {
+ memcpy(dst1_rgba, dst_rgba_p_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_p_org, w*h*4);
+ nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8(dst1_rgba, w, h, w*4, src_rgba_n, w*4, mask, w);
+ nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8_ref(dst2_rgba, w, h, w*4, src_rgba_n, w*4, mask, w);
+ TS_ASSERT( IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+
+ void testnr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8()
+ {
+ memcpy(dst1_rgba, dst_rgba_p_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_p_org, w*h*4);
+ nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8(dst1_rgba, w, h, w*4, src_rgba_p, w*4, mask, w);
+ nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8_ref(dst2_rgba, w, h, w*4, src_rgba_p, w*4, mask, w);
+ TS_ASSERT( IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+
+ // FINAL DST MASK COLOR
+
+ void testnr_R8G8B8A8_N_EMPTY_A8_RGBA32()
+ {
+ for(size_t j=0; j<G_N_ELEMENTS(rgb_vals); j++) {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int rgba = rgb_vals[j]+alpha_vals[i];
+ char msg[100];
+ sprintf(msg, "color = (%u,%u,%u,%u)", (rgba>>24u)&0xff, (rgba>>16u)&0xff, (rgba>>8u)&0xff, rgba&0xff);
+ memcpy(dst1_rgba, dst_rgba_n_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_n_org, w*h*4);
+ nr_R8G8B8A8_N_EMPTY_A8_RGBA32(dst1_rgba, w, h, w*4, mask, w, rgba);
+ nr_R8G8B8A8_N_EMPTY_A8_RGBA32_ref(dst2_rgba, w, h, w*4, mask, w, rgba);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+ }
+ }
+
+ void testnr_R8G8B8A8_P_EMPTY_A8_RGBA32()
+ {
+ for(size_t j=0; j<G_N_ELEMENTS(rgb_vals); j++) {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int rgba = rgb_vals[j]+alpha_vals[i];
+ char msg[100];
+ sprintf(msg, "color = (%u,%u,%u,%u)", (rgba>>24u)&0xff, (rgba>>16u)&0xff, (rgba>>8u)&0xff, rgba&0xff);
+ memcpy(dst1_rgba, dst_rgba_p_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_p_org, w*h*4);
+ nr_R8G8B8A8_P_EMPTY_A8_RGBA32(dst1_rgba, w, h, w*4, mask, w, rgba);
+ nr_R8G8B8A8_P_EMPTY_A8_RGBA32_ref(dst2_rgba, w, h, w*4, mask, w, rgba);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+ }
+ }
+
+ void testnr_R8G8B8_R8G8B8_A8_RGBA32()
+ {
+ for(size_t j=0; j<G_N_ELEMENTS(rgb_vals); j++) {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int rgba = rgb_vals[j]+alpha_vals[i];
+ char msg[100];
+ sprintf(msg, "color = (%u,%u,%u,%u)", (rgba>>24u)&0xff, (rgba>>16u)&0xff, (rgba>>8u)&0xff, rgba&0xff);
+ memcpy(dst1_rgb, dst_rgb_org, w*h*3);
+ memcpy(dst2_rgb, dst_rgb_org, w*h*3);
+ nr_R8G8B8_R8G8B8_A8_RGBA32(dst1_rgb, w, h, w*3, mask, w, rgba);
+ nr_R8G8B8_R8G8B8_A8_RGBA32_ref(dst2_rgb, w, h, w*3, mask, w, rgba);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8>(dst1_rgb, dst2_rgb, w*h*3) == 0 );
+ }
+ }
+ }
+
+ void testnr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32()
+ {
+ for(size_t j=0; j<G_N_ELEMENTS(rgb_vals); j++) {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int rgba = rgb_vals[j]+alpha_vals[i];
+ char msg[100];
+ sprintf(msg, "color = (%u,%u,%u,%u)", (rgba>>24u)&0xff, (rgba>>16u)&0xff, (rgba>>8u)&0xff, rgba&0xff);
+ memcpy(dst1_rgba, dst_rgba_n_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_n_org, w*h*4);
+ nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32(dst1_rgba, w, h, w*4, mask, w, rgba);
+ nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32_ref(dst2_rgba, w, h, w*4, mask, w, rgba);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8A8N>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+ }
+ }
+
+ void testnr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32()
+ {
+ for(size_t j=0; j<G_N_ELEMENTS(rgb_vals); j++) {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int rgba = rgb_vals[j]+alpha_vals[i];
+ char msg[100];
+ sprintf(msg, "color = (%u,%u,%u,%u)", (rgba>>24u)&0xff, (rgba>>16u)&0xff, (rgba>>8u)&0xff, rgba&0xff);
+ memcpy(dst1_rgba, dst_rgba_p_org, w*h*4);
+ memcpy(dst2_rgba, dst_rgba_p_org, w*h*4);
+ nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32(dst1_rgba, w, h, w*4, mask, w, rgba);
+ nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32_ref(dst2_rgba, w, h, w*4, mask, w, rgba);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8A8P>(dst1_rgba, dst2_rgba, w*h*4) == 0 );
+ }
+ }
+ }
+
+ // RGB
+
+ void testnr_R8G8B8_R8G8B8_R8G8B8A8_N()
+ {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int alpha = alpha_vals[i];
+ char msg[40];
+ sprintf(msg, "alpha = %u", alpha);
+ memcpy(dst1_rgb, dst_rgb_org, w*h*3);
+ memcpy(dst2_rgb, dst_rgb_org, w*h*3);
+ nr_R8G8B8_R8G8B8_R8G8B8A8_N(dst1_rgb, w, h, w*3, src_rgba_n, w*4, alpha);
+ nr_R8G8B8_R8G8B8_R8G8B8A8_N_ref(dst2_rgb, w, h, w*3, src_rgba_n, w*4, alpha);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8>(dst1_rgb, dst2_rgb, w*h*3) == 0 );
+ }
+ }
+
+ void testnr_R8G8B8_R8G8B8_R8G8B8A8_P()
+ {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int alpha = alpha_vals[i];
+ char msg[40];
+ sprintf(msg, "alpha = %u", alpha);
+ memcpy(dst1_rgb, dst_rgb_org, w*h*3);
+ memcpy(dst2_rgb, dst_rgb_org, w*h*3);
+ nr_R8G8B8_R8G8B8_R8G8B8A8_P(dst1_rgb, w, h, w*3, src_rgba_p, w*4, alpha);
+ nr_R8G8B8_R8G8B8_R8G8B8A8_P_ref(dst2_rgb, w, h, w*3, src_rgba_p, w*4, alpha);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8>(dst1_rgb, dst2_rgb, w*h*3) == 0 );
+ }
+ }
+
+ void testnr_R8G8B8_R8G8B8_R8G8B8A8_N_A8()
+ {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int alpha = alpha_vals[i];
+ char msg[40];
+ sprintf(msg, "alpha = %u", alpha);
+ memcpy(dst1_rgb, dst_rgb_org, w*h*3);
+ memcpy(dst2_rgb, dst_rgb_org, w*h*3);
+ nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8(dst1_rgb, w, h, w*3, src_rgba_n, w*4, mask, w);
+ nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8_ref(dst2_rgb, w, h, w*3, src_rgba_n, w*4, mask, w);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8>(dst1_rgb, dst2_rgb, w*h*3) == 0 );
+ }
+ }
+
+ void testnr_R8G8B8_R8G8B8_R8G8B8A8_P_A8()
+ {
+ for(size_t i=0; i<G_N_ELEMENTS(alpha_vals); i++) {
+ unsigned int alpha = alpha_vals[i];
+ char msg[40];
+ sprintf(msg, "alpha = %u", alpha);
+ memcpy(dst1_rgb, dst_rgb_org, w*h*3);
+ memcpy(dst2_rgb, dst_rgb_org, w*h*3);
+ nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8(dst1_rgb, w, h, w*3, src_rgba_p, w*4, mask, w);
+ nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8_ref(dst2_rgb, w, h, w*3, src_rgba_p, w*4, mask, w);
+ TSM_ASSERT(msg, IMGCMP<R8G8B8>(dst1_rgb, dst2_rgb, w*h*3) == 0 );
+ }
+ }
+};
+
+unsigned int const NrComposeTest::alpha_vals[7] = {0, 1, 127, 128, 129, 254, 255};
+unsigned int const NrComposeTest::rgb_vals[3] = {
+ ( 0u<<24u)+( 1u<<16u)+( 92u<<8u),
+ (127u<<24u)+(128u<<16u)+(129u<<8u),
+ (163u<<24u)+(254u<<16u)+(255u<<8u)};
+
+/*
+Local Variables:
+mode:c++
+c-file-style:"stroustrup"
+c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+indent-tabs-mode:nil
+fill-column:99
+End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :