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.
248 lines
5.4 KiB
C++
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;
|
|
}
|