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 */