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

📄 video.c

📁 quake3工具源码。包括生成bsp文件
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <assert.h>
#include "q3data.h"

static int s_resample_width = 256;
static int s_resample_height = 256;

#define OUTPUT_TGAS			1

#define UNCOMPRESSED		0
#define BTC_COMPRESSION		1

static int s_compression_method = BTC_COMPRESSION;

static const char *CIN_EXTENSION = "cn2";
static const int CIN_SIGNATURE = ( 'C' << 24 ) | ( 'I' << 16 ) | ( 'N' << 8 ) | ( '2' );

static byte	*s_soundtrack;
static char	s_base[32];
static char	s_output_base[32];

/*
===============================================================================

WAV loading

===============================================================================
*/

typedef struct
{
	int			rate;
	int			width;
	int			channels;
	int			loopstart;
	int			samples;
	int			dataofs;		// chunk starts this many bytes from file start
} wavinfo_t;


byte	*data_p;
byte 	*iff_end;
byte 	*last_chunk;
byte 	*iff_data;
int 	iff_chunk_len;


static int			s_samplecounts[0x10000];
static wavinfo_t	s_wavinfo;

short GetLittleShort(void)
{
	short val = 0;
	val = *data_p;
	val = val + (*(data_p+1)<<8);
	data_p += 2;
	return val;
}

int GetLittleLong(void)
{
	int val = 0;
	val = *data_p;
	val = val + (*(data_p+1)<<8);
	val = val + (*(data_p+2)<<16);
	val = val + (*(data_p+3)<<24);
	data_p += 4;
	return val;
}

void FindNextChunk(char *name)
{
	while (1)
	{
		data_p=last_chunk;

		if (data_p >= iff_end)
		{	// didn't find the chunk
			data_p = NULL;
			return;
		}
		
		data_p += 4;
		iff_chunk_len = GetLittleLong();
		if (iff_chunk_len < 0)
		{
			data_p = NULL;
			return;
		}
//		if (iff_chunk_len > 1024*1024)
//			Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
		data_p -= 8;
		last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
		if (!strncmp(data_p, name, 4))
			return;
	}
}

void FindChunk(char *name)
{
	last_chunk = iff_data;
	FindNextChunk (name);
}


void DumpChunks(void)
{
	char	str[5];
	
	str[4] = 0;
	data_p=iff_data;
	do
	{
		memcpy (str, data_p, 4);
		data_p += 4;
		iff_chunk_len = GetLittleLong();
		printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
		data_p += (iff_chunk_len + 1) & ~1;
	} while (data_p < iff_end);
}

/*
============
GetWavinfo
============
*/
wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
{
	wavinfo_t	info;
	int     i;
	int     format;
	int		samples;

	memset (&info, 0, sizeof(info));

	if (!wav)
		return info;
		
	iff_data = wav;
	iff_end = wav + wavlength;

// find "RIFF" chunk
	FindChunk("RIFF");
	if (!(data_p && !strncmp(data_p+8, "WAVE", 4)))
	{
		printf("Missing RIFF/WAVE chunks\n");
		return info;
	}

// get "fmt " chunk
	iff_data = data_p + 12;
// DumpChunks ();

	FindChunk("fmt ");
	if (!data_p)
	{
		printf("Missing fmt chunk\n");
		return info;
	}
	data_p += 8;
	format = GetLittleShort();
	if (format != 1)
	{
		printf("Microsoft PCM format only\n");
		return info;
	}

	info.channels = GetLittleShort();
	info.rate = GetLittleLong();
	data_p += 4+2;
	info.width = GetLittleShort() / 8;

// get cue chunk
	FindChunk("cue ");
	if (data_p)
	{
		data_p += 32;
		info.loopstart = GetLittleLong();
//		Com_Printf("loopstart=%d\n", sfx->loopstart);

	// if the next chunk is a LIST chunk, look for a cue length marker
		FindNextChunk ("LIST");
		if (data_p)
		{
			if (!strncmp (data_p + 28, "mark", 4))
			{	// this is not a proper parse, but it works with cooledit...
				data_p += 24;
				i = GetLittleLong ();	// samples in loop
				info.samples = info.loopstart + i;
			}
		}
	}
	else
		info.loopstart = -1;

// find data chunk
	FindChunk("data");
	if (!data_p)
	{
		printf("Missing data chunk\n");
		return info;
	}

	data_p += 4;
	samples = GetLittleLong ();

	if (info.samples)
	{
		if (samples < info.samples)
			Error ("Sound %s has a bad loop length", name);
	}
	else
		info.samples = samples;

	info.dataofs = data_p - wav;

	return info;
}

//=====================================================================

