コード例 #1
0
ファイル: mesh_convert.c プロジェクト: wangyxuan/blender
/* This is a Mesh-based copy of the same function in DerivedMesh.c */
static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int actshape_uid)
{
  KeyBlock *kb;
  int i, j, tot;

  if (!mesh_dst->key) {
    return;
  }

  tot = CustomData_number_of_layers(&mesh_src->vdata, CD_SHAPEKEY);
  for (i = 0; i < tot; i++) {
    CustomDataLayer *layer =
        &mesh_src->vdata.layers[CustomData_get_layer_index_n(&mesh_src->vdata, CD_SHAPEKEY, i)];
    float(*cos)[3], (*kbcos)[3];

    for (kb = mesh_dst->key->block.first; kb; kb = kb->next) {
      if (kb->uid == layer->uid) {
        break;
      }
    }

    if (!kb) {
      kb = BKE_keyblock_add(mesh_dst->key, layer->name);
      kb->uid = layer->uid;
    }

    if (kb->data) {
      MEM_freeN(kb->data);
    }

    cos = CustomData_get_layer_n(&mesh_src->vdata, CD_SHAPEKEY, i);
    kb->totelem = mesh_src->totvert;

    kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, 3 * sizeof(float), __func__);
    if (kb->uid == actshape_uid) {
      MVert *mvert = mesh_src->mvert;

      for (j = 0; j < mesh_src->totvert; j++, kbcos++, mvert++) {
        copy_v3_v3(*kbcos, mvert->co);
      }
    }
    else {
      for (j = 0; j < kb->totelem; j++, cos++, kbcos++) {
        copy_v3_v3(*kbcos, *cos);
      }
    }
  }

  for (kb = mesh_dst->key->block.first; kb; kb = kb->next) {
    if (kb->totelem != mesh_src->totvert) {
      if (kb->data) {
        MEM_freeN(kb->data);
      }

      kb->totelem = mesh_src->totvert;
      kb->data = MEM_calloc_arrayN(kb->totelem, 3 * sizeof(float), __func__);
      CLOG_ERROR(&LOG, "lost a shapekey layer: '%s'! (bmesh internal error)", kb->name);
    }
  }
}
コード例 #2
0
static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights)
{
  const MPoly *mpoly = mesh->mpoly;
  const MLoop *mloop = mesh->mloop;
  const MEdge *medge = mesh->medge;
  unsigned int mpoly_num, medge_num, i;
  unsigned short *boundaries;

  mpoly_num = (unsigned int)mesh->totpoly;
  medge_num = (unsigned int)mesh->totedge;

  boundaries = MEM_calloc_arrayN(medge_num, sizeof(*boundaries), __func__);

  /* count the number of adjacent faces */
  for (i = 0; i < mpoly_num; i++) {
    const MPoly *p = &mpoly[i];
    const int totloop = p->totloop;
    int j;
    for (j = 0; j < totloop; j++) {
      boundaries[mloop[p->loopstart + j].e]++;
    }
  }

  for (i = 0; i < medge_num; i++) {
    if (boundaries[i] == 1) {
      smooth_weights[medge[i].v1] = 0.0f;
      smooth_weights[medge[i].v2] = 0.0f;
    }
  }

  MEM_freeN(boundaries);
}
コード例 #3
0
ファイル: multires_reshape.c プロジェクト: dfelinto/blender
static void multires_reshape_allocate_displacement_grid(MDisps *displacement_grid, const int level)
{
  const int grid_size = BKE_subdiv_grid_size_from_level(level);
  const int grid_area = grid_size * grid_size;
  float(*disps)[3] = MEM_calloc_arrayN(grid_area, 3 * sizeof(float), "multires disps");
  if (displacement_grid->disps != NULL) {
    MEM_freeN(displacement_grid->disps);
  }
  displacement_grid->disps = disps;
  displacement_grid->totdisp = grid_area;
  displacement_grid->level = level;
}
コード例 #4
0
ファイル: mesh_convert.c プロジェクト: wangyxuan/blender
static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src)
{
  KeyBlock *kb;
  Key *key = mesh_src->key;
  int i;

  if (!mesh_src->key) {
    return;
  }

  /* ensure we can use mesh vertex count for derived mesh custom data */
  if (mesh_src->totvert != mesh_dest->totvert) {
    CLOG_ERROR(&LOG,
               "vertex size mismatch (mesh/dm) '%s' (%d != %d)",
               mesh_src->id.name + 2,
               mesh_src->totvert,
               mesh_dest->totvert);
    return;
  }

  for (i = 0, kb = key->block.first; kb; kb = kb->next, i++) {
    int ci;
    float *array;

    if (mesh_src->totvert != kb->totelem) {
      CLOG_ERROR(&LOG,
                 "vertex size mismatch (Mesh '%s':%d != KeyBlock '%s':%d)",
                 mesh_src->id.name + 2,
                 mesh_src->totvert,
                 kb->name,
                 kb->totelem);
      array = MEM_calloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__);
    }
    else {
      array = MEM_malloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__);
      memcpy(array, kb->data, (size_t)mesh_src->totvert * 3 * sizeof(float));
    }

    CustomData_add_layer_named(
        &mesh_dest->vdata, CD_SHAPEKEY, CD_ASSIGN, array, mesh_dest->totvert, kb->name);
    ci = CustomData_get_layer_index_n(&mesh_dest->vdata, CD_SHAPEKEY, i);

    mesh_dest->vdata.layers[ci].uid = kb->uid;
  }
}
コード例 #5
0
static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numPolys, int a_numLoops, int a_numVerts)
{
	LaplacianSystem *sys;
	sys = MEM_callocN(sizeof(LaplacianSystem), "ModLaplSmoothSystem");
	sys->numEdges = a_numEdges;
	sys->numPolys = a_numPolys;
	sys->numLoops = a_numLoops;
	sys->numVerts = a_numVerts;

	sys->eweights =  MEM_calloc_arrayN(sys->numEdges, sizeof(float), __func__);
	sys->fweights =  MEM_calloc_arrayN(sys->numLoops, sizeof(float[3]), __func__);
	sys->numNeEd =  MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__);
	sys->numNeFa =  MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__);
	sys->ring_areas =  MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__);
	sys->vlengths =  MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__);
	sys->vweights =  MEM_calloc_arrayN(sys->numVerts, sizeof(float), __func__);
	sys->zerola =  MEM_calloc_arrayN(sys->numVerts, sizeof(short), __func__);

	return sys;
}
コード例 #6
0
/**
 * This calculates #CorrectiveSmoothModifierData.delta_cache
 * It's not run on every update (during animation for example).
 */
