⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 video.c

📁 quake3工具源码。包括生成bsp文件
💻 C
📖 第 1 页 / 共 2 页
字号:
			int shortest = -1;

			for ( i = 0; i < 4; i++ )
			{
				float d;

				if ( ( d = BTCDistanceSquared( inBlock[blockY][blockX], colorLine[i] ) ) < distance )
				{
					distance = d;
					shortest = i;
				}
			}

			error += distance;

			//
			// if bestError is not -1 then that means this is a speculative quantization
			//
			if ( bestError != -1 )
			{
				if ( error > bestError )
					return error;
			}

			btcQuantizedBlock[blockY][blockX] = shortest;
		}
	}

	return error;
}

/*
** float BTCCompressBlock
*/
static float BTCCompressBlock( float inBlock[4][4][3], unsigned long out[2] )
{
	int i;
	int btcQuantizedBlock[4][4];	// values should be [0..3]
	unsigned long encodedEndPoints, encodedBitmap;
	unsigned int endPoints[2][2];		// endPoints[0] = color start, endPoints[1] = color end
	int blockY, blockX;
	float error = 0;
	float bestError = 10000000000;
	unsigned int bestEndPoints[2][2];

#if 0
	//
	// find the "ideal" end points for the color vector 
	//
	BTCFindEndpoints( inBlock, endPoints );
	error = BTCQuantizeBlock( inBlock, endPoints, btcQuantizedBlock );
	memcpy( bestEndPoints, endPoints, sizeof( bestEndPoints ) );
#else
	for ( blockY = 0; blockY < 4; blockY++ )
	{
		for ( blockX = 0; blockX < 4; blockX++ )
		{
			int x2, y2;

			for ( y2 = 0; y2 < 4; y2++ )
			{
				for ( x2 = 0; x2 < 4; x2++ )
				{
					if ( ( x2 == blockX ) && ( y2 == blockY ) )
						continue;

					endPoints[0][0] = blockX;
					endPoints[0][1] = blockY;
					endPoints[1][0] = x2;
					endPoints[1][1] = y2;

					error = BTCQuantizeBlock( inBlock, endPoints, btcQuantizedBlock, -1 ); //bestError );

					if ( error < bestError )
					{
						bestError = error;
						memcpy( bestEndPoints, endPoints, sizeof( bestEndPoints ) );
					}
				}
			}
		}
	}

	error = BTCQuantizeBlock( inBlock, bestEndPoints, btcQuantizedBlock, -1.0f );
#endif

	//
	// encode the results
	//
	encodedBitmap = 0;
	for ( blockY = 0; blockY < 4; blockY++ )
	{
		for ( blockX = 0; blockX < 4; blockX++ )
		{
			int shift = ( blockX + blockY * 4 ) * 2;
			encodedBitmap |= btcQuantizedBlock[blockY][blockX] << shift;
		}
	}

	//
	// encode endpoints
	//
	encodedEndPoints = 0;
	for ( i = 0; i < 2; i++ )
	{
		int iR, iG, iB;

		iR = ( ( int ) inBlock[bestEndPoints[i][1]][bestEndPoints[i][0]][0] );
		if ( iR > 255 ) 
			iR = 255;
		else if ( iR < 0 ) 
			iR = 0;
		iR >>= 3;

		iG = ( ( int ) inBlock[bestEndPoints[i][1]][bestEndPoints[i][0]][1] );
		if ( iG > 255 )
			iG = 255;
		else if ( iG < 0 )
			iG = 0;
		iG >>= 2;

		iB = ( ( int ) inBlock[bestEndPoints[i][1]][bestEndPoints[i][0]][2] );
		if ( iB > 255 )
			iB = 255;
		else if ( iB < 0 )
			iB = 0;
		iB >>= 3;


		encodedEndPoints |= ( ( ( iR << 11 ) | ( iG << 5 ) | ( iB ) ) << ( i * 16 ) );
	}

	//
	// store 
	//
	out[0] = encodedBitmap;
	out[1] = encodedEndPoints;

	return error;
}

