Beispiel #1
0
/* qsort comparison function to sort by luminance */
int compare_luminance(const void *a, const void *b) {
  pgcolor color_a = *(pgcolor *)a;
  pgcolor color_b = *(pgcolor *)b;
  int lum_a = getred(color_a)*30 + getgreen(color_a)*59 + getblue(color_a)*11;
  int lum_b = getred(color_b)*30 + getgreen(color_b)*59 + getblue(color_b)*11;
  if (lum_a < lum_b)
    return -1;
  if (lum_a > lum_b)
    return 1;
  return 0;
}
Beispiel #2
0
void directfb_pixel(hwrbitmap dest,s16 x,s16 y,hwrcolor c,s16 lgop) {
   DFBResult err;
   DFBSurfaceDrawingFlags flags;
   if (dest) {
      def_pixel(dest,x,y,c,lgop);
      return;
   }
#ifdef DEBUG_VIDEO
   if (!directfb)
     printf("Directfb driver: pixel at %d,%d set when uninitialized\n",x,y);
   if (x<0 || y<0 || (x>=vid->xres) || (y>=vid->yres))
     printf("Directfb driver: pixel out of bounds at %d,%d\n",x,y);
#endif
   err = primary->SetColor (primary, getred(c), getgreen(c), getblue(c), h_getalpha(c));
   dfb_errcheck_die;
   // FIXME: should support all lgops
   switch (lgop) {
   case PG_LGOP_NONE:
     flags = DSDRAW_NOFX;
     break;
   case PG_LGOP_ALPHA:
     flags = DSDRAW_BLEND;
     break;
   default:
     flags = DSDRAW_NOFX;
     printf("ignoring lgop: %d\n", lgop);
   }
   err = primary->SetDrawingFlags (primary, flags);
   dfb_errcheck_die;
   err = DrawPixel (primary, x, y);
   dfb_errcheck_die;
}
Beispiel #3
0
void directfb_alpha_charblit(hwrbitmap dest, u8 *chardat, s16 x, s16 y, s16 w, s16 h,
			     int char_pitch, u8 *gammatable, s16 angle, hwrcolor c,
			     struct pgquad *clip, s16 lgop) {
  int i,j,xp,yp;
  u8 *l;
  u8 red, green, blue, alpha;
  DFBResult err;
  DFBSurfaceDrawingFlags flags;

  if (dest) {
    def_alpha_charblit(dest, chardat, x, y, w, h, char_pitch, gammatable, angle, c, clip, lgop);
    return;
  }

  // FIXME: we're effectively ignoring the lgop
  flags = DSDRAW_BLEND;
  err = primary->SetDrawingFlags (primary, flags);
  dfb_errcheck_die;

  /* little stupid optimization */
  red = getred(c); green = getgreen(c); blue = getblue(c);

  for (j=0;j<h;j++,chardat+=char_pitch)
    for (i=0,l=chardat;i<w;i++,l++) {

      switch (angle) {
      case 0:
	xp = x+i;
	yp = y+j;
	break;
      case 90:
	xp = x+j;
	yp = y-i;
	break;
      case 180:
	xp = x-i;
	yp = y-j;
	break;
      case 270:
	xp = x-j;
	yp = y+i;
	break;
      }

      if (clip)
	if (xp < clip->x1 || xp > clip->x2 ||
	    yp < clip->y1 || yp > clip->y2)
	  continue;
      
      if (gammatable)
	alpha = gammatable[*l];
      else
	alpha = *l;

      err = primary->SetColor (primary, red, green, blue, alpha);
      dfb_errcheck_die;
      err = DrawPixel (primary, xp, yp);
      dfb_errcheck_die;
    }
}
Beispiel #4
0
void
alter_colors (iImage * source, int o_r, int o_g, int o_b, int r2, int g2,
	      int b2)
{
  int i, j;
  int r, g, b;
//float bright;


//int red_ratio;
//int green_ratio;
//int blue_ratio;




  for (i = 0; i < source->GetWidth (); i++)
    for (j = 0; j < source->GetHeight (); j++)
      {
	r = getred (source, i, j);
	g = getgreen (source, i, j);
	b = getblue (source, i, j);

//bright=sqrt(r*r+g*g+b*b);

	setred (source, i, j, (int)(r2 * sqrt (o_r * r + o_g * g + o_b * b) / 255)  );
	setgreen (source, i, j,(int)(
		  g2 * sqrt (o_r * r + o_g * g + o_b * b) / 255));
   	setblue (source, i, j,(int)(b2 * sqrt (o_r * r + o_g * g + o_b * b) / 255));
      }

}
Beispiel #5
0
	//sux
