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

File: CubemappedPlanetReader.h
Desc: A class for managing cubemapped planets
		
Date: 2005/01/01

Author: Wim Lemkens

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

#ifndef CUBEMAPPEDPLANETREADER_H
#define CUBEMAPPEDPLANETREADER_H

#include "PlanetReader.h"
#include "Vertex.h"
#include "Vector3ix.h"
#include <OgreVector3.h>
#include <OgreVector2.h>

namespace Ogre {
	
class CubemappedPlanetReader : public PlanetReader {
public:

	CubemappedPlanetReader();
	virtual ~CubemappedPlanetReader();
	
	/**
	 * Return the vertex with the given coordinates
	 * @param x		The x-coordinate of the vertex to return
	 * @param y		The y-coordinate of the vertex to return
	 * @param level	The level of detail from which the vertex is to be 
	 * 				returned
	 * @param map	The side of the cubemap from which the vertex is to be 
	 * 				returned
	 */
	Vertex* getVertex(int x, int y, int level, int map);

	/**
	 * Return a vector pointing perpendicular away from the surface
	 * @param x		The x-coordinate of the vertex to return the normal of
	 * @param y		The y-coordinate of the vertex to return the normal of
	 * @param level	The level of detail from which the normal of the vertex is to be 
	 * 				returned
	 * @param map	The side of the cubemap from which the normal of the vertex is to be 
	 * 				returned
	 */
	Vector3 getNormalOnSphere(int x, int y, int level, int map) const;
	
	/**
	 * Returns the width in number of vertices
	 */
	int getMapSize() const;
	
	/**
	 * Return the height of the vertex at the given coordinates
	 * @param x		The x-coordinate of the vertex to return the height of
	 * @param y		The y-coordinate of the vertex to return the height of
	 * @param level	The level of detail from which the height of the vertex
	 * 				is to be returned
	 * @param map	The side of the cubemap from which the height is to be 
	 * 				returned
	 */
	Real getHeight(int x, int y, int level, int map) const;

	/**
	 * An ugly method for not having to rewrite all the Quad methods
	 * Returns 0 if the quad is of the map
	 * Returns the topleft vertex of the quad if it is on the map
	 */
	Vertex* getQuad(Vector3ix pos, int map);
	
	/**
	 * Returns the height of a point taking into account that if the vertex is
	 * on the edge of a cubemap it will take the correct value
	 * @param x	The x-coordinate of the requested vertex
	 * @param y	The y-coordinate of the requested vertex
	 * @param level	The level of which the point is requested
	 * @param map	Which of the 6 sides of the cube the vertex is requested from
	 */
	Real getEdgeHeight(int x, int y, int level, int map) const;

        /**
         * Returns the height of a point on the map
         * @param x     The x-coordinate of the requested vertex
         * @param y     The y-coordinate of the requested vertex
         * @param level The level of which the point is requested
         * @param map   Which of the 6 sides of the cube the vertex is requested from
         */
	Real getRealHeight(int x, int y, int level, int map) const;

	/**
	 * Calculates the vertex-coordinates for a given height on the given position
	 * @param x	The x-coordinate of the requested vertex
	 * @param y	The y-coordinate of the requested vertex
	 * @param level	The level of which the point is requested
	 * @param map	Which of the 6 sides of the cube the vertex is requested from
	 * @param height	The height to be added to the sphere
	 */
	Vector3 getEdgePosition(int x, int y, int level, int map, Real height);

protected:

	/**
	 * Read the height from file of the vertex at the given coordinates
	 * @param x		The x-coordinate of the vertex to return the height of
	 * @param y		The y-coordinate of the vertex to return the height of
	 * @param level	The level of detail from which the height of the vertex
	 * 				is to be returned
	 * @param map	The side of the cubemap from which the height is to be 
	 * 				returned
	 */
	virtual Real readHeight(int x, int y, int level, int map) const;

