2 * art_render_gradient.c: SVP mask source for modular rendering.
4 * Libart_LGPL - library of basic graphic primitives
5 * Copyright (C) 2000 Raph Levien
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.
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.
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.
22 * Authors: Raph Levien <raph@acm.org>
26 #include "art_alphagamma.h"
28 #include "art_svp_render_aa.h"
30 #include "art_render.h"
31 #include "art_render_svp.h"
33 typedef struct _ArtMaskSourceSVP ArtMaskSourceSVP;
35 struct _ArtMaskSourceSVP {
43 art_render_svp_done (ArtRenderCallback *self, ArtRender *render)
49 art_render_svp_can_drive (ArtMaskSource *self, ArtRender *render)
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. */
60 art_render_svp_callback (void *callback_data, int y,
61 int start, ArtSVPRenderAAStep *steps, int n_steps)
63 ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
64 ArtRender *render = z->render;
67 int running_sum = start;
71 ArtRenderMaskRun *run = render->run;
76 if (run_x1 > x0 && running_sum > 0x80ff)
79 run[0].alpha = running_sum;
83 for (i = 0; i < n_steps - 1; i++)
85 running_sum += steps[i].delta;
87 run_x1 = steps[i + 1].x;
90 run[n_run].x = run_x0;
91 run[n_run].alpha = running_sum;
97 running_sum += steps[n_steps - 1].delta;
98 run[n_run].x = run_x1;
99 run[n_run].alpha = running_sum;
102 if (running_sum > 0x80ff)
105 run[n_run].alpha = 0x8000;
110 render->n_run = n_run;
112 art_render_invoke_callbacks (render, z->dest_ptr, y);
114 z->dest_ptr += render->rowstride;
118 art_render_svp_callback_span (void *callback_data, int y,
119 int start, ArtSVPRenderAAStep *steps, int n_steps)
121 ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
122 ArtRender *render = z->render;
126 int running_sum = start;
130 ArtRenderMaskRun *run = render->run;
131 int *span_x = render->span_x;
136 if (run_x1 > x0 && running_sum > 0x80ff)
139 run[0].alpha = running_sum;
145 for (i = 0; i < n_steps - 1; i++)
147 running_sum += steps[i].delta;
149 run_x1 = steps[i + 1].x;
152 run[n_run].x = run_x0;
153 run[n_run].alpha = running_sum;
155 if ((n_span & 1) != (running_sum > 0x80ff))
156 span_x[n_span++] = run_x0;
161 running_sum += steps[n_steps - 1].delta;
162 run[n_run].x = run_x1;
163 run[n_run].alpha = running_sum;
165 if ((n_span & 1) != (running_sum > 0x80ff))
166 span_x[n_span++] = run_x1;
168 if (running_sum > 0x80ff)
171 run[n_run].alpha = 0x8000;
173 span_x[n_span++] = x1;
177 render->n_run = n_run;
178 render->n_span = n_span;
180 art_render_invoke_callbacks (render, z->dest_ptr, y);
182 z->dest_ptr += render->rowstride;
186 art_render_svp_callback_opacity (void *callback_data, int y,
187 int start, ArtSVPRenderAAStep *steps, int n_steps)
189 ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
190 ArtRender *render = z->render;
197 ArtRenderMaskRun *run = render->run;
198 art_u32 opacity = render->opacity;
201 running_sum = start - 0x7f80;
206 alpha = ((running_sum >> 8) * opacity + 0x80080) >> 8;
207 if (run_x1 > x0 && alpha > 0x80ff)
210 run[0].alpha = alpha;
214 for (i = 0; i < n_steps - 1; i++)
216 running_sum += steps[i].delta;
218 run_x1 = steps[i + 1].x;
221 run[n_run].x = run_x0;
222 alpha = ((running_sum >> 8) * opacity + 0x80080) >> 8;
223 run[n_run].alpha = alpha;
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;
238 run[n_run].alpha = 0x8000;
243 render->n_run = n_run;
245 art_render_invoke_callbacks (render, z->dest_ptr, y);
247 z->dest_ptr += render->rowstride;
251 art_render_svp_callback_opacity_span (void *callback_data, int y,
252 int start, ArtSVPRenderAAStep *steps, int n_steps)
254 ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
255 ArtRender *render = z->render;
263 ArtRenderMaskRun *run = render->run;
264 int *span_x = render->span_x;
265 art_u32 opacity = render->opacity;
268 running_sum = start - 0x7f80;
273 alpha = ((running_sum >> 8) * opacity + 0x800080) >> 8;
274 if (run_x1 > x0 && alpha > 0x80ff)
277 run[0].alpha = alpha;
283 for (i = 0; i < n_steps - 1; i++)
285 running_sum += steps[i].delta;
287 run_x1 = steps[i + 1].x;
290 run[n_run].x = run_x0;
291 alpha = ((running_sum >> 8) * opacity + 0x800080) >> 8;
292 run[n_run].alpha = alpha;
294 if ((n_span & 1) != (alpha > 0x80ff))
295 span_x[n_span++] = run_x0;
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;
305 if ((n_span & 1) != (alpha > 0x80ff))
306 span_x[n_span++] = run_x1;
311 run[n_run].alpha = 0x8000;
313 span_x[n_span++] = x1;
317 render->n_run = n_run;
318 render->n_span = n_span;
320 art_render_invoke_callbacks (render, z->dest_ptr, y);
322 z->dest_ptr += render->rowstride;
326 art_render_svp_invoke_driver (ArtMaskSource *self, ArtRender *render)
328 ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)self;
329 void (*callback) (void *callback_data,
332 ArtSVPRenderAAStep *steps, int n_steps);
334 z->dest_ptr = render->pixels;
335 if (render->opacity == 0x10000)
337 if (render->need_span)
338 callback = art_render_svp_callback_span;
340 callback = art_render_svp_callback;
344 if (render->need_span)
345 callback = art_render_svp_callback_opacity_span;
347 callback = art_render_svp_callback_opacity;
350 art_svp_render_aa (z->svp,
351 render->x0, render->y0,
352 render->x1, render->y1, callback,
354 art_render_svp_done (&self->super, render);
358 art_render_svp_prepare (ArtMaskSource *self, ArtRender *render,
362 art_die ("art_render_svp non-driver mode not yet implemented.\n");
366 * art_render_svp: Use an SVP as a render mask source.
367 * @render: Render object.
370 * Adds @svp to the render object as a mask. Note: @svp must remain
371 * allocated until art_render_invoke() is called on @render.
374 art_render_svp (ArtRender *render, const ArtSVP *svp)
376 ArtMaskSourceSVP *mask_source;
377 mask_source = art_new (ArtMaskSourceSVP, 1);
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;
387 art_render_add_mask_source (render, &mask_source->super);