User:Chipsnapper2/HL2 Xbox Research/BSP Analysis

From Valve Developer Community
Jump to navigation Jump to search

Xbox BSPs have data in Lumps 51 and 52, yet they have no data in Lump 8. The opposite occurs on PC, where all lighting data is in Lump 8. As a result, Xbox BSPs appear fullbright on PC and PC BSPs appear fullbright on Xbox.

BSPInfo claims that Xbox BSPs have HDR data - this is incorrect. vbspinfo throws an "old version of lump 53" error.


BSPinfo PC.pngBSPinfo xbox.png

Lightmaps

In the Episode One (Source 2006) SDK, it looks like the code for VRAD's -xbox parameter still exists but is already marked as deprecated:

https://github.com/Source-SDK-Archives/source-sdk-2006-ep1/blob/master/utils/vrad/lightmap.cpp#L3976-L3982

https://github.com/Source-SDK-Archives/source-sdk-2006-ep1/blob/master/utils/vrad/vrad.cpp#L2053-L2059

https://github.com/Source-SDK-Archives/source-sdk-2006-ep1/blob/master/utils/vrad/lightmap.cpp#L4040-L4092C2


//-----------------------------------------------------------------------------
// Iterate surfaces generating cooked lightmap pages for palettizing
// Each page gets its own palette.
//-----------------------------------------------------------------------------
void BuildPalettedLightmaps( void )
{
	int		i;
	int		j;

	g_rawLightmapPages.Purge();
	g_currentMaterialName[0] = '\0';

	g_dLightmapPageInfos.Purge();

	CUtlRBTree< int, int >	surfaces( 0, numfaces, LightmapLess );
	for ( i = 0; i < numfaces; i++ )
	{
		surfaces.Insert( i );
	}

	// surfaces must be iterated in order to achieve proper lightmap allocation
	for ( i = surfaces.FirstInorder(); i != surfaces.InvalidIndex(); i = surfaces.NextInorder(i) )
	{
		dface_t *pFace = &g_pFaces[surfaces[i]];

		bool hasLightmap = (texinfo[pFace->texinfo].flags & SURF_NOLIGHT) == 0;
		if ( hasLightmap && pFace->lightofs != -1 )
		{
			RegisterLightmappedSurface( pFace );
		}
		else
		{
			pFace->lightofs = -1;
		}

		// remove unsupported light styles
		for (j=0; j<MAXLIGHTMAPS; j++)
			pFace->styles[j] = 255;
	}

	// convert cooked 32b lightmap pages into their palettized versions
	PalettizeLightmaps();

	for (i=0; i<g_rawLightmapPages.Count(); i++)
		free( g_rawLightmapPages[i] );
	
	g_rawLightmapPages.Purge();
	g_ImagePackers.Purge();
	
	// no longer require raw rgb light data
	// ensure light data doesn't get serialized
	pdlightdata->Purge();
}

//-----------------------------------------------------------------------------
// Quantize the 32b lightmap pages into a palettized equivalent ready for serialization
//-----------------------------------------------------------------------------
void PalettizeLightmaps( void )
{
	uint8	*pPixels;
	uint8	*pPalette3;
	uint8	*pPalette4;
	int		i;
	int		j;

	g_dLightmapPages.Purge();
	g_dLightmapPages.EnsureCount( g_rawLightmapPages.Count() );

	if ( g_bExportLightmaps )
	{
		// write out the raw 32bpp lightmap page
		for ( i=0; i<g_rawLightmapPages.Count(); ++i )
		{	
			char	buff[256];
			sprintf( buff, "lightmap_%2.2d.tga", i );

			CUtlBuffer outBuf;
			TGAWriter::WriteToBuffer( 
				g_rawLightmapPages[i], outBuf, MAX_LIGHTMAPPAGE_WIDTH, 
				MAX_LIGHTMAPPAGE_HEIGHT, IMAGE_FORMAT_RGBA8888, IMAGE_FORMAT_RGBA8888 );
			g_pFileSystem->WriteFile( buff, NULL, outBuf );			
		}
	}

	pPixels   = (uint8 *)malloc( MAX_LIGHTMAPPAGE_WIDTH*MAX_LIGHTMAPPAGE_HEIGHT );
	pPalette3 = (uint8 *)malloc( 256*3 );
	pPalette4 = (uint8 *)malloc( 256*4 );

	for (i=0; i<g_rawLightmapPages.Count(); i++)
	{	
		// remap to 256x3 palette
		ColorQuantize( 
			g_rawLightmapPages[i], 
			MAX_LIGHTMAPPAGE_WIDTH, 
			MAX_LIGHTMAPPAGE_HEIGHT,
			QUANTFLAGS_NODITHER,
			256,
			pPixels,
			pPalette3,
			0 );

		// fixup 256x3 rgb palette to d3d 256x4 bgra
		for (j=0; j<256; j++)
		{
			pPalette4[j*4+0] = pPalette3[j*3+2];
			pPalette4[j*4+1] = pPalette3[j*3+1];
			pPalette4[j*4+2] = pPalette3[j*3+0];
			pPalette4[j*4+3] = 0xFF;
		}

		SwizzleRect( pPixels, g_dLightmapPages[i].data, MAX_LIGHTMAPPAGE_WIDTH, MAX_LIGHTMAPPAGE_HEIGHT, 1 );
		memcpy( g_dLightmapPages[i].palette, pPalette4, 256*4 );

		if ( g_bExportLightmaps && g_pFullFileSystem )
		{
			// write out the palettize page
			byte *pRaw4 = (byte *)malloc( MAX_LIGHTMAPPAGE_WIDTH*MAX_LIGHTMAPPAGE_HEIGHT*4 );
			for (j=0; j<MAX_LIGHTMAPPAGE_WIDTH*MAX_LIGHTMAPPAGE_HEIGHT; j++)
			{
				// index the palette, fixup to tga rgba order
				int color = pPixels[j]*4;
				pRaw4[j*4+0] = pPalette4[color+2];
				pRaw4[j*4+1] = pPalette4[color+1];
				pRaw4[j*4+2] = pPalette4[color+0];
				pRaw4[j*4+3] = pPalette4[color+3];
			}

			char	buff[256];
			sprintf(buff, "lightmap_%2.2d_256.tga", i);

			CUtlBuffer outBuf;
			TGAWriter::WriteToBuffer( 
				pRaw4, 
				outBuf, 
				MAX_LIGHTMAPPAGE_WIDTH, 
				MAX_LIGHTMAPPAGE_HEIGHT, 
				IMAGE_FORMAT_RGBA8888, 
				IMAGE_FORMAT_RGBA8888 );
			g_pFullFileSystem->WriteFile( buff, NULL, outBuf );

			free( pRaw4 );
		}
	}

	free( pPixels );
	free( pPalette3 );
	free( pPalette4 );
}

This is one of the last methods that runs in VRAD's main - it takes the lightmaps and converts them from 32-bit color 'pages' to a 256x3 RGB palette, then converts that to a 256x4 BGRA texture.

After that, it clears the RGB palette from the file, then destroys any PC lightmaps. From there, we now see the Xbox light palettes in lumps 51/52!