Listing 1: File 3dtable.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "3dtable.h"

struct match_array *creatematcharray(int rbits, int gbits,
    int bbits, struct rgb_color *palette, int palettesize)
{
int rval, gval, bval, len, r, g, b;
char *taken, *match, *same;
int i, set, sqstep, tp, maxtp, *entryr, *entryg, *entryb;
struct match_array *table;

if(rbits<1 || rbits>8 || gbits<1 || gbits>8 || bbits<1 || bbits>8)
  return NULL;
table=(struct match_array *)malloc(sizeof(struct match_array));
if (table==NULL) return NULL;

/* Set up some values: */
table->rb=rbits;
table->gb=gbits;
table->bb=bbits;
rval=1<<rbits;
gval=1<<gbits;
bval=1<<bbits;
len=rval*gval*bval;

/* Prepare table buffers: */
table->match=(char *)malloc(len*sizeof(char));
if (table->match==NULL)
  {
  free((void *)table);
  return NULL;
  }
taken=(char *)malloc(len*sizeof(char));
if (taken==NULL)
  {
  free((void *)table->match);
  free((void *)table);
  return NULL;
  };
memset((void *)taken, 0, len*sizeof(char));

/* Select colors to use for fill: */
set=0;
entryr=(int *)malloc(palettesize*sizeof(int));
entryg=(int *)malloc(palettesize*sizeof(int));
entryb=(int *)malloc(palettesize*sizeof(int));
same=(char *)malloc(palettesize*sizeof(char));
if (entryr==NULL || entryg==NULL || entryb==NULL || same==NULL)
  {
  free((void *)table->match), free((void *)table),
  free((void *)entryr), free((void *)entryg),
  free((void *)entryb), free((void *)same);
  return NULL;
  }
match=table->match;
for (i=0; i<palettesize; i++)
  {
  same[i]=0;
  /* Compute 3d-table coordinates of palette rgb color: */
  r=palette[i].r&0xff, g=palette[i].g&0xff, b=palette[i].b&0xff;
  r>>=8-rbits;
  g>>=8-gbits;
  b>>=8-bbits;
  /* Put color in position: */
  if (taken[b*rval*gval+g*rval+r]==0) set++;
  else same[match[b*rval*gval+g*rval+r]]=1;
  match[b*rval*gval+g*rval+r]=i;
  taken[b*rval*gval+g*rval+r]=1;
  entryr[i]=r; entryg[i]=g; entryb[i]=b;
  }

/* @@@ Fill match_array by steps: @@@ */
for (set=len-set, sqstep=1; set>0; sqstep++)
  {
  for (i=0; i<palettesize && set>0; i++)
    if (same[i]==0)
    {
    /* Fill all six sides of incremented cube
       (by pairs, 3 loops): */
    for (b=entryb[i]-sqstep; b<=entryb[i]+sqstep; b+=sqstep*2)
      if (b>=0 && b<bval)
        for (r=entryr[i]-sqstep; r<=entryr[i]+sqstep; r++)
          if (r>=0 && r<rval)
            { /* Draw one 3d line: */
            tp=b*rval*gval+(entryg[i]-sqstep)*rval+r;
            maxtp=b*rval*gval+(entryg[i]+sqstep)*rval+r;
            if (tp<b*rval*gval+0*rval+r)
              tp=b*rval*gval+0*rval+r;
            if (maxtp>b*rval*gval+(gval-1)*rval+r)
              maxtp=b*rval*gval+(gval-1)*rval+r;
            for (; tp<=maxtp; tp+=rval)
              if (!taken[tp])
                taken[tp]=1, match[tp]=i, set--;
            }
    for (g=entryg[i]-sqstep; g<=entryg[i]+sqstep; g+=sqstep*2)
      if (g>=0 && g<gval)
        for (b=entryb[i]-sqstep; b<=entryb[i]+sqstep; b++)
          if (b>=0 && b<bval)
            { /* Draw one 3d line: */
            tp=b*rval*gval+g*rval+(entryr[i]-sqstep);
            maxtp=b*rval*gval+g*rval+(entryr[i]+sqstep);
            if (tp<b*rval*gval+g*rval+0)
              tp=b*rval*gval+g*rval+0;
            if (maxtp>b*rval*gval+g*rval+(rval-1))
              maxtp=b*rval*gval+g*rval+(rval-1);
            for (; tp<=maxtp; tp++)
              if (!taken[tp])
                taken[tp]=1, match[tp]=i, set--;
            }
    for (r=entryr[i]-sqstep; r<=entryr[i]+sqstep; r+=sqstep*2)
      if (r>=0 && r<rval)
        for (g=entryg[i]-sqstep; g<=entryg[i]+sqstep; g++)
          if (g>=0 && g<gval)
            { /* Draw one 3d line: */
            tp=(entryb[i]-sqstep)*rval*gval+g*rval+r;
            maxtp=(entryb[i]+sqstep)*rval*gval+g*rval+r;
            if (tp<0*rval*gval+g*rval+r)
              tp=0*rval*gval+g*rval+r;
            if (maxtp>(bval-1)*rval*gval+g*rval+r)
              maxtp=(bval-1)*rval*gval+g*rval+r;
            for (; tp<=maxtp; tp+=rval*gval)
              if (!taken[tp])
                taken[tp]=1, match[tp]=i, set--;
            }
    }
  }
free((void *)same);
free((void *)entryr);
free((void *)entryg);
free((void *)entryb);
free((void *)taken);
return table;
}

void deletematcharray(struct match_array *table)
{
if (table!=NULL)
  {
  free((void *)table->match);
  free((void *)table);
  }
}

int findcolor(struct match_array *table, struct rgb_color c)
{
int r=c.r, g=c.g, b=c.b;
if (r<0) r=0; if (r>255) r=255;
if (g<0) g=0; if (g>255) g=255;
if (b<0) b=0; if (b>255) b=255;
if (table!=NULL)
  {
  r>>=8-table->rb;
  g>>=8-table->gb;
  b>>=8-table->bb;
  return table->match[(b<<table->gb<<table->rb)+(g<<table->rb)+r];
  }
return -1;
}
/* End of File */