The Allegro Wiki is migrating to github at https://github.com/liballeg/allegro_wiki/wiki

Intro

Filled areas in VectorGraphics are more complicated than for rasters. Each discrete filled area is a polygon .

Linear

• Linear tint with control points: Notes:

• Linear tints need the same 3 control points that Radial (and textured) fills use, in order to survive being sheared in transformations. A lot of the guff I wrote on this subject became obsolete when I realised this --

• Radial tint showing control points: Notes:

• This fill pattern is commonly called Radial (e.g. in Macromedia Flash) but could more correctly called Circular or Concentric. Paint Shop Pro calls it Sunburst.

Transforming pixel co-ordinates to a,b space

The vectors oa and ob are axes in their own 2d space. A vector can be transformed into pixel co-ordinates by multiplying by the following vector

TODO: matmul1.png

| a.x , b.x | | v.a |     =      | v.x |
| a.y , b.y | | v.b |     =      | v.y |

What we need for rendering though is the other way around, so we want the inverse of the matrix so that

M    | v.x |     =      | v.a |
| v.y |     =      | v.b |

The inverse of a 2x2 matrix | a b | is given by | | (from mathworld.wolfram.com)

Provided we have checked that neither oa or ob is of zero length, and o, a and b are not otherwise inline, then we can safely assume the determinant of the matrix is non-zero and the matrix is inversible.

So,

1                | b.y  ,  -b.x | | v.x |  =  | v.a |
-----------------------     |-a.y  ,   a.x | | v.y |     | v.b |
a.x * b.y  -  b.x * a.y

and thus, the code to get the a,b co-ordinates of the point (v.x,v.y) is :-

<highlightSyntax language="c">

v.a = ( b.y * v.x - b.x * v.y ) / (a.x * b.y - b.x * a.y);
v.b = (-a.y * v.x + a.x * v.y ) / (a.x * b.y - b.x * a.y);
</highlightSyntax>

Do I divide the determinant like this? -- Main.MattyMatt

Rendering by scanlines

• The results of the necessary transformation are calculated once before filling starts
• Each pixel is taken from the colourspace of the transformed fill pattern
• An array of ints holds the gradient: • Each scanline is passed the following params

* BITMAP * *bmp bitmap to draw to, this and y will be replaced by a single memory pointer in the final tuned version. * int *x left pixel * int *y y position to draw to * float *a,*b* co-ordinates in vector space. Linear tints only need the a co-ord. * float *da,*db* delta for each increment in x. * int * *t table of colours

<highlightSyntax language="c"> void draw_lineartint_scanline_( BITMAP * bmp, int x, int y, float a, float b, float da, float db, int t); void draw_radialtint_scanline_( BITMAP * bmp, int x, int y, float a, float b, float da, float db, int t); void draw_texturetint_scanline_( BITMAP * bmp, int x, int y, float a, float b, float da, float db, int t);

void draw_lineartint_scanline_(BITMAP * bmp, int x1, int y, int x2,

float a, float b, float da, float db, int * t)

{

int d = ftofix(a);
int dx = ftofix(da);
for (x = x1; x<x2; x++)
{
d = pt >> 6;                  // scale fixed 0~1 to table index.
if ( d < 0) d = 0;               // clamp min
if ( d >= VG_SIZE) d = VG_SIZE-1;   // clamp max
c = t[d];
putpixel(bmp, x, y, c);
d+=dx;
}

}

}

rectfill_tint( BITMAP * bmp, int x , int y, int x2, int y2, TINT * tint) {

start_a = tint->oax  *  x + tint->oay * y;
start_b = tint->obx  *  x + tint->oby * y;
/*delta a & b are oax and oay */
for (y1 =y; y1<= y2; y1++)
draw_lineartint_scanline_(bmp, x, y1,
start_a += tint->oay, start_b += tint->oby,
tint->oax, tint->obx,
tint->colortable );

}

setup_tint( TINT * tint, int x, int y, fixed scale, fixed rotate) {

fixed s = fixsin(rotate); fixed c = fixcos(rotate);

tint->oox = x + (in->ox * c + in->oy *s) * scale;
tint->ooy = y + (in->ox * s - in->oy *c) * scale;

tint->oax = x + (in->ax * c + in->ay *s) * scale;
tint->oay = y + (in->ax * s - in->ay *c) * scale;
tint->obx = x + (in->bx * c + in->by *s) * scale;
tint->oby = y + (in->bx * s - in->by *c) * scale;

}

/* now invert the new oa and ob vectors */

out-> ov.a = ( b.y * v.x - b.x * v.y ) / (a.x * b.y - b.x * a.y);
out-> ov.b = (-a.y * v.x + a.x * v.y ) / (a.x * b.y - b.x * a.y);

}

</highlightSyntax>