static void calc_deltas(CorrectiveSmoothModifierData *csmd,
                        Mesh *mesh,
                        MDeformVert *dvert,
                        const int defgrp_index,
                        const float (*rest_coords)[3],
                        unsigned int numVerts)
{
  float(*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords);
  float(*tangent_spaces)[3][3];
  unsigned int i;

  tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__);

  if (csmd->delta_cache_num != numVerts) {
    MEM_SAFE_FREE(csmd->delta_cache);
  }

  /* allocate deltas if they have not yet been allocated, otheriwse we will just write over them */
  if (!csmd->delta_cache) {
    csmd->delta_cache_num = numVerts;
    csmd->delta_cache = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__);
  }

  smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, numVerts);

  calc_tangent_spaces(mesh, smooth_vertex_coords, tangent_spaces);

  for (i = 0; i < numVerts; i++) {
    float imat[3][3], delta[3];

#ifdef USE_TANGENT_CALC_INLINE
    calc_tangent_ortho(tangent_spaces[i]);
#endif

    sub_v3_v3v3(delta, rest_coords[i], smooth_vertex_coords[i]);
    if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) {
      transpose_m3_m3(imat, tangent_spaces[i]);
    }
    mul_v3_m3v3(csmd->delta_cache[i], imat, delta);
  }

  MEM_freeN(tangent_spaces);
  MEM_freeN(smooth_vertex_coords);
}
コード例 #7
0
ファイル: multires_reshape.c プロジェクト: dfelinto/blender
static void multires_reshape_ensure_mask_grids(Mesh *mesh, const int grid_level)
{
  GridPaintMask *grid_paint_masks = CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
  if (grid_paint_masks == NULL) {
    return;
  }
  const int num_grids = mesh->totloop;
  const int grid_size = BKE_subdiv_grid_size_from_level(grid_level);
  const int grid_area = grid_size * grid_size;
  for (int grid_index = 0; grid_index < num_grids; grid_index++) {
    GridPaintMask *grid_paint_mask = &grid_paint_masks[grid_index];
    if (grid_paint_mask->level == grid_level) {
      continue;
    }
    grid_paint_mask->level = grid_level;
    if (grid_paint_mask->data) {
      MEM_freeN(grid_paint_mask->data);
    }
    grid_paint_mask->data = MEM_calloc_arrayN(grid_area, sizeof(float), "gpm.data");
  }
}
コード例 #8
0
ファイル: MOD_util.c プロジェクト: Ichthyostega/blender
void get_texture_coords(
        MappingInfoModifierData *dmd, Object *ob,
        DerivedMesh *dm,
        float (*co)[3], float (*texco)[3],
        int numVerts)
{
	int i;
	int texmapping = dmd->texmapping;
	float mapob_imat[4][4];

	if (texmapping == MOD_DISP_MAP_OBJECT) {
		if (dmd->map_object)
			invert_m4_m4(mapob_imat, dmd->map_object->obmat);
		else /* if there is no map object, default to local */
			texmapping = MOD_DISP_MAP_LOCAL;
	}

	/* UVs need special handling, since they come from faces */
	if (texmapping == MOD_DISP_MAP_UV) {
		if (CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
			MPoly *mpoly = dm->getPolyArray(dm);
			MPoly *mp;
			MLoop *mloop = dm->getLoopArray(dm);
			char *done = MEM_calloc_arrayN(numVerts, sizeof(*done),
			                         "get_texture_coords done");
			int numPolys = dm->getNumPolys(dm);
			char uvname[MAX_CUSTOMDATA_LAYER_NAME];
			MLoopUV *mloop_uv;

			CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, dmd->uvlayer_name, uvname);
			mloop_uv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);

			/* verts are given the UV from the first face that uses them */
			for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) {
				unsigned int fidx = mp->totloop - 1;

				do {
					unsigned int lidx = mp->loopstart + fidx;
					unsigned int vidx = mloop[lidx].v;

					if (done[vidx] == 0) {
						/* remap UVs from [0, 1] to [-1, 1] */
						texco[vidx][0] = (mloop_uv[lidx].uv[0] * 2.0f) - 1.0f;
						texco[vidx][1] = (mloop_uv[lidx].uv[1] * 2.0f) - 1.0f;
						done[vidx] = 1;
					}

				} while (fidx--);
			}

			MEM_freeN(done);
			return;
		}
		else /* if there are no UVs, default to local */
			texmapping = MOD_DISP_MAP_LOCAL;
	}

	for (i = 0; i < numVerts; ++i, ++co, ++texco) {
		switch (texmapping) {
			case MOD_DISP_MAP_LOCAL:
				copy_v3_v3(*texco, *co);
				break;
			case MOD_DISP_MAP_GLOBAL:
				mul_v3_m4v3(*texco, ob->obmat, *co);
				break;
			case MOD_DISP_MAP_OBJECT:
				mul_v3_m4v3(*texco, ob->obmat, *co);
				mul_m4_v3(mapob_imat, *texco);
				break;
		}
	}
}
コード例 #9
0
ファイル: mesh_convert.c プロジェクト: wangyxuan/blender
void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int edge_users_test)
{
  MVert *mvert = me->mvert;
  MEdge *med, *medge = me->medge;
  MPoly *mp, *mpoly = me->mpoly;
  MLoop *mloop = me->mloop;

  int medge_len = me->totedge;
  int mpoly_len = me->totpoly;
  int totedges = 0;
  int i;

  /* only to detect edge polylines */
  int *edge_users;

  ListBase edges = {NULL, NULL};

  /* get boundary edges */
  edge_users = MEM_calloc_arrayN(medge_len, sizeof(int), __func__);
  for (i = 0, mp = mpoly; i < mpoly_len; i++, mp++) {
    MLoop *ml = &mloop[mp->loopstart];
    int j;
    for (j = 0; j < mp->totloop; j++, ml++) {
      edge_users[ml->e]++;
    }
  }

  /* create edges from all faces (so as to find edges not in any faces) */
  med = medge;
  for (i = 0; i < medge_len; i++, med++) {
    if (edge_users[i] == edge_users_test) {
      EdgeLink *edl = MEM_callocN(sizeof(EdgeLink), "EdgeLink");
      edl->edge = med;

      BLI_addtail(&edges, edl);
      totedges++;
    }
  }
  MEM_freeN(edge_users);

  if (edges.first) {
    while (edges.first) {
      /* each iteration find a polyline and add this as a nurbs poly spline */

      ListBase polyline = {NULL, NULL}; /* store a list of VertLink's */
      bool closed = false;
      int totpoly = 0;
      MEdge *med_current = ((EdgeLink *)edges.last)->edge;
      unsigned int startVert = med_current->v1;
      unsigned int endVert = med_current->v2;
      bool ok = true;

      appendPolyLineVert(&polyline, startVert);
      totpoly++;
      appendPolyLineVert(&polyline, endVert);
      totpoly++;
      BLI_freelinkN(&edges, edges.last);
      totedges--;

      while (ok) { /* while connected edges are found... */
        EdgeLink *edl = edges.last;
        ok = false;
        while (edl) {
          EdgeLink *edl_prev = edl->prev;

          med = edl->edge;

          if (med->v1 == endVert) {
            endVert = med->v2;
            appendPolyLineVert(&polyline, med->v2);
            totpoly++;
            BLI_freelinkN(&edges, edl);
            totedges--;
            ok = true;
          }
          else if (med->v2 == endVert) {
            endVert = med->v1;
            appendPolyLineVert(&polyline, endVert);
            totpoly++;
            BLI_freelinkN(&edges, edl);
            totedges--;
            ok = true;
          }
          else if (med->v1 == startVert) {
            startVert = med->v2;
            prependPolyLineVert(&polyline, startVert);
            totpoly++;
            BLI_freelinkN(&edges, edl);
            totedges--;
            ok = true;
          }
          else if (med->v2 == startVert) {
            startVert = med->v1;
            prependPolyLineVert(&polyline, startVert);
            totpoly++;
            BLI_freelinkN(&edges, edl);
            totedges--;
            ok = true;
          }

          edl = edl_prev;
        }
      }

      /* Now we have a polyline, make into a curve */
      if (startVert == endVert) {
        BLI_freelinkN(&polyline, polyline.last);
        totpoly--;
        closed = true;
      }

      /* --- nurbs --- */
      {
        Nurb *nu;
        BPoint *bp;
        VertLink *vl;

        /* create new 'nurb' within the curve */
        nu = (Nurb *)MEM_callocN(sizeof(Nurb), "MeshNurb");

        nu->pntsu = totpoly;
        nu->pntsv = 1;
        nu->orderu = 4;
        nu->flagu = CU_NURB_ENDPOINT | (closed ? CU_NURB_CYCLIC : 0); /* endpoint */
        nu->resolu = 12;

        nu->bp = (BPoint *)MEM_calloc_arrayN(totpoly, sizeof(BPoint), "bpoints");

        /* add points */
        vl = polyline.first;
        for (i = 0, bp = nu->bp; i < totpoly; i++, bp++, vl = (VertLink *)vl->next) {
          copy_v3_v3(bp->vec, mvert[vl->index].co);
          bp->f1 = SELECT;
          bp->radius = bp->weight = 1.0;
        }
        BLI_freelistN(&polyline);

        /* add nurb to curve */
        BLI_addtail(nurblist, nu);
      }
      /* --- done with nurbs --- */
    }
  }
}
コード例 #10
0
ファイル: mesh_convert.c プロジェクト: wangyxuan/blender
/* use specified dispbase */
int BKE_mesh_nurbs_displist_to_mdata(Object *ob,
                                     const ListBase *dispbase,
                                     MVert **r_allvert,
                                     int *r_totvert,
                                     MEdge **r_alledge,
                                     int *r_totedge,
                                     MLoop **r_allloop,
                                     MPoly **r_allpoly,
                                     MLoopUV **r_alluv,
                                     int *r_totloop,
                                     int *r_totpoly)
{
  Curve *cu = ob->data;
  DispList *dl;
  MVert *mvert;
  MPoly *mpoly;
  MLoop *mloop;
  MLoopUV *mloopuv = NULL;
  MEdge *medge;
  const float *data;
  int a, b, ofs, vertcount, startvert, totvert = 0, totedge = 0, totloop = 0, totpoly = 0;
  int p1, p2, p3, p4, *index;
  const bool conv_polys = ((CU_DO_2DFILL(cu) ==
                            false) || /* 2d polys are filled with DL_INDEX3 displists */
                           (ob->type == OB_SURF)); /* surf polys are never filled */

  /* count */
  dl = dispbase->first;
  while (dl) {
    if (dl->type == DL_SEGM) {
      totvert += dl->parts * dl->nr;
      totedge += dl->parts * (dl->nr - 1);
    }
    else if (dl->type == DL_POLY) {
      if (conv_polys) {
        totvert += dl->parts * dl->nr;
        totedge += dl->parts * dl->nr;
      }
    }
    else if (dl->type == DL_SURF) {
      int tot;
      totvert += dl->parts * dl->nr;
      tot = (dl->parts - 1 + ((dl->flag & DL_CYCL_V) == 2)) *
            (dl->nr - 1 + (dl->flag & DL_CYCL_U));
      totpoly += tot;
      totloop += tot * 4;
    }
    else if (dl->type == DL_INDEX3) {
      int tot;
      totvert += dl->nr;
      tot = dl->parts;
      totpoly += tot;
      totloop += tot * 3;
    }
    dl = dl->next;
  }

  if (totvert == 0) {
    /* error("can't convert"); */
    /* Make Sure you check ob->data is a curve */
    return -1;
  }

  *r_allvert = mvert = MEM_calloc_arrayN(totvert, sizeof(MVert), "nurbs_init mvert");
  *r_alledge = medge = MEM_calloc_arrayN(totedge, sizeof(MEdge), "nurbs_init medge");
  *r_allloop = mloop = MEM_calloc_arrayN(
      totpoly, 4 * sizeof(MLoop), "nurbs_init mloop");  // totloop
  *r_allpoly = mpoly = MEM_calloc_arrayN(totpoly, sizeof(MPoly), "nurbs_init mloop");

  if (r_alluv) {
    *r_alluv = mloopuv = MEM_calloc_arrayN(totpoly, 4 * sizeof(MLoopUV), "nurbs_init mloopuv");
  }

  /* verts and faces */
  vertcount = 0;

  dl = dispbase->first;
  while (dl) {
    const bool is_smooth = (dl->rt & CU_SMOOTH) != 0;

    if (dl->type == DL_SEGM) {
      startvert = vertcount;
      a = dl->parts * dl->nr;
      data = dl->verts;
      while (a--) {
        copy_v3_v3(mvert->co, data);
        data += 3;
        vertcount++;
        mvert++;
      }

      for (a = 0; a < dl->parts; a++) {
        ofs = a * dl->nr;
        for (b = 1; b < dl->nr; b++) {
          medge->v1 = startvert + ofs + b - 1;
          medge->v2 = startvert + ofs + b;
          medge->flag = ME_LOOSEEDGE | ME_EDGERENDER | ME_EDGEDRAW;

          medge++;
        }
      }
    }
    else if (dl->type == DL_POLY) {
      if (conv_polys) {
        startvert = vertcount;
        a = dl->parts * dl->nr;
        data = dl->verts;
        while (a--) {
          copy_v3_v3(mvert->co, data);
          data += 3;
          vertcount++;
          mvert++;
        }

        for (a = 0; a < dl->parts; a++) {
          ofs = a * dl->nr;
          for (b = 0; b < dl->nr; b++) {
            medge->v1 = startvert + ofs + b;
            if (b == dl->nr - 1) {
              medge->v2 = startvert + ofs;
            }
            else {
              medge->v2 = startvert + ofs + b + 1;
            }
            medge->flag = ME_LOOSEEDGE | ME_EDGERENDER | ME_EDGEDRAW;
            medge++;
          }
        }
      }
    }
    else if (dl->type == DL_INDEX3) {
      startvert = vertcount;
      a = dl->nr;
      data = dl->verts;
      while (a--) {
        copy_v3_v3(mvert->co, data);
        data += 3;
        vertcount++;
        mvert++;
      }

      a = dl->parts;
      index = dl->index;
      while (a--) {
        mloop[0].v = startvert + index[0];
        mloop[1].v = startvert + index[2];
        mloop[2].v = startvert + index[1];
        mpoly->loopstart = (int)(mloop - (*r_allloop));
        mpoly->totloop = 3;
        mpoly->mat_nr = dl->col;

        if (mloopuv) {
          int i;

          for (i = 0; i < 3; i++, mloopuv++) {
            mloopuv->uv[0] = (mloop[i].v - startvert) / (float)(dl->nr - 1);
            mloopuv->uv[1] = 0.0f;
          }
        }

        if (is_smooth) {
          mpoly->flag |= ME_SMOOTH;
        }
        mpoly++;
        mloop += 3;
        index += 3;
      }
    }
    else if (dl->type == DL_SURF) {
      startvert = vertcount;
      a = dl->parts * dl->nr;
      data = dl->verts;
      while (a--) {
        copy_v3_v3(mvert->co, data);
        data += 3;
        vertcount++;
        mvert++;
      }

      for (a = 0; a < dl->parts; a++) {

        if ((dl->flag & DL_CYCL_V) == 0 && a == dl->parts - 1) {
          break;
        }

        if (dl->flag & DL_CYCL_U) {    /* p2 -> p1 -> */
          p1 = startvert + dl->nr * a; /* p4 -> p3 -> */
          p2 = p1 + dl->nr - 1;        /* -----> next row */
          p3 = p1 + dl->nr;
          p4 = p2 + dl->nr;
          b = 0;
        }
        else {
          p2 = startvert + dl->nr * a;
          p1 = p2 + 1;
          p4 = p2 + dl->nr;
          p3 = p1 + dl->nr;
          b = 1;
        }
        if ((dl->flag & DL_CYCL_V) && a == dl->parts - 1) {
          p3 -= dl->parts * dl->nr;
          p4 -= dl->parts * dl->nr;
        }

        for (; b < dl->nr; b++) {
          mloop[0].v = p1;
          mloop[1].v = p3;
          mloop[2].v = p4;
          mloop[3].v = p2;
          mpoly->loopstart = (int)(mloop - (*r_allloop));
          mpoly->totloop = 4;
          mpoly->mat_nr = dl->col;

          if (mloopuv) {
            int orco_sizeu = dl->nr - 1;
            int orco_sizev = dl->parts - 1;
            int i;

            /* exception as handled in convertblender.c too */
            if (dl->flag & DL_CYCL_U) {
              orco_sizeu++;
              if (dl->flag & DL_CYCL_V) {
                orco_sizev++;
              }
            }
            else if (dl->flag & DL_CYCL_V) {
              orco_sizev++;
            }

            for (i = 0; i < 4; i++, mloopuv++) {
              /* find uv based on vertex index into grid array */
              int v = mloop[i].v - startvert;

              mloopuv->uv[0] = (v / dl->nr) / (float)orco_sizev;
              mloopuv->uv[1] = (v % dl->nr) / (float)orco_sizeu;

              /* cyclic correction */
              if ((i == 1 || i == 2) && mloopuv->uv[0] == 0.0f) {
                mloopuv->uv[0] = 1.0f;
              }
              if ((i == 0 || i == 1) && mloopuv->uv[1] == 0.0f) {
                mloopuv->uv[1] = 1.0f;
              }
            }
          }

          if (is_smooth) {
            mpoly->flag |= ME_SMOOTH;
          }
          mpoly++;
          mloop += 4;

          p4 = p3;
          p3++;
          p2 = p1;
          p1++;
        }
      }
    }

    dl = dl->next;
  }

  if (totpoly) {
    make_edges_mdata_extend(r_alledge, &totedge, *r_allpoly, *r_allloop, totpoly);
  }

  *r_totpoly = totpoly;
  *r_totloop = totloop;
  *r_totedge = totedge;
  *r_totvert = totvert;

  return 0;
}
コード例 #11
0
ファイル: mesh_convert.c プロジェクト: wangyxuan/blender
/**
 * Specialized function to use when we _know_ existing edges don't overlap with poly edges.
 */
