Beispiel #1
0
/* fli_read:
 *  Helper function to get a block of data from the FLI, which can read 
 *  from disk or a copy of the FLI held in memory. If buf is set, that is 
 *  where it stores the data, otherwise it uses the scratch buffer. Returns 
 *  a pointer to the data, or NULL on error.
 */
static void *fli_read(void *buf, int size)
{
   int result;

   if (fli_mem_data) {
      if (buf)
	 memcpy(buf, (char *)fli_mem_data+fli_mem_pos, size);
      else
	 buf = (char *)fli_mem_data+fli_mem_pos;

      fli_mem_pos += size;
   }
   else {
      if (!buf) {
	 _grow_scratch_mem(size);
	 buf = _scratch_mem;
      }

      result = pack_fread(buf, size, fli_file);
      if (result != size)
	 return NULL;
   }

   return buf;
}
Beispiel #2
0
/* polygon:
 *  Draws a filled polygon with an arbitrary number of corners. Pass the
 *  number of vertices, then an array containing a series of x, y points
 *  (a total of vertices*2 values).
 */
void _soft_polygon(BITMAP *bmp, int vertices, AL_CONST int *points, int color)
{
   int c;
   int top = INT_MAX;
   int bottom = INT_MIN;
   AL_CONST int *i1, *i2;
   POLYGON_EDGE *edge, *next_edge;
   POLYGON_EDGE *active_edges = NULL;
   POLYGON_EDGE *inactive_edges = NULL;
   ASSERT(bmp);

   /* allocate some space and fill the edge table */
   _grow_scratch_mem(sizeof(POLYGON_EDGE) * vertices);

   edge = (POLYGON_EDGE *)_scratch_mem;
   i1 = points;
   i2 = points + (vertices-1) * 2;

   for (c=0; c<vertices; c++) {
      fill_edge_structure(edge, i1, i2);

      if (edge->bottom >= edge->top) {

         if (edge->top < top)
            top = edge->top;

         if (edge->bottom > bottom)
            bottom = edge->bottom;

         inactive_edges = _add_edge(inactive_edges, edge, FALSE);
         edge++;
      }

      i2 = i1;
      i1 += 2;
   }

   if (bottom >= bmp->cb)
      bottom = bmp->cb-1;

   acquire_bitmap(bmp);

   /* for each scanline in the polygon... */
   for (c=top; c<=bottom; c++) {
      int hid = 0;
      int b1 = 0;
      int e1 = 0;
      int up = 0;
      int draw = 0;
      int e;

      /* check for newly active edges */
      edge = inactive_edges;
      while ((edge) && (edge->top == c)) {
         next_edge = edge->next;
         inactive_edges = _remove_edge(inactive_edges, edge);
         active_edges = _add_edge(active_edges, edge, TRUE);
         edge = next_edge;
      }

      /* draw horizontal line segments */
      edge = active_edges;
      while (edge) {
         e = edge->w;
         if (edge->bottom != c) {
            up = 1 - up;
         }
         else {
            e = edge->w >> 1;
         }

         if (edge->top == c) {
            e = edge->w >> 1;
         }

         if ((draw < 1) && (up >= 1)) {
            b1 = (edge->x + e) >> POLYGON_FIX_SHIFT;
         }
         else if (draw >= 1) {
Beispiel #3
0
/* flooder:
 *  Fills a horizontal line around the specified position, and adds it
 *  to the list of drawn segments. Returns the first x coordinate after
 *  the part of the line which it has dealt with.
 */
static int flooder (Image *image, int x, int y,
                    int src_color, int tolerance, void *data, AlgoHLine proc)
{
  FLOODED_LINE *p;
  int left = 0, right = 0;
  int c;

  switch (image->getPixelFormat()) {

    case IMAGE_RGB:
      {
        uint32_t* address = ((uint32_t**)image->line)[y];

        /* check start pixel */
        if (!color_equal_32((int)*(address+x), src_color, tolerance))
          return x+1;

        /* work left from starting point */
        for (left=x-1; left>=0; left--) {
          if (!color_equal_32((int)*(address+left), src_color, tolerance))
            break;
        }

        /* work right from starting point */
        for (right=x+1; right<image->w; right++) {
          if (!color_equal_32((int)*(address+right), src_color, tolerance))
            break;
        }
      }
      break;

    case IMAGE_GRAYSCALE:
      {
        uint16_t* address = ((uint16_t**)image->line)[y];

        /* check start pixel */
        if (!color_equal_16((int)*(address+x), src_color, tolerance))
          return x+1;

        /* work left from starting point */
        for (left=x-1; left>=0; left--) {
          if (!color_equal_16((int)*(address+left), src_color, tolerance))
            break;
        }

        /* work right from starting point */
        for (right=x+1; right<image->w; right++) {
          if (!color_equal_16((int)*(address+right), src_color, tolerance))
            break;
        }
      }
      break;

    case IMAGE_INDEXED:
      {
        uint8_t* address = ((uint8_t**)image->line)[y];

        /* check start pixel */
        if (!color_equal_8((int)*(address+x), src_color, tolerance))
          return x+1;

        /* work left from starting point */
        for (left=x-1; left>=0; left--) {
          if (!color_equal_8((int)*(address+left), src_color, tolerance))
            break;
        }

        /* work right from starting point */
        for (right=x+1; right<image->w; right++) {
          if (!color_equal_8((int)*(address+right), src_color, tolerance))
            break;
        }
      }
      break;

    default:
      /* check start pixel */
      if (image_getpixel(image, x, y) != src_color)
        return x+1;

      /* work left from starting point */
      for (left=x-1; left>=0; left--) {
        if (image_getpixel(image, left, y) != src_color)
          break;
      }

      /* work right from starting point */
      for (right=x+1; right<image->w; right++) {
        if (image_getpixel(image, right, y) != src_color)
          break;
      }
      break;
  }

  left++;
  right--;

  /* draw the line */
  (*proc)(left, y, right, data);

  /* store it in the list of flooded segments */
  c = y;
  p = FLOOD_LINE(c);

  if (p->flags) {
    while (p->next) {
      c = p->next;
      p = FLOOD_LINE(c);
    }

    p->next = c = flood_count++;
    _grow_scratch_mem(sizeof(FLOODED_LINE) * flood_count);
    p = FLOOD_LINE(c);
  }

  p->flags = FLOOD_IN_USE;
  p->lpos = left;
  p->rpos = right;
  p->y = y;
  p->next = 0;

  if (y > 0)
    p->flags |= FLOOD_TODO_ABOVE;

  if (y+1 < image->h)
    p->flags |= FLOOD_TODO_BELOW;

  return right+2;
}
Beispiel #4
0
/* floodfill:
 *  Fills an enclosed area (starting at point x, y) with the specified color.
 */
void algo_floodfill(Image* image, int x, int y, int tolerance, void *data, AlgoHLine proc)
{
  int src_color;
  int c, done;
  FLOODED_LINE *p;

  /* make sure we have a valid starting point */
  if ((x < 0) || (x >= image->w) ||
      (y < 0) || (y >= image->h))
    return;

  /* what color to replace? */
  src_color = image_getpixel (image, x, y);

  /* set up the list of flooded segments */
  _grow_scratch_mem(sizeof(FLOODED_LINE) * image->h);
  flood_count = image->h;
  p = (FLOODED_LINE*)_scratch_mem;
  for (c=0; c<flood_count; c++) {
    p[c].flags = 0;
    p[c].lpos = SHRT_MAX;
    p[c].rpos = SHRT_MIN;
    p[c].y = y;
    p[c].next = 0;
  }

  /* start up the flood algorithm */
  flooder(image, x, y, src_color, tolerance, data, proc);

  /* continue as long as there are some segments still to test */
  do {
    done = true;

    /* for each line on the screen */
    for (c=0; c<flood_count; c++) {

      p = FLOOD_LINE(c);

      /* check below the segment? */
      if (p->flags & FLOOD_TODO_BELOW) {
        p->flags &= ~FLOOD_TODO_BELOW;
        if (check_flood_line(image, p->y+1, p->lpos, p->rpos,
                             src_color, tolerance, data, proc)) {
          done = false;
          p = FLOOD_LINE(c);
        }
      }

      /* check above the segment? */
      if (p->flags & FLOOD_TODO_ABOVE) {
        p->flags &= ~FLOOD_TODO_ABOVE;
        if (check_flood_line(image, p->y-1, p->lpos, p->rpos,
                             src_color, tolerance, data, proc)) {
          done = false;
          /* special case shortcut for going backwards */
          if ((c < image->h) && (c > 0))
            c -= 2;
        }
      }
    }
  } while (!done);
}