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

		I3DShRenderable.h

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

		Author:	Alec
		Date:	3/16/98

		Revision History

		when		who			what & why
		==========	==========	======================================================
		08/10/99	Arnaud		FacetMesh is now counted.
		7/1/99		Alec		removed opacity flag, use renderable blended flag instead,
									interactive renderer does not handle true transparency
		6/8/99		Alec		added skip draw flag
		5/26/99		Emil		changed GetStandardShader/Texture to GetShaderApprox,
									GetFlatennedTexturesAsync
		5/19/99		Alec		fixed IsBoxOnly call, added skip pick flag
		4/8/99		Alec		added several flags to the renderable, added the
									interface for setting the
		3/10/99		Alec		added IsBlended case for interactive transparency
		3/9/99		Alec		added kInterfaceShapeMask so that we can classify
									the renderable
		12/6/98		Alec		class -> struct for interface, added ClearFCache member,
									GetShader -> GetShadingApproximation
		11/24/98	Joshua		Added IID
		10/6/98		Alec		new today - a simplification of instance to rendering
									specific data

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

#ifndef __I3DSHRENDERABLE__
#define __I3DSHRENDERABLE__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "I3DShFacetMesh.h"
#include "BitField.h"
#include "MCClassArray.h"
#include "MCCountedPtr.h"
#include "Transforms.h"
#include "MCColorRGB.h"
#include "InstancePath.h"
#include "I3DShInstance.h"
#include "TBBox.h"
#include "LodParamEnum.h"


//****** Globally Unique Ids *************************************************

MCDEFINE_GUID_H(IID_I3DShRenderable);

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

class TMCPixelBucket;
class TMCRect;
struct IShTextureMapBucketCache;

						 
enum ERenderableMod
{
	// these are change messages that we care about for a particular renderable
	
	kRenderableMod_Clear			= 0,  // force clearing a single renderable cache without reason
	
	kRenderableMod_Added			= 1,  // these would be nice, but cache can probably cleanup without them
	kRenderableMod_Deleted			= 2,
	
	kRenderableMod_Moved			= 16,  // especially time change message should translate into this
	kRenderableMod_ShapeChange 		= 17, // for deformers
	kRenderableMod_ShaderChange		= 18, // the surface of the object has changed
	kRenderableMod_LightingChange	= 19  // light may not have moved, but user could mod the intensity
};

/// \addtogroup Data 
/// \{

/// These are various flags to communicate object state to the renderer.
///
class TRenderableFlags : public TBitField32
{
public:
	enum
	{
		// If you add flags here, make sure you provide a test function.  Also be
		// careful about the 0 state, since 0 is the default flag value.

		kStaticMask 			= ( 1 << 0 ), ///< moving or not
		kSelectedMask 			= ( 1 << 1 ), ///< selected (for instances ?)
		kBackfacedMask 			= ( 1 << 2 ), ///< backfaces removed
		kDropShadowedMask 		= ( 1 << 3 ), ///< drop shadowed
			
		kInterfaceShapeMask		= ( 1 << 4 ), ///< a shape may be purely for interface
		kBlendedMask			= ( 1 << 5 ), ///< apply faux blended transparency, not a surface property
		
		kOrientClockwiseMask	= ( 1 << 6 ), ///< clockwise = 1, counter = 0

		// kSingleSidedSurface 	= ( 1 << 7 ), // use backface flag instead for now
		// kInfinitePlane		= ( 1 << 8 ),
		kBoxOnly				= ( 1 << 9 ), ///< render mesh only as bbox

		kNoDepthBuffering		= ( 1 << 10 ), ///< transform the pts, but don't depth buffer 
		
		kSkipPick				= ( 1 << 11 ), ///< skipped for picking
		kSkipDraw				= ( 1 << 12 ), ///< skipped for rendering
		
		kForceWire				= ( 1 << 13 ), // 
		kForceTexturing			= ( 1 << 14 ), // 
		kForceFlat				= ( 1 << 15 ), // 