static void make_edges_mdata_extend(
    MEdge **r_alledge, int *r_totedge, const MPoly *mpoly, MLoop *mloop, const int totpoly)
{
  int totedge = *r_totedge;
  int totedge_new;
  EdgeHash *eh;
  unsigned int eh_reserve;
  const MPoly *mp;
  int i;

  eh_reserve = max_ii(totedge, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(totpoly));
  eh = BLI_edgehash_new_ex(__func__, eh_reserve);

  for (i = 0, mp = mpoly; i < totpoly; i++, mp++) {
    BKE_mesh_poly_edgehash_insert(eh, mp, mloop + mp->loopstart);
  }

  totedge_new = BLI_edgehash_len(eh);

#ifdef DEBUG
  /* ensure that there's no overlap! */
  if (totedge_new) {
    MEdge *medge = *r_alledge;
    for (i = 0; i < totedge; i++, medge++) {
      BLI_assert(BLI_edgehash_haskey(eh, medge->v1, medge->v2) == false);
    }
  }
#endif

  if (totedge_new) {
    EdgeHashIterator *ehi;
    MEdge *medge;
    unsigned int e_index = totedge;

    *r_alledge = medge = (*r_alledge ?
                              MEM_reallocN(*r_alledge, sizeof(MEdge) * (totedge + totedge_new)) :
                              MEM_calloc_arrayN(totedge_new, sizeof(MEdge), __func__));
    medge += totedge;

    totedge += totedge_new;

    /* --- */
    for (ehi = BLI_edgehashIterator_new(eh); BLI_edgehashIterator_isDone(ehi) == false;
         BLI_edgehashIterator_step(ehi), ++medge, e_index++) {
      BLI_edgehashIterator_getKey(ehi, &medge->v1, &medge->v2);
      BLI_edgehashIterator_setValue(ehi, POINTER_FROM_UINT(e_index));

      medge->crease = medge->bweight = 0;
      medge->flag = ME_EDGEDRAW | ME_EDGERENDER;
    }
    BLI_edgehashIterator_free(ehi);

    *r_totedge = totedge;

    for (i = 0, mp = mpoly; i < totpoly; i++, mp++) {
      MLoop *l = &mloop[mp->loopstart];
      MLoop *l_prev = (l + (mp->totloop - 1));
      int j;
      for (j = 0; j < mp->totloop; j++, l++) {
        /* lookup hashed edge index */
        l_prev->e = POINTER_AS_UINT(BLI_edgehash_lookup(eh, l_prev->v, l->v));
        l_prev = l;
      }
    }
  }

  BLI_edgehash_free(eh, NULL);
}
コード例 #12
0
static void correctivesmooth_modifier_do(ModifierData *md,
                                         Depsgraph *depsgraph,
                                         Object *ob,
                                         Mesh *mesh,
                                         float (*vertexCos)[3],
                                         unsigned int numVerts,
                                         struct BMEditMesh *em)
{
  CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;

