Files
create/src/Gui/GLBuffer.cpp
2018-09-03 12:59:27 +02:00

187 lines
5.2 KiB
C++

/***************************************************************************
* Copyright (c) 2018 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef FC_OS_WIN32
#define GL_GLEXT_PROTOTYPES
#endif
#ifdef FC_OS_MACOSX
# include <OpenGL/gl.h>
# include <OpenGL/glu.h>
# include <OpenGL/glext.h>
#else
# include <GL/gl.h>
# include <GL/glu.h>
# include <GL/glext.h>
#endif
#include <Inventor/elements/SoGLCacheContextElement.h>
#include <Inventor/errors/SoDebugError.h>
#include <Inventor/misc/SoContextHandler.h>
#include <string>
#include "GLBuffer.h"
using namespace Gui;
OpenGLBuffer::OpenGLBuffer(GLenum type)
: target(type)
, bufferId(0)
, context(-1)
, currentContext(-1)
, glue(0)
{
SoContextHandler::addContextDestructionCallback(context_destruction_cb, this);
}
OpenGLBuffer::~OpenGLBuffer()
{
SoContextHandler::removeContextDestructionCallback(context_destruction_cb, this);
destroy();
}
/*!
* \brief OpenGLBuffer::isVBOSupported returns if the OpenGL driver
* supports the VBO extension.
* When calling this function there must be a current OpenGL context.
* \return
*/
bool OpenGLBuffer::isVBOSupported(uint32_t ctx)
{
auto glue = cc_glglue_instance(ctx);
if (!glue || !cc_glglue_has_vertex_buffer_object(glue))
return false;
const GLubyte * str = glGetString(GL_EXTENSIONS);
if (!str)
return false;
std::string ext = reinterpret_cast<const char*>(str);
return (ext.find("GL_ARB_vertex_buffer_object") != std::string::npos);
}
void OpenGLBuffer::setCurrentContext(uint32_t ctx)
{
currentContext = ctx;
glue = cc_glglue_instance(currentContext);
}
bool OpenGLBuffer::create()
{
if (bufferId > 0)
return true;
if (!cc_glglue_has_vertex_buffer_object(glue))
return false;
cc_glglue_glGenBuffers(glue, 1, &bufferId);
context = currentContext;
return true;
}
bool OpenGLBuffer::isCreated() const
{
return (bufferId > 0);
}
void OpenGLBuffer::destroy()
{
// schedule delete for all allocated GL resources
if (bufferId > 0) {
void * ptr0 = (void*) ((uintptr_t) bufferId);
SoGLCacheContextElement::scheduleDeleteCallback(context, buffer_delete, ptr0);
bufferId = 0;
}
}
void OpenGLBuffer::allocate(const void *data, int count)
{
if (bufferId > 0) {
cc_glglue_glBufferData(glue, target, count, data, GL_STATIC_DRAW);
}
}
bool OpenGLBuffer::bind()
{
if (bufferId) {
if (context != currentContext) {
SoDebugError::postWarning("OpenGLBuffer::bind",
"buffer not created");
return false;
}
cc_glglue_glBindBuffer(glue, target, bufferId);
return true;
}
return false;
}
void OpenGLBuffer::release()
{
if (bufferId) {
cc_glglue_glBindBuffer(glue, target, 0);
}
}
GLuint OpenGLBuffer::getBufferId() const
{
return bufferId;
}
uint32_t OpenGLBuffer::getBoundContext() const
{
return context;
}
int OpenGLBuffer::size() const
{
GLint value = -1;
if (bufferId > 0) {
cc_glglue_glGetBufferParameteriv(glue, target, GL_BUFFER_SIZE, &value);
}
return value;
}
void OpenGLBuffer::context_destruction_cb(uint32_t context, void * userdata)
{
OpenGLBuffer * self = static_cast<OpenGLBuffer*>(userdata);
if (self->context == context && self->bufferId) {
const cc_glglue * glue = cc_glglue_instance((int) context);
GLuint buffer = self->bufferId;
cc_glglue_glDeleteBuffers(glue, 1, &buffer);
self->context = -1;
self->bufferId = 0;
}
}
void OpenGLBuffer::buffer_delete(void * closure, uint32_t contextid)
{
const cc_glglue * glue = cc_glglue_instance((int) contextid);
GLuint id = (GLuint) ((uintptr_t) closure);
cc_glglue_glDeleteBuffers(glue, 1, &id);
}