		kUpdateTexture			= ( 1 << 16 ), // 
		kForceBumpMap			= ( 1 << 17 ), //
		kForceSpecularMap		= ( 1 << 18 ), //
		// also flags for forcing object to always display as facets as wires
		// still need flags here for whether to cache data or not 

		// flags needed by the vertex modeler
		kUseScreenCoordsMask 	= ( 1 << 29 ), // screen coordinates ?
		kUseScreenColorsMask 	= ( 1 << 30 ), // colors in array are used directly

		// hilite uv space
		kHiliteUVSpace			= ( 1 << 31 ),
	
		kMaxMask				= 0x7fffffff  // not a valid constant
	};
	
	inline TRenderableFlags()
		: TBitField32( 0 )
	{ }
	
	// should renderers know about this state info ?
	inline boolean IsStatic() const
		{ return TestMasked( kStaticMask ); }
	inline boolean IsSelected() const
		{ return TestMasked( kSelectedMask ); }

	// this shape is interface and may be skipped for final quality renders
	inline boolean IsInterfaceShape() const
		{ return TestMasked( kInterfaceShapeMask ); }
	inline boolean IsBoxOnly() const
		{ return TestMasked( kBoxOnly ); }

	// visibility for various modes (for now rendering/picking both)
	inline boolean IsDrawn() const
		{ return ! TestMasked( kSkipDraw ); }
	inline boolean IsPickable() const
		{ return ! TestMasked( kSkipPick ); }
	
	// some points/lines may not be visible during depth buffering, this disables it
	inline boolean IsDepthBuffered() const
		{ return ! TestMasked( kNoDepthBuffering ); }

	// drop shadows displayed if possible
	inline boolean IsDropShadowed() const
		{ return TestMasked( kDropShadowedMask ); }

	// these two determine the backfacing on the mesh
	inline boolean IsBackfaced() const
		{ return TestMasked( kBackfacedMask ); }
	inline boolean IsOrientedClockwise() const
		{ return TestMasked( kOrientClockwiseMask ); }
	
	// a simple transparent blend is applied to this object
	inline boolean IsBlended() const
		{ return TestMasked( kBlendedMask ); }

	inline boolean IsUpdateTexture() const
		{ return TestMasked( kUpdateTexture); }

	inline boolean IsHiliteUVSpace() const
		{ return TestMasked(kHiliteUVSpace); }

	int32		fUVSpace;
};
/// \}

/// This class represents an approximation to the basic shader properties
/// for an object.  Use the diffuse color when a single representative
/// color is desired.
///
class TShadingApproximation
{


public:
	inline void Init( void )
	{
		// the material props
		fDiffuseColor 		= TMCColorRGB::kWhite,
		fEmissiveColor 		= TMCColorRGB::kBlack,
		fAmbientColor 		= TMCColorRGB::kBlack,
		fSpecularColor 		= TMCColorRGB::kBlack,
		fSpecularIntensity 	= 0.0;
		fSpecularCoeff		= 1.0;
		fOpacity			= 1.0;
		fReflection			= TMCColorRGB::kBlack;

		// to respond to changes in the shader
		fShaderChangeCounter	= 0;
	};

	TMCColorRGB	fDiffuseColor;
	TMCColorRGB fEmissiveColor;
	TMCColorRGB fAmbientColor;
	TMCColorRGB fSpecularColor;
	real		fSpecularIntensity;
	real		fSpecularCoeff;
	real		fOpacity;
	TMCColorRGB fReflection;

	/// this is an incrementing counter advanced each time the surface changes
	/// the counter is used by the renderer to determine whether it's local cache is invalid
	///
	uint32		fShaderChangeCounter;
};

/// \addtogroup ShellInterface
/// \{