	/**
	 * Return the position in the file where the height of the given vertex
	 * is stored
	 * @param x		The x-coordinate of the vertex to return the height of
	 * @param y		The y-coordinate of the vertex to return the height of
	 * @param level	The level of detail from which the height of the vertex
	 * 				is to be returned
	 * @param map	The side of the cubemap from which the height is to be 
	 * 				returned
	 */
	virtual int getVertexPosition(int x,int y,int level,int map) const;

	/**
	 * Returns the size 1 map takes in the file
	 */
	int getMapSaveSize() const;
	
	/**
	 * The size 1 map takes in the file
	 */
	int mMapSize;

	/**
	 * Returns the position of the vertex with given coordinates in world-
	 * coordinates
	 * @param x		The x-coordinate of the vertex
	 * @param y		The y-coordinate of the vertex
	 * @param level	The level of detail
	 * @param map	The side of the cubemap
	 */
	Vector3 getPosition(int x, int y, int level, int map) const;

	/**
	 * Returns the position of the vertex with given coordinates in world-
	 * coordinates. The height of the vertex is given to prevent double 
	 * calculations
	 * @param x		The x-coordinate of the vertex
	 * @param y		The y-coordinate of the vertex
	 * @param level	The level of detail
	 * @param map	The side of the cubemap
	 * @param height	The height of the vertex
	 */
	Vector3 getPosition(int x, int y, int level, int map, Real height) const;

	/**
	 * Returns the point on the sphere-surface
	 * @param x		The x-coordinate of the vertex
	 * @param y		The y-coordinate of the vertex
	 * @param level	The level of detail
	 * @param map	The side of the cubemap
	 */
	Vector3 getPointOnSphere(int x, int y, int level, int map) const;

	
	/**
	 * Returns the normal of the vertex
	 * @param x		The x-coordinate of the vertex
	 * @param y		The y-coordinate of the vertex
	 * @param level	The level of detail
	 * @param map	The side of the cubemap
	 * @param &point	The position of the point, given to not having to
	 * 					calculate it twice
	 */
	Vector3 getNormal(int x, int y, int level, int map, Vector3 &point) const;

	/**
	 * The 6 vertexbuffers associated with the 6 sides of the cubemap
	 */
	VertexBuffer *vertexBuffers[6];
	
	/**
	 * Return true if the given vertex is in the buffer
	 */
	bool isInBuffer(int x,int y,int level,int map) const;
	
	/**
	 * Calculates the height of a point on the sphere by interpolating between 
	 * the vertices of the previous level
	 */
	Real calculateHeight(int x, int y, int level, int map) const;
	
	/**
	 * Calculates the height of a point on the sphere by interpolating between 
	 * the vertices of the previous level
	 */
	Real interpolateHeight(int x, int y, int level, int map) const;

	/**
	 * Calculates the texturecoordinates for the given vertex
	 */
	virtual Vector2 getTextureCoordinates(int x, int y, int level, int map) const = 0;
	
	/**
	 * Returns true if the vertex in the borders of its lod
	 */
	bool isInLevelBorders(int x, int y, int level) const;

	/**
	 * Assembles the vertex, puts it in the buffer and returns it.
	 */
	Vertex* calculateVertex(int x, int y, int level, int map);

	//TOCHECK is this in use?
	Real rnd() const;
	
	/**
	 * Returns true is the given coordinates are on the border of a level
	 */
	bool isOnLevelBorders(int x, int y, int level) const;
	
	/**
	 * Get a vertex that is exterior to the asked map
	 * @param x	The x-coordinate of the requested vertex
	 * @param y	The y-coordinate of the requested vertex
	 * @param level The level of the requested vertex
	 * @param map	The reference side of the cubemap
	 * @pre	<x> or <y> should be out of the map-bounds
	 */
	Vertex* getExternalVertex(int x, int y, int level, int map);

	/**
	 * Turn coordinates that are out of bound into coordinates that are 
	 * in bounds on the map relative to the original coordinates
	 */
	void putOnCorrectMap(int &x, int &y, int &level, int &map) const ;
};

} //namespace Ogre
#endif // CUBEMAPPEDPLANETREADER_H
