/****************************************************************************************

		BasicPrimitive.h

		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Author:	Ray Dream
		Date:	9/29/98

		Revision History

		when		who			what & why
		==========	==========	======================================================
		11/19/99	Yann		Removed GetPolygonInfo
		08/10/99	Arnaud		FacetMesh is now counted.
		07/28/99	Arnaud		LOD indexes are now all ZERO based
		7/14/99		cph			added GetPolygonInfo() to geo prim interface
		2/24/99		Alec		added AppendToRenderables call

*****************************************************************************************/

#ifndef __BasicPrimitive__
#define __BasicPrimitive__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "BasicCOMImplementations.h"
#include "MCBasicTypes.h"

#include "I3DExPrimitive.h"


/// \addtogroup BaseClass
/// \{
/*******************************************************************************\
*                                                                               *
*     TBasicPrimitive                                                           *
*                                                                               *
\*******************************************************************************/
/// Basic Primitive class.  Derive from this for a default implementation of I3DExGeometricPrimitive
/// \see I3DExGeometricPrimitive
class TBasicPrimitive : public TBasicDataExchanger,
					    public I3DExGeometricPrimitive
{
	public:
									 TBasicPrimitive();
		virtual 				 	 ~TBasicPrimitive();

		virtual MCCOMErr 	MCCOMAPI QueryInterface			(const MCIID &riid, void** ppvObj);
		virtual uint32 		MCCOMAPI AddRef 				() { return TBasicDataExchanger::AddRef(); }

		virtual void*		MCCOMAPI GetExtensionDataBuffer	();

		// I3DExGeometricPrimitive		
		// Compute the bounding box of the primitive. MUST be implemented : that's why TBasicPrimitive does not provide any default implementation
		// virtual void	   MCCOMAPI GetBoundingBox		(TBBox3D& bbox); - Not implemented at this level

		virtual void	   MCCOMAPI GetRenderingBoundingBox		(TBBox3D& bbox) { GetBoundingBox(bbox); }
		virtual MCCOMErr   MCCOMAPI GetApproximateBoundingBox	(TBBox3D& bbox) { return MC_S_FALSE; }
		
		// If your primitive is based on bicubic Bezier patches, you can use this rather than implementing GetFacetMesh
		virtual MCCOMErr   MCCOMAPI EnumPatches			(EnumPatchesCallback callback, void* privData, boolean& closed);
		
		//   IMPORTANT :	Read the technical explanations in BasicPrimitive.cpp to learn everything about LOD (Level Of Details) management,
		//					and multi-resolution support.

		// Return the number of Facet Meshes that the primitive can return
		virtual MCCOMErr   MCCOMAPI GetNbrLOD			(int16& nbrLod);

		// Return the floating point value of the level of detail that corresponds to the 0-based 'lodIndex'. lodIndex=0 means highest resolution.
		virtual MCCOMErr   MCCOMAPI GetLOD				(int16 lodIndex, real& lod);

		// Return the Facet Mesh for this lod index. Always implement this one.
		virtual MCCOMErr   MCCOMAPI GetFacetMesh		(uint32 lodIndex, FacetMesh** outMesh);

		// ****************************************************************************
		//								ChangeLocalTimeInHit
		// 
		/// Let the object change the local time after a hit
		/// 
		/// \param params  the parameters of the hit, only params.fHit->fTime should be changed
		/// 
		virtual void		MCCOMAPI ChangeLocalTimeInHit(RayHitParameters& params) {}

		/// Returns true if this primitive uses local time and therefore need animated shaders.
		virtual boolean		MCCOMAPI NeedAnimatedShader() { return false; }

		// Returns true if this primitive has a mesh used only for final rendering.
		virtual boolean	   MCCOMAPI HasRenderingFacetMesh();

		/// Returns the mesh that should be used for final rendering.
		virtual MCCOMErr   MCCOMAPI GetRenderingFacetMesh(FacetMesh** outMesh);

		// ****************************************************************************
		//								GetRenderingMesh
		// 
		/// Returns a pointer to the rendering mesh associated with the primitive. Note
		/// that the mesh is not cached by the primitive so you can modify it and it is
		/// your responsability to delete it.
		///
		/// \return NULL if the primitive does not support this (in which case you should
		/// get the facet mesh.
		///
		virtual void MCCOMAPI GetRenderingMesh(MeshDataStructure::TMeshList** meshList);

		/// Returns the face set list associated with the primitive
		virtual void MCCOMAPI GetFaceSetList(TMCCountedPtrArray<TFaceSet>& faceSetList) {}

		// Never implement that one, reserved for future use (primitives with an infinite number of resolutions)
		//virtual MCCOMErr   MCCOMAPI GetFacetMesh		(real lod, FacetMesh** outMesh);

		// Return true if the primitive can split itself into sub parts of the same type
		virtual boolean		MCCOMAPI CanBeSplit			();

		// Builds a list of sub-parts of itself. 'subPartPositions' gives the relative position of each sub part in the object local coordinates. Both
		// arrays need to be of same size.
		virtual MCCOMErr	MCCOMAPI SplitPrimitive		(TMCCountedPtrArray<I3DExGeometricPrimitive>& subParts,
															 TMCArray<TTransform3D>& subPartPositions);

		virtual uint32		MCCOMAPI GetUVSpaceCount	();
		virtual MCCOMErr	MCCOMAPI GetUVSpace			(uint32 uvSpaceID, UVSpaceInfo* uvSpaceInfo);
		virtual boolean	    MCCOMAPI CanRenameUVSpace	() { return false; }
		virtual MCCOMErr	MCCOMAPI RenameUVSpace		(uint32 uvSpaceID, const TMCString& name) { return MC_E_NOTIMPL; }
		virtual MCCOMErr	MCCOMAPI UV2XYZ				(TVector2* uv, uint32 uvSpaceID, TVector3* resultPosition, boolean* inUVSpace); // Optional - Return E_NOTIMPL if not implemented
		virtual MCCOMErr	MCCOMAPI GetUVSpaceRDS5		(uint32 uvSpaceID, UVSpaceInfoRDS5* uvSpaceInfoRDS5); // To be implemented only if your primitive existed in RDS 5 or earlier, so that UV spaces can be mapped properly to the new 0..1 boundaries

		// retrieve the renderables through this routine
		virtual MCCOMErr	MCCOMAPI AppendToRenderables(const TTransform3D& worldFromModelTfm, 
															 TRenderableAndTfmArray& renderableAndTfm );
		//--
		// Return true if the primitive should be open in its modeler immediately after its insertion
		virtual boolean		MCCOMAPI AutoSwitchToModeler() const;

		// Return true if the primitive can be picked in the 3D View when clicking on its bounding box. Usually, you want
		// to reply no, since the picking is done thru a ray-tarcing hit test. However, some primitives such as volumic primitives
		// or particles systems may want to answer yes. Default implementation in TBasicPrimitive returns false.
		virtual boolean		MCCOMAPI IsBBoxPickable() const  {return false;}
		
		virtual MCCOMErr	 MCCOMAPI GetWizardPath(TMCString& path) { return MC_S_FALSE; }

		virtual boolean		 MCCOMAPI CanConvertToOtherModeler() { return false; }

		/// Return the path from the preset folder to the user-defined preset folder
		virtual void		MCCOMAPI GetUserPresetPath( TMCDynamicString& path ) { path = kNullString; };


		// Return true if its instances should be excluded from the triple buffer (eg used for skinning)
		virtual boolean		MCCOMAPI IsExcludedFromTripleBuffer() { return false; }

		virtual void		MCCOMAPI GetDefaultShader(I3DShShader** shader, TMCString* name = nil);

		virtual void		MCCOMAPI GetDefaultShaderInfo(	int32& 		outShaderResID,
															int32& 		outNameStringResID,
															int32& 		outNameStringIndex);

		virtual void		MCCOMAPI ChangedData() {}

		virtual boolean		MCCOMAPI IsGenerator() const { return false; }

		virtual void		MCCOMAPI GetPreviewObject(I3DShMasterShader* masterShader, I3DShObject** object, I3DShTreeElement** previewTree, I3DShTreeElement** additionnalChildInstance) {}

		virtual int32		MCCOMAPI GetPrimitiveInstanceType() const { return I3DShInstance::kStandardInstance; }

		virtual boolean		MCCOMAPI IsScalable() const			{ return false; }
		virtual real32		MCCOMAPI GetScalingFactor()	const	{ return Int16ToReal(1); }
		virtual void		MCCOMAPI SetScalingFactor(real32 inValue) {}

		virtual boolean		MCCOMAPI CanImportData	(I3DImportData*	inImportData, I3DShInstance* inInstance)	{ return false; }
		virtual boolean		MCCOMAPI ImportData		(I3DImportData* inImportData, I3DShInstance* inInstance)	{ return false; }

		virtual boolean MCCOMAPI ImplementDisplacementMapping() { return false; }
		virtual void MCCOMAPI DisplacementShaderChanged() {}
	// ****************************************************************************
	//								GetLodParamType
	// 
	/// \return The type of information used to calculate the appropriate LOD
	/// the default implementation return kLod_PixelSpaceDiagonalLength where subclasses can override
	/// 
	virtual ELODParamType	MCCOMAPI GetLODParamType() const;
   	// ****************************************************************************
	//								GetLodIndex
	//
    //  Calculate the appropriate LOD index for the specified distance
    //  the GetLodParamType() must kLod_DistanceFromCamera be otherwise there would be an exception
	//  This implementation always throws an exception as kLod_PixelSpaceDiagonalLength is always used.
	/// 
	virtual int16	MCCOMAPI GetLODIndex(real32 distance) const;
   	// ****************************************************************************
	//								GetAdditionalBoundingBoxVertices
	//
    //  Get an array of additional points needed to calculate the bounding box
    //  Default implementation does not add any point
	/// 
	virtual void GetAdditionalBoundingBoxVertices(TMCArray<TVector3>& additionalVertices) const;

	protected:

		//-- TBasicPrimitive specific calls 
		// You may want to override GetFidelity() if you are using the default LOD (level of detail) management of TBasicPrimitive
		virtual real				 GetFidelity		();
		virtual void				 GetMinMaxLOD		(real& minLOD, real& maxLOD);
};
/// \}
#endif
