Code

e3ee033259ae2032c10b3094e05dac85148d3a7f
[inkscape.git] / src / display / nr-gradient-gpl.cpp
1 #define __NR_GRADIENT_C__
3 /*
4  * Pixel buffer rendering library
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *
9  * Copyright (C) 2001-2002 Lauris Kaplinski
10  * Copyright (C) 2001-2002 Ximian, Inc.
11  *
12  * Released under GNU GPL, read the file 'COPYING' for more information
13  */
15 #include <libnr/nr-pixops.h>
16 #include <libnr/nr-pixblock-pixel.h>
18 #include "nr-gradient-gpl.h"
20 #define noNR_USE_GENERIC_RENDERER
22 #define NRG_MASK (NR_GRADIENT_VECTOR_LENGTH - 1)
23 #define NRG_2MASK ((NR_GRADIENT_VECTOR_LENGTH << 1) - 1)
25 static void nr_lgradient_render_block (NRRenderer *r, NRPixBlock *pb, NRPixBlock *m);
26 static void nr_lgradient_render_R8G8B8A8N_EMPTY (NRLGradientRenderer *lgr, unsigned char *px, int x0, int y0, int width, int height, int rs);
27 static void nr_lgradient_render_R8G8B8A8N (NRLGradientRenderer *lgr, unsigned char *px, int x0, int y0, int width, int height, int rs);
28 static void nr_lgradient_render_R8G8B8 (NRLGradientRenderer *lgr, unsigned char *px, int x0, int y0, int width, int height, int rs);
29 static void nr_lgradient_render_generic (NRLGradientRenderer *lgr, NRPixBlock *pb);
31 NRRenderer *
32 nr_lgradient_renderer_setup (NRLGradientRenderer *lgr,
33                              const unsigned char *cv, 
34                              unsigned int spread, 
35                              const NRMatrix *gs2px,
36                              float x0, float y0,
37                              float x1, float y1)
38 {
39         NRMatrix n2gs, n2px, px2n;
41         lgr->renderer.render = nr_lgradient_render_block;
43         lgr->vector = cv;
44         lgr->spread = spread;
46         n2gs.c[0] = x1 - x0;
47         n2gs.c[1] = y1 - y0;
48         n2gs.c[2] = y1 - y0;
49         n2gs.c[3] = x0 - x1;
50         n2gs.c[4] = x0;
51         n2gs.c[5] = y0;
53         nr_matrix_multiply (&n2px, &n2gs, gs2px);
54         nr_matrix_invert (&px2n, &n2px);
56         lgr->x0 = n2px.c[4] - 0.5;
57         lgr->y0 = n2px.c[5] - 0.5;
58         lgr->dx = px2n.c[0] * NR_GRADIENT_VECTOR_LENGTH;
59         lgr->dy = px2n.c[2] * NR_GRADIENT_VECTOR_LENGTH;
61         return (NRRenderer *) lgr;
62 }
64 static void
65 nr_lgradient_render_block (NRRenderer *r, NRPixBlock *pb, NRPixBlock *m)
66 {
67         NRLGradientRenderer *lgr;
68         int width, height;
70         lgr = (NRLGradientRenderer *) r;
72         width = pb->area.x1 - pb->area.x0;
73         height = pb->area.y1 - pb->area.y0;
75 #ifdef NR_USE_GENERIC_RENDERER
76         nr_lgradient_render_generic (lgr, pb);
77 #else
78         if (pb->empty) {
79                 switch (pb->mode) {
80                 case NR_PIXBLOCK_MODE_A8:
81                         nr_lgradient_render_generic (lgr, pb);
82                         break;
83                 case NR_PIXBLOCK_MODE_R8G8B8:
84                         nr_lgradient_render_generic (lgr, pb);
85                         break;
86                 case NR_PIXBLOCK_MODE_R8G8B8A8N:
87                         nr_lgradient_render_R8G8B8A8N_EMPTY (lgr, NR_PIXBLOCK_PX (pb), pb->area.x0, pb->area.y0, width, height, pb->rs);
88                         break;
89                 case NR_PIXBLOCK_MODE_R8G8B8A8P:
90                         nr_lgradient_render_generic (lgr, pb);
91                         break;
92                 default:
93                         break;
94                 }
95         } else {
96                 switch (pb->mode) {
97                 case NR_PIXBLOCK_MODE_A8:
98                         nr_lgradient_render_generic (lgr, pb);
99                         break;
100                 case NR_PIXBLOCK_MODE_R8G8B8:
101                         nr_lgradient_render_R8G8B8 (lgr, NR_PIXBLOCK_PX (pb), pb->area.x0, pb->area.y0, width, height, pb->rs);
102                         break;
103                 case NR_PIXBLOCK_MODE_R8G8B8A8N:
104                         nr_lgradient_render_R8G8B8A8N (lgr, NR_PIXBLOCK_PX (pb), pb->area.x0, pb->area.y0, width, height, pb->rs);
105                         break;
106                 case NR_PIXBLOCK_MODE_R8G8B8A8P:
107                         nr_lgradient_render_generic (lgr, pb);
108                         break;
109                 default:
110                         break;
111                 }
112         }
113 #endif
116 static void
117 nr_lgradient_render_R8G8B8A8N_EMPTY (NRLGradientRenderer *lgr, unsigned char *px, int x0, int y0, int width, int height, int rs)
119         int x, y;
120         double pos;
122         for (y = 0; y < height; y++) {
123                 const unsigned char *s;
124                 unsigned char *d;
125                 int idx;
126                 d = px + y * rs;
127                 pos = (y + y0 - lgr->y0) * lgr->dy + (0 + x0 - lgr->x0) * lgr->dx;
128                 if (lgr->spread == NR_GRADIENT_SPREAD_PAD) {
129                         for (x = 0; x < width; x++) {
130                                 idx = (int) CLAMP (pos, 0, (double) NRG_MASK);
131                                 s = lgr->vector + 4 * idx;
132                                 d[0] = s[0];
133                                 d[1] = s[1];
134                                 d[2] = s[2];
135                                 d[3] = s[3];
136                                 d += 4;
137                                 pos += lgr->dx;
138                         }
139                 } else if (lgr->spread == NR_GRADIENT_SPREAD_REFLECT) {
140                         for (x = 0; x < width; x++) {
141                                 idx = (int) ((long long) pos & NRG_2MASK);
142                                 if (idx > NRG_MASK) idx = NRG_2MASK - idx;
143                                 s = lgr->vector + 4 * idx;
144                                 d[0] = s[0];
145                                 d[1] = s[1];
146                                 d[2] = s[2];
147                                 d[3] = s[3];
148                                 d += 4;
149                                 pos += lgr->dx;
150                         }
151                 } else {
152                         for (x = 0; x < width; x++) {
153                                 idx = (int) ((long long) pos & NRG_MASK);
154                                 s = lgr->vector + 4 * idx;
155                                 d[0] = s[0];
156                                 d[1] = s[1];
157                                 d[2] = s[2];
158                                 d[3] = s[3];
159                                 d += 4;
160                                 pos += lgr->dx;
161                         }
162                 }
163         }
166 static void
167 nr_lgradient_render_R8G8B8A8N (NRLGradientRenderer *lgr, unsigned char *px, int x0, int y0, int width, int height, int rs)
169         int x, y;
170         unsigned char *d;
171         double pos;
173         for (y = 0; y < height; y++) {
174                 d = px + y * rs;
175                 pos = (y + y0 - lgr->y0) * lgr->dy + (0 + x0 - lgr->x0) * lgr->dx;
176                 for (x = 0; x < width; x++) {
177                         int idx;
178                         unsigned int ca;
179                         const unsigned char *s;
180                         switch (lgr->spread) {
181                         case NR_GRADIENT_SPREAD_PAD:
182                                 idx = (int) CLAMP (pos, 0, (double) NRG_MASK);
183                                 break;
184                         case NR_GRADIENT_SPREAD_REFLECT:
185                                 idx = (int) ((long long) pos & NRG_2MASK);
186                                 if (idx > NRG_MASK) idx = NRG_2MASK - idx;
187                                 break;
188                         case NR_GRADIENT_SPREAD_REPEAT:
189                                 idx = (int) ((long long) pos & NRG_MASK);
190                                 break;
191                         default:
192                                 idx = 0;
193                                 break;
194                         }
195                         /* Full composition */
196                         s = lgr->vector + 4 * idx;
197                         if (s[3] == 255) {
198                                 d[0] = s[0];
199                                 d[1] = s[1];
200                                 d[2] = s[2];
201                                 d[3] = 255;
202                         } else if (s[3] != 0) {
203                                 ca = NR_COMPOSEA_112(s[3],d[3]);
204                                 d[0] = NR_COMPOSENNN_111121 (s[0], s[3], d[0], d[3], ca);
205                                 d[1] = NR_COMPOSENNN_111121 (s[1], s[3], d[1], d[3], ca);
206                                 d[2] = NR_COMPOSENNN_111121 (s[2], s[3], d[2], d[3], ca);
207                                 d[3] = NR_NORMALIZE_21(ca);
208                         }
209                         d += 4;
210                         pos += lgr->dx;
211                 }
212         }
215 static void
216 nr_lgradient_render_R8G8B8 (NRLGradientRenderer *lgr, unsigned char *px, int x0, int y0, int width, int height, int rs)
218         int x, y;
219         unsigned char *d;
220         double pos;
222         for (y = 0; y < height; y++) {
223                 d = px + y * rs;
224                 pos = (y + y0 - lgr->y0) * lgr->dy + (0 + x0 - lgr->x0) * lgr->dx;
225                 for (x = 0; x < width; x++) {
226                         int idx;
227                         const unsigned char *s;
228                         switch (lgr->spread) {
229                         case NR_GRADIENT_SPREAD_PAD:
230                                 idx = (int) CLAMP (pos, 0, (double) NRG_MASK);
231                                 break;
232                         case NR_GRADIENT_SPREAD_REFLECT:
233                                 idx = (int) ((long long) pos & NRG_2MASK);
234                                 if (idx > NRG_MASK) idx = NRG_2MASK - idx;
235                                 break;
236                         case NR_GRADIENT_SPREAD_REPEAT:
237                                 idx = (int) ((long long) pos & NRG_MASK);
238                                 break;
239                         default:
240                                 idx = 0;
241                                 break;
242                         }
243                         /* Full composition */
244                         s = lgr->vector + 4 * idx;
245                         d[0] = NR_COMPOSEN11_1111 (s[0], s[3], d[0]);
246                         d[1] = NR_COMPOSEN11_1111 (s[1], s[3], d[1]);
247                         d[2] = NR_COMPOSEN11_1111 (s[2], s[3], d[2]);
248                         d += 3;
249                         pos += lgr->dx;
250                 }
251         }
254 static void
255 nr_lgradient_render_generic (NRLGradientRenderer *lgr, NRPixBlock *pb)
257         int x, y;
258         unsigned char *d;
259         double pos;
260         int bpp;
261         NRPixBlock spb;
262         int x0, y0, width, height, rs;
264         x0 = pb->area.x0;
265         y0 = pb->area.y0;
266         width = pb->area.x1 - pb->area.x0;
267         height = pb->area.y1 - pb->area.y0;
268         rs = pb->rs;
270         nr_pixblock_setup_extern (&spb, NR_PIXBLOCK_MODE_R8G8B8A8N, 0, 0, NR_GRADIENT_VECTOR_LENGTH, 1,
271                                   (unsigned char *) lgr->vector,
272                                   4 * NR_GRADIENT_VECTOR_LENGTH,
273                                   0, 0);
274     spb.visible_area = pb->visible_area; 
275         bpp = (pb->mode == NR_PIXBLOCK_MODE_A8) ? 1 : (pb->mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
277         for (y = 0; y < height; y++) {
278                 d = NR_PIXBLOCK_PX (pb) + y * rs;
279                 pos = (y + y0 - lgr->y0) * lgr->dy + (0 + x0 - lgr->x0) * lgr->dx;
280                 for (x = 0; x < width; x++) {
281                         int idx;
282                         const unsigned char *s;
283                         switch (lgr->spread) {
284                         case NR_GRADIENT_SPREAD_PAD:
285                                 idx = (int) CLAMP (pos, 0, (double) NRG_MASK);
286                                 break;
287                         case NR_GRADIENT_SPREAD_REFLECT:
288                                 idx = (int) ((long long) pos & NRG_2MASK);
289                                 if (idx > NRG_MASK) idx = NRG_2MASK - idx;
290                                 break;
291                         case NR_GRADIENT_SPREAD_REPEAT:
292                                 idx = (int) ((long long) pos & NRG_MASK);
293                                 break;
294                         default:
295                                 idx = 0;
296                                 break;
297                         }
298                         s = lgr->vector + 4 * idx;
299                         nr_compose_pixblock_pixblock_pixel (pb, d, &spb, s);
300                         d += bpp;
301                         pos += lgr->dx;
302                 }
303         }
305         nr_pixblock_release (&spb);