/* * ***** BEGIN GPL LICENSE BLOCK ***** * * 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. * * The Original Code is Copyright (C) 2005 Blender Foundation. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** */ /** \file blender/blenkernel/intern/subsurf_ccg.c * \ingroup bke */ #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L # ifdef __GNUC__ # pragma GCC diagnostic ignored "-Wvla" # endif # define USE_DYNSIZE #endif #include #include #include #include #include #include "atomic_ops.h" #include "MEM_guardedalloc.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BLI_utildefines.h" #include "BLI_bitmap.h" #include "BLI_blenlib.h" #include "BLI_edgehash.h" #include "BLI_math.h" #include "BLI_memarena.h" #include "BLI_threads.h" #include "BKE_pbvh.h" #include "BKE_ccg.h" #include "BKE_cdderivedmesh.h" #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_multires.h" #include "BKE_paint.h" #include "BKE_scene.h" #include "BKE_subsurf.h" #ifndef USE_DYNSIZE # include "BLI_array.h" #endif #include "GPU_draw.h" #include "GPU_glew.h" #include "GPU_buffers.h" #include "GPU_shader.h" #include "GPU_basic_shader.h" #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 static ThreadRWMutex loops_cache_rwlock = BLI_RWLOCK_INITIALIZER; static ThreadRWMutex origindex_cache_rwlock = BLI_RWLOCK_INITIALIZER; static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, int drawInteriorEdges, int useSubsurfUv, DerivedMesh *dm, bool use_gpu_backend); static int ccgDM_use_grid_pbvh(CCGDerivedMesh *ccgdm); /// static void *arena_alloc(CCGAllocatorHDL a, int numBytes) { return BLI_memarena_alloc(a, numBytes); } static void *arena_realloc(CCGAllocatorHDL a, void *ptr, int newSize, int oldSize) { void *p2 = BLI_memarena_alloc(a, newSize); if (ptr) { memcpy(p2, ptr, oldSize); } return p2; } static void arena_free(CCGAllocatorHDL UNUSED(a), void *UNUSED(ptr)) { /* do nothing */ } static void arena_release(CCGAllocatorHDL a) { BLI_memarena_free(a); } typedef enum { CCG_USE_AGING = 1, CCG_USE_ARENA = 2, CCG_CALC_NORMALS = 4, /* add an extra four bytes for a mask layer */ CCG_ALLOC_MASK = 8, CCG_SIMPLE_SUBDIV = 16 } CCGFlags; static CCGSubSurf *_getSubSurf(CCGSubSurf *prevSS, int subdivLevels, int numLayers, CCGFlags flags) { CCGMeshIFC ifc; CCGSubSurf *ccgSS; int useAging = !!(flags & CCG_USE_AGING); int useArena = flags & CCG_USE_ARENA; int normalOffset = 0; /* (subdivLevels == 0) is not allowed */ subdivLevels = MAX2(subdivLevels, 1); if (prevSS) { int oldUseAging; ccgSubSurf_getUseAgeCounts(prevSS, &oldUseAging, NULL, NULL, NULL); if ((oldUseAging != useAging) || (ccgSubSurf_getSimpleSubdiv(prevSS) != !!(flags & CCG_SIMPLE_SUBDIV))) { ccgSubSurf_free(prevSS); } else { ccgSubSurf_setSubdivisionLevels(prevSS, subdivLevels); return prevSS; } } if (useAging) { ifc.vertUserSize = ifc.edgeUserSize = ifc.faceUserSize = 12; } else { ifc.vertUserSize = ifc.edgeUserSize = ifc.faceUserSize = 8; } ifc.numLayers = numLayers; ifc.vertDataSize = sizeof(float) * numLayers; normalOffset += sizeof(float) * numLayers; if (flags & CCG_CALC_NORMALS) ifc.vertDataSize += sizeof(float) * 3; if (flags & CCG_ALLOC_MASK) ifc.vertDataSize += sizeof(float); ifc.simpleSubdiv = !!(flags & CCG_SIMPLE_SUBDIV); if (useArena) { CCGAllocatorIFC allocatorIFC; CCGAllocatorHDL allocator = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "subsurf arena"); allocatorIFC.alloc = arena_alloc; allocatorIFC.realloc = arena_realloc; allocatorIFC.free = arena_free; allocatorIFC.release = arena_release; ccgSS = ccgSubSurf_new(&ifc, subdivLevels, &allocatorIFC, allocator); } else { ccgSS = ccgSubSurf_new(&ifc, subdivLevels, NULL, NULL); } if (useAging) { ccgSubSurf_setUseAgeCounts(ccgSS, 1, 8, 8, 8); } if (flags & CCG_ALLOC_MASK) { normalOffset += sizeof(float); /* mask is allocated after regular layers */ ccgSubSurf_setAllocMask(ccgSS, 1, sizeof(float) * numLayers); } if (flags & CCG_CALC_NORMALS) ccgSubSurf_setCalcVertexNormals(ccgSS, 1, normalOffset); else ccgSubSurf_setCalcVertexNormals(ccgSS, 0, 0); return ccgSS; } static int getEdgeIndex(CCGSubSurf *ss, CCGEdge *e, int x, int edgeSize) { CCGVert *v0 = ccgSubSurf_getEdgeVert0(e); CCGVert *v1 = ccgSubSurf_getEdgeVert1(e); int v0idx = *((int *) ccgSubSurf_getVertUserData(ss, v0)); int v1idx = *((int *) ccgSubSurf_getVertUserData(ss, v1)); int edgeBase = *((int *) ccgSubSurf_getEdgeUserData(ss, e)); if (x == 0) { return v0idx; } else if (x == edgeSize - 1) { return v1idx; } else { return edgeBase + x - 1; } } static int getFaceIndex(CCGSubSurf *ss, CCGFace *f, int S, int x, int y, int edgeSize, int gridSize) { int faceBase = *((int *) ccgSubSurf_getFaceUserData(ss, f)); int numVerts = ccgSubSurf_getFaceNumVerts(f); if (x == gridSize - 1 && y == gridSize - 1) { CCGVert *v = ccgSubSurf_getFaceVert(f, S); return *((int *) ccgSubSurf_getVertUserData(ss, v)); } else if (x == gridSize - 1) { CCGVert *v = ccgSubSurf_getFaceVert(f, S); CCGEdge *e = ccgSubSurf_getFaceEdge(f, S); int edgeBase = *((int *) ccgSubSurf_getEdgeUserData(ss, e)); if (v == ccgSubSurf_getEdgeVert0(e)) { return edgeBase + (gridSize - 1 - y) - 1; } else { return edgeBase + (edgeSize - 2 - 1) - ((gridSize - 1 - y) - 1); } } else if (y == gridSize - 1) { CCGVert *v = ccgSubSurf_getFaceVert(f, S); CCGEdge *e = ccgSubSurf_getFaceEdge(f, (S + numVerts - 1) % numVerts); int edgeBase = *((int *) ccgSubSurf_getEdgeUserData(ss, e)); if (v == ccgSubSurf_getEdgeVert0(e)) { return edgeBase + (gridSize - 1 - x) - 1; } else { return edgeBase + (edgeSize - 2 - 1) - ((gridSize - 1 - x) - 1); } } else if (x == 0 && y == 0) { return faceBase; } else if (x == 0) { S = (S + numVerts - 1) % numVerts; return faceBase + 1 + (gridSize - 2) * S + (y - 1); } else if (y == 0) { return faceBase + 1 + (gridSize - 2) * S + (x - 1); } else { return faceBase + 1 + (gridSize - 2) * numVerts + S * (gridSize - 2) * (gridSize - 2) + (y - 1) * (gridSize - 2) + (x - 1); } } static void get_face_uv_map_vert(UvVertMap *vmap, struct MPoly *mpoly, struct MLoop *ml, int fi, CCGVertHDL *fverts) { UvMapVert *v, *nv; int j, nverts = mpoly[fi].totloop; for (j = 0; j < nverts; j++) { for (nv = v = BKE_mesh_uv_vert_map_get_vert(vmap, ml[j].v); v; v = v->next) { if (v->separate) nv = v; if (v->f == fi) break; } fverts[j] = SET_UINT_IN_POINTER(mpoly[nv->f].loopstart + nv->tfindex); } } static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, MLoopUV *mloopuv) { MPoly *mpoly = dm->getPolyArray(dm); MLoop *mloop = dm->getLoopArray(dm); MVert *mvert = dm->getVertArray(dm); int totvert = dm->getNumVerts(dm); int totface = dm->getNumPolys(dm); int i, seam; UvMapVert *v; UvVertMap *vmap; float limit[2]; #ifndef USE_DYNSIZE CCGVertHDL *fverts = NULL; BLI_array_declare(fverts); #endif EdgeSet *eset; float creaseFactor = (float)ccgSubSurf_getSubdivisionLevels(ss); float uv[3] = {0.0f, 0.0f, 0.0f}; /* only first 2 values are written into */ limit[0] = limit[1] = STD_UV_CONNECT_LIMIT; /* previous behavior here is without accounting for winding, however this causes stretching in * UV map in really simple cases with mirror + subsurf, see second part of T44530. Also, initially * intention is to treat merged vertices from mirror modifier as seams, see code below with ME_VERT_MERGED * This fixes a very old regression (2.49 was correct here) */ vmap = BKE_mesh_uv_vert_map_create(mpoly, mloop, mloopuv, totface, totvert, limit, false, true); if (!vmap) return 0; ccgSubSurf_initFullSync(ss); /* create vertices */ for (i = 0; i < totvert; i++) { if (!BKE_mesh_uv_vert_map_get_vert(vmap, i)) continue; for (v = BKE_mesh_uv_vert_map_get_vert(vmap, i)->next; v; v = v->next) if (v->separate) break; seam = (v != NULL) || ((mvert + i)->flag & ME_VERT_MERGED); for (v = BKE_mesh_uv_vert_map_get_vert(vmap, i); v; v = v->next) { if (v->separate) { CCGVert *ssv; int loopid = mpoly[v->f].loopstart + v->tfindex; CCGVertHDL vhdl = SET_INT_IN_POINTER(loopid); copy_v2_v2(uv, mloopuv[loopid].uv); ccgSubSurf_syncVert(ss, vhdl, uv, seam, &ssv); } } } /* create edges */ eset = BLI_edgeset_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(totface)); for (i = 0; i < totface; i++) { MPoly *mp = &mpoly[i]; int nverts = mp->totloop; int j, j_next; CCGFace *origf = ccgSubSurf_getFace(origss, SET_INT_IN_POINTER(i)); /* unsigned int *fv = &mp->v1; */ MLoop *ml = mloop + mp->loopstart; #ifdef USE_DYNSIZE CCGVertHDL fverts[nverts]; #else BLI_array_empty(fverts); BLI_array_grow_items(fverts, nverts); #endif get_face_uv_map_vert(vmap, mpoly, ml, i, fverts); for (j = 0, j_next = nverts - 1; j < nverts; j_next = j++) { unsigned int v0 = GET_UINT_FROM_POINTER(fverts[j_next]); unsigned int v1 = GET_UINT_FROM_POINTER(fverts[j]); MVert *mv0 = mvert + (ml[j_next].v); MVert *mv1 = mvert + (ml[j].v); if (BLI_edgeset_add(eset, v0, v1)) { CCGEdge *e, *orige = ccgSubSurf_getFaceEdge(origf, j_next); CCGEdgeHDL ehdl = SET_INT_IN_POINTER(mp->loopstart + j_next); float crease; if ((mv0->flag & mv1->flag) & ME_VERT_MERGED) crease = creaseFactor; else crease = ccgSubSurf_getEdgeCrease(orige); ccgSubSurf_syncEdge(ss, ehdl, fverts[j_next], fverts[j], crease, &e); } } } BLI_edgeset_free(eset); /* create faces */ for (i = 0; i < totface; i++) { MPoly *mp = &mpoly[i]; MLoop *ml = &mloop[mp->loopstart]; int nverts = mp->totloop; CCGFace *f; #ifdef USE_DYNSIZE CCGVertHDL fverts[nverts]; #else BLI_array_empty(fverts); BLI_array_grow_items(fverts, nverts); #endif get_face_uv_map_vert(vmap, mpoly, ml, i, fverts); ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), nverts, fverts, &f); } #ifndef USE_DYNSIZE BLI_array_free(fverts); #endif BKE_mesh_uv_vert_map_free(vmap); ccgSubSurf_processSync(ss); return 1; } #ifdef WITH_OPENSUBDIV static void UNUSED_FUNCTION(set_subsurf_osd_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++) { const int delta[4][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}}; float uv[4][2]; int i; for (i = 0; i < 4; i++) { const int dx = delta[i][0], dy = delta[i][1]; const float grid_u = ((float)(x + dx)) / (gridSize - 1), grid_v = ((float)(y + dy)) / (gridSize - 1); ccgSubSurf_evaluatorFVarUV(ss, index, S, grid_u, grid_v, uv[i]); } if (tf) { copy_v2_v2(tf->uv[0], uv[0]); copy_v2_v2(tf->uv[1], uv[1]); copy_v2_v2(tf->uv[2], uv[2]); copy_v2_v2(tf->uv[3], uv[3]); tf++; } if (mluv) { copy_v2_v2(mluv[0].uv, uv[0]); copy_v2_v2(mluv[1].uv, uv[1]); copy_v2_v2(mluv[2].uv, uv[2]); copy_v2_v2(mluv[3].uv, uv[3]); mluv += 4; } } } } } MEM_freeN(faceMap); } #endif /* WITH_OPENSUBDIV */ static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int n) { CCGSubSurf *uvss; CCGFace **faceMap; MTFace *tf; MLoopUV *mluv; CCGFaceIterator fi; int index, gridSize, gridFaces, /*edgeSize,*/ totface, x, y, S; MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, n); /* 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, n); MLoopUV *mloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, n); if (!dmloopuv || (!tface && !mloopuv)) return; /* create a CCGSubSurf from uv's */ uvss = _getSubSurf(NULL, ccgSubSurf_getSubdivisionLevels(ss), 2, CCG_USE_ARENA); if (!ss_sync_from_uv(uvss, ss, dm, dmloopuv)) { ccgSubSurf_free(uvss); return; } /* get some info from CCGSubSurf */ totface = ccgSubSurf_getNumFaces(uvss); /* edgeSize = ccgSubSurf_getEdgeSize(uvss); */ /*UNUSED*/ gridSize = ccgSubSurf_getGridSize(uvss); gridFaces = gridSize - 1; /* make a map from original faces to CCGFaces */ faceMap = MEM_mallocN(totface * sizeof(*faceMap), "facemapuv"); for (ccgSubSurf_initFaceIterator(uvss, &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++) { float (*faceGridData)[2] = ccgSubSurf_getFaceGridDataArray(uvss, f, S); for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { float *a = faceGridData[(y + 0) * gridSize + x + 0]; float *b = faceGridData[(y + 0) * gridSize + x + 1]; float *c = faceGridData[(y + 1) * gridSize + x + 1]; float *d = faceGridData[(y + 1) * gridSize + x + 0]; if (tf) { copy_v2_v2(tf->uv[0], a); copy_v2_v2(tf->uv[1], d); copy_v2_v2(tf->uv[2], c); copy_v2_v2(tf->uv[3], b); tf++; } if (mluv) { copy_v2_v2(mluv[0].uv, a); copy_v2_v2(mluv[1].uv, d); copy_v2_v2(mluv[2].uv, c); copy_v2_v2(mluv[3].uv, b); mluv += 4; } } } } } ccgSubSurf_free(uvss); MEM_freeN(faceMap); } static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int layer_index) { #ifdef WITH_OPENSUBDIV 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 #endif { set_subsurf_legacy_uv(ss, dm, result, layer_index); } } /* face weighting */ typedef struct FaceVertWeightEntry { FaceVertWeight *weight; float *w; int valid; } FaceVertWeightEntry; typedef struct WeightTable { FaceVertWeightEntry *weight_table; int len; } WeightTable; static float *get_ss_weights(WeightTable *wtable, int gridCuts, int faceLen) { int x, y, i, j; float *w, w1, w2, w4, fac, fac2, fx, fy; if (wtable->len <= faceLen) { void *tmp = MEM_callocN(sizeof(FaceVertWeightEntry) * (faceLen + 1), "weight table alloc 2"); if (wtable->len) { memcpy(tmp, wtable->weight_table, sizeof(FaceVertWeightEntry) * wtable->len); MEM_freeN(wtable->weight_table); } wtable->weight_table = tmp; wtable->len = faceLen + 1; } if (!wtable->weight_table[faceLen].valid) { wtable->weight_table[faceLen].valid = 1; wtable->weight_table[faceLen].w = w = MEM_callocN(sizeof(float) * faceLen * faceLen * (gridCuts + 2) * (gridCuts + 2), "weight table alloc"); fac = 1.0f / (float)faceLen; for (i = 0; i < faceLen; i++) { for (x = 0; x < gridCuts + 2; x++) { for (y = 0; y < gridCuts + 2; y++) { fx = 0.5f - (float)x / (float)(gridCuts + 1) / 2.0f; fy = 0.5f - (float)y / (float)(gridCuts + 1) / 2.0f; fac2 = faceLen - 4; w1 = (1.0f - fx) * (1.0f - fy) + (-fac2 * fx * fy * fac); w2 = (1.0f - fx + fac2 * fx * -fac) * (fy); w4 = (fx) * (1.0f - fy + -fac2 * fy * fac); /* these values aren't used for tri's and cause divide by zero */ if (faceLen > 3) { fac2 = 1.0f - (w1 + w2 + w4); fac2 = fac2 / (float)(faceLen - 3); for (j = 0; j < faceLen; j++) { w[j] = fac2; } } w[i] = w1; w[(i - 1 + faceLen) % faceLen] = w2; w[(i + 1) % faceLen] = w4; w += faceLen; } } } } return wtable->weight_table[faceLen].w; } static void free_ss_weights(WeightTable *wtable) { int i; for (i = 0; i < wtable->len; i++) { if (wtable->weight_table[i].valid) MEM_freeN(wtable->weight_table[i].w); } if (wtable->weight_table) MEM_freeN(wtable->weight_table); } 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 CCGVertHDL *fVerts = NULL; BLI_array_declare(fVerts); #endif MVert *mvert = dm->getVertArray(dm); MEdge *medge = dm->getEdgeArray(dm); /* MFace *mface = dm->getTessFaceArray(dm); */ /* UNUSED */ MVert *mv; MEdge *me; MLoop *mloop = dm->getLoopArray(dm), *ml; MPoly *mpoly = dm->getPolyArray(dm), *mp; /*MFace *mf;*/ /*UNUSED*/ int totvert = dm->getNumVerts(dm); int totedge = dm->getNumEdges(dm); /*int totface = dm->getNumTessFaces(dm);*/ /*UNUSED*/ /*int totpoly = dm->getNumFaces(dm);*/ /*UNUSED*/ int i, j; int *index; ccgSubSurf_initFullSync(ss); mv = mvert; index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX); for (i = 0; i < totvert; i++, mv++) { CCGVert *v; if (vertexCos) { ccgSubSurf_syncVert(ss, SET_INT_IN_POINTER(i), vertexCos[i], 0, &v); } else { ccgSubSurf_syncVert(ss, SET_INT_IN_POINTER(i), mv->co, 0, &v); } ((int *)ccgSubSurf_getVertUserData(ss, v))[1] = (index) ? *index++ : i; } me = medge; index = (int *)dm->getEdgeDataArray(dm, CD_ORIGINDEX); for (i = 0; i < totedge; i++, me++) { CCGEdge *e; float crease; crease = useFlatSubdiv ? creaseFactor : me->crease * creaseFactor / 255.0f; ccgSubSurf_syncEdge(ss, SET_INT_IN_POINTER(i), SET_UINT_IN_POINTER(me->v1), SET_UINT_IN_POINTER(me->v2), crease, &e); ((int *)ccgSubSurf_getEdgeUserData(ss, e))[1] = (index) ? *index++ : i; } mp = mpoly; index = (int *)dm->getPolyDataArray(dm, CD_ORIGINDEX); for (i = 0; i < dm->numPolyData; i++, mp++) { CCGFace *f; #ifdef USE_DYNSIZE CCGVertHDL fVerts[mp->totloop]; #else BLI_array_empty(fVerts); BLI_array_grow_items(fVerts, mp->totloop); #endif ml = mloop + mp->loopstart; for (j = 0; j < mp->totloop; j++, ml++) { fVerts[j] = SET_UINT_IN_POINTER(ml->v); } /* this is very bad, means mesh is internally inconsistent. * it is not really possible to continue without modifying * other parts of code significantly to handle missing faces. * since this really shouldn't even be possible we just bail.*/ if (ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), mp->totloop, fVerts, &f) == eCCGError_InvalidValue) { static int hasGivenError = 0; if (!hasGivenError) { //XXX error("Unrecoverable error in SubSurf calculation," // " mesh is inconsistent."); hasGivenError = 1; } return; } ((int *)ccgSubSurf_getFaceUserData(ss, f))[1] = (index) ? *index++ : i; } ccgSubSurf_processSync(ss); #ifndef USE_DYNSIZE BLI_array_free(fVerts); #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, bool use_subdiv_uvs) { #ifndef WITH_OPENSUBDIV UNUSED_VARS(use_subdiv_uvs); #endif #ifdef WITH_OPENSUBDIV /* Reset all related descriptors if actual mesh topology changed or if * other evaluation-related settings changed. */ if (!ccgSubSurf_needGrids(ss)) { /* TODO(sergey): Use vertex coordinates and flat subdiv flag. */ ccgSubSurf__sync_subdivUvs(ss, use_subdiv_uvs); ccgSubSurf_checkTopologyChanged(ss, dm); 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) { return ((int *) ccgSubSurf_getVertUserData(ss, v))[1]; } static int ccgDM_getEdgeMapIndex(CCGSubSurf *ss, CCGEdge *e) { return ((int *) ccgSubSurf_getEdgeUserData(ss, e))[1]; } static int ccgDM_getFaceMapIndex(CCGSubSurf *ss, CCGFace *f) { return ((int *) ccgSubSurf_getFaceUserData(ss, f))[1]; } static void minmax_v3_v3v3(const float vec[3], float min[3], float max[3]) { if (min[0] > vec[0]) min[0] = vec[0]; if (min[1] > vec[1]) min[1] = vec[1]; if (min[2] > vec[2]) min[2] = vec[2]; if (max[0] < vec[0]) max[0] = vec[0]; if (max[1] < vec[1]) max[1] = vec[1]; if (max[2] < vec[2]) max[2] = vec[2]; } static void ccgDM_getMinMax(DerivedMesh *dm, float r_min[3], float r_max[3]) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGVertIterator vi; CCGEdgeIterator ei; CCGFaceIterator fi; CCGKey key; int i, edgeSize = ccgSubSurf_getEdgeSize(ss); int gridSize = ccgSubSurf_getGridSize(ss); #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { ccgSubSurf_getMinMax(ccgdm->ss, r_min, r_max); return; } #endif CCG_key_top_level(&key, ss); if (!ccgSubSurf_getNumVerts(ss)) r_min[0] = r_min[1] = r_min[2] = r_max[0] = r_max[1] = r_max[2] = 0.0; for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) { CCGVert *v = ccgVertIterator_getCurrent(&vi); float *co = ccgSubSurf_getVertData(ss, v); minmax_v3_v3v3(co, r_min, r_max); } for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) { CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); for (i = 0; i < edgeSize; i++) minmax_v3_v3v3(CCG_elem_offset_co(&key, edgeData, i), r_min, r_max); } for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) { CCGFace *f = ccgFaceIterator_getCurrent(&fi); int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); for (S = 0; S < numVerts; S++) { CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S); for (y = 0; y < gridSize; y++) for (x = 0; x < gridSize; x++) minmax_v3_v3v3(CCG_grid_elem_co(&key, faceGridData, x, y), r_min, r_max); } } } static int ccgDM_getNumVerts(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; return ccgSubSurf_getNumFinalVerts(ccgdm->ss); } static int ccgDM_getNumEdges(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; return ccgSubSurf_getNumFinalEdges(ccgdm->ss); } static int ccgDM_getNumPolys(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; return ccgSubSurf_getNumFinalFaces(ccgdm->ss); } static int ccgDM_getNumTessFaces(DerivedMesh *dm) { return dm->numTessFaceData; } static int ccgDM_getNumLoops(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; /* All subsurf faces are quads */ return 4 * ccgSubSurf_getNumFinalFaces(ccgdm->ss); } static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGElem *vd; CCGKey key; int i; CCG_key_top_level(&key, ss); memset(mv, 0, sizeof(*mv)); if ((vertNum < ccgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumFaces(ss) > 0)) { /* this vert comes from face data */ int lastface = ccgSubSurf_getNumFaces(ss) - 1; CCGFace *f; int x, y, grid, numVerts; int offset; int gridSize = ccgSubSurf_getGridSize(ss); int gridSideVerts; int gridInternalVerts; int gridSideEnd; int gridInternalEnd; i = 0; while (i < lastface && vertNum >= ccgdm->faceMap[i + 1].startVert) { i++; } f = ccgdm->faceMap[i].face; numVerts = ccgSubSurf_getFaceNumVerts(f); gridSideVerts = gridSize - 2; gridInternalVerts = gridSideVerts * gridSideVerts; gridSideEnd = 1 + numVerts * gridSideVerts; gridInternalEnd = gridSideEnd + numVerts * gridInternalVerts; offset = vertNum - ccgdm->faceMap[i].startVert; if (offset < 1) { vd = ccgSubSurf_getFaceCenterData(f); copy_v3_v3(mv->co, CCG_elem_co(&key, vd)); normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd)); } else if (offset < gridSideEnd) { offset -= 1; grid = offset / gridSideVerts; x = offset % gridSideVerts + 1; vd = ccgSubSurf_getFaceGridEdgeData(ss, f, grid, x); copy_v3_v3(mv->co, CCG_elem_co(&key, vd)); normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd)); } else if (offset < gridInternalEnd) { offset -= gridSideEnd; grid = offset / gridInternalVerts; offset %= gridInternalVerts; y = offset / gridSideVerts + 1; x = offset % gridSideVerts + 1; vd = ccgSubSurf_getFaceGridData(ss, f, grid, x, y); copy_v3_v3(mv->co, CCG_elem_co(&key, vd)); normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd)); } } else if ((vertNum < ccgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) { /* this vert comes from edge data */ CCGEdge *e; int lastedge = ccgSubSurf_getNumEdges(ss) - 1; int x; i = 0; while (i < lastedge && vertNum >= ccgdm->edgeMap[i + 1].startVert) { i++; } e = ccgdm->edgeMap[i].edge; x = vertNum - ccgdm->edgeMap[i].startVert + 1; vd = ccgSubSurf_getEdgeData(ss, e, x); copy_v3_v3(mv->co, CCG_elem_co(&key, vd)); normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd)); } else { /* this vert comes from vert data */ CCGVert *v; i = vertNum - ccgdm->vertMap[0].startVert; v = ccgdm->vertMap[i].vert; vd = ccgSubSurf_getVertData(ss, v); copy_v3_v3(mv->co, CCG_elem_co(&key, vd)); normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd)); } } static void ccgDM_getFinalVertCo(DerivedMesh *dm, int vertNum, float r_co[3]) { MVert mvert; ccgDM_getFinalVert(dm, vertNum, &mvert); copy_v3_v3(r_co, mvert.co); } static void ccgDM_getFinalVertNo(DerivedMesh *dm, int vertNum, float r_no[3]) { MVert mvert; ccgDM_getFinalVert(dm, vertNum, &mvert); normal_short_to_float_v3(r_no, mvert.no); } static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; int i; memset(med, 0, sizeof(*med)); if (edgeNum < ccgdm->edgeMap[0].startEdge) { /* this edge comes from face data */ int lastface = ccgSubSurf_getNumFaces(ss) - 1; CCGFace *f; int x, y, grid /*, numVerts*/; int offset; int gridSize = ccgSubSurf_getGridSize(ss); int edgeSize = ccgSubSurf_getEdgeSize(ss); int gridSideEdges; int gridInternalEdges; /* code added in bmesh but works correctly without, commenting - campbell */ #if 0 int lasti, previ; i = lastface; lasti = 0; while (1) { previ = i; if (ccgdm->faceMap[i].startEdge >= edgeNum) { i -= fabsf(i - lasti) / 2.0f; } else if (ccgdm->faceMap[i].startEdge < edgeNum) { i += fabsf(i - lasti) / 2.0f; } else { break; } if (i < 0) { i = 0; break; } if (i > lastface) { i = lastface; break; } if (i == lasti) break; lasti = previ; } i = i > 0 ? i - 1 : i; #endif i = 0; while (i < lastface && edgeNum >= ccgdm->faceMap[i + 1].startEdge) { i++; } f = ccgdm->faceMap[i].face; /* numVerts = ccgSubSurf_getFaceNumVerts(f); */ /*UNUSED*/ gridSideEdges = gridSize - 1; gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2; offset = edgeNum - ccgdm->faceMap[i].startEdge; grid = offset / (gridSideEdges + gridInternalEdges); offset %= (gridSideEdges + gridInternalEdges); if (offset < gridSideEdges) { x = offset; med->v1 = getFaceIndex(ss, f, grid, x, 0, edgeSize, gridSize); med->v2 = getFaceIndex(ss, f, grid, x + 1, 0, edgeSize, gridSize); } else { offset -= gridSideEdges; x = (offset / 2) / gridSideEdges + 1; y = (offset / 2) % gridSideEdges; if (offset % 2 == 0) { med->v1 = getFaceIndex(ss, f, grid, x, y, edgeSize, gridSize); med->v2 = getFaceIndex(ss, f, grid, x, y + 1, edgeSize, gridSize); } else { med->v1 = getFaceIndex(ss, f, grid, y, x, edgeSize, gridSize); med->v2 = getFaceIndex(ss, f, grid, y + 1, x, edgeSize, gridSize); } } } else { /* this vert comes from edge data */ CCGEdge *e; int edgeSize = ccgSubSurf_getEdgeSize(ss); int x; short *edgeFlag; unsigned int flags = 0; i = (edgeNum - ccgdm->edgeMap[0].startEdge) / (edgeSize - 1); e = ccgdm->edgeMap[i].edge; if (!ccgSubSurf_getEdgeNumFaces(e)) flags |= ME_LOOSEEDGE; x = edgeNum - ccgdm->edgeMap[i].startEdge; med->v1 = getEdgeIndex(ss, e, x, edgeSize); med->v2 = getEdgeIndex(ss, e, x + 1, edgeSize); edgeFlag = (ccgdm->edgeFlags) ? &ccgdm->edgeFlags[i] : NULL; if (edgeFlag) flags |= (*edgeFlag & (ME_SEAM | ME_SHARP)) | ME_EDGEDRAW | ME_EDGERENDER; else flags |= ME_EDGEDRAW | ME_EDGERENDER; med->flag = flags; } } static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; int gridSize = ccgSubSurf_getGridSize(ss); int edgeSize = ccgSubSurf_getEdgeSize(ss); int gridSideEdges = gridSize - 1; int gridFaces = gridSideEdges * gridSideEdges; int i; CCGFace *f; /*int numVerts;*/ int offset; int grid; int x, y; /*int lastface = ccgSubSurf_getNumFaces(ss) - 1;*/ /*UNUSED*/ DMFlagMat *faceFlags = ccgdm->faceFlags; memset(mf, 0, sizeof(*mf)); if (faceNum >= ccgdm->dm.numTessFaceData) return; i = ccgdm->reverseFaceMap[faceNum]; f = ccgdm->faceMap[i].face; /*numVerts = ccgSubSurf_getFaceNumVerts(f);*/ /*UNUSED*/ offset = faceNum - ccgdm->faceMap[i].startFace; grid = offset / gridFaces; offset %= gridFaces; y = offset / gridSideEdges; x = offset % gridSideEdges; mf->v1 = getFaceIndex(ss, f, grid, x + 0, y + 0, edgeSize, gridSize); mf->v2 = getFaceIndex(ss, f, grid, x + 0, y + 1, edgeSize, gridSize); mf->v3 = getFaceIndex(ss, f, grid, x + 1, y + 1, edgeSize, gridSize); mf->v4 = getFaceIndex(ss, f, grid, x + 1, y + 0, edgeSize, gridSize); if (faceFlags) { mf->flag = faceFlags[i].flag; mf->mat_nr = faceFlags[i].mat_nr; } else { mf->flag = ME_SMOOTH; } mf->edcode = 0; } /* Translate GridHidden into the ME_HIDE flag for MVerts. Assumes * vertices are in the order output by ccgDM_copyFinalVertArray. */ void subsurf_copy_grid_hidden(DerivedMesh *dm, const MPoly *mpoly, MVert *mvert, const MDisps *mdisps) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; CCGSubSurf *ss = ccgdm->ss; int level = ccgSubSurf_getSubdivisionLevels(ss); int gridSize = ccgSubSurf_getGridSize(ss); int edgeSize = ccgSubSurf_getEdgeSize(ss); int totface = ccgSubSurf_getNumFaces(ss); int i, j, x, y; for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; for (j = 0; j < mpoly[i].totloop; j++) { const MDisps *md = &mdisps[mpoly[i].loopstart + j]; int hidden_gridsize = BKE_ccg_gridsize(md->level); int factor = BKE_ccg_factor(level, md->level); BLI_bitmap *hidden = md->hidden; if (!hidden) continue; for (y = 0; y < gridSize; y++) { for (x = 0; x < gridSize; x++) { int vndx, offset; vndx = getFaceIndex(ss, f, j, x, y, edgeSize, gridSize); offset = (y * factor) * hidden_gridsize + (x * factor); if (BLI_BITMAP_TEST(hidden, offset)) mvert[vndx].flag |= ME_HIDE; } } } } } /* Translate GridPaintMask into vertex paint masks. Assumes vertices * are in the order output by ccgDM_copyFinalVertArray. */ void subsurf_copy_grid_paint_mask(DerivedMesh *dm, const MPoly *mpoly, float *paint_mask, const GridPaintMask *grid_paint_mask) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; CCGSubSurf *ss = ccgdm->ss; int level = ccgSubSurf_getSubdivisionLevels(ss); int gridSize = ccgSubSurf_getGridSize(ss); int edgeSize = ccgSubSurf_getEdgeSize(ss); int totface = ccgSubSurf_getNumFaces(ss); int i, j, x, y, factor, gpm_gridsize; for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; const MPoly *p = &mpoly[i]; for (j = 0; j < p->totloop; j++) { const GridPaintMask *gpm = &grid_paint_mask[p->loopstart + j]; if (!gpm->data) continue; factor = BKE_ccg_factor(level, gpm->level); gpm_gridsize = BKE_ccg_gridsize(gpm->level); for (y = 0; y < gridSize; y++) { for (x = 0; x < gridSize; x++) { int vndx, offset; vndx = getFaceIndex(ss, f, j, x, y, edgeSize, gridSize); offset = y * factor * gpm_gridsize + x * factor; paint_mask[vndx] = gpm->data[offset]; } } } } } /* utility functon */ BLI_INLINE void ccgDM_to_MVert(MVert *mv, const CCGKey *key, CCGElem *elem) { copy_v3_v3(mv->co, CCG_elem_co(key, elem)); normal_float_to_short_v3(mv->no, CCG_elem_no(key, elem)); mv->flag = mv->bweight = 0; } static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGElem *vd; CCGKey key; int index; int totvert, totedge, totface; int gridSize = ccgSubSurf_getGridSize(ss); int edgeSize = ccgSubSurf_getEdgeSize(ss); unsigned int i = 0; CCG_key_top_level(&key, ss); totface = ccgSubSurf_getNumFaces(ss); for (index = 0; index < totface; index++) { CCGFace *f = ccgdm->faceMap[index].face; int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); vd = ccgSubSurf_getFaceCenterData(f); ccgDM_to_MVert(&mvert[i++], &key, vd); for (S = 0; S < numVerts; S++) { for (x = 1; x < gridSize - 1; x++) { vd = ccgSubSurf_getFaceGridEdgeData(ss, f, S, x); ccgDM_to_MVert(&mvert[i++], &key, vd); } } for (S = 0; S < numVerts; S++) { for (y = 1; y < gridSize - 1; y++) { for (x = 1; x < gridSize - 1; x++) { vd = ccgSubSurf_getFaceGridData(ss, f, S, x, y); ccgDM_to_MVert(&mvert[i++], &key, vd); } } } } totedge = ccgSubSurf_getNumEdges(ss); for (index = 0; index < totedge; index++) { CCGEdge *e = ccgdm->edgeMap[index].edge; int x; for (x = 1; x < edgeSize - 1; x++) { /* This gives errors with -debug-fpe * the normals don't seem to be unit length. * this is most likely caused by edges with no * faces which are now zerod out, see comment in: * ccgSubSurf__calcVertNormals(), - campbell */ vd = ccgSubSurf_getEdgeData(ss, e, x); ccgDM_to_MVert(&mvert[i++], &key, vd); } } totvert = ccgSubSurf_getNumVerts(ss); for (index = 0; index < totvert; index++) { CCGVert *v = ccgdm->vertMap[index].vert; vd = ccgSubSurf_getVertData(ss, v); ccgDM_to_MVert(&mvert[i++], &key, vd); } } /* utility functon */ BLI_INLINE void ccgDM_to_MEdge(MEdge *med, const int v1, const int v2, const short flag) { med->v1 = v1; med->v2 = v2; med->crease = med->bweight = 0; med->flag = flag; } static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; int index; int totedge, totface; int gridSize = ccgSubSurf_getGridSize(ss); int edgeSize = ccgSubSurf_getEdgeSize(ss); unsigned int i = 0; short *edgeFlags = ccgdm->edgeFlags; const short ed_interior_flag = ccgdm->drawInteriorEdges ? (ME_EDGEDRAW | ME_EDGERENDER) : 0; totface = ccgSubSurf_getNumFaces(ss); for (index = 0; index < totface; index++) { CCGFace *f = ccgdm->faceMap[index].face; int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); for (S = 0; S < numVerts; S++) { for (x = 0; x < gridSize - 1; x++) { ccgDM_to_MEdge(&medge[i++], getFaceIndex(ss, f, S, x, 0, edgeSize, gridSize), getFaceIndex(ss, f, S, x + 1, 0, edgeSize, gridSize), ed_interior_flag); } for (x = 1; x < gridSize - 1; x++) { for (y = 0; y < gridSize - 1; y++) { ccgDM_to_MEdge(&medge[i++], getFaceIndex(ss, f, S, x, y, edgeSize, gridSize), getFaceIndex(ss, f, S, x, y + 1, edgeSize, gridSize), ed_interior_flag); ccgDM_to_MEdge(&medge[i++], getFaceIndex(ss, f, S, y, x, edgeSize, gridSize), getFaceIndex(ss, f, S, y + 1, x, edgeSize, gridSize), ed_interior_flag); } } } } totedge = ccgSubSurf_getNumEdges(ss); for (index = 0; index < totedge; index++) { CCGEdge *e = ccgdm->edgeMap[index].edge; short ed_flag = 0; int x; int edgeIdx = GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e)); if (!ccgSubSurf_getEdgeNumFaces(e)) { ed_flag |= ME_LOOSEEDGE; } if (edgeFlags) { if (edgeIdx != -1) { ed_flag |= ((edgeFlags[index] & (ME_SEAM | ME_SHARP)) | ME_EDGEDRAW | ME_EDGERENDER); } } else { ed_flag |= ME_EDGEDRAW | ME_EDGERENDER; } for (x = 0; x < edgeSize - 1; x++) { ccgDM_to_MEdge(&medge[i++], getEdgeIndex(ss, e, x, edgeSize), getEdgeIndex(ss, e, x + 1, edgeSize), ed_flag); } } } static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; int index; int totface; int gridSize = ccgSubSurf_getGridSize(ss); int edgeSize = ccgSubSurf_getEdgeSize(ss); int i = 0; DMFlagMat *faceFlags = ccgdm->faceFlags; totface = dm->getNumTessFaces(dm); for (index = 0; index < totface; index++) { CCGFace *f = ccgdm->faceMap[index].face; int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); /* keep types in sync with MFace, avoid many conversions */ char flag = (faceFlags) ? faceFlags[index].flag : ME_SMOOTH; short mat_nr = (faceFlags) ? faceFlags[index].mat_nr : 0; for (S = 0; S < numVerts; S++) { for (y = 0; y < gridSize - 1; y++) { for (x = 0; x < gridSize - 1; x++) { MFace *mf = &mface[i]; mf->v1 = getFaceIndex(ss, f, S, x + 0, y + 0, edgeSize, gridSize); mf->v2 = getFaceIndex(ss, f, S, x + 0, y + 1, edgeSize, gridSize); mf->v3 = getFaceIndex(ss, f, S, x + 1, y + 1, edgeSize, gridSize); mf->v4 = getFaceIndex(ss, f, S, x + 1, y + 0, edgeSize, gridSize); mf->mat_nr = mat_nr; mf->flag = flag; mf->edcode = 0; i++; } } } } } static void ccgDM_copyFinalLoopArray(DerivedMesh *dm, MLoop *mloop) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; int index; int totface; int gridSize = ccgSubSurf_getGridSize(ss); int edgeSize = ccgSubSurf_getEdgeSize(ss); int i = 0; MLoop *mv; /* DMFlagMat *faceFlags = ccgdm->faceFlags; */ /* UNUSED */ if (!ccgdm->ehash) { BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_WRITE); if (!ccgdm->ehash) { MEdge *medge; ccgdm->ehash = BLI_edgehash_new_ex(__func__, ccgdm->dm.numEdgeData); medge = ccgdm->dm.getEdgeArray((DerivedMesh *)ccgdm); for (i = 0; i < ccgdm->dm.numEdgeData; i++) { BLI_edgehash_insert(ccgdm->ehash, medge[i].v1, medge[i].v2, SET_INT_IN_POINTER(i)); } } BLI_rw_mutex_unlock(&loops_cache_rwlock); } BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_READ); totface = ccgSubSurf_getNumFaces(ss); mv = mloop; for (index = 0; index < totface; index++) { CCGFace *f = ccgdm->faceMap[index].face; int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); /* int flag = (faceFlags) ? faceFlags[index * 2]: ME_SMOOTH; */ /* UNUSED */ /* int mat_nr = (faceFlags) ? faceFlags[index * 2 + 1]: 0; */ /* UNUSED */ for (S = 0; S < numVerts; S++) { for (y = 0; y < gridSize - 1; y++) { for (x = 0; x < gridSize - 1; x++) { unsigned int v1, v2, v3, v4; v1 = getFaceIndex(ss, f, S, x + 0, y + 0, edgeSize, gridSize); v2 = getFaceIndex(ss, f, S, x + 0, y + 1, edgeSize, gridSize); v3 = getFaceIndex(ss, f, S, x + 1, y + 1, edgeSize, gridSize); v4 = getFaceIndex(ss, f, S, x + 1, y + 0, edgeSize, gridSize); mv->v = v1; mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v1, v2)); mv++; i++; mv->v = v2; mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v2, v3)); mv++; i++; mv->v = v3; mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v3, v4)); mv++; i++; mv->v = v4; mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v4, v1)); mv++; i++; } } } } BLI_rw_mutex_unlock(&loops_cache_rwlock); } static void ccgDM_copyFinalPolyArray(DerivedMesh *dm, MPoly *mpoly) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; int index; int totface; int gridSize = ccgSubSurf_getGridSize(ss); /* int edgeSize = ccgSubSurf_getEdgeSize(ss); */ /* UNUSED */ int i = 0, k = 0; DMFlagMat *faceFlags = ccgdm->faceFlags; totface = ccgSubSurf_getNumFaces(ss); for (index = 0; index < totface; index++) { CCGFace *f = ccgdm->faceMap[index].face; int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); int flag = (faceFlags) ? faceFlags[index].flag : ME_SMOOTH; int mat_nr = (faceFlags) ? faceFlags[index].mat_nr : 0; for (S = 0; S < numVerts; S++) { for (y = 0; y < gridSize - 1; y++) { for (x = 0; x < gridSize - 1; x++) { MPoly *mp = &mpoly[i]; mp->mat_nr = mat_nr; mp->flag = flag; mp->loopstart = k; mp->totloop = 4; k += 4; i++; } } } } } static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; int edgeSize = ccgSubSurf_getEdgeSize(ss); int gridSize = ccgSubSurf_getGridSize(ss); int i; CCGVertIterator vi; CCGEdgeIterator ei; CCGFaceIterator fi; CCGFace **faceMap2; CCGEdge **edgeMap2; CCGVert **vertMap2; int index, totvert, totedge, totface; totvert = ccgSubSurf_getNumVerts(ss); vertMap2 = MEM_mallocN(totvert * sizeof(*vertMap2), "vertmap"); for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) { CCGVert *v = ccgVertIterator_getCurrent(&vi); vertMap2[GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v))] = v; } totedge = ccgSubSurf_getNumEdges(ss); edgeMap2 = MEM_mallocN(totedge * sizeof(*edgeMap2), "edgemap"); for (ccgSubSurf_initEdgeIterator(ss, &ei), i = 0; !ccgEdgeIterator_isStopped(&ei); i++, ccgEdgeIterator_next(&ei)) { CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); edgeMap2[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))] = e; } totface = ccgSubSurf_getNumFaces(ss); faceMap2 = MEM_mallocN(totface * sizeof(*faceMap2), "facemap"); for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) { CCGFace *f = ccgFaceIterator_getCurrent(&fi); faceMap2[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f))] = f; } i = 0; for (index = 0; index < totface; index++) { CCGFace *f = faceMap2[index]; int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); copy_v3_v3(cos[i++], ccgSubSurf_getFaceCenterData(f)); for (S = 0; S < numVerts; S++) { for (x = 1; x < gridSize - 1; x++) { copy_v3_v3(cos[i++], ccgSubSurf_getFaceGridEdgeData(ss, f, S, x)); } } for (S = 0; S < numVerts; S++) { for (y = 1; y < gridSize - 1; y++) { for (x = 1; x < gridSize - 1; x++) { copy_v3_v3(cos[i++], ccgSubSurf_getFaceGridData(ss, f, S, x, y)); } } } } for (index = 0; index < totedge; index++) { CCGEdge *e = edgeMap2[index]; int x; for (x = 1; x < edgeSize - 1; x++) { copy_v3_v3(cos[i++], ccgSubSurf_getEdgeData(ss, e, x)); } } for (index = 0; index < totvert; index++) { CCGVert *v = vertMap2[index]; copy_v3_v3(cos[i++], ccgSubSurf_getVertData(ss, v)); } MEM_freeN(vertMap2); MEM_freeN(edgeMap2); MEM_freeN(faceMap2); } static void ccgDM_foreachMappedVert( DerivedMesh *dm, void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]), void *userData, DMForeachFlag flag) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGVertIterator vi; CCGKey key; CCG_key_top_level(&key, ccgdm->ss); for (ccgSubSurf_initVertIterator(ccgdm->ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) { CCGVert *v = ccgVertIterator_getCurrent(&vi); const int index = ccgDM_getVertMapIndex(ccgdm->ss, v); if (index != -1) { CCGElem *vd = ccgSubSurf_getVertData(ccgdm->ss, v); const float *no = (flag & DM_FOREACH_USE_NORMAL) ? CCG_elem_no(&key, vd) : NULL; func(userData, index, CCG_elem_co(&key, vd), no, NULL); } } } static void ccgDM_foreachMappedEdge( DerivedMesh *dm, void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]), void *userData) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGEdgeIterator ei; CCGKey key; int i, edgeSize = ccgSubSurf_getEdgeSize(ss); CCG_key_top_level(&key, ss); for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) { CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); const int index = ccgDM_getEdgeMapIndex(ss, e); if (index != -1) { CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); for (i = 0; i < edgeSize - 1; i++) { func(userData, index, CCG_elem_offset_co(&key, edgeData, i), CCG_elem_offset_co(&key, edgeData, i + 1)); } } } } static void ccgDM_foreachMappedLoop( DerivedMesh *dm, void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]), void *userData, DMForeachFlag flag) { /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would * return loop data from bmesh itself. */ const float (*lnors)[3] = (flag & DM_FOREACH_USE_NORMAL) ? DM_get_loop_data_layer(dm, CD_NORMAL) : NULL; MVert *mv = dm->getVertArray(dm); MLoop *ml = dm->getLoopArray(dm); MPoly *mp = dm->getPolyArray(dm); const int *v_index = dm->getVertDataArray(dm, CD_ORIGINDEX); const int *f_index = dm->getPolyDataArray(dm, CD_ORIGINDEX); int p_idx, i; for (p_idx = 0; p_idx < dm->numPolyData; ++p_idx, ++mp) { for (i = 0; i < mp->totloop; ++i, ++ml) { const int v_idx = v_index ? v_index[ml->v] : ml->v; const int f_idx = f_index ? f_index[p_idx] : p_idx; const float *no = lnors ? *lnors++ : NULL; if (!ELEM(ORIGINDEX_NONE, v_idx, f_idx)) { func(userData, v_idx, f_idx, mv[ml->v].co, no); } } } } static void ccgDM_drawVerts(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; int edgeSize = ccgSubSurf_getEdgeSize(ss); int gridSize = ccgSubSurf_getGridSize(ss); CCGVertIterator vi; CCGEdgeIterator ei; CCGFaceIterator fi; glBegin(GL_POINTS); for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) { CCGVert *v = ccgVertIterator_getCurrent(&vi); glVertex3fv(ccgSubSurf_getVertData(ss, v)); } for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) { CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); int x; for (x = 1; x < edgeSize - 1; x++) glVertex3fv(ccgSubSurf_getEdgeData(ss, e, x)); } for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) { CCGFace *f = ccgFaceIterator_getCurrent(&fi); int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); glVertex3fv(ccgSubSurf_getFaceCenterData(f)); for (S = 0; S < numVerts; S++) for (x = 1; x < gridSize - 1; x++) glVertex3fv(ccgSubSurf_getFaceGridEdgeData(ss, f, S, x)); for (S = 0; S < numVerts; S++) for (y = 1; y < gridSize - 1; y++) for (x = 1; x < gridSize - 1; x++) glVertex3fv(ccgSubSurf_getFaceGridData(ss, f, S, x, y)); } glEnd(); } static void ccgdm_pbvh_update(CCGDerivedMesh *ccgdm) { if (ccgdm->pbvh && ccgDM_use_grid_pbvh(ccgdm)) { CCGFace **faces; int totface; BKE_pbvh_get_grid_updates(ccgdm->pbvh, 1, (void ***)&faces, &totface); if (totface) { ccgSubSurf_updateFromFaces(ccgdm->ss, 0, faces, totface); ccgSubSurf_updateNormals(ccgdm->ss, faces, totface); MEM_freeN(faces); } } } static void ccgDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges) { GPUDrawObject *gdo; CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { /* TODO(sergey): We currently only support all edges drawing. */ if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) { ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1); } return; } #endif ccgdm_pbvh_update(ccgdm); /* old debug feature for edges, unsupported for now */ #if 0 int useAging = 0; if (!(G.f & G_BACKBUFSEL)) { CCGSubSurf *ss = ccgdm->ss; ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL); /* it needs some way to upload this to VBO now */ if (useAging) { int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4; glColor3ub(0, ageCol > 0 ? ageCol : 0, 0); } } #endif GPU_edge_setup(dm); gdo = dm->drawObject; if (gdo->edges && gdo->points) { if (drawAllEdges && drawLooseEdges) { GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, (gdo->totedge - gdo->totinterior) * 2); } else if (drawAllEdges) { GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->loose_edge_offset * 2); } else { GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->tot_edge_drawn * 2); GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->loose_edge_offset * 2, gdo->tot_loose_edge_drawn * 2); } } if (gdo->edges && ccgdm->drawInteriorEdges) { GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->interior_offset * 2, gdo->totinterior * 2); } GPU_buffers_unbind(); } static void ccgDM_drawLooseEdges(DerivedMesh *dm) { int start; int count; #ifdef WITH_OPENSUBDIV CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; if (ccgdm->useGpuBackend) { /* TODO(sergey): Needs implementation. */ return; } #endif GPU_edge_setup(dm); start = (dm->drawObject->loose_edge_offset * 2); count = (dm->drawObject->interior_offset - dm->drawObject->loose_edge_offset) * 2; if (count) { GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, start, count); } GPU_buffers_unbind(); } static void ccgDM_NormalFast(float *a, float *b, float *c, float *d, float no[3]) { float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2]; float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2]; no[0] = b_dY * a_cZ - b_dZ * a_cY; no[1] = b_dZ * a_cX - b_dX * a_cZ; no[2] = b_dX * a_cY - b_dY * a_cX; normalize_v3(no); } static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d) { float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2]; float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2]; float no[3]; no[0] = b_dY * a_cZ - b_dZ * a_cY; no[1] = b_dZ * a_cX - b_dX * a_cZ; no[2] = b_dX * a_cY - b_dY * a_cX; /* don't normalize, GL_NORMALIZE is enabled */ glNormal3fv(no); } /* Only used by non-editmesh types */ static void ccgDM_buffer_copy_normal( DerivedMesh *dm, short *varray) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); int gridSize = ccgSubSurf_getGridSize(ss); int gridFaces = gridSize - 1; DMFlagMat *faceFlags = ccgdm->faceFlags; int i, totface = ccgSubSurf_getNumFaces(ss); int shademodel; int start = 0; /* we are in sculpt mode, disable loop normals (since they won't get updated) */ if (ccgdm->pbvh) lnors = NULL; CCG_key_top_level(&key, ss); for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); const float (*ln)[3] = NULL; if (faceFlags) { shademodel = (lnors || (faceFlags[index].flag & ME_SMOOTH)) ? GL_SMOOTH : GL_FLAT; } else { shademodel = GL_SMOOTH; } if (lnors) { ln = lnors; lnors += gridFaces * gridFaces * numVerts * 4; } for (S = 0; S < numVerts; S++) { CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S); if (ln) { /* Can't use quad strips here... */ for (y = 0; y < gridFaces; y ++) { for (x = 0; x < gridFaces; x ++) { normal_float_to_short_v3(&varray[start + 0], ln[0]); normal_float_to_short_v3(&varray[start + 4], ln[3]); normal_float_to_short_v3(&varray[start + 8], ln[2]); normal_float_to_short_v3(&varray[start + 12], ln[1]); start += 16; ln += 4; } } } else if (shademodel == GL_SMOOTH) { for (y = 0; y < gridFaces; y ++) { for (x = 0; x < gridFaces; x ++) { float *a = CCG_grid_elem_no(&key, faceGridData, x, y ); float *b = CCG_grid_elem_no(&key, faceGridData, x + 1, y); float *c = CCG_grid_elem_no(&key, faceGridData, x + 1, y + 1); float *d = CCG_grid_elem_no(&key, faceGridData, x, y + 1); normal_float_to_short_v3(&varray[start], a); normal_float_to_short_v3(&varray[start + 4], b); normal_float_to_short_v3(&varray[start + 8], c); normal_float_to_short_v3(&varray[start + 12], d); start += 16; } } } else { for (y = 0; y < gridFaces; y ++) { for (x = 0; x < gridFaces; x ++) { float f_no[3]; short f_no_s[3]; float *a = CCG_grid_elem_co(&key, faceGridData, x, y ); float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y ); float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1); ccgDM_NormalFast(a, b, c, d, f_no); normal_float_to_short_v3(f_no_s, f_no); copy_v3_v3_short(&varray[start], f_no_s); copy_v3_v3_short(&varray[start + 4], f_no_s); copy_v3_v3_short(&varray[start + 8], f_no_s); copy_v3_v3_short(&varray[start + 12], f_no_s); start += 16; } } } } } } typedef struct FaceCount { unsigned int i_visible; unsigned int i_hidden; unsigned int i_tri_visible; unsigned int i_tri_hidden; } FaceCount; /* Only used by non-editmesh types */ static void ccgDM_buffer_copy_triangles( DerivedMesh *dm, unsigned int *varray, const int *mat_orig_to_new) { GPUBufferMaterial *gpumat, *gpumaterials = dm->drawObject->materials; const int gpu_totmat = dm->drawObject->totmaterial; const short dm_totmat = dm->totmat; CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; int gridSize = ccgSubSurf_getGridSize(ss); int gridFaces = gridSize - 1; DMFlagMat *faceFlags = ccgdm->faceFlags; int i, totface = ccgSubSurf_getNumFaces(ss); short mat_nr = -1; int start; int totloops = 0; FaceCount *fc = MEM_mallocN(sizeof(*fc) * gpu_totmat, "gpumaterial.facecount"); CCG_key_top_level(&key, ss); for (i = 0; i < gpu_totmat; i++) { fc[i].i_visible = 0; fc[i].i_tri_visible = 0; fc[i].i_hidden = gpumaterials[i].totpolys - 1; fc[i].i_tri_hidden = gpumaterials[i].totelements - 1; } for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); bool is_hidden; int mati; if (faceFlags) { mat_nr = ME_MAT_NR_TEST(faceFlags[index].mat_nr, dm_totmat); is_hidden = (faceFlags[index].flag & ME_HIDE) != 0; } else { mat_nr = 0; is_hidden = false; } mati = mat_orig_to_new[mat_nr]; gpumat = dm->drawObject->materials + mati; if (is_hidden) { for (S = 0; S < numVerts; S++) { for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { start = gpumat->start + fc[mati].i_tri_hidden; varray[start--] = totloops; varray[start--] = totloops + 2; varray[start--] = totloops + 3; varray[start--] = totloops; varray[start--] = totloops + 1; varray[start--] = totloops + 2; fc[mati].i_tri_hidden -= 6; totloops += 4; } } } gpumat->polys[fc[mati].i_hidden--] = i; } else { for (S = 0; S < numVerts; S++) { for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { start = gpumat->start + fc[mati].i_tri_visible; varray[start++] = totloops + 3; varray[start++] = totloops + 2; varray[start++] = totloops; varray[start++] = totloops + 2; varray[start++] = totloops + 1; varray[start++] = totloops; fc[mati].i_tri_visible += 6; totloops += 4; } } } gpumat->polys[fc[mati].i_visible++] = i; } } /* set the visible polygons */ for (i = 0; i < gpu_totmat; i++) { gpumaterials[i].totvisiblepolys = fc[i].i_visible; } MEM_freeN(fc); } /* Only used by non-editmesh types */ static void ccgDM_buffer_copy_vertex( DerivedMesh *dm, void *varray_p) { float *varray = varray_p; CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; int gridSize = ccgSubSurf_getGridSize(ss); int gridFaces = gridSize - 1; int i, totface = ccgSubSurf_getNumFaces(ss); int totedge = ccgSubSurf_getNumEdges(ss); int start = 0; int edgeSize = ccgSubSurf_getEdgeSize(ss); CCG_key_top_level(&key, ss); for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); for (S = 0; S < numVerts; S++) { CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S); for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { float *a = CCG_grid_elem_co(&key, faceGridData, x, y); float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y); float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1); copy_v3_v3(&varray[start], a); copy_v3_v3(&varray[start + 3], b); copy_v3_v3(&varray[start + 6], c); copy_v3_v3(&varray[start + 9], d); start += 12; } } } } /* upload loose points */ for (i = 0; i < totedge; i++) { CCGEdge *e = ccgdm->edgeMap[i].edge; CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); if (!ccgSubSurf_getEdgeNumFaces(e)) { int j = 0; for (j = 0; j < edgeSize; j++) { copy_v3_v3(&varray[start], CCG_elem_offset_co(&key, edgeData, j)); start += 3; } } } } /* Only used by non-editmesh types */ static void ccgDM_buffer_copy_color( DerivedMesh *dm, unsigned char *varray, const void *user_data) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; const unsigned char *mloopcol = user_data; int gridSize = ccgSubSurf_getGridSize(ss); int gridFaces = gridSize - 1; int i, totface = ccgSubSurf_getNumFaces(ss); int start = 0; int iface = 0; CCG_key_top_level(&key, ss); for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); for (S = 0; S < numVerts; S++) { for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { copy_v3_v3_uchar(&varray[start + 0], &mloopcol[iface * 16 + 0]); copy_v3_v3_uchar(&varray[start + 3], &mloopcol[iface * 16 + 12]); copy_v3_v3_uchar(&varray[start + 6], &mloopcol[iface * 16 + 8]); copy_v3_v3_uchar(&varray[start + 9], &mloopcol[iface * 16 + 4]); start += 12; iface++; } } } } } static void ccgDM_buffer_copy_uv( DerivedMesh *dm, void *varray_p) { float *varray = varray_p; CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; MLoopUV *mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV); int gridSize = ccgSubSurf_getGridSize(ss); int gridFaces = gridSize - 1; int i, totface = ccgSubSurf_getNumFaces(ss); int start = 0; CCG_key_top_level(&key, ss); for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); for (S = 0; S < numVerts; S++) { for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { copy_v2_v2(&varray[start + 0], mloopuv[0].uv); copy_v2_v2(&varray[start + 2], mloopuv[3].uv); copy_v2_v2(&varray[start + 4], mloopuv[2].uv); copy_v2_v2(&varray[start + 6], mloopuv[1].uv); mloopuv += 4; start += 8; } } } } } static void ccgDM_buffer_copy_uv_texpaint( DerivedMesh *dm, float *varray) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; int gridSize = ccgSubSurf_getGridSize(ss); int gridFaces = gridSize - 1; int i, totface = ccgSubSurf_getNumFaces(ss); int start = 0; DMFlagMat *faceFlags = ccgdm->faceFlags; int dm_totmat = dm->totmat; MLoopUV **mloopuv_base; MLoopUV *stencil_base; int stencil; CCG_key_top_level(&key, ss); /* should have been checked for before, reassert */ BLI_assert(DM_get_loop_data_layer(dm, CD_MLOOPUV)); mloopuv_base = MEM_mallocN(dm_totmat * sizeof(*mloopuv_base), "texslots"); for (i = 0; i < dm_totmat; i++) { mloopuv_base[i] = DM_paint_uvlayer_active_get(dm, i); } stencil = CustomData_get_stencil_layer(&dm->loopData, CD_MLOOPUV); stencil_base = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, stencil); start = 0; for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); int matnr; if (faceFlags) { matnr = faceFlags[index].mat_nr; } else { matnr = 0; } for (S = 0; S < numVerts; S++) { for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { /* divide by 4, gives us current loop-index */ unsigned int i_ml = start / 4; copy_v2_v2(&varray[start + 0], mloopuv_base[matnr][i_ml + 0].uv); copy_v2_v2(&varray[start + 2], stencil_base[i_ml + 0].uv); copy_v2_v2(&varray[start + 4], mloopuv_base[matnr][i_ml + 3].uv); copy_v2_v2(&varray[start + 6], stencil_base[i_ml + 3].uv); copy_v2_v2(&varray[start + 8], mloopuv_base[matnr][i_ml + 2].uv); copy_v2_v2(&varray[start + 10], stencil_base[i_ml + 2].uv); copy_v2_v2(&varray[start + 12], mloopuv_base[matnr][i_ml + 1].uv); copy_v2_v2(&varray[start + 14], stencil_base[i_ml + 1].uv); start += 16; } } } } MEM_freeN(mloopuv_base); } static void ccgDM_buffer_copy_uvedge( DerivedMesh *dm, float *varray) { int i, totpoly; int start; const MLoopUV *mloopuv; #ifndef USE_LOOP_LAYOUT_FAST const MPoly *mpoly = dm->getPolyArray(dm); #endif if ((mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV)) == NULL) { return; } totpoly = dm->getNumPolys(dm); start = 0; #ifndef USE_LOOP_LAYOUT_FAST for (i = 0; i < totpoly; i++, mpoly++) { for (j = 0; j < mpoly->totloop; j++) { copy_v2_v2(&varray[start], mloopuv[mpoly->loopstart + j].uv); copy_v2_v2(&varray[start + 2], mloopuv[mpoly->loopstart + (j + 1) % mpoly->totloop].uv); start += 4; } } #else for (i = 0; i < totpoly; i++) { copy_v2_v2(&varray[start + 0], mloopuv[(i * 4) + 0].uv); copy_v2_v2(&varray[start + 2], mloopuv[(i * 4) + 1].uv); copy_v2_v2(&varray[start + 4], mloopuv[(i * 4) + 1].uv); copy_v2_v2(&varray[start + 6], mloopuv[(i * 4) + 2].uv); copy_v2_v2(&varray[start + 8], mloopuv[(i * 4) + 2].uv); copy_v2_v2(&varray[start + 10], mloopuv[(i * 4) + 3].uv); copy_v2_v2(&varray[start + 12], mloopuv[(i * 4) + 3].uv); copy_v2_v2(&varray[start + 14], mloopuv[(i * 4) + 0].uv); start += 16; } #endif } static void ccgDM_buffer_copy_edge( DerivedMesh *dm, unsigned int *varray) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; /* getEdgeSuze returns num of verts, edges is one less */ int i, j, edgeSize = ccgSubSurf_getEdgeSize(ss) - 1; int totedge = ccgSubSurf_getNumEdges(ss); int grid_face_side = ccgSubSurf_getGridSize(ss) - 1; int totface = ccgSubSurf_getNumFaces(ss); unsigned int index_start; unsigned int tot_interior = 0; unsigned int grid_tot_face = grid_face_side * grid_face_side; unsigned int iloose, inorm, iloosehidden, inormhidden; unsigned int tot_loose_hidden = 0, tot_loose = 0; unsigned int tot_hidden = 0, tot = 0; unsigned int iloosevert; /* int tot_interior = 0; */ /* first, handle hidden/loose existing edges, then interior edges */ for (j = 0; j < totedge; j++) { CCGEdge *e = ccgdm->edgeMap[j].edge; if (ccgdm->edgeFlags && !(ccgdm->edgeFlags[j] & ME_EDGEDRAW)) { if (!ccgSubSurf_getEdgeNumFaces(e)) tot_loose_hidden++; else tot_hidden++; } else { if (!ccgSubSurf_getEdgeNumFaces(e)) tot_loose++; else tot++; } } inorm = 0; inormhidden = tot * edgeSize; iloose = (tot + tot_hidden) * edgeSize; iloosehidden = (tot + tot_hidden + tot_loose) * edgeSize; iloosevert = dm->drawObject->tot_loop_verts; /* part one, handle all normal edges */ for (j = 0; j < totedge; j++) { CCGFace *f; int fhandle = 0; int totvert = 0; unsigned int S = 0; CCGEdge *e = ccgdm->edgeMap[j].edge; bool isloose = !ccgSubSurf_getEdgeNumFaces(e); if (!isloose) { CCGVert *v1, *v2; CCGVert *ev1 = ccgSubSurf_getEdgeVert0(e); CCGVert *ev2 = ccgSubSurf_getEdgeVert1(e); f = ccgSubSurf_getEdgeFace(e, 0); fhandle = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); totvert = ccgSubSurf_getFaceNumVerts(f); /* find the index of vertices in the face */ for (i = 0; i < totvert; i++) { v1 = ccgSubSurf_getFaceVert(f, i); v2 = ccgSubSurf_getFaceVert(f, (i + 1) % totvert); if ((ev1 == v1 && ev2 == v2) || (ev1 == v2 && ev2 == v1)) { S = i; break; } } } if (ccgdm->edgeFlags && !(ccgdm->edgeFlags[j] & ME_EDGEDRAW)) { if (isloose) { for (i = 0; i < edgeSize; i++) { varray[iloosehidden * 2] = iloosevert; varray[iloosehidden * 2 + 1] = iloosevert + 1; iloosehidden++; iloosevert++; } /* we are through with this loose edge and moving to the next, so increase by one */ iloosevert++; } else { index_start = ccgdm->faceMap[fhandle].startFace; for (i = 0; i < grid_face_side; i++) { varray[inormhidden * 2] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 1; varray[inormhidden * 2 + 1] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 2; varray[inormhidden * 2 + 2] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 2; varray[inormhidden * 2 + 3] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 3; inormhidden += 2; } } } else { if (isloose) { for (i = 0; i < edgeSize; i++) { varray[iloose * 2] = iloosevert; varray[iloose * 2 + 1] = iloosevert + 1; iloose++; iloosevert++; } /* we are through with this loose edge and moving to the next, so increase by one */ iloosevert++; } else { index_start = ccgdm->faceMap[fhandle].startFace; for (i = 0; i < grid_face_side; i++) { varray[inorm * 2] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 1; varray[inorm * 2 + 1] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 2; varray[inorm * 2 + 2] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 2; varray[inorm * 2 + 3] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 3; inorm += 2; } } } } /* part two, handle interior edges */ inorm = totedge * grid_face_side * 2; index_start = 0; for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; unsigned int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); for (S = 0; S < numVerts; S++) { for (x = 1; x < grid_face_side; x++) { for (y = 0; y < grid_face_side; y++) { unsigned int tmp = (index_start + x * grid_face_side + y) * 4; varray[inorm * 2] = tmp; varray[inorm * 2 + 1] = tmp + 1; inorm++; } } for (x = 0; x < grid_face_side; x++) { for (y = 0; y < grid_face_side; y++) { unsigned int tmp = (index_start + x * grid_face_side + y) * 4; varray[inorm * 2] = tmp + 3; varray[inorm * 2 + 1] = tmp; inorm++; } } tot_interior += grid_face_side * (2 * grid_face_side - 1); index_start += grid_tot_face; } } dm->drawObject->tot_loose_edge_drawn = tot_loose * edgeSize; dm->drawObject->loose_edge_offset = (tot + tot_hidden) * edgeSize; dm->drawObject->tot_edge_drawn = tot * edgeSize; dm->drawObject->interior_offset = totedge * edgeSize; dm->drawObject->totinterior = tot_interior; } static void ccgDM_copy_gpu_data( DerivedMesh *dm, int type, void *varray_p, const int *mat_orig_to_new, const void *user_data) { /* 'varray_p' cast is redundant but include for self-documentation */ switch (type) { case GPU_BUFFER_VERTEX: ccgDM_buffer_copy_vertex(dm, (float *)varray_p); break; case GPU_BUFFER_NORMAL: ccgDM_buffer_copy_normal(dm, (short *)varray_p); break; case GPU_BUFFER_UV: ccgDM_buffer_copy_uv(dm, (float *)varray_p); break; case GPU_BUFFER_UV_TEXPAINT: ccgDM_buffer_copy_uv_texpaint(dm, (float *)varray_p); break; case GPU_BUFFER_COLOR: ccgDM_buffer_copy_color(dm, (unsigned char *)varray_p, user_data); break; case GPU_BUFFER_UVEDGE: ccgDM_buffer_copy_uvedge(dm, (float *)varray_p); break; case GPU_BUFFER_EDGE: ccgDM_buffer_copy_edge(dm, (unsigned int *)varray_p); break; case GPU_BUFFER_TRIANGLES: ccgDM_buffer_copy_triangles(dm, (unsigned int *)varray_p, mat_orig_to_new); break; default: break; } } static GPUDrawObject *ccgDM_GPUObjectNew(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; GPUDrawObject *gdo; DMFlagMat *faceFlags = ccgdm->faceFlags; int gridFaces = ccgSubSurf_getGridSize(ss) - 1; const short dm_totmat = (faceFlags) ? dm->totmat : 1; GPUBufferMaterial *matinfo; int i; unsigned int tot_internal_edges = 0; int edgeVerts = ccgSubSurf_getEdgeSize(ss); int edgeSize = edgeVerts - 1; int totedge = ccgSubSurf_getNumEdges(ss); int totface = ccgSubSurf_getNumFaces(ss); /* object contains at least one material (default included) so zero means uninitialized dm */ BLI_assert(dm_totmat != 0); matinfo = MEM_callocN(sizeof(*matinfo) * dm_totmat, "GPU_drawobject_new.mat_orig_to_new"); if (faceFlags) { for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; int numVerts = ccgSubSurf_getFaceNumVerts(f); int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); const short new_matnr = ME_MAT_NR_TEST(faceFlags[index].mat_nr, dm_totmat); matinfo[new_matnr].totelements += numVerts * gridFaces * gridFaces * 6; matinfo[new_matnr].totloops += numVerts * gridFaces * gridFaces * 4; matinfo[new_matnr].totpolys++; tot_internal_edges += numVerts * gridFaces * (2 * gridFaces - 1); } } else { for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; int numVerts = ccgSubSurf_getFaceNumVerts(f); matinfo[0].totelements += numVerts * gridFaces * gridFaces * 6; matinfo[0].totloops += numVerts * gridFaces * gridFaces * 4; matinfo[0].totpolys++; tot_internal_edges += numVerts * gridFaces * (2 * gridFaces - 1); } } /* create the GPUDrawObject */ gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject"); gdo->totvert = 0; /* used to count indices, doesn't really matter for ccgsubsurf */ gdo->totedge = (totedge * edgeSize + tot_internal_edges); GPU_buffer_material_finalize(gdo, matinfo, dm_totmat); /* store total number of points used for triangles */ gdo->tot_triangle_point = ccgSubSurf_getNumFinalFaces(ss) * 6; gdo->tot_loop_verts = ccgSubSurf_getNumFinalFaces(ss) * 4; /* finally, count loose points */ for (i = 0; i < totedge; i++) { CCGEdge *e = ccgdm->edgeMap[i].edge; if (!ccgSubSurf_getEdgeNumFaces(e)) gdo->tot_loose_point += edgeVerts; } return gdo; } /* Only used by non-editmesh types */ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)[4], bool fast, DMSetMaterial setMaterial) { int a; CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; ccgdm_pbvh_update(ccgdm); if (ccgdm->pbvh && ccgdm->multires.mmd) { if (BKE_pbvh_has_faces(ccgdm->pbvh)) { BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL, setMaterial, false, fast); } return; } #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { CCGSubSurf *ss = ccgdm->ss; const DMFlagMat *faceFlags = ccgdm->faceFlags; const int level = ccgSubSurf_getSubdivisionLevels(ss); const int face_side = 1 << level; const int grid_side = 1 << (level - 1); const int face_patches = face_side * face_side; const int grid_patches = grid_side * grid_side; const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss); int i, current_patch = 0; int mat_nr = -1; bool draw_smooth = false; int start_draw_patch = -1, num_draw_patches = 0; if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL, -1) == false)) { return; } if (setMaterial == NULL) { ccgSubSurf_drawGLMesh(ss, true, -1, -1); return; } for (i = 0; i < num_base_faces; ++i) { const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i); const int num_patches = (num_face_verts == 4) ? face_patches : num_face_verts * grid_patches; int new_matnr; bool new_draw_smooth; if (faceFlags) { new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH); new_matnr = (faceFlags[i].mat_nr + 1); } else { new_draw_smooth = true; new_matnr = 1; } if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) { if (num_draw_patches != 0) { bool do_draw = setMaterial(mat_nr, NULL); if (do_draw) { glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); ccgSubSurf_drawGLMesh(ss, true, start_draw_patch, num_draw_patches); } } start_draw_patch = current_patch; num_draw_patches = num_patches; mat_nr = new_matnr; draw_smooth = new_draw_smooth; } else { num_draw_patches += num_patches; } current_patch += num_patches; } if (num_draw_patches != 0) { bool do_draw = setMaterial(mat_nr, NULL); if (do_draw) { glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); ccgSubSurf_drawGLMesh(ss, true, start_draw_patch, num_draw_patches); } } glShadeModel(GL_SMOOTH); return; } #endif GPU_vertex_setup(dm); GPU_normal_setup(dm); GPU_triangle_setup(dm); for (a = 0; a < dm->drawObject->totmaterial; a++) { if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) { GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements); } } GPU_buffers_unbind(); } typedef struct { DMVertexAttribs attribs; int numdata; GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/ } GPUMaterialConv; /* Only used by non-editmesh types */ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial, DMSetDrawOptions setDrawOptions, void *userData) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; GPUVertexAttribs gattribs; int a, b; const DMFlagMat *faceFlags = ccgdm->faceFlags; unsigned char *varray; size_t max_element_size = 0; int tot_loops = 0; int totpoly = ccgSubSurf_getNumFaces(ss); int gridSize = ccgSubSurf_getGridSize(ss); int gridFaces = gridSize - 1; int edgeSize = ccgSubSurf_getEdgeSize(ss); #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { const int level = ccgSubSurf_getSubdivisionLevels(ss); const int face_side = 1 << level; const int grid_side = 1 << (level - 1); const int face_patches = face_side * face_side; const int grid_patches = grid_side * grid_side; const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss); int i, current_patch = 0; int mat_nr = -1; bool draw_smooth = false; int start_draw_patch = -1, num_draw_patches = 0; GPU_draw_update_fvar_offset(dm); if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, false, -1) == false)) { return; } for (i = 0; i < num_base_faces; ++i) { const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i); const int num_patches = (num_face_verts == 4) ? face_patches : num_face_verts * grid_patches; int new_matnr; bool new_draw_smooth; if (faceFlags) { new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH); new_matnr = (faceFlags[i].mat_nr + 1); } else { new_draw_smooth = true; new_matnr = 1; } if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) { if (num_draw_patches != 0) { bool do_draw = setMaterial(mat_nr, &gattribs); if (do_draw) { glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); ccgSubSurf_drawGLMesh(ss, true, start_draw_patch, num_draw_patches); } } start_draw_patch = current_patch; num_draw_patches = num_patches; mat_nr = new_matnr; draw_smooth = new_draw_smooth; } else { num_draw_patches += num_patches; } current_patch += num_patches; } if (num_draw_patches != 0) { bool do_draw = setMaterial(mat_nr, &gattribs); if (do_draw) { glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); ccgSubSurf_drawGLMesh(ss, true, start_draw_patch, num_draw_patches); } } glShadeModel(GL_SMOOTH); return; } #endif CCG_key_top_level(&key, ss); ccgdm_pbvh_update(ccgdm); if (setDrawOptions != NULL) { const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); DMVertexAttribs attribs = {{{NULL}}}; int i; int matnr = -1; int do_draw = 0; #define PASSATTRIB(dx, dy, vert) { \ if (attribs.totorco) \ index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \ else \ index = 0; \ DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \ DM_draw_attrib_vertex_uniforms(&attribs); \ } (void)0 totpoly = ccgSubSurf_getNumFaces(ss); for (a = 0, i = 0; i < totpoly; i++) { CCGFace *f = ccgdm->faceMap[i].face; const float (*ln)[3] = NULL; int S, x, y, drawSmooth; int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); int origIndex = ccgDM_getFaceMapIndex(ss, f); int numVerts = ccgSubSurf_getFaceNumVerts(f); int new_matnr; if (faceFlags) { drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH)); new_matnr = faceFlags[index].mat_nr + 1; } else { drawSmooth = 1; new_matnr = 1; } if (lnors) { ln = lnors; lnors += (gridFaces * gridFaces * numVerts) * 4; } if (new_matnr != matnr) { do_draw = setMaterial(matnr = new_matnr, &gattribs); if (do_draw) DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); } if (!do_draw || (setDrawOptions && (origIndex != ORIGINDEX_NONE) && (setDrawOptions(userData, origIndex) == DM_DRAW_OPTION_SKIP))) { a += gridFaces * gridFaces * numVerts; continue; } glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT); for (S = 0; S < numVerts; S++) { CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S); CCGElem *vda, *vdb; if (ln) { glBegin(GL_QUADS); for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { float *aco = CCG_grid_elem_co(&key, faceGridData, x, y); float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y); float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1); PASSATTRIB(0, 1, 1); glNormal3fv(ln[1]); glVertex3fv(dco); PASSATTRIB(1, 1, 2); glNormal3fv(ln[2]); glVertex3fv(cco); PASSATTRIB(1, 0, 3); glNormal3fv(ln[3]); glVertex3fv(bco); PASSATTRIB(0, 0, 0); glNormal3fv(ln[0]); glVertex3fv(aco); ln += 4; a++; } } glEnd(); } else if (drawSmooth) { for (y = 0; y < gridFaces; y++) { glBegin(GL_QUAD_STRIP); for (x = 0; x < gridFaces; x++) { vda = CCG_grid_elem(&key, faceGridData, x, y + 0); vdb = CCG_grid_elem(&key, faceGridData, x, y + 1); PASSATTRIB(0, 0, 0); glNormal3fv(CCG_elem_no(&key, vda)); glVertex3fv(CCG_elem_co(&key, vda)); PASSATTRIB(0, 1, 1); glNormal3fv(CCG_elem_no(&key, vdb)); glVertex3fv(CCG_elem_co(&key, vdb)); if (x != gridFaces - 1) a++; } vda = CCG_grid_elem(&key, faceGridData, x, y + 0); vdb = CCG_grid_elem(&key, faceGridData, x, y + 1); PASSATTRIB(0, 0, 3); glNormal3fv(CCG_elem_no(&key, vda)); glVertex3fv(CCG_elem_co(&key, vda)); PASSATTRIB(0, 1, 2); glNormal3fv(CCG_elem_no(&key, vdb)); glVertex3fv(CCG_elem_co(&key, vdb)); glEnd(); a++; } } else { glBegin(GL_QUADS); for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { float *aco = CCG_grid_elem_co(&key, faceGridData, x, y); float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y); float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1); ccgDM_glNormalFast(aco, bco, cco, dco); PASSATTRIB(0, 1, 1); glVertex3fv(dco); PASSATTRIB(1, 1, 2); glVertex3fv(cco); PASSATTRIB(1, 0, 3); glVertex3fv(bco); PASSATTRIB(0, 0, 0); glVertex3fv(aco); a++; } } glEnd(); } } } glShadeModel(GL_SMOOTH); #undef PASSATTRIB } else { GPUMaterialConv *matconv; size_t offset; int *mat_orig_to_new; int tot_active_mat; GPUBuffer *buffer = NULL; GPU_vertex_setup(dm); GPU_normal_setup(dm); GPU_triangle_setup(dm); tot_active_mat = dm->drawObject->totmaterial; matconv = MEM_callocN(sizeof(*matconv) * tot_active_mat, "cdDM_drawMappedFacesGLSL.matconv"); mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat, "cdDM_drawMappedFacesGLSL.mat_orig_to_new"); /* part one, check what attributes are needed per material */ for (a = 0; a < tot_active_mat; a++) { int new_matnr; int do_draw; new_matnr = dm->drawObject->materials[a].mat_nr; /* map from original material index to new * GPUBufferMaterial index */ mat_orig_to_new[new_matnr] = a; do_draw = setMaterial(new_matnr + 1, &gattribs); if (do_draw) { int numdata = 0; DM_vertex_attributes_from_gpu(dm, &gattribs, &matconv[a].attribs); if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) { matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index; matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index; matconv[a].datatypes[numdata].size = 3; matconv[a].datatypes[numdata].type = GL_FLOAT; numdata++; } for (b = 0; b < matconv[a].attribs.tottface; b++) { if (matconv[a].attribs.tface[b].array) { matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index; matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index; matconv[a].datatypes[numdata].size = 2; matconv[a].datatypes[numdata].type = GL_FLOAT; numdata++; } } for (b = 0; b < matconv[a].attribs.totmcol; b++) { if (matconv[a].attribs.mcol[b].array) { matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index; matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index; matconv[a].datatypes[numdata].size = 4; matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE; numdata++; } } for (b = 0; b < matconv[a].attribs.tottang; b++) { if (matconv[a].attribs.tottang && matconv[a].attribs.tang[b].array) { matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index; matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index; matconv[a].datatypes[numdata].size = 4; matconv[a].datatypes[numdata].type = GL_FLOAT; numdata++; } } if (numdata != 0) { matconv[a].numdata = numdata; max_element_size = max_ii(GPU_attrib_element_size(matconv[a].datatypes, numdata), max_element_size); } } } /* part two, generate and fill the arrays with the data */ if (max_element_size > 0) { buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts); varray = GPU_buffer_lock_stream(buffer, GPU_BINDING_ARRAY); if (varray == NULL) { GPU_buffers_unbind(); GPU_buffer_free(buffer); MEM_freeN(mat_orig_to_new); MEM_freeN(matconv); fprintf(stderr, "Out of memory, can't draw object\n"); return; } for (a = 0; a < totpoly; a++) { CCGFace *f = ccgdm->faceMap[a].face; int orig_index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); int i; if (faceFlags) { i = mat_orig_to_new[faceFlags[orig_index].mat_nr]; } else { i = mat_orig_to_new[0]; } if (matconv[i].numdata != 0) { for (S = 0; S < numVerts; S++) { for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { offset = tot_loops * max_element_size; if (matconv[i].attribs.totorco && matconv[i].attribs.orco.array) { int index; index = getFaceIndex(ss, f, S, x, y, edgeSize, gridSize); copy_v3_v3((float *)&varray[offset], (float *)matconv[i].attribs.orco.array[index]); index = getFaceIndex(ss, f, S, x + 1, y, edgeSize, gridSize); copy_v3_v3((float *)&varray[offset + max_element_size], (float *)matconv[i].attribs.orco.array[index]); index = getFaceIndex(ss, f, S, x + 1, y + 1, edgeSize, gridSize); copy_v3_v3((float *)&varray[offset + 2 * max_element_size], (float *)matconv[i].attribs.orco.array[index]); index = getFaceIndex(ss, f, S, x, y + 1, edgeSize, gridSize); copy_v3_v3((float *)&varray[offset + 3 * max_element_size], (float *)matconv[i].attribs.orco.array[index]); offset += sizeof(float) * 3; } for (b = 0; b < matconv[i].attribs.tottface; b++) { if (matconv[i].attribs.tface[b].array) { const MLoopUV *mloopuv = matconv[i].attribs.tface[b].array + tot_loops; copy_v2_v2((float *)&varray[offset], mloopuv[0].uv); copy_v2_v2((float *)&varray[offset + max_element_size], mloopuv[3].uv); copy_v2_v2((float *)&varray[offset + 2 * max_element_size], mloopuv[2].uv); copy_v2_v2((float *)&varray[offset + 3 * max_element_size], mloopuv[1].uv); offset += sizeof(float) * 2; } } for (b = 0; b < matconv[i].attribs.totmcol; b++) { if (matconv[i].attribs.mcol[b].array) { const MLoopCol *mloopcol = matconv[i].attribs.mcol[b].array + tot_loops; copy_v4_v4_uchar(&varray[offset], &mloopcol[0].r); copy_v4_v4_uchar(&varray[offset + max_element_size], &mloopcol[3].r); copy_v4_v4_uchar(&varray[offset + 2 * max_element_size], &mloopcol[2].r); copy_v4_v4_uchar(&varray[offset + 3 * max_element_size], &mloopcol[1].r); offset += sizeof(unsigned char) * 4; } } for (b = 0; b < matconv[i].attribs.tottang; b++) { if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) { const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array + tot_loops; copy_v4_v4((float *)&varray[offset], looptang[0]); copy_v4_v4((float *)&varray[offset + max_element_size], looptang[3]); copy_v4_v4((float *)&varray[offset + 2 * max_element_size], looptang[2]); copy_v4_v4((float *)&varray[offset + 3 * max_element_size], looptang[1]); offset += sizeof(float) * 4; } } tot_loops += 4; } } } } else { tot_loops += 4 * numVerts * gridFaces * gridFaces; } } GPU_buffer_unlock(buffer, GPU_BINDING_ARRAY); } for (a = 0; a < tot_active_mat; a++) { int new_matnr; int do_draw; new_matnr = dm->drawObject->materials[a].mat_nr; do_draw = setMaterial(new_matnr + 1, &gattribs); if (do_draw) { if (matconv[a].numdata) { GPU_interleaved_attrib_setup(buffer, matconv[a].datatypes, matconv[a].numdata, max_element_size); } GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements); if (matconv[a].numdata) { GPU_interleaved_attrib_unbind(); } } } GPU_buffers_unbind(); if (buffer) GPU_buffer_free(buffer); MEM_freeN(mat_orig_to_new); MEM_freeN(matconv); } } static void ccgDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial) { dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL); } /* Only used by non-editmesh types */ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm, void (*setMaterial)(void *userData, int matnr, void *attribs), bool (*setFace)(void *userData, int index), void *userData) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; GPUVertexAttribs gattribs; DMVertexAttribs attribs = {{{NULL}}}; int gridSize = ccgSubSurf_getGridSize(ss); int gridFaces = gridSize - 1; int edgeSize = ccgSubSurf_getEdgeSize(ss); DMFlagMat *faceFlags = ccgdm->faceFlags; const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); int a, i, numVerts, matnr, totface; #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { const int level = ccgSubSurf_getSubdivisionLevels(ss); const int face_side = 1 << level; const int grid_side = 1 << (level - 1); const int face_patches = face_side * face_side; const int grid_patches = grid_side * grid_side; const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss); int current_patch = 0; int mat_nr = -1; bool draw_smooth = false; int start_draw_patch = -1, num_draw_patches = 0; GPU_draw_update_fvar_offset(dm); if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) { return; } for (i = 0; i < num_base_faces; ++i) { const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i); const int num_patches = (num_face_verts == 4) ? face_patches : num_face_verts * grid_patches; int new_matnr; bool new_draw_smooth; if (faceFlags) { new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH); new_matnr = (faceFlags[i].mat_nr + 1); } else { new_draw_smooth = true; new_matnr = 1; } if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) { if (num_draw_patches != 0) { setMaterial(userData, mat_nr, &gattribs); glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); ccgSubSurf_drawGLMesh(ss, true, start_draw_patch, num_draw_patches); } start_draw_patch = current_patch; num_draw_patches = num_patches; mat_nr = new_matnr; draw_smooth = new_draw_smooth; } else { num_draw_patches += num_patches; } current_patch += num_patches; } if (num_draw_patches != 0) { setMaterial(userData, mat_nr, &gattribs); glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); ccgSubSurf_drawGLMesh(ss, true, start_draw_patch, num_draw_patches); } glShadeModel(GL_SMOOTH); return; } #endif CCG_key_top_level(&key, ss); ccgdm_pbvh_update(ccgdm); matnr = -1; #define PASSATTRIB(dx, dy, vert) { \ if (attribs.totorco) \ index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \ else \ index = 0; \ DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \ DM_draw_attrib_vertex_uniforms(&attribs); \ } (void)0 totface = ccgSubSurf_getNumFaces(ss); for (a = 0, i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; const float (*ln)[3] = NULL; int S, x, y, drawSmooth; int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); int origIndex = ccgDM_getFaceMapIndex(ss, f); int new_matnr; numVerts = ccgSubSurf_getFaceNumVerts(f); /* get flags */ if (faceFlags) { drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH)); new_matnr = faceFlags[index].mat_nr + 1; } else { drawSmooth = 1; new_matnr = 1; } if (lnors) { ln = lnors; lnors += (gridFaces * gridFaces * numVerts) * 4; } /* material */ if (new_matnr != matnr) { setMaterial(userData, matnr = new_matnr, &gattribs); DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); } /* face hiding */ if ((setFace && (origIndex != ORIGINDEX_NONE) && !setFace(userData, origIndex))) { a += gridFaces * gridFaces * numVerts; continue; } /* draw face*/ glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT); for (S = 0; S < numVerts; S++) { CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S); CCGElem *vda, *vdb; if (ln) { glBegin(GL_QUADS); for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { float *aco = CCG_grid_elem_co(&key, faceGridData, x, y + 0); float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0); float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1); PASSATTRIB(0, 1, 1); glNormal3fv(ln[1]); glVertex3fv(dco); PASSATTRIB(1, 1, 2); glNormal3fv(ln[2]); glVertex3fv(cco); PASSATTRIB(1, 0, 3); glNormal3fv(ln[3]); glVertex3fv(bco); PASSATTRIB(0, 0, 0); glNormal3fv(ln[0]); glVertex3fv(aco); ln += 4; a++; } } glEnd(); } else if (drawSmooth) { for (y = 0; y < gridFaces; y++) { glBegin(GL_QUAD_STRIP); for (x = 0; x < gridFaces; x++) { vda = CCG_grid_elem(&key, faceGridData, x, y); vdb = CCG_grid_elem(&key, faceGridData, x, y + 1); PASSATTRIB(0, 0, 0); glNormal3fv(CCG_elem_no(&key, vda)); glVertex3fv(CCG_elem_co(&key, vda)); PASSATTRIB(0, 1, 1); glNormal3fv(CCG_elem_no(&key, vdb)); glVertex3fv(CCG_elem_co(&key, vdb)); if (x != gridFaces - 1) a++; } vda = CCG_grid_elem(&key, faceGridData, x, y + 0); vdb = CCG_grid_elem(&key, faceGridData, x, y + 1); PASSATTRIB(0, 0, 3); glNormal3fv(CCG_elem_no(&key, vda)); glVertex3fv(CCG_elem_co(&key, vda)); PASSATTRIB(0, 1, 2); glNormal3fv(CCG_elem_no(&key, vdb)); glVertex3fv(CCG_elem_co(&key, vdb)); glEnd(); a++; } } else { glBegin(GL_QUADS); for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { float *aco = CCG_grid_elem_co(&key, faceGridData, x, y + 0); float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0); float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1); ccgDM_glNormalFast(aco, bco, cco, dco); PASSATTRIB(0, 1, 1); glVertex3fv(dco); PASSATTRIB(1, 1, 2); glVertex3fv(cco); PASSATTRIB(1, 0, 3); glVertex3fv(bco); PASSATTRIB(0, 0, 0); glVertex3fv(aco); a++; } } glEnd(); } } } glShadeModel(GL_SMOOTH); #undef PASSATTRIB } static void ccgDM_drawFacesTex_common(DerivedMesh *dm, DMSetDrawOptionsTex drawParams, DMSetDrawOptionsMappedTex drawParamsMapped, DMCompareDrawOptions compareDrawOptions, void *userData, DMDrawFlag flag) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; int colType; const MLoopCol *mloopcol = NULL; MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY); DMFlagMat *faceFlags = ccgdm->faceFlags; DMDrawOption draw_option; int i, totpoly; bool flush; const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0; const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0; unsigned int next_actualFace; unsigned int gridFaces = ccgSubSurf_getGridSize(ss) - 1; int mat_index; int tot_element, start_element, tot_drawn; if (use_colors) { colType = CD_TEXTURE_MLOOPCOL; mloopcol = dm->getLoopDataArray(dm, colType); if (!mloopcol) { colType = CD_PREVIEW_MLOOPCOL; mloopcol = dm->getLoopDataArray(dm, colType); } if (!mloopcol) { colType = CD_MLOOPCOL; mloopcol = dm->getLoopDataArray(dm, colType); } } #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { const int active_uv_layer = CustomData_get_active_layer_index(&dm->loopData, CD_MLOOPUV); if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, active_uv_layer) == false)) { return; } if (drawParams == NULL) { ccgSubSurf_drawGLMesh(ss, true, -1, -1); return; } const int level = ccgSubSurf_getSubdivisionLevels(ss); const int face_side = 1 << level; const int grid_side = 1 << (level - 1); const int face_patches = face_side * face_side; const int grid_patches = grid_side * grid_side; const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss); int current_patch = 0; int mat_nr = -1; int start_draw_patch = 0, num_draw_patches = 0; bool draw_smooth = false; for (i = 0; i < num_base_faces; ++i) { const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i); const int num_patches = (num_face_verts == 4) ? face_patches : num_face_verts * grid_patches; if (faceFlags) { mat_nr = faceFlags[i].mat_nr; draw_smooth = (faceFlags[i].flag & ME_SMOOTH); } else { mat_nr = 0; draw_smooth = false; } if (drawParams != NULL) { MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[i] : NULL; draw_option = drawParams(tp, (mloopcol != NULL), mat_nr); } else { draw_option = (drawParamsMapped) ? drawParamsMapped(userData, i, mat_nr) : DM_DRAW_OPTION_NORMAL; } flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == num_base_faces - 1); const int next_face = min_ii(i + 1, num_base_faces - 1); if (!flush && compareDrawOptions) { flush |= compareDrawOptions(userData, i, next_face) == 0; } if (!flush && faceFlags) { bool new_draw_smooth = (faceFlags[next_face].flag & ME_SMOOTH); flush |= (new_draw_smooth != draw_smooth); } current_patch += num_patches; if (flush) { if (draw_option != DM_DRAW_OPTION_SKIP) { num_draw_patches += num_patches; } if (num_draw_patches != 0) { glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); ccgSubSurf_drawGLMesh(ss, true, start_draw_patch, num_draw_patches); } start_draw_patch = current_patch; num_draw_patches = 0; } else { num_draw_patches += num_patches; } } glShadeModel(GL_SMOOTH); return; } #endif CCG_key_top_level(&key, ss); ccgdm_pbvh_update(ccgdm); GPU_vertex_setup(dm); GPU_normal_setup(dm); GPU_triangle_setup(dm); if (flag & DM_DRAW_USE_TEXPAINT_UV) GPU_texpaint_uv_setup(dm); else GPU_uv_setup(dm); if (mloopcol) { GPU_color_setup(dm, colType); } next_actualFace = 0; /* lastFlag = 0; */ /* UNUSED */ for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) { GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index; next_actualFace = bufmat->polys[0]; totpoly = bufmat->totpolys; tot_element = 0; tot_drawn = 0; start_element = 0; for (i = 0; i < totpoly; i++) { int polyindex = bufmat->polys[i]; CCGFace *f = ccgdm->faceMap[polyindex].face; int numVerts = ccgSubSurf_getFaceNumVerts(f); int index = ccgDM_getFaceMapIndex(ss, f); int orig_index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); int mat_nr; int facequads = numVerts * gridFaces * gridFaces; int actualFace = ccgdm->faceMap[polyindex].startFace; if (i != totpoly - 1) { polyindex = bufmat->polys[i + 1]; next_actualFace = ccgdm->faceMap[polyindex].startFace; } if (faceFlags) { mat_nr = faceFlags[orig_index].mat_nr; } else { mat_nr = 0; } if (drawParams) { MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[actualFace] : NULL; draw_option = drawParams(tp, (mloopcol != NULL), mat_nr); } else if (index != ORIGINDEX_NONE) draw_option = (drawParamsMapped) ? drawParamsMapped(userData, index, mat_nr) : DM_DRAW_OPTION_NORMAL; else draw_option = DM_DRAW_OPTION_NORMAL; /* flush buffer if current triangle isn't drawable or it's last triangle */ flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == totpoly - 1); if (!flush && compareDrawOptions) { /* also compare draw options and flush buffer if they're different * need for face selection highlight in edit mode */ flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0; } tot_element += facequads * 6; if (flush) { if (draw_option != DM_DRAW_OPTION_SKIP) tot_drawn += facequads * 6; if (tot_drawn) { if (mloopcol && draw_option != DM_DRAW_OPTION_NO_MCOL) GPU_color_switch(1); else GPU_color_switch(0); GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn); tot_drawn = 0; } start_element = tot_element; } else { tot_drawn += facequads * 6; } } } GPU_buffers_unbind(); } static void ccgDM_drawFacesTex(DerivedMesh *dm, DMSetDrawOptionsTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, void *userData, DMDrawFlag flag) { ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag); } static void ccgDM_drawMappedFacesTex(DerivedMesh *dm, DMSetDrawOptionsMappedTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, void *userData, DMDrawFlag flag) { ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag); } /* same as cdDM_drawUVEdges */ static void ccgDM_drawUVEdges(DerivedMesh *dm) { MPoly *mpoly = dm->getPolyArray(dm); int totpoly = dm->getNumPolys(dm); int prevstart = 0; bool prevdraw = true; int curpos = 0; int i; GPU_uvedge_setup(dm); for (i = 0; i < totpoly; i++, mpoly++) { const bool draw = (mpoly->flag & ME_HIDE) == 0; if (prevdraw != draw) { if (prevdraw && (curpos != prevstart)) { glDrawArrays(GL_LINES, prevstart, curpos - prevstart); } prevstart = curpos; } curpos += 2 * mpoly->totloop; prevdraw = draw; } if (prevdraw && (curpos != prevstart)) { glDrawArrays(GL_LINES, prevstart, curpos - prevstart); } GPU_buffers_unbind(); } static void ccgDM_drawMappedFaces(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, DMSetMaterial setMaterial, DMCompareDrawOptions compareDrawOptions, void *userData, DMDrawFlag flag) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; MLoopCol *mloopcol = NULL; const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); int i, gridSize = ccgSubSurf_getGridSize(ss); DMFlagMat *faceFlags = ccgdm->faceFlags; int useColors = flag & DM_DRAW_USE_COLORS; int gridFaces = gridSize - 1, totface; int prev_mat_nr = -1; if (ccgdm->pbvh) { if (G.debug_value == 14) BKE_pbvh_draw_BB(ccgdm->pbvh); } #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { int new_matnr; bool draw_smooth, do_draw = true; if (setDrawOptions == NULL) { /* 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. */ glColor3f(0.8f, 0.8f, 0.8f); } if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) { return; } 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); } if (setDrawOptions) { if (setDrawOptions(userData, 0) == DM_DRAW_OPTION_SKIP) { do_draw = false; } } if (do_draw) { glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); ccgSubSurf_drawGLMesh(ss, true, -1, -1); glShadeModel(GL_SMOOTH); } return; } #endif CCG_key_top_level(&key, ss); /* currently unused -- each original face is handled separately */ (void)compareDrawOptions; if (useColors) { mloopcol = dm->getLoopDataArray(dm, CD_PREVIEW_MLOOPCOL); if (!mloopcol) mloopcol = dm->getLoopDataArray(dm, CD_MLOOPCOL); } totface = ccgSubSurf_getNumFaces(ss); for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); int drawSmooth, index = ccgDM_getFaceMapIndex(ss, f); int origIndex; unsigned char *cp = NULL; const float (*ln)[3] = NULL; origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); if (flag & DM_DRAW_ALWAYS_SMOOTH) drawSmooth = 1; else if (faceFlags) drawSmooth = (lnors || (faceFlags[origIndex].flag & ME_SMOOTH)); else drawSmooth = 1; if (mloopcol) { cp = (unsigned char *)mloopcol; mloopcol += gridFaces * gridFaces * numVerts * 4; } if (lnors) { ln = lnors; lnors += (gridFaces * gridFaces * numVerts) * 4; } { DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL; if (setMaterial) { int mat_nr = faceFlags ? faceFlags[origIndex].mat_nr + 1 : 1; if (mat_nr != prev_mat_nr) { setMaterial(mat_nr, NULL); /* XXX, no faceFlags no material */ prev_mat_nr = mat_nr; } } if (setDrawOptions && (index != ORIGINDEX_NONE)) draw_option = setDrawOptions(userData, index); if (draw_option != DM_DRAW_OPTION_SKIP) { if (draw_option == DM_DRAW_OPTION_STIPPLE) { GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE); } for (S = 0; S < numVerts; S++) { CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S); if (ln) { glBegin(GL_QUADS); for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { float *a = CCG_grid_elem_co(&key, faceGridData, x, y + 0); float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0); float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1); if (cp) glColor3ubv(&cp[4]); glNormal3fv(ln[1]); glVertex3fv(d); if (cp) glColor3ubv(&cp[8]); glNormal3fv(ln[2]); glVertex3fv(c); if (cp) glColor3ubv(&cp[12]); glNormal3fv(ln[3]); glVertex3fv(b); if (cp) glColor3ubv(&cp[0]); glNormal3fv(ln[0]); glVertex3fv(a); if (cp) cp += 16; ln += 4; } } glEnd(); } else if (drawSmooth) { for (y = 0; y < gridFaces; y++) { CCGElem *a, *b; glBegin(GL_QUAD_STRIP); for (x = 0; x < gridFaces; x++) { a = CCG_grid_elem(&key, faceGridData, x, y + 0); b = CCG_grid_elem(&key, faceGridData, x, y + 1); if (cp) glColor3ubv(&cp[0]); glNormal3fv(CCG_elem_no(&key, a)); glVertex3fv(CCG_elem_co(&key, a)); if (cp) glColor3ubv(&cp[4]); glNormal3fv(CCG_elem_no(&key, b)); glVertex3fv(CCG_elem_co(&key, b)); if (x != gridFaces - 1) { if (cp) cp += 16; } } a = CCG_grid_elem(&key, faceGridData, x, y + 0); b = CCG_grid_elem(&key, faceGridData, x, y + 1); if (cp) glColor3ubv(&cp[12]); glNormal3fv(CCG_elem_no(&key, a)); glVertex3fv(CCG_elem_co(&key, a)); if (cp) glColor3ubv(&cp[8]); glNormal3fv(CCG_elem_no(&key, b)); glVertex3fv(CCG_elem_co(&key, b)); if (cp) cp += 16; glEnd(); } } else { glBegin(GL_QUADS); for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { float *a = CCG_grid_elem_co(&key, faceGridData, x, y + 0); float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0); float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1); ccgDM_glNormalFast(a, b, c, d); if (cp) glColor3ubv(&cp[4]); glVertex3fv(d); if (cp) glColor3ubv(&cp[8]); glVertex3fv(c); if (cp) glColor3ubv(&cp[12]); glVertex3fv(b); if (cp) glColor3ubv(&cp[0]); glVertex3fv(a); if (cp) cp += 16; } } glEnd(); } } if (draw_option == DM_DRAW_OPTION_STIPPLE) GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } } } } static void ccgDM_drawMappedEdges(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, void *userData) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGEdgeIterator ei; CCGKey key; int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss); #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { /* TODO(sergey): Only draw edges from base mesh. */ if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) { if (!setDrawOptions || (setDrawOptions(userData, 0) != DM_DRAW_OPTION_SKIP)) { ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1); } } return; } #endif CCG_key_top_level(&key, ss); ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL); for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) { CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); int index = ccgDM_getEdgeMapIndex(ss, e); glBegin(GL_LINE_STRIP); if (index != -1 && (!setDrawOptions || (setDrawOptions(userData, index) != DM_DRAW_OPTION_SKIP))) { if (useAging && !(G.f & G_BACKBUFSEL)) { int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4; glColor3ub(0, ageCol > 0 ? ageCol : 0, 0); } for (i = 0; i < edgeSize - 1; i++) { glVertex3fv(CCG_elem_offset_co(&key, edgeData, i)); glVertex3fv(CCG_elem_offset_co(&key, edgeData, i + 1)); } } glEnd(); } } static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, DMSetDrawInterpOptions setDrawInterpOptions, void *userData) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; 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); for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) { CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); int index = ccgDM_getEdgeMapIndex(ss, e); glBegin(GL_LINE_STRIP); if (index != -1 && (!setDrawOptions || (setDrawOptions(userData, index) != DM_DRAW_OPTION_SKIP))) { for (i = 0; i < edgeSize; i++) { setDrawInterpOptions(userData, index, (float) i / (edgeSize - 1)); if (useAging && !(G.f & G_BACKBUFSEL)) { int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4; glColor3ub(0, ageCol > 0 ? ageCol : 0, 0); } glVertex3fv(CCG_elem_offset_co(&key, edgeData, i)); } } glEnd(); } } static void ccgDM_foreachMappedFaceCenter( DerivedMesh *dm, void (*func)(void *userData, int index, const float co[3], const float no[3]), void *userData, DMForeachFlag flag) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; CCGFaceIterator fi; CCG_key_top_level(&key, ss); for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) { CCGFace *f = ccgFaceIterator_getCurrent(&fi); const int index = ccgDM_getFaceMapIndex(ss, f); if (index != -1) { /* Face center data normal isn't updated atm. */ CCGElem *vd = ccgSubSurf_getFaceGridData(ss, f, 0, 0, 0); const float *no = (flag & DM_FOREACH_USE_NORMAL) ? CCG_elem_no(&key, vd) : NULL; func(userData, index, CCG_elem_co(&key, vd), no); } } } static void ccgDM_release(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; if (DM_release(dm)) { /* Before freeing, need to update the displacement map */ if (ccgdm->multires.modified_flags) { /* Check that mmd still exists */ if (!ccgdm->multires.local_mmd && BLI_findindex(&ccgdm->multires.ob->modifiers, ccgdm->multires.mmd) < 0) { ccgdm->multires.mmd = NULL; } if (ccgdm->multires.mmd) { if (ccgdm->multires.modified_flags & MULTIRES_COORDS_MODIFIED) multires_modifier_update_mdisps(dm); if (ccgdm->multires.modified_flags & MULTIRES_HIDDEN_MODIFIED) multires_modifier_update_hidden(dm); } } if (ccgdm->ehash) BLI_edgehash_free(ccgdm->ehash, NULL); if (ccgdm->reverseFaceMap) MEM_freeN(ccgdm->reverseFaceMap); if (ccgdm->gridFaces) MEM_freeN(ccgdm->gridFaces); if (ccgdm->gridData) MEM_freeN(ccgdm->gridData); if (ccgdm->gridOffset) MEM_freeN(ccgdm->gridOffset); if (ccgdm->gridFlagMats) MEM_freeN(ccgdm->gridFlagMats); if (ccgdm->gridHidden) { int i, numGrids = dm->getNumGrids(dm); for (i = 0; i < numGrids; i++) { if (ccgdm->gridHidden[i]) MEM_freeN(ccgdm->gridHidden[i]); } MEM_freeN(ccgdm->gridHidden); } if (ccgdm->freeSS) ccgSubSurf_free(ccgdm->ss); if (ccgdm->pmap) MEM_freeN(ccgdm->pmap); if (ccgdm->pmap_mem) MEM_freeN(ccgdm->pmap_mem); MEM_freeN(ccgdm->edgeFlags); MEM_freeN(ccgdm->faceFlags); if (ccgdm->useGpuBackend == false) { MEM_freeN(ccgdm->vertMap); MEM_freeN(ccgdm->edgeMap); MEM_freeN(ccgdm->faceMap); } MEM_freeN(ccgdm); } } static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type) { if (type == CD_ORIGINDEX) { /* create origindex on demand to save memory */ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; CCGSubSurf *ss = ccgdm->ss; int *origindex; int a, index, totnone, totorig; /* Avoid re-creation if the layer exists already */ BLI_rw_mutex_lock(&origindex_cache_rwlock, THREAD_LOCK_READ); origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX); BLI_rw_mutex_unlock(&origindex_cache_rwlock); if (origindex) { return origindex; } BLI_rw_mutex_lock(&origindex_cache_rwlock, THREAD_LOCK_WRITE); DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL); origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX); totorig = ccgSubSurf_getNumVerts(ss); totnone = dm->numVertData - totorig; /* original vertices are at the end */ for (a = 0; a < totnone; a++) origindex[a] = ORIGINDEX_NONE; for (index = 0; index < totorig; index++, a++) { CCGVert *v = ccgdm->vertMap[index].vert; origindex[a] = ccgDM_getVertMapIndex(ccgdm->ss, v); } BLI_rw_mutex_unlock(&origindex_cache_rwlock); return origindex; } return DM_get_vert_data_layer(dm, type); } static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type) { if (type == CD_ORIGINDEX) { /* create origindex on demand to save memory */ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; CCGSubSurf *ss = ccgdm->ss; int *origindex; int a, i, index, totnone, totorig, totedge; int edgeSize = ccgSubSurf_getEdgeSize(ss); /* Avoid re-creation if the layer exists already */ origindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX); if (origindex) { return origindex; } DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL); origindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX); totedge = ccgSubSurf_getNumEdges(ss); totorig = totedge * (edgeSize - 1); totnone = dm->numEdgeData - totorig; /* original edges are at the end */ for (a = 0; a < totnone; a++) origindex[a] = ORIGINDEX_NONE; for (index = 0; index < totedge; index++) { CCGEdge *e = ccgdm->edgeMap[index].edge; int mapIndex = ccgDM_getEdgeMapIndex(ss, e); for (i = 0; i < edgeSize - 1; i++, a++) origindex[a] = mapIndex; } return origindex; } return DM_get_edge_data_layer(dm, type); } static void *ccgDM_get_tessface_data_layer(DerivedMesh *dm, int type) { if (type == CD_ORIGINDEX) { /* create origindex on demand to save memory */ int *origindex; /* Avoid re-creation if the layer exists already */ origindex = DM_get_tessface_data_layer(dm, CD_ORIGINDEX); if (origindex) { return origindex; } DM_add_tessface_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL); origindex = DM_get_tessface_data_layer(dm, CD_ORIGINDEX); /* silly loop counting up */ range_vn_i(origindex, dm->getNumTessFaces(dm), 0); return origindex; } if (type == CD_TESSLOOPNORMAL) { /* Create tessloopnormal on demand to save memory. */ /* Note that since tessellated face corners are the same a loops in CCGDM, and since all faces have four * loops/corners, we can simplify the code here by converting tessloopnormals from 'short (*)[4][3]' * to 'short (*)[3]'. */ short (*tlnors)[3]; /* Avoid re-creation if the layer exists already */ tlnors = DM_get_tessface_data_layer(dm, CD_TESSLOOPNORMAL); if (!tlnors) { float (*lnors)[3]; short (*tlnors_it)[3]; const int numLoops = ccgDM_getNumLoops(dm); int i; lnors = dm->getLoopDataArray(dm, CD_NORMAL); if (!lnors) { return NULL; } DM_add_tessface_layer(dm, CD_TESSLOOPNORMAL, CD_CALLOC, NULL); tlnors = tlnors_it = (short (*)[3])DM_get_tessface_data_layer(dm, CD_TESSLOOPNORMAL); /* With ccgdm, we have a simple one to one mapping between loops and tessellated face corners. */ for (i = 0; i < numLoops; ++i, ++tlnors_it, ++lnors) { normal_float_to_short_v3(*tlnors_it, *lnors); } } return tlnors; } return DM_get_tessface_data_layer(dm, type); } static void *ccgDM_get_poly_data_layer(DerivedMesh *dm, int type) { if (type == CD_ORIGINDEX) { /* create origindex on demand to save memory */ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; CCGSubSurf *ss = ccgdm->ss; int *origindex; int a, i, index, totface; int gridFaces = ccgSubSurf_getGridSize(ss) - 1; /* Avoid re-creation if the layer exists already */ origindex = DM_get_poly_data_layer(dm, CD_ORIGINDEX); if (origindex) { return origindex; } DM_add_poly_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL); origindex = DM_get_poly_data_layer(dm, CD_ORIGINDEX); totface = ccgSubSurf_getNumFaces(ss); for (a = 0, index = 0; index < totface; index++) { CCGFace *f = ccgdm->faceMap[index].face; int numVerts = ccgSubSurf_getFaceNumVerts(f); int mapIndex = ccgDM_getFaceMapIndex(ss, f); for (i = 0; i < gridFaces * gridFaces * numVerts; i++, a++) origindex[a] = mapIndex; } return origindex; } return DM_get_poly_data_layer(dm, type); } static void *ccgDM_get_vert_data(DerivedMesh *dm, int index, int type) { if (type == CD_ORIGINDEX) { /* ensure creation of CD_ORIGINDEX layer */ ccgDM_get_vert_data_layer(dm, type); } return DM_get_vert_data(dm, index, type); } static void *ccgDM_get_edge_data(DerivedMesh *dm, int index, int type) { if (type == CD_ORIGINDEX) { /* ensure creation of CD_ORIGINDEX layer */ ccgDM_get_edge_data_layer(dm, type); } return DM_get_edge_data(dm, index, type); } static void *ccgDM_get_tessface_data(DerivedMesh *dm, int index, int type) { if (ELEM(type, CD_ORIGINDEX, CD_TESSLOOPNORMAL)) { /* ensure creation of CD_ORIGINDEX/CD_TESSLOOPNORMAL layers */ ccgDM_get_tessface_data_layer(dm, type); } return DM_get_tessface_data(dm, index, type); } static void *ccgDM_get_poly_data(DerivedMesh *dm, int index, int type) { if (type == CD_ORIGINDEX) { /* ensure creation of CD_ORIGINDEX layer */ ccgDM_get_tessface_data_layer(dm, type); } return DM_get_poly_data(dm, index, type); } static int ccgDM_getNumGrids(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; int index, numFaces, numGrids; numFaces = ccgSubSurf_getNumFaces(ccgdm->ss); numGrids = 0; for (index = 0; index < numFaces; index++) { CCGFace *f = ccgdm->faceMap[index].face; numGrids += ccgSubSurf_getFaceNumVerts(f); } return numGrids; } static int ccgDM_getGridSize(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; return ccgSubSurf_getGridSize(ccgdm->ss); } static void ccgdm_create_grids(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; CCGSubSurf *ss = ccgdm->ss; CCGElem **gridData; DMFlagMat *gridFlagMats; CCGFace **gridFaces; int *gridOffset; int index, numFaces, numGrids, S, gIndex /*, gridSize*/; if (ccgdm->gridData) return; numGrids = ccgDM_getNumGrids(dm); numFaces = ccgSubSurf_getNumFaces(ss); /*gridSize = ccgDM_getGridSize(dm);*/ /*UNUSED*/ /* compute offset into grid array for each face */ gridOffset = MEM_mallocN(sizeof(int) * numFaces, "ccgdm.gridOffset"); for (gIndex = 0, index = 0; index < numFaces; index++) { CCGFace *f = ccgdm->faceMap[index].face; int numVerts = ccgSubSurf_getFaceNumVerts(f); gridOffset[index] = gIndex; gIndex += numVerts; } /* compute grid data */ gridData = MEM_mallocN(sizeof(CCGElem *) * numGrids, "ccgdm.gridData"); gridFaces = MEM_mallocN(sizeof(CCGFace *) * numGrids, "ccgdm.gridFaces"); gridFlagMats = MEM_mallocN(sizeof(DMFlagMat) * numGrids, "ccgdm.gridFlagMats"); ccgdm->gridHidden = MEM_callocN(sizeof(*ccgdm->gridHidden) * numGrids, "ccgdm.gridHidden"); for (gIndex = 0, index = 0; index < numFaces; index++) { CCGFace *f = ccgdm->faceMap[index].face; int numVerts = ccgSubSurf_getFaceNumVerts(f); for (S = 0; S < numVerts; S++, gIndex++) { gridData[gIndex] = ccgSubSurf_getFaceGridDataArray(ss, f, S); gridFaces[gIndex] = f; gridFlagMats[gIndex] = ccgdm->faceFlags[index]; } } ccgdm->gridData = gridData; ccgdm->gridFaces = gridFaces; ccgdm->gridOffset = gridOffset; ccgdm->gridFlagMats = gridFlagMats; } static CCGElem **ccgDM_getGridData(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; ccgdm_create_grids(dm); return ccgdm->gridData; } static int *ccgDM_getGridOffset(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; ccgdm_create_grids(dm); return ccgdm->gridOffset; } static void ccgDM_getGridKey(DerivedMesh *dm, CCGKey *key) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; CCG_key_top_level(key, ccgdm->ss); } static DMFlagMat *ccgDM_getGridFlagMats(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; ccgdm_create_grids(dm); return ccgdm->gridFlagMats; } static BLI_bitmap **ccgDM_getGridHidden(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; ccgdm_create_grids(dm); return ccgdm->gridHidden; } static const MeshElemMap *ccgDM_getPolyMap(Object *ob, DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; if (!ccgdm->multires.mmd && !ccgdm->pmap && ob->type == OB_MESH) { Mesh *me = ob->data; BKE_mesh_vert_poly_map_create(&ccgdm->pmap, &ccgdm->pmap_mem, me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop); } return ccgdm->pmap; } static int ccgDM_use_grid_pbvh(CCGDerivedMesh *ccgdm) { MultiresModifierData *mmd = ccgdm->multires.mmd; /* both of multires and subsurf modifiers are CCG, but * grids should only be used when sculpting on multires */ if (!mmd) return 0; return 1; } static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; CCGKey key; int numGrids, grid_pbvh; CCG_key_top_level(&key, ccgdm->ss); if (!ob) { ccgdm->pbvh = NULL; return NULL; } if (!ob->sculpt) return NULL; /* In vwpaint, we always use a grid_pbvh for multires/subsurf */ grid_pbvh = (!(ob->mode & OB_MODE_SCULPT) || ccgDM_use_grid_pbvh(ccgdm)); if (ob->sculpt->pbvh) { if (grid_pbvh) { /* pbvh's grids, gridadj and gridfaces points to data inside ccgdm * but this can be freed on ccgdm release, this updates the pointers * when the ccgdm gets remade, the assumption is that the topology * does not change. */ ccgdm_create_grids(dm); BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, (void **)ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden); } ccgdm->pbvh = ob->sculpt->pbvh; } if (ccgdm->pbvh) { /* For vertex paint, keep track of ccgdm */ if (!(ob->mode & OB_MODE_SCULPT)) { BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm); } return ccgdm->pbvh; } /* no pbvh exists yet, we need to create one. only in case of multires * we build a pbvh over the modified mesh, in other cases the base mesh * is being sculpted, so we build a pbvh from that. */ /* Note: vwpaint always builds a pbvh over the modified mesh. */ if (grid_pbvh) { ccgdm_create_grids(dm); numGrids = ccgDM_getNumGrids(dm); ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new(); BKE_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, numGrids, &key, (void **) ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden); } else if (ob->type == OB_MESH) { Mesh *me = ob->data; const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop); MLoopTri *looptri; looptri = MEM_mallocN(sizeof(*looptri) * looptris_num, __func__); BKE_mesh_recalc_looptri( me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri); ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new(); BKE_pbvh_build_mesh(ccgdm->pbvh, me->mpoly, me->mloop, me->mvert, me->totvert, &me->vdata, looptri, looptris_num); } if (ccgdm->pbvh) pbvh_show_diffuse_color_set(ccgdm->pbvh, ob->sculpt->show_diffuse_color); /* For vertex paint, keep track of ccgdm */ if (!(ob->mode & OB_MODE_SCULPT) && ccgdm->pbvh) { BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm); } return ccgdm->pbvh; } static void ccgDM_recalcTessellation(DerivedMesh *UNUSED(dm)) { /* Nothing to do: CCG handles creating its own tessfaces */ } /* WARNING! *MUST* be called in an 'loops_cache_rwlock' protected thread context! */ static void ccgDM_recalcLoopTri(DerivedMesh *dm) { MLoopTri *mlooptri = dm->looptris.array; const int tottri = dm->numPolyData * 2; int i, poly_index; DM_ensure_looptri_data(dm); mlooptri = dm->looptris.array_wip; BLI_assert(tottri == 0 || mlooptri != NULL); BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); BLI_assert(tottri == dm->looptris.num); for (i = 0, poly_index = 0; i < tottri; i += 2, poly_index += 1) { MLoopTri *lt; lt = &mlooptri[i]; /* quad is (0, 3, 2, 1) */ lt->tri[0] = (poly_index * 4) + 0; lt->tri[1] = (poly_index * 4) + 2; lt->tri[2] = (poly_index * 4) + 3; lt->poly = poly_index; lt = &mlooptri[i + 1]; lt->tri[0] = (poly_index * 4) + 0; lt->tri[1] = (poly_index * 4) + 1; lt->tri[2] = (poly_index * 4) + 2; lt->poly = poly_index; } BLI_assert(dm->looptris.array == NULL); atomic_cas_ptr((void **)&dm->looptris.array, dm->looptris.array, dm->looptris.array_wip); dm->looptris.array_wip = NULL; } static void ccgDM_calcNormals(DerivedMesh *dm) { /* Nothing to do: CCG calculates normals during drawing */ dm->dirty &= ~DM_DIRTY_NORMALS; } static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm) { ccgdm->dm.getMinMax = ccgDM_getMinMax; ccgdm->dm.getNumVerts = ccgDM_getNumVerts; ccgdm->dm.getNumEdges = ccgDM_getNumEdges; ccgdm->dm.getNumLoops = ccgDM_getNumLoops; /* reuse of ccgDM_getNumTessFaces is intentional here: subsurf polys are just created from tessfaces */ ccgdm->dm.getNumPolys = ccgDM_getNumPolys; ccgdm->dm.getNumTessFaces = ccgDM_getNumTessFaces; ccgdm->dm.getVert = ccgDM_getFinalVert; ccgdm->dm.getEdge = ccgDM_getFinalEdge; ccgdm->dm.getTessFace = ccgDM_getFinalFace; ccgdm->dm.getVertCo = ccgDM_getFinalVertCo; ccgdm->dm.getVertNo = ccgDM_getFinalVertNo; ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray; ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray; ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray; ccgdm->dm.copyLoopArray = ccgDM_copyFinalLoopArray; ccgdm->dm.copyPolyArray = ccgDM_copyFinalPolyArray; ccgdm->dm.getVertData = ccgDM_get_vert_data; ccgdm->dm.getEdgeData = ccgDM_get_edge_data; ccgdm->dm.getTessFaceData = ccgDM_get_tessface_data; ccgdm->dm.getPolyData = ccgDM_get_poly_data; ccgdm->dm.getVertDataArray = ccgDM_get_vert_data_layer; ccgdm->dm.getEdgeDataArray = ccgDM_get_edge_data_layer; ccgdm->dm.getTessFaceDataArray = ccgDM_get_tessface_data_layer; ccgdm->dm.getPolyDataArray = ccgDM_get_poly_data_layer; ccgdm->dm.getNumGrids = ccgDM_getNumGrids; ccgdm->dm.getGridSize = ccgDM_getGridSize; ccgdm->dm.getGridData = ccgDM_getGridData; ccgdm->dm.getGridOffset = ccgDM_getGridOffset; ccgdm->dm.getGridKey = ccgDM_getGridKey; ccgdm->dm.getGridFlagMats = ccgDM_getGridFlagMats; ccgdm->dm.getGridHidden = ccgDM_getGridHidden; ccgdm->dm.getPolyMap = ccgDM_getPolyMap; ccgdm->dm.getPBVH = ccgDM_getPBVH; ccgdm->dm.calcNormals = ccgDM_calcNormals; ccgdm->dm.calcLoopNormals = CDDM_calc_loop_normals; ccgdm->dm.calcLoopNormalsSpaceArray = CDDM_calc_loop_normals_spacearr; ccgdm->dm.calcLoopTangents = DM_calc_loop_tangents; ccgdm->dm.recalcTessellation = ccgDM_recalcTessellation; ccgdm->dm.recalcLoopTri = ccgDM_recalcLoopTri; ccgdm->dm.getVertCos = ccgdm_getVertCos; ccgdm->dm.foreachMappedVert = ccgDM_foreachMappedVert; 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; ccgdm->dm.drawFacesSolid = ccgDM_drawFacesSolid; ccgdm->dm.drawFacesTex = ccgDM_drawFacesTex; ccgdm->dm.drawFacesGLSL = ccgDM_drawFacesGLSL; ccgdm->dm.drawMappedFaces = ccgDM_drawMappedFaces; ccgdm->dm.drawMappedFacesTex = ccgDM_drawMappedFacesTex; ccgdm->dm.drawMappedFacesGLSL = ccgDM_drawMappedFacesGLSL; ccgdm->dm.drawMappedFacesMat = ccgDM_drawMappedFacesMat; ccgdm->dm.drawUVEdges = ccgDM_drawUVEdges; ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp; ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges; ccgdm->dm.gpuObjectNew = ccgDM_GPUObjectNew; ccgdm->dm.copy_gpu_data = ccgDM_copy_gpu_data; ccgdm->dm.release = ccgDM_release; } 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)) { CCGVert *v = ccgVertIterator_getCurrent(&vi); ccgdm->vertMap[GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v))].vert = v; } totedge = ccgSubSurf_getNumEdges(ss); ccgdm->edgeMap = MEM_mallocN(totedge * sizeof(*ccgdm->edgeMap), "edgeMap"); 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; } totface = ccgSubSurf_getNumFaces(ss); ccgdm->faceMap = MEM_mallocN(totface * sizeof(*ccgdm->faceMap), "faceMap"); 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 gridInternalEdges; WeightTable wtable = {NULL}; MEdge *medge = NULL; MPoly *mpoly = NULL; bool has_edge_cd; edgeSize = ccgSubSurf_getEdgeSize(ss); gridSize = ccgSubSurf_getGridSize(ss); gridFaces = gridSize - 1; gridCuts = gridSize - 2; /*gridInternalVerts = gridSideVerts * gridSideVerts; - as yet, unused */ gridSideEdges = gridSize - 1; gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2; /* mvert = dm->getVertArray(dm); */ /* UNUSED */ medge = dm->getEdgeArray(dm); /* mface = dm->getTessFaceArray(dm); */ /* UNUSED */ mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); base_polyOrigIndex = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX); vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX); edgeOrigIndex = DM_get_edge_data_layer(&ccgdm->dm, CD_ORIGINDEX); faceOrigIndex = DM_get_tessface_data_layer(&ccgdm->dm, CD_ORIGINDEX); polyOrigIndex = DM_get_poly_data_layer(&ccgdm->dm, CD_ORIGINDEX); has_edge_cd = ((ccgdm->dm.edgeData.totlayer - (edgeOrigIndex ? 1 : 0)) != 0); #if 0 /* this is not in trunk, can gives problems because colors initialize * as black, just don't do it!, it works fine - campbell */ if (!CustomData_has_layer(&ccgdm->dm.faceData, CD_MCOL)) DM_add_tessface_layer(&ccgdm->dm, CD_MCOL, CD_CALLOC, NULL); mcol = DM_get_tessface_data_layer(&ccgdm->dm, CD_MCOL); #endif loopindex = loopindex2 = 0; /* current loop index */ for (index = 0; index < totface; index++) { CCGFace *f = ccgdm->faceMap[index].face; int numVerts = ccgSubSurf_getFaceNumVerts(f); int numFinalEdges = numVerts * (gridSideEdges + gridInternalEdges); int origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f)); int g2_wid = gridCuts + 2; float *w, *w2; int s, x, y; #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++; /* set the face base vert */ *((int *)ccgSubSurf_getFaceUserData(ss, f)) = vertNum; #ifndef USE_DYNSIZE BLI_array_empty(loopidx); BLI_array_grow_items(loopidx, numVerts); #endif for (s = 0; s < numVerts; s++) { loopidx[s] = loopindex++; } #ifndef USE_DYNSIZE BLI_array_empty(vertidx); BLI_array_grow_items(vertidx, numVerts); #endif for (s = 0; s < numVerts; s++) { 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); DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2, numVerts, vertNum); if (vertOrigIndex) { *vertOrigIndex = ORIGINDEX_NONE; vertOrigIndex++; } vertNum++; /*interpolate per-vert data*/ for (s = 0; s < numVerts; s++) { for (x = 1; x < gridFaces; x++) { w2 = w + s * numVerts * g2_wid * g2_wid + x * numVerts; DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2, numVerts, vertNum); if (vertOrigIndex) { *vertOrigIndex = ORIGINDEX_NONE; vertOrigIndex++; } vertNum++; } } /*interpolate per-vert data*/ for (s = 0; s < numVerts; s++) { for (y = 1; y < gridFaces; y++) { for (x = 1; x < gridFaces; x++) { w2 = w + s * numVerts * g2_wid * g2_wid + (y * g2_wid + x) * numVerts; DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2, numVerts, vertNum); if (vertOrigIndex) { *vertOrigIndex = ORIGINDEX_NONE; vertOrigIndex++; } vertNum++; } } } if (edgeOrigIndex) { for (i = 0; i < numFinalEdges; ++i) { edgeOrigIndex[edgeNum + i] = ORIGINDEX_NONE; } } for (s = 0; s < numVerts; s++) { /*interpolate per-face data*/ for (y = 0; y < gridFaces; y++) { for (x = 0; x < gridFaces; x++) { w2 = w + s * numVerts * g2_wid * g2_wid + (y * g2_wid + x) * numVerts; CustomData_interp(&dm->loopData, &ccgdm->dm.loopData, loopidx, w2, NULL, numVerts, loopindex2); loopindex2++; w2 = w + s * numVerts * g2_wid * g2_wid + ((y + 1) * g2_wid + (x)) * numVerts; CustomData_interp(&dm->loopData, &ccgdm->dm.loopData, loopidx, w2, NULL, numVerts, loopindex2); loopindex2++; w2 = w + s * numVerts * g2_wid * g2_wid + ((y + 1) * g2_wid + (x + 1)) * numVerts; 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); loopindex2++; /*copy over poly data, e.g. mtexpoly*/ CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, origIndex, faceNum, 1); /*set original index data*/ if (faceOrigIndex) { /* reference the index in 'polyOrigIndex' */ *faceOrigIndex = faceNum; faceOrigIndex++; } if (polyOrigIndex) { *polyOrigIndex = base_polyOrigIndex ? base_polyOrigIndex[origIndex] : origIndex; polyOrigIndex++; } ccgdm->reverseFaceMap[faceNum] = index; /* This is a simple one to one mapping, here... */ if (polyidx) { polyidx[faceNum] = faceNum; } faceNum++; } } } edgeNum += numFinalEdges; } for (index = 0; index < totedge; ++index) { CCGEdge *e = ccgdm->edgeMap[index].edge; int numFinalEdges = edgeSize - 1; int mapIndex = ccgDM_getEdgeMapIndex(ss, e); int x; int vertIdx[2]; int edgeIdx = GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e)); CCGVert *v; v = ccgSubSurf_getEdgeVert0(e); vertIdx[0] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v)); v = ccgSubSurf_getEdgeVert1(e); vertIdx[1] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v)); ccgdm->edgeMap[index].startVert = vertNum; ccgdm->edgeMap[index].startEdge = edgeNum; if (edgeIdx >= 0 && edgeFlags) edgeFlags[edgeIdx] = medge[edgeIdx].flag; /* set the edge base vert */ *((int *)ccgSubSurf_getEdgeUserData(ss, e)) = vertNum; for (x = 1; x < edgeSize - 1; x++) { float w[2]; w[1] = (float) x / (edgeSize - 1); w[0] = 1 - w[1]; DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w, 2, vertNum); if (vertOrigIndex) { *vertOrigIndex = ORIGINDEX_NONE; vertOrigIndex++; } vertNum++; } if (has_edge_cd) { BLI_assert(edgeIdx >= 0 && edgeIdx < dm->getNumEdges(dm)); for (i = 0; i < numFinalEdges; ++i) { CustomData_copy_data(&dm->edgeData, &ccgdm->dm.edgeData, edgeIdx, edgeNum + i, 1); } } if (edgeOrigIndex) { for (i = 0; i < numFinalEdges; ++i) { edgeOrigIndex[edgeNum + i] = mapIndex; } } edgeNum += numFinalEdges; } if (useSubsurfUv) { CustomData *ldata = &ccgdm->dm.loopData; CustomData *dmldata = &dm->loopData; int numlayer = CustomData_number_of_layers(ldata, CD_MLOOPUV); int dmnumlayer = CustomData_number_of_layers(dmldata, CD_MLOOPUV); for (i = 0; i < numlayer && i < dmnumlayer; i++) set_subsurf_uv(ss, dm, &ccgdm->dm, i); } for (index = 0; index < totvert; ++index) { CCGVert *v = ccgdm->vertMap[index].vert; int mapIndex = ccgDM_getVertMapIndex(ccgdm->ss, v); int vertIdx; vertIdx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v)); ccgdm->vertMap[index].startVert = vertNum; /* set the vert base vert */ *((int *) ccgSubSurf_getVertUserData(ss, v)) = vertNum; DM_copy_vert_data(dm, &ccgdm->dm, vertIdx, vertNum, 1); if (vertOrigIndex) { *vertOrigIndex = mapIndex; vertOrigIndex++; } vertNum++; } #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, DerivedMesh *dm) { const int totface = dm->getNumPolys(dm); 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) { #ifdef WITH_OPENSUBDIV const int totedge = dm->getNumEdges(dm); const int totface = dm->getNumPolys(dm); #else const int totedge = ccgSubSurf_getNumEdges(ss); const int totface = ccgSubSurf_getNumFaces(ss); #endif CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm"); if (use_gpu_backend == false) { BLI_assert(totedge == ccgSubSurf_getNumEdges(ss)); BLI_assert(totface == ccgSubSurf_getNumFaces(ss)); DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM, ccgSubSurf_getNumFinalVerts(ss), ccgSubSurf_getNumFinalEdges(ss), 0, ccgSubSurf_getNumFinalFaces(ss) * 4, 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, dm); } ccgdm->dm.numVertData = ccgSubSurf_getNumFinalVerts(ss); ccgdm->dm.numEdgeData = ccgSubSurf_getNumFinalEdges(ss); ccgdm->dm.numPolyData = ccgSubSurf_getNumFinalFaces(ss); ccgdm->dm.numLoopData = ccgdm->dm.numPolyData * 4; ccgdm->dm.numTessFaceData = 0; 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, float (*vertCos)[3], SubsurfFlags flags) { int useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : 0; CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0; 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); #ifdef WITH_OPENSUBDIV ccgSubSurf_setSkipGrids(smd->emCache, use_gpu_backend); #endif ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple, useSubsurfUv); result = getCCGDerivedMesh(smd->emCache, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend); } else if (flags & SUBSURF_USE_RENDER_PARAMS) { /* Do not use cache in render mode. */ CCGSubSurf *ss; int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->renderLevels, true) : smd->renderLevels; if (levels == 0) return dm; ss = _getSubSurf(NULL, levels, 3, useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS); ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv); result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, false); result->freeSS = 1; } else { int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental); int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels; CCGSubSurf *ss; /* It is quite possible there is a much better place to do this. It * depends a bit on how rigorously we expect this function to never * be called in editmode. In semi-theory we could share a single * cache, but the handles used inside and outside editmode are not * the same so we would need some way of converting them. Its probably * not worth the effort. But then why am I even writing this long * comment that no one will read? Hmmm. - zr * * Addendum: we can't really ensure that this is never called in edit * mode, so now we have a parameter to verify it. - brecht */ if (!(flags & SUBSURF_IN_EDIT_MODE) && smd->emCache) { ccgSubSurf_free(smd->emCache); smd->emCache = NULL; } if (useIncremental && (flags & SUBSURF_IS_FINAL_CALC)) { smd->mCache = ss = _getSubSurf(smd->mCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS); ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv); result = getCCGDerivedMesh(smd->mCache, drawInteriorEdges, 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 investigated still to be sure we don't have * regressions here. */ if (use_gpu_backend) { prevSS = smd->mCache; } else #endif { ccgSubSurf_free(smd->mCache); smd->mCache = NULL; } } if (flags & SUBSURF_ALLOC_PAINT_MASK) ccg_flags |= CCG_ALLOC_MASK; 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, useSubsurfUv); result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend); if (flags & SUBSURF_IS_FINAL_CALC) smd->mCache = ss; else result->freeSS = 1; if (flags & SUBSURF_ALLOC_PAINT_MASK) ccgSubSurf_setNumLayers(ss, 4); } } return (DerivedMesh *)result; } void subsurf_calculate_limit_positions(Mesh *me, float (*r_positions)[3]) { /* Finds the subsurf limit positions for the verts in a mesh * and puts them in an array of floats. Please note that the * calculated vert positions is incorrect for the verts * on the boundary of the mesh. */ CCGSubSurf *ss = _getSubSurf(NULL, 1, 3, CCG_USE_ARENA); float edge_sum[3], face_sum[3]; CCGVertIterator vi; DerivedMesh *dm = CDDM_from_mesh(me); ss_sync_from_derivedmesh(ss, dm, NULL, 0, 0); for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) { CCGVert *v = ccgVertIterator_getCurrent(&vi); int idx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v)); int N = ccgSubSurf_getVertNumEdges(v); int numFaces = ccgSubSurf_getVertNumFaces(v); float *co; int i; zero_v3(edge_sum); zero_v3(face_sum); for (i = 0; i < N; i++) { CCGEdge *e = ccgSubSurf_getVertEdge(v, i); add_v3_v3v3(edge_sum, edge_sum, ccgSubSurf_getEdgeData(ss, e, 1)); } for (i = 0; i < numFaces; i++) { CCGFace *f = ccgSubSurf_getVertFace(v, i); add_v3_v3(face_sum, ccgSubSurf_getFaceCenterData(f)); } /* ad-hoc correction for boundary vertices, to at least avoid them * moving completely out of place (brecht) */ if (numFaces && numFaces != N) mul_v3_fl(face_sum, (float)N / (float)numFaces); co = ccgSubSurf_getVertData(ss, v); r_positions[idx][0] = (co[0] * N * N + edge_sum[0] * 4 + face_sum[0]) / (N * (N + 5)); r_positions[idx][1] = (co[1] * N * N + edge_sum[1] * 4 + face_sum[1]) / (N * (N + 5)); r_positions[idx][2] = (co[2] * N * N + edge_sum[2] * 4 + face_sum[2]) / (N * (N + 5)); } ccgSubSurf_free(ss); dm->release(dm); } bool subsurf_has_edges(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { return true; } #else (void)ccgdm; #endif return dm->getNumEdges(dm) != 0; } bool subsurf_has_faces(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { return true; } #else (void)ccgdm; #endif return dm->getNumPolys(dm) != 0; }