OpenSubdiv/examples/farViewer/gl_mesh.cpp
George ElKoura a79dbcc074 Renamed vtrViewer to farViewer.
The name change is motivated by the desire to reflect that Vtr is
private API and its functionality is exposed publically through Far.
2015-05-18 19:46:22 -07:00

984 lines
31 KiB
C++

//
// Copyright 2013 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
#include "gl_mesh.h"
#include "gl_fontutils.h"
#include "../common/patchColors.h"
#include <cassert>
#include <cstdlib>
#include <cstring>
//------------------------------------------------------------------------------
// color palettes
static float g_solidColor[4] = {1.0f, 1.0f, 1.0f, 1.0f},
g_ambientColor[4] = {0.1f, 0.1f, 0.1f, 1.0f};
static float g_levelColors[10][4] = {{1.0f, 1.0f, 1.0f},
{1.0f, 1.0f, 0.0f},
{1.0f, 0.5f, 0.0f},
{0.8f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.5f},
{0.0f, 1.0f, 1.0f},
{0.0f, 0.5f, 1.0f},
{0.0f, 0.5f, 0.5f},
{0.5f, 0.0f, 1.0f},
{1.0f, 0.5f, 1.0f}};
static float g_parentTypeColors[4][4] = {{0.9f, 0.9f, 0.9f},
{0.4f, 0.8f, 0.4f},
{0.8f, 0.8f, 0.4f},
{0.8f, 0.4f, 0.4f}};
//------------------------------------------------------------------------------
void
GLMesh::setSolidColor(float * color) {
color[0] = _diffuseColor[0];
color[1] = _diffuseColor[1];
color[2] = _diffuseColor[2];
}
void
GLMesh::setColorByLevel(int level, float * color) {
color[0] = g_levelColors[level][0];
color[1] = g_levelColors[level][1];
color[2] = g_levelColors[level][2];
}
void
GLMesh::setColorBySharpness(float sharpness, float * color) {
// 0.0 2.0 4.0
// green --- yellow --- red
color[0] = std::min(1.0f, sharpness * 0.5f);
color[1] = std::min(1.0f, 2.0f - sharpness * 0.5f);
color[2] = 0;
}
//------------------------------------------------------------------------------
static GLuint g_faceTexture=0;
static GLuint
getFaceTexture() {
#include "face_texture.h"
if (not g_faceTexture) {
glGenTextures(1, &g_faceTexture);
glBindTexture(GL_TEXTURE_2D, g_faceTexture);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, FACE_TEXTURE_WIDTH,
FACE_TEXTURE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, face_texture);
}
return g_faceTexture;
}
//------------------------------------------------------------------------------
GLMesh::GLMesh() : _TBOfaceColors(0) {
for (int i=0; i<COMP_NUM_COMPONENTS; ++i) {
_VAO[i]=0;
_VBO[i]=0;
_EAO[i]=0;
_numComps[i] = 0;
}
memcpy(_ambientColor, g_ambientColor, sizeof(float)*4);
memcpy(_diffuseColor, g_solidColor, sizeof(float)*4);
}
GLMesh::~GLMesh() {
for (int i=0; i<COMP_NUM_COMPONENTS; ++i) {
if (_VAO[i]) {
glDeleteVertexArrays(1, &_VAO[i]);
}
if (_VBO[i]) {
glDeleteBuffers(1, &_VBO[i]);
}
if (_EAO[i]) {
glDeleteBuffers(1, &_EAO[i]);
}
}
}
//------------------------------------------------------------------------------
void
GLMesh::initializeVertexComponentBuffer(float const * vertData, int nverts) {
std::vector<float> & vbo = _vbo[COMP_VERT];
vbo.resize(nverts * 6);
std::vector<int> & eao = _eao[COMP_VERT];
eao.resize(nverts);
for (int vert=0; vert<nverts; ++vert) {
// copy positions
memcpy(&vbo[vert*6], &vertData[vert*3], 3*sizeof(float));
// populate EAO
eao[vert] = vert;
}
}
//------------------------------------------------------------------------------
void
GLMesh::Initialize(Options /* options */,
int nverts, int nfaces, int * vertsperface, int * faceverts,
float const * vertexData) {
{ // vertex color component ----------------------------
initializeVertexComponentBuffer(vertexData, nverts);
std::vector<float> & vbo = _vbo[COMP_VERT];
for (int vert=0, ofs=3; vert<nverts; ++vert, ofs+=6) {
setSolidColor(&vbo[ofs]);
}
}
{ // edge color component ------------------------------
int nedges = nfaces;
std::vector<float> & vbo = _vbo[COMP_EDGE];
vbo.resize(nedges * 2 * 6);
std::vector<int> & eao = _eao[COMP_EDGE];
eao.resize(nedges*2);
for (int edge=0; edge<nedges; ++edge) {
// edge mode expects faces with 2 verts (aka edges) as input
assert(vertsperface[edge]==2);
eao[edge*2 ] = edge*2;
eao[edge*2+1] = edge*2+1;
int const * verts = &faceverts[edge*2];
float * v0 = &vbo[edge*2*6],
* v1 = v0+6;
// copy position
memcpy(v0, vertexData + verts[0]*3, sizeof(float)*3);
memcpy(v1, vertexData + verts[1]*3, sizeof(float)*3);
// default to solid color
setSolidColor(v0+3);
setSolidColor(v1+3);
}
}
{ // face component ------------------------------------
std::vector<float> & vbo = _vbo[COMP_FACE];
vbo.resize(nverts * 3);
memcpy(&vbo[0], vertexData, nverts*sizeof(float)*3);
int nfaceverts = 0;
for (int i=0; i<nfaces; ++i) {
nfaceverts += vertsperface[i];
}
std::vector<int> & eao = _eao[COMP_FACE];
eao.resize(nfaceverts);
_faceColors.resize(nfaces*4);
int const * fverts = faceverts;
for (int face=0, ofs=0; face<nfaces; ++face) {
int nverts = vertsperface[face];
for (int vert=0; vert<nverts; ++vert) {
eao[ofs++] = fverts[vert];
}
setSolidColor(&_faceColors[face*4]);
fverts += nverts;
}
}
_numComps[COMP_FACE] = (int)_eao[COMP_FACE].size();
_numComps[COMP_EDGE] = (int)_eao[COMP_EDGE].size();
_numComps[COMP_VERT] = (int)_eao[COMP_VERT].size();
InitializeDeviceBuffers();
}
//------------------------------------------------------------------------------
void
GLMesh::Initialize(Options options, TopologyRefiner const & refiner,
PatchTables const * patchTables, float const * vertexData) {
if (patchTables) {
initializeBuffers(options, refiner, *patchTables, vertexData);
} else {
initializeBuffers(options, refiner, vertexData);
}
_numComps[COMP_FACE] = (int)_eao[COMP_FACE].size();
_numComps[COMP_EDGE] = (int)_eao[COMP_EDGE].size();
_numComps[COMP_VERT] = (int)_eao[COMP_VERT].size();
//InitializeDeviceBuffers();
}
//------------------------------------------------------------------------------
void
GLMesh::initializeBuffers(Options options,
TopologyRefiner const & refiner, float const * vertexData) {
typedef OpenSubdiv::Far::ConstIndexArray IndexArray;
int maxlevel = refiner.GetMaxLevel(),
nverts = refiner.GetNumVertices(maxlevel),
nedges = refiner.GetNumEdges(maxlevel),
nfaces = refiner.GetNumFaces(maxlevel),
firstvert = 0;
for (int i=0; i<maxlevel; ++i) {
firstvert += refiner.GetNumVertices(i);
}
float const * vertData = &vertexData[firstvert*3];
{ // vertex color component ----------------------------
initializeVertexComponentBuffer(vertData, nverts);
std::vector<float> & vbo = _vbo[COMP_VERT];
// set colors
if (options.vertColorMode==VERTCOLOR_BY_LEVEL) {
for (int level=0, ofs=3; level<=refiner.GetMaxLevel(); ++level) {
for (int vert=0; vert<refiner.GetNumVertices(level); ++vert, ofs+=6) {
setColorByLevel(level, &vbo[ofs]);
}
}
} else if (options.vertColorMode==VERTCOLOR_BY_SHARPNESS) {
for (int vert=0, ofs=3; vert<refiner.GetNumVertices(maxlevel); ++vert, ofs+=6) {
setColorBySharpness(refiner.GetVertexSharpness(maxlevel, vert), &vbo[ofs]);
}
} else if (options.vertColorMode==VERTCOLOR_BY_PARENT_TYPE) {
int ofs=3;
if (maxlevel>0) {
for (int vert=0; vert<refiner.GetNumFaces(maxlevel-1); ++vert, ofs+=6) {
memcpy(&vbo[ofs], g_parentTypeColors[1], sizeof(float)*3);
}
for (int vert=0; vert<refiner.GetNumEdges(maxlevel-1); ++vert, ofs+=6) {
memcpy(&vbo[ofs], g_parentTypeColors[2], sizeof(float)*3);
}
for (int vert=0; vert<refiner.GetNumVertices(maxlevel-1); ++vert, ofs+=6) {
memcpy(&vbo[ofs], g_parentTypeColors[3], sizeof(float)*3);
}
} else {
for (int vert=0; vert<refiner.GetNumVertices(maxlevel); ++vert, ofs+=6) {
memcpy(&vbo[ofs], g_parentTypeColors[0], sizeof(float)*3);
}
}
} else {
for (int vert=0, ofs=3; vert<nverts; ++vert) {
setSolidColor(&vbo[ofs+=6]);
}
}
}
{ // edge color component ------------------------------
std::vector<float> & vbo = _vbo[COMP_EDGE];
vbo.resize(nedges * 2 * 6);
std::vector<int> & eao = _eao[COMP_EDGE];
eao.resize(nedges*2);
for (int edge=0; edge<nedges; ++edge) {
eao[edge*2 ] = edge*2;
eao[edge*2+1] = edge*2+1;
IndexArray const verts = refiner.GetEdgeVertices(maxlevel, edge);
float * v0 = &vbo[edge*2*6],
* v1 = v0+6;
// copy position
memcpy(v0, vertData + verts[0]*3, sizeof(float)*3);
memcpy(v1, vertData + verts[1]*3, sizeof(float)*3);
// set colors
if (options.edgeColorMode==EDGECOLOR_BY_LEVEL) {
setColorByLevel(maxlevel, v0+3);
setColorByLevel(maxlevel, v1+3);
} else if (options.edgeColorMode==EDGECOLOR_BY_SHARPNESS) {
float sharpness = refiner.GetEdgeSharpness(maxlevel, edge);
setColorBySharpness(sharpness, v0+3);
setColorBySharpness(sharpness, v1+3);
} else {
// default to solid color
setSolidColor(v0+3);
setSolidColor(v1+3);
}
}
}
{ // face component ------------------------------------
std::vector<float> & vbo = _vbo[COMP_FACE];
vbo.resize(nverts * 3);
memcpy(&vbo[0], vertData, nverts*sizeof(float)*3);
int nfaceverts = refiner.GetNumFaceVertices(maxlevel);
std::vector<int> & eao = _eao[COMP_FACE];
eao.resize(nfaceverts);
_faceColors.resize(nfaces*4);
for (int face=0, ofs=0; face<nfaces; ++face) {
IndexArray fverts = refiner.GetFaceVertices(maxlevel, face);
for (int vert=0; vert<fverts.size(); ++vert) {
eao[ofs++] = fverts[vert];
}
setSolidColor(&_faceColors[face*4]);
}
}
}
//------------------------------------------------------------------------------
inline void
setEdge(std::vector<float> & vbo, int edge, float const * vertData, int v0, int v1, float const * color) {
float * dst0 = &vbo[edge*2*6],
* dst1 = dst0+6;
memcpy(dst0, vertData + (v0*3), sizeof(float)*3);
memcpy(dst1, vertData + (v1*3), sizeof(float)*3);
memcpy(dst0+3, color, sizeof(float)*3);
memcpy(dst1+3, color, sizeof(float)*3);
}
//------------------------------------------------------------------------------
void
GLMesh::InitializeFVar(Options options, TopologyRefiner const & refiner,
PatchTables const * patchTables, int channel, int tessFactor, float const * fvarData) {
int nverts = refiner.GetNumFVarValuesTotal(channel);
{ // vertex color component ----------------------------
initializeVertexComponentBuffer(fvarData, nverts);
std::vector<float> & vbo = _vbo[COMP_VERT];
if (options.vertColorMode==VERTCOLOR_BY_LEVEL) {
for (int level=0, ofs=3; level<=refiner.GetMaxLevel(); ++level) {
for (int vert=0; vert<refiner.GetNumFVarValues(level); ++vert, ofs+=6) {
assert(ofs<(int)vbo.size());
setColorByLevel(level, &vbo[ofs]);
}
}
} else {
for (int vert=0, ofs=3; vert<nverts; ++vert) {
setSolidColor(&vbo[ofs+=6]);
}
}
}
if (tessFactor>0) {
// edge color component ------------------------------
int npatches = patchTables->GetNumPatchesTotal(),
nvertsperpatch = (tessFactor) * (tessFactor),
nedgesperpatch = (tessFactor-1) * (tessFactor*2+tessFactor-1),
//nverts = npatches * nvertsperpatch,
nedges = npatches * nedgesperpatch;
std::vector<float> & vbo = _vbo[COMP_EDGE];
vbo.resize(nedges * 2 * 6);
std::vector<int> & eao = _eao[COMP_EDGE];
eao.reserve(nedges*2);
// default to solid color
float const * color=0;
// wireframe indices
int * basisedges = (int *)alloca(2*nedgesperpatch*sizeof(int)),
* ptr = basisedges;
for (int i=0; i<(tessFactor-1); ++i) { // tess pattern :
for (int j=0; j<(tessFactor-1); ++j) { //
*ptr++ = i*tessFactor + j; // o---o---o--
*ptr++ = i*tessFactor + j+1; // |\ |\ |
// | \ | \ |
*ptr++ = i * tessFactor + j; // | \| \|
*ptr++ = (i+1) * tessFactor + j; // o---o---o--
// |\ |\ |
*ptr++ = i * tessFactor + j; // | \ | \ |
*ptr++ = (i+1) * tessFactor + j+1; // | \| \|
} // o---o---o--
*ptr++ = (i+1) * tessFactor - 1; // | | |
*ptr++ = (i+2) * tessFactor - 1;
*ptr++ = tessFactor * (tessFactor-1) + i;
*ptr++ = tessFactor * (tessFactor-1) + i+1;
}
OpenSubdiv::Far::PatchTables::PatchHandle handle;
for (int patch=0, offset=0; patch<npatches; ++patch) {
if (options.edgeColorMode==EDGECOLOR_BY_PATCHTYPE) {
handle.patchIndex = patch;
OpenSubdiv::Far::PatchDescriptor::Type type =
patchTables->GetFVarPatchType(channel, handle);
if (OpenSubdiv::Far::PatchDescriptor::IsAdaptive(type)) {
color = getAdaptivePatchColor(
OpenSubdiv::Far::PatchDescriptor(type));
} else {
static float quadColor[3] = { 1.0f, 1.0f, 0.0f };
color = quadColor;
}
}
assert(color);
for (int edge=0; edge<nedgesperpatch; ++edge) {
eao.push_back((int)eao.size());
eao.push_back((int)eao.size());
int v0 = offset + basisedges[edge*2],
v1 = offset + basisedges[edge*2+1];
setEdge(vbo, patch*nedgesperpatch+edge, fvarData, v0, v1, color);
}
offset += nvertsperpatch;
}
}
_numComps[COMP_FACE] = (int)_eao[COMP_FACE].size();
_numComps[COMP_EDGE] = (int)_eao[COMP_EDGE].size();
_numComps[COMP_VERT] = (int)_eao[COMP_VERT].size();
InitializeDeviceBuffers();
}
//------------------------------------------------------------------------------
// returns the number of edges in a patch with 'numCVs'
inline int
getNumEdges(int numCVs) {
switch (numCVs) {
case 4: return 4;
// case 9: return 12;
case 9: return 4;
// case 12: return 17;
case 12: return 4;
// case 16: return 24;
case 16: return 4;
case 20: return 4;
default:
assert(0);
}
return -1;
}
//------------------------------------------------------------------------------
int const *
getEdgeList(int numCVs) {
static int edgeList4[] = { 0, 1, 1, 2, 2, 3, 3, 0 };
static int * edgeList9 = edgeList4,
* edgeList12 = edgeList4,
* edgeList16 = edgeList4;
/*
static int edgeList9[] = { 0, 1, 1, 4,
3, 2, 2, 5,
8, 7, 7, 6,
0, 3, 3, 8,
1, 2, 2, 7,
4, 5, 5, 6 };
static int edgeList12[] = { 4, 0, 0, 3, 3, 5,
11, 1, 1, 2, 2, 6,
10, 9, 9, 8, 8, 7,
4, 11, 11, 10, 0, 1,
1, 9, 3, 2, 2, 8,
5, 6, 6, 7 };
static int edgeList16[] = { 4, 15, 15, 14, 14, 13,
5, 0, 0, 3, 3, 12,
6, 1, 1, 2, 2, 11,
7, 8, 8, 9, 9, 10,
4, 5, 5, 6, 6, 7,
15, 0, 0, 1, 1, 8,
14, 3, 3, 2, 2, 9,
13, 12, 12, 11, 11, 10 };
*/
switch (numCVs) {
case 4: return edgeList4; break;
case 9: return edgeList9; break;
case 12: return edgeList12; break;
case 16: return edgeList16; break;
case 20: return edgeList4; break;
default:
assert(0);
}
return 0;
}
inline int
getRingSize(OpenSubdiv::Far::PatchDescriptor desc) {
if (desc.GetType()==OpenSubdiv::Far::PatchDescriptor::GREGORY_BASIS) {
return 4;
} else {
return desc.GetNumControlVertices();
}
}
//------------------------------------------------------------------------------
void
GLMesh::initializeBuffers(Options options, TopologyRefiner const & refiner,
PatchTables const & patchTables, float const * vertexData) {
int nverts = refiner.GetNumVerticesTotal();
{ // vertex color component ----------------------------
initializeVertexComponentBuffer(vertexData, nverts);
std::vector<float> & vbo = _vbo[COMP_VERT];
if (options.vertColorMode==VERTCOLOR_BY_LEVEL) {
for (int level=0, ofs=3; level<=refiner.GetMaxLevel(); ++level) {
for (int vert=0; vert<refiner.GetNumVertices(level); ++vert, ofs+=6) {
assert(ofs<(int)vbo.size());
setColorByLevel(level, &vbo[ofs]);
}
}
} else {
for (int vert=0, ofs=3; vert<nverts; ++vert) {
setSolidColor(&vbo[ofs+=6]);
}
}
}
typedef OpenSubdiv::Far::PatchDescriptor Descriptor;
{ // edge color component ------------------------------
int nedges = 0;
for (int array=0; array<(int)patchTables.GetNumPatchArrays(); ++array) {
int ncvs = getRingSize(patchTables.GetPatchArrayDescriptor(array));
nedges += patchTables.GetNumPatches(array) * getNumEdges(ncvs);
}
std::vector<float> & vbo = _vbo[COMP_EDGE];
vbo.resize(nedges * 2 * 6);
std::vector<int> & eao = _eao[COMP_EDGE];
eao.resize(nedges*2);
// default to solid color
float solidColor[3];
setSolidColor(solidColor);
float const * color=solidColor;
for (int array=0, edge=0; array<(int)patchTables.GetNumPatchArrays(); ++array) {
OpenSubdiv::Far::PatchDescriptor desc =
patchTables.GetPatchArrayDescriptor(array);
if (options.edgeColorMode==EDGECOLOR_BY_PATCHTYPE) {
color = getAdaptivePatchColor(desc);
}
int ncvs = getRingSize(desc);
for (int patch=0; patch<patchTables.GetNumPatches(array); ++patch) {
OpenSubdiv::Far::ConstIndexArray const cvs =
patchTables.GetPatchVertices(array, patch);
int const * edgeList=getEdgeList(ncvs);
for (int k=0; k<getNumEdges(cvs.size()); ++k, ++edge) {
eao[edge*2 ] = edge*2;
eao[edge*2+1] = edge*2+1;
int v0 = cvs[edgeList[k*2]],
v1 = cvs[edgeList[k*2+1]];
setEdge(vbo, edge, vertexData, v0, v1, color);
}
}
}
}
{ // face color component ------------------------------
int nfaces = patchTables.GetNumPatchesTotal();
std::vector<float> & vbo = _vbo[COMP_FACE];
vbo.resize(nverts*3);
memcpy(&vbo[0], vertexData, nverts*sizeof(float)*3);
std::vector<int> & eao = _eao[COMP_FACE];
eao.resize(nfaces*4);
_faceColors.resize(nfaces*4, 1.0f);
// default to solid color
for (int array=0, face=0; array<(int)patchTables.GetNumPatchArrays(); ++array) {
OpenSubdiv::Far::PatchDescriptor desc =
patchTables.GetPatchArrayDescriptor(array);
//int ncvs = getRingSize(desc);
for (int patch=0; patch<patchTables.GetNumPatches(array); ++patch, ++face) {
OpenSubdiv::Far::ConstIndexArray const cvs =
patchTables.GetPatchVertices(array, patch);
if (desc.GetType()==Descriptor::REGULAR) {
eao[face*4 ] = cvs[ 5];
eao[face*4+1] = cvs[ 6];
eao[face*4+2] = cvs[10];
eao[face*4+3] = cvs[ 9];
} else {
memcpy(&eao[face*4], cvs.begin(), 4*sizeof(OpenSubdiv::Far::Index));
}
if (options.faceColorMode==FACECOLOR_BY_PATCHTYPE) {
float const * color = getAdaptivePatchColor(desc);
memcpy(&_faceColors[face*4], color, 4*sizeof(float));
} else {
setSolidColor(&_faceColors[face*4]);
}
}
}
}
}
//------------------------------------------------------------------------------
template <typename T> static GLuint
createTextureBuffer(T const &data, GLint format, int offset=0) {
GLuint buffer = 0, texture = 0;
glGenTextures(1, &texture);
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER,
(data.size()-offset)*sizeof(typename T::value_type),
&data[offset], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_BUFFER, texture);
glTexBuffer(GL_TEXTURE_BUFFER, format, buffer);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glDeleteBuffers(1, &buffer);
checkGLErrors("createTextureBuffer");
return texture;
}
//------------------------------------------------------------------------------
void
GLMesh::InitializeDeviceBuffers() {
// copy buffers to device
for (int i=0; i<COMP_NUM_COMPONENTS; ++i) {
if (not _VAO[i]) {
glGenVertexArrays(1, &_VAO[i]);
}
glBindVertexArray(_VAO[i]);
if (not _vbo[i].empty()) {
if (not _VBO[i]) {
glGenBuffers(1, &_VBO[i]);
}
glBindBuffer(GL_ARRAY_BUFFER, _VBO[i]);
glBufferData(GL_ARRAY_BUFFER, _vbo[i].size()*sizeof(GLfloat), &_vbo[i][0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
int numelements = (i==COMP_FACE) ? 3 : 6;
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, numelements*sizeof(GLfloat), 0);
if (i==COMP_FACE) {
// face vbo has no color component
glDisableVertexAttribArray(1);
} else {
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), (void*)12);
}
}
if (not _eao[i].empty()) {
if (not _EAO[i]) {
glGenBuffers(1, &_EAO[i]);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _EAO[i]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _eao[i].size()*sizeof(int), &_eao[i][0], GL_STATIC_DRAW);
}
checkGLErrors("init");
}
if (not _faceColors.empty()) {
_TBOfaceColors = createTextureBuffer(_faceColors, GL_RGBA32F);
}
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
clearBuffers();
}
//------------------------------------------------------------------------------
void
GLMesh::clearBuffers() {
for (int i=0; i<COMP_NUM_COMPONENTS; ++i) {
_vbo[i].clear();
_eao[i].clear();
}
}
//------------------------------------------------------------------------------
static const char * g_simpleShaderSrc =
#include "simpleShader.gen.h"
;
static const char * g_faceShaderSrc =
#include "faceShader.gen.h"
;
GLuint g_simpleProgram=0,
g_faceProgram=0;
// Update and bind transform state
static void
bindProgram( char const * shaderSource,
GLuint * program,
GLuint transformUB,
GLuint lightingUB,
bool geometry) {
assert(program);
GLuint uboIndex=GL_INVALID_INDEX,
transformBinding=0,
lightingBinding=1;
// Update and bind transform state
if (not *program) {
*program = glCreateProgram();
static char const versionStr[] = "#version 330\n",
vtxDefineStr[] = "#define VERTEX_SHADER\n",
geoDefineStr[] = "#define GEOMETRY_SHADER\n",
fragDefineStr[] = "#define FRAGMENT_SHADER\n";
std::string vsSrc = std::string(versionStr) + vtxDefineStr + shaderSource,
gsSrc = std::string(versionStr) + geoDefineStr + shaderSource,
fsSrc = std::string(versionStr) + fragDefineStr + shaderSource;
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vsSrc.c_str()),
geometryShader = geometry ? compileShader(GL_GEOMETRY_SHADER, gsSrc.c_str()) : 0,
fragmentShader = compileShader(GL_FRAGMENT_SHADER, fsSrc.c_str());
glAttachShader(*program, vertexShader);
if (geometry) {
glAttachShader(*program, geometryShader);
}
glAttachShader(*program, fragmentShader);
glLinkProgram(*program);
GLint status;
glGetProgramiv(*program, GL_LINK_STATUS, &status);
if (status == GL_FALSE) {
GLint infoLogLength;
glGetProgramiv(*program, GL_INFO_LOG_LENGTH, &infoLogLength);
char *infoLog = new char[infoLogLength];
glGetProgramInfoLog(*program, infoLogLength, NULL, infoLog);
printf("%s\n", infoLog);
delete[] infoLog;
exit(1);
}
uboIndex = glGetUniformBlockIndex(*program, "Transform");
if (uboIndex != GL_INVALID_INDEX) {
glUniformBlockBinding(*program, uboIndex, transformBinding);
}
uboIndex = glGetUniformBlockIndex(*program, "Lighting");
if (uboIndex != GL_INVALID_INDEX) {
glUniformBlockBinding(*program, uboIndex, lightingBinding);
}
}
glUseProgram(*program);
if (transformUB) {
glBindBufferBase(GL_UNIFORM_BUFFER, transformBinding, transformUB);
}
if (lightingUB) {
glBindBufferBase(GL_UNIFORM_BUFFER, lightingBinding, lightingUB);
}
}
//------------------------------------------------------------------------------
void
GLMesh::Draw(Component comp, GLuint transformUB, GLuint lightingUB) {
if (comp==COMP_VERT) {
bindProgram(g_simpleShaderSrc, &g_simpleProgram, transformUB, lightingUB, false);
glBindVertexArray(_VAO[COMP_VERT]);
glPointSize(4.0f);
glDrawElements(GL_POINTS, _numComps[COMP_VERT], GL_UNSIGNED_INT, (void *)0);
glPointSize(1.0f);
} else if (comp==COMP_EDGE) {
bindProgram(g_simpleShaderSrc, &g_simpleProgram, transformUB, lightingUB, false);
glBindVertexArray(_VAO[COMP_EDGE]);
glDrawElements(GL_LINES, _numComps[COMP_EDGE], GL_UNSIGNED_INT, (void *)0);
} else if (comp==COMP_FACE) {
glEnable(GL_CULL_FACE);
bindProgram(g_faceShaderSrc, &g_faceProgram, transformUB, lightingUB, true);
{ // set shader parameters
GLuint diffuseColor = glGetUniformLocation(g_faceProgram, "diffuseColor");
glProgramUniform4f(g_faceProgram, diffuseColor, _diffuseColor[0],
_diffuseColor[1], _diffuseColor[2], _diffuseColor[3]);
GLuint faceColors = glGetUniformLocation(g_faceProgram, "faceColors");
glUniform1i(faceColors, 0); // GL_TEXTURE0
GLuint faceTexture = glGetUniformLocation(g_faceProgram, "faceTexture");
glUniform1i(faceTexture, 1); // GL_TEXTURE1
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, _TBOfaceColors);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, getFaceTexture());
}
glBindVertexArray(_VAO[COMP_FACE]);
glDrawElements(GL_LINES_ADJACENCY, _numComps[COMP_FACE], GL_UNSIGNED_INT, (void *)0);
glDisable(GL_CULL_FACE);
}
}
//------------------------------------------------------------------------------
void
GLMesh::SetDiffuseColor(float r, float g, float b, float a) {
_diffuseColor[0] = r;
_diffuseColor[1] = g;
_diffuseColor[2] = b;
_diffuseColor[3] = a;
}
//------------------------------------------------------------------------------
void
GLMesh::SetFaceColor(int face, float r, float g, float b, float a) {
assert( (face*4) < (int)_faceColors.size() );
float * color = &_faceColors[face*4];
color[0] = r;
color[1] = g;
color[2] = b;
color[3] = a;
}
//------------------------------------------------------------------------------