/*
								+----------------------------------+
								|                                  |
								|     ***  VBO wrap class  ***     |
								|                                  |
								|   Copyright © -tHE SWINe- 2005   |
								|                                  |
								|       VertexBufferObject.h       |
								|                                  |
								+----------------------------------+
*/

#pragma once
#ifndef __VERTEX_BUFFER_OBJECT_INCLUDED
#define __VERTEX_BUFFER_OBJECT_INCLUDED

/**
 *	@file gl2/VertexBufferObject.h
 *	@date 2005
 *	@author -tHE SWINe-
 *	@brief VBO wrap class
 *
 *	@date 2006-08-13
 *
 *	passed code revision
 *
 *	integers, contanining just true or false were changed to bool
 *	added CPixelBufferObject class
 *	changed behavior of CVertexBufferObject::UnMap() so it returns true when buffer was not mapped
 *	(thereby return walue false always mean buffer data were lost)
 *	renamed CVBOUnBinder to CBufferObjectUnBinder
 *
 *	@date 2007-03-14
 *
 *	passed code revision
 *
 *	fixed flaw in CGLVertexBufferObject::BindAs() where explicit bind target was not used
 *	renamed CVertexBufferObject to CGLVertexBufferObject, renamed CPixelBufferObject to
 *	CGLPixelBufferObject and CBufferObjectUnBinder to CGLBufferObjectUnBinder
 *
 *	@date 2007-05-10
 *
 *	removed debug buffer properties consistency checks as they fails in case another
 *	buffer (or no buffer) is bound, properties are now returned by inline functions
 *	added CGLVertexBufferObject::n_Primary_Target() and CGLVertexBufferObject::n_Bind_Target()
 *	functions to reduce confusion about what target should be unbound
 *
 *	@date 2007-11-10
 *
 *	improved linux compatibility
 *
 *	@date 2008-08-08
 *
 *	added \#ifdef for windows 64
 *
 *	@date 2009-05-04
 *
 *	fixed mixed windows / linux line endings
 *
 *	@date 2012-06-19
 *
 *	Moved multiple inclusion guard before file documentation comment.
 *
 */

/*
 *	class CGLVertexBufferObject
 *		- class, wrapping GL_ARB_VERTEX_BUFFER_OBJECT extension
 *		- object of this class holds a single vertex buffer object, it is created in OpenGL when
 *		  first called to Bind(), BindAs() or Alloc()
 *		- OpenGL object is destroyed when CGLVertexBufferObject class object is destroyed
 */
class CGLVertexBufferObject {
protected:
	GLuint m_n_buffer_id;
	unsigned int m_n_size;
	int m_n_usage;
	int m_n_access;
	GLenum m_n_primary_target, m_n_bind_target;
	bool m_b_mapped;

public:
	/*
	 *	CGLVertexBufferObject::CGLVertexBufferObject(GLenum n_target = GL_ARRAY_BUFFER_ARB)
	 *		- default constructor
	 *		- valid parameters are GL_ARRAY_BUFFER_ARB (vertex data) and
	 *		  GL_ELEMENT_ARRAY_BUFFER_ARB (vertex indices)
	 */
	CGLVertexBufferObject(GLenum n_target = GL_ARRAY_BUFFER_ARB);

	/*
	 *	CGLVertexBufferObject::~CGLVertexBufferObject()
	 *		- default destructor
	 */
	~CGLVertexBufferObject();

	/*
	 *	static bool CGLVertexBufferObject::b_Supported()
	 *		- returns true when GL_ARB_VERTEX_BUFFER_OBJECT extension is supported
	 *		  and all entry points are located
	 */
	static bool b_Supported();

	/*
	 *	bool CGLVertexBufferObject::Bind(CGLState *p_state)
	 *		- binds the buffer with target set to target, passed to constructor
	 *		  (when called first time, it creates OpenGL object as well)
	 *		- returns true on success, false on failure
	 */
	bool Bind(CGLState *p_state);