/// A renderable represents a geometry that should be rendered by the interactive renderer (see I3DExRendererBox).
/// It can be either composed of points, segments or facets.
///
struct I3DShRenderable : public IMCUnknown
{	
	// only one type of data is transported in each renderable
	enum EType
	{
		kType_Point,
		kType_Segment,
		kType_Facet,
		kType_Segment2D,
		kType_BitMap2D
	};
	// ****************************************************************************
	//								GetGeometryType
	// 
	/// Returns the type of geometry that should be rendered (points, segments or triangles...)
	/// 
	virtual I3DShRenderable::EType MCCOMAPI GetGeometryType		() const = 0;
	
	// ****************************************************************************
	//								GetPointMesh
	// 
	/// Returns a pointer to the point mesh contained in this renderable. Returns NULL
	/// if the renderable is not a point mesh (see GetGeometryType()).
	/// 
	virtual const TPointMesh*   MCCOMAPI	GetPointMesh		() const = 0;

	// ****************************************************************************
	//								GetSegmentMesh
	// 
	/// Returns a pointer to the segment mesh contained in this renderable. Returns NULL
	/// if the renderable is not a segment mesh (see GetGeometryType()).
	///
	virtual const TSegmentMesh* MCCOMAPI 	GetSegmentMesh		() const = 0;		
	
	// retrieve a facet mesh based on an lod level
	// ****************************************************************************
	//								GetFMesh
	// 
	/// Returns a pointer to the triangle mesh contained in this renderable (see GetGeometryType()).
	/// 
	/// \param lod    The lod that is requested.
	/// \param amesh  A pointer to the mesh that is returned.
	/// 
	virtual	MCCOMErr MCCOMAPI GetFMesh						(real lod, FacetMesh** amesh) = 0;


	// ****************************************************************************
	//								GetPixelBucket
	// 
	/// Returns a pointer to the pixel bucket contained by the renderable. Returns NULL
	/// if the renderable is not a 2D image (see GetGeometryType()).
	/// 
	virtual const TMCPixelBucket*	MCCOMAPI GetPixelBucket(TMCRect& rect) const = 0;

	
	// ****************************************************************************
	//								GetRenderableFlags
	// 
	/// Returns the flags associated with this renderable. See TRenderableFlags for
	/// more info.
	/// 
	virtual	TRenderableFlags MCCOMAPI GetRenderableFlags	(void) const = 0;
	
	// ****************************************************************************
	//								SetRenderableFlags
	// 
	/// Sets the flags associated with this renderable.
	/// 
	/// \param flags  The flags.
	/// 
	virtual	MCCOMErr		 MCCOMAPI SetRenderableFlags	(const TRenderableFlags flags) = 0;
	
	// ****************************************************************************
	//								GetShadingApproximation
	// 
	/// Returns an approximation of the shading that can be used for interactive
	/// rendering.
	/// 
	/// \param shadingApprox  The color of the shader.
	/// \param uvSpaceID      The UVSpaceID for which the approximation is required.
	/// 
	virtual	MCCOMErr MCCOMAPI GetShadingApproximation		(TShadingApproximation&	shadingApprox,uint32 uvSpaceID) const = 0;
	
	// ****************************************************************************
	//								GetFlatennedTexturesAsync
	// 
	/// Calculates a set of texture maps that approximates the shading on the instance.
	/// 
	/// \param uvSpaceID  The shading domain index.
	/// \param maps       The maps that are returned.
	/// \param proc		  A callback function called when the texture is available.
	/// \param privData   Data passed by the callback.
	/// \param range      A rectangle in the texture coordinates. (NULL if the whole uvspace is required).
	/// 
	virtual MCCOMErr MCCOMAPI GetFlatennedTexturesAsync		(uint32					uvSpaceID, 
															 UVMaps&				maps, 
															 TextureAvailableProc	proc, 
															 void*					privData, 
															 TMCRealRect*			range = nil) const = 0;