/*
==============
LoadSoundtrack
==============
*/
void LoadSoundtrack (void)
{
	char	name[1024];
	FILE	*f;
	int		len;
	int     i, val, j;

	s_soundtrack = NULL;
	sprintf (name, "%svideo/%s/%s.wav", gamedir, s_base, s_base);
	printf ("WAV: %s\n", name);
	f = fopen (name, "rb");
	if (!f)
	{
		printf ("no soundtrack for %s\n", s_base);
		return;
	}
	len = Q_filelength(f);
	s_soundtrack = malloc(len);
	fread (s_soundtrack, 1, len, f);
	fclose (f);

	s_wavinfo = GetWavinfo (name, s_soundtrack, len);

	// count samples for compression
	memset (s_samplecounts, 0, sizeof(s_samplecounts));

	j = s_wavinfo.samples/2;
	for (i=0 ; i<j ; i++)
	{
		val = ((unsigned short *)( s_soundtrack + s_wavinfo.dataofs))[i];
		s_samplecounts[val]++;
	}
	val = 0;
	for (i=0 ; i<0x10000 ; i++)
		if (s_samplecounts[i])
			val++;

	printf ("%i unique sample values\n", val);
}

/*
==================
WriteSound
==================
*/
void WriteSound (FILE *output, int frame)
{
	int		start, end;
	int		count;
	int		empty = 0;
	int		i;
	int		sample;
	int		width;

	width = s_wavinfo.width * s_wavinfo.channels;

	start = frame*s_wavinfo.rate/14;
	end = (frame+1)*s_wavinfo.rate/14;
	count = end - start;

	for (i=0 ; i<count ; i++)
	{
		sample = start+i;
		if (sample > s_wavinfo.samples || !s_soundtrack)
			fwrite (&empty, 1, width, output);
		else
			fwrite (s_soundtrack + s_wavinfo.dataofs + sample*width, 1, width,output);
	}
}

//==========================================================================

static float s_resampleXRatio;
static float s_resampleYRatio;

static void BoxFilterHorizontalElements( unsigned char *dst, unsigned char *src, float s0, float s1 )
{
	float w;
	float rSum = 0, gSum = 0, bSum = 0;
	float x = s0;
	float sumWeight = 0;

	for ( x = s0; x < s1; x++, src += 4 )
	{
		if ( x == s0 )
		{
			w = ( int ) ( s0 + 1 ) - x;
		}
		else if ( x + 1 >= s1 )
		{
			w = s1 - ( int ) x;
		}
		else
		{
			w = 1.0f;
		}

		rSum += src[0] * w;
		gSum += src[1] * w;
		bSum += src[2] * w;
		sumWeight += w;
	}

	rSum /= sumWeight;
	gSum /= sumWeight;
	bSum /= sumWeight;

	dst[0] = ( unsigned char ) ( rSum + 0.5 );
	dst[1] = ( unsigned char ) ( gSum + 0.5 );
	dst[2] = ( unsigned char ) ( bSum + 0.5 );
}

static void BoxFilterVerticalElements( unsigned char *dst, // destination of the filter process
									   unsigned char *src, // source pixels
									   int srcStep,		   // stride of the source pixels
									   float s0, float s1 )
{
	float w;
	float rSum = 0, gSum = 0, bSum = 0;
	float y = s0;
	float sumWeight = 0;

	for ( y = s0; y < ( int ) ( s1 + 1 ) ; y++, src += srcStep )
	{
		if ( y == s0 )
		{
			w = ( int ) ( s0 + 1 ) - y;
		}
		else if ( y + 1 >= s1 )
		{
			w = s1 - ( int ) y;
		}
		else
		{
			w = 1.0f;
		}

		rSum += src[0] * w;
		gSum += src[1] * w;
		bSum += src[2] * w;
		sumWeight += w;
	}

	rSum /= sumWeight;
	gSum /= sumWeight;
	bSum /= sumWeight;

	dst[0] = ( unsigned char ) ( rSum + 0.5 );
	dst[1] = ( unsigned char ) ( gSum + 0.5 );
	dst[2] = ( unsigned char ) ( bSum + 0.5 );
	dst[3] = 0xff;

}

static void BoxFilterRow( unsigned char *dstStart, cblock_t *in, int dstRow, int rowWidth )
{
	int i;
	unsigned char *indata = ( unsigned char * ) in->data;

	indata += 4 * dstRow * in->width;

	for ( i = 0; i < rowWidth; i++ )
	{
		float c0 = i * s_resampleXRatio;
		float c1 = ( i + 1 ) * s_resampleXRatio;

		BoxFilterHorizontalElements( &dstStart[i*4], &indata[( ( int ) c0 ) * 4], c0, c1 );
	}
}

static void BoxFilterColumn( unsigned char *dstStart, unsigned char *srcStart, int dstCol, int dstRowWidth, int dstColHeight, int srcRowWidthInPels )
{
	float c0, c1;
	int i;

	for ( i = 0; i < dstColHeight; i++ )
	{
		c0 = i * s_resampleYRatio;
		c1 = ( i + 1 ) * s_resampleYRatio;

		BoxFilterVerticalElements( &dstStart[i*4*dstRowWidth], &srcStart[(int)c0*srcRowWidthInPels*4], srcRowWidthInPels*4, c0, c1 );
	}
}

#define DROP_SAMPLE		0
#define BOX_FILTER		1

