digitalmars.D - Sometimes, all you need is some simple drawing primitives

• Downs (308/308) Sep 19 2007 -----BEGIN PGP SIGNED MESSAGE-----
• BCS (3/17) Sep 19 2007 Given me your dsource Username and I'll give you access so you can add
• Downs (13/31) Sep 19 2007 -----BEGIN PGP SIGNED MESSAGE-----
• BCS (2/4) Sep 19 2007 Now you tell me :-b
• Bill Baxter (4/17) Sep 19 2007 You can do a bresenham-style ellipse renderer.
• Downs (310/328) Sep 19 2007 -----BEGIN PGP SIGNED MESSAGE-----
Downs <default_357-line yahoo.de> writes:
```-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Here's some simple graphics primitives on top of SDL: pset, pget, line,
circle and bucket-fill (paint).
It's modelled after QBasic, which I still think has the most intuitive,
easy to use graphics API I've seen so far.

The code is placed in the public domain.

On that account, does anybody know a good algorithm for drawing
ellipses? The one I came up with is kind of broken for ratios around or
over 1:5 ...

Code <qd.d>:

import std.stdio, std.c.time;

void main() {
screen(640, 480);
pset(10, 10);
line(0, 0, 100, 100, Box, Back(Red~Black));
for (int i=0; i<=100; i+=10) {
line(i, 0, 100-i, 100);
line(0, i, 100, 100-i);
}
circle(100, 100, 50, 15, White~Black, Fill=White~Black);
paint(200, 200, Red, Back=White);
circle(100, 100, 50, 15, White);
paint(200, 200, Black);
pset(10, 11); pset(10, 11, Black);
pset(10, 10);
sleep(5);
}

extern(C) {
struct SDL_Rect {
short x, y;
ushort w, h;
}
struct SDL_PixelFormat {
//SDL_Palette *palette;
void *palette;
ubyte BitsPerPixel, BytesPerPixel, Rloss, Gloss, Bloss, Aloss,
Rshift, Gshift, Bshift, Ashift;
}
struct SDL_Surface {
uint flags;
SDL_PixelFormat *format;
int w, h;
ushort pitch;
void *pixels;
int offset;
void *hwdata;
SDL_Rect clip_rect;
uint unused;
uint locked;
void *map;
uint format_version;
int refcount;
}
uint SDL_MapRGBA(SDL_PixelFormat *format, ubyte r, ubyte g, ubyte b,
ubyte a);
void SDL_GetRGBA(uint pixel, SDL_PixelFormat *fmt, ubyte *r, ubyte *g,
ubyte *b, ubyte *a);
int SDL_LockSurface(SDL_Surface *);
void SDL_UnlockSurface(SDL_Surface *);
SDL_Surface * SDL_SetVideoMode(int width, int height, int bpp, uint
flags);
int SDL_Flip(SDL_Surface *);
const uint SDL_SWSURFACE=0;
const uint SDL_HWSURFACE=1;
const uint SDL_DOUBLEBUF=0x40000000;
const uint SDL_FULLSCREEN=0x80000000;
}

SDL_Surface *display;

void putpixel32(SDL_Surface *surf, int x, int y, ubyte[4] col) {
uint *bufp = cast(uint *)surf.pixels + y*surf.pitch/4 + x;
*bufp = SDL_MapRGBA(surf.format, col[0], col[1], col[2], col[3]);
}

void getpixel32(SDL_Surface *surf, int x, int y, ubyte[4] *col) {
uint *bufp = cast(uint *)surf.pixels + y*surf.pitch/4 + x;
SDL_GetRGBA(*bufp, surf.format, &(*col)[0], &(*col)[1], &(*col)[2],
&(*col)[3]);
}

struct rgb {
ubyte[3] values;
rgb opCat(rgb other) {
rgb res;
foreach (id, ref v; res.values) v=(values[id]+other.values[id])/2;
return res;
}
bool opEquals(rgb r) {
return values == r.values;
}
}

void putpixel(SDL_Surface *surf, int x, int y, rgb c) {
if ( (x<0) || (y<0) || (x!<surf.w) || (y!<surf.h) ) return;
putpixel32(surf, x, y, [c.values[0], c.values[1], c.values[2], 0]);
}

const rgb White={[255, 255, 255]};
const rgb Black={[0, 0, 0]};
const rgb Red={[255, 0, 0]};
const rgb Green={[0, 255, 0]};
const rgb Blue={[0, 0, 255]};
rgb color=White;
rgb back=Black;

template failfind(U, T...) {
static if (T.length)
static if (is(T[0] == U)) static assert(false, "Duplicate
"~U.stringof~" found!");
else const bool failfind=failfind!(U, T[1..\$]);
else
const bool failfind=true;
}

template select(U, T...) {
static if(T.length)
static if (is(U == T[0])) { static if (failfind!(U, T[1..\$])) { };
const int select = 0; }
else
static if (select!(U, T[1..\$]) != -1)
const int select = 1 + select!(U, T[1..\$]);
else
const int select = -1;
else
const int select = -1;
}

typedef rgb back_rgb;
back_rgb Back(rgb r) { return cast(back_rgb) r; }
back_rgb Back() { return cast(back_rgb) back; }
typedef rgb box_rgb;
box_rgb Box(rgb r) { return cast(box_rgb) r; }
box_rgb Box() { return cast(box_rgb) color; }
alias Back Fill;

void execParams(T...)(T params) {
const int col=select!(rgb, T);
static if (col != -1) color=params[col];
const int bcol=select!(back_rgb, T);
static if (bcol != -1) back=cast(rgb) params[bcol];
const int boxcol=select!(box_rgb, T);
static if (boxcol != -1) color=cast(rgb) params[boxcol];
}

void pset(T...)(int x, int y, T params) {
SDL_LockSurface(display);
scope(exit) { SDL_UnlockSurface(display); SDL_Flip(display); }
execParams(params);
putpixel(display, x, y, color);
}

rgb pget(int x, int y) {
SDL_LockSurface(display);
scope(exit) SDL_UnlockSurface(display);
ubyte[4] c;
getpixel32(display, x, y, &c);
rgb res; res.values[]=c[0..3]; return res;
}

void swap(T)(ref T a, ref T b) { T c=a; a=b; b=c; }

import std.math: abs;
void bresenham(bool countUp=true, bool steep=false)(int x0, int y0, int
x1, int y1) {
auto deltax = x1 - x0, deltay = y1 - y0;
static if (steep) {
auto Δerror = cast(float)deltax / cast(float)deltay;
auto var2 = x0;
const string name="y";
} else {
auto Δerror = cast(float)deltay / cast(float)deltax;
auto var2 = y0;
const string name="x";
}
auto error = 0f;
for (auto var1 = mixin(name~'0'); var1 <= mixin(name~'1'); ++var1) {
static if (steep) putpixel(display, var2, var1, color);
else putpixel(display, var1, var2, color);
error += Δerror;
if (abs(error) >= 1f) { static if (countUp) { var2++; error -= 1f; }
else { var2--; error += 1f; }}
}
}

T max(T)(T a, T b) { return a>b?a:b; }
T min(T)(T a, T b) { return a<b?a:b; }

void line(T...)(int x0, int y0, int x1, int y1, T p) {
execParams(p);
static if (select!(back_rgb, T)!=-1) {
SDL_LockSurface(display);
scope(exit) { SDL_UnlockSurface(display); SDL_Flip(display); }
auto xend=max(x0, x1);
for (int x=min(x0, x1); x<=xend; ++x) {
auto yend=max(y0, y1);
for (int y=min(y0, y1); y<=yend; ++y) {
putpixel(display, x, y, back);
}
}
}
static if (select!(box_rgb, T)!=-1) {
line(x0, y0, x1, y0);
line(x1, y0, x1, y1);
line(x1, y1, x0, y1);
line(x0, y1, x0, y0);
}
static if (select!(box_rgb, T)+select!(back_rgb, T)==-2) {
SDL_LockSurface(display);
scope(exit) { SDL_UnlockSurface(display); SDL_Flip(display); }
bool steep = abs(y1 - y0) > abs(x1 - x0);
void turn() { swap(x0, x1); swap(y0, y1); }
if (steep) { if (y1 < y0) turn; }
else { if (x1 < x0) turn; }
bool stepUp=steep ? (x0 < x1) : (y0 < y1);
if (steep) {
if (stepUp) bresenham!(true, true)(x0, y0, x1, y1);
else bresenham!(false, true)(x0, y0, x1, y1);
} else {
if (stepUp) bresenham!(true, false)(x0, y0, x1, y1);
else bresenham!(false, false)(x0, y0, x1, y1);
}
}
}

import std.math;
real sin45;
static this() { sin45=sqrt(0.5); }
void circle(T...)(int x, int y, int radius, T t) {
SDL_LockSurface(display);
scope(exit) { SDL_UnlockSurface(display); SDL_Flip(display); }
execParams(t);
auto ratio=1f;
static if (T.length && is(T[0]: int)) { ratio=(radius*1f)/t[0];
real sin45el=sqrt(1f/(ratio*ratio*ratio*ratio+ratio*ratio))*ratio;
auto ri=1f/ratio;
real sin45el2=sqrt(1f/(ri*ri*ri*ri+ri*ri))*ri;
//writefln("Sin45 ", sin45, " Sin45 Elliptic ", sin45el, " and ",
sin45el2);
static if (select!(back_rgb, T) != -1) {
for (int i=0; i<nradius; ++i) {
for (int lx=x-j; lx<=x+j; ++lx) putpixel(display, lx, y+i, back);
for (int lx=x-j; lx<=x+j; ++lx) putpixel(display, lx, y-i, back);
}
}
static if ((select!(rgb, T) != -1) || (select!(back_rgb, T) == -1)) {
for (int i=0; i<nradius*sin45el; ++i) {
putpixel(display, x+j, y-i, color);
putpixel(display, x+j, y+i, color);
putpixel(display, x-j, y-i, color);
putpixel(display, x-j, y+i, color);
}
for (int i=0; i<radius*sin45el2; ++i) {
putpixel(display, x+i, y-j, color);
putpixel(display, x+i, y+j, color);
putpixel(display, x-i, y-j, color);
putpixel(display, x-i, y+j, color);
}
}
}

struct floodfill_node {
int x, y;
static floodfill_node opCall(int x, int y) {
floodfill_node res;
res.x=x; res.y=y;
return res;
}
}

/// taken from wikipedia
void paint(T...)(int x, int y, T t) {
SDL_LockSurface(display);
scope(exit) { SDL_UnlockSurface(display); SDL_Flip(display); }
execParams(t);
bool border=true;
if (select!(back_rgb, T) == -1) {
back=pget(x, y);
border=false;
}
bool check(rgb r) {
if (border) return (r != back) && (r != color);
else return r == back;
}
if (back == color) throw new Exception("Having identical backgrounds
and foregrounds will severely mess up floodfill.");
alias floodfill_node node;
node[] queue;
queue ~= node(x, y);
size_t count=0;
while (count<queue.length) {
scope(exit) count++;
with (queue[count]) {
if (check(pget(x, y))) {
int w=x, e=x;
if (w<display.w) do w++; while ((w<display.w) && check(pget(w, y)));
if (e>=0) do e--; while (e>=0 && check(pget(e, y)));
//SDL_Flip(display);
for (int i=e+1; i<w; ++i) {
putpixel(display, i, y, color);
if (y && check(pget(i, y-1)) && ((i==w-1)||!check(pget(i+1,
y-1)))) queue ~= node(i, y-1);
if ((y < display.h-1) && check(pget(i, y+1)) &&
((i==w-1)||!check(pget(i+1, y+1)))) queue ~= node(i, y+1);
}
}
}
}
}

void screen(size_t w, size_t h) {
display = SDL_SetVideoMode(w, h, 32, SDL_SWSURFACE);
}

void cls() { line(0, 0, display.w-1, display.h-1, Fill=Black); }

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFG8aoCpEPJRr05fBERAk07AJwLkmvRw87myeS808x2lHIJaIRTCQCgi54S
5me3rPlYyt3Q8jZclxmDWB4=
=fZF2
-----END PGP SIGNATURE-----
```
Sep 19 2007
```Downs wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Here's some simple graphics primitives on top of SDL: pset, pget, line,
circle and bucket-fill (paint).
It's modelled after QBasic, which I still think has the most intuitive,
easy to use graphics API I've seen so far.

The code is placed in the public domain.

On that account, does anybody know a good algorithm for drawing
ellipses? The one I came up with is kind of broken for ratios around or
over 1:5 ...

this to scrapple.
```
Sep 19 2007
Downs <default_357-line yahoo.de> writes:
```-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

BCS wrote:
Downs wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Here's some simple graphics primitives on top of SDL: pset, pget, line,
circle and bucket-fill (paint).
It's modelled after QBasic, which I still think has the most intuitive,
easy to use graphics API I've seen so far.

The code is placed in the public domain.

On that account, does anybody know a good algorithm for drawing
ellipses? The one I came up with is kind of broken for ratios around or
over 1:5 ...

this to scrapple.

--downs aka FeepingCreature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFG8blxpEPJRr05fBERAgRnAKCXSL58y/sFUTTYz/MoI+T7Gy5UwgCeOzLO
ba8tmGSW9vo7J0ZYnxn5RLo=
=nbQK
-----END PGP SIGNATURE-----
```
Sep 19 2007
```Reply to Downs,

--downs aka FeepingCreature

Now you tell me :-b
```
Sep 19 2007
Bill Baxter <dnewsgroup billbaxter.com> writes:
```Downs wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Here's some simple graphics primitives on top of SDL: pset, pget, line,
circle and bucket-fill (paint).
It's modelled after QBasic, which I still think has the most intuitive,
easy to use graphics API I've seen so far.

The code is placed in the public domain.

On that account, does anybody know a good algorithm for drawing
ellipses? The one I came up with is kind of broken for ratios around or
over 1:5 ...

You can do a bresenham-style ellipse renderer.
http://homepage.smc.edu/kennedy_john/BELIPSE.PDF
```
Sep 19 2007
Downs <default_357-line yahoo.de> writes:
```-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Bill Baxter wrote:
Downs wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Here's some simple graphics primitives on top of SDL: pset, pget, line,
circle and bucket-fill (paint).
It's modelled after QBasic, which I still think has the most intuitive,
easy to use graphics API I've seen so far.

The code is placed in the public domain.

On that account, does anybody know a good algorithm for drawing
ellipses? The one I came up with is kind of broken for ratios around or
over 1:5 ...

You can do a bresenham-style ellipse renderer.
http://homepage.smc.edu/kennedy_john/BELIPSE.PDF

Thanks. I did that:

<qd.d>
import std.stdio, std.c.time;

void main() {
screen(640, 480);
pset(10, 10);
line(0, 0, 100, 100, Box, Back(Red~Black));
for (int i=0; i<=100; i+=10) {
line(i, 0, 100-i, 100);
line(0, i, 100, 100-i);
}
circle(100, 100, 50, 15, White~Black, Fill=White~Black);
paint(200, 200, Red, Back=White);
circle(100, 100, 50, 15, White);
paint(200, 200, Black);
pset(10, 11); pset(10, 11, Black);
pset(10, 10);
sleep(5);
}

extern(C) {
struct SDL_Rect {
short x, y;
ushort w, h;
}
struct SDL_PixelFormat {
//SDL_Palette *palette;
void *palette;
ubyte BitsPerPixel, BytesPerPixel, Rloss, Gloss, Bloss, Aloss,
Rshift, Gshift, Bshift, Ashift;
}
struct SDL_Surface {
uint flags;
SDL_PixelFormat *format;
int w, h;
ushort pitch;
void *pixels;
int offset;
void *hwdata;
SDL_Rect clip_rect;
uint unused;
uint locked;
void *map;
uint format_version;
int refcount;
}
uint SDL_MapRGBA(SDL_PixelFormat *format, ubyte r, ubyte g, ubyte b,
ubyte a);
void SDL_GetRGBA(uint pixel, SDL_PixelFormat *fmt, ubyte *r, ubyte *g,
ubyte *b, ubyte *a);
int SDL_LockSurface(SDL_Surface *);
void SDL_UnlockSurface(SDL_Surface *);
SDL_Surface * SDL_SetVideoMode(int width, int height, int bpp, uint
flags);
int SDL_Flip(SDL_Surface *);
const uint SDL_SWSURFACE=0;
const uint SDL_HWSURFACE=1;
const uint SDL_DOUBLEBUF=0x40000000;
const uint SDL_FULLSCREEN=0x80000000;
}

SDL_Surface *display;

void putpixel32(SDL_Surface *surf, int x, int y, ubyte[4] col) {
uint *bufp = cast(uint *)surf.pixels + y*surf.pitch/4 + x;
*bufp = SDL_MapRGBA(surf.format, col[0], col[1], col[2], col[3]);
}

void getpixel32(SDL_Surface *surf, int x, int y, ubyte[4] *col) {
uint *bufp = cast(uint *)surf.pixels + y*surf.pitch/4 + x;
SDL_GetRGBA(*bufp, surf.format, &(*col)[0], &(*col)[1], &(*col)[2],
&(*col)[3]);
}

struct rgb {
ubyte[3] values;
rgb opCat(rgb other) {
rgb res;
foreach (id, ref v; res.values) v=(values[id]+other.values[id])/2;
return res;
}
bool opEquals(rgb r) {
return values == r.values;
}
}

void putpixel(SDL_Surface *surf, int x, int y, rgb c) {
if ( (x<0) || (y<0) || (x!<surf.w) || (y!<surf.h) ) return;
putpixel32(surf, x, y, [c.values[0], c.values[1], c.values[2], 0]);
}

const rgb White={[255, 255, 255]};
const rgb Black={[0, 0, 0]};
const rgb Red={[255, 0, 0]};
const rgb Green={[0, 255, 0]};
const rgb Blue={[0, 0, 255]};
rgb color=White;
rgb back=Black;

template failfind(U, T...) {
static if (T.length)
static if (is(T[0] == U)) static assert(false, "Duplicate
"~U.stringof~" found!");
else const bool failfind=failfind!(U, T[1..\$]);
else
const bool failfind=true;
}

template select(U, T...) {
static if(T.length)
static if (is(U == T[0])) { static if (failfind!(U, T[1..\$])) { };
const int select = 0; }
else
static if (select!(U, T[1..\$]) != -1)
const int select = 1 + select!(U, T[1..\$]);
else
const int select = -1;
else
const int select = -1;
}

typedef rgb back_rgb;
back_rgb Back(rgb r) { return cast(back_rgb) r; }
back_rgb Back() { return cast(back_rgb) back; }
typedef rgb box_rgb;
box_rgb Box(rgb r) { return cast(box_rgb) r; }
box_rgb Box() { return cast(box_rgb) color; }
alias Back Fill;

void execParams(T...)(T params) {
const int col=select!(rgb, T);
static if (col != -1) color=params[col];
const int bcol=select!(back_rgb, T);
static if (bcol != -1) back=cast(rgb) params[bcol];
const int boxcol=select!(box_rgb, T);
static if (boxcol != -1) color=cast(rgb) params[boxcol];
}

void pset(T...)(int x, int y, T params) {
SDL_LockSurface(display);
scope(exit) { SDL_UnlockSurface(display); SDL_Flip(display); }
execParams(params);
putpixel(display, x, y, color);
}

rgb pget(int x, int y) {
SDL_LockSurface(display);
scope(exit) SDL_UnlockSurface(display);
ubyte[4] c;
getpixel32(display, x, y, &c);
rgb res; res.values[]=c[0..3]; return res;
}

void swap(T)(ref T a, ref T b) { T c=a; a=b; b=c; }

import std.math: abs;
void bresenham(bool countUp=true, bool steep=false)(int x0, int y0, int
x1, int y1) {
auto deltax = x1 - x0, deltay = y1 - y0;
static if (steep) {
auto Δerror = cast(float)deltax / cast(float)deltay;
auto var2 = x0;
const string name="y";
} else {
auto Δerror = cast(float)deltay / cast(float)deltax;
auto var2 = y0;
const string name="x";
}
auto error = 0f;
for (auto var1 = mixin(name~'0'); var1 <= mixin(name~'1'); ++var1) {
static if (steep) putpixel(display, var2, var1, color);
else putpixel(display, var1, var2, color);
error += Δerror;
if (abs(error) >= 1f) { static if (countUp) { var2++; error -= 1f; }
else { var2--; error += 1f; }}
}
}

T max(T)(T a, T b) { return a>b?a:b; }
T min(T)(T a, T b) { return a<b?a:b; }

void line(T...)(int x0, int y0, int x1, int y1, T p) {
execParams(p);
static if (select!(back_rgb, T)!=-1) {
SDL_LockSurface(display);
scope(exit) { SDL_UnlockSurface(display); SDL_Flip(display); }
auto xend=max(x0, x1);
for (int x=min(x0, x1); x<=xend; ++x) {
auto yend=max(y0, y1);
for (int y=min(y0, y1); y<=yend; ++y) {
putpixel(display, x, y, back);
}
}
}
static if (select!(box_rgb, T)!=-1) {
line(x0, y0, x1, y0);
line(x1, y0, x1, y1);
line(x1, y1, x0, y1);
line(x0, y1, x0, y0);
}
static if (select!(box_rgb, T)+select!(back_rgb, T)==-2) {
SDL_LockSurface(display);
scope(exit) { SDL_UnlockSurface(display); SDL_Flip(display); }
bool steep = abs(y1 - y0) > abs(x1 - x0);
void turn() { swap(x0, x1); swap(y0, y1); }
if (steep) { if (y1 < y0) turn; }
else { if (x1 < x0) turn; }
bool stepUp=steep ? (x0 < x1) : (y0 < y1);
if (steep) {
if (stepUp) bresenham!(true, true)(x0, y0, x1, y1);
else bresenham!(false, true)(x0, y0, x1, y1);
} else {
if (stepUp) bresenham!(true, false)(x0, y0, x1, y1);
else bresenham!(false, false)(x0, y0, x1, y1);
}
}
}

import std.math: sqrt;

template circle_bresenham_pass(bool first) {
const string xy=(first?"x":"y");
const string yx=(first?"y":"x");
const string str="
auto error=0;
while (stopx"~(first?">=":"<=")~"stopy) {
putpixel(display, cx+x, cy+y, color);
putpixel(display, cx+x, cy-y, color);
putpixel(display, cx-x, cy+y, color);
putpixel(display, cx-x, cy-y, color);
"~yx~"++;
stop"~yx~"+="~xy~"2square;
error+="~yx~"change;
"~yx~"change+="~xy~"2square;
if ((2*error+"~xy~"change)>0) {
--"~xy~";
stop"~xy~"-="~yx~"2square;
error+="~xy~"change;
"~xy~"change+="~yx~"2square;
}
}
";
}

void circle(T...)(int cx, int cy, int xradius, T t) {
SDL_LockSurface(display);
scope(exit) { SDL_UnlockSurface(display); SDL_Flip(display); }
execParams(t);
static if (T.length && is(T[0]: int)) yradius=t[0];
static if (select!(back_rgb, T) != -1) {
for (int i=0; i<=yradius; ++i) {
for (int lx=cx-j; lx<=cx+j; ++lx) putpixel(display, lx, cy+i, back);
for (int lx=cx-j; lx<=cx+j; ++lx) putpixel(display, lx, cy-i, back);
}
}
{ mixin(circle_bresenham_pass!(true).str); }
{ mixin(circle_bresenham_pass!(false).str); }
}

struct floodfill_node {
int x, y;
static floodfill_node opCall(int x, int y) {
floodfill_node res;
res.x=x; res.y=y;
return res;
}
}

void paint(T...)(int x, int y, T t) {
SDL_LockSurface(display);
scope(exit) { SDL_UnlockSurface(display); SDL_Flip(display); }
execParams(t);
bool border=true;
if (select!(back_rgb, T) == -1) {
back=pget(x, y);
border=false;
}
bool check(rgb r) {
if (border) return (r != back) && (r != color);
else return r == back;
}
if (back == color) throw new Exception("Having identical backgrounds
and foregrounds will severely mess up floodfill.");
alias floodfill_node node;
node[] queue;
queue ~= node(x, y);
size_t count=0;
while (count<queue.length) {
scope(exit) count++;
with (queue[count]) {
if (check(pget(x, y))) {
int w=x, e=x;
if (w<display.w) do w++; while ((w<display.w) && check(pget(w, y)));
if (e>=0) do e--; while (e>=0 && check(pget(e, y)));
//SDL_Flip(display);
for (int i=e+1; i<w; ++i) {
putpixel(display, i, y, color);
if (y && check(pget(i, y-1)) && ((i==w-1)||!check(pget(i+1,
y-1)))) queue ~= node(i, y-1);
if ((y < display.h-1) && check(pget(i, y+1)) &&
((i==w-1)||!check(pget(i+1, y+1)))) queue ~= node(i, y+1);
}
}
}
}
}

void screen(size_t w, size_t h) {
display = SDL_SetVideoMode(w, h, 32, SDL_SWSURFACE);
}

void cls() { line(0, 0, display.w-1, display.h-1, Fill=Black); }

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFG8bjhpEPJRr05fBERAv8DAJ9J45JyC3GG1/v83dfTXmwpUZvDUgCeIAZ1
Gvl4fkR8BfKgalAcWz5qGxg=
=KXAL
-----END PGP SIGNATURE-----
```
Sep 19 2007