From ea73edd643b1acff4a16e1d24b839722a0530912 Mon Sep 17 00:00:00 2001
From: "Mirar (Pontus Hagland)" <pike@sort.mirar.org>
Date: Wed, 29 Oct 1997 03:56:36 +0100
Subject: [PATCH] ordered dither

Rev: src/modules/Image/colortable.c:1.11
Rev: src/modules/Image/colortable.h:1.3
---
 src/modules/Image/colortable.c | 519 +++++++++++++++++++++++++++++++--
 src/modules/Image/colortable.h |  21 +-
 2 files changed, 516 insertions(+), 24 deletions(-)

diff --git a/src/modules/Image/colortable.c b/src/modules/Image/colortable.c
index 181cc46e4a..11c0962d25 100644
--- a/src/modules/Image/colortable.c
+++ b/src/modules/Image/colortable.c
@@ -1,11 +1,11 @@
 #include <config.h>
 
-/* $Id: colortable.c,v 1.10 1997/10/27 22:38:05 mirar Exp $ */
+/* $Id: colortable.c,v 1.11 1997/10/29 02:56:33 mirar Exp $ */
 
 /*
 **! module Image
 **! note
-**!	$Id: colortable.c,v 1.10 1997/10/27 22:38:05 mirar Exp $
+**!	$Id: colortable.c,v 1.11 1997/10/29 02:56:33 mirar Exp $
 **! class colortable
 **!
 **!	This object keeps colortable information,
@@ -21,7 +21,7 @@
 #undef COLORTABLE_REDUCE_DEBUG
 
 #include "global.h"
-RCSID("$Id: colortable.c,v 1.10 1997/10/27 22:38:05 mirar Exp $");
+RCSID("$Id: colortable.c,v 1.11 1997/10/29 02:56:33 mirar Exp $");
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -1628,6 +1628,55 @@ static rgbl_group dither_randomcube_encode(struct nct_dither *dith,
    return rgb;
 }
 
+static rgbl_group dither_randomgrey_encode(struct nct_dither *dith,
+					   int rowpos,
+					   rgb_group s)
+{
+   rgbl_group rgb;
+   int i;
+   int err=-(rand()%(dith->u.randomcube.r*2-1))+dith->u.randomcube.r+1;
+   i=(int)(s.r+err); 
+   rgb.r=i<0?0:(i>255?255:i); 			       
+   i=(int)(s.g+err); 
+   rgb.g=i<0?0:(i>255?255:i); 			       
+   i=(int)(s.b+err); 
+   rgb.b=i<0?0:(i>255?255:i);
+   return rgb;
+}
+
+static void dither_ordered_newline(struct nct_dither *dith,
+				   int *rowpos,
+				   rgb_group **s,
+				   rgb_group **d,
+				   int *cd)
+{
+   dith->u.ordered.row++;
+}
+
+static rgbl_group dither_ordered_encode(struct nct_dither *dith,
+					int rowpos,
+					rgb_group s)
+{
+   rgbl_group rgb;
+   int i;
+   int xs=dith->u.ordered.xs;
+   int ys=dith->u.ordered.ys;
+
+   i=(int)(s.r+dith->u.ordered.rdiff
+	          [((rowpos+dith->u.ordered.rx)%xs)+
+		   ((dith->u.ordered.row+dith->u.ordered.ry)%ys)*xs]); 
+   rgb.r=i<0?0:(i>255?255:i); 			       
+   i=(int)(s.g+dith->u.ordered.gdiff
+	          [((rowpos+dith->u.ordered.gx)%xs)+
+		   ((dith->u.ordered.row+dith->u.ordered.gy)%ys)*xs]); 
+   rgb.g=i<0?0:(i>255?255:i); 			       
+   i=(int)(s.b+dith->u.ordered.bdiff
+	          [((rowpos+dith->u.ordered.bx)%xs)+
+		   ((dith->u.ordered.row+dith->u.ordered.by)%ys)*xs]); 
+   rgb.b=i<0?0:(i>255?255:i);
+   return rgb;
+}
+
 
 static void dither_dummy_got(struct nct_dither *dith,
 			     int rowpos,
@@ -1676,13 +1725,54 @@ int image_colortable_initiate_dither(struct neo_colortable *nct,
 	 return 1;
 
       case NCTD_RANDOMCUBE:
-	 dith->u.randomcube.r=THIS->du.randomcube.r;
-	 dith->u.randomcube.g=THIS->du.randomcube.g;
-	 dith->u.randomcube.b=THIS->du.randomcube.b;
+	 dith->u.randomcube=THIS->du.randomcube;
 
 	 dith->encode=dither_randomcube_encode;
 	 dith->got=dither_dummy_got;
 
+	 return 1;
+
+      case NCTD_RANDOMGREY:
+	 dith->u.randomcube=THIS->du.randomcube;
+
+	 dith->encode=dither_randomgrey_encode;
+	 dith->got=dither_dummy_got;
+
+	 return 1;
+
+      case NCTD_ORDERED:
+	 /* copy it all */
+	 dith->u.ordered=nct->du.ordered;
+
+	 /* make space and copy diff matrices */
+	 dith->u.ordered.rdiff=malloc(sizeof(int)*nct->du.ordered.xs*
+				      nct->du.ordered.ys);
+	 dith->u.ordered.gdiff=malloc(sizeof(int)*nct->du.ordered.xs*
+				      nct->du.ordered.ys);
+	 dith->u.ordered.bdiff=malloc(sizeof(int)*nct->du.ordered.xs*
+				      nct->du.ordered.ys);
+	 if (!dith->u.ordered.rdiff||
+	     !dith->u.ordered.gdiff||
+	     !dith->u.ordered.bdiff)
+	 {
+	    if (dith->u.ordered.rdiff) free(dith->u.ordered.rdiff);
+	    if (dith->u.ordered.gdiff) free(dith->u.ordered.gdiff);
+	    if (dith->u.ordered.bdiff) free(dith->u.ordered.bdiff);
+	    return 0;
+	 }
+	 MEMCPY(dith->u.ordered.rdiff,nct->du.ordered.rdiff,
+		sizeof(int)*nct->du.ordered.xs*nct->du.ordered.ys);
+	 MEMCPY(dith->u.ordered.gdiff,nct->du.ordered.gdiff,
+		sizeof(int)*nct->du.ordered.xs*nct->du.ordered.ys);
+	 MEMCPY(dith->u.ordered.bdiff,nct->du.ordered.bdiff,
+		sizeof(int)*nct->du.ordered.xs*nct->du.ordered.ys);
+
+	 dith->u.ordered.row=0;
+
+	 dith->encode=dither_ordered_encode;
+	 dith->got=dither_dummy_got;
+	 dith->newline=dither_ordered_newline;
+
 	 return 1;
    }
    error("Illegal dither method\n");
