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
114 }
116 static void
117 nr_lgradient_render_R8G8B8A8N_EMPTY (NRLGradientRenderer *lgr, unsigned char *px, int x0, int y0, int width, int height, int rs)
118 {
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 }
164 }
166 static void
167 nr_lgradient_render_R8G8B8A8N (NRLGradientRenderer *lgr, unsigned char *px, int x0, int y0, int width, int height, int rs)
168 {
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_A7(s[3],d[3]);
204 d[0] = NR_COMPOSENNN_A7 (s[0], s[3], d[0], d[3], ca);
205 d[1] = NR_COMPOSENNN_A7 (s[1], s[3], d[1], d[3], ca);
206 d[2] = NR_COMPOSENNN_A7 (s[2], s[3], d[2], d[3], ca);
207 d[3] = NR_PREMUL_SINGLE(ca);
208 }
209 d += 4;
210 pos += lgr->dx;
211 }
212 }
213 }
215 static void
216 nr_lgradient_render_R8G8B8 (NRLGradientRenderer *lgr, unsigned char *px, int x0, int y0, int width, int height, int rs)
217 {
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 (s[0], s[3], d[0]);
246 d[1] = NR_COMPOSEN11 (s[1], s[3], d[1]);
247 d[2] = NR_COMPOSEN11 (s[2], s[3], d[2]);
248 d += 3;
249 pos += lgr->dx;
250 }
251 }
252 }
254 static void
255 nr_lgradient_render_generic (NRLGradientRenderer *lgr, NRPixBlock *pb)
256 {
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 bpp = (pb->mode == NR_PIXBLOCK_MODE_A8) ? 1 : (pb->mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
276 for (y = 0; y < height; y++) {
277 d = NR_PIXBLOCK_PX (pb) + y * rs;
278 pos = (y + y0 - lgr->y0) * lgr->dy + (0 + x0 - lgr->x0) * lgr->dx;
279 for (x = 0; x < width; x++) {
280 int idx;
281 const unsigned char *s;
282 switch (lgr->spread) {
283 case NR_GRADIENT_SPREAD_PAD:
284 idx = (int) CLAMP (pos, 0, (double) NRG_MASK);
285 break;
286 case NR_GRADIENT_SPREAD_REFLECT:
287 idx = (int) ((long long) pos & NRG_2MASK);
288 if (idx > NRG_MASK) idx = NRG_2MASK - idx;
289 break;
290 case NR_GRADIENT_SPREAD_REPEAT:
291 idx = (int) ((long long) pos & NRG_MASK);
292 break;
293 default:
294 idx = 0;
295 break;
296 }
297 s = lgr->vector + 4 * idx;
298 nr_compose_pixblock_pixblock_pixel (pb, d, &spb, s);
299 d += bpp;
300 pos += lgr->dx;
301 }
302 }
304 nr_pixblock_release (&spb);
305 }