static void ResampleFrame( cblock_t *in, unsigned char *out, int method, int outWidth, int outHeight )
{
	int row, column;
	unsigned char *indata = ( unsigned char * ) in->data;

	s_resampleXRatio = in->width / ( float ) outWidth;
	s_resampleYRatio = in->height / ( float ) outHeight;

	if ( method == DROP_SAMPLE )
	{
		for ( row = 0; row < outHeight; row++ )
		{
			int r = ( int ) ( row * s_resampleYRatio );

			for ( column = 0; column < outWidth; column++ )
			{
				int c = ( int ) ( column * s_resampleXRatio );

				out[(row*outWidth+column)*4+0] = indata[(r*in->width+c)*4+0];
				out[(row*outWidth+column)*4+1] = indata[(r*in->width+c)*4+1];
				out[(row*outWidth+column)*4+2] = indata[(r*in->width+c)*4+2];
				out[(row*outWidth+column)*4+3] = 0xff;
			}
		}
	}
	else if ( method == BOX_FILTER )
	{
		unsigned char intermediate[1024*1024*4];

		assert( in->height <= 1024 );
		assert( in->width <= 1024 );

		//
		// filter our M x N source image into a RESAMPLE_WIDTH x N horizontally filtered image
		//
		for ( row = 0; row < in->height; row++ )
		{
			BoxFilterRow( &intermediate[row*4*outWidth], in, row, outWidth );
		}

		//
		// filter our RESAMPLE_WIDTH x N horizontally filtered image into a RESAMPLE_WIDTH x RESAMPLE_HEIGHT filtered image
		//
		for ( column = 0; column < outWidth; column++ )
		{
			BoxFilterColumn( &out[column*4], &intermediate[column*4], column, outWidth, outHeight, s_resample_width );
		}
	}
}

static float BTCDistanceSquared( float a[3], float b[3] )
{
	return ( b[0] - a[0] ) * ( b[0] - a[0] ) + 
		   ( b[1] - a[1] ) * ( b[1] - a[1] ) +
		   ( b[2] - a[2] ) * ( b[2] - a[2] );
}

static void BTCFindEndpoints( float inBlock[4][4][3], unsigned int endPoints[2][2] )
{
	float longestDistance = -1;

	int bX, bY;

	//
	// find the two points farthest from each other
	//
	for ( bY = 0; bY < 4; bY++ )
	{
		for ( bX = 0; bX < 4; bX++ )
		{
			int cX, cY;
			float d;

			//
			// check the rest of the current row
			//
			for ( cX = bX + 1; cX < 4; cX++ )
			{
				if ( ( d = BTCDistanceSquared( inBlock[bY][bX], inBlock[bY][cX] ) ) > longestDistance )
				{
					longestDistance = d;
					endPoints[0][0] = bX;
					endPoints[0][1] = bY;
					endPoints[1][0] = cX;
					endPoints[1][1] = bY;
				}
			}

			//
			// check remaining rows and columns
			//
			for ( cY = bY+1; cY < 4; cY++ )
			{
				for ( cX = 0; cX < 4; cX++ )
				{
					if ( ( d = BTCDistanceSquared( inBlock[bY][bX], inBlock[cY][cX] ) ) > longestDistance )
					{
						longestDistance = d;
						endPoints[0][0] = bX;
						endPoints[0][1] = bY;
						endPoints[1][0] = cX;
						endPoints[1][1] = cY;
					}
				}
			}
		}
	}
}

static float BTCQuantizeBlock( float inBlock[4][4][3], unsigned long endPoints[2][2], int btcQuantizedBlock[4][4], float bestError )
{
	int i;
	int blockY, blockX;
	float dR, dG, dB;
	float R, G, B;
	float error = 0;
	float colorLine[4][3];

	//
	// build the color line
	//
	dR = inBlock[endPoints[1][1]][endPoints[1][0]][0] -
		 inBlock[endPoints[0][1]][endPoints[0][0]][0];
	dG = inBlock[endPoints[1][1]][endPoints[1][0]][1] -
		 inBlock[endPoints[0][1]][endPoints[0][0]][1];
	dB = inBlock[endPoints[1][1]][endPoints[1][0]][2] -
		 inBlock[endPoints[0][1]][endPoints[0][0]][2];

	dR *= 0.33f;
	dG *= 0.33f;
	dB *= 0.33f;

	R = inBlock[endPoints[0][1]][endPoints[0][0]][0];
	G = inBlock[endPoints[0][1]][endPoints[0][0]][1];
	B = inBlock[endPoints[0][1]][endPoints[0][0]][2];

	for ( i = 0; i < 4; i++ )
	{
		colorLine[i][0] = R;
		colorLine[i][1] = G;
		colorLine[i][2] = B;

		R += dR;
		G += dG;
		B += dB;
	}

	//
	// quantize each pixel into the appropriate range
	//
	for ( blockY = 0; blockY < 4; blockY++ )
	{
		for ( blockX = 0; blockX < 4; blockX++ )
		{
			float distance = 10000000000;

⌨️ 快捷键说明

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