You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
422 lines
9.8 KiB
422 lines
9.8 KiB
/*
|
|
* art_render_gradient.c: SVP mask source for modular rendering.
|
|
*
|
|
* Libart_LGPL - library of basic graphic primitives
|
|
* Copyright (C) 2000 Raph Levien
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*
|
|
* Authors: Raph Levien <raph@acm.org>
|
|
*/
|
|
|
|
#include "art_render_svp.h"
|
|
#include "art_svp_render_aa.h"
|
|
|
|
typedef struct _ArtMaskSourceSVP ArtMaskSourceSVP;
|
|
|
|
struct _ArtMaskSourceSVP {
|
|
ArtMaskSource super;
|
|
ArtRender *render;
|
|
const ArtSVP *svp;
|
|
art_u8 *dest_ptr;
|
|
};
|
|
|
|
static void
|
|
art_render_svp_done (ArtRenderCallback *self, ArtRender *render)
|
|
{
|
|
art_free (self);
|
|
}
|
|
|
|
static int
|
|
art_render_svp_can_drive (ArtMaskSource *self, ArtRender *render)
|
|
{
|
|
return 10;
|
|
}
|
|
|
|
/* The basic art_render_svp_callback function is repeated four times,
|
|
for all combinations of non-unit opacity and generating spans. In
|
|
general, I'd consider this bad style, but in this case I plead
|
|
a measurable performance improvement. */
|
|
|
|
static void
|
|
art_render_svp_callback (void *callback_data, int y,
|
|
int start, ArtSVPRenderAAStep *steps, int n_steps)
|
|
{
|
|
ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
|
|
ArtRender *render = z->render;
|
|
int n_run = 0;
|
|
int i;
|
|
int running_sum = start;
|
|
int x0 = render->x0;
|
|
int x1 = render->x1;
|
|
int run_x0, run_x1;
|
|
ArtRenderMaskRun *run = render->run;
|
|
|
|
if (n_steps > 0)
|
|
{
|
|
run_x1 = steps[0].x;
|
|
if (run_x1 > x0 && running_sum > 0x80ff)
|
|
{
|
|
run[0].x = x0;
|
|
run[0].alpha = running_sum;
|
|
n_run++;
|
|
}
|
|
|
|
for (i = 0; i < n_steps - 1; i++)
|
|
{
|
|
running_sum += steps[i].delta;
|
|
run_x0 = run_x1;
|
|
run_x1 = steps[i + 1].x;
|
|
if (run_x1 > run_x0)
|
|
{
|
|
run[n_run].x = run_x0;
|
|
run[n_run].alpha = running_sum;
|
|
n_run++;
|
|
}
|
|
}
|
|
if (x1 > run_x1)
|
|
{
|
|
running_sum += steps[n_steps - 1].delta;
|
|
run[n_run].x = run_x1;
|
|
run[n_run].alpha = running_sum;
|
|
n_run++;
|
|
}
|
|
if (running_sum > 0x80ff)
|
|
{
|
|
run[n_run].x = x1;
|
|
run[n_run].alpha = 0x8000;
|
|
n_run++;
|
|
}
|
|
}
|
|
else if ((running_sum >> 16) > 0)
|
|
{
|
|
run[0].x = x0;
|
|
run[0].alpha = running_sum;
|
|
run[1].x = x1;
|
|
run[1].alpha = running_sum;
|
|
n_run = 2;
|
|
}
|
|
|
|
render->n_run = n_run;
|
|
|
|
art_render_invoke_callbacks (render, z->dest_ptr, y);
|
|
|
|
z->dest_ptr += render->rowstride;
|
|
}
|
|
|
|
static void
|
|
art_render_svp_callback_span (void *callback_data, int y,
|
|
int start, ArtSVPRenderAAStep *steps, int n_steps)
|
|
{
|
|
ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
|
|
ArtRender *render = z->render;
|
|
int n_run = 0;
|
|
int n_span = 0;
|
|
int i;
|
|
int running_sum = start;
|
|
int x0 = render->x0;
|
|
int x1 = render->x1;
|
|
int run_x0, run_x1;
|
|
ArtRenderMaskRun *run = render->run;
|
|
int *span_x = render->span_x;
|
|
|
|
if (n_steps > 0)
|
|
{
|
|
run_x1 = steps[0].x;
|
|
if (run_x1 > x0 && running_sum > 0x80ff)
|
|
{
|
|
run[0].x = x0;
|
|
run[0].alpha = running_sum;
|
|
n_run++;
|
|
span_x[0] = x0;
|
|
n_span++;
|
|
}
|
|
|
|
for (i = 0; i < n_steps - 1; i++)
|
|
{
|
|
running_sum += steps[i].delta;
|
|
run_x0 = run_x1;
|
|
run_x1 = steps[i + 1].x;
|
|
if (run_x1 > run_x0)
|
|
{
|
|
run[n_run].x = run_x0;
|
|
run[n_run].alpha = running_sum;
|
|
n_run++;
|
|
if ((n_span & 1) != (running_sum > 0x80ff))
|
|
span_x[n_span++] = run_x0;
|
|
}
|
|
}
|
|
if (x1 > run_x1)
|
|
{
|
|
running_sum += steps[n_steps - 1].delta;
|
|
run[n_run].x = run_x1;
|
|
run[n_run].alpha = running_sum;
|
|
n_run++;
|
|
if ((n_span & 1) != (running_sum > 0x80ff))
|
|
span_x[n_span++] = run_x1;
|
|
}
|
|
if (running_sum > 0x80ff)
|
|
{
|
|
run[n_run].x = x1;
|
|
run[n_run].alpha = 0x8000;
|
|
n_run++;
|
|
span_x[n_span++] = x1;
|
|
}
|
|
}
|
|
else if ((running_sum >> 16) > 0)
|
|
{
|
|
run[0].x = x0;
|
|
run[0].alpha = running_sum;
|
|
run[1].x = x1;
|
|
run[1].alpha = running_sum;
|
|
n_run = 2;
|
|
span_x[0] = x0;
|
|
span_x[1] = x1;
|
|
n_span = 2;
|
|
}
|
|
|
|
render->n_run = n_run;
|
|
render->n_span = n_span;
|
|
|
|
art_render_invoke_callbacks (render, z->dest_ptr, y);
|
|
|
|
z->dest_ptr += render->rowstride;
|
|
}
|
|
|
|
static void
|
|
art_render_svp_callback_opacity (void *callback_data, int y,
|
|
int start, ArtSVPRenderAAStep *steps, int n_steps)
|
|
{
|
|
ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
|
|
ArtRender *render = z->render;
|
|
int n_run = 0;
|
|
int i;
|
|
art_u32 running_sum;
|
|
int x0 = render->x0;
|
|
int x1 = render->x1;
|
|
int run_x0, run_x1;
|
|
ArtRenderMaskRun *run = render->run;
|
|
art_u32 opacity = render->opacity;
|
|
art_u32 alpha;
|
|
|
|
running_sum = start - 0x7f80;
|
|
|
|
if (n_steps > 0)
|
|
{
|
|
run_x1 = steps[0].x;
|
|
alpha = ((running_sum >> 8) * opacity + 0x80080) >> 8;
|
|
if (run_x1 > x0 && alpha > 0x80ff)
|
|
{
|
|
run[0].x = x0;
|
|
run[0].alpha = alpha;
|
|
n_run++;
|
|
}
|
|
|
|
for (i = 0; i < n_steps - 1; i++)
|
|
{
|
|
running_sum += steps[i].delta;
|
|
run_x0 = run_x1;
|
|
run_x1 = steps[i + 1].x;
|
|
if (run_x1 > run_x0)
|
|
{
|
|
run[n_run].x = run_x0;
|
|
alpha = ((running_sum >> 8) * opacity + 0x80080) >> 8;
|
|
run[n_run].alpha = alpha;
|
|
n_run++;
|
|
}
|
|
}
|
|
if (x1 > run_x1)
|
|
{
|
|
running_sum += steps[n_steps - 1].delta;
|
|
run[n_run].x = run_x1;
|
|
alpha = ((running_sum >> 8) * opacity + 0x80080) >> 8;
|
|
run[n_run].alpha = alpha;
|
|
n_run++;
|
|
}
|
|
if (alpha > 0x80ff)
|
|
{
|
|
run[n_run].x = x1;
|
|
run[n_run].alpha = 0x8000;
|
|
n_run++;
|
|
}
|
|
}
|
|
else if ((running_sum >> 16) > 0)
|
|
{
|
|
run[0].x = x0;
|
|
run[0].alpha = running_sum;
|
|
run[1].x = x1;
|
|
run[1].alpha = running_sum;
|
|
n_run = 2;
|
|
}
|
|
|
|
render->n_run = n_run;
|
|
|
|
art_render_invoke_callbacks (render, z->dest_ptr, y);
|
|
|
|
z->dest_ptr += render->rowstride;
|
|
}
|
|
|
|
static void
|
|
art_render_svp_callback_opacity_span (void *callback_data, int y,
|
|
int start, ArtSVPRenderAAStep *steps, int n_steps)
|
|
{
|
|
ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
|
|
ArtRender *render = z->render;
|
|
int n_run = 0;
|
|
int n_span = 0;
|
|
int i;
|
|
art_u32 running_sum;
|
|
int x0 = render->x0;
|
|
int x1 = render->x1;
|
|
int run_x0, run_x1;
|
|
ArtRenderMaskRun *run = render->run;
|
|
int *span_x = render->span_x;
|
|
art_u32 opacity = render->opacity;
|
|
art_u32 alpha;
|
|
|
|
running_sum = start - 0x7f80;
|
|
|
|
if (n_steps > 0)
|
|
{
|
|
run_x1 = steps[0].x;
|
|
alpha = ((running_sum >> 8) * opacity + 0x800080) >> 8;
|
|
if (run_x1 > x0 && alpha > 0x80ff)
|
|
{
|
|
run[0].x = x0;
|
|
run[0].alpha = alpha;
|
|
n_run++;
|
|
span_x[0] = x0;
|
|
n_span++;
|
|
}
|
|
|
|
for (i = 0; i < n_steps - 1; i++)
|
|
{
|
|
running_sum += steps[i].delta;
|
|
run_x0 = run_x1;
|
|
run_x1 = steps[i + 1].x;
|
|
if (run_x1 > run_x0)
|
|
{
|
|
run[n_run].x = run_x0;
|
|
alpha = ((running_sum >> 8) * opacity + 0x800080) >> 8;
|
|
run[n_run].alpha = alpha;
|
|
n_run++;
|
|
if ((n_span & 1) != (alpha > 0x80ff))
|
|
span_x[n_span++] = run_x0;
|
|
}
|
|
}
|
|
if (x1 > run_x1)
|
|
{
|
|
running_sum += steps[n_steps - 1].delta;
|
|
run[n_run].x = run_x1;
|
|
alpha = ((running_sum >> 8) * opacity + 0x800080) >> 8;
|
|
run[n_run].alpha = alpha;
|
|
n_run++;
|
|
if ((n_span & 1) != (alpha > 0x80ff))
|
|
span_x[n_span++] = run_x1;
|
|
}
|
|
if (alpha > 0x80ff)
|
|
{
|
|
run[n_run].x = x1;
|
|
run[n_run].alpha = 0x8000;
|
|
n_run++;
|
|
span_x[n_span++] = x1;
|
|
}
|
|
}
|
|
else if ((running_sum >> 16) > 0)
|
|
{
|
|
run[0].x = x0;
|
|
run[0].alpha = running_sum;
|
|
run[1].x = x1;
|
|
run[1].alpha = running_sum;
|
|
n_run = 2;
|
|
span_x[0] = x0;
|
|
span_x[1] = x1;
|
|
n_span = 2;
|
|
}
|
|
|
|
render->n_run = n_run;
|
|
render->n_span = n_span;
|
|
|
|
art_render_invoke_callbacks (render, z->dest_ptr, y);
|
|
|
|
z->dest_ptr += render->rowstride;
|
|
}
|
|
|
|
static void
|
|
art_render_svp_invoke_driver (ArtMaskSource *self, ArtRender *render)
|
|
{
|
|
ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)self;
|
|
void (*callback) (void *callback_data,
|
|
int y,
|
|
int start,
|
|
ArtSVPRenderAAStep *steps, int n_steps);
|
|
|
|
z->dest_ptr = render->pixels;
|
|
if (render->opacity == 0x10000)
|
|
{
|
|
if (render->need_span)
|
|
callback = art_render_svp_callback_span;
|
|
else
|
|
callback = art_render_svp_callback;
|
|
}
|
|
else
|
|
{
|
|
if (render->need_span)
|
|
callback = art_render_svp_callback_opacity_span;
|
|
else
|
|
callback = art_render_svp_callback_opacity;
|
|
}
|
|
|
|
art_svp_render_aa (z->svp,
|
|
render->x0, render->y0,
|
|
render->x1, render->y1, callback,
|
|
self);
|
|
art_render_svp_done (&self->super, render);
|
|
}
|
|
|
|
static void
|
|
art_render_svp_prepare (ArtMaskSource *self, ArtRender *render,
|
|
art_boolean first)
|
|
{
|
|
/* todo */
|
|
art_die ("art_render_svp non-driver mode not yet implemented.\n");
|
|
}
|
|
|
|
/**
|
|
* art_render_svp: Use an SVP as a render mask source.
|
|
* @render: Render object.
|
|
* @svp: SVP.
|
|
*
|
|
* Adds @svp to the render object as a mask. Note: @svp must remain
|
|
* allocated until art_render_invoke() is called on @render.
|
|
**/
|
|
void
|
|
art_render_svp (ArtRender *render, const ArtSVP *svp)
|
|
{
|
|
ArtMaskSourceSVP *mask_source;
|
|
mask_source = art_new (ArtMaskSourceSVP, 1);
|
|
|
|
mask_source->super.super.render = NULL;
|
|
mask_source->super.super.done = art_render_svp_done;
|
|
mask_source->super.can_drive = art_render_svp_can_drive;
|
|
mask_source->super.invoke_driver = art_render_svp_invoke_driver;
|
|
mask_source->super.prepare = art_render_svp_prepare;
|
|
mask_source->render = render;
|
|
mask_source->svp = svp;
|
|
|
|
art_render_add_mask_source (render, &mask_source->super);
|
|
}
|