Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c')
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c970
1 files changed, 0 insertions, 970 deletions
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
deleted file mode 100644
index 3257dd2334c..00000000000
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
+++ /dev/null
@@ -1,970 +0,0 @@
-/*
- * 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.
- */
-
-/** \file
- * \ingroup bke
- */
-
-#ifdef WITH_OPENSUBDIV
-
-# include "BLI_sys_types.h" // for intptr_t support
-# include "MEM_guardedalloc.h"
-
-# include "BLI_listbase.h"
-# include "BLI_math.h"
-# include "BLI_threads.h"
-# include "BLI_utildefines.h" /* for BLI_assert */
-
-# include "CCGSubSurf.h"
-# include "CCGSubSurf_intern.h"
-
-# include "BKE_DerivedMesh.h"
-# include "BKE_subsurf.h"
-
-# include "DNA_userdef_types.h"
-
-# include "opensubdiv_capi.h"
-# include "opensubdiv_converter_capi.h"
-# include "opensubdiv_evaluator_capi.h"
-# include "opensubdiv_gl_mesh_capi.h"
-# include "opensubdiv_topology_refiner_capi.h"
-
-# include "GPU_extensions.h"
-# include "GPU_glew.h"
-
-# define OSD_LOG \
- if (false) \
- printf
-
-static bool compare_ccg_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
-{
- const int num_verts = dm->getNumVerts(dm);
- const int num_edges = dm->getNumEdges(dm);
- const int num_polys = dm->getNumPolys(dm);
- const MEdge *medge = dm->getEdgeArray(dm);
- const MLoop *mloop = dm->getLoopArray(dm);
- const MPoly *mpoly = dm->getPolyArray(dm);
-
- /* Quick preliminary tests based on the number of verts and facces. */
- {
- if (num_verts != ss->vMap->numEntries || num_edges != ss->eMap->numEntries ||
- num_polys != ss->fMap->numEntries) {
- return false;
- }
- }
-
- /* Rather slow check for faces topology change. */
- {
- CCGFaceIterator ccg_face_iter;
- for (ccgSubSurf_initFaceIterator(ss, &ccg_face_iter);
- !ccgFaceIterator_isStopped(&ccg_face_iter);
- ccgFaceIterator_next(&ccg_face_iter)) {
- /*const*/ CCGFace *ccg_face = ccgFaceIterator_getCurrent(&ccg_face_iter);
- const int poly_index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face));
- const MPoly *mp = &mpoly[poly_index];
- int corner;
- if (ccg_face->numVerts != mp->totloop) {
- return false;
- }
- for (corner = 0; corner < ccg_face->numVerts; corner++) {
- /*const*/ CCGVert *ccg_vert = FACE_getVerts(ccg_face)[corner];
- const int vert_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert));
- if (vert_index != mloop[mp->loopstart + corner].v) {
- return false;
- }
- }
- }
- }
-
- /* Check for edge topology change. */
- {
- CCGEdgeIterator ccg_edge_iter;
- for (ccgSubSurf_initEdgeIterator(ss, &ccg_edge_iter);
- !ccgEdgeIterator_isStopped(&ccg_edge_iter);
- ccgEdgeIterator_next(&ccg_edge_iter)) {
- /* const */ CCGEdge *ccg_edge = ccgEdgeIterator_getCurrent(&ccg_edge_iter);
- /* const */ CCGVert *ccg_vert1 = ccg_edge->v0;
- /* const */ CCGVert *ccg_vert2 = ccg_edge->v1;
- const int ccg_vert1_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert1));
- const int ccg_vert2_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert2));
- const int edge_index = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
- const MEdge *me = &medge[edge_index];
- if (me->v1 != ccg_vert1_index || me->v2 != ccg_vert2_index) {
- return false;
- }
- }
- }
-
- /* TODO(sergey): Crease topology changes detection. */
- {
- CCGEdgeIterator ccg_edge_iter;
- for (ccgSubSurf_initEdgeIterator(ss, &ccg_edge_iter);
- !ccgEdgeIterator_isStopped(&ccg_edge_iter);
- ccgEdgeIterator_next(&ccg_edge_iter)) {
- /* const */ CCGEdge *ccg_edge = ccgEdgeIterator_getCurrent(&ccg_edge_iter);
- const int edge_index = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
- if (ccg_edge->crease != medge[edge_index].crease) {
- return false;
- }
- }
- }
-
- return true;
-}
-
-static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
-{
- OpenSubdiv_Converter converter;
- bool result;
- if (ss->osd_mesh == NULL && ss->osd_topology_refiner == NULL) {
- return true;
- }
- /* TODO(sergey): De-duplicate with topology counter at the bottom of
- * the file.
- */
- ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
- result = openSubdiv_topologyRefinerCompareWithConverter(ss->osd_topology_refiner, &converter);
- ccgSubSurf_converter_free(&converter);
- return result;
-}
-
-static bool opensubdiv_is_topology_changed(CCGSubSurf *ss, DerivedMesh *dm)
-{
- if (ss->osd_compute != U.opensubdiv_compute_type) {
- return true;
- }
- if (ss->osd_topology_refiner != NULL) {
- const int levels = ss->osd_topology_refiner->getSubdivisionLevel(ss->osd_topology_refiner);
- BLI_assert(ss->osd_mesh_invalid == true);
- if (levels != ss->subdivLevels) {
- return true;
- }
- }
- if (ss->skip_grids == false) {
- return compare_ccg_derivedmesh_topology(ss, dm) == false;
- }
- else {
- return compare_osd_derivedmesh_topology(ss, dm) == false;
- }
- return false;
-}
-
-void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm)
-{
- if (opensubdiv_is_topology_changed(ss, dm)) {
- /* ** Make sure both GPU and CPU backends are properly reset. ** */
-
- ss->osd_coarse_coords_invalid = true;
-
- /* Reset GPU part. */
- ss->osd_mesh_invalid = true;
- if (ss->osd_topology_refiner != NULL) {
- openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner);
- ss->osd_topology_refiner = NULL;
- }
-
- /* Reset CPU side. */
- if (ss->osd_evaluator != NULL) {
- openSubdiv_deleteEvaluator(ss->osd_evaluator);
- ss->osd_evaluator = NULL;
- }
- }
-}
-
-static void ccgSubSurf__updateGLMeshCoords(CCGSubSurf *ss)
-{
- BLI_assert(ss->meshIFC.numLayers == 3);
- ss->osd_mesh->setCoarsePositions(
- ss->osd_mesh, (float *)ss->osd_coarse_coords, 0, ss->osd_num_coarse_coords);
-}
-
-bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl, int active_uv_index)
-{
- int compute_type;
-
- switch (U.opensubdiv_compute_type) {
-# define CHECK_COMPUTE_TYPE(type) \
- case USER_OPENSUBDIV_COMPUTE_##type: \
- compute_type = OPENSUBDIV_EVALUATOR_##type; \
- break;
- CHECK_COMPUTE_TYPE(CPU)
- CHECK_COMPUTE_TYPE(OPENMP)
- CHECK_COMPUTE_TYPE(OPENCL)
- CHECK_COMPUTE_TYPE(CUDA)
- CHECK_COMPUTE_TYPE(GLSL_TRANSFORM_FEEDBACK)
- CHECK_COMPUTE_TYPE(GLSL_COMPUTE)
- default:
- compute_type = OPENSUBDIV_EVALUATOR_CPU;
- break;
-# undef CHECK_COMPUTE_TYPE
- }
-
- if (ss->osd_vao == 0) {
- glGenVertexArrays(1, &ss->osd_vao);
- }
-
- if (ss->osd_mesh_invalid) {
- if (ss->osd_mesh != NULL) {
- ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
- ss->osd_mesh = NULL;
- }
- ss->osd_mesh_invalid = false;
- }
-
- if (ss->osd_mesh == NULL) {
- if (ss->osd_topology_refiner == NULL) {
- /* Happens with empty meshes. */
- /* TODO(sergey): Add assert that mesh is indeed empty. */
- return false;
- }
-
- ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner(ss->osd_topology_refiner,
- compute_type);
-
- if (UNLIKELY(ss->osd_mesh == NULL)) {
- /* Most likely compute device is not available. */
- return false;
- }
-
- ccgSubSurf__updateGLMeshCoords(ss);
- ss->osd_mesh->refine(ss->osd_mesh);
- ss->osd_mesh->synchronize(ss->osd_mesh);
- ss->osd_coarse_coords_invalid = false;
-
- glBindVertexArray(ss->osd_vao);
- ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
-
- glEnableVertexAttribArray(0);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, 0);
- glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (float *)12);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindVertexArray(0);
- }
- else if (ss->osd_coarse_coords_invalid) {
- ccgSubSurf__updateGLMeshCoords(ss);
- ss->osd_mesh->refine(ss->osd_mesh);
- ss->osd_mesh->synchronize(ss->osd_mesh);
- ss->osd_coarse_coords_invalid = false;
- }
-
- ss->osd_mesh->prepareDraw(ss->osd_mesh, use_osd_glsl, active_uv_index);
-
- return true;
-}
-
-void ccgSubSurf_drawGLMesh(CCGSubSurf *ss,
- bool fill_quads,
- int start_partition,
- int num_partitions)
-{
- if (LIKELY(ss->osd_mesh != NULL)) {
- glBindVertexArray(ss->osd_vao);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ss->osd_mesh->getPatchIndexBuffer(ss->osd_mesh));
-
- ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
- glBindVertexArray(ss->osd_vao);
- ss->osd_mesh->drawPatches(ss->osd_mesh, fill_quads, start_partition, num_partitions);
- glBindVertexArray(0);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- }
-}
-
-int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss)
-{
- if (ss->osd_topology_refiner != NULL) {
- return ss->osd_topology_refiner->getNumFaces(ss->osd_topology_refiner);
- }
- return 0;
-}
-
-/* Get number of vertices in base faces in a particular GL mesh. */
-int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face)
-{
- if (ss->osd_topology_refiner != NULL) {
- return ss->osd_topology_refiner->getNumFaceVertices(ss->osd_topology_refiner, face);
- }
- return 0;
-}
-
-void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids)
-{
- ss->skip_grids = skip_grids;
-}
-
-bool ccgSubSurf_needGrids(CCGSubSurf *ss)
-{
- return ss->skip_grids == false;
-}
-
-BLI_INLINE void ccgSubSurf__mapGridToFace(
- int S, float grid_u, float grid_v, float *face_u, float *face_v)
-{
- float u, v;
-
- /* - Each grid covers half of the face along the edges.
- * - Grid's (0, 0) starts from the middle of the face.
- */
- u = 0.5f - 0.5f * grid_u;
- v = 0.5f - 0.5f * grid_v;
-
- if (S == 0) {
- *face_u = v;
- *face_v = u;
- }
- else if (S == 1) {
- *face_u = 1.0f - u;
- *face_v = v;
- }
- else if (S == 2) {
- *face_u = 1.0f - v;
- *face_v = 1.0f - u;
- }
- else {
- *face_u = u;
- *face_v = 1.0f - v;
- }
-}
-
-BLI_INLINE void ccgSubSurf__mapEdgeToFace(
- int S, int edge_segment, bool inverse_edge, int edgeSize, float *face_u, float *face_v)
-{
- int t = inverse_edge ? edgeSize - edge_segment - 1 : edge_segment;
- if (S == 0) {
- *face_u = (float)t / (edgeSize - 1);
- *face_v = 0.0f;
- }
- else if (S == 1) {
- *face_u = 1.0f;
- *face_v = (float)t / (edgeSize - 1);
- }
- else if (S == 2) {
- *face_u = 1.0f - (float)t / (edgeSize - 1);
- *face_v = 1.0f;
- }
- else {
- *face_u = 0.0f;
- *face_v = 1.0f - (float)t / (edgeSize - 1);
- }
-}
-
-void ccgSubSurf_evaluatorSetFVarUV(CCGSubSurf *ss, DerivedMesh *dm, int layer_index)
-{
- MPoly *mpoly = dm->getPolyArray(dm);
- MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer_index);
- int num_polys = dm->getNumPolys(dm);
- int index, poly;
- BLI_assert(ss->osd_evaluator != NULL);
- for (poly = 0, index = 0; poly < num_polys; poly++) {
- int loop;
- MPoly *mp = &mpoly[poly];
- for (loop = 0; loop < mp->totloop; loop++, index++) {
- MLoopUV *mluv = &mloopuv[loop + mp->loopstart];
- (void)mluv;
- /* TODO(sergey): Send mluv->uv to the evaluator's face varying
- * buffer.
- */
- }
- }
- (void)ss;
-}
-
-void ccgSubSurf_evaluatorFVarUV(
- CCGSubSurf *ss, int face_index, int S, float grid_u, float grid_v, float uv[2])
-{
- float face_u, face_v;
- ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v);
- (void)ss;
- (void)face_index;
- /* TODO(sergey): Evaluate face varying coordinate. */
- zero_v2(uv);
-}
-
-static bool opensubdiv_createEvaluator(CCGSubSurf *ss)
-{
- OpenSubdiv_Converter converter;
- OpenSubdiv_TopologyRefiner *topology_refiner;
- if (ss->fMap->numEntries == 0) {
- /* OpenSubdiv doesn't support meshes without faces. */
- return false;
- }
- ccgSubSurf_converter_setup_from_ccg(ss, &converter);
- OpenSubdiv_TopologyRefinerSettings settings;
- settings.level = ss->subdivLevels;
- settings.is_adaptive = false;
- topology_refiner = openSubdiv_createTopologyRefinerFromConverter(&converter, &settings);
- ccgSubSurf_converter_free(&converter);
- ss->osd_evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(topology_refiner);
- if (ss->osd_evaluator == NULL) {
- BLI_assert(!"OpenSubdiv initialization failed, should not happen.");
- return false;
- }
- return true;
-}
-
-static bool opensubdiv_ensureEvaluator(CCGSubSurf *ss)
-{
- if (ss->osd_evaluator == NULL) {
- OSD_LOG("Allocating new evaluator, %d verts\n", ss->vMap->numEntries);
- opensubdiv_createEvaluator(ss);
- }
- return ss->osd_evaluator != NULL;
-}
-
-static void opensubdiv_updateEvaluatorCoarsePositions(CCGSubSurf *ss)
-{
- float(*positions)[3];
- int vertDataSize = ss->meshIFC.vertDataSize;
- int num_basis_verts = ss->vMap->numEntries;
- int i;
-
- /* TODO(sergey): Avoid allocation on every update. We could either update
- * coordinates in chunks of 1K vertices (which will only use stack memory)
- * or do some callback magic for OSD evaluator can invoke it and fill in
- * buffer directly.
- */
- if (ss->meshIFC.numLayers == 3) {
- /* If all the components are to be initialized, no need to memset the
- * new memory block.
- */
- positions = MEM_mallocN(3 * sizeof(float) * num_basis_verts, "OpenSubdiv coarse points");
- }
- else {
- /* Calloc in order to have z component initialized to 0 for Uvs */
- positions = MEM_callocN(3 * sizeof(float) * num_basis_verts, "OpenSubdiv coarse points");
- }
-# pragma omp parallel for
- for (i = 0; i < ss->vMap->curSize; i++) {
- CCGVert *v = (CCGVert *)ss->vMap->buckets[i];
- for (; v; v = v->next) {
- float *co = VERT_getCo(v, 0);
- BLI_assert(v->osd_index < ss->vMap->numEntries);
- VertDataCopy(positions[v->osd_index], co, ss);
- OSD_LOG("Point %d has value %f %f %f\n",
- v->osd_index,
- positions[v->osd_index][0],
- positions[v->osd_index][1],
- positions[v->osd_index][2]);
- }
- }
-
- ss->osd_evaluator->setCoarsePositions(ss->osd_evaluator, (float *)positions, 0, num_basis_verts);
- ss->osd_evaluator->refine(ss->osd_evaluator);
-
- MEM_freeN(positions);
-}
-
-static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss,
- CCGFace *face,
- const int osd_face_index)
-{
- int normalDataOffset = ss->normalDataOffset;
- int subdivLevels = ss->subdivLevels;
- int gridSize = ccg_gridsize(subdivLevels);
- int edgeSize = ccg_edgesize(subdivLevels);
- int vertDataSize = ss->meshIFC.vertDataSize;
- int S;
- bool do_normals = ss->meshIFC.numLayers == 3;
-
-# pragma omp parallel for
- for (S = 0; S < face->numVerts; S++) {
- int x, y, k;
- CCGEdge *edge = NULL;
- bool inverse_edge = false;
-
- for (x = 0; x < gridSize; x++) {
- for (y = 0; y < gridSize; y++) {
- float *co = FACE_getIFCo(face, subdivLevels, S, x, y);
- float *no = FACE_getIFNo(face, subdivLevels, S, x, y);
- float grid_u = (float)x / (gridSize - 1), grid_v = (float)y / (gridSize - 1);
- float face_u, face_v;
- float P[3], dPdu[3], dPdv[3];
-
- ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v);
-
- /* TODO(sergey): Need proper port. */
- ss->osd_evaluator->evaluateLimit(ss->osd_evaluator,
- osd_face_index,
- face_u,
- face_v,
- P,
- do_normals ? dPdu : NULL,
- do_normals ? dPdv : NULL);
-
- OSD_LOG("face=%d, corner=%d, grid_u=%f, grid_v=%f, face_u=%f, face_v=%f, P=(%f, %f, %f)\n",
- osd_face_index,
- S,
- grid_u,
- grid_v,
- face_u,
- face_v,
- P[0],
- P[1],
- P[2]);
-
- VertDataCopy(co, P, ss);
- if (do_normals) {
- cross_v3_v3v3(no, dPdu, dPdv);
- normalize_v3(no);
- }
-
- if (x == gridSize - 1 && y == gridSize - 1) {
- float *vert_co = VERT_getCo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_co, co, ss);
- if (do_normals) {
- float *vert_no = VERT_getNo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_no, no, ss);
- }
- }
- if (S == 0 && x == 0 && y == 0) {
- float *center_co = (float *)FACE_getCenterData(face);
- VertDataCopy(center_co, co, ss);
- if (do_normals) {
- float *center_no = (float *)((byte *)FACE_getCenterData(face) + normalDataOffset);
- VertDataCopy(center_no, no, ss);
- }
- }
- }
- }
-
- for (x = 0; x < gridSize; x++) {
- VertDataCopy(
- FACE_getIECo(face, subdivLevels, S, x), FACE_getIFCo(face, subdivLevels, S, x, 0), ss);
- if (do_normals) {
- VertDataCopy(
- FACE_getIENo(face, subdivLevels, S, x), FACE_getIFNo(face, subdivLevels, S, x, 0), ss);
- }
- }
-
- for (k = 0; k < face->numVerts; k++) {
- CCGEdge *current_edge = FACE_getEdges(face)[k];
- CCGVert **face_verts = FACE_getVerts(face);
- if (current_edge->v0 == face_verts[S] &&
- current_edge->v1 == face_verts[(S + 1) % face->numVerts]) {
- edge = current_edge;
- inverse_edge = false;
- break;
- }
- if (current_edge->v1 == face_verts[S] &&
- current_edge->v0 == face_verts[(S + 1) % face->numVerts]) {
- edge = current_edge;
- inverse_edge = true;
- break;
- }
- }
-
- BLI_assert(edge != NULL);
-
- for (x = 0; x < edgeSize; x++) {
- float u = 0, v = 0;
- float *co = EDGE_getCo(edge, subdivLevels, x);
- float *no = EDGE_getNo(edge, subdivLevels, x);
- float P[3], dPdu[3], dPdv[3];
- ccgSubSurf__mapEdgeToFace(S, x, inverse_edge, edgeSize, &u, &v);
-
- /* TODO(sergey): Ideally we will re-use grid here, but for now
- * let's just re-evaluate for simplicity.
- */
- /* TODO(sergey): Need proper port. */
- ss->osd_evaluator->evaluateLimit(ss->osd_evaluator, osd_face_index, u, v, P, dPdu, dPdv);
- VertDataCopy(co, P, ss);
- if (do_normals) {
- cross_v3_v3v3(no, dPdu, dPdv);
- normalize_v3(no);
- }
- }
- }
-}
-
-static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss,
- CCGFace *face,
- const int osd_face_index)
-{
- CCGVert **all_verts = FACE_getVerts(face);
- int normalDataOffset = ss->normalDataOffset;
- int subdivLevels = ss->subdivLevels;
- int gridSize = ccg_gridsize(subdivLevels);
- int edgeSize = ccg_edgesize(subdivLevels);
- int vertDataSize = ss->meshIFC.vertDataSize;
- int S;
- bool do_normals = ss->meshIFC.numLayers == 3;
-
- /* Note about handling non-quad faces.
- *
- * In order to deal with non-quad faces we need to split them
- * into a quads in the following way:
- *
- * |
- * (vert_next)
- * |
- * |
- * |
- * (face_center) ------------------- (v2)
- * | (o)--------------------> |
- * | | v |
- * | | |
- * | | |
- * | | |
- * | | y ^ |
- * | | | |
- * | v u x | |
- * | <---(o) |
- * ---- (vert_prev) ---- (v1) -------------------- (vert)
- *
- * This is how grids are expected to be stored and it's how
- * OpenSubdiv deals with non-quad faces using ptex face indices.
- * We only need to convert ptex (x, y) to grid (u, v) by some
- * simple flips and evaluate the ptex face.
- */
-
- /* Evaluate face grids. */
-# pragma omp parallel for
- for (S = 0; S < face->numVerts; S++) {
- int x, y;
- for (x = 0; x < gridSize; x++) {
- for (y = 0; y < gridSize; y++) {
- float *co = FACE_getIFCo(face, subdivLevels, S, x, y);
- float *no = FACE_getIFNo(face, subdivLevels, S, x, y);
- float u = 1.0f - (float)y / (gridSize - 1), v = 1.0f - (float)x / (gridSize - 1);
- float P[3], dPdu[3], dPdv[3];
-
- /* TODO(sergey): Need proper port. */
- ss->osd_evaluator->evaluateLimit(
- ss->osd_evaluator, osd_face_index + S, u, v, P, dPdu, dPdv);
-
- OSD_LOG("face=%d, corner=%d, u=%f, v=%f, P=(%f, %f, %f)\n",
- osd_face_index + S,
- S,
- u,
- v,
- P[0],
- P[1],
- P[2]);
-
- VertDataCopy(co, P, ss);
- if (do_normals) {
- cross_v3_v3v3(no, dPdu, dPdv);
- normalize_v3(no);
- }
-
- /* TODO(sergey): De-dpuplicate with the quad case. */
- if (x == gridSize - 1 && y == gridSize - 1) {
- float *vert_co = VERT_getCo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_co, co, ss);
- if (do_normals) {
- float *vert_no = VERT_getNo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_no, no, ss);
- }
- }
- if (S == 0 && x == 0 && y == 0) {
- float *center_co = (float *)FACE_getCenterData(face);
- VertDataCopy(center_co, co, ss);
- if (do_normals) {
- float *center_no = (float *)((byte *)FACE_getCenterData(face) + normalDataOffset);
- VertDataCopy(center_no, no, ss);
- }
- }
- }
- }
- for (x = 0; x < gridSize; x++) {
- VertDataCopy(
- FACE_getIECo(face, subdivLevels, S, x), FACE_getIFCo(face, subdivLevels, S, x, 0), ss);
- if (do_normals) {
- VertDataCopy(
- FACE_getIENo(face, subdivLevels, S, x), FACE_getIFNo(face, subdivLevels, S, x, 0), ss);
- }
- }
- }
-
- /* Evaluate edges. */
- for (S = 0; S < face->numVerts; S++) {
- CCGEdge *edge = FACE_getEdges(face)[S];
- int x, S0 = 0, S1 = 0;
- bool flip;
-
- for (x = 0; x < face->numVerts; x++) {
- if (all_verts[x] == edge->v0) {
- S0 = x;
- }
- else if (all_verts[x] == edge->v1) {
- S1 = x;
- }
- }
- if (S == face->numVerts - 1) {
- flip = S0 > S1;
- }
- else {
- flip = S0 < S1;
- }
-
- for (x = 0; x <= edgeSize / 2; x++) {
- float *edge_co = EDGE_getCo(edge, subdivLevels, x);
- float *edge_no = EDGE_getNo(edge, subdivLevels, x);
- float *face_edge_co;
- float *face_edge_no;
- if (flip) {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S0, gridSize - 1, gridSize - 1 - x);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S0, gridSize - 1, gridSize - 1 - x);
- }
- else {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S0, gridSize - 1 - x, gridSize - 1);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S0, gridSize - 1 - x, gridSize - 1);
- }
- VertDataCopy(edge_co, face_edge_co, ss);
- if (do_normals) {
- VertDataCopy(edge_no, face_edge_no, ss);
- }
- }
- for (x = edgeSize / 2 + 1; x < edgeSize; x++) {
- float *edge_co = EDGE_getCo(edge, subdivLevels, x);
- float *edge_no = EDGE_getNo(edge, subdivLevels, x);
- float *face_edge_co;
- float *face_edge_no;
- if (flip) {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S1, x - edgeSize / 2, gridSize - 1);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S1, x - edgeSize / 2, gridSize - 1);
- }
- else {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S1, gridSize - 1, x - edgeSize / 2);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S1, gridSize - 1, x - edgeSize / 2);
- }
- VertDataCopy(edge_co, face_edge_co, ss);
- if (do_normals) {
- VertDataCopy(edge_no, face_edge_no, ss);
- }
- }
- }
-}
-
-static void opensubdiv_evaluateGrids(CCGSubSurf *ss)
-{
- int i;
- for (i = 0; i < ss->fMap->curSize; i++) {
- CCGFace *face = (CCGFace *)ss->fMap->buckets[i];
- for (; face; face = face->next) {
- if (face->numVerts == 4) {
- /* For quads we do special magic with converting face coords
- * into corner coords and interpolating grids from it.
- */
- opensubdiv_evaluateQuadFaceGrids(ss, face, face->osd_index);
- }
- else {
- /* NGons and tris are split into separate osd faces which
- * evaluates onto grids directly.
- */
- opensubdiv_evaluateNGonFaceGrids(ss, face, face->osd_index);
- }
- }
- }
-}
-
-CCGError ccgSubSurf_initOpenSubdivSync(CCGSubSurf *ss)
-{
- if (ss->syncState != eSyncState_None) {
- return eCCGError_InvalidSyncState;
- }
- ss->syncState = eSyncState_OpenSubdiv;
- return eCCGError_None;
-}
-
-void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, DerivedMesh *dm)
-{
- if (ss->osd_mesh == NULL || ss->osd_mesh_invalid) {
- if (dm->getNumPolys(dm) != 0) {
- OpenSubdiv_Converter converter;
- ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
- /* TODO(sergey): Remove possibly previously allocated refiner. */
- OpenSubdiv_TopologyRefinerSettings settings;
- settings.level = ss->subdivLevels;
- settings.is_adaptive = false;
- ss->osd_topology_refiner = openSubdiv_createTopologyRefinerFromConverter(&converter,
- &settings);
- ccgSubSurf_converter_free(&converter);
- }
- }
-
- /* Update number of grids, needed for things like final faces
- * counter, used by display drawing.
- */
- {
- const int num_polys = dm->getNumPolys(dm);
- const MPoly *mpoly = dm->getPolyArray(dm);
- int poly;
- ss->numGrids = 0;
- for (poly = 0; poly < num_polys; poly++) {
- ss->numGrids += mpoly[poly].totloop;
- }
- }
-
- {
- const int num_verts = dm->getNumVerts(dm);
- const MVert *mvert = dm->getVertArray(dm);
- int vert;
- if (ss->osd_coarse_coords != NULL && num_verts != ss->osd_num_coarse_coords) {
- MEM_freeN(ss->osd_coarse_coords);
- ss->osd_coarse_coords = NULL;
- }
- if (ss->osd_coarse_coords == NULL) {
- ss->osd_coarse_coords = MEM_mallocN(sizeof(float) * 6 * num_verts, "osd coarse positions");
- }
- for (vert = 0; vert < num_verts; vert++) {
- copy_v3_v3(ss->osd_coarse_coords[vert * 2 + 0], mvert[vert].co);
- normal_short_to_float_v3(ss->osd_coarse_coords[vert * 2 + 1], mvert[vert].no);
- }
- ss->osd_num_coarse_coords = num_verts;
- ss->osd_coarse_coords_invalid = true;
- }
-}
-
-void ccgSubSurf__sync_opensubdiv(CCGSubSurf *ss)
-{
- BLI_assert(ss->meshIFC.numLayers == 2 || ss->meshIFC.numLayers == 3);
-
- /* Common synchronization steps */
- ss->osd_compute = U.opensubdiv_compute_type;
-
- if (ss->skip_grids == false) {
- /* Make sure OSD evaluator is up-to-date. */
- if (opensubdiv_ensureEvaluator(ss)) {
- /* Update coarse points in the OpenSubdiv evaluator. */
- opensubdiv_updateEvaluatorCoarsePositions(ss);
-
- /* Evaluate opensubdiv mesh into the CCG grids. */
- opensubdiv_evaluateGrids(ss);
- }
- }
- else {
- BLI_assert(ss->meshIFC.numLayers == 3);
- }
-
-# ifdef DUMP_RESULT_GRIDS
- ccgSubSurf__dumpCoords(ss);
-# endif
-}
-
-void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss)
-{
- if (ss->osd_mesh != NULL) {
- ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
- ss->osd_mesh = NULL;
- }
- if (ss->osd_vao != 0) {
- glDeleteVertexArrays(1, &ss->osd_vao);
- ss->osd_vao = 0;
- }
-}
-
-void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3])
-{
- int i;
- BLI_assert(ss->skip_grids == true);
- if (ss->osd_num_coarse_coords == 0) {
- zero_v3(r_min);
- zero_v3(r_max);
- }
- for (i = 0; i < ss->osd_num_coarse_coords; i++) {
- /* Coarse coordinates has normals interleaved into the array. */
- DO_MINMAX(ss->osd_coarse_coords[2 * i], r_min, r_max);
- }
-}
-
-/* ** Delayed delete routines ** */
-
-typedef struct OsdDeletePendingItem {
- struct OsdDeletePendingItem *next, *prev;
- OpenSubdiv_GLMesh *osd_mesh;
- unsigned int vao;
-} OsdDeletePendingItem;
-
-static SpinLock delete_spin;
-static ListBase delete_pool = {NULL, NULL};
-
-static void delete_pending_push(OpenSubdiv_GLMesh *osd_mesh, unsigned int vao)
-{
- OsdDeletePendingItem *new_entry = MEM_mallocN(sizeof(OsdDeletePendingItem),
- "opensubdiv delete entry");
- new_entry->osd_mesh = osd_mesh;
- new_entry->vao = vao;
- BLI_spin_lock(&delete_spin);
- BLI_addtail(&delete_pool, new_entry);
- BLI_spin_unlock(&delete_spin);
-}
-
-void ccgSubSurf__delete_osdGLMesh(OpenSubdiv_GLMesh *osd_mesh)
-{
- if (BLI_thread_is_main()) {
- openSubdiv_deleteOsdGLMesh(osd_mesh);
- }
- else {
- delete_pending_push(osd_mesh, 0);
- }
-}
-
-void ccgSubSurf__delete_vertex_array(unsigned int vao)
-{
- if (BLI_thread_is_main()) {
- glDeleteVertexArrays(1, &vao);
- }
- else {
- delete_pending_push(NULL, vao);
- }
-}
-
-void ccgSubSurf__delete_pending(void)
-{
- OsdDeletePendingItem *entry;
- BLI_assert(BLI_thread_is_main());
- BLI_spin_lock(&delete_spin);
- for (entry = delete_pool.first; entry != NULL; entry = entry->next) {
- if (entry->osd_mesh != NULL) {
- openSubdiv_deleteOsdGLMesh(entry->osd_mesh);
- }
- if (entry->vao != 0) {
- glDeleteVertexArrays(1, &entry->vao);
- }
- }
- BLI_freelistN(&delete_pool);
- BLI_spin_unlock(&delete_spin);
-}
-
-void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subdiv_uvs)
-{
- ss->osd_subdiv_uvs = subdiv_uvs;
-}
-
-/* ** Public API ** */
-
-void BKE_subsurf_osd_init(void)
-{
- openSubdiv_init();
- BLI_spin_init(&delete_spin);
-}
-
-void BKE_subsurf_free_unused_buffers(void)
-{
- ccgSubSurf__delete_pending();
-}
-
-void BKE_subsurf_osd_cleanup(void)
-{
- openSubdiv_cleanup();
- ccgSubSurf__delete_pending();
- BLI_spin_end(&delete_spin);
-}
-
-#endif /* WITH_OPENSUBDIV */