Mesh *bc_get_mesh_copy(Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate) { Mesh *tmpmesh; CustomDataMask mask = CD_MASK_MESH; Mesh *mesh = (Mesh *)ob->data; DerivedMesh *dm = NULL; if (apply_modifiers) { switch (export_mesh_type) { case BC_MESH_TYPE_VIEW: { dm = mesh_create_derived_view(scene, ob, mask); break; } case BC_MESH_TYPE_RENDER: { dm = mesh_create_derived_render(scene, ob, mask); break; } } } else { dm = mesh_create_derived((Mesh *)ob->data, NULL); } tmpmesh = BKE_mesh_add(G.main, "ColladaMesh"); // name is not important here DM_to_mesh(dm, tmpmesh, ob, CD_MASK_MESH, true); tmpmesh->flag = mesh->flag; if (triangulate) { bc_triangulate_mesh(tmpmesh); } BKE_mesh_tessface_ensure(tmpmesh); return tmpmesh; }
// A replacement of BKE_object_add() for better performance. Object *BlenderStrokeRenderer::NewMesh() const { Object *ob; Base *base; char name[MAX_ID_NAME]; unsigned int mesh_id = get_stroke_mesh_id(); /* XXX this is for later review, for now we start names with 27 (DEL) to allow ignoring them in DAG_ids_check_recalc() */ BLI_snprintf(name, MAX_ID_NAME, "%c0%08xOB", 27, mesh_id); ob = BKE_object_add_only_object(freestyle_bmain, OB_MESH, name); BLI_snprintf(name, MAX_ID_NAME, "%c0%08xME", 27, mesh_id); ob->data = BKE_mesh_add(freestyle_bmain, name); ob->lay = 1; base = BKE_scene_base_add(freestyle_scene, ob); #if 0 BKE_scene_base_deselect_all(scene); BKE_scene_base_select(scene, base); #else (void)base; #endif ob->recalc = OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME; return ob; }
// create a mesh storing a pointer in a map so it can be retrieved later by geometry UID bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom) { if (geom->getType() != COLLADAFW::Geometry::GEO_TYPE_MESH) { // TODO: report warning fprintf(stderr, "Mesh type %s is not supported\n", bc_geomTypeToStr(geom->getType())); return true; } COLLADAFW::Mesh *mesh = (COLLADAFW::Mesh *)geom; if (!is_nice_mesh(mesh)) { fprintf(stderr, "Ignoring mesh %s\n", bc_get_dae_name(mesh).c_str()); return true; } const std::string& str_geom_id = mesh->getName().size() ? mesh->getName() : mesh->getOriginalId(); Mesh *me = BKE_mesh_add(G.main, (char *)str_geom_id.c_str()); me->id.us--; // is already 1 here, but will be set later in BKE_mesh_assign_object // store the Mesh pointer to link it later with an Object // mesh_geom_map needed to map mesh to its geometry name (for shape key naming) this->uid_mesh_map[mesh->getUniqueId()] = me; this->mesh_geom_map[std::string(me->id.name)] = str_geom_id; read_vertices(mesh, me); read_polys(mesh, me); BKE_mesh_calc_edges(me, false, false); // read_lines() must be called after the face edges have been generated. // Oterwise the loose edges will be silently deleted again. read_lines(mesh, me); return true; }
/* 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; }
/* this may fail replacing ob->data, be sure to check ob->type */ void BKE_mesh_from_nurbs_displist(Main *bmain, Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name, bool temporary) { Object *ob1; Mesh *me_eval = ob->runtime.mesh_eval; Mesh *me; Curve *cu; MVert *allvert = NULL; MEdge *alledge = NULL; MLoop *allloop = NULL; MLoopUV *alluv = NULL; MPoly *allpoly = NULL; int totvert, totedge, totloop, totpoly; cu = ob->data; if (me_eval == NULL) { if (BKE_mesh_nurbs_displist_to_mdata(ob, dispbase, &allvert, &totvert, &alledge, &totedge, &allloop, &allpoly, (use_orco_uv) ? &alluv : NULL, &totloop, &totpoly) != 0) { /* Error initializing */ return; } /* make mesh */ me = BKE_mesh_add(bmain, obdata_name); me->totvert = totvert; me->totedge = totedge; me->totloop = totloop; me->totpoly = totpoly; me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, allvert, me->totvert); me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, alledge, me->totedge); me->mloop = CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, allloop, me->totloop); me->mpoly = CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly); if (alluv) { const char *uvname = "Orco"; me->mloopuv = CustomData_add_layer_named( &me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname); } BKE_mesh_calc_normals(me); } else { me = BKE_mesh_add(bmain, obdata_name); ob->runtime.mesh_eval = NULL; BKE_mesh_nomain_to_mesh(me_eval, me, ob, &CD_MASK_MESH, true); } me->totcol = cu->totcol; me->mat = cu->mat; /* Copy evaluated texture space from curve to mesh. * * Note that we disable auto texture space feature since that will cause * texture space to evaluate differently for curve and mesh, since curve * uses CV to calculate bounding box, and mesh uses what is coming from * tessellated curve. */ me->texflag = cu->texflag & ~CU_AUTOSPACE; copy_v3_v3(me->loc, cu->loc); copy_v3_v3(me->size, cu->size); copy_v3_v3(me->rot, cu->rot); BKE_mesh_texspace_calc(me); cu->mat = NULL; cu->totcol = 0; /* Do not decrement ob->data usercount here, * it's done at end of func with BKE_id_free_us() call. */ ob->data = me; ob->type = OB_MESH; /* other users */ ob1 = bmain->objects.first; while (ob1) { if (ob1->data == cu) { ob1->type = OB_MESH; id_us_min((ID *)ob1->data); ob1->data = ob->data; id_us_plus((ID *)ob1->data); } ob1 = ob1->id.next; } if (temporary) { /* For temporary objects in BKE_mesh_new_from_object don't remap * the entire scene with associated depsgraph updates, which are * problematic for renderers exporting data. */ BKE_id_free(NULL, cu); } else { BKE_id_free_us(bmain, cu); } }