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
|