mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-30 15:20:07 +00:00
c3aa00e706
As a preparation for retiring DrawContext, move SupportsAdaptiveTessellation method to examples/common/glUtils, which is renamed and namespaced from gl_common.{cpp,h} to be consistent to other files. Same renamings applied to other example files.
987 lines
31 KiB
C++
987 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);
|
|
|
|
GLUtils::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);
|
|
}
|
|
|
|
GLUtils::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 =
|
|
GLUtils::CompileShader(GL_VERTEX_SHADER, vsSrc.c_str()),
|
|
geometryShader = geometry ?
|
|
GLUtils::CompileShader(GL_GEOMETRY_SHADER, gsSrc.c_str()) : 0,
|
|
fragmentShader =
|
|
GLUtils::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;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|