  const bool force_delta_cache_update =
      /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */
      ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) &&
       (((ID *)ob->data)->recalc & ID_RECALC_ALL));

  bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0;
  MDeformVert *dvert = NULL;
  int defgrp_index;

  MOD_get_vgroup(ob, mesh, csmd->defgrp_name, &dvert, &defgrp_index);

  /* if rest bind_coords not are defined, set them (only run during bind) */
  if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) &&
      /* signal to recalculate, whoever sets MUST also free bind coords */
      (csmd->bind_coords_num == (unsigned int)-1)) {
    if (DEG_is_active(depsgraph)) {
      BLI_assert(csmd->bind_coords == NULL);
      csmd->bind_coords = MEM_dupallocN(vertexCos);
      csmd->bind_coords_num = numVerts;
      BLI_assert(csmd->bind_coords != NULL);
      /* Copy bound data to the original modifier. */
      CorrectiveSmoothModifierData *csmd_orig = (CorrectiveSmoothModifierData *)
          modifier_get_original(&csmd->modifier);
      csmd_orig->bind_coords = MEM_dupallocN(csmd->bind_coords);
      csmd_orig->bind_coords_num = csmd->bind_coords_num;
    }
    else {
      modifier_setError(md, "Attempt to bind from inactive dependency graph");
    }
  }

  if (UNLIKELY(use_only_smooth)) {
    smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts);
    return;
  }

  if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) {
    modifier_setError(md, "Bind data required");
    goto error;
  }

  /* If the number of verts has changed, the bind is invalid, so we do nothing */
  if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
    if (csmd->bind_coords_num != numVerts) {
      modifier_setError(
          md, "Bind vertex count mismatch: %u to %u", csmd->bind_coords_num, numVerts);
      goto error;
    }
  }
  else {
    /* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */
    if (ob->type != OB_MESH) {
      modifier_setError(md, "Object is not a mesh");
      goto error;
    }
    else {
      unsigned int me_numVerts = (unsigned int)((em) ? em->bm->totvert :
                                                       ((Mesh *)ob->data)->totvert);

      if (me_numVerts != numVerts) {
        modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts);
        goto error;
      }
    }
  }

  /* check to see if our deltas are still valid */
  if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) {
    const float(*rest_coords)[3];
    bool is_rest_coords_alloc = false;

    if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
      /* caller needs to do sanity check here */
      csmd->bind_coords_num = numVerts;
      rest_coords = (const float(*)[3])csmd->bind_coords;
    }
    else {
      int me_numVerts;
      rest_coords = (const float(*)[3])((em) ? BKE_editmesh_vertexCos_get_orco(em, &me_numVerts) :
                                               BKE_mesh_vertexCos_get(ob->data, &me_numVerts));

      BLI_assert((unsigned int)me_numVerts == numVerts);
      is_rest_coords_alloc = true;
    }

