diff options
Diffstat (limited to 'source/blender/blenkernel/intern/subsurf_ccg.c')
-rw-r--r-- | source/blender/blenkernel/intern/subsurf_ccg.c | 609 |
1 files changed, 496 insertions, 113 deletions
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index d419fc70be9..7d21b3304cd 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -77,6 +77,10 @@ #include "CCGSubSurf.h" +#ifdef WITH_OPENSUBDIV +# include "opensubdiv_capi.h" +#endif + /* assumes MLoop's are layed out 4 for each poly, in order */ #define USE_LOOP_LAYOUT_FAST @@ -88,7 +92,8 @@ static ThreadRWMutex origindex_cache_rwlock = BLI_RWLOCK_INITIALIZER; static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, int drawInteriorEdges, int useSubsurfUv, - DerivedMesh *dm); + DerivedMesh *dm, + bool use_gpu_backend); static int ccgDM_use_grid_pbvh(CCGDerivedMesh *ccgdm); /// @@ -268,6 +273,7 @@ static int getFaceIndex(CCGSubSurf *ss, CCGFace *f, int S, int x, int y, int edg } } +#ifndef WITH_OPENSUBDIV static void get_face_uv_map_vert(UvVertMap *vmap, struct MPoly *mpoly, struct MLoop *ml, int fi, CCGVertHDL *fverts) { UvMapVert *v, *nv; @@ -409,7 +415,96 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, return 1; } +#endif /* WITH_OPENSUBDIV */ + +#ifdef WITH_OPENSUBDIV +static void set_subsurf_ccg_uv(CCGSubSurf *ss, + DerivedMesh *dm, + DerivedMesh *result, + int layer_index) +{ + CCGFace **faceMap; + MTFace *tf; + MLoopUV *mluv; + CCGFaceIterator fi; + int index, gridSize, gridFaces, totface, x, y, S; + MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer_index); + /* need to update both CD_MTFACE & CD_MLOOPUV, hrmf, we could get away with + * just tface except applying the modifier then looses subsurf UV */ + MTFace *tface = CustomData_get_layer_n(&result->faceData, CD_MTFACE, layer_index); + MLoopUV *mloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, layer_index); + + if (dmloopuv == NULL || (tface == NULL && mloopuv == NULL)) { + return; + } + + ccgSubSurf_evaluatorSetFVarUV(ss, dm, layer_index); + + /* get some info from CCGSubSurf */ + totface = ccgSubSurf_getNumFaces(ss); + gridSize = ccgSubSurf_getGridSize(ss); + gridFaces = gridSize - 1; + + /* make a map from original faces to CCGFaces */ + faceMap = MEM_mallocN(totface * sizeof(*faceMap), "facemapuv"); + for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(&fi); + faceMap[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f))] = f; + } + + /* load coordinates from uvss into tface */ + tf = tface; + mluv = mloopuv; + for (index = 0; index < totface; index++) { + CCGFace *f = faceMap[index]; + int numVerts = ccgSubSurf_getFaceNumVerts(f); + for (S = 0; S < numVerts; S++) { + for (y = 0; y < gridFaces; y++) { + for (x = 0; x < gridFaces; x++) { + float grid_u = ((float)(x)) / (gridSize - 1), + grid_v = ((float)(y)) / (gridSize - 1); + float uv[2]; + /* TODO(sergey): Evaluator all 4 corners. */ + ccgSubSurf_evaluatorFVarUV(ss, + index, + S, + grid_u, grid_v, + uv); + if (tf) { + copy_v2_v2(tf->uv[0], uv); + copy_v2_v2(tf->uv[1], uv); + copy_v2_v2(tf->uv[2], uv); + copy_v2_v2(tf->uv[3], uv); + tf++; + } + if (mluv) { + copy_v2_v2(mluv[0].uv, uv); + copy_v2_v2(mluv[1].uv, uv); + copy_v2_v2(mluv[2].uv, uv); + copy_v2_v2(mluv[3].uv, uv); + mluv += 4; + } + } + } + } + } + MEM_freeN(faceMap); +} +static void set_subsurf_uv(CCGSubSurf *ss, + DerivedMesh *dm, + DerivedMesh *result, + int layer_index) +{ + if (!ccgSubSurf_needGrids(ss)) { + /* GPU backend is used, no need to evaluate UVs on CPU. */ + /* TODO(sergey): Think of how to support edit mode of UVs. */ + } + else { + set_subsurf_ccg_uv(ss, dm, result, layer_index); + } +} +#else /* WITH_OPENSUBDIV */ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int n) { CCGSubSurf *uvss; @@ -490,6 +585,7 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, ccgSubSurf_free(uvss); MEM_freeN(faceMap); } +#endif /* WITH_OPENSUBDIV */ /* face weighting */ typedef struct FaceVertWeightEntry { @@ -571,8 +667,10 @@ static void free_ss_weights(WeightTable *wtable) MEM_freeN(wtable->weight_table); } -static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm, - float (*vertexCos)[3], int useFlatSubdiv) +static void ss_sync_ccg_from_derivedmesh(CCGSubSurf *ss, + DerivedMesh *dm, + float (*vertexCos)[3], + int useFlatSubdiv) { float creaseFactor = (float) ccgSubSurf_getSubdivisionLevels(ss); #ifndef USE_DYNSIZE @@ -672,6 +770,37 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm, #endif } +#ifdef WITH_OPENSUBDIV +static void ss_sync_osd_from_derivedmesh(CCGSubSurf *ss, + DerivedMesh *dm) +{ + ccgSubSurf_initFullSync(ss); + ccgSubSurf_prepareTopologyRefiner(ss, dm); + ccgSubSurf_processSync(ss); +} +#endif /* WITH_OPENSUBDIV */ + +static void ss_sync_from_derivedmesh(CCGSubSurf *ss, + DerivedMesh *dm, + float (*vertexCos)[3], + int use_flat_subdiv) +{ +#ifdef WITH_OPENSUBDIV + /* Reset all related descriptors if actual mesh topology changed or if + * other evlauation-related settings changed. + */ + ccgSubSurf_checkTopologyChanged(ss, dm); + if (!ccgSubSurf_needGrids(ss)) { + /* TODO(sergey): Use vertex coordinates and flat subdiv flag. */ + ss_sync_osd_from_derivedmesh(ss, dm); + } + else +#endif + { + ss_sync_ccg_from_derivedmesh(ss, dm, vertexCos, use_flat_subdiv); + } +} + /***/ static int ccgDM_getVertMapIndex(CCGSubSurf *ss, CCGVert *v) @@ -1651,6 +1780,16 @@ static void ccgDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEd int gridSize = ccgSubSurf_getGridSize(ss); int useAging; +#ifdef WITH_OPENSUBDIV + if (ccgdm->useGpuBackend) { + /* TODO(sergey): We currently only support all edges drawing. */ + if (ccgSubSurf_prepareGLMesh(ss, true)) { + ccgSubSurf_drawGLMesh(ss, false, -1, -1); + } + return; + } +#endif + CCG_key_top_level(&key, ss); ccgdm_pbvh_update(ccgdm); @@ -1722,6 +1861,13 @@ static void ccgDM_drawLooseEdges(DerivedMesh *dm) int totedge = ccgSubSurf_getNumEdges(ss); int i, j, edgeSize = ccgSubSurf_getEdgeSize(ss); +#ifdef WITH_OPENSUBDIV + if (ccgdm->useGpuBackend) { + /* TODO(sergey): Needs implementation. */ + return; + } +#endif + CCG_key_top_level(&key, ss); for (j = 0; j < totedge; j++) { @@ -2301,7 +2447,34 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes) return; } - + +#ifdef WITH_OPENSUBDIV + if (ccgdm->useGpuBackend) { + CCGSubSurf *ss = ccgdm->ss; + DMFlagMat *faceFlags = ccgdm->faceFlags; + int new_matnr; + bool draw_smooth; + if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL) == false)) { + return; + } + /* TODO(sergey): Single matierial currently. */ + if (faceFlags) { + draw_smooth = (faceFlags[0].flag & ME_SMOOTH); + new_matnr = (faceFlags[0].mat_nr + 1); + } + else { + draw_smooth = true; + new_matnr = 1; + } + if (setMaterial) { + setMaterial(new_matnr, NULL); + } + glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); + ccgSubSurf_drawGLMesh(ss, true, -1, -1); + return; + } +#endif + GPU_vertex_setup(dm); GPU_normal_setup(dm); GPU_triangle_setup(dm); @@ -2334,6 +2507,30 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL); int a, i, do_draw, numVerts, matnr, new_matnr, totface; +#ifdef WITH_OPENSUBDIV + if (ccgdm->useGpuBackend) { + int new_matnr; + bool draw_smooth; + GPU_draw_update_fvar_offset(dm); + if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, false) == false)) { + return; + } + /* TODO(sergey): Single matierial currently. */ + if (faceFlags) { + draw_smooth = (faceFlags[0].flag & ME_SMOOTH); + new_matnr = (faceFlags[0].mat_nr + 1); + } + else { + draw_smooth = true; + new_matnr = 1; + } + glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); + setMaterial(new_matnr, &gattribs); + ccgSubSurf_drawGLMesh(ss, true, -1, -1); + return; + } +#endif + CCG_key_top_level(&key, ss); ccgdm_pbvh_update(ccgdm); @@ -2506,6 +2703,13 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm, short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL); int a, i, numVerts, matnr, new_matnr, totface; +#ifdef WITH_OPENSUBDIV + if (ccgdm->useGpuBackend) { + BLI_assert(!"Not currently supported"); + return; + } +#endif + CCG_key_top_level(&key, ss); ccgdm_pbvh_update(ccgdm); @@ -2678,6 +2882,16 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, int mat_index; int tot_element, start_element, tot_drawn; +#ifdef WITH_OPENSUBDIV + if (ccgdm->useGpuBackend) { + if (ccgSubSurf_prepareGLMesh(ss, true) == false) { + return; + } + ccgSubSurf_drawGLMesh(ss, true, -1, -1); + return; + } +#endif + CCG_key_top_level(&key, ss); ccgdm_pbvh_update(ccgdm); @@ -2847,6 +3061,26 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, int gridFaces = gridSize - 1, totface; int prev_mat_nr = -1; +#ifdef WITH_OPENSUBDIV + if (ccgdm->useGpuBackend) { + /* TODO(sergey): This is for cases when vertex colors or weights + * are visualising. Currently we don't have CD layers for this data + * and here we only make it so there's no garbage displayed. + * + * In the future we'll either need to have CD for this data or pass + * this data as face-varying or vertex-varying data in OSD mesh. + */ + if (setDrawOptions == NULL) { + glColor3f(0.8f, 0.8f, 0.8f); + } + if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true) == false)) { + return; + } + ccgSubSurf_drawGLMesh(ss, true, -1, -1); + return; + } +#endif + CCG_key_top_level(&key, ss); /* currently unused -- each original face is handled separately */ @@ -3016,6 +3250,13 @@ static void ccgDM_drawMappedEdges(DerivedMesh *dm, CCGKey key; int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss); +#ifdef WITH_OPENSUBDIV + if (ccgdm->useGpuBackend) { + BLI_assert(!"Not currently supported"); + return; + } +#endif + CCG_key_top_level(&key, ss); ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL); @@ -3051,6 +3292,13 @@ static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm, CCGEdgeIterator ei; int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss); +#ifdef WITH_OPENSUBDIV + if (ccgdm->useGpuBackend) { + BLI_assert(!"Not currently supported"); + return; + } +#endif + CCG_key_top_level(&key, ss); ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL); @@ -3145,9 +3393,11 @@ static void ccgDM_release(DerivedMesh *dm) if (ccgdm->pmap_mem) MEM_freeN(ccgdm->pmap_mem); MEM_freeN(ccgdm->edgeFlags); MEM_freeN(ccgdm->faceFlags); - MEM_freeN(ccgdm->vertMap); - MEM_freeN(ccgdm->edgeMap); - MEM_freeN(ccgdm->faceMap); + if (ccgdm->useGpuBackend == false) { + MEM_freeN(ccgdm->vertMap); + MEM_freeN(ccgdm->edgeMap); + MEM_freeN(ccgdm->faceMap); + } MEM_freeN(ccgdm); } } @@ -3681,74 +3931,8 @@ static void ccgDM_calcNormals(DerivedMesh *dm) dm->dirty &= ~DM_DIRTY_NORMALS; } -static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, - int drawInteriorEdges, - int useSubsurfUv, - DerivedMesh *dm) +static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm) { - CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm"); - CCGVertIterator vi; - CCGEdgeIterator ei; - CCGFaceIterator fi; - int index, totvert, totedge, totface; - int i; - int vertNum, edgeNum, faceNum; - int *vertOrigIndex, *faceOrigIndex, *polyOrigIndex, *base_polyOrigIndex, *edgeOrigIndex; - short *edgeFlags; - DMFlagMat *faceFlags; - int *polyidx = NULL; -#ifndef USE_DYNSIZE - int *loopidx = NULL, *vertidx = NULL; - BLI_array_declare(loopidx); - BLI_array_declare(vertidx); -#endif - int loopindex, loopindex2; - int edgeSize; - int gridSize; - int gridFaces, gridCuts; - /*int gridSideVerts;*/ - int gridSideEdges; - int numTex, numCol; - int hasPCol, hasOrigSpace; - int gridInternalEdges; - WeightTable wtable = {NULL}; - /* MCol *mcol; */ /* UNUSED */ - MEdge *medge = NULL; - /* MFace *mface = NULL; */ - MPoly *mpoly = NULL; - bool has_edge_cd; - - DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM, - ccgSubSurf_getNumFinalVerts(ss), - ccgSubSurf_getNumFinalEdges(ss), - ccgSubSurf_getNumFinalFaces(ss), - ccgSubSurf_getNumFinalFaces(ss) * 4, - ccgSubSurf_getNumFinalFaces(ss)); - - CustomData_free_layer_active(&ccgdm->dm.polyData, CD_NORMAL, - ccgdm->dm.numPolyData); - - numTex = CustomData_number_of_layers(&ccgdm->dm.loopData, CD_MLOOPUV); - numCol = CustomData_number_of_layers(&ccgdm->dm.loopData, CD_MLOOPCOL); - hasPCol = CustomData_has_layer(&ccgdm->dm.loopData, CD_PREVIEW_MLOOPCOL); - hasOrigSpace = CustomData_has_layer(&ccgdm->dm.loopData, CD_ORIGSPACE_MLOOP); - - if ( - (numTex && CustomData_number_of_layers(&ccgdm->dm.faceData, CD_MTFACE) != numTex) || - (numCol && CustomData_number_of_layers(&ccgdm->dm.faceData, CD_MCOL) != numCol) || - (hasPCol && !CustomData_has_layer(&ccgdm->dm.faceData, CD_PREVIEW_MCOL)) || - (hasOrigSpace && !CustomData_has_layer(&ccgdm->dm.faceData, CD_ORIGSPACE)) ) - { - CustomData_from_bmeshpoly(&ccgdm->dm.faceData, - &ccgdm->dm.polyData, - &ccgdm->dm.loopData, - ccgSubSurf_getNumFinalFaces(ss)); - } - - /* We absolutely need that layer, else it's no valid tessellated data! */ - polyidx = CustomData_add_layer(&ccgdm->dm.faceData, CD_ORIGINDEX, CD_CALLOC, - NULL, ccgSubSurf_getNumFinalFaces(ss)); - ccgdm->dm.getMinMax = ccgDM_getMinMax; ccgdm->dm.getNumVerts = ccgDM_getNumVerts; ccgdm->dm.getNumEdges = ccgDM_getNumEdges; @@ -3801,7 +3985,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, ccgdm->dm.foreachMappedEdge = ccgDM_foreachMappedEdge; ccgdm->dm.foreachMappedLoop = ccgDM_foreachMappedLoop; ccgdm->dm.foreachMappedFaceCenter = ccgDM_foreachMappedFaceCenter; - + ccgdm->dm.drawVerts = ccgDM_drawVerts; ccgdm->dm.drawEdges = ccgDM_drawEdges; ccgdm->dm.drawLooseEdges = ccgDM_drawLooseEdges; @@ -3820,14 +4004,22 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, ccgdm->dm.copy_gpu_data = ccgDM_copy_gpu_data; ccgdm->dm.release = ccgDM_release; - - ccgdm->ss = ss; - ccgdm->drawInteriorEdges = drawInteriorEdges; - ccgdm->useSubsurfUv = useSubsurfUv; +} + +static void create_ccgdm_maps(CCGDerivedMesh *ccgdm, + CCGSubSurf *ss) +{ + CCGVertIterator vi; + CCGEdgeIterator ei; + CCGFaceIterator fi; + int totvert, totedge, totface; totvert = ccgSubSurf_getNumVerts(ss); ccgdm->vertMap = MEM_mallocN(totvert * sizeof(*ccgdm->vertMap), "vertMap"); - for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) { + for (ccgSubSurf_initVertIterator(ss, &vi); + !ccgVertIterator_isStopped(&vi); + ccgVertIterator_next(&vi)) + { CCGVert *v = ccgVertIterator_getCurrent(&vi); ccgdm->vertMap[GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v))].vert = v; @@ -3835,7 +4027,10 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, totedge = ccgSubSurf_getNumEdges(ss); ccgdm->edgeMap = MEM_mallocN(totedge * sizeof(*ccgdm->edgeMap), "edgeMap"); - for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) { + for (ccgSubSurf_initEdgeIterator(ss, &ei); + !ccgEdgeIterator_isStopped(&ei); + ccgEdgeIterator_next(&ei)) + { CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); ccgdm->edgeMap[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))].edge = e; @@ -3843,13 +4038,60 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, totface = ccgSubSurf_getNumFaces(ss); ccgdm->faceMap = MEM_mallocN(totface * sizeof(*ccgdm->faceMap), "faceMap"); - for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) { + for (ccgSubSurf_initFaceIterator(ss, &fi); + !ccgFaceIterator_isStopped(&fi); + ccgFaceIterator_next(&fi)) + { CCGFace *f = ccgFaceIterator_getCurrent(&fi); ccgdm->faceMap[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f))].face = f; } +} + +/* Fill in all geometry arrays making it possible to access any + * hires data from the CPU. + */ +static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, + CCGSubSurf *ss, + DerivedMesh *dm, + bool useSubsurfUv) +{ + const int totvert = ccgSubSurf_getNumVerts(ss); + const int totedge = ccgSubSurf_getNumEdges(ss); + const int totface = ccgSubSurf_getNumFaces(ss); + int index; + int i; + int vertNum = 0, edgeNum = 0, faceNum = 0; + int *vertOrigIndex, *faceOrigIndex, *polyOrigIndex, *base_polyOrigIndex, *edgeOrigIndex; + short *edgeFlags = ccgdm->edgeFlags; + DMFlagMat *faceFlags = ccgdm->faceFlags; + int *polyidx = NULL; +#ifndef USE_DYNSIZE + int *loopidx = NULL, *vertidx = NULL; + BLI_array_declare(loopidx); + BLI_array_declare(vertidx); +#endif + int loopindex, loopindex2; + int edgeSize; + int gridSize; + int gridFaces, gridCuts; + int gridSideEdges; + int numTex, numCol; + int hasPCol, hasOrigSpace; + int gridInternalEdges; + WeightTable wtable = {NULL}; + MEdge *medge = NULL; + MPoly *mpoly = NULL; + bool has_edge_cd; - ccgdm->reverseFaceMap = MEM_callocN(sizeof(int) * ccgSubSurf_getNumFinalFaces(ss), "reverseFaceMap"); + numTex = CustomData_number_of_layers(&ccgdm->dm.loopData, CD_MLOOPUV); + numCol = CustomData_number_of_layers(&ccgdm->dm.loopData, CD_MLOOPCOL); + hasPCol = CustomData_has_layer(&ccgdm->dm.loopData, CD_PREVIEW_MLOOPCOL); + hasOrigSpace = CustomData_has_layer(&ccgdm->dm.loopData, CD_ORIGSPACE_MLOOP); + + /* We absolutely need that layer, else it's no valid tessellated data! */ + polyidx = CustomData_add_layer(&ccgdm->dm.faceData, CD_ORIGINDEX, CD_CALLOC, + NULL, ccgSubSurf_getNumFinalFaces(ss)); edgeSize = ccgSubSurf_getEdgeSize(ss); gridSize = ccgSubSurf_getGridSize(ss); @@ -3857,11 +4099,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, gridCuts = gridSize - 2; /*gridInternalVerts = gridSideVerts * gridSideVerts; - as yet, unused */ gridSideEdges = gridSize - 1; - gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2; - - vertNum = 0; - edgeNum = 0; - faceNum = 0; + gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2; /* mvert = dm->getVertArray(dm); */ /* UNUSED */ medge = dm->getEdgeArray(dm); @@ -3869,10 +4107,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); base_polyOrigIndex = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX); - - /*CDDM hack*/ - edgeFlags = ccgdm->edgeFlags = MEM_callocN(sizeof(short) * totedge, "edgeFlags"); - faceFlags = ccgdm->faceFlags = MEM_callocN(sizeof(DMFlagMat) * totface, "faceFlags"); vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX); edgeOrigIndex = DM_get_edge_data_layer(&ccgdm->dm, CD_ORIGINDEX); @@ -3902,13 +4136,12 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, #ifdef USE_DYNSIZE int loopidx[numVerts], vertidx[numVerts]; #endif - w = get_ss_weights(&wtable, gridCuts, numVerts); ccgdm->faceMap[index].startVert = vertNum; ccgdm->faceMap[index].startEdge = edgeNum; ccgdm->faceMap[index].startFace = faceNum; - + faceFlags->flag = mpoly ? mpoly[origIndex].flag : 0; faceFlags->mat_nr = mpoly ? mpoly[origIndex].mat_nr : 0; faceFlags++; @@ -3932,7 +4165,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, CCGVert *v = ccgSubSurf_getFaceVert(f, s); vertidx[s] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v)); } - /*I think this is for interpolating the center vert?*/ w2 = w; // + numVerts*(g2_wid-1) * (g2_wid-1); //numVerts*((g2_wid-1) * g2_wid+g2_wid-1); @@ -4003,7 +4235,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, CustomData_interp(&dm->loopData, &ccgdm->dm.loopData, loopidx, w2, NULL, numVerts, loopindex2); loopindex2++; - + w2 = w + s * numVerts * g2_wid * g2_wid + ((y) * g2_wid + (x + 1)) * numVerts; CustomData_interp(&dm->loopData, &ccgdm->dm.loopData, loopidx, w2, NULL, numVerts, loopindex2); @@ -4016,7 +4248,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, ccg_loops_to_corners(&ccgdm->dm.faceData, &ccgdm->dm.loopData, &ccgdm->dm.polyData, loopindex2 - 4, faceNum, faceNum, numTex, numCol, hasPCol, hasOrigSpace); - + /*set original index data*/ if (faceOrigIndex) { /* reference the index in 'polyOrigIndex' */ @@ -4123,26 +4355,149 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, vertNum++; } - ccgdm->dm.numVertData = vertNum; - ccgdm->dm.numEdgeData = edgeNum; - ccgdm->dm.numTessFaceData = faceNum; - ccgdm->dm.numLoopData = loopindex2; - ccgdm->dm.numPolyData = faceNum; - - /* All tessellated CD layers were updated! */ - ccgdm->dm.dirty &= ~DM_DIRTY_TESS_CDLAYERS; - #ifndef USE_DYNSIZE BLI_array_free(vertidx); BLI_array_free(loopidx); #endif free_ss_weights(&wtable); + BLI_assert(vertNum == ccgSubSurf_getNumFinalVerts(ss)); + BLI_assert(edgeNum == ccgSubSurf_getNumFinalEdges(ss)); + BLI_assert(loopindex2 == ccgSubSurf_getNumFinalFaces(ss) * 4); + BLI_assert(faceNum == ccgSubSurf_getNumFinalFaces(ss)); + +} + +/* Fill in only geometry arrays needed for the GPU tessellation. */ +static void set_ccgdm_gpu_geometry(CCGDerivedMesh *ccgdm, + CCGSubSurf *ss, + DerivedMesh *dm) +{ + const int totface = ccgSubSurf_getNumFaces(ss); + MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); + int index; + DMFlagMat *faceFlags = ccgdm->faceFlags; + + for (index = 0; index < totface; index++) { + faceFlags->flag = mpoly ? mpoly[index].flag : 0; + faceFlags->mat_nr = mpoly ? mpoly[index].mat_nr : 0; + faceFlags++; + } + + /* TODO(sergey): Fill in edge flags. */ +} + +static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, + int drawInteriorEdges, + int useSubsurfUv, + DerivedMesh *dm, + bool use_gpu_backend) +{ + const int totedge = ccgSubSurf_getNumEdges(ss); + const int totface = ccgSubSurf_getNumFaces(ss); + CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm"); + int numTex, numCol; + int hasPCol, hasOrigSpace; + + if (use_gpu_backend == false) { + DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM, + ccgSubSurf_getNumFinalVerts(ss), + ccgSubSurf_getNumFinalEdges(ss), + ccgSubSurf_getNumFinalFaces(ss), + ccgSubSurf_getNumFinalFaces(ss) * 4, + ccgSubSurf_getNumFinalFaces(ss)); + + numTex = CustomData_number_of_layers(&ccgdm->dm.loopData, + CD_MLOOPUV); + numCol = CustomData_number_of_layers(&ccgdm->dm.loopData, + CD_MLOOPCOL); + hasPCol = CustomData_has_layer(&ccgdm->dm.loopData, + CD_PREVIEW_MLOOPCOL); + hasOrigSpace = CustomData_has_layer(&ccgdm->dm.loopData, + CD_ORIGSPACE_MLOOP); + + if ( + (numTex && CustomData_number_of_layers(&ccgdm->dm.faceData, + CD_MTFACE) != numTex) || + (numCol && CustomData_number_of_layers(&ccgdm->dm.faceData, + CD_MCOL) != numCol) || + (hasPCol && !CustomData_has_layer(&ccgdm->dm.faceData, + CD_PREVIEW_MCOL)) || + (hasOrigSpace && !CustomData_has_layer(&ccgdm->dm.faceData, + CD_ORIGSPACE)) ) + { + CustomData_from_bmeshpoly(&ccgdm->dm.faceData, + &ccgdm->dm.polyData, + &ccgdm->dm.loopData, + ccgSubSurf_getNumFinalFaces(ss)); + } + + CustomData_free_layer_active(&ccgdm->dm.polyData, CD_NORMAL, + ccgdm->dm.numPolyData); + + ccgdm->reverseFaceMap = + MEM_callocN(sizeof(int) * ccgSubSurf_getNumFinalFaces(ss), + "reverseFaceMap"); + + create_ccgdm_maps(ccgdm, ss); + } + else { + DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM, + 0, 0, 0, 0, dm->getNumPolys(dm)); + CustomData_copy_data(&dm->polyData, + &ccgdm->dm.polyData, + 0, 0, dm->getNumPolys(dm)); + } + + set_default_ccgdm_callbacks(ccgdm); + + ccgdm->ss = ss; + ccgdm->drawInteriorEdges = drawInteriorEdges; + ccgdm->useSubsurfUv = useSubsurfUv; + ccgdm->useGpuBackend = use_gpu_backend; + + /* CDDM hack. */ + ccgdm->edgeFlags = MEM_callocN(sizeof(short) * totedge, "edgeFlags"); + ccgdm->faceFlags = MEM_callocN(sizeof(DMFlagMat) * totface, "faceFlags"); + + if (use_gpu_backend == false) { + set_ccgdm_all_geometry(ccgdm, ss, dm, useSubsurfUv != 0); + } + else { + set_ccgdm_gpu_geometry(ccgdm, ss, dm); + } + + ccgdm->dm.numVertData = ccgSubSurf_getNumFinalVerts(ss); + ccgdm->dm.numEdgeData = ccgSubSurf_getNumFinalEdges(ss); + ccgdm->dm.numTessFaceData = ccgSubSurf_getNumFinalFaces(ss); + ccgdm->dm.numLoopData = ccgdm->dm.numTessFaceData * 4; + ccgdm->dm.numPolyData = ccgdm->dm.numTessFaceData; + + /* All tessellated CD layers were updated! */ + ccgdm->dm.dirty &= ~DM_DIRTY_TESS_CDLAYERS; + return ccgdm; } /***/ +static bool subsurf_use_gpu_backend(SubsurfFlags flags) +{ +#ifdef WITH_OPENSUBDIV + /* Use GPU backend if it's a last modifier in the stack + * and user choosed to use any of the OSD compute devices, + * but also check if GPU has all needed features. + */ + return + (flags & SUBSURF_USE_GPU_BACKEND) != 0 && + (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE) && + (openSubdiv_supportGPUDisplay()); +#else + (void)flags; + return false; +#endif +} + struct DerivedMesh *subsurf_make_derived_from_derived( struct DerivedMesh *dm, struct SubsurfModifierData *smd, @@ -4154,18 +4509,28 @@ struct DerivedMesh *subsurf_make_derived_from_derived( int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv; int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges); CCGDerivedMesh *result; + bool use_gpu_backend = subsurf_use_gpu_backend(flags); /* note: editmode calculation can only run once per * modifier stack evaluation (uses freed cache) [#36299] */ if (flags & SUBSURF_FOR_EDIT_MODE) { int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels; + /* TODO(sergey): Same as emCache below. */ + if ((flags & SUBSURF_IN_EDIT_MODE) && smd->mCache) { + ccgSubSurf_free(smd->mCache); + smd->mCache = NULL; + } + smd->emCache = _getSubSurf(smd->emCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS); - ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple); +#ifdef WITH_OPENSUBDIV + ccgSubSurf_setSkipGrids(smd->emCache, use_gpu_backend); +#endif + ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple); result = getCCGDerivedMesh(smd->emCache, drawInteriorEdges, - useSubsurfUv, dm); + useSubsurfUv, dm, use_gpu_backend); } else if (flags & SUBSURF_USE_RENDER_PARAMS) { /* Do not use cache in render mode. */ @@ -4180,7 +4545,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple); result = getCCGDerivedMesh(ss, - drawInteriorEdges, useSubsurfUv, dm); + drawInteriorEdges, useSubsurfUv, dm, false); result->freeSS = 1; } @@ -4212,23 +4577,41 @@ struct DerivedMesh *subsurf_make_derived_from_derived( result = getCCGDerivedMesh(smd->mCache, drawInteriorEdges, - useSubsurfUv, dm); + useSubsurfUv, dm, false); } else { CCGFlags ccg_flags = useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS; - + CCGSubSurf *prevSS = NULL; + if (smd->mCache && (flags & SUBSURF_IS_FINAL_CALC)) { +#ifdef WITH_OPENSUBDIV + /* With OpenSubdiv enabled we always tries to re-use previos + * subsurf structure in order to save computation time since + * re-creation is rather a complicated business. + * + * TODO(sergey): There was a good eason why final calculation + * used to free entirely cached subsurf structure. reason of + * this is to be investiated still to be sure we don't have + * regressions here. + */ + prevSS = smd->mCache; +#else ccgSubSurf_free(smd->mCache); smd->mCache = NULL; +#endif } + if (flags & SUBSURF_ALLOC_PAINT_MASK) ccg_flags |= CCG_ALLOC_MASK; - ss = _getSubSurf(NULL, levels, 3, ccg_flags); + ss = _getSubSurf(prevSS, levels, 3, ccg_flags); +#ifdef WITH_OPENSUBDIV + ccgSubSurf_setSkipGrids(ss, use_gpu_backend); +#endif ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple); - result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm); + result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend); if (flags & SUBSURF_IS_FINAL_CALC) smd->mCache = ss; |