git-svn-id: svn://db.shs.com.ru/libs@663 a8b55f48-bf90-11e4-a774-851b48703e85

This commit is contained in:
2019-12-08 22:53:21 +00:00
parent da962779d8
commit 1a210defb1
19 changed files with 4598 additions and 197 deletions

View File

@@ -28,10 +28,7 @@ static int _count = 0;
Mesh::Mesh(GLenum geom_type_): geom_type(geom_type_),
buffer_geom(GL_ARRAY_BUFFER, GL_STATIC_DRAW),
buffer_ind (GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW),
buffer_obj (GL_ARRAY_BUFFER, GL_STREAM_DRAW),
buffer_sel (GL_ARRAY_BUFFER, GL_STREAM_DRAW) {
vao = 0;
buffer_ind (GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW) {
hash_ = 0;
changed = hash_changed = objects_changed = selected_changed = true;
//qDebug() << "Mesh, now" << ++_count;
@@ -60,26 +57,17 @@ Mesh * Mesh::clone() {
void Mesh::init(QOpenGLExtraFunctions * f) {
if (!isInit()) {
buffer_geom.init(f);
buffer_ind .init(f);
buffer_obj .init(f);
buffer_sel .init(f);
f->glGenVertexArrays(1, &vao);
}
buffer_geom.init(f);
buffer_ind .init(f);
vao.bindBuffers(f, buffer_geom, buffer_ind);
changed = true;
}
void Mesh::destroy(QOpenGLExtraFunctions * f) {
if (vao != 0) {
f->glDeleteVertexArrays(1, &vao);
buffer_geom.destroy(f);
buffer_ind .destroy(f);
buffer_obj .destroy(f);
buffer_sel .destroy(f);
}
vao = 0;
buffer_geom.destroy(f);
buffer_ind .destroy(f);
vao.destroy(f);
}
@@ -131,21 +119,6 @@ void Mesh::calculateTangents() {
}
void Mesh::loadBuffer(QOpenGLExtraFunctions * f, Buffer & buf, const void * data, int size) {
if (!isInit()) init(f);
if (!buf.isInit() || !data) return;
buf.bind(f);
buf.resize(f, size);
buf.load(f, data, size);
//qDebug() << "loadBuffer" << size << "bytes";
/*void * map = buf.map(f, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
qDebug() << map;
if (map)
memcpy(map, objects_.constData(), osize);
buf.unmap(f);*/
}
bool Mesh::rebuffer(QOpenGLExtraFunctions * f) {
changed = false;
if (vertices_.isEmpty()) return true;
@@ -168,12 +141,10 @@ bool Mesh::rebuffer(QOpenGLExtraFunctions * f) {
int gsize = data_.size() * sizeof(Vertex);
int tsize = triangles_.size() * sizeof(Vector3i);
int lsize = lines_.size() * sizeof(Vector2i);
f->glBindVertexArray(vao);
buffer_geom.bind(f);
buffer_geom.resize(f, gsize);
buffer_geom.load(f, data_.constData(), gsize);
prepareDrawGeom(f);
buffer_ind.bind(f);
if (geom_type == GL_TRIANGLES) {
@@ -184,86 +155,19 @@ bool Mesh::rebuffer(QOpenGLExtraFunctions * f) {
buffer_ind.load(f, lines_.constData(), lsize);
}
buffer_obj.bind(f);
prepareDrawObj(f);
buffer_sel.bind(f);
prepareDrawSel(f);
f->glBindVertexArray(0);
return !isEmpty();
}
void Mesh::prepareDrawGeom(QOpenGLExtraFunctions * f) {
//qDebug() << "prepareDrawGeom";
f->glEnableVertexAttribArray(pos_loc );
f->glEnableVertexAttribArray(normal_loc );
f->glEnableVertexAttribArray(tangent_loc );
f->glEnableVertexAttribArray(bitangent_loc);
f->glEnableVertexAttribArray(tex_loc );
int size = sizeof(Vertex);
f->glVertexAttribPointer(pos_loc , 3, GL_FLOAT, GL_FALSE, size, (const void *)pos_offset );
f->glVertexAttribPointer(normal_loc , 3, GL_FLOAT, GL_FALSE, size, (const void *)normal_offset );
f->glVertexAttribPointer(tangent_loc , 3, GL_FLOAT, GL_FALSE, size, (const void *)tangent_offset );
f->glVertexAttribPointer(bitangent_loc, 3, GL_FLOAT, GL_FALSE, size, (const void *)bitangent_offset);
f->glVertexAttribPointer(tex_loc , 2, GL_FLOAT, GL_FALSE, size, (const void *)tex_offset );
}
void Mesh::prepareDrawObj(QOpenGLExtraFunctions * f) {
//qDebug() << "prepareDrawObj";
f->glEnableVertexAttribArray(material_loc );
f->glEnableVertexAttribArray(object_id_loc);
f->glEnableVertexAttribArray(color_loc );
for (int i = 0; i < 4; ++i) {
f->glEnableVertexAttribArray(modelmatrix_loc + i);
}
GLsizei size = sizeof(Object);
f->glVertexAttribIPointer(material_loc , 1, GL_UNSIGNED_INT , size, (const void *)material_offset );
f->glVertexAttribIPointer(object_id_loc, 1, GL_UNSIGNED_INT , size, (const void *)object_id_offset);
f->glVertexAttribPointer (color_loc , 4, GL_FLOAT, GL_FALSE, size, (const void *)color_offset );
for (int i = 0; i < 4; ++i) {
f->glVertexAttribPointer(modelmatrix_loc + i, 4, GL_FLOAT, GL_FALSE, size, (const void *)(modelmatrix_offset + sizeof(QVector4D)*i));
}
f->glVertexAttribDivisor(material_loc , 1);
f->glVertexAttribDivisor(object_id_loc, 1);
f->glVertexAttribDivisor(color_loc , 1);
for (int i = 0; i < 4; ++i) {
f->glVertexAttribDivisor(modelmatrix_loc + i, 1);
}
}
void Mesh::prepareDrawSel(QOpenGLExtraFunctions * f) {
//qDebug() << "prepareDrawObj";
f->glEnableVertexAttribArray(is_selected_loc);
GLsizei size = 1;
f->glVertexAttribIPointer(is_selected_loc, 1, GL_UNSIGNED_BYTE, size, (const void *)is_selected_offset);
f->glVertexAttribDivisor(is_selected_loc, 1);
}
void Mesh::draw(QOpenGLExtraFunctions * f, int count) {
if (isEmpty()) return;
if (!isInit()) init(f);
if (changed) rebuffer(f);
//qDebug() << "draw" << geom_type << vert_count << count;
f->glBindVertexArray(vao);
if (geom_type == GL_TRIANGLES)
f->glDrawElementsInstanced(geom_type, triangles_.size() * 3, GL_UNSIGNED_INT, 0, count);
vao.draw(f, geom_type, triangles_.size() * 3, count);
else
f->glDrawElementsInstanced(geom_type, lines_.size() * 2, GL_UNSIGNED_INT, 0, count);
f->glBindVertexArray(0);
vao.draw(f, geom_type, lines_.size() * 2, count);
}
@@ -281,18 +185,18 @@ void Mesh::clear() {
void Mesh::loadObject(QOpenGLExtraFunctions * f, const Object & object) {
loadBuffer(f, buffer_obj, &object, sizeof(Object));
vao.loadObject(f, object);
}
void Mesh::loadObjects(QOpenGLExtraFunctions * f, const QVector<Object> & objects) {
loadBuffer(f, buffer_obj, objects.constData(), objects.size() * sizeof(Object));
vao.loadObjects(f, objects);
}
void Mesh::loadSelections(QOpenGLExtraFunctions * f, const QVector<uchar> & sels) {
//qDebug() << "loadSelections" << sels;
loadBuffer(f, buffer_sel, sels.constData(), sels.size());
vao.loadSelections(f, sels);
}

View File

@@ -20,8 +20,7 @@
#define GLMESH_H
#include <chunkstream.h>
#include "glbuffer.h"
#include "glshaders_types.h"
#include "glvertexobject.h"
class Mesh
@@ -51,7 +50,7 @@ public:
int verticesCount() const {return vertices_.size();}
int trianglesCount() const {return triangles_.size();}
int linesCount() const {return lines_.size();}
bool isInit() const {return vao != 0;}
bool isInit() const {return vao.isInit();}
bool isEmpty() const {return vertices_.isEmpty();}
uint hash() const;
@@ -76,14 +75,9 @@ public:
Box3D boundingBox() const;
static void prepareDrawGeom(QOpenGLExtraFunctions * f);
static void prepareDrawObj (QOpenGLExtraFunctions * f);
static void prepareDrawSel (QOpenGLExtraFunctions * f);
private:
void calculateNormals();
void calculateTangents();
void loadBuffer(QOpenGLExtraFunctions * f, Buffer & buf, const void * data, int size);
QVector<QVector3D> vertices_, normals_, tangents_, bitangents_;
QVector<QVector2D> texcoords_;
@@ -91,8 +85,9 @@ private:
QVector< Vector2i> lines_;
QVector<QGLEngineShaders::Vertex> data_;
GLenum vao, geom_type;
Buffer buffer_geom, buffer_ind, buffer_obj, buffer_sel;
GLenum geom_type;
Buffer buffer_geom, buffer_ind;
VertexObject vao;
mutable uint hash_;
mutable bool hash_changed;
int vert_count;

View File

@@ -117,70 +117,30 @@ bool QGLEngineShaders::loadShadersMulti(QOpenGLShaderProgram *& prog, const QStr
}
void QGLEngineShaders::setUniformMatrices(QOpenGLShaderProgram * prog, QMatrix4x4 proj, QMatrix4x4 view, QMatrix4x4 prevproj, QMatrix4x4 prevview) {
if (!prog) return;
if (!prog->isLinked()) return;
QMatrix4x4 mvpm = proj * view;
QMatrix4x4 pmvpm = prevproj * prevview;
QMatrix3x3 nm = view.normalMatrix();
//nm.in;
prog->setUniformValue("qgl_ModelViewMatrix", view);
prog->setUniformValue("qgl_ProjectionMatrix", proj);
prog->setUniformValue("prev_ModelViewProjectioMatrix", pmvpm);
prog->setUniformValue("prev_ModelViewMatrix", prevview);
prog->setUniformValue("qgl_ModelViewProjectionMatrix", mvpm);
prog->setUniformValue("qgl_NormalMatrix", nm);
//prog->setUniformValue("qgl_BumpMatrix", nm.);
prog->setUniformValue("qgl_ModelViewMatrixTranspose", view.transposed());
prog->setUniformValue("qgl_ProjectionMatrixTranspose", proj.transposed());
prog->setUniformValue("qgl_ModelViewProjectionMatrixTranspose", mvpm.transposed());
}
void QGLEngineShaders::setUniformLights(QOpenGLShaderProgram * prog, const QVector<Light*> & lights, const QMatrix4x4 & mat, int shadow_start) {
for (int i = 0; i < lights.size(); ++i)
;//setUniformLight(prog, lights[i], QString("qgl_Light[%1]").arg(i), mat, shadow_start + i);
}
/*
" vec3 position;\n"
" vec3 direction;\n"
" vec4 color;\n"
" float intensity;\n"
" float startAngle;\n"
" float endAngle;\n"
" float constantAttenuation;\n"
" float linearAttenuation;\n"
" float quadraticAttenuation;\n"
" sampler2DShadow shadow;\n"
" mat4 shadowMatrix;\n"
*/
void QGLEngineShaders::setUniformLight(QOpenGLShaderProgram * prog, Light * light, QString ulightn, const QMatrix4x4 & mat, int shadow) {
if (!prog) return;
if (!prog->isLinked()) return;
QMatrix4x4 m = mat * light->worldTransform();
QVector4D pos(0, 0, 0, 1.), dir(light->direction(), 1);//, dir0(light->dir0), dir1(light->dir1);
pos = m * pos;
dir = ((m * dir) - pos).normalized();
float ang_start = light->angle_start / 2.f, ang_end = light->angle_end / 2.f;
if (light->light_type == Light::Omni)
ang_start = ang_end = 180.;
//qDebug() << "light" << light->name() << ulightn << pos;
prog->setUniformValue((ulightn + ".position").toLatin1().constData(), pos);
prog->setUniformValue((ulightn + ".direction").toLatin1().constData(), dir);
prog->setUniformValue((ulightn + ".intensity").toLatin1().constData(), GLfloat(light->intensity));
prog->setUniformValue((ulightn + ".startAngle").toLatin1().constData(), GLfloat(ang_start));
prog->setUniformValue((ulightn + ".startAngleCos").toLatin1().constData(), GLfloat(cosf(ang_start * deg2rad)));
prog->setUniformValue((ulightn + ".endAngle").toLatin1().constData(), GLfloat(ang_end));
prog->setUniformValue((ulightn + ".endAngleCos").toLatin1().constData(), GLfloat(cosf(ang_end * deg2rad)));
//prog->setUniformValue((ulightn + ".color").toLatin1().constData(), light->color());
prog->setUniformValue((ulightn + ".constantAttenuation").toLatin1().constData(), GLfloat(light->decay_const));
prog->setUniformValue((ulightn + ".linearAttenuation").toLatin1().constData(), GLfloat(light->decay_linear));
prog->setUniformValue((ulightn + ".quadraticAttenuation").toLatin1().constData(), GLfloat(light->decay_quadratic));
prog->setUniformValue((ulightn + ".shadow").toLatin1().constData(), shadow);
prog->setUniformValue((ulightn + ".shadowColor").toLatin1().constData(), shadow);
prog->setUniformValue((ulightn + ".shadowMatrix").toLatin1().constData(), light->shadow_matrix);
//qDebug() << light->shadow_matrix;
//prog->setUniformValue((ulightn + ".shadowDir0").toLatin1().constData(), (mat * dir0));
//prog->setUniformValue((ulightn + ".shadowDir1").toLatin1().constData(), (mat * dir1));
//qDebug() << light->direction << light->dir0 << light->dir1;
bool QGLEngineShaders::loadShaders(QOpenGLShaderProgram *& prog, const QStringList & files, bool add_qgl, const QStringList & defines) {
if (!prog)
prog = new QOpenGLShaderProgram();
prog->removeAllShaders();
QString cur_shader, defs = prepareDefines(defines);
foreach (QString f, files) {
QFileInfo fi(f);
QOpenGLShader::ShaderType type = 0;
if (fi.suffix().toLower() == "vert") type = QOpenGLShader::Vertex ;
if (fi.suffix().toLower() == "frag") type = QOpenGLShader::Fragment;
if (fi.suffix().toLower() == "geom") type = QOpenGLShader::Geometry;
if (type == 0) continue;
QFile file(f);
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "[QGLView] Shader" << f << "Error: can`t open file!";
return false;
}
cur_shader = file.readAll();
if (!addShader(prog, type, cur_shader, f, add_qgl, defs)) return false;
}
if (!prog->link()) {
qDebug() << "[QGLView] Shader" << files << "Link error:\n" << prog->log();
return false;
}
qDebug() << "[QGLView] Shader" << files << "ok";
return true;
}

View File

@@ -24,10 +24,7 @@
namespace QGLEngineShaders {
bool loadShadersMulti(QOpenGLShaderProgram *& prog, const QString & file, bool add_qgl = true, const QStringList & defines = QStringList());
void setUniformMatrices(QOpenGLShaderProgram * prog, QMatrix4x4 proj, QMatrix4x4 view, QMatrix4x4 prevproj = QMatrix4x4(), QMatrix4x4 prevview = QMatrix4x4());
void setUniformLights(QOpenGLShaderProgram * prog, const QVector<Light*> & lights, const QMatrix4x4 & mat, int shadow_start);
void setUniformLight(QOpenGLShaderProgram * prog, Light * light, QString ulightn, const QMatrix4x4 & mat = QMatrix4x4(), int shadow = 0);
bool loadShaders(QOpenGLShaderProgram *& prog, const QStringList & files, bool add_qgl = true, const QStringList & defines = QStringList());
}

View File

@@ -39,3 +39,60 @@ QGLEngineShaders::QGLMaterial::QGLMaterial() {
map[mtNormal].map_index = emrBlue;
map[mtRoughness].amount = 0.75;
}
void QGLEngineShaders::prepareDrawGeom(QOpenGLExtraFunctions * f) {
//qDebug() << "prepareDrawGeom";
f->glEnableVertexAttribArray(pos_loc );
f->glEnableVertexAttribArray(normal_loc );
f->glEnableVertexAttribArray(tangent_loc );
f->glEnableVertexAttribArray(bitangent_loc);
f->glEnableVertexAttribArray(tex_loc );
int size = sizeof(Vertex);
f->glVertexAttribPointer(pos_loc , 3, GL_FLOAT, GL_FALSE, size, (const void *)pos_offset );
f->glVertexAttribPointer(normal_loc , 3, GL_FLOAT, GL_FALSE, size, (const void *)normal_offset );
f->glVertexAttribPointer(tangent_loc , 3, GL_FLOAT, GL_FALSE, size, (const void *)tangent_offset );
f->glVertexAttribPointer(bitangent_loc, 3, GL_FLOAT, GL_FALSE, size, (const void *)bitangent_offset);
f->glVertexAttribPointer(tex_loc , 2, GL_FLOAT, GL_FALSE, size, (const void *)tex_offset );
}
void QGLEngineShaders::prepareDrawObj(QOpenGLExtraFunctions * f) {
//qDebug() << "prepareDrawObj";
f->glEnableVertexAttribArray(material_loc );
f->glEnableVertexAttribArray(object_id_loc);
f->glEnableVertexAttribArray(color_loc );
for (int i = 0; i < 4; ++i) {
f->glEnableVertexAttribArray(modelmatrix_loc + i);
}
GLsizei size = sizeof(Object);
f->glVertexAttribIPointer(material_loc , 1, GL_UNSIGNED_INT , size, (const void *)material_offset );
f->glVertexAttribIPointer(object_id_loc, 1, GL_UNSIGNED_INT , size, (const void *)object_id_offset);
f->glVertexAttribPointer (color_loc , 4, GL_FLOAT, GL_FALSE, size, (const void *)color_offset );
for (int i = 0; i < 4; ++i) {
f->glVertexAttribPointer(modelmatrix_loc + i, 4, GL_FLOAT, GL_FALSE, size, (const void *)(modelmatrix_offset + sizeof(QVector4D)*i));
}
f->glVertexAttribDivisor(material_loc , 1);
f->glVertexAttribDivisor(object_id_loc, 1);
f->glVertexAttribDivisor(color_loc , 1);
for (int i = 0; i < 4; ++i) {
f->glVertexAttribDivisor(modelmatrix_loc + i, 1);
}
}
void QGLEngineShaders::prepareDrawSel(QOpenGLExtraFunctions * f) {
//qDebug() << "prepareDrawObj";
f->glEnableVertexAttribArray(is_selected_loc);
GLsizei size = 1;
f->glVertexAttribIPointer(is_selected_loc, 1, GL_UNSIGNED_BYTE, size, (const void *)is_selected_offset);
f->glVertexAttribDivisor(is_selected_loc, 1);
}

View File

@@ -142,6 +142,10 @@ struct QGLLightPosition {
};
#pragma pack(pop)
void prepareDrawGeom(QOpenGLExtraFunctions * f);
void prepareDrawObj (QOpenGLExtraFunctions * f);
void prepareDrawSel (QOpenGLExtraFunctions * f);
}

View File

@@ -176,6 +176,7 @@ class TextureManager;
class Texture2DArray;
class Framebuffer;
class FramebufferMipmap;
class VertexObject;
class Mesh;
class Scene;
class RendererBase;

View File

@@ -0,0 +1,114 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define GL_GLEXT_PROTOTYPES
#include <QOpenGLExtraFunctions>
#include "glvertexobject.h"
using namespace QGLEngineShaders;
VertexObject::VertexObject():
buffer_obj (GL_ARRAY_BUFFER, GL_STREAM_DRAW),
buffer_sel (GL_ARRAY_BUFFER, GL_STREAM_DRAW) {
vao_ = 0;
}
VertexObject::~VertexObject() {
}
void VertexObject::init(QOpenGLExtraFunctions * f) {
if (!isInit()) {
buffer_obj.init(f);
buffer_sel.init(f);
f->glGenVertexArrays(1, &vao_);
}
}
void VertexObject::destroy(QOpenGLExtraFunctions * f) {
if (vao_ != 0) {
buffer_obj.destroy(f);
buffer_sel.destroy(f);
f->glDeleteVertexArrays(1, &vao_);
}
vao_ = 0;
}
void VertexObject::bind(QOpenGLExtraFunctions * f) {
//qDebug() << "bind" << target_ << buffer_;
f->glBindVertexArray(vao_);
}
void VertexObject::release(QOpenGLExtraFunctions * f) {
f->glBindVertexArray(0);
}
void VertexObject::bindBuffers(QOpenGLExtraFunctions * f, Buffer & geom, Buffer & elem) {
init(f);
bind(f);
geom.bind(f);
prepareDrawGeom(f);
elem.bind(f);
buffer_obj.bind(f);
prepareDrawObj(f);
buffer_sel.bind(f);
prepareDrawSel(f);
release(f);
}
void VertexObject::loadObject(QOpenGLExtraFunctions * f, const Object & object) {
loadBuffer(f, buffer_obj, &object, sizeof(Object));
}
void VertexObject::loadObjects(QOpenGLExtraFunctions * f, const QVector<Object> & objects) {
loadBuffer(f, buffer_obj, objects.constData(), objects.size() * sizeof(Object));
}
void VertexObject::loadSelections(QOpenGLExtraFunctions * f, const QVector<uchar> & sels) {
loadBuffer(f, buffer_sel, sels.constData(), sels.size());
}
void VertexObject::draw(QOpenGLExtraFunctions * f, GLenum geom_type, int vert_cout, int obj_count) {
bind(f);
f->glDrawElementsInstanced(geom_type, vert_cout, GL_UNSIGNED_INT, 0, obj_count);
release(f);
}
void VertexObject::loadBuffer(QOpenGLExtraFunctions * f, Buffer & buf, const void * data, int size) {
buf.init(f);
if (!data) return;
buf.bind(f);
buf.resize(f, size);
buf.load(f, data, size);
}

View File

@@ -0,0 +1,58 @@
/*
QGLView
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLVERTEXOBJECT_H
#define GLVERTEXOBJECT_H
#include "glbuffer.h"
#include "glshaders_types.h"
class VertexObject
{
friend class Mesh;
public:
VertexObject();
~VertexObject();
void init (QOpenGLExtraFunctions * f);
void destroy (QOpenGLExtraFunctions * f);
void bind (QOpenGLExtraFunctions * f);
void release (QOpenGLExtraFunctions * f);
void bindBuffers (QOpenGLExtraFunctions * f, Buffer & geom, Buffer & elem);
void loadObject (QOpenGLExtraFunctions * f, const QGLEngineShaders::Object & object);
void loadObjects (QOpenGLExtraFunctions * f, const QVector<QGLEngineShaders::Object> & objects);
void loadSelections(QOpenGLExtraFunctions * f, const QVector<uchar> & sels);
void draw(QOpenGLExtraFunctions * f, GLenum geom_type, int vert_cout, int obj_count);
GLuint ID() const {return vao_;}
bool isInit() const {return vao_ != 0;}
private:
void loadBuffer(QOpenGLExtraFunctions * f, Buffer & buf, const void * data, int size);
GLuint vao_;
Buffer buffer_obj, buffer_sel;
};
#endif // GLVERTEXOBJECT_H