/*
** void BTCDecompressFrame
*/
static void BTCDecompressFrame( unsigned long *src, unsigned char *dst )
{
	int x, y;
	int iR, iG, iB;
	int dstX, dstY;
	float colorStart[3], colorEnd[3];
	unsigned char colorRampABGR[4][4];
	unsigned encoded;

	memset( colorRampABGR, 0xff, sizeof( colorRampABGR ) );

	for ( y = 0; y < s_resample_height / 4; y++ )
	{
		for ( x = 0; x < s_resample_width / 4; x++ )
		{
			unsigned colorStartPacked = src[(y*s_resample_width/4 + x)*2 + 1] & 0xffff;
			unsigned colorEndPacked = src[(y*s_resample_width/4 + x)*2 + 1] >> 16;

			//
			// grab the end points
			//   0 = color start
			//   1 = color end
			//
			iR = ( ( colorStartPacked >> 11 ) & ( ( 1 << 5 ) - 1 ) );
			iR = ( iR << 3 ) | ( iR >> 2 );
			iG = ( ( colorStartPacked >> 5 ) & ( ( 1 << 6 )  - 1 ) );
			iG = ( iG << 2 ) | ( iG >> 4 );
			iB = ( ( colorStartPacked ) & ( ( 1 << 5  ) - 1 ) );
			iB = ( iB << 3 ) | ( iB >> 2 );

			colorStart[0] = iR;
			colorStart[1] = iG;
			colorStart[2] = iB;
			colorRampABGR[0][0] = iR;
			colorRampABGR[0][1] = iG;
			colorRampABGR[0][2] = iB;

			iR = ( ( colorEndPacked >> 11 ) & ( ( 1 << 5 ) - 1 ) );
			iR = ( iR << 3 ) | ( iR >> 2 );
			iG = ( ( colorEndPacked >> 5 ) & ( ( 1 << 6 )  - 1 ) );
			iG = ( iG << 2 ) | ( iG >> 4 );
			iB = ( colorEndPacked & ( ( 1 << 5  ) - 1 ) );
			iB = ( iB << 3 ) | ( iB >> 2 );

			colorEnd[0] = iR;
			colorEnd[1] = iG;
			colorEnd[2] = iB;
			colorRampABGR[3][0] = iR;
			colorRampABGR[3][1] = iG;
			colorRampABGR[3][2] = iB;
			
			//
			// compute this block's color ramp
			// FIXME: This needs to be reversed on big-endian machines
			//
			
			colorRampABGR[1][0] = colorStart[0] * 0.66f + colorEnd[0] * 0.33f;
			colorRampABGR[1][1] = colorStart[1] * 0.66f + colorEnd[1] * 0.33f;
			colorRampABGR[1][2] = colorStart[2] * 0.66f + colorEnd[2] * 0.33f;

			colorRampABGR[2][0] = colorStart[0] * 0.33f + colorEnd[0] * 0.66f;
			colorRampABGR[2][1] = colorStart[1] * 0.33f + colorEnd[1] * 0.66f;
			colorRampABGR[2][2] = colorStart[2] * 0.33f + colorEnd[2] * 0.66f;

			//
			// decode the color data
			// information is encoded in 2-bit pixels, with low order bits corresponding
			// to upper left pixels.  These 2-bit values are indexed into the block's
			// computer color ramp.
			//
			encoded = src[(y*s_resample_width/4 + x)*2 + 0];

			for ( dstY = 0; dstY < 4; dstY++ )
			{
				for ( dstX = 0; dstX < 4; dstX++ )
				{
					memcpy( &dst[(y*4+dstY)*s_resample_width*4+x*4*4+dstX*4], colorRampABGR[encoded&3], sizeof( colorRampABGR[0] ) );
					encoded >>= 2;
				}
			}
		}
	}
}

/*
** BTCCompressFrame
**
** Perform a BTC compression using a 2-bit encoding at each pixel.  This
** compression method is performed by decomposing the incoming image into
** a sequence of 4x4 blocks.  At each block two color values are computed
** that define the endpoints of a vector in color space that represent
** the two colors "farthest apart".
*/
static float BTCCompressFrame( unsigned char *src, unsigned long *dst )
{
	int x, y;
	int bX, bY;
	float btcBlock[4][4][3];

	float error = 0;
	
	for ( y = 0; y < s_resample_height / 4; y++ )
	{
		for ( x = 0; x < s_resample_width / 4; x++ )
		{
			//
			// fill in the BTC block with raw values
			//
			for ( bY = 0; bY < 4; bY++ )
			{
				for ( bX = 0; bX < 4; bX++ )
				{
					btcBlock[bY][bX][0] = src[(y*4+bY)*s_resample_width*4 + (x*4+bX)*4 + 0];
					btcBlock[bY][bX][1] = src[(y*4+bY)*s_resample_width*4 + (x*4+bX)*4 + 1];
					btcBlock[bY][bX][2] = src[(y*4+bY)*s_resample_width*4 + (x*4+bX)*4 + 2];
				}
			}

			error += BTCCompressBlock( btcBlock, &dst[(y*s_resample_width/4+x)*2] );
		}
	}

	return error / ( ( s_resample_width / 4 ) * ( s_resample_height / 4 ) );
}