@@ -1700,6 +1790,7 @@ void image_colortable_free_dither(struct nct_dither *dith)
 	 free(dith->u.floyd_steinberg.nexterrors);
 	 break;
       case NCTD_RANDOMCUBE:
+      case NCTD_RANDOMGREY:
 	 break;
    }
 }
@@ -2315,15 +2406,23 @@ void image_colortable_cubicles(INT32 args)
 **!	<td><illustration> object c=Image.colortable(lena(),8)->floyd_steinberg(); return c*lena(); </illustration></td>
 **!	<td><illustration> object c=Image.colortable(lena(),16)->floyd_steinberg(); return c*lena(); </illustration></td>
 **!	<td><illustration> object c=Image.colortable(lena(),32)->floyd_steinberg(); return c*lena(); </illustration></td>
-**!	<td>floyd-steinberg dither</td>
+**!	<td><ref>floyd_steinberg</ref> dither</td>
+**!	</tr><tr valign=center>
+**!	<td></td>
+**!	<td><illustration> object c=Image.colortable(lena(),2)->ordered(60,60,60); return c*lena(); </illustration></td>
+**!	<td><illustration> object c=Image.colortable(lena(),4)->ordered(45,45,45); return c*lena(); </illustration></td>
+**!	<td><illustration> object c=Image.colortable(lena(),8)->ordered(40,40,40); return c*lena(); </illustration></td>
+**!	<td><illustration> object c=Image.colortable(lena(),16)->ordered(40,40,40); return c*lena(); </illustration></td>
+**!	<td><illustration> object c=Image.colortable(lena(),32)->ordered(15,15,15); return c*lena(); </illustration></td>
+**!	<td><ref>ordered</ref> dither</td>
 **!	</tr><tr valign=center>
 **!	<td><illustration> return lena(); </illustration></td>
