Example #1
0
geBitmap_Palette * createPaletteFast(const geBitmap_Info * Info,const void * Bits)
{
octNode * root;
int nLeaves,minCount,gotLeaves;
octNode ** leaves,**leavesPtr;
uint8 palette[768];
int palEntries = 256;
geBitmap_Palette * Pal;

	pushTSC();

	// read the whole image into an octree
	//	this is the only pass over the input plane

	MemPool_Reset(octNodePool);
	root = MemPool_GetHunk(octNodePool);
	assert(root);
	nLeaves = createOctTree(root,Info,Bits,GE_FALSE);

	leaves = geRam_AllocateClear(sizeof(octNode *)*nLeaves);
	assert(leaves);
	
	// gather leaves into a linear array
	//	for speed we ignore leaves with a count lower than [x]

	gotLeaves = 0;
	for( minCount = 3; minCount >= 0 && gotLeaves < palEntries ; minCount-- )
	{
		leavesPtr = leaves;
		gatherLeaves(root,&leavesPtr,minCount);
		gotLeaves = ((uint32)leavesPtr - (uint32)leaves)/sizeof(octNode *);
	}

	// sort the leaves by count

	qsort(leaves,gotLeaves,sizeof(octNode *),leafCompareCount);

	// read the sorted leaves in by count; we try to only read in leaves
	//	that are farther than 'minDistance' from nodes already in the palette

	readLeavesToPal(leaves,gotLeaves,palette,palEntries);

	destroy(leaves);

	showPopTSC("createPalFast");

	Pal = geBitmap_Palette_Create(GE_PIXELFORMAT_24BIT_RGB,palEntries);
	if ( ! Pal )
		return NULL;
	if ( ! geBitmap_Palette_SetData(Pal,palette,GE_PIXELFORMAT_24BIT_RGB,palEntries) )
		assert(0);
return Pal;
}
Example #2
0
geBitmap_Palette * createPaletteGoodSub(const geBitmap_Info * Info,const void * Bits)
{
octNode * root;
int nLeaves,i,gotLeaves,radixN;
octNode ** leaves,**leavesPtr;
octNode *leaf,*node;
octNode *radix;
uint8 palette[768],*palPtr;
int palEntries = 256;
geBitmap_Palette * Pal;

	pushTSC();

	// read the whole image into an octree
	//	this is the only pass over the input plane

	MemPool_Reset(octNodePool);
	root = MemPool_GetHunk(octNodePool);
	assert(root);

	nLeaves = createOctTree(root,Info,Bits,GE_TRUE);

	leaves = geRam_AllocateClear(sizeof(octNode *)*nLeaves);
	assert(leaves);

	computeOctRGBs(root);
	root->parent = root;
	computeCutCosts(root);
	root->parent = NULL;
	
	// gather leaves into a linear array
	//	for speed we ignore leaves with a count lower than [x]

	leavesPtr = leaves;
	gatherLeavesCutting(root,&leavesPtr);
	gotLeaves = ((uint32)leavesPtr - (uint32)leaves)/sizeof(octNode *);

	// if gotLeaves < palEntries, just exit asap
	if ( gotLeaves < palEntries )
	{
		readLeavesToPal(leaves,gotLeaves,palette,palEntries);
		goto done;
	}

	// sort the leaves by cutCost
	// radix sort instead of qsort

	radix = geRam_AllocateClear(sizeof(octNode)*RADIX_SIZE);
	assert(radix);

	for(i=0;i<RADIX_SIZE;i++)
		radix[i].next = radix[i].prev = &radix[i];

	for(i=0;i<gotLeaves;i++)
		insertRadix(radix,leaves[i]);

	// keep cutting the tail
	radixN = 0;
	while(gotLeaves > palEntries)
	{
		while( (leaf = radix[radixN].next) == &(radix[radixN]) )
		{
			radixN++;
			assert( radixN < RADIX_SIZE );
		}
		// cut it
		leaf->prev->next = leaf->next;
		leaf->next->prev = leaf->prev;

		node = leaf->parent;
		assert(node);
		node->nKids --;

		// might turn its parent into a leaf;
		// if so, add it to the list
			// nKids no longer corresponds to the actual number of active kids

		if ( node->nKids == 0 )
			insertRadix(radix,node);
		else
			gotLeaves--;
	}

	// read the sorted leaves in by count; we try to only read in leaves
	//	that are farther than 'minDistance' from nodes already in the palette

	palPtr = palette;
	radixN = RADIX_SIZE-1;
	leaf = radix[radixN].prev;	
	for(i=0;i<palEntries && radixN>0;i++)
	{
		*palPtr++ = leaf->R;
		*palPtr++ = leaf->G;
		*palPtr++ = leaf->B;
		leaf = leaf->prev;
		while ( leaf == &(radix[radixN]) )
		{
			radixN --;
			if ( ! radixN )
				break;
			leaf = radix[radixN].prev;
		}
	}

	destroy(radix);

done:

	destroy(leaves);

	showPopTSC("createPalGood");

	YUVb_to_RGBb_line(palette,palette,palEntries);

	Pal = geBitmap_Palette_Create(GE_PIXELFORMAT_24BIT_RGB,palEntries);
	if ( ! Pal )
		return NULL;

	if ( ! geBitmap_Palette_SetData(Pal,palette,GE_PIXELFORMAT_24BIT_RGB,palEntries) )
		assert(0);

return Pal;
}
Example #3
0
void paletteOptimize(const geBitmap_Info * BmInfo,const void * Bits,uint8 *palette,int palEntries,int maxSamples)
{
palInfo *palInfo;
int pal,R,G,B,A;
uint32 mse,last_mse;
uint8 *palPtr;
uint8 savePalette[768];
int extraStepIndex,extraStepSize,extraStepSizeBytes=0,samples,totSamples;
gePixelFormat_ColorGetter GetColor;
const gePixelFormat_Operations * PixelOps;
uint8 *ptr,*ptrEnd;
int d;
palOptInfo optInfo[256];

	assert(palEntries <= 256);

	pushTSC();

	// palette is 768 bytes

	R = palette[(palEntries-1)*3 + 0];
	G = palette[(palEntries-1)*3 + 1];
	B = palette[(palEntries-1)*3 + 2];
	for(pal=palEntries;pal<256;pal++)
	{
		palette[pal*3 + 0] = R;
		palette[pal*3 + 1] = G;
		palette[pal*3 + 2] = B;
	}

	PixelOps = gePixelFormat_GetOperations(BmInfo->Format);
	GetColor = PixelOps->GetColor;
	ptrEnd = (uint8 *)Bits + BmInfo->Stride * BmInfo->Height * PixelOps->BytesPerPel;

	mse = ~(uint32)0;
	extraStepIndex = 0;
	extraStepSize = -1;
	totSamples = 0;
	if ( maxSamples <= 0 ) maxSamples = 0x0FFFFFFF;
	for(;;)
	{
		if ( extraStepSize != 0 )
		{
			extraStepSize = ( stepTable[ extraStepIndex ] - 1 );
			extraStepSizeBytes = extraStepSize * PixelOps->BytesPerPel;
			extraStepIndex++;
		}

		last_mse = mse;

		// <> this 'closestPal' is not great for this application
		//		it's approximate & has a large initialization overhead
		//	 we should use the methods from the "Local K-Means" paper

		palInfo = closestPalInit(palette);
		if ( ! palInfo ) return;

		memclear(optInfo,sizeof(palOptInfo)*palEntries);

		mse = 0;
		samples =0;
		ptr = (uint8 *)Bits;
		while( ptr < ptrEnd )
		{
			GetColor(&ptr,&R,&G,&B,&A);

			pal = closestPal(R,G,B,palInfo);

			if ( pal >= palEntries ) pal = palEntries-1;			
		
			palPtr = palette + pal*3;
			d = R - (*palPtr++);	mse += d*d;
			d = G - (*palPtr++);	mse += d*d;
			d = B - (*palPtr  );	mse += d*d;

			optInfo[pal].totR += R;
			optInfo[pal].totG += G;
			optInfo[pal].totB += B;
			optInfo[pal].count ++;

			ptr += extraStepSizeBytes;
			samples ++;
		}

		closestPalFree(palInfo);

		if ( samples == 0 ) continue;
		mse = (int)(((double)mse*256.0)/samples);
		totSamples += samples;

		if ( mse >= last_mse && extraStepSize == 0 )
		{
			memcpy(palette,savePalette,768);
			mse = last_mse;
			break;
		}
		else if ( mse > last_mse )
		{
#if 0
			// seems to slow convergence (!?)
			memcpy(palette,savePalette,768);
			mse = last_mse;
#endif
		}
		else
		{
			memcpy(savePalette,palette,768);
		}
	
		Log_Printf("mse*256 = %7d , extrastep = %4d, samples = %7d\n",mse,extraStepSize,samples);

		if ( totSamples >= maxSamples )
			break;

		for(pal=0,palPtr = palette; pal<palEntries ; pal++,palPtr += 3)
		{
		double fd;
		int diffR,diffG,diffB;

			if ( optInfo[pal].count == 0 ) continue;

			fd = 1.0 / optInfo[pal].count;

			diffR = (int)(optInfo[pal].totR * fd) - palPtr[0];
			diffG = (int)(optInfo[pal].totG * fd) - palPtr[1];
			diffB = (int)(optInfo[pal].totB * fd) - palPtr[2];

#if 1
			#define DIV(diff)	if ( diff < 0 ) diff = - ((-diff + 1)>>1); else if ( diff > 0 ) diff = ((diff + 1)>>1)
			DIV(diffR);
			DIV(diffG);
			DIV(diffB);
#endif

#if 0
			// this helps sometimes, hurts sometimes
			diffR = GaussianRand(diffR,abs(diffR));
			diffG = GaussianRand(diffG,abs(diffG));
			diffB = GaussianRand(diffB,abs(diffB));
#endif

			palPtr[0] = minmax( palPtr[0]+diffR , 0,255);
			palPtr[1] = minmax( palPtr[1]+diffG , 0,255);
			palPtr[2] = minmax( palPtr[2]+diffB , 0,255);
		}
		
		if ( abs(mse - last_mse) < 50 && extraStepSize == 0 )
		{
			break;
		}
	}

	showPopTSC("palOptimize");
}
Example #4
0
//=====================================================================================
//	Vis_VisWorld
//=====================================================================================
geBoolean Vis_VisWorld(geEngine *Engine, geWorld *World, const geCamera *Camera, Frustum_Info *Fi)
{
	uint8			*VisData;
	int32			k, i, Area;
	GFX_Node		*GFXNodes;
	GFX_Leaf		*GFXLeafs;
	Surf_SurfInfo	*SurfInfo;
	uint8			*GFXVisData;
	int32			Leaf, Cluster;
	GFX_Model		*GFXModels;
	int32			*GFXLeafFaces;
	GFX_Cluster		*GFXClusters;
	GBSP_BSPData	*BSPData;
	geWorld_Model	*Models;
	const geVec3d	*Pos;
	GFX_Leaf		*pLeaf;

#ifdef _TSC
	pushTSC();
#endif

	Pos = geCamera_GetVisPov(Camera);

	BSPData = &World->CurrentBSP->BSPData;

	GFXNodes = BSPData->GFXNodes;
	GFXLeafs = BSPData->GFXLeafs;
	GFXClusters = BSPData->GFXClusters;
	GFXVisData = BSPData->GFXVisData;
	GFXModels = BSPData->GFXModels;
	GFXLeafFaces = BSPData->GFXLeafFaces;

	SurfInfo = World->CurrentBSP->SurfInfo;

	Leaf = Plane_FindLeaf(World, GFXModels[0].RootNode[0], Pos);
	Area = GFXLeafs[Leaf].Area;

	// Check to see if we cen get rid of most of the work load by seeing if the leaf has not changed...
	if (World->CurrentLeaf == Leaf && !World->ForceVis)
		goto LeafDidNotChange;

	World->ForceVis = GE_FALSE;			// Reset force vis flag
	
	World->CurrentLeaf = Leaf;

	World->CurFrameStatic++;			// Make all old vis info obsolete

	Cluster = GFXLeafs[Leaf].Cluster;

	if (Cluster == -1 || GFXClusters[Cluster].VisOfs == -1)
	{
		World->VisInfo = GE_FALSE;
		return GE_TRUE;
	}

	if (Area)
		Vis_FloodAreas_r(World, Area);

	World->VisInfo = GE_TRUE;

	VisData = &GFXVisData[GFXClusters[Cluster].VisOfs];

	// Mark all visible clusters
	for (i=0; i<GFXModels[0].NumClusters; i++)
	{
		if (VisData[i>>3] & (1<<(i&7)) )
			World->CurrentBSP->ClusterVisFrame[i] = World->CurFrameStatic;
	}

	pLeaf = &GFXLeafs[GFXModels[0].FirstLeaf];

	// Go through and find all visible leafs based on the visible clusters the leafs are in
	for (i=0; i< GFXModels[0].NumLeafs; i++, pLeaf++)
	{
		int32	*pFace;

		Cluster = pLeaf->Cluster;

		if (Cluster == -1)		// No cluster info for this leaf (must be solid)
			continue;

		// If the cluster is not visible, then the leaf is not visible
		if (World->CurrentBSP->ClusterVisFrame[Cluster] != World->CurFrameStatic)
			continue;
		
		// If the area is not visible, then the leaf is not visible
		if (World->CurrentBSP->AreaVisFrame[pLeaf->Area] != World->CurFrameStatic)
			continue;

		// Mark all visible nodes by bubbling up the tree from the leaf
		MarkVisibleParents(World, i);

		// Mark the leafs vis frame to worlds current frame
		World->CurrentBSP->LeafData[i].VisFrame = World->CurFrameStatic;
			
		pFace = &GFXLeafFaces[pLeaf->FirstFace];

		// Go ahead and vis surfaces here...
		for (k=0; k< pLeaf->NumFaces; k++)
		{
			// Update each surface infos visframe thats touches each visible leaf
			SurfInfo[*pFace++].VisFrame = World->CurFrameStatic;
		}
	}

	LeafDidNotChange:

	// The world is always visible as a model
	World->CurrentBSP->Models[0].VisFrame = World->CurFrameDynamic;

	Models = &World->CurrentBSP->Models[1];
	// Do models, skipping world models (it's always visible)
	for (i=1; i< BSPData->NumGFXModels; i++, Models++)
	{
	#if 0
		int32		Cluster;

		// First, lets cheat, and see if the center is in a valid location to test for vis
		Leaf = Plane_FindLeaf(World, GFXModels[0].RootNode[0], &Models->Pivot);

		Cluster = GFXLeafs[Leaf].Cluster;

		if (Cluster >= 0 && GFXClusters[Cluster].VisOfs >= 0)		// If there is vis data for this leaf
		{
			if (World->CurrentBSP->LeafData[Leaf].VisFrame == World->CurFrameStatic)
				Models->VisFrame = World->CurFrameDynamic;
			else
			{
				GFX_Model	*pModel;

				pModel = &BSPData->GFXModels[i];

				if (pModel->Areas[0] == Area || pModel->Areas[1] == Area && 
					World->CurrentBSP->ClusterVisFrame[Cluster] == World->CurFrameStatic)
					Models->VisFrame = World->CurFrameDynamic;
			}
		}
		else if (ModelVisible(World, Models))
			Models->VisFrame = World->CurFrameDynamic;
	#else
		
		if (ModelVisible(World, Models))
			Models->VisFrame = World->CurFrameDynamic;
		
	#endif
		
		Models->ChangedFlags &= ~MODEL_CHANGED_XFORM;
	}
	
	VisFog(Engine, World, Camera, Fi, Area);

#ifdef _TSC
	showPopTSC("Vis_VisWorld");
#endif
	
	return GE_TRUE;
}