diff options
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_DerivedMesh.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/DerivedMesh.c | 120 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cdderivedmesh.c | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/editderivedmesh.c | 221 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/subsurf_ccg.c | 1 |
5 files changed, 246 insertions, 101 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 2eac1a07daf..e6d5b89e6ef 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -209,6 +209,8 @@ struct DerivedMesh { void (*calcLoopNormalsSpaceArray)(DerivedMesh *dm, const bool use_split_normals, const float split_angle, struct MLoopNorSpaceArray *r_lnors_spacearr); + void (*calcLoopTangents)(DerivedMesh *dm); + /** Recalculates mesh tessellation */ void (*recalcTessellation)(DerivedMesh *dm); @@ -771,7 +773,7 @@ void DM_vertex_attributes_from_gpu( void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, int loop); -void DM_add_tangent_layer(DerivedMesh *dm); +void DM_calc_loop_tangents(DerivedMesh *dm); void DM_calc_auto_bump_scale(DerivedMesh *dm); /** Set object's bounding box based on DerivedMesh min/max data */ diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 6c13c791da9..c470b48a9d5 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -3070,7 +3070,7 @@ static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[ pRes[3] = fSign; } -void DM_add_tangent_layer(DerivedMesh *dm) +void DM_calc_loop_tangents(DerivedMesh *dm) { /* mesh vars */ const MLoopTri *looptri; @@ -3296,6 +3296,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs, { CustomData *vdata, *ldata; int a, b, layer; + const bool is_editmesh = (dm->type == DM_TYPE_EDITBMESH); /* From the layers requested by the GLSL shader, figure out which ones are * actually available for this derivedmesh, and retrieve the pointers */ @@ -3312,115 +3313,64 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs, /* add a tangent layer if necessary */ for (b = 0; b < gattribs->totlayer; b++) { if (gattribs->layer[b].type == CD_TANGENT) { - if (CustomData_get_layer_index(ldata, CD_TANGENT) == -1) { - DM_add_tangent_layer(dm); - break; + if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) { + dm->calcLoopTangents(dm); } + break; } } for (b = 0; b < gattribs->totlayer; b++) { if (gattribs->layer[b].type == CD_MTFACE) { /* uv coordinates */ - if (dm->type == DM_TYPE_EDITBMESH) { - /* exception .. */ - CustomData *ldata = dm->getLoopDataLayout(dm); - - if (gattribs->layer[b].name[0]) - layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, - gattribs->layer[b].name); - else - layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV); - - a = attribs->tottface++; + if (gattribs->layer[b].name[0]) + layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name); + else + layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV); - if (layer != -1) { - attribs->tface[a].array = NULL; - attribs->tface[a].em_offset = ldata->layers[layer].offset; - } - else { - attribs->tface[a].array = NULL; - attribs->tface[a].em_offset = -1; - } + a = attribs->tottface++; - attribs->tface[a].gl_index = gattribs->layer[b].glindex; - attribs->tface[a].gl_texco = gattribs->layer[b].gltexco; + if (layer != -1) { + attribs->tface[a].array = is_editmesh ? NULL: ldata->layers[layer].data; + attribs->tface[a].em_offset = ldata->layers[layer].offset; } else { - if (gattribs->layer[b].name[0]) - layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, - gattribs->layer[b].name); - else - layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV); - - a = attribs->tottface++; - - if (layer != -1) { - attribs->tface[a].array = ldata->layers[layer].data; - attribs->tface[a].em_offset = ldata->layers[layer].offset; - } - else { - attribs->tface[a].array = NULL; - attribs->tface[a].em_offset = -1; - } - - attribs->tface[a].gl_index = gattribs->layer[b].glindex; - attribs->tface[a].gl_texco = gattribs->layer[b].gltexco; + attribs->tface[a].array = NULL; + attribs->tface[a].em_offset = -1; } + + attribs->tface[a].gl_index = gattribs->layer[b].glindex; + attribs->tface[a].gl_texco = gattribs->layer[b].gltexco; } else if (gattribs->layer[b].type == CD_MCOL) { - if (dm->type == DM_TYPE_EDITBMESH) { - if (gattribs->layer[b].name[0]) - layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, - gattribs->layer[b].name); - else - layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL); - - a = attribs->totmcol++; + if (gattribs->layer[b].name[0]) + layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name); + else + layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL); - if (layer != -1) { - attribs->mcol[a].array = NULL; - /* odd, store the offset for a different layer type here, but editmode draw code expects it */ - attribs->mcol[a].em_offset = ldata->layers[layer].offset; - } - else { - attribs->mcol[a].array = NULL; - attribs->mcol[a].em_offset = -1; - } + a = attribs->totmcol++; - attribs->mcol[a].gl_index = gattribs->layer[b].glindex; + if (layer != -1) { + attribs->mcol[a].array = is_editmesh ? NULL: ldata->layers[layer].data; + /* odd, store the offset for a different layer type here, but editmode draw code expects it */ + attribs->mcol[a].em_offset = ldata->layers[layer].offset; } else { - /* vertex colors */ - if (gattribs->layer[b].name[0]) - layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, - gattribs->layer[b].name); - else - layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL); - - a = attribs->totmcol++; - - if (layer != -1) { - attribs->mcol[a].array = ldata->layers[layer].data; - /* odd, store the offset for a different layer type here, but editmode draw code expects it */ - attribs->mcol[a].em_offset = ldata->layers[layer].offset; - } - else { - attribs->mcol[a].array = NULL; - attribs->mcol[a].em_offset = -1; - } - - attribs->mcol[a].gl_index = gattribs->layer[b].glindex; + attribs->mcol[a].array = NULL; + attribs->mcol[a].em_offset = -1; } + + attribs->mcol[a].gl_index = gattribs->layer[b].glindex; } else if (gattribs->layer[b].type == CD_TANGENT) { - layer = CustomData_get_layer_index(ldata, CD_TANGENT); + /* note, even with 'is_editmesh' this uses the derived-meshes loop data */ + layer = CustomData_get_layer_index(&dm->loopData, CD_TANGENT); attribs->tottang = 1; if (layer != -1) { - attribs->tang.array = ldata->layers[layer].data; - attribs->tang.em_offset = ldata->layers[layer].offset; + attribs->tang.array = dm->loopData.layers[layer].data; + attribs->tang.em_offset = dm->loopData.layers[layer].offset; } else { attribs->tang.array = NULL; diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 19c4e66f7eb..c3168c0d6af 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -1957,6 +1957,7 @@ static CDDerivedMesh *cdDM_create(const char *desc) dm->calcNormals = CDDM_calc_normals; dm->calcLoopNormals = CDDM_calc_loop_normals; dm->calcLoopNormalsSpaceArray = CDDM_calc_loop_normals_spacearr; + dm->calcLoopTangents = DM_calc_loop_tangents; dm->recalcTessellation = CDDM_recalc_tessellation; dm->recalcLoopTri = CDDM_recalc_looptri; diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index 8158411c2e4..f463cab1a10 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -237,6 +237,184 @@ static void emDM_calcLoopNormalsSpaceArray( #endif } + +typedef struct { + const float (*precomputedFaceNormals)[3]; + const float (*precomputedLoopNormals)[3]; + BMLoop *(*looptris)[3]; + int cd_loop_uv_offset; /* texture coordinates */ + const float (*orco)[3]; + float (*tangent)[4]; /* destination */ + int numTessFaces; + +} SGLSLEditMeshToTangent; + +/* interface */ +#include "mikktspace.h" + +static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext) +{ + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + return pMesh->numTessFaces; +} + +static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) +{ + //SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + UNUSED_VARS(pContext, face_num); + return 3; +} + +static void emdm_ts_GetPosition( + const SMikkTSpaceContext *pContext, float r_co[3], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + BMLoop **lt = pMesh->looptris[face_num]; + const float *co = lt[vert_index]->v->co; + copy_v3_v3(r_co, co); +} + +static void emdm_ts_GetTextureCoordinate( + const SMikkTSpaceContext *pContext, float r_uv[2], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + BMLoop **lt = pMesh->looptris[face_num]; + + if (pMesh->cd_loop_uv_offset != -1) { + const float *uv = BM_ELEM_CD_GET_VOID_P(lt[vert_index], pMesh->cd_loop_uv_offset); + copy_v2_v2(r_uv, uv); + } + else { + const float *orco = pMesh->orco[BM_elem_index_get(lt[vert_index]->v)]; + map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]); + } +} + +static void emdm_ts_GetNormal( + const SMikkTSpaceContext *pContext, float r_no[3], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + BMLoop **lt = pMesh->looptris[face_num]; + const bool smoothnormal = BM_elem_flag_test_bool(lt[0]->f, BM_ELEM_SMOOTH); + + if (pMesh->precomputedLoopNormals) { + copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(lt[vert_index])]); + } + else if (!smoothnormal) { + if (pMesh->precomputedFaceNormals) { + copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(lt[0]->f)]); + } + else { + copy_v3_v3(r_no, lt[0]->f->no); + } + } + else { + copy_v3_v3(r_no, lt[vert_index]->v->no); + } +} + +static void emdm_ts_SetTSpace( + const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + BMLoop **lt = pMesh->looptris[face_num]; + float *pRes = pMesh->tangent[BM_elem_index_get(lt[vert_index])]; + copy_v3_v3(pRes, fvTangent); + pRes[3] = fSign; +} + +/** + * \see #DM_calc_loop_tangents, same logic but used arrays instead of #BMesh data. + * + * \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`. + * This is done because #CD_TANGENT is cache data used only for drawing. + */ +static void emDM_calcLoopTangents(DerivedMesh *dm) +{ + EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; + BMEditMesh *em = bmdm->em; + BMesh *bm = bmdm->em->bm; + + /* mesh vars */ + int cd_loop_uv_offset; + float (*orco)[3] = NULL, (*tangent)[4]; + int /* totvert, */ totface; + const float (*fnors)[3]; + const float (*tlnors)[3]; + char htype_index = BM_LOOP; + + if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) != -1) + return; + + fnors = bmdm->polyNos; /* dm->getPolyDataArray(dm, CD_NORMAL) */ + + /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled), + * have to check this is valid... + */ + tlnors = dm->getLoopDataArray(dm, CD_NORMAL); + + /* check we have all the needed layers */ + totface = em->tottri; + + cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + /* needed for indexing loop-tangents */ + htype_index = BM_LOOP; + if (cd_loop_uv_offset == -1) { + orco = dm->getVertDataArray(dm, CD_ORCO); + if (!orco) + return; + /* needed for orco lookups */ + htype_index |= BM_VERT; + } + + if (fnors) { + /* needed for face normal lookups */ + htype_index |= BM_FACE; + } + + BM_mesh_elem_index_ensure(bm, htype_index); + + /* create tangent layer */ + DM_add_loop_layer(dm, CD_TANGENT, CD_CALLOC, NULL); + tangent = DM_get_loop_data_layer(dm, CD_TANGENT); + + /* new computation method */ + { + SGLSLEditMeshToTangent mesh2tangent = {NULL}; + SMikkTSpaceContext sContext = {NULL}; + SMikkTSpaceInterface sInterface = {NULL}; + + mesh2tangent.precomputedFaceNormals = fnors; + mesh2tangent.precomputedLoopNormals = tlnors; + mesh2tangent.looptris = em->looptris; + mesh2tangent.cd_loop_uv_offset = cd_loop_uv_offset; + mesh2tangent.orco = orco; + mesh2tangent.tangent = tangent; + mesh2tangent.numTessFaces = totface; + + sContext.m_pUserData = &mesh2tangent; + sContext.m_pInterface = &sInterface; + sInterface.m_getNumFaces = emdm_ts_GetNumFaces; + sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace; + sInterface.m_getPosition = emdm_ts_GetPosition; + sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate; + sInterface.m_getNormal = emdm_ts_GetNormal; + sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace; + + /* 0 if failed */ + genTangSpaceDefault(&sContext); + } +} + static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm)) { /* do nothing */ @@ -1035,7 +1213,7 @@ static void emDM_drawMappedFacesTex( * ... because the material may use layer names to select different UV's * see: [#34378] */ -static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const BMLoop *loop, const int index_in_face, const int face_index) +static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const BMLoop *loop) { BMVert *eve = loop->v; int i; @@ -1078,8 +1256,13 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B glVertexAttrib4ubvARB(attribs->mcol[i].gl_index, col); } if (attribs->tottang) { - int index = face_index * 4 + index_in_face; - const float *tang = (attribs->tang.array) ? attribs->tang.array[index] : zero; + const float *tang; + if (attribs->tang.em_offset != -1) { + tang = attribs->tang.array[BM_elem_index_get(loop)]; + } + else { + tang = zero; + } glVertexAttrib4fvARB(attribs->tang.gl_index, tang); } } @@ -1119,7 +1302,7 @@ static void emDM_drawMappedFacesGLSL( /* always use smooth shading even for flat faces, else vertex colors wont interpolate */ glShadeModel(GL_SMOOTH); - BM_mesh_elem_index_ensure(bm, lnors ? BM_VERT | BM_FACE | BM_LOOP : BM_VERT | BM_FACE); + BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0)); for (i = 0; i < em->tottri; i++) { BMLoop **ltri = looptris[i]; @@ -1130,14 +1313,19 @@ static void emDM_drawMappedFacesGLSL( if (setDrawOptions && (setDrawOptions(userData, BM_elem_index_get(efa)) == DM_DRAW_OPTION_SKIP)) continue; + /* material */ new_matnr = efa->mat_nr + 1; if (new_matnr != matnr) { if (matnr != -1) glEnd(); do_draw = setMaterial(matnr = new_matnr, &gattribs); - if (do_draw) + if (do_draw) { DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); + if (UNLIKELY(attribs.tottang && bm->elem_index_dirty & BM_LOOP)) { + BM_mesh_elem_index_ensure(bm, BM_LOOP); + } + } glBegin(GL_TRIANGLES); } @@ -1151,14 +1339,14 @@ static void emDM_drawMappedFacesGLSL( if (vertexCos) { glNormal3fv(polyNos[BM_elem_index_get(efa)]); for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]); } } else { glNormal3fv(efa->no); for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); glVertex3fv(ltri[fi]->v->co); } } @@ -1167,7 +1355,7 @@ static void emDM_drawMappedFacesGLSL( if (vertexCos) { for (fi = 0; fi < 3; fi++) { const int j = BM_elem_index_get(ltri[fi]->v); - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); else glNormal3fv(vertexNos[j]); glVertex3fv(vertexCos[j]); @@ -1175,7 +1363,7 @@ static void emDM_drawMappedFacesGLSL( } else { for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); else glNormal3fv(ltri[fi]->v->no); glVertex3fv(ltri[fi]->v->co); @@ -1225,8 +1413,7 @@ static void emDM_drawMappedFacesMat( /* always use smooth shading even for flat faces, else vertex colors wont interpolate */ glShadeModel(GL_SMOOTH); - - BM_mesh_elem_index_ensure(bm, lnors ? BM_VERT | BM_FACE | BM_LOOP : BM_VERT | BM_FACE); + BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0)); for (i = 0; i < em->tottri; i++) { BMLoop **ltri = looptris[i]; @@ -1246,6 +1433,9 @@ static void emDM_drawMappedFacesMat( setMaterial(userData, matnr = new_matnr, &gattribs); DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); + if (UNLIKELY(attribs.tottang && bm->elem_index_dirty & BM_LOOP)) { + BM_mesh_elem_index_ensure(bm, BM_LOOP); + } glBegin(GL_TRIANGLES); } @@ -1257,14 +1447,14 @@ static void emDM_drawMappedFacesMat( if (vertexCos) { glNormal3fv(polyNos[BM_elem_index_get(efa)]); for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]); } } else { glNormal3fv(efa->no); for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); glVertex3fv(ltri[fi]->v->co); } } @@ -1273,7 +1463,7 @@ static void emDM_drawMappedFacesMat( if (vertexCos) { for (fi = 0; fi < 3; fi++) { const int j = BM_elem_index_get(ltri[fi]->v); - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); else glNormal3fv(vertexNos[j]); glVertex3fv(vertexCos[j]); @@ -1281,7 +1471,7 @@ static void emDM_drawMappedFacesMat( } else { for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi], fi, i); + emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); else glNormal3fv(ltri[fi]->v->no); glVertex3fv(ltri[fi]->v->co); @@ -1864,6 +2054,7 @@ DerivedMesh *getEditDerivedBMesh( bmdm->dm.calcNormals = emDM_calcNormals; bmdm->dm.calcLoopNormals = emDM_calcLoopNormals; bmdm->dm.calcLoopNormalsSpaceArray = emDM_calcLoopNormalsSpaceArray; + bmdm->dm.calcLoopTangents = emDM_calcLoopTangents; bmdm->dm.recalcTessellation = emDM_recalcTessellation; bmdm->dm.recalcLoopTri = emDM_recalcLoopTri; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 94872dc9bd9..903648b5e39 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -4096,6 +4096,7 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm) 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; |