void
invert_brightness (iImage * source)
{
  int i, j;
  int r, g, b;
//float bright;

  for (i = 0; i < source->GetWidth (); i++)
    for (j = 0; j < source->GetHeight (); j++)
      {
	r = getred (source, i, j);
	g = getgreen (source, i, j);
	b = getblue (source, i, j);
	r = 255 - r;
	g = 255 - g;
	b = 255 - b;

	setred (source, i, j, r);
	setgreen (source, i, j, g);
	setblue (source, i, j, b);


      }


}
Beispiel #6
0
inline void gl_color(hwrcolor c) {
  if (c & PGCF_ALPHA) {
    /* Convert 7-bit alpha channel to 8-bit */
    glColor4ub(getred(c),
	       getgreen(c),
	       getblue(c),
	       c>>23 | ((c>>24)&1));
  }
Beispiel #7
0
/* Look up a pgcolor in the palette. Really slow... */
hwrcolor palette_lookup(pgcolor c) {
  /* The downside of custom palettes is that we have to spend a good bit of
   * time looking up the color. Make this a little faster by caching the
   * most recently looked up color, since in image conversion there are usually
   * areas of equal color.
   */
  
  static pgcolor cached_color = 0xFFFFFFFF;  /* An invalid value that we won't get a cache hit on */
  static u8 cached_index = 0;
  int i;
  int distance, d;
  int r,g,b,rd,gd,bd;
  pgcolor pcolor;
  
  if (cached_color == c)
    return cached_index;
  
  /* Since our palette is sorted by luminance, we can handle black and white easily */
  if (c == 0xFFFFFF)
    return 255;
  if (c == 0)
    return 0;
  
  /* Now search for the closest color in RGB space */
  
  distance = 195076;  /* This is one greater than the distance between black and white */
  cached_color = c;
  r = getred(c);
  g = getgreen(c);
  b = getblue(c);
  for (i=0;i<256;i++) {
    pcolor = palette8_custom[i];
    rd = r - getred(pcolor);
    gd = g - getgreen(pcolor);
    bd = b - getblue(pcolor);
    d  = rd*rd + gd*gd + bd*bd;
    if (d < distance) {
      distance = d;
      cached_index = i;
    }
  }
  return cached_index;
}
Beispiel #8
0
hwrcolor def_color_pgtohwr(pgcolor c) {
  if (c & PGCF_ALPHA) {
    /* ARGB conversion, just premultiply the RGB color */
    return mkcolora( getalpha(c),
		     (getred(c)   * getalpha(c)) >> 7,
		     (getgreen(c) * getalpha(c)) >> 7,
		     (getblue(c)  * getalpha(c)) >> 7
		     );
  }
  else if (vid->bpp==0) {
Beispiel #9
0
void
blit_alpha (iImage * source, iImage * dest, int source_startx,
	    int source_starty, int destx, int desty, int source_endx,
	    int source_endy, int range)
{
  int x;
  int y;
//check if its out of range yourself :P
  int r, g, b, a;
  int i, j;

//int r2,g2,b2;
  x = dest->GetWidth ();
  y = dest->GetHeight ();


  if (source_endx + destx - source_startx >= x)
    source_endx = x - destx + source_startx;


  if (source_endy + desty - source_starty >= y)
    source_endy = y - desty + source_starty;


  i = 0;
  j = 0;
  for (x = source_startx; x < source_endx; x++)
    {
      for (y = source_starty; y < source_endy; y++)
	{
	  r = getred (source, x, y);
	  g = getgreen (source, x, y);
	  b = getblue (source, x, y);
	  a = getalpha (source, x, y);


	  if (a - range < 1)
	    {
	    }
	  else
	    {
	      setred (dest, i + destx, j + desty, r);
	      setgreen (dest, i + destx, j + desty, g);
	      setblue (dest, i + destx, j + desty, b);
	    }
	  j++;
	}
      j = 0;
      i++;
    }



}
Beispiel #10
0
void yuv16_422_planar_pixel(hwrbitmap dest,
			      s16 x, s16 y, hwrcolor c,
			      s16 lgop)
{
  struct stdbitmap *dstbit = (struct stdbitmap *) dest;

  if (yuv16_422_planar_is_offscreen(dstbit->bits)) {
    /* we are offscreen */
    def_pixel(dest, x, y, c, lgop);
    return;
  }
  else {
    unsigned long r = getred(c);
    unsigned long g = getgreen(c);
    unsigned long b = getblue(c);
    unsigned long a = getalpha(c);

    size_t offset = (dstbit->pitch)*y + x;
    
    u8 *dst_y  = dstbit->bits + offset;
    u8 *dst_uv = dstbit->bits + yuv16_422_planar_y_plane_size + (offset&~1);

    switch (lgop) {      
    case PG_LGOP_NONE: {
      int y, cb, cr;
      
      yuv16_rgb_shadow_buffer[offset] = c;
      
      /*
       * Alpha is null...We're transparent
       */
      if (!a)
	{
	  y = 0;
	  cb = 0;
	  cr = 0;
	}
      else
	rgb_to_ycbcr(r, g, b, &y, &cb, &cr);
      *dst_y = (char)y;
      *dst_uv++ = (char)cb;
      *dst_uv = (char)cr;
      
      break; 
    }
    
    default:
    /* Not supported yet */
      return;
    }
  }
}
Beispiel #11
0
//the except is where you have a 0...
//if o_r ==0 and o_g>0 and o_b>0 rng=10 no colors with red greater than 10 will be replaced
void
alter_colors_except (iImage * source, int o_r, int o_g, int o_b, int r2,
		     int g2, int b2, int rng)
{

  int i, j;
  int r, g, b;

  int ok;



  for (i = 0; i < source->GetWidth (); i++)
    for (j = 0; j < source->GetHeight (); j++)
      {
	ok = 1;
	r = getred (source, i, j);
	g = getgreen (source, i, j);
	b = getblue (source, i, j);

	if (o_r == 0)
	  if (r > rng)
	    ok = 0;

	if (o_g == 0)
	  if (g > rng)
	    ok = 0;

	if (o_b == 0)
	  if (b > rng)
	    ok = 0;




	if (ok == 1)
	  {
	    setred (source, i, j,(int)(
		    r2 * sqrt (o_r * r + o_g * g + o_b * b) / 255));
	    setgreen (source, i, j,(int)(
		      g2 * sqrt (o_r * r + o_g * g + o_b * b) / 255));
	    setblue (source, i, j,(int)(
		     b2 * sqrt (o_r * r + o_g * g + o_b * b) / 255));
	  }

      }

}
Beispiel #12
0
//This Blit conserves the alpha, Blit_merge blends the alphaed color in with background.
void
blit (iImage * source, iImage * dest, int source_startx, int source_starty,
      int destx, int desty, int source_endx, int source_endy)
{
  int x;
  int y;
  int r, g, b;
  int i, j;
  int a;

  x = dest->GetWidth ();
  y = dest->GetHeight ();


  if (source_endx + destx - source_startx >= x)
    source_endx = x - destx + source_startx;


  if (source_endy + desty - source_starty >= y)
    source_endy = y - desty + source_starty;


  i = 0;
  j = 0;
  for (x = source_startx; x < source_endx; x++)
    {
      for (y = source_starty; y < source_endy; y++)
	{
	  r = getred (source, x, y);
	  g = getgreen (source, x, y);
	  b = getblue (source, x, y);
	  a = getalpha (source, x, y);


	  setred (dest, i + destx, j + desty, r);
	  setgreen (dest, i + destx, j + desty, g);
	  setblue (dest, i + destx, j + desty, b);
	  setalpha (dest, i + destx, j + desty, a);
	  j++;
	}
      j = 0;
      i++;
    }



}
Beispiel #13
0
void
swap_blue_to_red (iImage * source)
{
  int i, j;
  int r, g, b;
//float bright;

  for (i = 0; i < source->GetWidth (); i++)
    for (j = 0; j < source->GetHeight (); j++)
      {
	r = getred (source, i, j);
	g = getgreen (source, i, j);
	b = getblue (source, i, j);

	setred (source, i, j, b);
	setgreen (source, i, j, g);
	setblue (source, i, j, r);
      }

}
Beispiel #14
0
void
blit_transparent (iImage * source, iImage * dest, int source_startx,
		  int source_starty, int destx, int desty, int source_endx,
		  int source_endy, int r0, int g0, int b0, int range)
{
  int x;
  int y;
  int r, g, b;
  int i, j;

  int r2, g2, b2;
  x = dest->GetWidth ();
  y = dest->GetHeight ();


  if (source_endx + destx - source_startx >= x)
    source_endx = x - destx + source_startx;


  if (source_endy + desty - source_starty >= y)
    source_endy = y - desty + source_starty;



  i = 0;
  j = 0;
  for (x = source_startx; x < source_endx; x++)
    {
      for (y = source_starty; y < source_endy; y++)
	{
	  r = getred (source, x, y);
	  g = getgreen (source, x, y);
	  b = getblue (source, x, y);

	  r2 = abs (r0 - r);
	  g2 = abs (g0 - g);
	  b2 = abs (b0 - b);


	  if (r2 < range && g2 < range && b2 < range)
	    {
	      r = r0;
	      setalpha (dest, i + destx, j + desty, 0);
	    }
	  else
	    {
	      setred (dest, i + destx, j + desty, r);
	      setgreen (dest, i + destx, j + desty, g);
	      setblue (dest, i + destx, j + desty, b);
	      setalpha (dest, i + destx, j + desty, 255);

	    }
	  j++;
	}
      j = 0;
      i++;
    }



}
Beispiel #15
0
//RNG is the times difference
void
alter_colors_ratio (iImage * source, int o_r, int o_g, int o_b, int r2,
		    int g2, int b2, int rng)
{

  int i, j;
  int r, g, b;

//int a1;
//float bright;
//int r3,g3,b3;

  float rg_rat, gb_rat, br_rat;

//Which way do the ratio's face:
  int rg_way = -1, gb_way = -1, br_way = -1;


  float rg_fly=0;
  float gb_fly, br_fly;


  int ok;

//Rat values: 0 - none of one element
// greater than 0: green is greater than red
// less than 0: red is less than green -inverse 1/ number- greater than...

// greater than 0: How many times difference

//compare: times difference, against current times difference, and see if within range

  if (o_r == 0)
    rg_rat = 0;
  else
    {
      rg_rat = o_g / o_r;
      if (rg_rat < 0)
	{
	  rg_rat = 1 / rg_rat;
	  rg_way = 1;
	}

    }

  if (o_g == 0)
    gb_rat = 0;
  else
    {
      gb_rat = o_b / o_g;
      if (gb_rat < 0)
	{
	  gb_rat = 1 / gb_rat;
	  gb_way = 1;
	}

    }

  if (o_b == 0)
    br_rat = 0;
  else
    {
      br_rat = o_r / o_b;
      if (br_rat < 0)
	{
	  br_rat = 1 / br_rat;
	  br_way = 1;
	}
    }




  for (i = 0; i < source->GetWidth (); i++)
    for (j = 0; j < source->GetHeight (); j++)
      {
	ok = 1;
	r = getred (source, i, j);
	g = getgreen (source, i, j);
	b = getblue (source, i, j);




//Check which way rg goes
	if (rg_way == -1)
	  {
//everything is cool if 0's.0 stops division by 0
	    if (r == 0)
	      {
		if (o_r > 0)
		  ok = 0;
	      }
	    else
	      {
		rg_fly = g / r;
//make sure we got green to red, and not red to green(insta failure for now)
//invert and negatize it, so its on a scale goin the other direction
		if (rg_fly < 0)
		  rg_fly = -(1 / rg_fly);
		rg_fly = abs ((int)(rg_fly - rg_rat));
		if (rg_fly > rng)
		  ok = 0;
	      }
	  }

	if (rg_way == 1)
	  {
	    rg_fly = r / g;
	    if (rg_fly < 0)
	      rg_fly = -(1 / rg_fly);
	    rg_fly = abs ((int)(rg_fly - rg_rat));
	    if (rg_fly > rng)
	      ok = 0;
	  }




	if (gb_way == -1)
	  {
//everything is cool if 0's.0 stops division by 0
	    if (g == 0)
	      {
		if (o_g > 0)
		  ok = 0;
	      }
	    else
	      {
		gb_fly = b / g;
//make sure we got green to red, and not red to green(insta failure for now)
//invert and negatize it, so its on a scale goin the other direction
		if (gb_fly < 0)
		  gb_fly = -(1 / gb_fly);
		gb_fly = abs ((int)(gb_fly - gb_rat));
		if (gb_fly > rng)
		  ok = 0;
	      }
	  }

	if (gb_way == 1)
	  {
	    gb_fly = g / b;
	    if (rg_fly < 0)
	      gb_fly = -(1 / gb_fly);
	    gb_fly = abs ((int)(gb_fly - gb_rat));
	    if (gb_fly > rng)
	      ok = 0;
	  }


	if (br_way == -1)
	  {
//everything is cool if 0's.0 stops division by 0
	    if (b == 0)
	      {
		if (o_b > 0)
		  ok = 0;
	      }
	    else
	      {
		br_fly = r / b;
//make sure we got green to red, and not red to green(insta failure for now)
//invert and negatize it, so its on a scale goin the other direction
		if (br_fly < 0)
		  br_fly = -(1 / br_fly);
		br_fly = abs ((int)(br_fly - br_rat));
		if (br_fly > rng)
		  ok = 0;
	      }
	  }

	if (br_way == 1)
	  {
	    br_fly = b / r;
	    if (rg_fly < 0)
	      br_fly = -(1 / br_fly);
	    br_fly = abs ((int)(br_fly - br_rat));
	    if (br_fly > rng)
	      ok = 0;
	  }



	if (ok == 1)
	  {
	    setred (source, i, j,(int)(
		    r2 * sqrt (o_r * r + o_g * g + o_b * b) / 255));
	    setgreen (source, i, j,(int)(
		      g2 * sqrt (o_r * r + o_g * g + o_b * b) / 255));
	    setblue (source, i, j,(int)(
		     b2 * sqrt (o_r * r + o_g * g + o_b * b) / 255));
	  }

      }

}
Beispiel #16
0
void yuv16_422_planar_slab (hwrbitmap dest, 
			    s16 x, s16 y, s16 w,
			    hwrcolor c, s16 lgop)
{
  struct stdbitmap * dstbit = (struct stdbitmap *) dest;

  if (yuv16_422_planar_is_offscreen (dstbit->bits)) {
    /* we are offscreen */
    def_slab (dest, x, y, w, c, lgop);
    return;
  }
  else {
    unsigned long r = getred(c);
    unsigned long g = getgreen(c);
    unsigned long b = getblue(c);
    unsigned long a = getalpha(c);
    int i;

    size_t offset = (dstbit->pitch) * y + x;
    
    u8 * dst_y  = dstbit->bits + offset;
    u8 * dst_uv = dstbit->bits + yuv16_422_planar_y_plane_size 
      + (offset &~ 1);

    switch (lgop) {      
    case PG_LGOP_NONE: {
      int y, cb, cr;
      
      /*
       * Alpha is null...We're transparent
       */
      if (!a) {
	y = 0;
	cb = 0;
	cr = 0;
      } else
	rgb_to_ycbcr (r, g, b, & y, & cb, & cr);

      memset (dst_y, (char) y, w);
      if (cb == cr) {
	memset (dst_uv, (char) cb, w * 2);
      } else {
	for (i = 0; i < w; i += 2) {
	  * dst_uv++ = (char) cb;
	  * dst_uv   = (char) cr;
	}
      }

      if (c == 0) {
	memset (yuv16_rgb_shadow_buffer, 0, w * sizeof (c));
      } else {
	for (i = 0; i < w; i++) {
	  yuv16_rgb_shadow_buffer [offset + i] = c;
	}
      }
      
      break; 
    }
    
    default:
      /* Not supported yet */
      def_slab (dest, x, y, w, c, lgop);
      return;
    }
  }
}
Beispiel #17
0
/* Fillstyle interpreter- generates/refreshes a gropnode list */
g_error exec_fillstyle_inner(struct gropctxt *ctx,u16 state,
			     u16 property) {
  g_error e;
  u32 fssize;  /* Fillstyle size */
  unsigned char *fs;  /* Pointer to the actual fillstyle data */
  unsigned char *p,*plimit;
  unsigned char op;
  int r,g,b;          /* For color arithmetic */
  struct widget *w;
  int stackframe = fsstkpos-4;

  /* Look up the fillstyle */
  e = rdhandle((void**)&fs,PG_TYPE_FILLSTYLE,-1,theme_lookup(state,property));
  errorcheck;

  if (!fs) {
    
    /* When our best just isn't good enough... */
    if (property == PGTH_P_BACKDROP || property == PGTH_P_BORDER_FILL)
      return success;

    /* The default fillstyle, if no theme is loaded or no 
       theme has defined the property*/

    addgrop(ctx,PG_GROP_SETCOLOR);
    ctx->current->param[0] = VID(color_pgtohwr) (0x000000);
    
    switch (state) {

    case PGTH_O_BUTTON_ON:      /* 2 borders */
      addgropsz(ctx,PG_GROP_FRAME,ctx->r.x,ctx->r.y,ctx->r.w,ctx->r.h);
      ctx->r.x += 1; ctx->r.y += 1; ctx->r.w -= 2; ctx->r.h -= 2;
    default:                    /* 1 border */
      addgropsz(ctx,PG_GROP_FRAME,ctx->r.x,ctx->r.y,ctx->r.w,ctx->r.h);
      ctx->r.x += 1; ctx->r.y += 1; ctx->r.w -= 2; ctx->r.h -= 2;
    case PGTH_O_LABEL_SCROLL:   /* No border */
      addgrop(ctx,PG_GROP_SETCOLOR);
      ctx->current->param[0] = VID(color_pgtohwr) (theme_lookup(state,PGTH_P_BGCOLOR));
      addgropsz(ctx,PG_GROP_RECT,ctx->r.x,ctx->r.y,ctx->r.w,ctx->r.h);      
    }
    return success;
  }

  /* Process the opcodes */
  fssize = *(((u32 *)fs)++);
  p = fs;
  plimit = fs+fssize;
  while (p<plimit) {
    op = *(p++);
    
    /* These must occur in MSB to LSB order! (see constants.h) */
    if (op & PGTH_OPSIMPLE_GROP) {
      /* 1-byte gropnode */
      e = fsgrop(ctx,op & (PGTH_OPSIMPLE_GROP-1));
      errorcheck;
    }
    else if (op & PGTH_OPSIMPLE_LITERAL) {
      /* 1-byte literal */
      fsstack[fsstkpos++] = op & (PGTH_OPSIMPLE_LITERAL-1);
    }
    else if (op & PGTH_OPSIMPLE_CMDCODE) {
      /* Command code */
      switch (op) {

      case PGTH_OPCMD_LONGLITERAL:
	if ((plimit-p)<4)
	  return mkerror(PG_ERRT_BADPARAM,91);  /* Truncated opcode */
	 fsstack[fsstkpos++] = NEXTLONG;
	 p += 4;
	 break;

      case PGTH_OPCMD_LONGGROP:
	if ((plimit-p)<2)
	  return mkerror(PG_ERRT_BADPARAM,91);  /* Truncated opcode */
	e = fsgrop(ctx,NEXTSHORT);
	p += 2;
	errorcheck;
	break;

      case PGTH_OPCMD_LONGGET:
	if (plimit<=p)
	  return mkerror(PG_ERRT_BADPARAM,91);  /* Truncated opcode */
	e = fsget(*(p++)+stackframe);
	errorcheck;
	break;

      case PGTH_OPCMD_LONGSET:
	if (plimit<=p)
	  return mkerror(PG_ERRT_BADPARAM,91);  /* Truncated opcode */
	e = fsset(*(p++)+stackframe);
	errorcheck;
	break;

      case PGTH_OPCMD_PROPERTY:
	if ((plimit-p)<4)
	  return mkerror(PG_ERRT_BADPARAM,91);  /* Truncated opcode */
	fsa = NEXTSHORT;
	p += 2;
	fsb = NEXTSHORT;
	p += 2;
	fsstack[fsstkpos++] = theme_lookup(fsa,fsb);

#ifdef CONFIG_ANIMATION
	/* If it depends on time or randomness, turn on the animated flag in the divnode */
	if ((fsb==PGTH_P_TICKS || fsb==PGTH_P_RANDOM) && ctx->owner)
	  ctx->owner->flags |= DIVNODE_ANIMATED;
#endif
	break;

      case PGTH_OPCMD_LOCALPROP:
	if ((plimit-p)<2)
	  return mkerror(PG_ERRT_BADPARAM,91);  /* Truncated opcode */
	 fsa = NEXTSHORT;
	 p += 2;
#ifdef DEBUG_THEME
	 printf("Local theme lookup, property %d\n",(int)fsa);
#endif
	 fsstack[fsstkpos++] = theme_lookup(state,fsa);

#ifdef CONFIG_ANIMATION
	/* If it depends on time or randomness, turn on the animated flag in the divnode */
	if ((fsa==PGTH_P_TICKS || fsa==PGTH_P_RANDOM) && ctx->owner)
	  ctx->owner->flags |= DIVNODE_ANIMATED;
#endif
	break;

      case PGTH_OPCMD_PLUS:
	e = fspopargs();
	errorcheck;
	fsstack[fsstkpos++] = fsa + fsb;
	break;

      case PGTH_OPCMD_MINUS:
	e = fspopargs();
	errorcheck;
	fsstack[fsstkpos++] = fsa -  fsb;
	break;

      case PGTH_OPCMD_MULTIPLY:
	e = fspopargs();
	errorcheck;
	fsstack[fsstkpos++] = fsa * fsb;
	break;

      case PGTH_OPCMD_SHIFTL:
	e = fspopargs();
	errorcheck;
	fsstack[fsstkpos++] = fsa << fsb; 
	break;
	
      case PGTH_OPCMD_SHIFTR:
	e = fspopargs();
	errorcheck;
	fsstack[fsstkpos++] = fsa >> fsb;
	break;

      case PGTH_OPCMD_OR:
	e = fspopargs();
	errorcheck;
	fsstack[fsstkpos++] = fsa | fsb;
	break;

      case PGTH_OPCMD_AND:
	e = fspopargs();
	errorcheck;
	fsstack[fsstkpos++] = fsa & fsb;
	break;

      case PGTH_OPCMD_EQ:
	e = fspopargs();
	errorcheck;
	fsstack[fsstkpos++] = fsa == fsb;
	break;

      case PGTH_OPCMD_LT:
	e = fspopargs();
	errorcheck;
	fsstack[fsstkpos++] = fsa < fsb;
	break;

      case PGTH_OPCMD_GT:
	e = fspopargs();
	errorcheck;
	fsstack[fsstkpos++] = fsa > fsb;
	break;

      case PGTH_OPCMD_LOGICAL_OR:
	e = fspopargs();
	errorcheck;
	fsstack[fsstkpos++] = fsa || fsb;
	break;

      case PGTH_OPCMD_LOGICAL_AND:
	e = fspopargs();
	errorcheck;
	fsstack[fsstkpos++] = fsa && fsb;
	break;

      case PGTH_OPCMD_LOGICAL_NOT:
	fsstack[fsstkpos-1] = !fsstack[fsstkpos-1];
	break;

      case PGTH_OPCMD_DIVIDE:   
	e = fspopargs();
	errorcheck;
	if (fsb)
	  fsstack[fsstkpos++] = fsa / fsb; 
	else
	  fsstack[fsstkpos++] = 0xFFFFFFFF;   /* limit of fsa/fsb as fsb approaches 0 */
	break;

      case PGTH_OPCMD_COLORADD:
	e = fspopargs();
	errorcheck;
	r = getred(fsa);
	g = getgreen(fsa);
	b = getblue(fsa);
	r += getred(fsb);
	g += getgreen(fsb);
	b += getblue(fsb);
	if (r>255) r = 255;
	if (g>255) g = 255;
	if (b>255) b = 255;
	fsstack[fsstkpos++] = mkcolor(r,g,b);
	break;

      case PGTH_OPCMD_COLORSUB:
	e = fspopargs();
	errorcheck;
	r = getred(fsa);
	g = getgreen(fsa);
	b = getblue(fsa);
	r -= getred(fsb);
	g -= getgreen(fsb);
	b -= getblue(fsb);
	if (r<0) r = 0;
	if (g<0) g = 0;
	if (b<0) b = 0;
	fsstack[fsstkpos++] = mkcolor(r,g,b);
	break;

      case PGTH_OPCMD_COLORDIV:
	e = fspopargs();
	errorcheck;
	r = getred(fsa);
	g = getgreen(fsa);
	b = getblue(fsa);
	r = getred(fsb) ? (r/getred(fsb)) : 0xFF;     /* Avoid divide by zero */
	g = getgreen(fsb) ? (g/getgreen(fsb)) : 0xFF; 
	b = getred(fsb) ? (b/getblue(fsb)) : 0xFF;
     	fsstack[fsstkpos++] = mkcolor(r,g,b);
	break;

      case PGTH_OPCMD_COLORMULT:
	e = fspopargs();
	errorcheck;
	r = getred(fsa);
	g = getgreen(fsa);
	b = getblue(fsa);
	r *= getred(fsb);
	g *= getgreen(fsb);
	b *= getblue(fsb);
	if (r>255) r = 255;
	if (g>255) g = 255;
	if (b>255) b = 255;
	fsstack[fsstkpos++] = mkcolor(r,g,b);
	break;

      case PGTH_OPCMD_QUESTIONCOLON:
	if (fsstkpos<3)
	  return mkerror(PG_ERRT_BADPARAM,88);  /* Stack underflow */
	fsstkpos -= 2;
	fsstack[fsstkpos-1] = fsstack[fsstkpos+1] ? 
	  fsstack[fsstkpos] : fsstack[fsstkpos-1];
	break;

      case PGTH_OPCMD_WIDGET:
	if (ctx->owner && ctx->owner->owner)
	  fsstack[fsstkpos++] = hlookup(ctx->owner->owner,NULL);
	else
	  fsstack[fsstkpos++] = 0;
	break;
	
      case PGTH_OPCMD_TRAVERSEWGT:
	if (fsstkpos<3)
	  return mkerror(PG_ERRT_BADPARAM,88);  /* Stack underflow */
	fsstkpos -= 2;
	e = rdhandle((void**)&w, PG_TYPE_WIDGET, -1, fsstack[fsstkpos+1]);
	errorcheck;
	if (w)
	  fsstack[fsstkpos-1] = hlookup(widget_traverse(w,fsstack[fsstkpos],fsstack[fsstkpos-1]),NULL);
	else
	  fsstack[fsstkpos-1] = 0;
	break;

      case PGTH_OPCMD_GETWIDGET:
	e = fspopargs();
	errorcheck;
	e = rdhandle((void**)&w, PG_TYPE_WIDGET, -1, fsa);
	errorcheck;
	if (w) 
	  fsstack[fsstkpos++] = widget_get(w,fsb);
	else
	  fsstack[fsstkpos++] = 0;
	break;

      case PGTH_OPCMD_CALL:
	if ((plimit-p)<4)
	  return mkerror(PG_ERRT_BADPARAM,91);  /* Truncated opcode */
	fsa = NEXTSHORT;
	p += 2;
	fsb = NEXTSHORT;
	p += 2;
	e = exec_fillstyle_inner(ctx,fsa,fsb);
	errorcheck;
	break;

      case PGTH_OPCMD_LOCALCALL:
	if ((plimit-p)<2)
	  return mkerror(PG_ERRT_BADPARAM,91);  /* Truncated opcode */
	fsb = NEXTSHORT;
	p += 2;
	e = exec_fillstyle_inner(ctx,state,fsb);
	errorcheck;
	break;

      case PGTH_OPCMD_EXTENDED:
	/* extended command */
	op = *(p++);
	switch (op) {

	case PGTH_EXCMD_SKIP_IF:
	  if (!fsstack[--fsstkpos]) {
	    --fsstkpos;
	    break;
	  }
	  /* else proceed to EXCMD_SKIP */

	case PGTH_EXCMD_SKIP:
	  p += (s32)fsstack[--fsstkpos];
	  break;

	}
	break;

      }
    }
    else if (op & PGTH_OPSIMPLE_GET) {
      /* 1-byte get */
      e = fsget((op & (PGTH_OPSIMPLE_GET-1)) + stackframe);
      errorcheck;
    }
    else {
      /* 1-byte set */
      e = fsset(op + stackframe);
      errorcheck;
    }

#ifdef DEBUG_THEME
    /* trace */
    printf("FILLSTYLE --- Op: 0x%02X Stk:",op);
    for (fsa=0;fsa<fsstkpos;fsa++)
      printf(" %d",(int)fsstack[fsa]);
    printf("\n"); 
#endif
    
    /* check for stack over/underflow */
    if (fsstkpos<0)
      return mkerror(PG_ERRT_BADPARAM,88);  /* Stack underflow */
    if (fsstkpos>=FSSTACKSIZE)
      return mkerror(PG_ERRT_BADPARAM,89);  /* Stack overflow */
  }