How about this? It would compile if it had a main()...
I didn't go so far as to test it in OpenGL, but it probably works.
typedef struct
{
unsigned char r, g, b;
} RGB;
typedef struct
{
unsigned int width, height;
RGB *data;
} canvas;
typedef struct
{
unsigned int first;
unsigned int next;
unsigned int max;
int *data;
} queue;
int init_queue(queue *Queue, unsigned int initial_size)
{
if(!Queue || initial_size < 1)
return 0;
Queue->first = 0;
Queue->next = 0;
Queue->max = initial_size;
Queue->data = malloc(initial_size*sizeof(unsigned int)*2);
if(!Queue->data)
return 0;
return 1;
}
void queue_append(queue *q, int x, int y)
{
if(q->next < q->max)
{
q->data[q->next*2] = x;
q->data[q->next*2+1] = y;
q->next++;
}
else
{
//realloc, unfortunately, does not have the ability to do partial copies...
int *new = malloc(q->max*2*sizeof(unsigned int)*2);
if(!new)
{
if(q->first > 0)
{
memmove(q->data, &(q->data[q->first*2]), (q->max-q->first)*2*sizeof(int));
q->next -= q->first;
q->first = 0;
}
else return;//cannot make space. What should happen depends on the program, here we will ignore the pixel and hope to get it later.
}
else
{
memcpy(new, &(q->data[q->first*2]), (q->max-q->first)*2*sizeof(int));
free(q->data);
q->data = new;
q->next -= q->first;
q->first = 0;
q->max *= 2;
}
q->data[q->next*2] = x;
q->data[q->next*2+1] = y;
q->next++;
}
}
int in_queue(queue *q, int x, int y)
{
if(!q || x<0 || y<0)
return 0;
int i;
for(i=q->first;i<q->next;i++)
{
if(q->data[i*2]==x && q->data[i*2+1]==y)
return 1;
}
return 0;
}
int queue_next(queue *q, int *x, int *y)
{
if(q->first == q->next)
return 0;
*x = q->data[q->first*2];
*y = q->data[q->first*2+1];
q->first++;
if(q->first == q->next)
q->first=q->next=0;
return 1;
}
int in_bounds(int x, int y, canvas *c)
{
if(!c || x < 0 || y < 0 || x >= c->width || y >= c->height)
return 0;
else
return 1;
}
RGB get_colour(int x, int y, canvas *c)
{
return c->data[y*c->width+x];
}
int is_colour(int x, int y, canvas *c, RGB *colour)
{
return memcmp(&(c->data[y*c->width+x]), colour, sizeof(RGB)) == 0;
}
void set_colour(int x, int y, canvas *c, RGB *new)
{
c->data[y*c->width+x] = *new;
}
void floodfill_add(queue *q, int x, int y, canvas *c, RGB *target)
{
if(in_bounds(x, y, c) && is_colour(x, y, c, target) && !in_queue(q, x, y))
queue_append(q, x, y);
}
void floodfill(int x, int y, canvas *Canvas, RGB *newcolour)
{
//Check first for bad pointers, then bad locations.
if(!Canvas || !newcolour || !Canvas->data || !in_bounds(x, y, Canvas))
return;
queue Queue;
if(!init_queue(&Queue, 512))
return;
RGB target_colour = get_colour(x, y, Canvas);
queue_append(&Queue, x, y);
while(queue_next(&Queue, &x, &y))
{
set_colour(x, y, Canvas, newcolour);
floodfill_add(&Queue, x+1, y, Canvas, &target_colour);
floodfill_add(&Queue, x-1, y, Canvas, &target_colour);
floodfill_add(&Queue, x, y+1, Canvas, &target_colour);
floodfill_add(&Queue, x, y-1, Canvas, &target_colour);
}
}