/* do not free mball itself */ void BKE_mball_free(MetaBall *mb) { BKE_mball_unlink(mb); if (mb->adt) { BKE_animdata_free((ID *)mb); mb->adt = NULL; } if (mb->mat) MEM_freeN(mb->mat); BLI_freelistN(&mb->elems); if (mb->disp.first) BKE_displist_free(&mb->disp); }
static DerivedMesh *create_orco_dm(Scene *scene, Object *ob) { DerivedMesh *dm; ListBase disp = {NULL, NULL}; /* OrcoDM should be created from underformed disp lists */ BKE_displist_make_curveTypes_forOrco(scene, ob, &disp); dm = CDDM_from_curve_displist(ob, &disp); BKE_displist_free(&disp); return dm; }
void BKE_lattice_modifiers_calc(Scene *scene, Object *ob) { Lattice *lt = ob->data; VirtualModifierData virtualModifierData; ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); float (*vertexCos)[3] = NULL; int numVerts, editmode = (lt->editlatt != NULL); if (ob->curve_cache) { BKE_displist_free(&ob->curve_cache->disp); } else { ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice"); } for (; md; md = md->next) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); md->scene = scene; if (!(md->mode & eModifierMode_Realtime)) continue; if (editmode && !(md->mode & eModifierMode_Editmode)) continue; if (mti->isDisabled && mti->isDisabled(md, 0)) continue; if (mti->type != eModifierTypeType_OnlyDeform) continue; if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob, &numVerts); mti->deformVerts(md, ob, NULL, vertexCos, numVerts, 0); } /* always displist to make this work like derivedmesh */ if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob, &numVerts); { DispList *dl = MEM_callocN(sizeof(*dl), "lt_dl"); dl->type = DL_VERTS; dl->parts = 1; dl->nr = numVerts; dl->verts = (float *) vertexCos; BLI_addtail(&ob->curve_cache->disp, dl); } }
void BKE_displist_copy(ListBase *lbn, ListBase *lb) { DispList *dln, *dl; BKE_displist_free(lbn); dl = lb->first; while (dl) { dln = MEM_dupallocN(dl); BLI_addtail(lbn, dln); dln->verts = MEM_dupallocN(dl->verts); dln->nors = MEM_dupallocN(dl->nors); dln->index = MEM_dupallocN(dl->index); if (dl->bevel_split) { dln->bevel_split = MEM_dupallocN(dl->bevel_split); } dl = dl->next; } }
void BKE_displist_make_mball(EvaluationContext *eval_ctx, Scene *scene, Object *ob) { if (!ob || ob->type != OB_MBALL) return; if (ob == BKE_mball_basis_find(scene, ob)) { if (ob->curve_cache) { BKE_displist_free(&(ob->curve_cache->disp)); } else { ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall"); } BKE_mball_polygonize(eval_ctx, scene, ob, &ob->curve_cache->disp); BKE_mball_texspace_calc(ob); object_deform_mball(ob, &ob->curve_cache->disp); /* NOP for MBALLs anyway... */ boundbox_displist_object(ob); } }
void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb) { BPoint *bp; int i, u, v, w; float fu, fv, fw, uc, vc, wc, du = 0.0, dv = 0.0, dw = 0.0; float *co, (*vertexCos)[3] = NULL; /* vertex weight groups are just freed all for now */ if (lt->dvert) { free_dverts(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); lt->dvert = NULL; } while (uNew * vNew * wNew > 32000) { if (uNew >= vNew && uNew >= wNew) uNew--; else if (vNew >= uNew && vNew >= wNew) vNew--; else wNew--; } vertexCos = MEM_mallocN(sizeof(*vertexCos) * uNew * vNew * wNew, "tmp_vcos"); calc_lat_fudu(lt->flag, uNew, &fu, &du); calc_lat_fudu(lt->flag, vNew, &fv, &dv); calc_lat_fudu(lt->flag, wNew, &fw, &dw); /* If old size is different then resolution changed in interface, * try to do clever reinit of points. Pretty simply idea, we just * deform new verts by old lattice, but scaling them to match old * size first. */ if (ltOb) { if (uNew != 1 && lt->pntsu != 1) { fu = lt->fu; du = (lt->pntsu - 1) * lt->du / (uNew - 1); } if (vNew != 1 && lt->pntsv != 1) { fv = lt->fv; dv = (lt->pntsv - 1) * lt->dv / (vNew - 1); } if (wNew != 1 && lt->pntsw != 1) { fw = lt->fw; dw = (lt->pntsw - 1) * lt->dw / (wNew - 1); } } co = vertexCos[0]; for (w = 0, wc = fw; w < wNew; w++, wc += dw) { for (v = 0, vc = fv; v < vNew; v++, vc += dv) { for (u = 0, uc = fu; u < uNew; u++, co += 3, uc += du) { co[0] = uc; co[1] = vc; co[2] = wc; } } } if (ltOb) { float mat[4][4]; int typeu = lt->typeu, typev = lt->typev, typew = lt->typew; /* works best if we force to linear type (endpoints match) */ lt->typeu = lt->typev = lt->typew = KEY_LINEAR; /* prevent using deformed locations */ BKE_displist_free(<Ob->disp); copy_m4_m4(mat, ltOb->obmat); unit_m4(ltOb->obmat); lattice_deform_verts(ltOb, NULL, NULL, vertexCos, uNew * vNew * wNew, NULL, 1.0f); copy_m4_m4(ltOb->obmat, mat); lt->typeu = typeu; lt->typev = typev; lt->typew = typew; } lt->fu = fu; lt->fv = fv; lt->fw = fw; lt->du = du; lt->dv = dv; lt->dw = dw; lt->pntsu = uNew; lt->pntsv = vNew; lt->pntsw = wNew; MEM_freeN(lt->def); lt->def = MEM_callocN(lt->pntsu * lt->pntsv * lt->pntsw * sizeof(BPoint), "lattice bp"); bp = lt->def; for (i = 0; i < lt->pntsu * lt->pntsv * lt->pntsw; i++, bp++) { copy_v3_v3(bp->vec, vertexCos[i]); } MEM_freeN(vertexCos); }
static void bevels_to_filledpoly(Curve *cu, ListBase *dispbase) { const float z_up[3] = {0.0f, 0.0f, 1.0f}; ListBase front, back; DispList *dl, *dlnew; float *fp, *fp1; int a, dpoly; BLI_listbase_clear(&front); BLI_listbase_clear(&back); dl = dispbase->first; while (dl) { if (dl->type == DL_SURF) { if ((dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U) == 0) { if ((cu->flag & CU_BACK) && (dl->flag & DL_BACK_CURVE)) { dlnew = MEM_callocN(sizeof(DispList), "filldisp"); BLI_addtail(&front, dlnew); dlnew->verts = fp1 = MEM_mallocN(sizeof(float) * 3 * dl->parts, "filldisp1"); dlnew->nr = dl->parts; dlnew->parts = 1; dlnew->type = DL_POLY; dlnew->flag = DL_BACK_CURVE; dlnew->col = dl->col; dlnew->charidx = dl->charidx; fp = dl->verts; dpoly = 3 * dl->nr; a = dl->parts; while (a--) { copy_v3_v3(fp1, fp); fp1 += 3; fp += dpoly; } } if ((cu->flag & CU_FRONT) && (dl->flag & DL_FRONT_CURVE)) { dlnew = MEM_callocN(sizeof(DispList), "filldisp"); BLI_addtail(&back, dlnew); dlnew->verts = fp1 = MEM_mallocN(sizeof(float) * 3 * dl->parts, "filldisp1"); dlnew->nr = dl->parts; dlnew->parts = 1; dlnew->type = DL_POLY; dlnew->flag = DL_FRONT_CURVE; dlnew->col = dl->col; dlnew->charidx = dl->charidx; fp = dl->verts + 3 * (dl->nr - 1); dpoly = 3 * dl->nr; a = dl->parts; while (a--) { copy_v3_v3(fp1, fp); fp1 += 3; fp += dpoly; } } } } dl = dl->next; } BKE_displist_fill(&front, dispbase, z_up, true); BKE_displist_fill(&back, dispbase, z_up, false); BKE_displist_free(&front); BKE_displist_free(&back); BKE_displist_fill(dispbase, dispbase, z_up, false); }
/* settings: 1 - preview, 2 - render * * The convention goes as following: * * - Passing original object with apply_modifiers=false will give a * non-modified non-deformed mesh. * The result mesh will point to datablocks from the original "domain". For * example, materials will be original. * * - Passing original object with apply_modifiers=true will give a mesh which * has all modifiers applied. * The result mesh will point to datablocks from the original "domain". For * example, materials will be original. * * - Passing evaluated object will ignore apply_modifiers argument, and the * result always contains all modifiers applied. * The result mesh will point to an evaluated datablocks. For example, * materials will be an evaluated IDs from the dependency graph. */ Mesh *BKE_mesh_new_from_object(Depsgraph *depsgraph, Main *bmain, Scene *sce, Object *ob, const bool apply_modifiers, const bool calc_undeformed) { Mesh *tmpmesh; Curve *tmpcu = NULL, *copycu; int i; const bool render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); bool effective_apply_modifiers = apply_modifiers; bool do_mat_id_data_us = true; Object *object_input = ob; Object *object_eval = DEG_get_evaluated_object(depsgraph, object_input); Object object_for_eval; if (object_eval == object_input) { /* Evaluated mesh contains all modifiers applied already. * The other types of object has them applied, but are stored in other * data structures than a mesh. So need to apply modifiers again on a * temporary copy before converting result to mesh. */ if (object_input->type == OB_MESH) { effective_apply_modifiers = false; } else { effective_apply_modifiers = true; } object_for_eval = *object_eval; } else { if (apply_modifiers) { object_for_eval = *object_eval; if (object_for_eval.runtime.mesh_orig != NULL) { object_for_eval.data = object_for_eval.runtime.mesh_orig; } } else { object_for_eval = *object_input; } } const bool cage = !effective_apply_modifiers; /* perform the mesh extraction based on type */ switch (object_for_eval.type) { case OB_FONT: case OB_CURVE: case OB_SURF: { ListBase dispbase = {NULL, NULL}; Mesh *me_eval_final = NULL; int uv_from_orco; /* copies object and modifiers (but not the data) */ Object *tmpobj; BKE_id_copy_ex(NULL, &object_for_eval.id, (ID **)&tmpobj, LIB_ID_COPY_LOCALIZE); tmpcu = (Curve *)tmpobj->data; /* Copy cached display list, it might be needed by the stack evaluation. * Ideally stack should be able to use render-time display list, but doing * so is quite tricky and not safe so close to the release. * * TODO(sergey): Look into more proper solution. */ if (object_for_eval.runtime.curve_cache != NULL) { if (tmpobj->runtime.curve_cache == NULL) { tmpobj->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types"); } BKE_displist_copy(&tmpobj->runtime.curve_cache->disp, &object_for_eval.runtime.curve_cache->disp); } /* if getting the original caged mesh, delete object modifiers */ if (cage) { BKE_object_free_modifiers(tmpobj, LIB_ID_CREATE_NO_USER_REFCOUNT); } /* copies the data, but *not* the shapekeys. */ BKE_id_copy_ex(NULL, object_for_eval.data, (ID **)©cu, LIB_ID_COPY_LOCALIZE); tmpobj->data = copycu; /* make sure texture space is calculated for a copy of curve, * it will be used for the final result. */ BKE_curve_texspace_calc(copycu); /* temporarily set edit so we get updates from edit mode, but * also because for text datablocks copying it while in edit * mode gives invalid data structures */ copycu->editfont = tmpcu->editfont; copycu->editnurb = tmpcu->editnurb; /* get updated display list, and convert to a mesh */ BKE_displist_make_curveTypes_forRender( depsgraph, sce, tmpobj, &dispbase, &me_eval_final, false, NULL); copycu->editfont = NULL; copycu->editnurb = NULL; tmpobj->runtime.mesh_eval = me_eval_final; /* convert object type to mesh */ uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0; BKE_mesh_from_nurbs_displist( bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2, true); /* Function above also frees copycu (aka tmpobj->data), make this obvious here. */ copycu = NULL; tmpmesh = tmpobj->data; id_us_min( &tmpmesh->id); /* Gets one user from its creation in BKE_mesh_from_nurbs_displist(). */ BKE_displist_free(&dispbase); /* BKE_mesh_from_nurbs changes the type to a mesh, check it worked. * if it didn't the curve did not have any segments or otherwise * would have generated an empty mesh */ if (tmpobj->type != OB_MESH) { BKE_id_free(NULL, tmpobj); return NULL; } BKE_id_free(NULL, tmpobj); /* XXX The curve to mesh conversion is convoluted... * But essentially, BKE_mesh_from_nurbs_displist() * already transfers the ownership of materials from the temp copy of the Curve ID to the * new Mesh ID, so we do not want to increase materials' usercount later. */ do_mat_id_data_us = false; break; } case OB_MBALL: { /* metaballs don't have modifiers, so just convert to mesh */ Object *basis_ob = BKE_mball_basis_find(sce, object_input); /* todo, re-generatre for render-res */ /* metaball_polygonize(scene, ob) */ if (basis_ob != object_input) { /* Only do basis metaball. */ return NULL; } tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2); /* BKE_mesh_add gives us a user count we don't need */ id_us_min(&tmpmesh->id); if (render) { ListBase disp = {NULL, NULL}; BKE_displist_make_mball_forRender(depsgraph, sce, &object_for_eval, &disp); BKE_mesh_from_metaball(&disp, tmpmesh); BKE_displist_free(&disp); } else { ListBase disp = {NULL, NULL}; if (object_for_eval.runtime.curve_cache) { disp = object_for_eval.runtime.curve_cache->disp; } BKE_mesh_from_metaball(&disp, tmpmesh); } BKE_mesh_texspace_copy_from_object(tmpmesh, &object_for_eval); break; } case OB_MESH: /* copies object and modifiers (but not the data) */ if (cage) { /* copies the data (but *not* the shapekeys). */ Mesh *mesh = object_for_eval.data; BKE_id_copy_ex(bmain, &mesh->id, (ID **)&tmpmesh, 0); /* XXX BKE_mesh_copy() already handles materials usercount. */ do_mat_id_data_us = false; } /* if not getting the original caged mesh, get final derived mesh */ else { /* Make a dummy mesh, saves copying */ Mesh *me_eval; CustomData_MeshMasks mask = CD_MASK_MESH; /* this seems more suitable, exporter, * for example, needs CD_MASK_MDEFORMVERT */ if (calc_undeformed) { mask.vmask |= CD_MASK_ORCO; } if (render) { me_eval = mesh_create_eval_final_render(depsgraph, sce, &object_for_eval, &mask); } else { me_eval = mesh_create_eval_final_view(depsgraph, sce, &object_for_eval, &mask); } tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2); BKE_mesh_nomain_to_mesh(me_eval, tmpmesh, &object_for_eval, &mask, true); /* Copy autosmooth settings from original mesh. */ Mesh *me = (Mesh *)object_for_eval.data; tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH); tmpmesh->smoothresh = me->smoothresh; } /* BKE_mesh_add/copy gives us a user count we don't need */ id_us_min(&tmpmesh->id); break; default: /* "Object does not have geometry data") */ return NULL; } /* Copy materials to new mesh */ switch (object_for_eval.type) { case OB_SURF: case OB_FONT: case OB_CURVE: tmpmesh->totcol = tmpcu->totcol; /* free old material list (if it exists) and adjust user counts */ if (tmpcu->mat) { for (i = tmpcu->totcol; i-- > 0;) { /* are we an object material or data based? */ tmpmesh->mat[i] = give_current_material(object_input, i + 1); if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) { id_us_plus(&tmpmesh->mat[i]->id); } } } break; case OB_MBALL: { MetaBall *tmpmb = (MetaBall *)object_for_eval.data; tmpmesh->mat = MEM_dupallocN(tmpmb->mat); tmpmesh->totcol = tmpmb->totcol; /* free old material list (if it exists) and adjust user counts */ if (tmpmb->mat) { for (i = tmpmb->totcol; i-- > 0;) { /* are we an object material or data based? */ tmpmesh->mat[i] = give_current_material(object_input, i + 1); if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) { id_us_plus(&tmpmesh->mat[i]->id); } } } break; } case OB_MESH: if (!cage) { Mesh *origmesh = object_for_eval.data; tmpmesh->flag = origmesh->flag; tmpmesh->mat = MEM_dupallocN(origmesh->mat); tmpmesh->totcol = origmesh->totcol; tmpmesh->smoothresh = origmesh->smoothresh; if (origmesh->mat) { for (i = origmesh->totcol; i-- > 0;) { /* are we an object material or data based? */ tmpmesh->mat[i] = give_current_material(object_input, i + 1); if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) { id_us_plus(&tmpmesh->mat[i]->id); } } } } break; } /* end copy materials */ return tmpmesh; }
/* PolyFill function, uses Blenders scanfill to fill multiple poly lines */ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject *polyLineSeq) { PyObject *tri_list; /*return this list of tri's */ PyObject *polyLine, *polyVec; int i, len_polylines, len_polypoints, ls_error = 0; /* display listbase */ ListBase dispbase = {NULL, NULL}; DispList *dl; float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */ int index, *dl_face, totpoints = 0; if (!PySequence_Check(polyLineSeq)) { PyErr_SetString(PyExc_TypeError, "expected a sequence of poly lines"); return NULL; } len_polylines = PySequence_Size(polyLineSeq); for (i = 0; i < len_polylines; i++) { polyLine = PySequence_GetItem(polyLineSeq, i); if (!PySequence_Check(polyLine)) { BKE_displist_free(&dispbase); Py_XDECREF(polyLine); /* may be null so use Py_XDECREF*/ PyErr_SetString(PyExc_TypeError, "One or more of the polylines is not a sequence of mathutils.Vector's"); return NULL; } len_polypoints = PySequence_Size(polyLine); if (len_polypoints > 0) { /* don't bother adding edges as polylines */ #if 0 if (EXPP_check_sequence_consistency(polyLine, &vector_Type) != 1) { freedisplist(&dispbase); Py_DECREF(polyLine); PyErr_SetString(PyExc_TypeError, "A point in one of the polylines is not a mathutils.Vector type"); return NULL; } #endif dl = MEM_callocN(sizeof(DispList), "poly disp"); BLI_addtail(&dispbase, dl); dl->type = DL_INDEX3; dl->nr = len_polypoints; dl->type = DL_POLY; dl->parts = 1; /* no faces, 1 edge loop */ dl->col = 0; /* no material */ dl->verts = fp = MEM_callocN(sizeof(float) * 3 * len_polypoints, "dl verts"); dl->index = MEM_callocN(sizeof(int) * 3 * len_polypoints, "dl index"); for (index = 0; index < len_polypoints; index++, fp += 3) { polyVec = PySequence_GetItem(polyLine, index); if (VectorObject_Check(polyVec)) { if (BaseMath_ReadCallback((VectorObject *)polyVec) == -1) ls_error = 1; fp[0] = ((VectorObject *)polyVec)->vec[0]; fp[1] = ((VectorObject *)polyVec)->vec[1]; if (((VectorObject *)polyVec)->size > 2) fp[2] = ((VectorObject *)polyVec)->vec[2]; else fp[2] = 0.0f; /* if its a 2d vector then set the z to be zero */ } else { ls_error = 1; } totpoints++; Py_DECREF(polyVec); } } Py_DECREF(polyLine); } if (ls_error) { BKE_displist_free(&dispbase); /* possible some dl was allocated */ PyErr_SetString(PyExc_TypeError, "A point in one of the polylines " "is not a mathutils.Vector type"); return NULL; } else if (totpoints) { /* now make the list to return */ BKE_displist_fill(&dispbase, &dispbase, 0); /* The faces are stored in a new DisplayList * thats added to the head of the listbase */ dl = dispbase.first; tri_list = PyList_New(dl->parts); if (!tri_list) { BKE_displist_free(&dispbase); PyErr_SetString(PyExc_RuntimeError, "failed to make a new list"); return NULL; } index = 0; dl_face = dl->index; while (index < dl->parts) { PyList_SET_ITEM(tri_list, index, Py_BuildValue("iii", dl_face[0], dl_face[1], dl_face[2])); dl_face += 3; index++; } BKE_displist_free(&dispbase); } else { /* no points, do this so scripts don't barf */ BKE_displist_free(&dispbase); /* possible some dl was allocated */ tri_list = PyList_New(0); } return tri_list; }