182 lines
4.3 KiB
C
182 lines
4.3 KiB
C
#include <string.h>
|
||
#include "alloc.h"
|
||
#include "dos.h"
|
||
#include "quant.h"
|
||
#include "octree.h"
|
||
|
||
#define TESTBIT(a,i) ( ((a) >> (i)) & 1)
|
||
#define MAXDEPTH 8
|
||
#define BYTE unsigned char
|
||
|
||
UCHAR palette [MAXCOLORS][3];
|
||
|
||
static UINT size;
|
||
static UINT reducelevel;
|
||
static UINT leaflevel;
|
||
static OCTREE tree;
|
||
static BYTE rgb_mio[3];
|
||
static OCTREE reducelist[MAXDEPTH + 1];
|
||
|
||
static unsigned char quant_r,
|
||
quant_g,
|
||
quant_b;
|
||
|
||
/* Quantiza seg£n TESTBIT, pero solamente de retorno */
|
||
|
||
static char quant2(OCTREE tree)
|
||
{
|
||
if (tree->leaf) return(tree->colorindex);
|
||
else return(quant2(tree->next[
|
||
TESTBIT(quant_r, MAXDEPTH - tree->level) * 4 +
|
||
TESTBIT(quant_g, MAXDEPTH - tree->level) * 2 +
|
||
TESTBIT(quant_b, MAXDEPTH - tree->level)]));
|
||
}
|
||
|
||
/* devuelve el indice a la paleta quantizada de acuerdo con RGB apuntado */
|
||
|
||
int pal_index(UCHAR *p)
|
||
{
|
||
quant_r = p[RED];
|
||
quant_g = p[GREEN];
|
||
quant_b = p[BLUE];
|
||
return quant2(tree);
|
||
}
|
||
|
||
static double init_Cfactor;
|
||
static UINT init_col_num;
|
||
|
||
static void initpalette(OCTREE tree)
|
||
{
|
||
UINT j;
|
||
|
||
if (tree == NULL) return;
|
||
if (tree->leaf || tree->level == leaflevel) {
|
||
palette[init_col_num][RED] = (char) ((init_Cfactor * tree->rgbsum.r) / tree->colorcount + .5);
|
||
palette[init_col_num][GREEN] = (char) ((init_Cfactor * tree->rgbsum.g) / tree->colorcount + .5);
|
||
palette[init_col_num][BLUE] = (char) ((init_Cfactor * tree->rgbsum.b) / tree->colorcount + .5);
|
||
tree->colorindex = init_col_num;
|
||
tree->leaf = TRUE;
|
||
init_col_num++;
|
||
} else {
|
||
for (j = 0; j < 8; j++)
|
||
initpalette(tree->next[j]);
|
||
}
|
||
}
|
||
|
||
/* calcula la paleta de acuerdo con un factor introducido */
|
||
|
||
UINT calc_palette(UINT i, double Cfactor)
|
||
{
|
||
init_Cfactor = Cfactor;
|
||
init_col_num = i;
|
||
initpalette(tree);
|
||
return init_col_num;
|
||
}
|
||
|
||
|
||
static void newandinit(OCTREE *tree, UINT depth)
|
||
{
|
||
unsigned long rest;
|
||
*tree = (OCTREE)calloc(1,sizeof(struct node));
|
||
if (*tree == NULL) {
|
||
rest=coreleft();
|
||
printf("No hay bastante Memoria");
|
||
exit(1);
|
||
}
|
||
(*tree)->level = depth;
|
||
(*tree)->leaf = (depth >= leaflevel);
|
||
if ((*tree)->leaf)
|
||
size++;
|
||
}
|
||
|
||
static void getreduceable(OCTREE *node)
|
||
{
|
||
UINT newreducelevel;
|
||
|
||
newreducelevel = reducelevel;
|
||
while (reducelist[newreducelevel] == NULL)
|
||
newreducelevel--;
|
||
*node = reducelist[newreducelevel];
|
||
reducelist[newreducelevel] =
|
||
reducelist[newreducelevel]->nextreduceable;
|
||
}
|
||
|
||
static void makereduceable(UINT level,OCTREE node)
|
||
{
|
||
node->nextreduceable = reducelist[level];
|
||
reducelist[level] = node;
|
||
}
|
||
|
||
/* reduzcamos el arbol, pues K+1>size */
|
||
|
||
static void reducetree(void)
|
||
{
|
||
OCTREE node;
|
||
UINT depth;
|
||
|
||
getreduceable(&node);
|
||
node->leaf = 1;
|
||
size = size - node->children + 1;
|
||
depth = node->level;
|
||
if (depth < reducelevel) {
|
||
reducelevel = depth;
|
||
leaflevel = reducelevel + 1;
|
||
}
|
||
}
|
||
|
||
static UCHAR insert_rgb[3];
|
||
|
||
/* para insertar cada color dentro del arbol */
|
||
|
||
static void inserttree(OCTREE *tree, UINT depth)
|
||
{
|
||
UINT branch;
|
||
|
||
if (*tree == NULL)
|
||
newandinit(tree,depth);
|
||
(*tree)->colorcount++;
|
||
(*tree)->rgbsum.r += insert_rgb[RED];
|
||
(*tree)->rgbsum.g += insert_rgb[GREEN];
|
||
(*tree)->rgbsum.b += insert_rgb[BLUE];
|
||
if ((*tree)->leaf == FALSE && depth < leaflevel) {
|
||
branch = TESTBIT(insert_rgb[RED],MAXDEPTH - depth) * 4 +
|
||
TESTBIT(insert_rgb[GREEN],MAXDEPTH - depth) * 2 +
|
||
TESTBIT(insert_rgb[BLUE],MAXDEPTH - depth);
|
||
if ((*tree)->next[branch] == NULL) {
|
||
(*tree)->children++;
|
||
if ((*tree)->children == 2)
|
||
makereduceable(depth,*tree);
|
||
}
|
||
inserttree(&((*tree)->next[branch]), depth + 1);
|
||
}
|
||
}
|
||
|
||
|
||
void lee(FILE *uno,double gamm) /* funci¢n que leer la 1¦ vez el TGA */
|
||
{
|
||
union REGS regset;
|
||
struct SREGS sregset;
|
||
|
||
reducelevel = MAXDEPTH;
|
||
leaflevel = reducelevel + 1;
|
||
|
||
while (!feof(uno)) {
|
||
fread(&rgb_mio,3,1,uno);
|
||
insert_rgb[0]=rgb_mio[2]; // CUIDADO, valores de TGA tipo 2
|
||
insert_rgb[1]=rgb_mio[1]; // Estan BGR no RGB
|
||
insert_rgb[2]=rgb_mio[0];
|
||
inserttree(&tree, 0);
|
||
if (size > MAXCOLORS - 1) /* > K+1? (colores) */
|
||
reducetree();
|
||
}
|
||
calc_palette((unsigned int)0,gamm);
|
||
regset.x.ax=0x1012;
|
||
regset.x.bx=0;
|
||
regset.x.cx=256;
|
||
regset.x.dx=FP_OFF(palette);
|
||
sregset.es=FP_SEG(palette);
|
||
int86x(0x10,®set,®set,&sregset); /* interrupci¢n que carga y */
|
||
/* activa la paleta nueva */
|
||
}
|
||
|