static void PlaceDetail( DetailModel_t const& model, const Vector& pt, const Vector& normal )
{
	// But only place it on the surface if it meets the angle constraints...
	float cosAngle = normal.z;

	// Never emit if the angle's too steep
	if (cosAngle < model.m_MaxCosAngle)
		return;

	// If it's between min + max, flip a coin...
	if (cosAngle < model.m_MinCosAngle)
	{
		float probability = (cosAngle - model.m_MaxCosAngle) / 
			(model.m_MinCosAngle - model.m_MaxCosAngle);

		float t = rand() / (float)RAND_MAX;
		if (t > probability)
			return;
	}

	// Compute the orientation of the detail
	QAngle angles;
	if (model.m_Flags & MODELFLAG_UPRIGHT)
	{
		// If it's upright, we just select a random yaw
		angles.Init( 0, 360.0f * rand() / (float)RAND_MAX, 0.0f );
	}
	else
	{
		// It's not upright, so it must conform to the ground. Choose
		// a random orientation based on the surface normal

		Vector zaxis;
		VectorCopy( normal, zaxis );

		// Choose any two arbitrary axes which are perpendicular to the normal
		Vector xaxis( 1, 0, 0 );
		if (fabs(xaxis.Dot(zaxis)) - 1.0 > -1e-3)
			xaxis.Init( 0, 1, 0 );
		Vector yaxis;
		CrossProduct( zaxis, xaxis, yaxis );
		CrossProduct( yaxis, zaxis, xaxis );
		VMatrix matrix;
		matrix.SetBasisVectors( xaxis, yaxis, zaxis );

		float rotAngle = 360.0f * rand() / (float)RAND_MAX;
		VMatrix rot = SetupMatrixAxisRot( Vector( 0, 0, 1 ), rotAngle );
		matrix = matrix * rot;

		MatrixToAngles( matrix, angles );
	}

	// FIXME: We may also want a purely random rotation too

	// Insert an element into the object dictionary if it aint there...
	switch ( model.m_Type )
	{
	case DETAIL_PROP_TYPE_MODEL:
		AddDetailToLump( model.m_ModelName.String(), pt, angles, model.m_Orientation );
		break;

	case DETAIL_PROP_TYPE_SPRITE:
		{
			float flScale = 1.0f;
			if ( model.m_flRandomScaleStdDev != 0.0f ) 
			{
				flScale = fabs( RandomGaussianFloat( 1.0f, model.m_flRandomScaleStdDev ) );
			}

			AddDetailSpriteToLump( pt, angles, model.m_Orientation, model.m_Pos, model.m_Tex, flScale );
		}
		break;
	}
}
//-----------------------------------------------------------------------------
// Copies the texture coordinate system from pFrom into pTo. Then it rotates 
// the texture around the edge until it's as close to pTo's normal as possible.
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::CopyTCoordSystem( const CMapFace *pFrom, CMapFace *pTo )
{
	Vector		axis[2], vEdge, vEdgePt, vOrigin;
	Vector		vFromPt, vNextFromPt;
	Vector		vToPt, vPrevToPt;
	Vector		vTestTextureNormal, vTextureNormal;
	VMatrix		mEdgeRotation, mOriginRotation, mTranslation;
	float		fAngle, fDot;
	bool		bRotate;
	float		fShift[2];
	Vector		vProjTexNormal;
	Vector		vProjPolyNormal;

	// The edge vector lies on both planes.
	vEdge = pFrom->plane.normal.Cross(pTo->plane.normal);
	VectorNormalize( vEdge );

	// To find a point on the plane, we make a plane from the edge vector and find the intersection
	// between the three planes (without the third plane, there are an infinite number of solutions).
	if( PlaneIntersection( VPlane(pFrom->plane.normal, pFrom->plane.dist),
		                   VPlane(pTo->plane.normal, pTo->plane.dist),
		                   VPlane(vEdge, 0.0f), vEdgePt ) )
	{
		bRotate = true;
	}
	else
	{
		// Ok, in this case, the planes are parallel so we don't need to rotate around the edge anyway!
		bRotate = false;
	}

	// Copy the texture coordinate system.
	axis[0] = pFrom->texture.UAxis.AsVector3D();
	axis[1] = pFrom->texture.VAxis.AsVector3D();
	fShift[0] = pFrom->texture.UAxis[3];
	fShift[1] = pFrom->texture.VAxis[3];
	vOrigin = axis[0]*fShift[0]*pFrom->texture.scale[0] + axis[1]*fShift[1]*pFrom->texture.scale[1];
	
	vTextureNormal = axis[0].Cross(axis[1]);
	VectorNormalize(vTextureNormal);
	if(bRotate)
	{
		// Project texture normal and poly normal into the plane of rotation
		// to get the angle between them.
		vProjTexNormal = vTextureNormal - vEdge * vEdge.Dot(vTextureNormal);
		vProjPolyNormal = pTo->plane.normal - vEdge * vEdge.Dot(pTo->plane.normal);

		VectorNormalize( vProjTexNormal );
		VectorNormalize( vProjPolyNormal );

		fDot = vProjTexNormal.Dot(vProjPolyNormal);
		fAngle = (float)(acos(fDot) * (180.0f / M_PI));
		if(fDot < 0.0f)
			fAngle = 180.0f - fAngle;

		// Ok, rotate them for the final values.
		mEdgeRotation = SetupMatrixAxisRot(vEdge, fAngle);
		axis[0] = mEdgeRotation.ApplyRotation(axis[0]);
		axis[1] = mEdgeRotation.ApplyRotation(axis[1]);

		// Origin needs translation and rotation to rotate around the edge.
		mTranslation = SetupMatrixTranslation(vEdgePt);
		mOriginRotation = ~mTranslation * mEdgeRotation * mTranslation;
		vOrigin = mOriginRotation * vOrigin;
	}

	pTo->texture.UAxis.AsVector3D() = axis[0];
	pTo->texture.VAxis.AsVector3D() = axis[1];

	pTo->texture.UAxis[3] = axis[0].Dot(vOrigin) / pFrom->texture.scale[0];
	pTo->texture.VAxis[3] = axis[1].Dot(vOrigin) / pFrom->texture.scale[1];
	pTo->NormalizeTextureShifts();

	pTo->texture.scale[0] = pFrom->texture.scale[0];
	pTo->texture.scale[1] = pFrom->texture.scale[1];

	// rotate is only for UI purposes, it doesn't actually do anything.
	pTo->texture.rotate = 0.0f;

	pTo->CalcTextureCoords();
}
			VMatrix rotationMatrix;
			VMatrix invRotationMatrix;
			Vector transformedEye;
			float angle = 0.0f;
			if(sv_surface_rotate.GetBool())
			{
				angle = view->GetViewSetup()->angles.y+180.0f;

				//ConMsg("Angle = %f\n", angle);
				pRenderContext->Rotate(angle, 0.0f, 0.0f, 1.0f);

				//VMatrix rotationMatrix2 = SetupMatrixAngles(view->GetViewSetup()->angles);
				//pRenderContext->MultMatrix(rotationMatrix2);
				//VMatrix rotationMatrix = rotationMatrix2.InverseTR(); //SetupMatrixAngles(-(view->GetViewSetup()->angles));

				rotationMatrix = SetupMatrixAxisRot(Vector(0.0f, 0.0f, 1.0f), -angle);
				invRotationMatrix = SetupMatrixAxisRot(Vector(0.0f, 0.0f, 1.0f), angle);
				Vector eye = view->GetViewSetup()->origin;
				transformedEye = (eye-center)*(1.0f/m_flRadius);
				transformedEye = rotationMatrix.ApplyRotation(transformedEye);
			}
			else
			{
				rotationMatrix.Identity();
				invRotationMatrix.Identity();
				transformedEye.Init();
				angle = 0.0f;
			}

			if(sv_surface_use_tiler.GetBool())
			{
static int vmatrix_SetupMatrixAxisRot (lua_State *L) {
  lua_pushvmatrix(L, SetupMatrixAxisRot(luaL_checkvector(L, 1), luaL_checknumber(L, 2)));
  return 1;
}