269 lines
11 KiB
C++
269 lines
11 KiB
C++
/**************************************************************************************/
|
||
/* */
|
||
/* Visualization Library */
|
||
/* http://visualizationlibrary.org */
|
||
/* */
|
||
/* Copyright (c) 2005-2020, Michele Bosi */
|
||
/* All rights reserved. */
|
||
/* */
|
||
/* Redistribution and use in source and binary forms, with or without modification, */
|
||
/* are permitted provided that the following conditions are met: */
|
||
/* */
|
||
/* - Redistributions of source code must retain the above copyright notice, this */
|
||
/* list of conditions and the following disclaimer. */
|
||
/* */
|
||
/* - Redistributions in binary form must reproduce the above copyright notice, this */
|
||
/* list of conditions and the following disclaimer in the documentation and/or */
|
||
/* other materials provided with the distribution. */
|
||
/* */
|
||
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
|
||
/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
|
||
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
|
||
/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
|
||
/* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
|
||
/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
|
||
/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
|
||
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
|
||
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
|
||
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
|
||
/* */
|
||
/**************************************************************************************/
|
||
|
||
#ifndef BufferObject_INCLUDE_ONCE
|
||
#define BufferObject_INCLUDE_ONCE
|
||
|
||
#include <vlCore/Vector2.hpp>
|
||
#include <vlCore/Vector3.hpp>
|
||
#include <vlCore/Vector4.hpp>
|
||
#include <vlCore/Buffer.hpp>
|
||
#include <vlGraphics/OpenGL.hpp>
|
||
#include <vlCore/vlnamespace.hpp>
|
||
#include <vlCore/Vector4.hpp>
|
||
#include <vlCore/Sphere.hpp>
|
||
#include <vlCore/AABB.hpp>
|
||
|
||
namespace vl
|
||
{
|
||
//-----------------------------------------------------------------------------
|
||
// BufferObject
|
||
//-----------------------------------------------------------------------------
|
||
/**
|
||
* The BufferObject class is a Buffer that can upload its data on the GPU memory.
|
||
* \remarks
|
||
* BufferObject is the storage used by ArrayAbstract and subclasses like ArrayFloat3, ArrayUByte4 etc.
|
||
*/
|
||
class BufferObject: public Buffer
|
||
{
|
||
VL_INSTRUMENT_CLASS(vl::BufferObject, Buffer)
|
||
|
||
public:
|
||
BufferObject()
|
||
{
|
||
VL_DEBUG_SET_OBJECT_NAME()
|
||
mHandle = 0;
|
||
mUsage = BU_STATIC_DRAW;
|
||
mByteCountBufferObject = 0;
|
||
}
|
||
|
||
BufferObject(const BufferObject& other): Buffer(other)
|
||
{
|
||
VL_DEBUG_SET_OBJECT_NAME()
|
||
mHandle = 0;
|
||
mUsage = BU_STATIC_DRAW;
|
||
mByteCountBufferObject = 0;
|
||
// copy local data
|
||
*this = other;
|
||
}
|
||
|
||
// deletes the BufferObject data and copyes only the local data
|
||
BufferObject& operator=(const BufferObject& other)
|
||
{
|
||
deleteBufferObject();
|
||
super::operator=(other);
|
||
return *this;
|
||
}
|
||
|
||
// swaps data with another BufferObject, including BufferObject handle, usage and local data.
|
||
void swap(BufferObject& other)
|
||
{
|
||
// swap local data
|
||
Buffer::swap(other);
|
||
// tmp
|
||
unsigned int tmp_handle = mHandle;
|
||
EBufferObjectUsage tmp_usage = mUsage;
|
||
GLsizeiptr tmp_bytes = mByteCountBufferObject;
|
||
// this <- other
|
||
mHandle = other.mHandle;
|
||
mUsage = tmp_usage;
|
||
mByteCountBufferObject = other.mByteCountBufferObject;
|
||
// other <- this
|
||
other.mHandle = tmp_handle;
|
||
other.mUsage = tmp_usage;
|
||
other.mByteCountBufferObject = tmp_bytes;
|
||
}
|
||
|
||
~BufferObject()
|
||
{
|
||
deleteBufferObject();
|
||
}
|
||
|
||
void setHandle(unsigned int handle) { mHandle = handle; }
|
||
|
||
unsigned int handle() const { return mHandle; }
|
||
|
||
GLsizeiptr byteCountBufferObject() const { return mByteCountBufferObject; }
|
||
|
||
void createBufferObject()
|
||
{
|
||
VL_CHECK_OGL();
|
||
VL_CHECK(Has_BufferObject)
|
||
if (Has_BufferObject && handle() == 0)
|
||
{
|
||
VL_CHECK(mByteCountBufferObject == 0)
|
||
VL_glGenBuffers( 1, &mHandle ); VL_CHECK_OGL();
|
||
mByteCountBufferObject = 0;
|
||
VL_CHECK(handle())
|
||
}
|
||
}
|
||
|
||
void deleteBufferObject()
|
||
{
|
||
// mic fixme: it would be nice to re-enable these
|
||
// VL_CHECK_OGL();
|
||
VL_CHECK(Has_BufferObject || handle() == 0)
|
||
if (Has_BufferObject && handle() != 0)
|
||
{
|
||
VL_glDeleteBuffers( 1, &mHandle ); // VL_CHECK_OGL();
|
||
mHandle = 0;
|
||
mByteCountBufferObject = 0;
|
||
}
|
||
}
|
||
|
||
void downloadBufferObject()
|
||
{
|
||
VL_CHECK(Has_BufferObject)
|
||
if ( Has_BufferObject && handle() )
|
||
{
|
||
resize( byteCountBufferObject() );
|
||
void* vbo_ptr = mapBufferObject(BA_READ_ONLY);
|
||
memcpy( ptr(), vbo_ptr, byteCountBufferObject() );
|
||
unmapBufferObject();
|
||
}
|
||
}
|
||
|
||
// Modifies the BufferObject using data from the local storage.
|
||
// @note Discarding the local storage might delete data used by other Arrays.
|
||
void setBufferData( EBufferObjectUsage usage, bool discard_local_storage=false )
|
||
{
|
||
setBufferData( (int)bytesUsed(), ptr(), usage );
|
||
mUsage = usage;
|
||
if (discard_local_storage)
|
||
clear();
|
||
}
|
||
|
||
// Modifies the BufferObject using the supplied data.
|
||
// @note Use this function to initialize or resize the BufferObject and set it's usage flag.
|
||
// If data == NULL the buffer will be allocated but no data will be written to the BufferObject.
|
||
// If data != NULL such data will be copied into the BufferObject.
|
||
void setBufferData( GLsizeiptr byte_count, const GLvoid* data, EBufferObjectUsage usage )
|
||
{
|
||
VL_CHECK_OGL();
|
||
VL_CHECK(Has_BufferObject)
|
||
if ( Has_BufferObject )
|
||
{
|
||
createBufferObject();
|
||
// we use the GL_ARRAY_BUFFER slot to send the data for no special reason
|
||
VL_glBindBuffer( GL_ARRAY_BUFFER, handle() ); VL_CHECK_OGL();
|
||
VL_glBufferData( GL_ARRAY_BUFFER, byte_count, data, usage ); VL_CHECK_OGL();
|
||
VL_glBindBuffer( GL_ARRAY_BUFFER, 0 ); VL_CHECK_OGL();
|
||
mByteCountBufferObject = byte_count;
|
||
mUsage = usage;
|
||
}
|
||
}
|
||
|
||
// Modifies an existing BufferObject using data from the local storage.
|
||
// @note You can use this function only on already initialized BufferObjects, use setBufferData() to initialize a BufferObject.
|
||
// @note Discarding the local storage might delete data used by other Arrays.
|
||
void setBufferSubData( GLintptr offset=0, GLsizeiptr byte_count=-1, bool discard_local_storage=false )
|
||
{
|
||
byte_count = byte_count < 0 ? byteCountBufferObject() : byte_count;
|
||
setBufferSubData( offset, byte_count, ptr() );
|
||
if (discard_local_storage)
|
||
clear();
|
||
}
|
||
|
||
// Modifies an existing BufferObject using the supplied data.
|
||
// @note You can use this function only on already initialized BufferObjects, use setBufferData() to initialize a BufferObject.
|
||
// @param[in] data Must be != NULL, pointer to the data being written to the BufferObject.
|
||
void setBufferSubData( GLintptr offset, GLsizeiptr byte_count, const GLvoid* data )
|
||
{
|
||
VL_CHECK_OGL();
|
||
VL_CHECK(Has_BufferObject)
|
||
VL_CHECK(data);
|
||
VL_CHECK(handle())
|
||
if (Has_BufferObject && data && handle())
|
||
{
|
||
// we use the GL_ARRAY_BUFFER slot to send the data for no special reason
|
||
VL_glBindBuffer( GL_ARRAY_BUFFER, handle() ); VL_CHECK_OGL();
|
||
VL_glBufferSubData( GL_ARRAY_BUFFER, offset, byte_count, data ); VL_CHECK_OGL();
|
||
VL_glBindBuffer( GL_ARRAY_BUFFER, 0 ); VL_CHECK_OGL();
|
||
}
|
||
}
|
||
|
||
// Maps a BufferObject so that it can be read or written by the CPU.
|
||
// @note You can map only one BufferObject at a time and you must unmap it before using the BufferObject again or mapping another one.
|
||
void* mapBufferObject(EBufferObjectAccess access)
|
||
{
|
||
VL_CHECK_OGL();
|
||
VL_CHECK(Has_BufferObject)
|
||
if ( Has_BufferObject )
|
||
{
|
||
createBufferObject();
|
||
VL_glBindBuffer( GL_ARRAY_BUFFER, handle() ); VL_CHECK_OGL();
|
||
void* ptr = VL_glMapBuffer( GL_ARRAY_BUFFER, access ); VL_CHECK_OGL();
|
||
VL_glBindBuffer( GL_ARRAY_BUFFER, 0 ); VL_CHECK_OGL();
|
||
return ptr;
|
||
}
|
||
else
|
||
return NULL;
|
||
}
|
||
|
||
// Unmaps a previously mapped BufferObject.
|
||
// @return Returs true or false based on what's specified in the OpenGL specs:
|
||
// "UnmapBuffer returns TRUE unless data values in the buffer<65>s data store have
|
||
// become corrupted during the period that the buffer was mapped. Such corruption
|
||
// can be the result of a screen resolution change or other window system-dependent
|
||
// event that causes system heaps such as those for high-performance graphics memory
|
||
// to be discarded. GL implementations must guarantee that such corruption can
|
||
// occur only during the periods that a buffer<65>s data store is mapped. If such corruption
|
||
// has occurred, UnmapBuffer returns FALSE, and the contents of the buffer<65>s
|
||
// data store become undefined."
|
||
bool unmapBufferObject()
|
||
{
|
||
VL_CHECK_OGL();
|
||
VL_CHECK(Has_BufferObject)
|
||
if ( Has_BufferObject )
|
||
{
|
||
createBufferObject();
|
||
VL_glBindBuffer( GL_ARRAY_BUFFER, handle() ); VL_CHECK_OGL();
|
||
bool ok = VL_glUnmapBuffer( GL_ARRAY_BUFFER ) == GL_TRUE; VL_CHECK_OGL();
|
||
VL_glBindBuffer( GL_ARRAY_BUFFER, 0 ); VL_CHECK_OGL();
|
||
VL_CHECK_OGL();
|
||
return ok;
|
||
}
|
||
else
|
||
return false;
|
||
}
|
||
|
||
//! BufferObject usage flag as specified by setBufferData().
|
||
EBufferObjectUsage usage() const { return mUsage; }
|
||
|
||
protected:
|
||
unsigned int mHandle;
|
||
GLsizeiptr mByteCountBufferObject;
|
||
EBufferObjectUsage mUsage;
|
||
};
|
||
}
|
||
|
||
#endif
|