// 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 #endif #include #include #include using OpenSubdiv::Far::StencilTable; using OpenSubdiv::Osd::GLMeshInterface; using OpenSubdiv::Osd::GLPatchTable; using OpenSubdiv::Osd::Mesh; using OpenSubdiv::Osd::MeshBitset; // CPU backend. #include #include using OpenSubdiv::Osd::CpuEvaluator; using OpenSubdiv::Osd::CpuGLVertexBuffer; typedef Mesh OsdCpuMesh; // OpenMP backend. #ifdef OPENSUBDIV_HAS_OPENMP # include using OpenSubdiv::Osd::OmpEvaluator; typedef Mesh OsdOmpMesh; #endif // OpenCL backend. #ifdef OPENSUBDIV_HAS_OPENCL # include "opensubdiv_device_context_opencl.h" # include # include using OpenSubdiv::Osd::CLEvaluator; using OpenSubdiv::Osd::CLGLVertexBuffer; using OpenSubdiv::Osd::CLStencilTable; /* TODO(sergey): Use CLDeviceContext similar to OSD examples? */ typedef Mesh OsdCLMesh; static CLDeviceContext g_cl_device_context; #endif // CUDA backend. #ifdef OPENSUBDIV_HAS_CUDA # include "opensubdiv_device_context_cuda.h" # include # include using OpenSubdiv::Osd::CudaEvaluator; using OpenSubdiv::Osd::CudaGLVertexBuffer; using OpenSubdiv::Osd::CudaStencilTable; typedef Mesh OsdCudaMesh; static CudaDeviceContext g_cuda_device_context; #endif // Transform feedback backend. #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK # include # include using OpenSubdiv::Osd::GLStencilTableTBO; using OpenSubdiv::Osd::GLVertexBuffer; using OpenSubdiv::Osd::GLXFBEvaluator; typedef Mesh OsdGLSLTransformFeedbackMesh; #endif // GLSL compute backend. #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE # include # include using OpenSubdiv::Osd::GLComputeEvaluator; using OpenSubdiv::Osd::GLStencilTableSSBO; using OpenSubdiv::Osd::GLVertexBuffer; typedef Mesh 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 uvs; vector 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); }