// Copyright (C) 2004-2009 Christoph Kubisch & Eike Decker
// This file is part of the "Luxinia Engine".
// For conditions of distribution and use, see copyright notice in luxiniapublicsdk.txt
//
// <Author: Christoph Kubisch>


#ifndef __LUXMATH_BOUNDING_H__
#define __LUXMATH_BOUDNING_H__

#include <luxmath/basetypes.h>

#ifdef __cplusplus
extern "C"{
#endif


//////////////////////////////////////////////////////////////////////////
// Generic

booln lxMinMax_intersectsV(float selfminmax[6], float otherminmax[6]);


///////////////////////////////////////////////////////////////////////////////
// BOUNDING VOLUMES

void lxBoundingBox_init(lxBoundingBox_t *box);

void lxBoundingBox_complete(lxBoundingBox_t *box, booln fromMinMax);

// copy a bounding volume to another
lxBoundingBox_t *lxBoundingBox_copy(lxBoundingBox_t *out, lxBoundingBox_t *in);
lxBoundingSphere_t *lxBoundingSphere_copy(lxBoundingSphere_t *out, const lxBoundingSphere_t *in);


// use min/max
// ------------
// merge two bounding volumes
lxBoundingBox_t * lxBoundingBox_merge(lxBoundingBox_t *out, lxBoundingBox_t *a, lxBoundingBox_t *b);
// returns TRUE if result differs from a
booln	lxBoundingBox_mergeChange(lxBoundingBox_t *out, lxBoundingBox_t *a, lxBoundingBox_t *b);
booln	lxBoundingSphere_mergeChange(lxBoundingSphere_t *out, const lxBoundingSphere_t *a, const lxBoundingSphere_t *b);

// converts a bounding box to a bounding sphere
lxBoundingSphere_t *lxBoundingBox_toSphere(lxBoundingBox_t *bbox, lxBoundingSphere_t *sphere);
void lxBoundingBox_toSphereV(const lxVector3 min,const lxVector3 max, lxVector3 center, float *radius);

// convert bounding box to capsule
// a capsule along major axis of boundingbox is generated with radius
// of the greater half dimension of the other 2 axis
lxBoundingCapsule_t *lxBoundingBox_toCapsule(lxBoundingBox_t *bbox,lxBoundingCapsule_t *capsule);

// transforms a bounding box to an axis aligned bounding box
lxBoundingBox_t *lxBoundingBox_transform( lxBoundingBox_t *out, lxBoundingBox_t *in, lxMatrix44 trans);
void lxBoundingBox_transformBoxCorners(const lxBoundingBox_t *in, const lxMatrix44 trans, lxVector3 box[8]);
void lxBoundingBox_transformV(lxVector3 outmins, lxVector3 outmaxs,lxVector3 mins, lxVector3 maxs, lxMatrix44 trans);

void lxBoundingBox_fromCorners(lxBoundingBox_t *bbox,const lxVector3 vecs[8]);
void lxBoundingVectors_fromCamera(lxVector3 vecs[8],const lxMatrix44 mat,const float fov, const float frontplane, const float backplane, const float aspect);

booln lxBoundingBox_intersect(const lxBoundingBox_t *a,const lxBoundingBox_t *b);
booln	lxBoundingBox_checkPoint(const lxBoundingBox_t *out,const lxVector3 point);
booln lxBoundingCone_checkSphereV(lxBoundingCone_t *cone,lxVector3 center, float radius, float radiusSqr);

// approximates frustum via Sphere & Cone, dir must be normalized
void lxBoundingSphereCone_fromCamera(lxBoundingSphere_t *sphere, lxBoundingCone_t *cone,float frontplane, float backplane, lxVector3 pos, lxVector3 dir, float fov);
void lxBoundingCone_fromFrustumCorners(lxBoundingCone_t *cone, lxVector3 box[FRUSTUM_CORNERS]);
void lxBoundingSphere_fromFrustumCorners(lxBoundingSphere_t *sphere,lxVector3 box[FRUSTUM_CORNERS]);

//////////////////////////////////////////////////////////////////////////
LUX_INLINE void lxBoundingBox_init(lxBoundingBox_t *box)
{
	box->min[0] = 0.0f;
	box->min[1] = 0.0f;
	box->min[2] = 0.0f;

	box->max[0] = 0.0f;
	box->max[1] = 0.0f;
	box->max[2] = 0.0f;

	box->center[0] = 0.0f;
	box->center[1] = 0.0f;
	box->center[2] = 0.0f;

	box->length[0] = 0.0f;
	box->length[1] = 0.0f;
	box->length[2] = 0.0f;
}

LUX_INLINE booln lxMinMax_intersectsV(float selfminmax[6], float otherminmax[6]){
	return (	
		selfminmax[0] <= otherminmax[3] && 
		selfminmax[1] <= otherminmax[4] &&
		selfminmax[2] <= otherminmax[5] &&
		selfminmax[3] >= otherminmax[0] &&
		selfminmax[4] >= otherminmax[1] &&
		selfminmax[5] >= otherminmax[2]	);
}

#ifdef __cplusplus
}
#endif

#endif

