home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / GRAPHICS / MISC / PVQUAN15.ZIP / QUANT.ZIP / OCTREE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-22  |  5.0 KB  |  176 lines

  1. /************************************************************************
  2.  *                                                                      *
  3.  *                  Copyright (c) 1991, Frank van der Hulst             *
  4.  *                          All Rights Reserved                         *
  5.  *                                                                      *
  6.  * Authors:                                                             *
  7.  *          FvdH - Frank van der Hulst (Wellington, NZ)                     *
  8.  *                                                                      *
  9.  * Versions:                                                            *
  10.  *      V1.1 910626 FvdH - QUANT released for DBW_RENDER                *
  11.  *      V1.2 911021 FvdH - QUANT released for PoV Ray                   *
  12.  *                                                                      *
  13.  ************************************************************************/
  14. /* This code implements the alogrithm described in:
  15.  * Graphic Gems edited by Andrew Glassner
  16.  * Article: A Simple Method for Color Quantisation:
  17.  *          Octree Quantisation, pg. 287 ff
  18.  * by:      Michael Gervautz, Werner Purgathofer
  19.  *          Technical University Vienna
  20.  *          Vienna, Austria
  21.  */
  22.  
  23. /* Written by wRZL (Wolfgang Stuerzlinger) */
  24.  
  25. /* This code is hereby placed in public domain */
  26.  
  27. #include <string.h>
  28. #include "quant.h"
  29. #include "octree.h"
  30.  
  31. #define RGB(r,g,b) ((((unsigned long)(b) << input_bits) | ((g) << input_bits)) | (r))
  32. #define TESTBIT(a,i) ( ((a) >> (i)) & 1)
  33. #define MAXDEPTH 7
  34.  
  35. static UINT size;
  36. static UINT reducelevel;
  37. static UINT leaflevel;
  38. static OCTREE tree;
  39. static OCTREE reducelist[MAXDEPTH + 1];
  40.  
  41. static unsigned char quant_r,    /* Originally a parameter for quant2(), */
  42.                             quant_g,    /* moved here to reduce stack usage */
  43.                             quant_b;
  44.  
  45. static char quant2(OCTREE tree)
  46. {
  47.     if (tree->leaf)   return(tree->colorindex);
  48.     else                    return(quant2(tree->next[
  49.                                 TESTBIT(quant_r, MAXDEPTH - tree->level) * 4 +
  50.                                 TESTBIT(quant_g, MAXDEPTH - tree->level) * 2 +
  51.                                 TESTBIT(quant_b, MAXDEPTH - tree->level)]));
  52. }
  53.  
  54. int pal_index(UCHAR *p)
  55. {
  56.     quant_r = p[RED];
  57.     quant_g = p[GREEN];
  58.     quant_b = p[BLUE];
  59.     return quant2(tree);
  60. }
  61.  
  62. static double init_Cfactor;
  63. static UINT init_col_num;
  64.  
  65. static void initpalette(OCTREE tree)
  66. {
  67.     UINT j;
  68.  
  69.     if (tree == NULL) return;
  70.     if (tree->leaf || tree->level == leaflevel) {
  71.         palette[init_col_num][RED]   = (char) ((init_Cfactor * tree->rgbsum.r) / tree->colorcount + 0.5);
  72.         palette[init_col_num][GREEN] = (char) ((init_Cfactor * tree->rgbsum.g) / tree->colorcount + 0.5);
  73.         palette[init_col_num][BLUE]  = (char) ((init_Cfactor * tree->rgbsum.b) / tree->colorcount + 0.5);
  74.         tree->colorindex = init_col_num;
  75.         tree->leaf = TRUE;
  76.         init_col_num++;
  77.     } else {
  78.         for (j = 0; j < 8; j++)
  79.             initpalette(tree->next[j]);
  80.     }
  81. }
  82.  
  83. UINT calc_palette(UINT i, double Cfactor)
  84. {
  85.     init_Cfactor = Cfactor;
  86.     init_col_num = i;
  87.     initpalette(tree);
  88.     return init_col_num;
  89. }
  90.  
  91.  
  92. static void newandinit(OCTREE *tree, UINT depth)
  93.     {
  94.     *tree = (OCTREE)calloc(1,sizeof(struct node));
  95.     if (*tree == NULL) {
  96.         printf("out of memory");
  97.         exit(1);
  98.         }
  99.     (*tree)->level = depth;
  100.     (*tree)->leaf = (depth >= leaflevel);
  101.     if ((*tree)->leaf)
  102.         size++;
  103.     }
  104.  
  105. static void getreduceable(OCTREE *node)
  106.     {
  107.     UINT newreducelevel;
  108.  
  109.     newreducelevel = reducelevel;
  110.     while (reducelist[newreducelevel] == NULL)
  111.         newreducelevel--;
  112.     *node = reducelist[newreducelevel];
  113.     reducelist[newreducelevel] =
  114.                 reducelist[newreducelevel]->nextreduceable;
  115.     }
  116.  
  117. static void makereduceable(UINT level,OCTREE node)
  118. {
  119.     node->nextreduceable = reducelist[level];
  120.     reducelist[level] = node;
  121. }
  122.  
  123. static void reducetree(void)
  124. {
  125.     OCTREE node;
  126.     UINT depth;
  127.  
  128.     getreduceable(&node);
  129.     node->leaf = 1;
  130.     size = size - node->children + 1;
  131.     depth = node->level;
  132.     if (depth < reducelevel) {
  133.         reducelevel = depth;
  134.         leaflevel = reducelevel + 1;
  135.     }
  136. }
  137.  
  138. static UCHAR insert_rgb[3];   /* Originally a parameter for inserttree(), moved
  139.                                         here to reduce stack usage */
  140.  
  141. static void inserttree(OCTREE *tree, UINT depth)
  142. {
  143.     UINT branch;
  144.  
  145.     if (*tree == NULL)
  146.         newandinit(tree,depth);
  147.     (*tree)->colorcount++;
  148.     (*tree)->rgbsum.r += insert_rgb[RED];
  149.     (*tree)->rgbsum.g += insert_rgb[GREEN];
  150.     (*tree)->rgbsum.b += insert_rgb[BLUE];
  151.     if ((*tree)->leaf == FALSE && depth < leaflevel) {
  152.         branch = TESTBIT(insert_rgb[RED],MAXDEPTH - depth) * 4 +
  153.                     TESTBIT(insert_rgb[GREEN],MAXDEPTH - depth) * 2 +
  154.                     TESTBIT(insert_rgb[BLUE],MAXDEPTH - depth);
  155.         if ((*tree)->next[branch] == NULL) {
  156.             (*tree)->children++;
  157.             if ((*tree)->children == 2)
  158.                 makereduceable(depth,*tree);
  159.         }
  160.         inserttree(&((*tree)->next[branch]), depth + 1);
  161.     }
  162. }
  163.  
  164. void generateoctree(void)
  165. {
  166.     reducelevel = MAXDEPTH;
  167.     leaflevel = reducelevel + 1;
  168.  
  169.     while (get_pixel(insert_rgb)) {
  170.         inserttree(&tree, 0);
  171.         if (size > MAXCOLORS - 1)        /* max number of colors ! */
  172.             reducetree();
  173.     }
  174. }
  175.  
  176.