blender/intern/opensubdiv/internal/opensubdiv_gl_mesh.cc
2020-03-19 09:33:58 +01:00

261 lines
9.1 KiB
C++

// Copyright 2013 Blender Foundation. All rights reserved.
//
// 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 2
// 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, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "opensubdiv_gl_mesh_capi.h"
#ifdef _MSC_VER
# include <iso646.h>
#endif
#include <opensubdiv/far/stencilTable.h>
#include <opensubdiv/osd/glMesh.h>
#include <opensubdiv/osd/glPatchTable.h>
using OpenSubdiv::Far::StencilTable;
using OpenSubdiv::Osd::GLMeshInterface;
using OpenSubdiv::Osd::GLPatchTable;
using OpenSubdiv::Osd::Mesh;
using OpenSubdiv::Osd::MeshBitset;
// CPU backend.
#include <opensubdiv/osd/cpuEvaluator.h>
#include <opensubdiv/osd/cpuGLVertexBuffer.h>
using OpenSubdiv::Osd::CpuEvaluator;
using OpenSubdiv::Osd::CpuGLVertexBuffer;
typedef Mesh<CpuGLVertexBuffer, StencilTable, CpuEvaluator, GLPatchTable> OsdCpuMesh;
// OpenMP backend.
#ifdef OPENSUBDIV_HAS_OPENMP
# include <opensubdiv/osd/ompEvaluator.h>
using OpenSubdiv::Osd::OmpEvaluator;
typedef Mesh<CpuGLVertexBuffer, StencilTable, OmpEvaluator, GLPatchTable> OsdOmpMesh;
#endif
// OpenCL backend.
#ifdef OPENSUBDIV_HAS_OPENCL
# include "opensubdiv_device_context_opencl.h"
# include <opensubdiv/osd/clEvaluator.h>
# include <opensubdiv/osd/clGLVertexBuffer.h>
using OpenSubdiv::Osd::CLEvaluator;
using OpenSubdiv::Osd::CLGLVertexBuffer;
using OpenSubdiv::Osd::CLStencilTable;
/* TODO(sergey): Use CLDeviceContext similar to OSD examples? */
typedef Mesh<CLGLVertexBuffer, CLStencilTable, CLEvaluator, GLPatchTable, CLDeviceContext>
OsdCLMesh;
static CLDeviceContext g_cl_device_context;
#endif
// CUDA backend.
#ifdef OPENSUBDIV_HAS_CUDA
# include "opensubdiv_device_context_cuda.h"
# include <opensubdiv/osd/cudaEvaluator.h>
# include <opensubdiv/osd/cudaGLVertexBuffer.h>
using OpenSubdiv::Osd::CudaEvaluator;
using OpenSubdiv::Osd::CudaGLVertexBuffer;
using OpenSubdiv::Osd::CudaStencilTable;
typedef Mesh<CudaGLVertexBuffer, CudaStencilTable, CudaEvaluator, GLPatchTable> OsdCudaMesh;
static CudaDeviceContext g_cuda_device_context;
#endif
// Transform feedback backend.
#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
# include <opensubdiv/osd/glVertexBuffer.h>
# include <opensubdiv/osd/glXFBEvaluator.h>
using OpenSubdiv::Osd::GLStencilTableTBO;
using OpenSubdiv::Osd::GLVertexBuffer;
using OpenSubdiv::Osd::GLXFBEvaluator;
typedef Mesh<GLVertexBuffer, GLStencilTableTBO, GLXFBEvaluator, GLPatchTable>
OsdGLSLTransformFeedbackMesh;
#endif
// GLSL compute backend.
#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
# include <opensubdiv/osd/glComputeEvaluator.h>
# include <opensubdiv/osd/glVertexBuffer.h>
using OpenSubdiv::Osd::GLComputeEvaluator;
using OpenSubdiv::Osd::GLStencilTableSSBO;
using OpenSubdiv::Osd::GLVertexBuffer;
typedef Mesh<GLVertexBuffer, GLStencilTableSSBO, GLComputeEvaluator, GLPatchTable>
OsdGLSLComputeMesh;
#endif
#include "MEM_guardedalloc.h"
#include "internal/opensubdiv_gl_mesh_draw.h"
#include "internal/opensubdiv_gl_mesh_fvar.h"
#include "internal/opensubdiv_gl_mesh_internal.h"
#include "internal/opensubdiv_topology_refiner_internal.h"
#include "internal/opensubdiv_util.h"
#include "opensubdiv_topology_refiner_capi.h"
using opensubdiv_capi::vector;
namespace {
GLMeshInterface *createGLMeshInterface(OpenSubdiv::Far::TopologyRefiner *topology_refiner,
const MeshBitset &bits,
const int num_vertex_elements,
const int num_varying_elements,
const int level,
eOpenSubdivEvaluator evaluator_type)
{
GLMeshInterface *mesh = NULL;
switch (evaluator_type) {
#define CHECK_EVALUATOR_TYPE(type, class) \
case OPENSUBDIV_EVALUATOR_##type: \
mesh = new class(topology_refiner, num_vertex_elements, num_varying_elements, level, bits); \
break;
#define CHECK_EVALUATOR_TYPE_STUB(type) \
case OPENSUBDIV_EVALUATOR_##type: \
mesh = NULL; \
break;
CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh)
#ifdef OPENSUBDIV_HAS_OPENMP
CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh)
#else
CHECK_EVALUATOR_TYPE_STUB(OPENMP)
#endif
#ifdef OPENSUBDIV_HAS_OPENCL
CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh)
#else
CHECK_EVALUATOR_TYPE_STUB(OPENCL)
#endif
#ifdef OPENSUBDIV_HAS_CUDA
CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh)
#else
CHECK_EVALUATOR_TYPE_STUB(CUDA)
#endif
#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK, OsdGLSLTransformFeedbackMesh)
#else
CHECK_EVALUATOR_TYPE_STUB(GLSL_TRANSFORM_FEEDBACK)
#endif
#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh)
#else
CHECK_EVALUATOR_TYPE_STUB(GLSL_COMPUTE)
#endif
#undef CHECK_EVALUATOR_TYPE
#undef CHECK_EVALUATOR_TYPE_STUB
}
return mesh;
}
////////////////////////////////////////////////////////////////////////////////
// GLMesh structure "methods".
opensubdiv_capi::GLMeshFVarData *createFVarData(OpenSubdiv::Far::TopologyRefiner *topology_refiner,
GLMeshInterface *mesh,
const float *fvar_src_buffer)
{
using opensubdiv_capi::GLMeshFVarData;
GLMeshFVarData *fvar_data = new GLMeshFVarData();
fvar_data->create(topology_refiner, mesh->GetFarPatchTable(), 2, fvar_src_buffer);
return fvar_data;
}
unsigned int getPatchIndexBuffer(OpenSubdiv_GLMesh *gl_mesh)
{
return gl_mesh->internal->mesh_interface->GetPatchTable()->GetPatchIndexBuffer();
}
void bindVertexBuffer(OpenSubdiv_GLMesh *gl_mesh)
{
gl_mesh->internal->mesh_interface->BindVertexBuffer();
}
void setCoarsePositions(OpenSubdiv_GLMesh *gl_mesh,
const float *positions,
const int start_vertex,
const int num_vertices)
{
gl_mesh->internal->mesh_interface->UpdateVertexBuffer(positions, start_vertex, num_vertices);
}
void refine(OpenSubdiv_GLMesh *gl_mesh)
{
gl_mesh->internal->mesh_interface->Refine();
}
void synchronize(struct OpenSubdiv_GLMesh *gl_mesh)
{
gl_mesh->internal->mesh_interface->Synchronize();
}
void assignFunctionPointers(OpenSubdiv_GLMesh *gl_mesh)
{
gl_mesh->getPatchIndexBuffer = getPatchIndexBuffer;
gl_mesh->bindVertexBuffer = bindVertexBuffer;
gl_mesh->setCoarsePositions = setCoarsePositions;
gl_mesh->refine = refine;
gl_mesh->synchronize = synchronize;
gl_mesh->prepareDraw = opensubdiv_capi::GLMeshDisplayPrepare;
gl_mesh->drawPatches = opensubdiv_capi::GLMeshDisplayDrawPatches;
}
} // namespace
struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
OpenSubdiv_TopologyRefiner *topology_refiner, eOpenSubdivEvaluator evaluator_type)
{
using OpenSubdiv::Far::TopologyRefiner;
TopologyRefiner *osd_topology_refiner = topology_refiner->internal->osd_topology_refiner;
// TODO(sergey): Query this from refiner.
const bool is_adaptive = false;
MeshBitset bits;
bits.set(OpenSubdiv::Osd::MeshAdaptive, is_adaptive);
bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, 0);
bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, 1);
bits.set(OpenSubdiv::Osd::MeshFVarData, 1);
bits.set(OpenSubdiv::Osd::MeshEndCapBSplineBasis, 1);
const int num_vertex_elements = 3;
const int num_varying_elements = 3;
GLMeshInterface *mesh = createGLMeshInterface(osd_topology_refiner,
bits,
num_vertex_elements,
num_varying_elements,
osd_topology_refiner->GetMaxLevel(),
evaluator_type);
if (mesh == NULL) {
return NULL;
}
OpenSubdiv_GLMesh *gl_mesh = OBJECT_GUARDED_NEW(OpenSubdiv_GLMesh);
assignFunctionPointers(gl_mesh);
gl_mesh->internal = new OpenSubdiv_GLMeshInternal();
gl_mesh->internal->evaluator_type = evaluator_type;
gl_mesh->internal->mesh_interface = mesh;
// Face-varying support.
// TODO(sergey): This part needs to be re-done.
if (osd_topology_refiner->GetNumFVarChannels() > 0) {
// TODO(sergey): This is a temporary stub to get things compiled. Need
// to store base level UVs somewhere else.
vector<float> uvs;
vector<float> fvar_data_buffer;
opensubdiv_capi::interpolateFVarData(*osd_topology_refiner, uvs, &fvar_data_buffer);
gl_mesh->internal->fvar_data = createFVarData(
osd_topology_refiner, mesh, &fvar_data_buffer[0]);
}
else {
gl_mesh->internal->fvar_data = NULL;
}
return gl_mesh;
}
void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh)
{
delete gl_mesh->internal;
OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh);
}