////////////////////////////////////////////////////////////////////////////////
// Texture.h
// Copyright Björn Ganster 
// Developed since 2000
////////////////////////////////////////////////////////////////////////////////

#ifndef Texture__h
#define Texture__h

////////////////////////////////////////////////////////////////////////////////
// Includes

#include "BGBase.h"
#include "Color.h"

typedef size_t TextureDim;

////////////////////////////////////////////////////////////////////////////////
// Beginning with OpenGL 1.2, GL_BGR_EXT is replaced by GL_BGR.
// For compatibility with older systems, we define GL_BGR ourselves, if it is
// not provided.

#ifndef GL_BGR
   #ifdef GL_BGR_EXT
      #define GL_BGR GL_BGR_EXT
   #endif
#endif

////////////////////////////////////////////////////////////////////////////////
// Class declaration

class Texture: public VirtualClass
{
public:
	// Default constructor
	Texture (TextureDim sizex = 0, TextureDim sizey = 0, 
		GLenum _format = GL_BGR, const char* newname = "Texture",
		void* data = nullptr);

	// Destructor
	~Texture () OVERRIDE;

	// Clear texture
	void clear();

	// Load a texture from a file
	bool loadFromFile (const PathChar* FileName);
	bool loadFromFile (const char* data, size_t dataSize);

	// Save a texture to a file
	bool saveToFile (const PathChar* FileName, TextureDim left, TextureDim top, 
		TextureDim saveWidth, TextureDim saveHeight) const;

	// Read a texture from framebuffer
	void readFromFrameBuffer (unsigned int x, unsigned int y);

	// Prepare texture for rendering (will activate texture when needed)
	void use();
	void useMipmap();

	// Inform OpenGL that the texels were updated
	void update();

	// Deactivate texture
	void deactivate();

	// Resize the texture (contents are lost)
	bool resize (TextureDim sizex, TextureDim sizey, GLenum _format);

	// Some simple get/set functions
	TextureDim getWidth () const { return width; }
	TextureDim getHeight () const { return height; }
	unsigned char* getPicData () { return texels; }
	const unsigned char* getPicData () const { return texels; }

	// Copy part of another texture into this one
	void copy (Texture* other, TextureDim x1, TextureDim y1, TextureDim x2, TextureDim y2, 
		TextureDim tx, TextureDim ty);

	// Set pixel
	void setRGB (TextureDim u, TextureDim v, unsigned char r, 
		unsigned char g, unsigned char b);
	void setRGBA (TextureDim u, TextureDim v, unsigned char r, 
		unsigned char g, unsigned char b, unsigned char a);

	// Get pixel
	void getRGB (TextureDim u, TextureDim v, unsigned char& r, unsigned char& g, unsigned char& b) const;
	void getRGBA(TextureDim u, TextureDim v, unsigned char& r, unsigned char& g, unsigned char& b,
		unsigned char& a) const;

   // Check if format supports alpha
   bool hasAlpha () const
   { return format == GL_RGBA; }

   unsigned char getComponentCount()
   { return texelComponents; }

   void glTexCoord (double u, double v) const
   { 
      translateCoords(u,v);
      glTexCoord2d(u,v); 
   }

   // Translate coordinates
   void translateCoords (double& u, double& v) const
   {
      u = u * ((double) (width)) / ((double) (potWidth));
      v = v * ((double) (height)) / ((double) (potHeight));
   }

   // Render a line (includes line endpoint)
   void renderLine (int x1, int y1, int x2, int y2, 
                    unsigned char r, unsigned char g, unsigned char b);

   // Fill triangle
   void fillTriangle (int x1, int y1, int x2, int y2, int x3, int y3,
                      unsigned char r, unsigned char g, unsigned char b);

   // Fill star-shaped polygon given as a vector
   #ifdef TextureRasterizers
   void fillPolygon (const vector <int>& polygon, unsigned char r,
                     unsigned char g, unsigned char b, int cx, int cy);
   #endif

   // Fill square
   void fillRectI(int x1, int y1, int x2, int y2, unsigned char r,
	   unsigned char g, unsigned char b, unsigned char a);
   void fillRectI(int x1, int y1, int x2, int y2, unsigned char r,
	   unsigned char g, unsigned char b);
   void fillRectD(double x1, double y1, double x2, double y2, unsigned char r,
	   unsigned char g, unsigned char b);

   bool isActive() const
   { return active; }

   void takeScreenshot(int x1, int y1, int x2, int y2);

   void operator=(const Texture& other);

	// Fill part of target texture if the corresponding source texel is non-transparent
	// Used for font rendering. No scaling is applied.
	// x1, y1, x2, y2: range in source texture to copy
	// tx, ty: start of range in target texture (this texture)
	void copyNonTransparent (Texture* other, TextureDim x1, TextureDim y1, 
		TextureDim x2, TextureDim y2, TextureDim tx, TextureDim ty, unsigned char r, 
		unsigned char g, unsigned char b);

	// Copy one part of a texture to another, stretching it if necessary
	void stretchCopy(Texture* source, TextureDim su1, TextureDim sv1, TextureDim su2, TextureDim sv2,
		TextureDim tu1, TextureDim tv1, TextureDim tu2, TextureDim tv2, bool blendAlpha);

	// Get the handle that currently represents this texture in OpenGL
	GLuint getGLHandle() const;

	// Get width as a power of two
	TextureDim getPotWidth() const
	{ return potWidth; }

	// Get height as a power of two
	TextureDim getPotHeight() const
	{ return potHeight; }

protected:
   TextureDim width, height, potWidth, potHeight; // pot: power-of-two
   GLuint GLHandle;
   unsigned char* texels;
   GLenum format;
   unsigned char texelComponents; // Number of components in a texel
   TextureDim redOffset, blueOffset, greenOffset, alphaOffset;
   bool active;
};

#endif