-**!	<td><illustration> object c=Image.colortable(lena(),2)->randomcube(250); return c*lena(); </illustration></td>
-**!	<td><illustration> object c=Image.colortable(lena(),4)->randomcube(200); return c*lena(); </illustration></td>
-**!	<td><illustration> object c=Image.colortable(lena(),8)->randomcube(70); return c*lena(); </illustration></td>
-**!	<td><illustration> object c=Image.colortable(lena(),16)->randomcube(40); return c*lena(); </illustration></td>
-**!	<td><illustration> object c=Image.colortable(lena(),32)->randomcube(15); return c*lena(); </illustration></td>
-**!	<td>randomcube dither</td>
+**!	<td><illustration> object c=Image.colortable(lena(),2)->randomcube(60,60,60); return c*lena(); </illustration></td>
+**!	<td><illustration> object c=Image.colortable(lena(),4)->randomcube(45,45,45); return c*lena(); </illustration></td>
+**!	<td><illustration> object c=Image.colortable(lena(),8)->randomcube(40,40,40); return c*lena(); </illustration></td>
+**!	<td><illustration> object c=Image.colortable(lena(),16)->randomcube(40,40,40); return c*lena(); </illustration></td>
+**!	<td><illustration> object c=Image.colortable(lena(),32)->randomcube(15,15,15); return c*lena(); </illustration></td>
+**!	<td><ref>randomcube</ref> dither</td>
 **!	</tr><tr valign=center>
 **!	<td>original</td>
 **!	<td>2</td>
