/*
================
idBrittleFracture::Fracture_r
================
*/
void idBrittleFracture::Fracture_r( idFixedWinding &w ) {
	int i, j, bestPlane;
	float a, c, s, dist, bestDist;
	idVec3 origin;
	idPlane windingPlane, splitPlanes[2];
	idMat3 axis, axistemp;
	idFixedWinding back;
	idTraceModel trm;
	idClipModel *clipModel;
	while( 1 ) {
		origin = w.GetCenter();
		w.GetPlane( windingPlane );
		if( w.GetArea() < maxShardArea ) {
			break;
		}
		// randomly create a split plane
		a = gameLocal.random.RandomFloat() * idMath::TWO_PI;
		c = cos( a );
		s = -sin( a );
		axis[2] = windingPlane.Normal();
		axis[2].NormalVectors( axistemp[0], axistemp[1] );
		axis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * s;
		axis[1] = axistemp[ 0 ] * s + axistemp[ 1 ] * -c;
		// get the best split plane
		bestDist = 0.0f;
		bestPlane = 0;
		for( i = 0; i < 2; i++ ) {
			splitPlanes[i].SetNormal( axis[i] );
			splitPlanes[i].FitThroughPoint( origin );
			for( j = 0; j < w.GetNumPoints(); j++ ) {
				dist = splitPlanes[i].Distance( w[j].ToVec3() );
				if( dist > bestDist ) {
					bestDist = dist;
					bestPlane = i;
				}
			}
		}
		// split the winding
		if( !w.Split( &back, splitPlanes[bestPlane] ) ) {
			break;
		}
		// recursively create shards for the back winding
		Fracture_r( back );
	}
	// translate the winding to it's center
	origin = w.GetCenter();
	for( j = 0; j < w.GetNumPoints(); j++ ) {
		w[j].ToVec3() -= origin;
	}
	w.RemoveEqualPoints();
	trm.SetupPolygon( w );
	trm.Shrink( CM_CLIP_EPSILON );
	clipModel = new idClipModel( trm );
	physicsObj.SetClipModel( clipModel, 1.0f, shards.Num() );
	physicsObj.SetOrigin( GetPhysics()->GetOrigin() + origin, shards.Num() );
	physicsObj.SetAxis( GetPhysics()->GetAxis(), shards.Num() );
	AddShard( clipModel, w );
}
/*
=================
idRenderModelDecal::CreateProjectionInfo
=================
*/
bool idRenderModelDecal::CreateProjectionInfo( decalProjectionInfo_t &info, const idFixedWinding &winding, const idVec3 &projectionOrigin, const bool parallel, const float fadeDepth, const idMaterial *material, const int startTime ) {
	if( winding.GetNumPoints() != NUM_DECAL_BOUNDING_PLANES - 2 ) {
		common->Printf( "idRenderModelDecal::CreateProjectionInfo: winding must have %d points\n", NUM_DECAL_BOUNDING_PLANES - 2 );
		return false;
	}
	assert( material != NULL );
	info.projectionOrigin = projectionOrigin;
	info.material = material;
	info.parallel = parallel;
	info.fadeDepth = fadeDepth;
	info.startTime = startTime;
	info.force = false;
	// get the winding plane and the depth of the projection volume
	idPlane windingPlane;
	winding.GetPlane( windingPlane );
	float depth = windingPlane.Distance( projectionOrigin );
	// find the bounds for the projection
	winding.GetBounds( info.projectionBounds );
	if( parallel ) {
		info.projectionBounds.ExpandSelf( depth );
	} else {
		info.projectionBounds.AddPoint( projectionOrigin );
	}
	// calculate the world space projection volume bounding planes, positive sides face outside the decal
	if( parallel ) {
		for( int i = 0; i < winding.GetNumPoints(); i++ ) {
			idVec3 edge = winding[( i + 1 ) % winding.GetNumPoints()].ToVec3() - winding[i].ToVec3();
			info.boundingPlanes[i].Normal().Cross( windingPlane.Normal(), edge );
			info.boundingPlanes[i].Normalize();
			info.boundingPlanes[i].FitThroughPoint( winding[i].ToVec3() );
		}
	} else {
		for( int i = 0; i < winding.GetNumPoints(); i++ ) {
			info.boundingPlanes[i].FromPoints( projectionOrigin, winding[i].ToVec3(), winding[( i + 1 ) % winding.GetNumPoints()].ToVec3() );
		}
	}
	info.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 2] = windingPlane;
	info.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 2][3] -= depth;
	info.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 1] = -windingPlane;
	// fades will be from these plane
	info.fadePlanes[0] = windingPlane;
	info.fadePlanes[0][3] -= fadeDepth;
	info.fadePlanes[1] = -windingPlane;
	info.fadePlanes[1][3] += depth - fadeDepth;
	// calculate the texture vectors for the winding
	float	len, texArea, inva;
	idVec3	temp;
	idVec5	d0, d1;
	const idVec5 &a = winding[0];
	const idVec5 &b = winding[1];
	const idVec5 &c = winding[2];
	d0 = b.ToVec3() - a.ToVec3();
	d0.s = b.s - a.s;
	d0.t = b.t - a.t;
	d1 = c.ToVec3() - a.ToVec3();
	d1.s = c.s - a.s;
	d1.t = c.t - a.t;
	texArea = ( d0[3] * d1[4] ) - ( d0[4] * d1[3] );
	inva = 1.0f / texArea;
	temp[0] = ( d0[0] * d1[4] - d0[4] * d1[0] ) * inva;
	temp[1] = ( d0[1] * d1[4] - d0[4] * d1[1] ) * inva;
	temp[2] = ( d0[2] * d1[4] - d0[4] * d1[2] ) * inva;
	len = temp.Normalize();
	info.textureAxis[0].Normal() = temp * ( 1.0f / len );
	info.textureAxis[0][3] = winding[0].s - ( winding[0].ToVec3() * info.textureAxis[0].Normal() );
	temp[0] = ( d0[3] * d1[0] - d0[0] * d1[3] ) * inva;
	temp[1] = ( d0[3] * d1[1] - d0[1] * d1[3] ) * inva;
	temp[2] = ( d0[3] * d1[2] - d0[2] * d1[3] ) * inva;
	len = temp.Normalize();
	info.textureAxis[1].Normal() = temp * ( 1.0f / len );
	info.textureAxis[1][3] = winding[0].t - ( winding[0].ToVec3() * info.textureAxis[1].Normal() );
	return true;
}