/*
===================
LoadFrame
===================
*/
cblock_t LoadFrame (char *base, int frame, int digits, byte **palette)
{
	int			ten3, ten2, ten1, ten0;
	cblock_t	in;
	int			width, height;
	char		name[1024];
	FILE		*f;

	in.data = NULL;
	in.count = -1;

	ten3 = frame/1000;
	ten2 = (frame-ten3*1000)/100;
	ten1 = (frame-ten3*1000-ten2*100)/10;
	ten0 = frame%10;

	if (digits == 4)
		sprintf (name, "%svideo/%s/%s%i%i%i%i.tga", gamedir, base, base, ten3, ten2, ten1, ten0);
	else
		sprintf (name, "%svideo/%s/%s%i%i%i.tga", gamedir, base, base, ten2, ten1, ten0);

	f = fopen(name, "rb");
	if (!f)
	{
		in.data = NULL;
		return in;
	}
	fclose (f);

	printf ("%s", name);
	LoadTGA( name, ( unsigned char ** ) &in.data, &width, &height );
	if ( palette )
		*palette = 0;
//	Load256Image (name, &in.data, palette, &width, &height);
	in.count = width*height;
	in.width = width;
	in.height = height;
// FIXME: map 0 and 255!

#if 0
	// rle compress
	rle = RLE(in);
	free (in.data);

	return rle;
#endif

	return in;
}

/*
===============
Cmd_Video

video <directory> <framedigits>
===============
*/
void Cmd_Video (void)
{
	float sumError = 0, error = 0, maxError = 0;
	char	savename[1024];
	char	name[1024];
	FILE	*output;
	int		startframe, frame;
	int		width, height;
	int		i;
	int		digits;
	int		minutes;
	float	fseconds;
	int		remSeconds;
	cblock_t	in;
	unsigned char *resampled;
	unsigned long *compressed;
	clock_t start, stop;

	GetToken (qfalse);
	strcpy (s_base, token);
	if (g_release)
	{
//		sprintf (savename, "video/%s.cin", token);
//		ReleaseFile (savename);
		return;
	}

	GetToken( qfalse );
	strcpy( s_output_base, token );

	GetToken (qfalse);
	digits = atoi(token);

	GetToken( qfalse );

	if ( !strcmp( token, "btc" ) )
	{
		s_compression_method = BTC_COMPRESSION;
		printf( "Compression: BTC\n" );
	}
	else if ( !strcmp( token, "uc" ) )
	{
		s_compression_method = UNCOMPRESSED;
		printf( "Compression: none\n" );
	}
	else
	{
		Error( "Uknown compression method '%s'\n", token );
	}

	GetToken( qfalse );
	s_resample_width = atoi( token );

	GetToken( qfalse );
	s_resample_height = atoi( token );

	resampled = malloc( sizeof( unsigned char ) * 4 * s_resample_width * s_resample_height );
	compressed = malloc( sizeof( long ) * 2 * ( s_resample_width / 4 ) * ( s_resample_height / 4 ) );

	printf( "Resample width: %d\n", s_resample_width );
	printf( "Resample height: %d\n", s_resample_height );

	// optionally skip frames
	if (TokenAvailable ())
	{
		GetToken (qfalse);
		startframe = atoi(token);
	}
	else
		startframe=0;

	sprintf (savename, "%svideo/%s.%s", writedir, s_output_base, CIN_EXTENSION );

	// load the entire sound wav file if present
	LoadSoundtrack ();

	if (digits == 4)
		sprintf (name, "%svideo/%s/%s0000.tga", gamedir, s_base, s_base);
	else
		sprintf (name, "%svideo/%s/%s000.tga", gamedir, s_base, s_base);

	printf ("%s\n", name);
	LoadTGA( name, NULL, &width, &height);

	output = fopen (savename, "wb");
	if (!output)
		Error ("Can't open %s", savename);

	// write header info
	i = LittleLong( CIN_SIGNATURE );
	fwrite (&i, 4, 1, output );
	i = LittleLong (s_resample_width);
	fwrite (&i, 4, 1, output);
	i = LittleLong (s_resample_height);
	fwrite (&i, 4, 1, output);
	i = LittleLong (s_wavinfo.rate);
	fwrite (&i, 4, 1, output);
	i = LittleLong (s_wavinfo.width);
	fwrite (&i, 4, 1, output);
	i = LittleLong (s_wavinfo.channels);
	fwrite (&i, 4, 1, output);
	i = LittleLong ( s_compression_method );
	fwrite (&i, 4, 1, output );

	start = clock();

	// perform compression on a per frame basis
	for ( frame=startframe ;  ; frame++)
	{
		printf ("%02d: ", frame);
		in = LoadFrame (s_base, frame, digits, 0 );
		if (!in.data)
			break;

		ResampleFrame( &in, ( unsigned char * ) resampled, BOX_FILTER, s_resample_width, s_resample_height );

		if ( s_compression_method == UNCOMPRESSED )
		{
			printf( "\n" );
			fwrite( resampled, 1, sizeof( unsigned char ) * s_resample_width * s_resample_height * 4, output );

#if OUTPUT_TGAS
			{
				int x, y;
				char buffer[1000];

				for ( y = 0; y < s_resample_height/2; y++ )
				{
					for ( x = 0; x < s_resample_width; x++ )
					{
						unsigned char tmp[4];

						tmp[0] = resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 0];
						tmp[1] = resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 1];
						tmp[2] = resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 2];
						tmp[3] = resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 3];

						resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 0] = resampled[y*s_resample_width*4 + x*4 + 0];
						resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 1] = resampled[y*s_resample_width*4 + x*4 + 1];
						resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 2] = resampled[y*s_resample_width*4 + x*4 + 2];
						resampled[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 3] = resampled[y*s_resample_width*4 + x*4 + 3];

						resampled[y*s_resample_width*4 + x*4 + 0] = tmp[0];
						resampled[y*s_resample_width*4 + x*4 + 1] = tmp[1];
						resampled[y*s_resample_width*4 + x*4 + 2] = tmp[2];
						resampled[y*s_resample_width*4 + x*4 + 3] = tmp[3];
					}
				}

				sprintf( buffer, "%svideo/%s/uc%04d.tga", gamedir, s_base, frame );
				WriteTGA( buffer, resampled, s_resample_width, s_resample_height );
			}