@@ -3318,35 +3417,74 @@ void image_colortable_nodither(INT32 args)
 /*
 **! method object randomcube()
 **! method object randomcube(int r,int g,int b)
+**! method object randomgrey()
+**! method object randomgrey(int err)
 **!	Set random cube dithering.
 **!	Color choosen is the closest one to color in picture
 **!	plus (flat) random error; <tt>color�random(error)</tt>.
 **!
+**!	The randomgrey method uses the same random error on red, green
+**!	and blue and the randomcube method has three random errors.
+**!
 **!	<table><tr valign=center>
 **!	<td><illustration> return lena(); </illustration></td>
 **!	<td><illustration> object c=Image.colortable(4,4,4)->randomcube(); return c*lena(); </illustration></td>
-**!	</tr><tr valign=center>
+**!	<td><illustration> object c=Image.colortable(4,4,4)->randomgrey(); return c*lena(); </illustration></td>
+**!	</tr><tr valign=top>
 **!	<td>original</td>
-**!	<td>mapped to <tt>Image.colortable(4,4,4)-><wbr>randomcube();</td>
+**!	<td colspan=2>mapped to <br><tt>Image.colortable(4,4,4)-></tt></td>
+**!	</tr><tr valign=top>
+**!	<td></td>
+**!	<td>randomcube()</td>
+**!	<td>randomgrey()</td>
+**!	</tr><tr valign=top>
+**!	<td><illustration> 
+**!		object i=Image.image(lena()->xsize(),lena()->ysize()); 
+**!		i->tuned_box(0,0,i->xsize()-1,i->ysize()-1,
+**!		     ({({0,0,0}),({0,0,0}),({255,255,255}),({255,255,255})})); 
+**!		return i; 
+**!	</illustration></td>
+**!	<td><illustration> 
+**!		object i=Image.image(lena()->xsize(),lena()->ysize()); 
+**!		i->tuned_box(0,0,i->xsize()-1,i->ysize()-1,
+**!		     ({({0,0,0}),({0,0,0}),({255,255,255}),({255,255,255})})); 
+**!		object c=Image.colortable(4,4,4)->randomcube(); 
+**!		return c*i; 
+**!	</illustration></td>
+**!	<td><illustration> 
+**!		object i=Image.image(lena()->xsize(),lena()->ysize()); 
+**!		i->tuned_box(0,0,i->xsize()-1,i->ysize()-1,
+**!		     ({({0,0,0}),({0,0,0}),({255,255,255}),({255,255,255})})); 
+**!		object c=Image.colortable(4,4,4)->randomgrey(); 
+**!		return c*i; 
+**!	</illustration></td>
 **!	</tr></table>
 **!
 **! arg int r
 **! arg int g
 **! arg int b
+**! arg int err
 **!	The maximum error. Default is 32, or colorcube step.
 **!
 **! returns the called object
 **!
-**! see also: nodither, floyd_steinberg, create
+**! see also: ordered, nodither, floyd_steinberg, create
+**!
+**! note
+**!	<ref>randomgrey</ref> method needs colorcube size to be the same on
+**!	red, green and blue sides to work properly. It uses the
+**!	red colorcube value as default.
 **/
 
 void image_colortable_randomcube(INT32 args)
 {
+   THIS->dither_type=NCTD_NONE;
+
    if (args>=3)
       if (sp[-args].type!=T_INT||
 	  sp[1-args].type!=T_INT||
 	  sp[2-args].type!=T_INT)
-	 error("Image.colortable->nodither(): illegal argument(s)\n");
+	 error("Image.colortable->randomcube(): illegal argument(s)\n");
       else
       {
 	 THIS->du.randomcube.r=sp[-args].u.integer;
@@ -3373,6 +3511,348 @@ void image_colortable_randomcube(INT32 args)
    push_object(THISOBJ); THISOBJ->refs++;
 }
 
+void image_colortable_randomgrey(INT32 args)
+{
+   THIS->dither_type=NCTD_NONE;
+
+   if (args>=3)
+      if (sp[-args].type!=T_INT)
+	 error("Image.colortable->randomgrey(): illegal argument(s)\n");
+      else
+	 THIS->du.randomcube.r=sp[-args].u.integer;
+   else if (THIS->type==NCT_CUBE && THIS->u.cube.r)
+      THIS->du.randomcube.r=256/THIS->u.cube.r;
+   else
+      THIS->du.randomcube.r=32;
+
+   THIS->dither_type=NCTD_RANDOMGREY;
+
+   pop_n_elems(args);
+   push_object(THISOBJ); THISOBJ->refs++;
+}
+
+static int* ordered_calculate_errors(int dxs,int dys)
+{
+   int *src,*dest;
+   int sxs,sys;
+
+   static int errors2x1[2]={0,1};
+   static int errors2x2[4]={0,2,3,1};
+   static int errors3x1[3]={1,0,2};
+   static int errors3x2[6]={4,0,2,1,5,3};
+   static int errors3x3[9]={6,8,4,1,0,3,5,2,7};
+
+   int szx,szy,*errs,*errp,sz,*d,*s;
+   int xf,yf;
+   int x,y;
+   
+   src=malloc(sizeof(int)*dxs*dys);
+   dest=malloc(sizeof(int)*dxs*dys);
+
+   if (!src||!dest) 
+   {
+      if (src) free(src);
+      if (dest) free(dest);
+      return NULL;
+   }
+
+   *src=0;
+   sxs=sys=1;
+   MEMSET(src,0,sizeof(int)*dxs*dys);
+   MEMSET(dest,0,sizeof(int)*dxs*dys);
+
+   for (;;)
+   {
+      if (dxs==sxs) xf=1;
+      else if (((dxs/sxs)%2)==0) xf=2;
+      else if (((dxs/sxs)%3)==0) xf=3;
+      else break;
+      if (dys==sys) yf=1;
+      else if (((dys/sys)%2)==0) yf=2;
+      else if (((dys/sys)%3)==0) yf=3;
+      else break;
+
+      if (xf==1 && yf==1) break;
+
+      szx=xf; szy=yf;
+
+      switch (xf*yf)
+      {
+	 case 2: errs=errors2x1; break;
+	 case 3: errs=errors3x1; break;
+	 case 4: errs=errors2x2; break;
+	 case 6: errs=errors3x2; break;
+	 case 9: errs=errors3x3; break;
+	 default: return; /* uh<tm> (not in {x|x={1,2,3}*{1,2,3}}) */
+      }
+      
+      sz=sxs*sys;
+      d=dest;
+      s=src;
+
+      for (y=0; y<sys; y++)
+      {
+	 int *errq=errs;
+	 for (yf=0; yf<szy; yf++)
+	 {
+	    int *sd=s;
+	    for (x=0; x<sxs; x++)
+	    {
+	       int *errp=errq;
+	       for (xf=0; xf<szx; xf++)
+		  *(d++)=*sd+sz**(errp++);
+	       sd++;
+	    }
+	    errq+=szx;
+	 }
+	 s+=sxs;
+      }
+
+      sxs*=szx;
+      sys*=szy;
+
+      /* ok, rotate... */
+
+      errs=src;
+      src=dest;
+      dest=errs;
+   }
+
+#if 0
+   s=src;
+   for (y=0; y<dys; y++)
+   {
+      printf("(");
+      for (x=0; x<dxs; x++)
+         printf("%4d",*(s++));
+      printf(" )\n");
+   }
+#endif
+
+   return src;
+}
+
+static int *ordered_make_diff(int *errors,int sz,int err)
+{
+   /* ok, i want errors between -err and +err from 0 and sz-1 */
+
+   int *dest;
+   int *d;
+   int n=sz;
+   float q;
+
+   d=dest=(int*)malloc(sizeof(int)*sz);
+   if (!d) return d;
+
+   if (sz!=1) q=1.0/(sz-1); else q=1.0;
+
+   while (n--)
+      *(d++)=(int)((*(errors++)*q-0.5)*2*err);
+   
+   return dest;
+}
+
+/*
+**! method object ordered()
+**! method object ordered(int r,int g,int b)
+**! method object ordered(int r,int g,int b,int xsize,int ysize)
+**! method object ordered(int r,int g,int b,int xsize,int ysize,int x,int y)
+**! method object ordered(int r,int g,int b,int xsize,int ysize,int rx,int ry,int gx,int gy,int bx,int by)
+**!	Set ordered dithering, which gives a position-dependent error added
+**!	to the pixel values. 
+**!
+**!	<table><tr valign=center>
+**!	<td><illustration> return lena(); </illustration></td>
+**!	<td><illustration> object c=Image.colortable(6,6,6)->ordered(42,42,42,2,2); return c*lena(); </illustration></td>
+**!	<td><illustration> object c=Image.colortable(6,6,6)->ordered(); return c*lena(); </illustration></td>
+**!	<td><illustration> object c=Image.colortable(6,6,6)->ordered(42,42,42,8,8,0,0,0,1,1,0); return c*lena(); </illustration></td>
+**!	</tr><tr valign=top>
+**!	<td>original</td>
+**!	<td colspan=2>mapped to <br><tt>Image.colortable(6,6,6)-></tt></td>
+**!	</tr><tr valign=top>
+**!	<td></td>
+**!	<td><tt>ordered<br> (42,42,42,2,2)</tt></td>
+**!	<td><tt>ordered()</tt></td>
+**!	<td><tt>ordered<br> (42,42,42, 8,8,<br> 0,0, 0,1, 1,0)</tt></td>
+**!	</tr><tr valign=top>
+**!	<td><illustration> 
+**!		object i=Image.image(lena()->xsize(),lena()->ysize()); 
+**!		i->tuned_box(0,0,i->xsize()-1,i->ysize()-1,
+**!		     ({({0,0,0}),({0,0,0}),({255,255,255}),({255,255,255})})); 
+**!		return i; 
+**!	</illustration></td>
+**!	<td><illustration> 
+**!		object i=Image.image(lena()->xsize(),lena()->ysize()); 
+**!		i->tuned_box(0,0,i->xsize()-1,i->ysize()-1,
+**!		     ({({0,0,0}),({0,0,0}),({255,255,255}),({255,255,255})})); 
+**!		object c=Image.colortable(6,6,6)->ordered(42,42,42,2,2); 
+**!		return c*i; 
+**!	</illustration></td>
+**!	<td><illustration> 
+**!		object i=Image.image(lena()->xsize(),lena()->ysize()); 
+**!		i->tuned_box(0,0,i->xsize()-1,i->ysize()-1,
+**!		     ({({0,0,0}),({0,0,0}),({255,255,255}),({255,255,255})})); 
+**!		object c=Image.colortable(6,6,6)->ordered(); 
+**!		return c*i; 
+**!	</illustration></td>
+**!	<td><illustration> 
+**!		object i=Image.image(lena()->xsize(),lena()->ysize()); 
+**!		i->tuned_box(0,0,i->xsize()-1,i->ysize()-1,
+**!		     ({({0,0,0}),({0,0,0}),({255,255,255}),({255,255,255})})); 
+**!		object c=Image.colortable(6,6,6)->ordered(42,42,42,8,8,0,0,0,1,1,0); 
+**!		return c*i; 
+**!	</illustration></td>
+**!	</tr></table>
+**!
+**! arg int r
+**! arg int g
+**! arg int b
+**!	The maximum error. Default is 32, or colorcube steps (256/size).
+**!
+**! arg int xsize
+**! arg int ysize
+**!	Size of error matrix. Default is 8�8.
+**!	Only values which factors to multiples of 2 and 3 are
+**!	possible to choose (2,3,4,6,8,12,...).
+**!
+**! arg int x
+**! arg int y
+**! arg int rx
+**! arg int ry
+**! arg int gx
+**! arg int gy
+**! arg int bx
+**! arg int by
+**!	Offset for the error matrix. <tt>x</tt> and <tt>y</tt> is for
+**!	both red, green and blue values, the other is individual.
+**!
+**! returns the called object
+**!
+**! see also: randomcube, nodither, floyd_steinberg, create
+**/
+
+void image_colortable_ordered(INT32 args)
+{
+   int *errors;
+   int r,g,b;
+   int xsize,ysize;
+
+   THIS->dither_type=NCTD_NONE;
+
+   if (args>=3)
+      if (sp[-args].type!=T_INT||
+	  sp[1-args].type!=T_INT||
+	  sp[2-args].type!=T_INT)
+	 error("Image.colortable->ordered(): illegal argument(s)\n");
+      else
+      {
+	 r=sp[-args].u.integer;
+	 g=sp[1-args].u.integer;
+	 b=sp[2-args].u.integer;
+      }
+   else if (THIS->type==NCT_CUBE && THIS->u.cube.r && 
+	    THIS->u.cube.g && THIS->u.cube.b)
+   {
+      r=256/THIS->u.cube.r;
+      g=256/THIS->u.cube.g;
+      b=256/THIS->u.cube.b;
+   }
+   else
+   {
+      r=32;
+      g=32;
+      b=32;
+   }
+
+   xsize=ysize=8;
+
+   THIS->du.ordered.rx=
+   THIS->du.ordered.ry=
+   THIS->du.ordered.gx=
+   THIS->du.ordered.gy=
+   THIS->du.ordered.bx=
+   THIS->du.ordered.by=0;
+
+   if (args>=5)
+   {
+      if (sp[3-args].type!=T_INT||
+	  sp[4-args].type!=T_INT)
+	 error("Image.colortable->ordered(): illegal argument(s)\n");
+      else
+      {
+	 xsize=MAX(sp[3-args].u.integer,1);
+	 ysize=MAX(sp[4-args].u.integer,1);
+      }
+   }
+
+   if (args>=11)
+   {
+      if (sp[5-args].type!=T_INT||
+	  sp[6-args].type!=T_INT||
+	  sp[7-args].type!=T_INT||
+	  sp[8-args].type!=T_INT||
+          sp[9-args].type!=T_INT||
+	  sp[10-args].type!=T_INT)
+	 error("Image.colortable->ordered(): illegal argument(s)\n");
+      else
+      {
+	 THIS->du.ordered.rx=sp[5-args].u.integer;
+	 THIS->du.ordered.ry=sp[6-args].u.integer;
+	 THIS->du.ordered.gx=sp[7-args].u.integer;
+	 THIS->du.ordered.gy=sp[8-args].u.integer;
+	 THIS->du.ordered.bx=sp[9-args].u.integer;
+	 THIS->du.ordered.by=sp[10-args].u.integer;
+      }
+   }
+   else if (args>=7)
+   {
+      if (sp[5-args].type!=T_INT||
+	  sp[6-args].type!=T_INT)
+	 error("Image.colortable->ordered(): illegal argument(s)\n");
+      else
+      {
+	 THIS->du.ordered.rx=
+	 THIS->du.ordered.gx=
+	 THIS->du.ordered.bx=sp[5-args].u.integer;
+	 THIS->du.ordered.ry=
+	 THIS->du.ordered.gy=
+	 THIS->du.ordered.by=sp[6-args].u.integer;
+      }
+   }
+
+   errors=ordered_calculate_errors(xsize,ysize);
+   if (!errors) 
+   {
+      error("out of memory\n");
+      return;
+   }
+
+   THIS->du.ordered.rdiff=ordered_make_diff(errors,xsize*ysize,r);
+   THIS->du.ordered.gdiff=ordered_make_diff(errors,xsize*ysize,g);
+   THIS->du.ordered.bdiff=ordered_make_diff(errors,xsize*ysize,b);
+
+   free(errors);
+
+   if (!THIS->du.ordered.rdiff||
+       !THIS->du.ordered.gdiff||
+       !THIS->du.ordered.bdiff)
+   {
+      if (THIS->du.ordered.rdiff) free(THIS->du.ordered.rdiff);
+      if (THIS->du.ordered.gdiff) free(THIS->du.ordered.gdiff);
+      if (THIS->du.ordered.bdiff) free(THIS->du.ordered.bdiff);
+      error("out of memory!\n");
+      return;
+   }
+
+   THIS->du.ordered.xs=xsize;
+   THIS->du.ordered.ys=ysize;
+
+   THIS->dither_type=NCTD_ORDERED;
+
+   pop_n_elems(args);
+   push_object(THISOBJ); THISOBJ->refs++;
+}
+
 /***************** global init etc *****************************/
 
 void init_colortable_programs(void)
@@ -3433,6 +3913,11 @@ void init_colortable_programs(void)
 		"|function(int,int|float,int|float,int|float,int|float:object)",0);
    add_function("randomcube",image_colortable_randomcube,
 		"function(:object)|function(int,int,int:object)",0);
