The BIG graph update
[rrdtool.git] / libraries / libart_lgpl-2.3.7 / art_render_svp.c
1 /*
2  * art_render_gradient.c: SVP mask source for modular rendering.
3  *
4  * Libart_LGPL - library of basic graphic primitives
5  * Copyright (C) 2000 Raph Levien
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  *
22  * Authors: Raph Levien <raph@acm.org>
23  */
24
25 #include "art_misc.h"
26 #include "art_alphagamma.h"
27 #include "art_svp.h"
28 #include "art_svp_render_aa.h"
29
30 #include "art_render.h"
31 #include "art_render_svp.h"
32
33 typedef struct _ArtMaskSourceSVP ArtMaskSourceSVP;
34
35 struct _ArtMaskSourceSVP {
36   ArtMaskSource super;
37   ArtRender *render;
38   const ArtSVP *svp;
39   art_u8 *dest_ptr;
40 };
41
42 static void
43 art_render_svp_done (ArtRenderCallback *self, ArtRender *render)
44 {
45   art_free (self);
46 }
47
48 static int
49 art_render_svp_can_drive (ArtMaskSource *self, ArtRender *render)
50 {
51   return 10;
52 }
53
54 /* The basic art_render_svp_callback function is repeated four times,
55    for all combinations of non-unit opacity and generating spans. In
56    general, I'd consider this bad style, but in this case I plead
57    a measurable performance improvement. */
58
59 static void
60 art_render_svp_callback (void *callback_data, int y,
61                          int start, ArtSVPRenderAAStep *steps, int n_steps)
62 {
63   ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
64   ArtRender *render = z->render;
65   int n_run = 0;
66   int i;
67   int running_sum = start;
68   int x0 = render->x0;
69   int x1 = render->x1;
70   int run_x0, run_x1;
71   ArtRenderMaskRun *run = render->run;
72
73   if (n_steps > 0)
74     {
75       run_x1 = steps[0].x;
76       if (run_x1 > x0 && running_sum > 0x80ff)
77         {
78           run[0].x = x0;
79           run[0].alpha = running_sum;
80           n_run++;
81         }
82
83       for (i = 0; i < n_steps - 1; i++)
84         {
85           running_sum += steps[i].delta;
86           run_x0 = run_x1;
87           run_x1 = steps[i + 1].x;
88           if (run_x1 > run_x0)
89             {
90               run[n_run].x = run_x0;
91               run[n_run].alpha = running_sum;
92               n_run++;
93             }
94         }
95       if (x1 > run_x1)
96         {
97           running_sum += steps[n_steps - 1].delta;
98           run[n_run].x = run_x1;
99           run[n_run].alpha = running_sum;
100           n_run++;
101         }
102       if (running_sum > 0x80ff)
103         {
104           run[n_run].x = x1;
105           run[n_run].alpha = 0x8000;
106           n_run++;
107         }
108     }
109
110   render->n_run = n_run;
111
112   art_render_invoke_callbacks (render, z->dest_ptr, y);
113
114   z->dest_ptr += render->rowstride;
115 }
116
117 static void
118 art_render_svp_callback_span (void *callback_data, int y,
119                               int start, ArtSVPRenderAAStep *steps, int n_steps)
120 {
121   ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
122   ArtRender *render = z->render;
123   int n_run = 0;
124   int n_span = 0;
125   int i;
126   int running_sum = start;
127   int x0 = render->x0;
128   int x1 = render->x1;
129   int run_x0, run_x1;
130   ArtRenderMaskRun *run = render->run;
131   int *span_x = render->span_x;
132
133   if (n_steps > 0)
134     {
135       run_x1 = steps[0].x;
136       if (run_x1 > x0 && running_sum > 0x80ff)
137         {
138           run[0].x = x0;
139           run[0].alpha = running_sum;
140           n_run++;
141           span_x[0] = x0;
142           n_span++;
143         }
144
145       for (i = 0; i < n_steps - 1; i++)
146         {
147           running_sum += steps[i].delta;
148           run_x0 = run_x1;
149           run_x1 = steps[i + 1].x;
150           if (run_x1 > run_x0)
151             {
152               run[n_run].x = run_x0;
153               run[n_run].alpha = running_sum;
154               n_run++;
155               if ((n_span & 1) != (running_sum > 0x80ff))
156                 span_x[n_span++] = run_x0;
157             }
158         }
159       if (x1 > run_x1)
160         {
161           running_sum += steps[n_steps - 1].delta;
162           run[n_run].x = run_x1;
163           run[n_run].alpha = running_sum;
164           n_run++;
165           if ((n_span & 1) != (running_sum > 0x80ff))
166             span_x[n_span++] = run_x1;
167         }
168       if (running_sum > 0x80ff)
169         {
170           run[n_run].x = x1;
171           run[n_run].alpha = 0x8000;
172           n_run++;
173           span_x[n_span++] = x1;
174         }
175     }
176
177   render->n_run = n_run;
178   render->n_span = n_span;
179
180   art_render_invoke_callbacks (render, z->dest_ptr, y);
181
182   z->dest_ptr += render->rowstride;
183 }
184
185 static void
186 art_render_svp_callback_opacity (void *callback_data, int y,
187                                  int start, ArtSVPRenderAAStep *steps, int n_steps)
188 {
189   ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
190   ArtRender *render = z->render;
191   int n_run = 0;
192   int i;
193   art_u32 running_sum;
194   int x0 = render->x0;
195   int x1 = render->x1;
196   int run_x0, run_x1;
197   ArtRenderMaskRun *run = render->run;
198   art_u32 opacity = render->opacity;
199   art_u32 alpha;
200
201   running_sum = start - 0x7f80;
202
203   if (n_steps > 0)
204     {
205       run_x1 = steps[0].x;
206       alpha = ((running_sum >> 8) * opacity + 0x80080) >> 8;
207       if (run_x1 > x0 && alpha > 0x80ff)
208         {
209           run[0].x = x0;
210           run[0].alpha = alpha;
211           n_run++;
212         }
213
214       for (i = 0; i < n_steps - 1; i++)
215         {
216           running_sum += steps[i].delta;
217           run_x0 = run_x1;
218           run_x1 = steps[i + 1].x;
219           if (run_x1 > run_x0)
220             {
221               run[n_run].x = run_x0;
222               alpha = ((running_sum >> 8) * opacity + 0x80080) >> 8;
223               run[n_run].alpha = alpha;
224               n_run++;
225             }
226         }
227       if (x1 > run_x1)
228         {
229           running_sum += steps[n_steps - 1].delta;
230           run[n_run].x = run_x1;
231           alpha = ((running_sum >> 8) * opacity + 0x80080) >> 8;
232           run[n_run].alpha = alpha;
233           n_run++;
234         }
235       if (alpha > 0x80ff)
236         {
237           run[n_run].x = x1;
238           run[n_run].alpha = 0x8000;
239           n_run++;
240         }
241     }
242
243   render->n_run = n_run;
244
245   art_render_invoke_callbacks (render, z->dest_ptr, y);
246
247   z->dest_ptr += render->rowstride;
248 }
249
250 static void
251 art_render_svp_callback_opacity_span (void *callback_data, int y,
252                                       int start, ArtSVPRenderAAStep *steps, int n_steps)
253 {
254   ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
255   ArtRender *render = z->render;
256   int n_run = 0;
257   int n_span = 0;
258   int i;
259   art_u32 running_sum;
260   int x0 = render->x0;
261   int x1 = render->x1;
262   int run_x0, run_x1;
263   ArtRenderMaskRun *run = render->run;
264   int *span_x = render->span_x;
265   art_u32 opacity = render->opacity;
266   art_u32 alpha;
267
268   running_sum = start - 0x7f80;
269
270   if (n_steps > 0)
271     {
272       run_x1 = steps[0].x;
273       alpha = ((running_sum >> 8) * opacity + 0x800080) >> 8;
274       if (run_x1 > x0 && alpha > 0x80ff)
275         {
276           run[0].x = x0;
277           run[0].alpha = alpha;
278           n_run++;
279           span_x[0] = x0;
280           n_span++;
281         }
282
283       for (i = 0; i < n_steps - 1; i++)
284         {
285           running_sum += steps[i].delta;
286           run_x0 = run_x1;
287           run_x1 = steps[i + 1].x;
288           if (run_x1 > run_x0)
289             {
290               run[n_run].x = run_x0;
291               alpha = ((running_sum >> 8) * opacity + 0x800080) >> 8;
292               run[n_run].alpha = alpha;
293               n_run++;
294               if ((n_span & 1) != (alpha > 0x80ff))
295                 span_x[n_span++] = run_x0;
296             }
297         }
298       if (x1 > run_x1)
299         {
300           running_sum += steps[n_steps - 1].delta;
301           run[n_run].x = run_x1;
302           alpha = ((running_sum >> 8) * opacity + 0x800080) >> 8;
303           run[n_run].alpha = alpha;
304           n_run++;
305           if ((n_span & 1) != (alpha > 0x80ff))
306             span_x[n_span++] = run_x1;
307         }
308       if (alpha > 0x80ff)
309         {
310           run[n_run].x = x1;
311           run[n_run].alpha = 0x8000;
312           n_run++;
313           span_x[n_span++] = x1;
314         }
315     }
316
317   render->n_run = n_run;
318   render->n_span = n_span;
319
320   art_render_invoke_callbacks (render, z->dest_ptr, y);
321
322   z->dest_ptr += render->rowstride;
323 }
324
325 static void
326 art_render_svp_invoke_driver (ArtMaskSource *self, ArtRender *render)
327 {
328   ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)self;
329   void (*callback) (void *callback_data,
330                     int y,
331                     int start,
332                     ArtSVPRenderAAStep *steps, int n_steps);
333
334   z->dest_ptr = render->pixels;
335   if (render->opacity == 0x10000)
336     {
337       if (render->need_span)
338         callback = art_render_svp_callback_span;
339       else
340         callback = art_render_svp_callback;
341     }
342   else
343     {
344       if (render->need_span)
345         callback = art_render_svp_callback_opacity_span;
346       else
347         callback = art_render_svp_callback_opacity;
348     }
349
350   art_svp_render_aa (z->svp,
351                      render->x0, render->y0,
352                      render->x1, render->y1, callback,
353                      self);
354   art_render_svp_done (&self->super, render);
355 }
356
357 static void
358 art_render_svp_prepare (ArtMaskSource *self, ArtRender *render,
359                         art_boolean first)
360 {
361   /* todo */
362   art_die ("art_render_svp non-driver mode not yet implemented.\n");
363 }
364
365 /**
366  * art_render_svp: Use an SVP as a render mask source.
367  * @render: Render object.
368  * @svp: SVP.
369  *
370  * Adds @svp to the render object as a mask. Note: @svp must remain
371  * allocated until art_render_invoke() is called on @render.
372  **/
373 void
374 art_render_svp (ArtRender *render, const ArtSVP *svp)
375 {
376   ArtMaskSourceSVP *mask_source;
377   mask_source = art_new (ArtMaskSourceSVP, 1);
378
379   mask_source->super.super.render = NULL;
380   mask_source->super.super.done = art_render_svp_done;
381   mask_source->super.can_drive = art_render_svp_can_drive;
382   mask_source->super.invoke_driver = art_render_svp_invoke_driver;
383   mask_source->super.prepare = art_render_svp_prepare;
384   mask_source->render = render;
385   mask_source->svp = svp;
386
387   art_render_add_mask_source (render, &mask_source->super);
388 }