#ifdef DEBUG_TIME
    TIMEIT_START(corrective_smooth_deltas);
#endif

    calc_deltas(csmd, mesh, dvert, defgrp_index, rest_coords, numVerts);

#ifdef DEBUG_TIME
    TIMEIT_END(corrective_smooth_deltas);
#endif
    if (is_rest_coords_alloc) {
      MEM_freeN((void *)rest_coords);
    }
  }

  if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
    /* this could be a check, but at this point it _must_ be valid */
    BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache);
  }

#ifdef DEBUG_TIME
  TIMEIT_START(corrective_smooth);
#endif

  /* do the actual delta mush */
  smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts);

  {
    unsigned int i;

    float(*tangent_spaces)[3][3];

    /* calloc, since values are accumulated */
    tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__);

    calc_tangent_spaces(mesh, vertexCos, tangent_spaces);

    for (i = 0; i < numVerts; i++) {
      float delta[3];

#ifdef USE_TANGENT_CALC_INLINE
      calc_tangent_ortho(tangent_spaces[i]);
#endif

      mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]);
      add_v3_v3(vertexCos[i], delta);
    }

    MEM_freeN(tangent_spaces);
  }

#ifdef DEBUG_TIME
  TIMEIT_END(corrective_smooth);
#endif

  return;

  /* when the modifier fails to execute */
