Files
firestorm/Gameleap/code/mw4/Libraries/imagelib/OctTree.cpp
T
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

248 lines
5.4 KiB
C++

#include"octtree.h"
#include"image.h"
// Build octree
BOOL OctQuant::BuildTree()
{
int row; // Row counter
int col; // Column counter
BOOL status = TRUE; // Return status
ImgRGBColor color; // Pixel color
// Allocate octree root node
proot=MakeNode(0);
// Build the octree
for (row = 0; row < height; row++)
for (col = 0; col < width; col++)
{
color.Set(*(RGBPixel *)(olddata+col+row*image->Pitch),image->Mask);
InsertNode(proot, color);
if (num_leaf > max_color) ReduceTree();
}
return status;
}
// Recursively delete octree nodes
void OctQuant::DeleteNode( OctNode *pn )
{
int i; // Loop index
OctNode *pc; // Child node pointer
if (pn==NULL) return;
if (pn->IsLeaf() == FALSE)
{
// Delete child nodes
for (i = 0; i < 8; i++)
if ((pc = pn->GetChild(i)) != NULL)
{
DeleteNode(pc);
pn->SetChild(i, NULL);
pn->DecNumChild();
}
}
else num_leaf--;
delete pn;
}
// Set color palette entries
void OctQuant::FillPalette( OctNode *pn, int *pindex)
{
int i; // Loop index
// Perform recursive depth-first traversal of octree
if (pn != NULL)
{
if ((pn->IsLeaf()==TRUE) || pn->GetLevel()==leaf_level)
{
// Set color palette entry
image->AllocPal();
image->pal[*pindex] = pn->GetColor();
// Set node color palette index
pn->SetIndex(*pindex);
// Advance to next color palette entry
*pindex = *pindex + 1;
}
else
{
// Visit child nodes
for (i = 0; i < 8; i++)
FillPalette(pn->GetChild(i), pindex);
}
}
}
// Get next reducible node pointer
OctNode *OctQuant::GetReducible()
{
int new_level; // New reducible node level
OctNode *prn; // Reducible node pointer
OctNode *plcn = NULL; // Largest pixel count node
OctNode *pnext; // Next node
OctNode *pprev; // Previous node
new_level = leaf_level - 1;
// Find lowest reducible node level
while (prnl[new_level] == NULL)
new_level--;
// Find node with largest pixel count
prn = prnl[new_level];
while (prn != NULL)
{
if (plcn == NULL)
plcn = prn;
else if (prn->GetCount() < plcn->GetCount())
plcn = prn;
prn = prn->GetNext();
}
// Remove node from reducible list
pnext = plcn->GetNext();
pprev = plcn->GetPrev();
if (pprev == NULL)
{
prnl[new_level] = pnext;
if (pnext != NULL)
pnext->SetPrev(NULL);
}
else
{
pprev->SetNext(pnext);
if (pnext != NULL)
pnext->SetPrev(pprev);
}
plcn->SetNext(NULL);
plcn->SetPrev(NULL);
plcn->SetMark(FALSE);
return plcn;
}
void OctQuant::ReduceTree() // Reduce octree
{
int i; // Loop index
OctNode *pn; // Node pointer
OctNode *pc; // Child node pointer
pn = GetReducible(); // Get next reducible node
// Delete children
for (i = 0; i < 8; i++)
{
if ((pc = pn->GetChild(i)) != NULL)
{
DeleteNode(pc);
pn->SetChild(i, NULL);
pn->DecNumChild();
}
}
pn->SetLeaf(TRUE); // Mark node as leaf
num_leaf++; // Increment leaf count
// Update reduction and leaf levels
if (pn->GetLevel() < (leaf_level - 1))
leaf_level = pn->GetLevel() + 1;
}
// Insert node into octree
BOOL OctQuant::InsertNode( OctNode *pn, ImgRGBColor &c)
{
int c_index; // Child index
int level; // Node level
BOOL status = TRUE; // Return status
OctNode *pc; // Child node pointer
level = pn->GetLevel(); // Get node level
pn->AddColor(c); // Add RGB color to node
if (pn->IsLeaf() == FALSE && level < leaf_level)
{
// Find child node
c_index = pn->FindChild(c);
if ((pc = pn->GetChild(c_index)) == NULL)
{
// Allocate child node
if ((pc = MakeNode(level + 1)) == NULL)
return FALSE;
// Set child node pointer
pn->SetChild(c_index, pc);
pn->IncNumChild(); // Increment child count
}
if ((pn->GetNumChild() > 1) && (pn->IsMark() == FALSE))
{
// Mark node as candidate for reduction
MakeReducible(pn);
}
// Insert child node into octree
status = InsertNode(pc, c);
}
return status;
}
BOOL OctQuant::MapColors()
{
int row,col; // Row counter
ImgRGBColor color; // 24-bit RGB color
int psize=(image->Bpp>>3);
int x,axl=width*psize;
// Quantize the bitmap colors
for (row=0; row < height; row++)
for (x=0,col=0; x<axl; col++,x+=psize)
{
color.Set(*(RGBPixel *)(olddata+x+row*image->Pitch),image->Mask);
newdata[col+row*image->xlen]=(BYTE)QuantizeColor(proot, color);
}
return TRUE;
}
BOOL OctQuant::Quantize(Image *img)
{
BOOL status = TRUE; // Return status
image=img;
newdata=new BYTE[image->xlen*image->ylen];
olddata=image->Lock();
image->AllocPal();
for(int i=0;i<O_NumColor;i++) image->pal[i]=0;
width=image->xlen;
height=image->ylen;
int ncol=0;
status=BuildTree();
FillPalette(proot,&ncol);
status=MapColors();
DeleteTree(); // Delete color quantization octree
image->UnLock();
image->Bpp=8;
image->itype=ITYPE_INDEXED;
image->IAlloc();
image->AllocPal();
image->SetData(newdata);
image->RealizePalette();
delete newdata;
return status;
}