/* (c) 1999-2000 Tino Schwarze, see COPYING for details */
/**@pkg cObject.cMaterial.cTextureMaterial*/
/**
 * class for representing an OpenGL 2D textured material
 *
 * #include "cTextureMaterial.hh"
 *
 * -lMesaGL or -lGL
 *
 * A cTextureMaterial object can be used the same way as a
 * cMaterial object.
 * 
 * 1D textures are not supported.
 *
 * @see cMaterial
 *
 * @pkgdoc cObject.cMaterial.cTextureMaterial
 */

#ifndef cTextureMaterial_hh
#define cTextureMaterial_hh

#include <GL/gl.h>

#include "cMaterial.hh"
#include "common.hh"

/**
 * a class for representation of an OpenGL material
 	*
	* This is thought to be the base material class.
	*
	* It might be derived from it later. (e.g. for Texturing)
	*/
class cTextureMaterial : public cMaterial
{
public:
// LIFETIME
	/**
	 * default constructor
	 	* @param name optional name of object
		*/
	cTextureMaterial (const char *name = NULL);

	/**
	 * constructor with initialization
	 	* @param color material's color (cADSEColor object)
		* @param shininess how shiny is the surface (0..128)
		* @param name optional name of object
		*/
	cTextureMaterial (
		const cADSEColor &color = cADSEColor (),
		const int shininess = 0,
		const char *name = NULL);

	/**
	 * constructor with initialization
		* @param texture file name of texture to load
		* The texture is loaded by Init(). Only JPEG files are supported.
	 	* @param color material's color (cADSEColor object)
		* @param shininess how shiny is the surface (0..128)
		* @param name optional name of object
		*/
	cTextureMaterial (
		const char *texture,
		const cADSEColor &color,
		const int shininess,
		const char *name = NULL);

	/**
	 * constructor with initialization
		* @param texture file name of texture to load
		* The texture is loaded by Init(). Only JPEG files are supported.
		* @param usemipmaps enable mipmapping?
	 	* @param color material's color (cADSEColor object)
		* @param shininess how shiny is the surface (0..128)
		* @param name optional name of object
		*/
	cTextureMaterial (
		const char *texture,
		bool usemipmaps,
		const cADSEColor &color,
		const int shininess,
		const char *name = NULL);

	/**
	 * copy constructor - important!
	 	*/
	cTextureMaterial (const cTextureMaterial &ctm);

	/**
	 * destructor
	 	*/
	virtual ~cTextureMaterial ();

	/**
	 * initialization: loads texture
	 	*/
	virtual int Init ();

	/**
	 * enable/disable mipmapping
	 	* @param state enable or disable mipmaps
	 	*/
	virtual void SetMipmapping (bool state);

	/**
	 * get state of mipmapping
	 	*/
	virtual bool IsMipmapped () const;

	/**
	 * start using the material's properties
	 	*
		* This is only neccessary to embed a cMaterial into a
		* cVisibleObject. We cannot use Activate() there since
		* it will call cObject::Activate() which in turn calls
		* Deactivate() so the material settings are undone before
		* the object gets drawn.
		*/
	virtual void StartMaterialUse ();

	/**
	 * end using the material's properties
	 	*/
	virtual void EndMaterialUse ();

	/**
	 * load a (new) texture for the material
	 	* @param texture file name of texture to use (JPEG)
		* (NULL - delete texture, do not load a new one)
		* @param usemipmaps enable mipmapping?
		*
		* @return -1 on error, 0 on success
		*/
	virtual int LoadTexture (
		const char *texture,
		bool usemipmaps = false);

	/**
	 * supply a (new) texture for the material (it is copied)
	 	* @param width width of texture
		* @param height heigh of texture
		* @param components number of color components in texture
		* (3 = RGB, 4 = RGBA, no other values allowed)
		* @param data unsigned char ptr to texture data
		* @param usemipmaps enable mipmapping? (default: no)
		*
		* @return -1 on error, 0 on success
		*/
	virtual int UseTexture (
		int width,
		int height,
		int components,
		const unsigned char *data,
		bool usemipmaps = false);

	/**
	 * set parameters for texturing
	 	*
		* See OpenGL reference for GL_[NEAREST|LINEAR] etc. constants.
	 	* @param min_filter filter to use for minification
		* (default: GL_NEAREST)
		* @param min_mm_filter filter to use for minification when
		* using mipmapping (default: GL_NEAREST_MIPMAP_LINEAR)
		* @param mag_filter filter to use for magnification
		* (default: GL_NEAREST)
		* @param wrap_s method to use for wrapping textures s-coordinate
		* (default: GL_REPEAT)
		* @param wrap_t method to use for wrapping textures t-coordinate
		* (default: GL_REPEAT)
		* @param env_mode how to interpret the texel's color
		* (default: GL_DECAL)
	 	*/
	virtual void SetTextureParameters (
		GLenum min_filter = GL_NEAREST,
		GLenum min_mm_filter = GL_NEAREST_MIPMAP_LINEAR,
		GLenum mag_filter = GL_NEAREST,
		GLenum wrap_s = GL_REPEAT,
		GLenum wrap_t = GL_REPEAT,
		GLenum env_mode = GL_DECAL);

protected:
// PROTECTED METHODS
	virtual const char *GetDefaultName () const 
	{
		return "cTextureMaterial";
	}

	/**
	 * update texture - upload it to OpenGL
	 	*/
	virtual void UpdateTexture ();

	/**
	 * activate material
	 	*/
	virtual void Activate ();

	/**
	 * deactivate material
	 	*/
	virtual void Deactivate ();

	/** aquire a texture name from OpenGL */
	void AllocateTextureName ();

// PROTECTED DATA
	/** have we spoken to OpenGL yet? */
	bool mInitialized;

	/** file name of texture */
	string mTextureFile;

	/** current state of mipmapping */
	bool mMipmapped;

	/** width of texture */
	int mSizeX;

	/** height of texture */
	int mSizeY;

	/** number of color components within texture */
	int mComponentNo;

	/** texture data */
	void *mTextureData;

	/** 
	 * handle for texture (OpenGL slang: name) 
	 * 0 == no name allocated
	 */
	GLuint mTextureName;

	/** used by Start/EndMaterialUse to remember old bound
	 * texture */
	GLuint mOldTexBinding;
	/** old state of GL_TEXTURE_2D */
	GLboolean mOldTex2DState;

	/* used to store the texture parameters */
	GLint 
		/** minification filter for non-mipmaping */
		mMinFilter, 
		/** minification filter for mipmaping */
		mMinMmFilter, 
		/** magnification filter  */
		mMagFilter, 
		/** wrap-mode for S coordinate */
		mWrapS, 
		/** wrap-mode for T coordinate */
		mWrapT, 
		/** glTexEnv mode (how to apply texel color) */
		mEnvMode;

	/* needed for Deactivate() */
	GLint 
		/** saved minification filter */
		mOldMinFilter, 
		/** saved magnification filter  */
		mOldMagFilter, 
		/** saved wrap-mode for S coordinate */
		mOldWrapS, 
		/** saved wrap-mode for T coordinate */
		mOldWrapT, 
		/** saved glTexEnv mode (how to apply texel color) */
		mOldEnvMode;
};

#endif // ifndef cTextureMaterial_hh