error:
  MEM_SAFE_FREE(csmd->delta_cache);
  csmd->delta_cache_num = 0;
}
コード例 #13
0
/* Edge-Length Weighted Smoothing
 */
static void smooth_iter__length_weight(CorrectiveSmoothModifierData *csmd,
                                       Mesh *mesh,
                                       float (*vertexCos)[3],
                                       unsigned int numVerts,
                                       const float *smooth_weights,
                                       unsigned int iterations)
{
  const float eps = FLT_EPSILON * 10.0f;
  const unsigned int numEdges = (unsigned int)mesh->totedge;
  /* note: the way this smoothing method works, its approx half as strong as the simple-smooth,
   * and 2.0 rarely spikes, double the value for consistent behavior. */
  const float lambda = csmd->lambda * 2.0f;
  const MEdge *edges = mesh->medge;
  float *vertex_edge_count;
  unsigned int i;

  struct SmoothingData_Weighted {
    float delta[3];
    float edge_length_sum;
  } *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__);

  /* calculate as floats to avoid int->float conversion in #smooth_iter */
  vertex_edge_count = MEM_calloc_arrayN(numVerts, sizeof(float), __func__);
  for (i = 0; i < numEdges; i++) {
    vertex_edge_count[edges[i].v1] += 1.0f;
    vertex_edge_count[edges[i].v2] += 1.0f;
  }

  /* -------------------------------------------------------------------- */
  /* Main Smoothing Loop */

  while (iterations--) {
    for (i = 0; i < numEdges; i++) {
      struct SmoothingData_Weighted *sd_v1;
      struct SmoothingData_Weighted *sd_v2;
      float edge_dir[3];
      float edge_dist;

      sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]);
      edge_dist = len_v3(edge_dir);

      /* weight by distance */
      mul_v3_fl(edge_dir, edge_dist);

      sd_v1 = &smooth_data[edges[i].v1];
      sd_v2 = &smooth_data[edges[i].v2];

      add_v3_v3(sd_v1->delta, edge_dir);
      sub_v3_v3(sd_v2->delta, edge_dir);

      sd_v1->edge_length_sum += edge_dist;
      sd_v2->edge_length_sum += edge_dist;
    }

    if (smooth_weights == NULL) {
      /* fast-path */
      for (i = 0; i < numVerts; i++) {
        struct SmoothingData_Weighted *sd = &smooth_data[i];
        /* Divide by sum of all neighbour distances (weighted) and amount of neighbors,
         * (mean average). */
        const float div = sd->edge_length_sum * vertex_edge_count[i];
        if (div > eps) {
#if 0
          /* first calculate the new location */
          mul_v3_fl(sd->delta, 1.0f / div);
          /* then interpolate */
          madd_v3_v3fl(vertexCos[i], sd->delta, lambda);
#else
          /* do this in one step */
          madd_v3_v3fl(vertexCos[i], sd->delta, lambda / div);
#endif
        }
        /* zero for the next iteration (saves memset on entire array) */
        memset(sd, 0, sizeof(*sd));
      }
    }
    else {
      for (i = 0; i < numVerts; i++) {
        struct SmoothingData_Weighted *sd = &smooth_data[i];
        const float div = sd->edge_length_sum * vertex_edge_count[i];
        if (div > eps) {
          const float lambda_w = lambda * smooth_weights[i];
          madd_v3_v3fl(vertexCos[i], sd->delta, lambda_w / div);
        }

        memset(sd, 0, sizeof(*sd));
      }
    }
  }

  MEM_freeN(vertex_edge_count);
  MEM_freeN(smooth_data);
}
コード例 #14
0
/* Simple Weighted Smoothing
 *
 * (average of surrounding verts)
 */