#endif
		}
		else if ( s_compression_method == BTC_COMPRESSION )
		{
			error = BTCCompressFrame( resampled, compressed );

			sumError += error;

			if ( error > maxError ) 
				maxError = error;

			printf( " (error = %f)\n", error );
			fwrite( compressed, 1, 2 * sizeof( long ) * ( s_resample_width / 4 ) * ( s_resample_height / 4 ), output );

#if OUTPUT_TGAS
			{
				int x, y;
				unsigned char *uncompressed;
				char buffer[1000];

				uncompressed = malloc( sizeof( unsigned char ) * 4 * s_resample_width * s_resample_height );
				BTCDecompressFrame( compressed, uncompressed );

				for ( y = 0; y < s_resample_height/2; y++ )
				{
					for ( x = 0; x < s_resample_width; x++ )
					{
						unsigned char tmp[4];

						tmp[0] = uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 0];
						tmp[1] = uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 1];
						tmp[2] = uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 2];
						tmp[3] = uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 3];

						uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 0] = uncompressed[y*s_resample_width*4 + x*4 + 0];
						uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 1] = uncompressed[y*s_resample_width*4 + x*4 + 1];
						uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 2] = uncompressed[y*s_resample_width*4 + x*4 + 2];
						uncompressed[(s_resample_height-1-y)*s_resample_width*4 + x*4 + 3] = uncompressed[y*s_resample_width*4 + x*4 + 3];

						uncompressed[y*s_resample_width*4 + x*4 + 0] = tmp[0];
						uncompressed[y*s_resample_width*4 + x*4 + 1] = tmp[1];
						uncompressed[y*s_resample_width*4 + x*4 + 2] = tmp[2];
						uncompressed[y*s_resample_width*4 + x*4 + 3] = tmp[3];
					}
				}


				sprintf( buffer, "%svideo/%s/btc%04d.tga", gamedir, s_base, frame );
				WriteTGA( buffer, uncompressed, s_resample_width, s_resample_height );

				free( uncompressed );
			}
#endif
		}

		WriteSound( output, frame );

		free (in.data);
	}
	stop = clock();

	printf ("\n");

	printf ("Total size: %i\n", ftell( output ) );
	printf ("Average error: %f\n", sumError / ( frame - startframe ) );
	printf ("Max error: %f\n", maxError );

	fseconds = ( stop - start ) / 1000.0f;
	minutes = fseconds / 60;
	remSeconds = fseconds - minutes * 60;

	printf ("Total time: %d s (%d m %d s)\n", ( int ) fseconds, minutes, remSeconds );
	printf ("Time/frame: %.2f seconds\n", fseconds / ( frame - startframe ) );

	fclose (output);

	if ( s_soundtrack )
	{
		free( s_soundtrack );
		s_soundtrack = 0;
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -