OpenSubdiv/examples/glShareTopology/sceneBase.cpp
Takahito Tejima c3aa00e706 remove SupportsAdaptiveTessellation from OsdDrawContext, and example cleanups
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.
2015-05-19 10:30:16 -07:00

355 lines
12 KiB
C++

//
// Copyright 2015 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 <limits>
#include <common/vtr_utils.h>
#include <far/patchTablesFactory.h>
#include <far/stencilTablesFactory.h>
#include "sceneBase.h"
using namespace OpenSubdiv;
SceneBase::SceneBase(Options const &options)
: _options(options),
_indexBuffer(0), _patchParamTexture(0) {
}
SceneBase::~SceneBase() {
if (_indexBuffer) glDeleteBuffers(1, &_indexBuffer);
if (_patchParamTexture) glDeleteTextures(1, &_patchParamTexture);
for (int i = 0; i < (int)_patchTables.size(); ++i) {
delete _patchTables[i];
}
}
void
SceneBase::AddTopology(Shape const *shape, int level, bool varying) {
Far::PatchTables const * patchTable = NULL;
int numVerts = createStencilTable(shape, level, varying, &patchTable);
// centering rest position
float pmin[3] = { std::numeric_limits<float>::max(),
std::numeric_limits<float>::max(),
std::numeric_limits<float>::max() };
float pmax[3] = { -std::numeric_limits<float>::max(),
-std::numeric_limits<float>::max(),
-std::numeric_limits<float>::max() };
int nverts = shape->GetNumVertices();
for (int i = 0; i < nverts; ++i) {
for (int j = 0; j < 3; ++j) {
float v = shape->verts[i*3+j];
pmin[j] = std::min(v, pmin[j]);
pmax[j] = std::max(v, pmax[j]);
}
}
float center[3] = { (pmax[0]+pmin[0])*0.5f,
(pmax[1]+pmin[1])*0.5f,
pmin[2] };
float radius = sqrt((pmax[0]-pmin[0])*(pmax[0]-pmin[0]) +
(pmax[1]-pmin[1])*(pmax[1]-pmin[1]) +
(pmax[2]-pmin[2])*(pmax[2]-pmin[2]));
std::vector<float> restPosition(shape->verts);
for (size_t i=0; i < restPosition.size()/3; ++i) {
for (int j = 0; j < 3; ++j) {
restPosition[i*3+j] = (shape->verts[i*3+j] - center[j])/radius;
}
}
// store topology
Topology topology;
topology.numVerts = numVerts;
topology.restPosition = restPosition;
_topologies.push_back(topology);
// store patch.
// PatchTables is used later to be spliced into the index buffer.
_patchTables.push_back(patchTable);
}
int
SceneBase::createStencilTable(Shape const *shape, int level, bool varying,
OpenSubdiv::Far::PatchTables const **patchTablesOut) {
Far::TopologyRefiner * refiner = 0;
{
Sdc::SchemeType type = GetSdcType(*shape);
Sdc::Options options = GetSdcOptions(*shape);
refiner = Far::TopologyRefinerFactory<Shape>::Create(
*shape, Far::TopologyRefinerFactory<Shape>::Options(type, options));
assert(refiner);
}
// Adaptive refinement currently supported only for catmull-clark scheme
if (_options.adaptive) {
Far::TopologyRefiner::AdaptiveOptions options(level);
refiner->RefineAdaptive(options);
} else {
Far::TopologyRefiner::UniformOptions options(level);
options.fullTopologyInLastLevel = true;
refiner->RefineUniform(options);
}
Far::StencilTables const * vertexStencils=0, * varyingStencils=0;
{
Far::StencilTablesFactory::Options options;
options.generateOffsets = true;
options.generateIntermediateLevels = _options.adaptive;
vertexStencils = Far::StencilTablesFactory::Create(*refiner, options);
if (varying) {
varyingStencils = Far::StencilTablesFactory::Create(*refiner, options);
}
assert(vertexStencils);
}
Far::PatchTables const * patchTables = NULL;
{
Far::PatchTablesFactory::Options poptions(level);
if (_options.endCap == kEndCapBSplineBasis) {
poptions.SetEndCapType(
Far::PatchTablesFactory::Options::ENDCAP_BSPLINE_BASIS);
} else {
poptions.SetEndCapType(
Far::PatchTablesFactory::Options::ENDCAP_GREGORY_BASIS);
}
patchTables = Far::PatchTablesFactory::Create(*refiner, poptions);
}
*patchTablesOut = patchTables;
// append gregory vertices into stencils
{
if (Far::StencilTables const *vertexStencilsWithEndCap =
Far::StencilTablesFactory::AppendEndCapStencilTables(
*refiner,
vertexStencils,
patchTables->GetEndCapVertexStencilTables())) {
delete vertexStencils;
vertexStencils = vertexStencilsWithEndCap;
}
if (varyingStencils) {
if (Far::StencilTables const *varyingStencilsWithEndCap =
Far::StencilTablesFactory::AppendEndCapStencilTables(
*refiner,
varyingStencils,
patchTables->GetEndCapVaryingStencilTables())) {
delete varyingStencils;
varyingStencils = varyingStencilsWithEndCap;
}
}
}
int numControlVertices = refiner->GetNumVertices(0);
_stencilTableSize = createMeshRefiner(vertexStencils, varyingStencils,
numControlVertices);
// note: refiner takes ownerships of vertexStencils/ varyingStencils, patchTables
delete refiner;
return numControlVertices + vertexStencils->GetNumStencils();
}
int
SceneBase::AddObjects(int numObjects) {
_objects.clear();
int numTopologies = (int)_topologies.size();
int vertsOffset = 0;
for (int i = 0; i < numObjects; ++i) {
Object obj;
obj.topologyIndex = i % numTopologies;
obj.vertsOffset = vertsOffset;
_objects.push_back(obj);
vertsOffset += _topologies[obj.topologyIndex].numVerts;
}
// invalidate batch
for (int i = 0; i < (int)_batches.size(); ++i) {
glDeleteBuffers(1, &_batches[i].dispatchBuffer);
}
_batches.clear();
return vertsOffset;
}
size_t
SceneBase::CreateIndexBuffer() {
if (_indexBuffer == 0) {
glGenBuffers(1, &_indexBuffer);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
std::vector<int> buffer;
std::vector<unsigned int> ppBuffer;
int numTopologies = (int)_topologies.size();
for (int i = 0; i < numTopologies; ++i) {
Far::PatchTables const *patchTables = _patchTables[i];
int nPatchArrays = patchTables->GetNumPatchArrays();
_topologies[i].patchArrays.clear();
// for each patchArray
for (int j = 0; j < nPatchArrays; ++j) {
SceneBase::PatchArray patchArray;
patchArray.desc = patchTables->GetPatchArrayDescriptor(j);
patchArray.numPatches = patchTables->GetNumPatches(j);
patchArray.indexOffset = (int)buffer.size();
patchArray.primitiveIDOffset = (int)ppBuffer.size()/3;
_topologies[i].patchArrays.push_back(patchArray);
// indices
Far::ConstIndexArray indices = patchTables->GetPatchArrayVertices(j);
for (int k = 0; k < indices.size(); ++k) {
buffer.push_back(indices[k]);
}
// patchParams
Far::ConstPatchParamArray patchParams = patchTables->GetPatchParams(j);
// XXX: needs sharpness interface for patcharray or put sharpness into patchParam.
for (int k = 0; k < patchParams.size(); ++k) {
float sharpness = 0.0;
ppBuffer.push_back(patchParams[k].faceIndex);
ppBuffer.push_back(patchParams[k].bitField.field);
ppBuffer.push_back(*((unsigned int *)&sharpness));
}
}
#if 0
// XXX: we'll remove below APIs from Far::PatchTables.
// use GetPatchParams(patchArray) instead as above.
// patch param (all in one)
Far::PatchParamTable const &patchParamTables =
patchTables->GetPatchParamTable();
std::vector<int> const &sharpnessIndexTable =
patchTables->GetSharpnessIndexTable();
std::vector<float> const &sharpnessValues =
patchTables->GetSharpnessValues();
int npatches = (int)patchParamTables.size();
for (int i = 0; i < npatches; ++i) {
float sharpness = 0.0;
if (i < (int)sharpnessIndexTable.size()) {
sharpness = sharpnessIndexTable[i] >= 0 ?
sharpnessValues[sharpnessIndexTable[i]] : 0.0f;
}
ppBuffer.push_back(patchParamTables[i].faceIndex);
ppBuffer.push_back(patchParamTables[i].bitField.field);
ppBuffer.push_back(*((unsigned int *)&sharpness));
}
#endif
}
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
(int)buffer.size()*sizeof(int), &buffer[0], GL_STATIC_DRAW);
// patchParam is currently expected to be texture (it can be SSBO)
GLuint texBuffer = 0;
glGenBuffers(1, &texBuffer);
glBindBuffer(GL_ARRAY_BUFFER, texBuffer);
glBufferData(GL_ARRAY_BUFFER, ppBuffer.size()*sizeof(unsigned int),
&ppBuffer[0], GL_STATIC_DRAW);
if (_patchParamTexture == 0) {
glGenTextures(1, &_patchParamTexture);
}
glBindTexture(GL_TEXTURE_BUFFER, _patchParamTexture);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGB32I, texBuffer);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glDeleteBuffers(1, &texBuffer);
return buffer.size()*sizeof(int) + ppBuffer.size()*sizeof(int);
}
void
SceneBase::buildBatches() {
int numObjects = (int)_objects.size();
for (int i = 0; i < (int)_batches.size(); ++i) {
glDeleteBuffers(1, &_batches[i].dispatchBuffer);
}
_batches.clear();
typedef std::map<Far::PatchDescriptor, std::vector<int> > StagingBatches;
StagingBatches stagingBatches;
for (int i = 0; i < numObjects; ++i) {
// get patchArrays from topology
SceneBase::PatchArrayVector const &patchArrays =
_topologies[_objects[i].topologyIndex].patchArrays;
// for each patchArray:
for (int j = 0; j < (int)patchArrays.size(); ++j) {
SceneBase::PatchArray const &patchArray = patchArrays[j];
// find batch for the descriptor
std::vector<int> &command = stagingBatches[patchArray.desc];
int nPatch = patchArray.numPatches;
int baseVertex = GetVertsOffset(i);
command.push_back(nPatch * patchArray.desc.GetNumControlVertices());
command.push_back(1);
command.push_back(patchArray.indexOffset);
command.push_back(baseVertex);
command.push_back(0);
command.push_back(patchArray.primitiveIDOffset);
}
}
int stride = sizeof(int)*6; // not 5, since we interleave primitiveIDOffset
for (StagingBatches::iterator it = stagingBatches.begin();
it != stagingBatches.end(); ++it) {
Batch batch;
glGenBuffers(1, &batch.dispatchBuffer);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, batch.dispatchBuffer);
glBufferData(GL_DRAW_INDIRECT_BUFFER,
it->second.size()*sizeof(int),
&it->second[0], GL_STATIC_DRAW);
batch.desc = it->first;
batch.count = (int)it->second.size()/6;
batch.stride = stride;
_batches.push_back(batch);
}
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
}