2 // This is a reference implementation of the compositing functions in nr-compose.cpp.
4 #include "nr-compose-reference.h"
6 #define NR_RGBA32_R(v) (unsigned char) (((v) >> 24) & 0xff)
7 #define NR_RGBA32_G(v) (unsigned char) (((v) >> 16) & 0xff)
8 #define NR_RGBA32_B(v) (unsigned char) (((v) >> 8) & 0xff)
9 #define NR_RGBA32_A(v) (unsigned char) ((v) & 0xff)
11 static inline unsigned int DIV_ROUND(unsigned int v, unsigned int divisor) { return (v+divisor/2)/divisor; }
13 static unsigned int pixelSize[] = { 1, 3, 4, 4 };
15 // Computes :
16 // dc' = (1 - alpha*sa) * dc + alpha*sc
17 // da' = 1 - (1 - alpha*sa) * (1 - da)
18 // Assuming premultiplied color values
19 template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat, PIXEL_FORMAT foregroundFormat>
20 static void composePixel(unsigned char *d, const unsigned char *s, unsigned int alpha);
22 template<> void composePixel<R8G8B8, R8G8B8, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
23 d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + alpha*s[3]*s[0], 255*255);
24 d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + alpha*s[3]*s[1], 255*255);
25 d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + alpha*s[3]*s[2], 255*255);
26 }
28 template<> void composePixel<R8G8B8, R8G8B8, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
29 d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + 255*alpha*s[0], 255*255);
30 d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + 255*alpha*s[1], 255*255);
31 d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + 255*alpha*s[2], 255*255);
32 }
34 template<> void composePixel<R8G8B8A8N, EMPTY, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
35 unsigned int newa = 255*255 - (255*255 - alpha*s[3]);
36 d[0] = s[0];//newa == 0 ? 0 : DIV_ROUND(alpha*s[3]*s[0], newa);
37 d[1] = s[1];//newa == 0 ? 0 : DIV_ROUND(alpha*s[3]*s[1], newa);
38 d[2] = s[2];//newa == 0 ? 0 : DIV_ROUND(alpha*s[3]*s[2], newa);
39 d[3] = DIV_ROUND(newa, 255);
40 }
42 template<> void composePixel<R8G8B8A8N, EMPTY, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
43 unsigned int newa = 255*255 - (255*255 - alpha*s[3]);
44 d[0] = s[3] == 0 ? 0 : DIV_ROUND(255*s[0], s[3]);//newa == 0 ? 0 : DIV_ROUND(255*alpha*s[0], newa);
45 d[1] = s[3] == 0 ? 0 : DIV_ROUND(255*s[1], s[3]);//newa == 0 ? 0 : DIV_ROUND(255*alpha*s[1], newa);
46 d[2] = s[3] == 0 ? 0 : DIV_ROUND(255*s[2], s[3]);//newa == 0 ? 0 : DIV_ROUND(255*alpha*s[2], newa);
47 d[3] = DIV_ROUND(newa, 255);
48 }
50 template<> void composePixel<R8G8B8A8N, R8G8B8A8N, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
51 if ( d[3] == 0 ) {
52 composePixel<R8G8B8A8N, EMPTY, R8G8B8A8N>(d, s, alpha);
53 } else if ( alpha*s[3] == 0 ) {
54 /* NOP */
55 } else {
56 unsigned int newa = 255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]);
57 d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[0] + 255 * alpha*s[3]*s[0], newa);
58 d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[1] + 255 * alpha*s[3]*s[1], newa);
59 d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[2] + 255 * alpha*s[3]*s[2], newa);
60 d[3] = DIV_ROUND(newa, 255*255);
61 }
62 }
64 template<> void composePixel<R8G8B8A8N, R8G8B8A8N, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
65 if ( d[3] == 0 ) {
66 composePixel<R8G8B8A8N, EMPTY, R8G8B8A8P>(d, s, alpha);
67 } else if ( alpha*s[3] == 0 ) {
68 /* NOP */
69 } else {
70 unsigned int newa = 255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]);
71 d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[0] + 255*255 * alpha*s[0], newa);
72 d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[1] + 255*255 * alpha*s[1], newa);
73 d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[3]*d[2] + 255*255 * alpha*s[2], newa);
74 d[3] = DIV_ROUND(newa, 255*255);
75 }
76 }
78 template<> void composePixel<R8G8B8A8P, EMPTY, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
79 d[0] = DIV_ROUND(alpha*s[3]*s[0], 255*255);
80 d[1] = DIV_ROUND(alpha*s[3]*s[1], 255*255);
81 d[2] = DIV_ROUND(alpha*s[3]*s[2], 255*255);
82 d[3] = DIV_ROUND(255*255 - (255*255 - alpha*s[3]), 255);
83 }
85 template<> void composePixel<R8G8B8A8P, EMPTY, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
86 d[0] = DIV_ROUND(alpha*s[0], 255);
87 d[1] = DIV_ROUND(alpha*s[1], 255);
88 d[2] = DIV_ROUND(alpha*s[2], 255);
89 d[3] = DIV_ROUND(255*255 - (255*255 - alpha*s[3]), 255);
90 }
92 template<> void composePixel<R8G8B8A8P, R8G8B8A8P, R8G8B8A8N>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
93 d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + alpha*s[3]*s[0], 255*255);
94 d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + alpha*s[3]*s[1], 255*255);
95 d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + alpha*s[3]*s[2], 255*255);
96 d[3] = DIV_ROUND(255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]), 255*255);
97 }
99 template<> void composePixel<R8G8B8A8P, R8G8B8A8P, R8G8B8A8P>(unsigned char *d, const unsigned char *s, unsigned int alpha) {
100 d[0] = DIV_ROUND((255*255 - alpha*s[3]) * d[0] + 255 * alpha*s[0], 255*255);
101 d[1] = DIV_ROUND((255*255 - alpha*s[3]) * d[1] + 255 * alpha*s[1], 255*255);
102 d[2] = DIV_ROUND((255*255 - alpha*s[3]) * d[2] + 255 * alpha*s[2], 255*255);
103 d[3] = DIV_ROUND(255*255*255 - (255*255 - alpha*s[3]) * (255 - d[3]), 255*255);
104 }
107 // composeAlpha, iterates over all pixels and applies composePixel to each of them
108 template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat, PIXEL_FORMAT foregroundFormat>
109 static void composeAlpha(unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha) {
110 for(int y=0; y<h; y++) {
111 unsigned char* d = px;
112 const unsigned char* s = spx;
113 for(int x=0; x<w; x++) {
114 composePixel<resultFormat, backgroundFormat, foregroundFormat>(d, s, alpha);
115 d += pixelSize[resultFormat];
116 s += pixelSize[foregroundFormat];
117 }
118 px += rs;
119 spx += srs;
120 }
121 }
123 template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat, PIXEL_FORMAT foregroundFormat>
124 static void composeMask(unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs) {
125 for(int y=0; y<h; y++) {
126 unsigned char* d = px;
127 const unsigned char* s = spx;
128 const unsigned char* m = mpx;
129 for(int x=0; x<w; x++) {
130 composePixel<resultFormat, backgroundFormat, foregroundFormat>(d, s, *m);
131 d += pixelSize[resultFormat];
132 s += pixelSize[foregroundFormat];
133 m += 1;
134 }
135 px += rs;
136 spx += srs;
137 mpx += mrs;
138 }
139 }
141 template<PIXEL_FORMAT resultFormat, PIXEL_FORMAT backgroundFormat>
142 static void composeColor(unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba) {
143 const unsigned char rgba_array[4] = {NR_RGBA32_R(rgba), NR_RGBA32_G(rgba), NR_RGBA32_B(rgba), NR_RGBA32_A(rgba)};
144 for(int y=0; y<h; y++) {
145 unsigned char* d = px;
146 const unsigned char* m = mpx;
147 for(int x=0; x<w; x++) {
148 composePixel<resultFormat, backgroundFormat, R8G8B8A8N>(d, rgba_array, *m);
149 d += pixelSize[resultFormat];
150 m += 1;
151 }
152 px += rs;
153 mpx += mrs;
154 }
155 }
157 /* FINAL DST SRC */
159 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) {
160 composeAlpha<R8G8B8A8N, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha);
161 }
163 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) {
164 composeAlpha<R8G8B8A8N, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha);
165 }
167 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) {
168 composeAlpha<R8G8B8A8P, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha);
169 }
171 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) {
172 composeAlpha<R8G8B8A8P, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha);
173 }
176 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) {
177 composeAlpha<R8G8B8A8N, R8G8B8A8N, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha);
178 }
180 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) {
181 composeAlpha<R8G8B8A8N, R8G8B8A8N, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha);
182 }
184 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) {
185 composeAlpha<R8G8B8A8P, R8G8B8A8P, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha);
186 }
188 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) {
189 composeAlpha<R8G8B8A8P, R8G8B8A8P, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha);
190 }
192 /* FINAL DST SRC MASK */
194 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) {
195 composeMask<R8G8B8A8N, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, mpx, mrs);
196 }
198 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) {
199 composeMask<R8G8B8A8N, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, mpx, mrs);
200 }
202 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) {
203 composeMask<R8G8B8A8P, EMPTY, R8G8B8A8N>(px, w, h, rs, spx, srs, mpx, mrs);
204 }
206 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) {
207 composeMask<R8G8B8A8P, EMPTY, R8G8B8A8P>(px, w, h, rs, spx, srs, mpx, mrs);
208 }
211 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) {
212 composeMask<R8G8B8A8N, R8G8B8A8N, R8G8B8A8N>(p, w, h, rs, s, srs, m, mrs);
213 }
215 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) {
216 composeMask<R8G8B8A8N, R8G8B8A8N, R8G8B8A8P>(p, w, h, rs, s, srs, m, mrs);
217 }
219 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) {
220 composeMask<R8G8B8A8P, R8G8B8A8P, R8G8B8A8N>(p, w, h, rs, s, srs, m, mrs);
221 }
223 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) {
224 composeMask<R8G8B8A8P, R8G8B8A8P, R8G8B8A8P>(p, w, h, rs, s, srs, m, mrs);
225 }
227 /* FINAL DST MASK COLOR */
229 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) {
230 composeColor<R8G8B8A8N, EMPTY>(px, w, h, rs, mpx, mrs, rgba);
231 }
233 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) {
234 composeColor<R8G8B8A8P, EMPTY>(px, w, h, rs, mpx, mrs, rgba);
235 }
238 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) {
239 composeColor<R8G8B8, R8G8B8>(px, w, h, rs, spx, srs, rgba);
240 }
242 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) {
243 composeColor<R8G8B8A8N, R8G8B8A8N>(px, w, h, rs, spx, srs, rgba);
244 }
246 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) {
247 composeColor<R8G8B8A8P, R8G8B8A8P>(px, w, h, rs, spx, srs, rgba);
248 }
250 /* RGB */
252 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) {
253 composeAlpha<R8G8B8, R8G8B8, R8G8B8A8P>(px, w, h, rs, spx, srs, alpha);
254 }
256 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) {
257 composeAlpha<R8G8B8, R8G8B8, R8G8B8A8N>(px, w, h, rs, spx, srs, alpha);
258 }
260 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) {
261 composeMask<R8G8B8, R8G8B8, R8G8B8A8P>(px, w, h, rs, spx, srs, mpx, mrs);
262 }
264 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) {
265 composeMask<R8G8B8, R8G8B8, R8G8B8A8N>(px, w, h, rs, spx, srs, mpx, mrs);
266 }