	// ****************************************************************************
	//								GetBoundingBox
	// 
	/// Returns the bounding box of the renderable in local coordinates (for triangle meshes).
	/// 
	/// \param bb  The bounding box that is returned.
	/// 
	virtual void	MCCOMAPI GetBoundingBox					(TBBox3D& bb) = 0;
	
	// ****************************************************************************
	//								GetUVSpaceCount
	// 
	/// Returns the number of shading domaine (uv space) on the primitive.
	/// 
	/// 
	virtual uint32   MCCOMAPI GetUVSpaceCount				() = 0; // const
	
	// we will eventually need the data from the uvSpaceInfo ? wrap info
	// virtual MCCOMErr MCCOMAPI GetUVSpace(uint32 uvSpaceID, UVSpaceInfo* uvSpaceInfo);

	// ****************************************************************************
	//								GetInstance
	// 
	/// Returns a pointer to the instance that corresponds to the renderable. Note
	/// that it can be NULL if the renderable has no instance
	/// 
	/// \param instance  A pointer to the instance.
	/// 
	virtual MCCOMErr MCCOMAPI GetInstance				(I3DShInstance **instance) = 0;

	// ****************************************************************************
	//								SetFinalRenderingFlag
	// 
	/// \param finalRendering    True if the renderaable is used for final rendering.
	/// 
	virtual void		MCCOMAPI SetFinalRenderingFlag(boolean finalRendering) = 0;

	// ****************************************************************************
	//								GetLodParamType
	// 
	/// \return The type of information used to calculate the appropriate LOD
	/// 
	virtual ELODParamType	MCCOMAPI GetLODParamType() const = 0;
    // ****************************************************************************
    //                             GetRecommendedTextureSize
    //
    /// Calculate the intrinsic appropriate texture size.
    // \return true if there is such a size, or false of the texture is procedural 
    virtual boolean  MCCOMAPI GetRecommendedTextureSize(uint32 uvSpaceID, uint32 channelIndex, uint32& width, uint32& height) const = 0;

    // ****************************************************************************
    //                             GetRelevantTextureBucketCache
    //
    /// Get the texture map file associated to the specified shading domain.
    virtual void MCCOMAPI GetRelevantTextureBucketCache(uint32 uvSpaceID, uint32 channelIndex, boolean allowMultiplierModification, IShTextureMapBucketCache **outTextureMapFile) const = 0;
};

/// \}

/// This encapsulates an instance and renderable along with the flattened transform.
///
class TRenderableAndTfm
{
public:
	TRenderableAndTfm():fInstance(NULL) {}

	/// \note some renderables may not have a corresponding instance
	///
	I3DShInstance*	fInstance;		// We don't want to count the instance one as it can be the tree that owns the 
									// InstanceCache and wedon't want a circular reference

	/// Points to an object that contains the instantiation path (list of scene instances)
	/// This is used to identify the renderables when deleting them.
	///	This pointer is NULL if not child of a sceneInstance.
	TMCCountedPtr<TInstancePath>	fInstancePath;
	
	TMCCountedPtr<I3DShRenderable>	fRenderable;	///< The renderable to draw
	
	TTransform3D		fT;							
	TTransform3D 		fModelFromWorldTfm;

	void operator= (const TRenderableAndTfm& in)
	{
		fInstance=in.fInstance;
		fInstancePath=in.fInstancePath;
		fRenderable=in.fRenderable;
		fT=in.fT;
		fModelFromWorldTfm=in.fModelFromWorldTfm;
	}
};

// the renderables are typically stored in an array
class TRenderableAndTfmArray : public TMCClassArray<TRenderableAndTfm>
{
};

/// Encapsulates a 2D renderable
///
class TRenderable2D
{
public:
	TRenderable2D() {}

	TMCCountedPtr<I3DShRenderable>	fRenderable;	///< The renderable to draw
};

class TRenderable2DArray : public TMCClassArray<TRenderable2D>
{
};

#endif