	/*
	 *	bool CGLVertexBufferObject::BindAs(CGLState *p_state,
	 *		GLenum n_target = GL_PIXEL_PACK_BUFFER_ARB)
	 *		- binds the buffer with target n_target
	 *		  (when called first time, it creates OpenGL object as well)
	 *		- returns true on success, false on failure
	 *		- valid parameters are GL_ARRAY_BUFFER_ARB (vertex data) and
	 *		  GL_ELEMENT_ARRAY_BUFFER_ARB (vertex indices)
	 *		- note GL_PIXEL_PACK_BUFFER_ARB and GL_PIXEL_UNPACK_BUFFER_ARB are possible, but
	 *		  should only be used with CGLPixelBufferObject (it's essentialy the same class, but it
	 *		  makes you sure you check hardware support of this extension)
	 *		- you can copy data using glReadPixels or glGetTexImage with <data> parameter,
	 *		  returned by call to p_OffsetPointer(0)
	 */
	bool BindAs(CGLState *p_state, GLenum n_target = GL_PIXEL_PACK_BUFFER_ARB);

	/*
	 *	bool CGLVertexBufferObject::Alloc(CGLState *p_state, unsigned int n_size,
	 *		const void *p_data = 0, GLenum n_usage = GL_STATIC_DRAW_ARB)
	 *		- alloc buffer data of size n_size bytes, can be initialized to p_data in case
	 *		  non-NULL pointer is supplied
	 *		- n_usage is optimalization hint only, it is one of:
	 *		  GL_STREAM_DRAW_ARB, GL_STREAM_READ_ARB, GL_STREAM_COPY_ARB
	 *		  GL_STATIC_DRAW_ARB, GL_STATIC_READ_ARB, GL_STATIC_COPY_ARB
	 *		  GL_DYNAMIC_DRAW_ARB, GL_DYNAMIC_READ_ARB, GL_DYNAMIC_COPY_ARB
	 *		- in case buffer was allocated already, it's data are freed as soon as there are no
	 *		  OpenGL commands, sourcing data from it (it shouldn't block program execution,
	 *		  depends on graphics card vendor and driver version) and new buffer is allocated
	 *		- it always returns true, but it may generate GL_OUT_OF_MEMORY error (call glGetError())
	 */
	bool Alloc(CGLState *p_state, unsigned int n_size, const void *p_data = 0,
		GLenum n_usage = GL_STATIC_DRAW_ARB);

	/*
	 *	inline void *CGLVertexBufferObject::p_OffsetPointer(unsigned int n_offset)
	 *		- returns offset pointer for use with glDrawElements, etc ... (always, can never fail)
	 *		- do not use this pointer to access data, it doesn't point to client address space
	 */
	inline void *p_OffsetPointer(unsigned int n_offset) { return (void*)((char*)NULL + n_offset); }

	/*
	 *	void CGLVertexBufferObject::BufferSubData(CGLState *p_state, unsigned int n_offset,
	 *		unsigned int n_size, const void *p_data)
	 *		- re-specify part (or all) of buffer data from p_data
	 *		- n_offset must be greater or equal to 0, n_offset + n_size must
	 *		  be less or equal to buffer size, otherwise OpenGL error is generated (glGetError())
	 */
	void BufferSubData(CGLState *p_state, unsigned int n_offset,
		unsigned int n_size, const void *p_data);

	/*
	 *	void CGLVertexBufferObject::GetBufferSubData(CGLState *p_state, unsigned int n_offset,
	 *		unsigned int n_size, void *p_data)
	 *		- read part (or all) of buffer data into p_data
	 *		- n_offset must be greater or equal to 0, n_offset + n_size must
	 *		  be less or equal to buffer size, otherwise OpenGL error is generated (glGetError())
	 */
	void GetBufferSubData(CGLState *p_state, unsigned int n_offset,
		unsigned int n_size, void *p_data);

	/*
	 *	void *CGLVertexBufferObject::p_Map(CGLState *p_state, GLenum n_access)
	 *		- map buffer into client address space (one buffer only can be mapped at a time)
	 *		- n_access is buffer access, it can be one of:
	 *		  GL_READ_ONLY_ARB, GL_WRITE_ONLY_ARB, GL_READ_WRITE_ARB
	 *		- return client address space pointer in case of success or NULL on failure
	 */
	void *p_Map(CGLState *p_state, GLenum n_access);

	/*
	 *	void *CGLVertexBufferObject::p_BufferPointer(CGLState *p_state)
	 *		- in case buffer object has been successfuly mapped, return client-space pointer
	 *		  otherwise return NULL
	 */
	void *p_BufferPointer(CGLState *p_state); // return pointer only in case it's been mapped