+   add_function("randomgrey",image_colortable_randomgrey,
+		"function(:object)|function(int:object)",0);
+   add_function("ordered",image_colortable_ordered,
+		"function(:object)"
+		"|function(int,int,int:object)",0);
 
    /* tuning image */
    add_function("spacefactors",image_colortable_spacefactors,
diff --git a/src/modules/Image/colortable.h b/src/modules/Image/colortable.h
index a2b3d13c75..5f82dfe5f9 100644
--- a/src/modules/Image/colortable.h
+++ b/src/modules/Image/colortable.h
@@ -1,7 +1,7 @@
 /*
 **! module Image
 **! note
-**!	$Id: colortable.h,v 1.2 1997/10/27 22:41:18 mirar Exp $
+**!	$Id: colortable.h,v 1.3 1997/10/29 02:56:36 mirar Exp $
 */
 
 #define COLORLOOKUPCACHEHASHSIZE 207
@@ -86,7 +86,9 @@ struct neo_colortable
    {
       NCTD_NONE,
       NCTD_FLOYD_STEINBERG,
-      NCTD_RANDOMCUBE
+      NCTD_RANDOMCUBE,
+      NCTD_RANDOMGREY,
+      NCTD_ORDERED
    } dither_type;
 
    union
@@ -99,10 +101,17 @@ struct neo_colortable
 	 float forward;
 	 int dir;
       } floyd_steinberg;
-      struct
+      struct nctd_randomcube
       {
 	 int r,g,b;
       } randomcube;
+      struct nctd_ordered
+      {
+	 int xs,ys;
+	 int *rdiff,*gdiff,*bdiff;
+	 int rx,ry,gx,gy,bx,by;
+	 int row;
+      } ordered;
    } du;
 };
 
@@ -144,10 +153,8 @@ struct nct_dither
 	 int dir;
 	 int currentdir;
       } floyd_steinberg;
-      struct
-      {
-	 int r,g,b;
-      } randomcube;
+      struct nctd_randomcube randomcube;
+      struct nctd_ordered ordered;
    } u;
 };
 
-- 
GitLab