/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ typedef struct color *Color; #include struct color { unsigned char r, g, b; }; typedef struct treeNode *TreeNode; struct treeNode { int leaf; int knt; int r, g, b; TreeNode kids[8]; TreeNode next; TreeNode last; }; typedef struct treeNodeBuf *TreeNodeBuf; #define ALLOC 100 struct treeNodeBuf { struct treeNode nodes[ALLOC]; TreeNodeBuf nextbuf; int nextfree; }; static TreeNodeBuf buflist = NULL; static TreeNode freenodes = NULL; static int nLeaves; #define BRANCH(color, depth, index) \ { \ int d = 7 - depth; \ index = (((color->r >> d) & 0x1) << 0) + \ (((color->g >> d) & 0x1) << 1) + \ (((color->b >> d) & 0x1) << 2); \ } TreeNode GetTreeNode() { TreeNode new = NULL; if (freenodes) { new = freenodes; freenodes = freenodes->next; } else { if (!buflist || buflist->nextfree == ALLOC) { TreeNodeBuf newbuf = (TreeNodeBuf)DXAllocateZero(sizeof(struct treeNodeBuf)); if (! newbuf) return NULL; newbuf->nextfree = 0; newbuf->nextbuf = buflist; buflist = newbuf; } new = buflist->nodes + buflist->nextfree; buflist->nextfree ++; } return new; } void FreeNode(TreeNode node) { memset(node, 0, sizeof(struct treeNode)); node->next = freenodes; freenodes = node; } void CleanupNodes() { while (buflist) { TreeNodeBuf this = buflist->nextbuf; DXFree((Pointer)buflist); buflist = this; } freenodes = NULL; } struct treeNode depthlist[8]; TreeNode InsertTree(TreeNode node, Color color, int depth) { int index; if (! node) { node = GetTreeNode(); if (! node) goto error; node->r = 0; node->g = 0; node->b = 0; node->knt = 0; node->leaf = depth == 7; if (! node->leaf) { node->next = depthlist[depth].next; depthlist[depth].next = node; depthlist[depth].knt ++; } if (node->leaf) nLeaves ++; } if (node->leaf) { node->r += color->r; node->g += color->g; node->b += color->b; } else { BRANCH(color, depth, index); node->kids[index] = InsertTree(node->kids[index], color, depth+1); if (! node->kids[index]) goto error; } node->knt ++; return node; error: return NULL; } int SearchTree(TreeNode node, Color color, int depth) { int index; if (! node) { DXSetError(ERROR_INTERNAL, "null node in SearchTree"); return -1; } if (node->leaf) return node->knt; else { BRANCH(color, depth, index); return SearchTree(node->kids[index], color, depth+1); } } struct treeNode depthlist[8]; static int reduce_max = 1; int ReduceTree() { int i, j, bestknt; TreeNode last, next, best, node; for (i = 6; i >= 0; i--) { if (depthlist[i].next) { if (reduce_max) bestknt = 0; else bestknt = 99999999; last = depthlist + i; next = last->next; while(next) { if (reduce_max) { if (next->knt > bestknt) best = last; } else { if (next->knt < bestknt) best = last; } last = next; next = next->next; } node = best->next; best->next = node->next; depthlist[i].knt --; for (j = 0; j < 8; j++) { TreeNode child = node->kids[j]; if (child) { node->r += child->r; node->g += child->g; node->b += child->b; FreeNode(child); nLeaves --; } } node->leaf = 1; nLeaves ++; if (i > 0) { #if 0 node->next = depthlist[i-1].next; depthlist[i-1].next = node; depthlist[i-1].knt ++; #endif } else { DXSetError(ERROR_INTERNAL, "reduce at level 0?"); return ERROR; } return OK; } } return ERROR; } int CountLeaves(TreeNode tree, int *n) { if (tree->leaf) { *n = *n + 1; } else { int i; TreeNode child; for (i = 0; i < 8; i++) if (NULL != (child = tree->kids[i])) if (! CountLeaves(child, n)) return ERROR; } return OK; } static int find_me = -1; void found(){} static int skip = 11; TreeNode CreateTree(Pointer pixdata, int knt, int nColors, int float_pixels) { TreeNode tree = NULL; struct color pbuf; int skipsize; ubyte *u_pixdata = (ubyte *)pixdata; int i, j; int r = 0; if (float_pixels) skipsize = skip*3*sizeof(float); else skipsize = skip*sizeof(struct color); for (i = 0; i < 8; i++) { depthlist[i].next = NULL; depthlist[i].knt = 0; } nLeaves = 0; for (j = 0; j < skip; j++) { ubyte *p; if (float_pixels) p = u_pixdata + j*3*sizeof(float); else p = u_pixdata + j*sizeof(struct color); for (i = j; i < knt; i += skip, p += skipsize) { if (i == find_me) found(); if (float_pixels) { float fr = ((float *)p)[0]; float fg = ((float *)p)[1]; float fb = ((float *)p)[2]; pbuf.r = fr >= 1.0 ? 255 : fr <= 0.0 ? 0 : (unsigned char)(255 * fr); pbuf.g = fg >= 1.0 ? 255 : fg <= 0.0 ? 0 : (unsigned char)(255 * fg); pbuf.b = fb >= 1.0 ? 255 : fb <= 0.0 ? 0 : (unsigned char)(255 * fb); if (NULL == (tree = InsertTree(tree, &pbuf, 0))) goto error; } else if (NULL == (tree = InsertTree(tree, (Color)p, 0))) goto error; while (nLeaves > nColors) if (! ReduceTree()) goto error; } } return tree; error: return NULL; } TreeNode AddFieldToTree(TreeNode tree, Pointer pixdata, int knt, int float_pixels, int nColors) { struct color pbuf; int skipsize; ubyte *u_pixdata = (ubyte *)pixdata; int i, j; int r = 0; if (float_pixels) skipsize = skip*3*sizeof(float); else skipsize = skip*sizeof(struct color); for (j = 0; j < skip; j++) { ubyte *p; if (float_pixels) p = u_pixdata + j*3*sizeof(float); else p = u_pixdata + j*sizeof(struct color); for (i = j; i < knt; i += skip, p += skipsize) { if (i == find_me) found(); if (float_pixels) { float fr = ((float *)p)[0]; float fg = ((float *)p)[1]; float fb = ((float *)p)[2]; pbuf.r = fr >= 1.0 ? 255 : fr <= 0.0 ? 0 : (unsigned char)(255 * fr); pbuf.g = fg >= 1.0 ? 255 : fg <= 0.0 ? 0 : (unsigned char)(255 * fg); pbuf.b = fb >= 1.0 ? 255 : fb <= 0.0 ? 0 : (unsigned char)(255 * fb); if (NULL == (tree = InsertTree(tree, &pbuf, 0))) goto error; } else if (NULL == (tree = InsertTree(tree, (Color)p, 0))) goto error; while (nLeaves > nColors) if (! ReduceTree()) goto error; } } return tree; error: return NULL; } Error CreateTable(TreeNode node, Color table, int nColors, int *next) { if (node->leaf) { float recip = 1.0 / node->knt; Color c = table + (*next); if ((*next) < nColors) { c->r = node->r * recip; c->g = node->g * recip; c->b = node->b * recip; node->knt = (*next); } *next = *next + 1; } else { int i; TreeNode child; for (i = 0; i < 8; i++) if (NULL != (child = node->kids[i])) if (! CreateTable(child, table, nColors, next)) return ERROR; } return OK; } Error CreateQuantPixels(TreeNode tree, Pointer input, unsigned char *output, int knt, int float_pixels) { int i; unsigned char *s = (unsigned char *)input; unsigned char *d = output; int skipsize; struct color pbuf; skipsize = float_pixels ? 3*sizeof(float) : sizeof(struct color); for (i = 0; i < knt; i++, s += skipsize, d++) { int q; if (i == find_me) found(); if (float_pixels) { float fr = ((float *)s)[0]; float fg = ((float *)s)[1]; float fb = ((float *)s)[2]; pbuf.r = fr >= 1.0 ? 255 : fr <= 0.0 ? 0 : (unsigned char)(255 * fr); pbuf.g = fg >= 1.0 ? 255 : fg <= 0.0 ? 0 : (unsigned char)(255 * fg); pbuf.b = fb >= 1.0 ? 255 : fb <= 0.0 ? 0 : (unsigned char)(255 * fb); q = SearchTree(tree, (Color)&pbuf, 0); } else q = SearchTree(tree, (Color)s, 0); if (q < 0) return ERROR; *d = q; } return 1; }