added gfxline_transform(), gfxline_clone(), gfxmatrix_dump()
[swftools.git] / lib / art / 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_render_svp.h"
26 #include "art_svp_render_aa.h"
27
28 typedef struct _ArtMaskSourceSVP ArtMaskSourceSVP;
29
30 struct _ArtMaskSourceSVP {
31   ArtMaskSource super;
32   ArtRender *render;
33   const ArtSVP *svp;
34   art_u8 *dest_ptr;
35 };
36
37 static void
38 art_render_svp_done (ArtRenderCallback *self, ArtRender *render)
39 {
40   art_free (self);
41 }
42
43 static int
44 art_render_svp_can_drive (ArtMaskSource *self, ArtRender *render)
45 {
46   return 10;
47 }
48
49 /* The basic art_render_svp_callback function is repeated four times,
50    for all combinations of non-unit opacity and generating spans. In
51    general, I'd consider this bad style, but in this case I plead
52    a measurable performance improvement. */
53
54 static void
55 art_render_svp_callback (void *callback_data, int y,
56                          int start, ArtSVPRenderAAStep *steps, int n_steps)
57 {
58   ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
59   ArtRender *render = z->render;
60   int n_run = 0;
61   int i;
62   int running_sum = start;
63   int x0 = render->x0;
64   int x1 = render->x1;
65   int run_x0, run_x1;
66   ArtRenderMaskRun *run = render->run;
67
68   if (n_steps > 0)
69     {
70       run_x1 = steps[0].x;
71       if (run_x1 > x0 && running_sum > 0x80ff)
72         {
73           run[0].x = x0;
74           run[0].alpha = running_sum;
75           n_run++;
76         }
77
78       for (i = 0; i < n_steps - 1; i++)
79         {
80           running_sum += steps[i].delta;
81           run_x0 = run_x1;
82           run_x1 = steps[i + 1].x;
83           if (run_x1 > run_x0)
84             {
85               run[n_run].x = run_x0;
86               run[n_run].alpha = running_sum;
87               n_run++;
88             }
89         }
90       if (x1 > run_x1)
91         {
92           running_sum += steps[n_steps - 1].delta;
93           run[n_run].x = run_x1;
94           run[n_run].alpha = running_sum;
95           n_run++;
96         }
97       if (running_sum > 0x80ff)
98         {
99           run[n_run].x = x1;
100           run[n_run].alpha = 0x8000;
101           n_run++;
102         }
103     }
104   else if ((running_sum >> 16) > 0)
105     {
106       run[0].x = x0;
107       run[0].alpha = running_sum;
108       run[1].x = x1;
109       run[1].alpha = running_sum;
110       n_run = 2;
111     }
112
113   render->n_run = n_run;
114
115   art_render_invoke_callbacks (render, z->dest_ptr, y);
116
117   z->dest_ptr += render->rowstride;
118 }
119
120 static void
121 art_render_svp_callback_span (void *callback_data, int y,
122                               int start, ArtSVPRenderAAStep *steps, int n_steps)
123 {
124   ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
125   ArtRender *render = z->render;
126   int n_run = 0;
127   int n_span = 0;
128   int i;
129   int running_sum = start;
130   int x0 = render->x0;
131   int x1 = render->x1;
132   int run_x0, run_x1;
133   ArtRenderMaskRun *run = render->run;
134   int *span_x = render->span_x;
135
136   if (n_steps > 0)
137     {
138       run_x1 = steps[0].x;
139       if (run_x1 > x0 && running_sum > 0x80ff)
140         {
141           run[0].x = x0;
142           run[0].alpha = running_sum;
143           n_run++;
144           span_x[0] = x0;
145           n_span++;
146         }
147
148       for (i = 0; i < n_steps - 1; i++)
149         {
150           running_sum += steps[i].delta;
151           run_x0 = run_x1;
152           run_x1 = steps[i + 1].x;
153           if (run_x1 > run_x0)
154             {
155               run[n_run].x = run_x0;
156               run[n_run].alpha = running_sum;
157               n_run++;
158               if ((n_span & 1) != (running_sum > 0x80ff))
159                 span_x[n_span++] = run_x0;
160             }
161         }
162       if (x1 > run_x1)
163         {
164           running_sum += steps[n_steps - 1].delta;
165           run[n_run].x = run_x1;
166           run[n_run].alpha = running_sum;
167           n_run++;
168           if ((n_span & 1) != (running_sum > 0x80ff))
169             span_x[n_span++] = run_x1;
170         }
171       if (running_sum > 0x80ff)
172         {
173           run[n_run].x = x1;
174           run[n_run].alpha = 0x8000;
175           n_run++;
176           span_x[n_span++] = x1;
177         }
178     }
179   else if ((running_sum >> 16) > 0)
180     {
181       run[0].x = x0;
182       run[0].alpha = running_sum;
183       run[1].x = x1;
184       run[1].alpha = running_sum;
185       n_run = 2;
186       span_x[0] = x0;
187       span_x[1] = x1;
188       n_span = 2;
189     }
190
191   render->n_run = n_run;
192   render->n_span = n_span;
193
194   art_render_invoke_callbacks (render, z->dest_ptr, y);
195
196   z->dest_ptr += render->rowstride;
197 }
198
199 static void
200 art_render_svp_callback_opacity (void *callback_data, int y,
201                                  int start, ArtSVPRenderAAStep *steps, int n_steps)
202 {
203   ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
204   ArtRender *render = z->render;
205   int n_run = 0;
206   int i;
207   art_u32 running_sum;
208   int x0 = render->x0;
209   int x1 = render->x1;
210   int run_x0, run_x1;
211   ArtRenderMaskRun *run = render->run;
212   art_u32 opacity = render->opacity;
213   art_u32 alpha;
214
215   running_sum = start - 0x7f80;
216
217   if (n_steps > 0)
218     {
219       run_x1 = steps[0].x;
220       alpha = ((running_sum >> 8) * opacity + 0x80080) >> 8;
221       if (run_x1 > x0 && alpha > 0x80ff)
222         {
223           run[0].x = x0;
224           run[0].alpha = alpha;
225           n_run++;
226         }
227
228       for (i = 0; i < n_steps - 1; i++)
229         {
230           running_sum += steps[i].delta;
231           run_x0 = run_x1;
232           run_x1 = steps[i + 1].x;
233           if (run_x1 > run_x0)
234             {
235               run[n_run].x = run_x0;
236               alpha = ((running_sum >> 8) * opacity + 0x80080) >> 8;
237               run[n_run].alpha = alpha;
238               n_run++;
239             }
240         }
241       if (x1 > run_x1)
242         {
243           running_sum += steps[n_steps - 1].delta;
244           run[n_run].x = run_x1;
245           alpha = ((running_sum >> 8) * opacity + 0x80080) >> 8;
246           run[n_run].alpha = alpha;
247           n_run++;
248         }
249       if (alpha > 0x80ff)
250         {
251           run[n_run].x = x1;
252           run[n_run].alpha = 0x8000;
253           n_run++;
254         }
255     }
256   else if ((running_sum >> 16) > 0)
257     {
258       run[0].x = x0;
259       run[0].alpha = running_sum;
260       run[1].x = x1;
261       run[1].alpha = running_sum;
262       n_run = 2;
263     }
264
265   render->n_run = n_run;
266
267   art_render_invoke_callbacks (render, z->dest_ptr, y);
268
269   z->dest_ptr += render->rowstride;
270 }
271
272 static void
273 art_render_svp_callback_opacity_span (void *callback_data, int y,
274                                       int start, ArtSVPRenderAAStep *steps, int n_steps)
275 {
276   ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
277   ArtRender *render = z->render;
278   int n_run = 0;
279   int n_span = 0;
280   int i;
281   art_u32 running_sum;
282   int x0 = render->x0;
283   int x1 = render->x1;
284   int run_x0, run_x1;
285   ArtRenderMaskRun *run = render->run;
286   int *span_x = render->span_x;
287   art_u32 opacity = render->opacity;
288   art_u32 alpha;
289
290   running_sum = start - 0x7f80;
291
292   if (n_steps > 0)
293     {
294       run_x1 = steps[0].x;
295       alpha = ((running_sum >> 8) * opacity + 0x800080) >> 8;
296       if (run_x1 > x0 && alpha > 0x80ff)
297         {
298           run[0].x = x0;
299           run[0].alpha = alpha;
300           n_run++;
301           span_x[0] = x0;
302           n_span++;
303         }
304
305       for (i = 0; i < n_steps - 1; i++)
306         {
307           running_sum += steps[i].delta;
308           run_x0 = run_x1;
309           run_x1 = steps[i + 1].x;
310           if (run_x1 > run_x0)
311             {
312               run[n_run].x = run_x0;
313               alpha = ((running_sum >> 8) * opacity + 0x800080) >> 8;
314               run[n_run].alpha = alpha;
315               n_run++;
316               if ((n_span & 1) != (alpha > 0x80ff))
317                 span_x[n_span++] = run_x0;
318             }
319         }
320       if (x1 > run_x1)
321         {
322           running_sum += steps[n_steps - 1].delta;
323           run[n_run].x = run_x1;
324           alpha = ((running_sum >> 8) * opacity + 0x800080) >> 8;
325           run[n_run].alpha = alpha;
326           n_run++;
327           if ((n_span & 1) != (alpha > 0x80ff))
328             span_x[n_span++] = run_x1;
329         }
330       if (alpha > 0x80ff)
331         {
332           run[n_run].x = x1;
333           run[n_run].alpha = 0x8000;
334           n_run++;
335           span_x[n_span++] = x1;
336         }
337     }
338   else if ((running_sum >> 16) > 0)
339     {
340       run[0].x = x0;
341       run[0].alpha = running_sum;
342       run[1].x = x1;
343       run[1].alpha = running_sum;
344       n_run = 2;
345       span_x[0] = x0;
346       span_x[1] = x1;
347       n_span = 2;
348     }
349
350   render->n_run = n_run;
351   render->n_span = n_span;
352
353   art_render_invoke_callbacks (render, z->dest_ptr, y);
354
355   z->dest_ptr += render->rowstride;
356 }
357
358 static void
359 art_render_svp_invoke_driver (ArtMaskSource *self, ArtRender *render)
360 {
361   ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)self;
362   void (*callback) (void *callback_data,
363                     int y,
364                     int start,
365                     ArtSVPRenderAAStep *steps, int n_steps);
366
367   z->dest_ptr = render->pixels;
368   if (render->opacity == 0x10000)
369     {
370       if (render->need_span)
371         callback = art_render_svp_callback_span;
372       else
373         callback = art_render_svp_callback;
374     }
375   else
376     {
377       if (render->need_span)
378         callback = art_render_svp_callback_opacity_span;
379       else
380         callback = art_render_svp_callback_opacity;
381     }
382
383   art_svp_render_aa (z->svp,
384                      render->x0, render->y0,
385                      render->x1, render->y1, callback,
386                      self);
387   art_render_svp_done (&self->super, render);
388 }
389
390 static void
391 art_render_svp_prepare (ArtMaskSource *self, ArtRender *render,
392                         art_boolean first)
393 {
394   /* todo */
395   art_die ("art_render_svp non-driver mode not yet implemented.\n");
396 }
397
398 /**
399  * art_render_svp: Use an SVP as a render mask source.
400  * @render: Render object.
401  * @svp: SVP.
402  *
403  * Adds @svp to the render object as a mask. Note: @svp must remain
404  * allocated until art_render_invoke() is called on @render.
405  **/
406 void
407 art_render_svp (ArtRender *render, const ArtSVP *svp)
408 {
409   ArtMaskSourceSVP *mask_source;
410   mask_source = art_new (ArtMaskSourceSVP, 1);
411
412   mask_source->super.super.render = NULL;
413   mask_source->super.super.done = art_render_svp_done;
414   mask_source->super.can_drive = art_render_svp_can_drive;
415   mask_source->super.invoke_driver = art_render_svp_invoke_driver;
416   mask_source->super.prepare = art_render_svp_prepare;
417   mask_source->render = render;
418   mask_source->svp = svp;
419
420   art_render_add_mask_source (render, &mask_source->super);
421 }