	/*
	 *	bool CGLVertexBufferObject::UnMap(CGLState *p_state)
	 *		- unmaps buffer, returns true on success or in case buffer was not mapped
	 *		- returns false on failure (buffer contents were lost, may be caused by
	 *		  screen-mode switch while buffer was bound)
	 */
	bool UnMap(CGLState *p_state);

	/*
	 *	unsigned int CGLVertexBufferObject::n_Size()
	 *		- returns size of buffer in bytes
	 */
	inline unsigned int n_Size() { return m_n_size; }

	/*
	 *	int CGLVertexBufferObject::n_Usage()
	 *		- returns buffer ussage; one of:
	 *		  GL_STREAM_DRAW_ARB, GL_STREAM_READ_ARB, GL_STREAM_COPY_ARB
	 *		  GL_STATIC_DRAW_ARB, GL_STATIC_READ_ARB, GL_STATIC_COPY_ARB
	 *		  GL_DYNAMIC_DRAW_ARB, GL_DYNAMIC_READ_ARB, GL_DYNAMIC_COPY_ARB
	 */
	inline GLenum n_Usage() { return (m_b_mapped)? m_n_usage : 0; }

	/*
	 *	bool CGLVertexBufferObject::b_Mapped()
	 *		- returns true in case buffer contents were mapped into client-space memory
	 *		- it's possible to obtain pointer to buffer data by call to p_BufferPointer()
	 */
	inline bool b_Mapped() { return m_b_mapped; }

	/*
	 *	int CGLVertexBufferObject::n_AccessFlag()
	 *		- returns access flag to buffer in case it has been mapped (one of GL_READ_ONLY_ARB,
	 *		  GL_WRITE_ONLY_ARB, GL_READ_WRITE_ARB), in case buffer is not mapped, return 0
	 */
	inline GLenum n_AccessFlag() { return (m_b_mapped)? m_n_access : 0; }

	/*
	 *	GLenum CGLVertexBufferObject::n_Primary_Target()
	 *		- returns default target of buffer object (ie. target which is given
	 *		  in constructor and used in Bind())
	 *		- added to supress confusion about what target should be un-bound after
	 *		  finishing work with some buffer object
	 */
	inline GLenum n_Primary_Target() { return m_n_primary_target; }

	/*
	 *	GLenum CGLVertexBufferObject::n_Bind_Target()
	 *		- returns last bind target of buffer object (ie. target which is given
	 *		  in constructor and used in Bind())
	 *		- added to supress confusion about what target should be un-bound after
	 *		  finishing work with some buffer object
	 */
	inline GLenum n_Bind_Target() { return m_n_bind_target; }
};

/*
 *	class CGLPixelBufferObject
 *		- class, wrapping GL_ARB_PIXEL_BUFFER_OBJECT extension
 *		- extension adds no new api to GL_ARB_VERTEX_BUFFER_OBJECT, there are only two new
 *		  bind targets (GL_PIXEL_PACK_BUFFER_ARB, GL_PIXEL_UNPACK_BUFFER_ARB)
 *		- this class adds different default constructor parameter and checks for
 *		  GL_ARB_PIXEL_BUFFER_OBJECT extension support in b_Supported()
 */
class CGLPixelBufferObject : public CGLVertexBufferObject {
public:
	/*
	 *	CGLPixelBufferObject::CGLPixelBufferObject(GLenum n_target = GL_PIXEL_PACK_BUFFER_ARB)
	 *		- default constructor, valid parameters are GL_ARRAY_BUFFER_ARB (vertex data),
	 *		  GL_ELEMENT_ARRAY_BUFFER_ARB (vertex indices), GL_PIXEL_PACK_BUFFER_ARB
	 *		  (pixel-buffer in mode for pixel storage) and GL_PIXEL_UNPACK_BUFFER_ARB
	 *		  (pixel-buffer in mode for for reading pixels)
	 */
	CGLPixelBufferObject(GLenum n_target = GL_PIXEL_PACK_BUFFER_ARB);

	/*
	 *	static bool CGLPixelBufferObject::b_Supported()
	 *		- returns true when GL_ARB_VERTEX_BUFFER_OBJECT and GL_ARB_PIXEL_BUFFER_OBJECT
	 *		  extensions are supported and all entry points were found
	 */
	static bool b_Supported();
};

#endif // !__VERTEX_BUFFER_OBJECT_INCLUDED
