
#include "vis.h"

/*

Some textures (sky, water, slime, lava) are considered ambien sound emiters.
Find an aproximate distance to the nearest emiter of each class for each leaf.

*/

/*
====================
CalcAmbientSounds

====================
*/
void
CalcAmbientSounds( void ) {
	int i, j, k;
	dleaf_t		*leaf, *hit;
	byte		*vis;
	dface_t		*surf;
	float		maxd;
	int		ambient_type, *Ambient;
	texinfo_t	*info;
	miptex_t	*miptex;
	int		ofs, nummiptex;
	float		dists[ NUM_AMBIENTS ];
	float		vol;
	qboolean	AmbientUsed[ NUM_AMBIENTS ];

	nummiptex = ((dmiptexlump_t *) dtexdata )->nummiptex;
	Ambient = malloc( nummiptex * sizeof( int ));

	// Any textures at all ?
	if( texdatasize != 0 ) {
		for( i = 0; i < NUM_AMBIENTS; ++i )
			AmbientUsed[ i ] = false;

		// Calculate ambient type only once
		for( i = 0; i < nummiptex; i++ ) {
			Ambient[ i ] = -1;

			if( NoAmbient )
				continue; // All sounds disabled

			ofs = ((dmiptexlump_t *) dtexdata )->dataofs[ i ];

			if( ofs == -1 )
				continue; // Missing texture

			miptex = (miptex_t *) ( &dtexdata[ ofs ] );

			if( miptex->name[ 0 ] != '*' && miptex->name[ 0 ] != 's' && miptex->name[ 0 ] != 'S' )
				continue;

			if( !Q_strncasecmp( miptex->name, "*water", 6 ))
				Ambient[ i ] = NoAmbientWater ? -1 : AMBIENT_WATER;
			else if( !Q_strncasecmp( miptex->name, "sky", 3 ))
				Ambient[ i ] = NoAmbientSky ? -1 : AMBIENT_SKY;
			else if( !Q_strncasecmp( miptex->name, "*slime", 6 ))
				Ambient[ i ] = NoAmbientSlime ? -1 : AMBIENT_WATER; // AMBIENT_SLIME;
			else if( !Q_strncasecmp( miptex->name, "*lava", 5 ))
				Ambient[ i ] = NoAmbientLava ? -1 : AMBIENT_LAVA;
			else if( !Q_strncasecmp( miptex->name, "*04water", 8 ))
				Ambient[ i ] = NoAmbientWater ? -1 : AMBIENT_WATER;

			if( Ambient[ i ] != -1 )
				AmbientUsed[ Ambient[ i ] ] = true;
		}

		if( !NoAmbient ) {
			for( i = 0; i < NUM_AMBIENTS; ++i ) {
				if( AmbientUsed[ i ] )
					break;
			}

			if( i == NUM_AMBIENTS )
				NoAmbient = true; // No ambients used; disable sounds
		}
	}

	#ifdef FEATURE_DETAIL
	for( i = 0; i < numrealleafs; i++ ) { // numrealleafs - 1
	#else
	for( i = 0; i < portalleafs; i++ ) {
		#endif
		leaf = &dleafs[ i + 1 ];

		//
		// clear ambients
		//
		for( j = 0; j < NUM_AMBIENTS; j++ )
			dists[ j ] = 1020;

		// Any textures at all ?
		if( texdatasize != 0 && !NoAmbient ) {
			#ifdef FEATURE_DETAIL
			vis = &uncompressed[ leafcluster[ i ] * bitbytes_l ];
			#else
			vis = &uncompressed[ i * bitbytes ];
			#endif

			#ifdef FEATURE_DETAIL
			for( j = 0; j < numrealleafs; j++ ) { // numrealleafs - 1
			#else
			for( j = 0; j < portalleafs; j++ ) {
				#endif
				if( !( vis[ j >> 3 ] & ( 1 << ( j & 7 ))))
					continue;

				//
				// check this leaf for sound textures
				//
				hit = &dleafs[ j + 1 ];

				for( k = 0; k < hit->nummarksurfaces; k++ ) {
					surf = &dfaces[ dmarksurfaces[ hit->firstmarksurface + k ] ];
					info = &texinfo[ surf->texinfo ];

					if( Ambient[ info->miptex ] == -1 )
						continue;

					ambient_type = Ambient[ info->miptex ];

					maxd = 0.25; // Visible => very close
					if( maxd < dists[ ambient_type ] )
						dists[ ambient_type ] = maxd;
				}

				// NOTE: The logic below only works when maxd is fixed (as in original logic)
				for( k = 0; k < NUM_AMBIENTS; ++k ) {
					if( AmbientUsed[ k ] && dists[ k ] == 1020 )
						break;
				}

				if( k == NUM_AMBIENTS )
					break; // All used ambient positions done
			}
		}

		for( j = 0; j < NUM_AMBIENTS; j++ ) {
			if( dists[ j ] < 100 )
				vol = 1.0; // Very close => full volume
			else {
				// Strange logic: Not visible => dists[AMBIENT_SLIME] = 1020 => silent
				vol = 1.0 - dists[ 2 ] * 0.002;
				if( vol < 0 )
					vol = 0;
			}
			leaf->ambient_level[ j ] = vol * 255;
		}
	}

	free( Ambient );
}

#ifdef FEATURE_BSP2
void
CalcAmbientSoundsBSP2( void ) {
	int			i, j, k;
	dleafBSP2_t	*leaf, *hit;
	byte		*vis;
	dfaceBSP2_t	*surf;
	float		maxd;
	int			ambient_type, *Ambient;
	texinfo_t	*info;
	miptex_t	*miptex;
	int			ofs, nummiptex;
	float		dists[ NUM_AMBIENTS ];
	float		vol;
	qboolean	AmbientUsed[ NUM_AMBIENTS ];

	nummiptex = ((dmiptexlump_t *) dtexdata )->nummiptex;
	Ambient = malloc( nummiptex * sizeof( int ));

	// Any textures at all ?
	if( texdatasize != 0 ) {
		for( i = 0; i < NUM_AMBIENTS; ++i )
			AmbientUsed[ i ] = false;

		// Calculate ambient type only once
		for( i = 0; i < nummiptex; i++ ) {
			Ambient[ i ] = -1;

			if( NoAmbient )
				continue; // All sounds disabled

			ofs = ((dmiptexlump_t *) dtexdata )->dataofs[ i ];

			if( ofs == -1 )
				continue; // Missing texture

			miptex = (miptex_t *) ( &dtexdata[ ofs ] );

			if( miptex->name[ 0 ] != '*' && miptex->name[ 0 ] != 's' && miptex->name[ 0 ] != 'S' )
				continue;

			if( !Q_strncasecmp( miptex->name, "*water", 6 ))
				Ambient[ i ] = NoAmbientWater ? -1 : AMBIENT_WATER;
			else if( !Q_strncasecmp( miptex->name, "sky", 3 ))
				Ambient[ i ] = NoAmbientSky ? -1 : AMBIENT_SKY;
			else if( !Q_strncasecmp( miptex->name, "*slime", 6 ))
				Ambient[ i ] = NoAmbientSlime ? -1 : AMBIENT_WATER; // AMBIENT_SLIME;
			else if( !Q_strncasecmp( miptex->name, "*lava", 5 ))
				Ambient[ i ] = NoAmbientLava ? -1 : AMBIENT_LAVA;
			else if( !Q_strncasecmp( miptex->name, "*04water", 8 ))
				Ambient[ i ] = NoAmbientWater ? -1 : AMBIENT_WATER;

			if( Ambient[ i ] != -1 )
				AmbientUsed[ Ambient[ i ] ] = true;
		}

		if( !NoAmbient ) {
			for( i = 0; i < NUM_AMBIENTS; ++i ) {
				if( AmbientUsed[ i ] )
					break;
			}

			if( i == NUM_AMBIENTS )
				NoAmbient = true; // No ambients used; disable sounds
		}
	}

	#ifdef FEATURE_DETAIL
	for( i = 0; i < numrealleafs - 1; i++ ) {
	#else
	for( i = 0; i < portalleafs; i++ ) {
		#endif
		leaf = &dleafsBSP2[ i + 1 ];

		//
		// clear ambients
		//
		for( j = 0; j < NUM_AMBIENTS; j++ )
			dists[ j ] = 1020;

		// Any textures at all ?
		if( texdatasize != 0 && !NoAmbient ) {
			#ifdef FEATURE_DETAIL
			vis = &uncompressed[ leafcluster[ i ] * bitbytes_l ];
			#else
			vis = &uncompressed[ i * bitbytes ];
			#endif

			#ifdef FEATURE_DETAIL
			for( j = 0; j < numrealleafs - 1; j++ ) {
			#else
			for( j = 0; j < portalleafs; j++ ) {
				#endif
				if( !( vis[ j >> 3 ] & ( 1 << ( j & 7 ))))
					continue;

				//
				// check this leaf for sound textures
				//
				hit = &dleafsBSP2[ j + 1 ];

				for( k = 0; k < hit->nummarksurfaces; k++ ) {
					surf = &dfacesBSP2[ dmarksurfacesBSP2[ hit->firstmarksurface + k ] ];
					info = &texinfo[ surf->texinfo ];

					if( Ambient[ info->miptex ] == -1 )
						continue;

					ambient_type = Ambient[ info->miptex ];

					maxd = 0.25; // Visible => very close
					if( maxd < dists[ ambient_type ] )
						dists[ ambient_type ] = maxd;
				}

				// NOTE: The logic below only works when maxd is fixed (as in original logic)
				for( k = 0; k < NUM_AMBIENTS; ++k ) {
					if( AmbientUsed[ k ] && dists[ k ] == 1020 )
						break;
				}

				if( k == NUM_AMBIENTS )
					break; // All used ambient positions done
			}
		}

		for( j = 0; j < NUM_AMBIENTS; j++ ) {
			if( dists[ j ] < 100 )
				vol = 1.0; // Very close => full volume
			else {
				// Strange logic: Not visible => dists[AMBIENT_SLIME] = 1020 => silent
				vol = 1.0 - dists[ 2 ] * 0.002;
				if( vol < 0 )
					vol = 0;
			}
			leaf->ambient_level[ j ] = vol * 255;
		}
	}

	free( Ambient );
}
#endif