static void smooth_iter__simple(CorrectiveSmoothModifierData *csmd,
                                Mesh *mesh,
                                float (*vertexCos)[3],
                                unsigned int numVerts,
                                const float *smooth_weights,
                                unsigned int iterations)
{
  const float lambda = csmd->lambda;
  unsigned int i;

  const unsigned int numEdges = (unsigned int)mesh->totedge;
  const MEdge *edges = mesh->medge;
  float *vertex_edge_count_div;

  struct SmoothingData_Simple {
    float delta[3];
  } *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__);

  vertex_edge_count_div = MEM_calloc_arrayN(numVerts, sizeof(float), __func__);

  /* calculate as floats to avoid int->float conversion in #smooth_iter */
  for (i = 0; i < numEdges; i++) {
    vertex_edge_count_div[edges[i].v1] += 1.0f;
    vertex_edge_count_div[edges[i].v2] += 1.0f;
  }

  /* a little confusing, but we can include 'lambda' and smoothing weight
   * here to avoid multiplying for every iteration */
  if (smooth_weights == NULL) {
    for (i = 0; i < numVerts; i++) {
      vertex_edge_count_div[i] = lambda * (vertex_edge_count_div[i] ?
                                               (1.0f / vertex_edge_count_div[i]) :
                                               1.0f);
    }
  }
  else {
    for (i = 0; i < numVerts; i++) {
      vertex_edge_count_div[i] = smooth_weights[i] * lambda *
                                 (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) :
                                                             1.0f);
    }
  }

  /* -------------------------------------------------------------------- */
  /* Main Smoothing Loop */

  while (iterations--) {
    for (i = 0; i < numEdges; i++) {
      struct SmoothingData_Simple *sd_v1;
      struct SmoothingData_Simple *sd_v2;
      float edge_dir[3];

      sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]);

      sd_v1 = &smooth_data[edges[i].v1];
      sd_v2 = &smooth_data[edges[i].v2];

      add_v3_v3(sd_v1->delta, edge_dir);
      sub_v3_v3(sd_v2->delta, edge_dir);
    }

    for (i = 0; i < numVerts; i++) {
      struct SmoothingData_Simple *sd = &smooth_data[i];
      madd_v3_v3fl(vertexCos[i], sd->delta, vertex_edge_count_div[i]);
      /* zero for the next iteration (saves memset on entire array) */
      memset(sd, 0, sizeof(*sd));
    }
  }

  MEM_freeN(vertex_edge_count_div);
  MEM_freeN(smooth_data);
}
コード例 #15
0
ファイル: MOD_explode.c プロジェクト: dfelinto/blender
static void createFacepa(ExplodeModifierData *emd, ParticleSystemModifierData *psmd, Mesh *mesh)
{
  ParticleSystem *psys = psmd->psys;
  MFace *fa = NULL, *mface = NULL;
  MVert *mvert = NULL;
  ParticleData *pa;
  KDTree_3d *tree;
  RNG *rng;
  float center[3], co[3];
  int *facepa = NULL, *vertpa = NULL, totvert = 0, totface = 0, totpart = 0;
  int i, p, v1, v2, v3, v4 = 0;

  mvert = mesh->mvert;
  mface = mesh->mface;
  totvert = mesh->totvert;
  totface = mesh->totface;
  totpart = psmd->psys->totpart;

  rng = BLI_rng_new_srandom(psys->seed);

  if (emd->facepa) {
    MEM_freeN(emd->facepa);
  }
  facepa = emd->facepa = MEM_calloc_arrayN(totface, sizeof(int), "explode_facepa");

  vertpa = MEM_calloc_arrayN(totvert, sizeof(int), "explode_vertpa");

  /* initialize all faces & verts to no particle */
  for (i = 0; i < totface; i++) {
    facepa[i] = totpart;
  }
  for (i = 0; i < totvert; i++) {
    vertpa[i] = totpart;
  }

  /* set protected verts */
  if (emd->vgroup) {
    MDeformVert *dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
    if (dvert) {
      const int defgrp_index = emd->vgroup - 1;
      for (i = 0; i < totvert; i++, dvert++) {
        float val = BLI_rng_get_float(rng);
        val = (1.0f - emd->protect) * val + emd->protect * 0.5f;
        if (val < defvert_find_weight(dvert, defgrp_index)) {
          vertpa[i] = -1;
        }
      }
    }
  }

  /* make tree of emitter locations */
  tree = BLI_kdtree_3d_new(totpart);
  for (p = 0, pa = psys->particles; p < totpart; p++, pa++) {
    psys_particle_on_emitter(psmd,
                             psys->part->from,
                             pa->num,
                             pa->num_dmcache,
                             pa->fuv,
                             pa->foffset,
                             co,
                             NULL,
                             NULL,
                             NULL,
                             NULL);
    BLI_kdtree_3d_insert(tree, p, co);
  }
  BLI_kdtree_3d_balance(tree);

  /* set face-particle-indexes to nearest particle to face center */
  for (i = 0, fa = mface; i < totface; i++, fa++) {
    add_v3_v3v3(center, mvert[fa->v1].co, mvert[fa->v2].co);
    add_v3_v3(center, mvert[fa->v3].co);
    if (fa->v4) {
      add_v3_v3(center, mvert[fa->v4].co);
      mul_v3_fl(center, 0.25);
    }
    else {
      mul_v3_fl(center, 1.0f / 3.0f);
    }

    p = BLI_kdtree_3d_find_nearest(tree, center, NULL);

    v1 = vertpa[fa->v1];
    v2 = vertpa[fa->v2];
    v3 = vertpa[fa->v3];
    if (fa->v4) {
      v4 = vertpa[fa->v4];
    }

    if (v1 >= 0 && v2 >= 0 && v3 >= 0 && (fa->v4 == 0 || v4 >= 0)) {
      facepa[i] = p;
    }

    if (v1 >= 0) {
      vertpa[fa->v1] = p;
    }
    if (v2 >= 0) {
      vertpa[fa->v2] = p;
    }
    if (v3 >= 0) {
      vertpa[fa->v3] = p;
    }
    if (fa->v4 && v4 >= 0) {
      vertpa[fa->v4] = p;
    }
  }

  if (vertpa) {
    MEM_freeN(vertpa);
  }
  BLI_kdtree_3d_free(tree);

  BLI_rng_free(rng);
}
コード例 #16
0
ファイル: MOD_explode.c プロジェクト: dfelinto/blender
static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
{
  Mesh *split_m;
  MFace *mf = NULL, *df1 = NULL;
  MFace *mface = mesh->mface;
  MVert *dupve, *mv;
  EdgeHash *edgehash;
  EdgeHashIterator *ehi;
  int totvert = mesh->totvert;
  int totface = mesh->totface;

  int *facesplit = MEM_calloc_arrayN(totface, sizeof(int), "explode_facesplit");
  int *vertpa = MEM_calloc_arrayN(totvert, sizeof(int), "explode_vertpa2");
  int *facepa = emd->facepa;
  int *fs, totesplit = 0, totfsplit = 0, curdupface = 0;
  int i, v1, v2, v3, v4, esplit, v[4] = {0, 0, 0, 0}, /* To quite gcc barking... */
      uv[4] = {0, 0, 0, 0};                           /* To quite gcc barking... */
  int numlayer;
  unsigned int ed_v1, ed_v2;

  edgehash = BLI_edgehash_new(__func__);

  /* recreate vertpa from facepa calculation */
  for (i = 0, mf = mface; i < totface; i++, mf++) {
    vertpa[mf->v1] = facepa[i];
    vertpa[mf->v2] = facepa[i];
    vertpa[mf->v3] = facepa[i];
    if (mf->v4) {
      vertpa[mf->v4] = facepa[i];
    }
  }

  /* mark edges for splitting and how to split faces */
  for (i = 0, mf = mface, fs = facesplit; i < totface; i++, mf++, fs++) {
    v1 = vertpa[mf->v1];
    v2 = vertpa[mf->v2];
    v3 = vertpa[mf->v3];

    if (v1 != v2) {
      BLI_edgehash_reinsert(edgehash, mf->v1, mf->v2, NULL);
      (*fs) |= 1;
    }

    if (v2 != v3) {
      BLI_edgehash_reinsert(edgehash, mf->v2, mf->v3, NULL);
      (*fs) |= 2;
    }

    if (mf->v4) {
      v4 = vertpa[mf->v4];

      if (v3 != v4) {
        BLI_edgehash_reinsert(edgehash, mf->v3, mf->v4, NULL);
        (*fs) |= 4;
      }

      if (v1 != v4) {
        BLI_edgehash_reinsert(edgehash, mf->v1, mf->v4, NULL);
        (*fs) |= 8;
      }

      /* mark center vertex as a fake edge split */
      if (*fs == 15) {
        BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL);
      }
    }
    else {
      (*fs) |= 16; /* mark face as tri */

      if (v1 != v3) {
        BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL);
        (*fs) |= 4;
      }
    }
  }

  /* count splits & create indexes for new verts */
  ehi = BLI_edgehashIterator_new(edgehash);
  totesplit = totvert;
  for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
    BLI_edgehashIterator_setValue(ehi, POINTER_FROM_INT(totesplit));
    totesplit++;
  }
  BLI_edgehashIterator_free(ehi);

  /* count new faces due to splitting */
  for (i = 0, fs = facesplit; i < totface; i++, fs++) {
    totfsplit += add_faces[*fs];
  }

  split_m = BKE_mesh_new_nomain_from_template(mesh, totesplit, 0, totface + totfsplit, 0, 0);

  numlayer = CustomData_number_of_layers(&split_m->fdata, CD_MTFACE);

  /* copy new faces & verts (is it really this painful with custom data??) */
  for (i = 0; i < totvert; i++) {
    MVert source;
    MVert *dest;
    source = mesh->mvert[i];
    dest = &split_m->mvert[i];

    CustomData_copy_data(&mesh->vdata, &split_m->vdata, i, i, 1);
    *dest = source;
  }

  /* override original facepa (original pointer is saved in caller function) */

  /* BMESH_TODO, (totfsplit * 2) over allocation is used since the quads are
   * later interpreted as tri's, for this to work right I think we probably
   * have to stop using tessface - campbell */

  facepa = MEM_calloc_arrayN((totface + (totfsplit * 2)), sizeof(int), "explode_facepa");
  // memcpy(facepa, emd->facepa, totface*sizeof(int));
  emd->facepa = facepa;

  /* create new verts */
  ehi = BLI_edgehashIterator_new(edgehash);
  for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
    BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2);
    esplit = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
    mv = &split_m->mvert[ed_v2];
    dupve = &split_m->mvert[esplit];

    CustomData_copy_data(&split_m->vdata, &split_m->vdata, ed_v2, esplit, 1);

    *dupve = *mv;

    mv = &split_m->mvert[ed_v1];

    mid_v3_v3v3(dupve->co, dupve->co, mv->co);
  }
  BLI_edgehashIterator_free(ehi);

  /* create new faces */
  curdupface = 0;  //=totface;
  // curdupin=totesplit;
  for (i = 0, fs = facesplit; i < totface; i++, fs++) {
    mf = &mesh->mface[i];

    switch (*fs) {
      case 3:
      case 10:
      case 11:
      case 15:
        SET_VERTS(1, 2, 3, 4);
        break;
      case 5:
      case 6:
      case 7:
        SET_VERTS(2, 3, 4, 1);
        break;
      case 9:
      case 13:
        SET_VERTS(4, 1, 2, 3);
        break;
      case 12:
      case 14:
        SET_VERTS(3, 4, 1, 2);
        break;
      case 21:
      case 23:
        SET_VERTS(1, 2, 3, 4);
        break;
      case 19:
        SET_VERTS(2, 3, 1, 4);
        break;
      case 22:
        SET_VERTS(3, 1, 2, 4);
        break;
    }

    switch (*fs) {
      case 3:
      case 6:
      case 9:
      case 12:
        remap_faces_3_6_9_12(
            mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
        if (numlayer) {
          remap_uvs_3_6_9_12(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
        }
        break;
      case 5:
      case 10:
        remap_faces_5_10(
            mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
        if (numlayer) {
          remap_uvs_5_10(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
        }
        break;
      case 15:
        remap_faces_15(
            mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
        if (numlayer) {
          remap_uvs_15(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
        }
        break;
      case 7:
      case 11:
      case 13:
      case 14:
        remap_faces_7_11_13_14(
            mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
        if (numlayer) {
          remap_uvs_7_11_13_14(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
        }
        break;
      case 19:
      case 21:
      case 22:
        remap_faces_19_21_22(
            mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]);
        if (numlayer) {
          remap_uvs_19_21_22(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2]);
        }
        break;
      case 23:
        remap_faces_23(
            mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]);
        if (numlayer) {
          remap_uvs_23(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2]);
        }
        break;
      case 0:
      case 16:
        df1 = get_dface(mesh, split_m, curdupface, i, mf);
        facepa[curdupface] = vertpa[mf->v1];

        if (df1->v4) {
          df1->flag |= ME_FACE_SEL;
        }
        else {
          df1->flag &= ~ME_FACE_SEL;
        }
        break;
    }

    curdupface += add_faces[*fs] + 1;
  }

  for (i = 0; i < curdupface; i++) {
    mf = &split_m->mface[i];
    test_index_face(mf, &split_m->fdata, i, ((mf->flag & ME_FACE_SEL) ? 4 : 3));
  }

  BLI_edgehash_free(edgehash, NULL);
  MEM_freeN(facesplit);
  MEM_freeN(vertpa);

  BKE_mesh_calc_edges_tessface(split_m);
  BKE_mesh_convert_mfaces_to_mpolys(split_m);

  return split_m;
}