static void vpaint_proj_dm_map_cosnos_update( struct VertProjHandle *vp_handle, ARegion *ar, const float mval_fl[2]) { struct VertProjUpdate vp_update = {vp_handle, ar, mval_fl}; Scene *scene = vp_handle->scene; Object *ob = vp_handle->ob; Mesh *me = ob->data; DerivedMesh *dm; /* quick sanity check - we shouldn't have to run this if there are no modifiers */ BLI_assert(BLI_listbase_is_empty(&ob->modifiers) == false); dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX); /* highly unlikely this will become unavailable once painting starts (perhaps with animated modifiers) */ if (LIKELY(dm->foreachMappedVert)) { copy_vn_fl(vp_handle->dists_sq, me->totvert, FLT_MAX); dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_update__map_cb, &vp_update, DM_FOREACH_USE_NORMAL); } dm->release(dm); }
DupliApplyData *duplilist_apply(Object *ob, Scene *scene, ListBase *duplilist) { DupliApplyData *apply_data = NULL; int num_objects = BLI_listbase_count(duplilist); if (num_objects > 0) { DupliObject *dob; int i; apply_data = MEM_mallocN(sizeof(DupliApplyData), "DupliObject apply data"); apply_data->num_objects = num_objects; apply_data->extra = MEM_mallocN(sizeof(DupliExtraData) * (size_t) num_objects, "DupliObject apply extra data"); for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) { /* copy obmat from duplis */ copy_m4_m4(apply_data->extra[i].obmat, dob->ob->obmat); /* make sure derivedmesh is calculated once, before drawing */ if (scene && !(dob->ob->transflag & OB_DUPLICALCDERIVED) && dob->ob->type == OB_MESH) { mesh_get_derived_final(scene, dob->ob, scene->customdata_mask); dob->ob->transflag |= OB_DUPLICALCDERIVED; } copy_m4_m4(dob->ob->obmat, dob->mat); /* copy layers from the main duplicator object */ apply_data->extra[i].lay = dob->ob->lay; dob->ob->lay = ob->lay; } } return apply_data; }
static void make_duplis_verts(const DupliContext *ctx) { Scene *scene = ctx->scene; Object *parent = ctx->object; bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW); VertexDupliData vdd; vdd.ctx = ctx; vdd.use_rotation = parent->transflag & OB_DUPLIROT; /* gather mesh info */ { Mesh *me = parent->data; BMEditMesh *em = BKE_editmesh_from_object(parent); CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO : CD_MASK_BAREMESH); if (em) vdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask); else vdd.dm = mesh_get_derived_final(scene, parent, dm_mask); vdd.edit_btmesh = me->edit_btmesh; if (use_texcoords) vdd.orco = vdd.dm->getVertDataArray(vdd.dm, CD_ORCO); else vdd.orco = NULL; vdd.totvert = vdd.dm->getNumVerts(vdd.dm); } make_child_duplis(ctx, &vdd, make_child_duplis_verts); vdd.dm->release(vdd.dm); }
static int mask_flood_fill_exec(bContext *C, wmOperator *op) { ARegion *ar = CTX_wm_region(C); Object *ob = CTX_data_active_object(C); PaintMaskFloodMode mode; float value; DerivedMesh *dm; PBVH *pbvh; PBVHNode **nodes; int totnode, i; mode = RNA_enum_get(op->ptr, "mode"); value = RNA_float_get(op->ptr, "value"); dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH); pbvh = dm->getPBVH(ob, dm); ob->sculpt->pbvh = pbvh; BLI_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); sculpt_undo_push_begin("Mask flood fill"); for (i = 0; i < totnode; i++) { PBVHVertexIter vi; sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK); BLI_pbvh_vertex_iter_begin(pbvh, nodes[i], vi, PBVH_ITER_UNIQUE) { mask_flood_fill_set_elem(vi.mask, mode, value); } BLI_pbvh_vertex_iter_end; BLI_pbvh_node_mark_update(nodes[i]); if (BLI_pbvh_type(pbvh) == PBVH_GRIDS) multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); }
static LinkNode *knifeproject_poly_from_object(ARegion *ar, Scene *scene, Object *ob, LinkNode *polys) { DerivedMesh *dm; bool dm_needsFree; if (ob->type == OB_MESH || ob->derivedFinal) { dm = ob->derivedFinal ? ob->derivedFinal : mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); dm_needsFree = false; } else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { dm = CDDM_from_curve(ob); dm_needsFree = true; } else { dm = NULL; } if (dm) { ListBase nurbslist = {NULL, NULL}; float projmat[4][4]; BKE_mesh_to_curve_nurblist(dm, &nurbslist, 0); /* wire */ BKE_mesh_to_curve_nurblist(dm, &nurbslist, 1); /* boundary */ ED_view3d_ob_project_mat_get(ar->regiondata, ob, projmat); if (nurbslist.first) { Nurb *nu; for (nu = nurbslist.first; nu; nu = nu->next) { if (nu->bp) { int a; BPoint *bp; bool is_cyclic = (nu->flagu & CU_NURB_CYCLIC) != 0; float (*mval)[2] = MEM_mallocN(sizeof(*mval) * (nu->pntsu + is_cyclic), __func__); for (bp = nu->bp, a = 0; a < nu->pntsu; a++, bp++) { ED_view3d_project_float_v2_m4(ar, bp->vec, mval[a], projmat); } if (is_cyclic) { copy_v2_v2(mval[a], mval[0]); } BLI_linklist_prepend(&polys, mval); } } } BKE_nurbList_free(&nurbslist); if (dm_needsFree) { dm->release(dm); } } return polys; }
int NewBooleanMesh(Scene *scene, Base *base, Base *base_select, int int_op_type) { Mesh *me_new; int a, maxmat, totmat= 0; Object *ob_new, *ob, *ob_select; Material **mat; DerivedMesh *result; DerivedMesh *dm_select; DerivedMesh *dm; ob= base->object; ob_select= base_select->object; dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); dm_select = mesh_create_derived_view(scene, ob_select, 0); // no modifiers in editmode ?? maxmat= ob->totcol + ob_select->totcol; mat= (Material**)MEM_mallocN(sizeof(Material*)*maxmat, "NewBooleanMeshMat"); /* put some checks in for nice user feedback */ if (dm == NULL || dm_select == NULL) return 0; if (!dm->getNumFaces(dm) || !dm_select->getNumFaces(dm_select)) { MEM_freeN(mat); return -1; } result= NewBooleanDerivedMesh_intern(dm, ob, dm_select, ob_select, int_op_type, mat, &totmat); if (result == NULL) { MEM_freeN(mat); return 0; } /* create a new blender mesh object - using 'base' as a template */ ob_new= AddNewBlenderMesh(scene, base_select); me_new= ob_new->data; DM_to_mesh(result, me_new); result->release(result); dm->release(dm); dm_select->release(dm_select); /* add materials to object */ for (a = 0; a < totmat; a++) assign_material(ob_new, mat[a], a+1); MEM_freeN(mat); /* update dag */ DAG_id_tag_update(&ob_new->id, OB_RECALC_DATA); return 1; }
static int mask_flood_fill_exec(bContext *C, wmOperator *op) { ARegion *ar = CTX_wm_region(C); struct Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); struct MultiresModifierData *mmd = sculpt_multires_active(scene, ob); PaintMaskFloodMode mode; float value; DerivedMesh *dm; PBVH *pbvh; PBVHNode **nodes; int totnode, i; #ifdef _OPENMP Sculpt *sd = CTX_data_tool_settings(C)->sculpt; #endif mode = RNA_enum_get(op->ptr, "mode"); value = RNA_float_get(op->ptr, "value"); ED_sculpt_mask_layers_ensure(ob, mmd); dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); pbvh = dm->getPBVH(ob, dm); ob->sculpt->pbvh = pbvh; BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); sculpt_undo_push_begin("Mask flood fill"); #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) for (i = 0; i < totnode; i++) { PBVHVertexIter vi; sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK); BKE_pbvh_vertex_iter_begin(pbvh, nodes[i], vi, PBVH_ITER_UNIQUE) { mask_flood_fill_set_elem(vi.mask, mode, value); } BKE_pbvh_vertex_iter_end; BKE_pbvh_node_mark_redraw(nodes[i]); if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); }
static void make_duplis_faces(const DupliContext *ctx) { Scene *scene = ctx->scene; Object *parent = ctx->object; bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW); FaceDupliData fdd; fdd.use_scale = ((parent->transflag & OB_DUPLIFACES_SCALE) != 0); /* gather mesh info */ { BMEditMesh *em = BKE_editmesh_from_object(parent); CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO | CD_MASK_MLOOPUV : CD_MASK_BAREMESH); if (em) fdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask); else fdd.dm = mesh_get_derived_final(scene, parent, dm_mask); if (use_texcoords) { CustomData *ml_data = fdd.dm->getLoopDataLayout(fdd.dm); const int uv_idx = CustomData_get_render_layer(ml_data, CD_MLOOPUV); fdd.orco = fdd.dm->getVertDataArray(fdd.dm, CD_ORCO); fdd.mloopuv = CustomData_get_layer_n(ml_data, CD_MLOOPUV, uv_idx); } else { fdd.orco = NULL; fdd.mloopuv = NULL; } fdd.totface = fdd.dm->getNumPolys(fdd.dm); fdd.mpoly = fdd.dm->getPolyArray(fdd.dm); fdd.mloop = fdd.dm->getLoopArray(fdd.dm); fdd.mvert = fdd.dm->getVertArray(fdd.dm); } make_child_duplis(ctx, &fdd, make_child_duplis_faces); fdd.dm->release(fdd.dm); }
static void make_duplis_faces(const DupliContext *ctx) { Scene *scene = ctx->scene; Object *parent = ctx->object; bool for_render = ctx->eval_ctx->for_render; FaceDupliData fdd; fdd.use_scale = ((parent->transflag & OB_DUPLIFACES_SCALE) != 0); /* gather mesh info */ { BMEditMesh *em = BKE_editmesh_from_object(parent); CustomDataMask dm_mask = (for_render ? CD_MASK_BAREMESH | CD_MASK_ORCO | CD_MASK_MLOOPUV : CD_MASK_BAREMESH); if (em) fdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask); else fdd.dm = mesh_get_derived_final(scene, parent, dm_mask); if (for_render) { fdd.orco = fdd.dm->getVertDataArray(fdd.dm, CD_ORCO); fdd.mloopuv = fdd.dm->getLoopDataArray(fdd.dm, CD_MLOOPUV); } else { fdd.orco = NULL; fdd.mloopuv = NULL; } fdd.totface = fdd.dm->getNumPolys(fdd.dm); fdd.mpoly = fdd.dm->getPolyArray(fdd.dm); fdd.mloop = fdd.dm->getLoopArray(fdd.dm); fdd.mvert = fdd.dm->getVertArray(fdd.dm); } make_child_duplis(ctx, &fdd, make_child_duplis_faces); fdd.dm->release(fdd.dm); }
static void vpaint_proj_dm_map_cosnos_init( Scene *scene, Object *ob, struct VertProjHandle *vp_handle) { Mesh *me = ob->data; DerivedMesh *dm; dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX); if (dm->foreachMappedVert) { memset(vp_handle->vcosnos, 0, sizeof(DMCoNo) * me->totvert); dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_init__map_cb, vp_handle, DM_FOREACH_USE_NORMAL); } else { DMCoNo *v_co_no = vp_handle->vcosnos; int a; for (a = 0; a < me->totvert; a++, v_co_no++) { dm->getVertCo(dm, a, v_co_no->co); dm->getVertNo(dm, a, v_co_no->no); } } dm->release(dm); }
/* used for both 3d view and image window */ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_proj, bool use_palette) { Scene *scene = CTX_data_scene(C); Paint *paint = BKE_paint_get_active_from_context(C); Palette *palette = BKE_paint_palette(paint); PaletteColor *color; Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C)); unsigned int col; const unsigned char *cp; CLAMP(x, 0, ar->winx); CLAMP(y, 0, ar->winy); if (use_palette) { if (!palette) { palette = BKE_palette_add(CTX_data_main(C), "Palette"); BKE_paint_palette_set(paint, palette); } color = BKE_palette_color_add(palette); } if (CTX_wm_view3d(C) && texpaint_proj) { /* first try getting a colour directly from the mesh faces if possible */ Object *ob = OBACT; bool sample_success = false; if (ob) { DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); ViewContext vc; const int mval[2] = {x, y}; unsigned int faceindex; unsigned int totface = dm->getNumTessFaces(dm); MTFace *dm_mtface = dm->getTessFaceDataArray(dm, CD_MTFACE); DM_update_materials(dm, ob); if (dm_mtface) { view3d_set_viewcontext(C, &vc); view3d_operator_needs_opengl(C); if (imapaint_pick_face(&vc, mval, &faceindex, totface)) { Image *image = imapaint_face_image(dm, faceindex); ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL); if (ibuf && ibuf->rect) { float uv[2]; float u, v; imapaint_pick_uv(scene, ob, faceindex, mval, uv); sample_success = true; u = fmodf(uv[0], 1.0f); v = fmodf(uv[1], 1.0f); if (u < 0.0f) u += 1.0f; if (v < 0.0f) v += 1.0f; u = u * ibuf->x - 0.5f; v = v * ibuf->y - 0.5f; if (ibuf->rect_float) { float rgba_f[4]; bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v); straight_to_premul_v4(rgba_f); if (use_palette) { linearrgb_to_srgb_v3_v3(color->rgb, rgba_f); } else { linearrgb_to_srgb_v3_v3(rgba_f, rgba_f); BKE_brush_color_set(scene, br, rgba_f); } } else { unsigned char rgba[4]; bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v); if (use_palette) { rgb_uchar_to_float(color->rgb, rgba); } else { float rgba_f[3]; rgb_uchar_to_float(rgba_f, rgba); BKE_brush_color_set(scene, br, rgba_f); } } } BKE_image_release_ibuf(image, ibuf, NULL); } } dm->release(dm); } if (!sample_success) { glReadBuffer(GL_FRONT); glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); glReadBuffer(GL_BACK); } else return; } else { glReadBuffer(GL_FRONT); glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); glReadBuffer(GL_BACK); } cp = (unsigned char *)&col; if (use_palette) { rgb_uchar_to_float(color->rgb, cp); } else { float rgba_f[3]; rgb_uchar_to_float(rgba_f, cp); BKE_brush_color_set(scene, br, rgba_f); } }
static int hide_show_exec(bContext *C, wmOperator *op) { ARegion *ar = CTX_wm_region(C); Object *ob = CTX_data_active_object(C); Mesh *me = ob->data; PartialVisAction action; PartialVisArea area; PBVH *pbvh; PBVHNode **nodes; DerivedMesh *dm; PBVHType pbvh_type; float clip_planes[4][4]; rcti rect; int totnode, i; /* read operator properties */ action = RNA_enum_get(op->ptr, "action"); area = RNA_enum_get(op->ptr, "area"); rect_from_props(&rect, op->ptr); clip_planes_from_rect(C, clip_planes, &rect); dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH); pbvh = dm->getPBVH(ob, dm); ob->sculpt->pbvh = pbvh; get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area); pbvh_type = BLI_pbvh_type(pbvh); /* start undo */ switch (action) { case PARTIALVIS_HIDE: sculpt_undo_push_begin("Hide area"); break; case PARTIALVIS_SHOW: sculpt_undo_push_begin("Show area"); break; } for (i = 0; i < totnode; i++) { switch (pbvh_type) { case PBVH_FACES: partialvis_update_mesh(ob, pbvh, nodes[i], action, area, clip_planes); break; case PBVH_GRIDS: partialvis_update_grids(ob, pbvh, nodes[i], action, area, clip_planes); break; } } if (nodes) MEM_freeN(nodes); /* end undo */ sculpt_undo_push_end(); /* ensure that edges and faces get hidden as well (not used by * sculpt but it looks wrong when entering editmode otherwise) */ if (pbvh_type == PBVH_FACES) { BKE_mesh_flush_hidden_from_verts(me->mvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly); } ED_region_tag_redraw(ar); return OPERATOR_FINISHED; }
static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par, int heat, const bool mirror) { /* This functions implements the automatic computation of vertex group * weights, either through envelopes or using a heat equilibrium. * * This function can be called both when parenting a mesh to an armature, * or in weightpaint + posemode. In the latter case selection is taken * into account and vertex weights can be mirrored. * * The mesh vertex positions used are either the final deformed coords * from the derivedmesh in weightpaint mode, the final subsurf coords * when parenting, or simply the original mesh coords. */ bArmature *arm = par->data; Bone **bonelist, *bone; bDeformGroup **dgrouplist, **dgroupflip; bDeformGroup *dgroup; bPoseChannel *pchan; Mesh *mesh; Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = NULL; float (*root)[3], (*tip)[3], (*verts)[3]; int *selected; int numbones, vertsfilled = 0, i, j, segments = 0; int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT); struct { Object *armob; void *list; int heat; } looper_data; looper_data.armob = par; looper_data.heat = heat; looper_data.list = NULL; /* count the number of skinnable bones */ numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb); if (numbones == 0) return; if (BKE_object_defgroup_data_create(ob->data) == NULL) return; /* create an array of pointer to bones that are skinnable * and fill it with all of the skinnable bones */ bonelist = MEM_callocN(numbones * sizeof(Bone *), "bonelist"); looper_data.list = bonelist; bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb); /* create an array of pointers to the deform groups that * correspond to the skinnable bones (creating them * as necessary. */ dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist"); dgroupflip = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgroupflip"); looper_data.list = dgrouplist; bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb); /* create an array of root and tip positions transformed into * global coords */ root = MEM_callocN(numbones * sizeof(float) * 3, "root"); tip = MEM_callocN(numbones * sizeof(float) * 3, "tip"); selected = MEM_callocN(numbones * sizeof(int), "selected"); for (j = 0; j < numbones; ++j) { bone = bonelist[j]; dgroup = dgrouplist[j]; /* handle bbone */ if (heat) { if (segments == 0) { segments = 1; bbone = NULL; if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) { if (bone->segments > 1) { segments = bone->segments; b_bone_spline_setup(pchan, 1, bbone_array); bbone = bbone_array; } } } segments--; } /* compute root and tip */ if (bbone) { mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]); if ((segments + 1) < bone->segments) { mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]); } else { copy_v3_v3(tip[j], bone->arm_tail); } } else { copy_v3_v3(root[j], bone->arm_head); copy_v3_v3(tip[j], bone->arm_tail); } mul_m4_v3(par->obmat, root[j]); mul_m4_v3(par->obmat, tip[j]); /* set selected */ if (wpmode) { if ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED)) selected[j] = 1; } else selected[j] = 1; /* find flipped group */ if (dgroup && mirror) { char name_flip[MAXBONENAME]; BKE_deform_flip_side_name(name_flip, dgroup->name, false); dgroupflip[j] = defgroup_find_name(ob, name_flip); } } /* create verts */ mesh = (Mesh *)ob->data; verts = MEM_callocN(mesh->totvert * sizeof(*verts), "closestboneverts"); if (wpmode) { /* if in weight paint mode, use final verts from derivedmesh */ DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); if (dm->foreachMappedVert) { mesh_get_mapped_verts_coords(dm, verts, mesh->totvert); vertsfilled = 1; } dm->release(dm); } else if (modifiers_findByType(ob, eModifierType_Subsurf)) { /* is subsurf on? Lets use the verts on the limit surface then. * = same amount of vertices as mesh, but vertices moved to the * subsurfed position, like for 'optimal'. */ subsurf_calculate_limit_positions(mesh, verts); vertsfilled = 1; } /* transform verts to global space */ for (i = 0; i < mesh->totvert; i++) { if (!vertsfilled) copy_v3_v3(verts[i], mesh->mvert[i].co); mul_m4_v3(ob->obmat, verts[i]); } /* compute the weights based on gathered vertices and bones */ if (heat) { const char *error = NULL; heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip, root, tip, selected, &error); if (error) { BKE_report(reports, RPT_WARNING, error); } } else { envelope_bone_weighting(ob, mesh, verts, numbones, bonelist, dgrouplist, dgroupflip, root, tip, selected, mat4_to_scale(par->obmat)); } /* only generated in some cases but can call anyway */ ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e'); /* free the memory allocated */ MEM_freeN(bonelist); MEM_freeN(dgrouplist); MEM_freeN(dgroupflip); MEM_freeN(root); MEM_freeN(tip); MEM_freeN(selected); MEM_freeN(verts); }
/* Note: rna_enum_dt_layers_select_src_items enum is from rna_modifier.c */ static EnumPropertyItem *dt_layers_select_src_itemf( bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) { EnumPropertyItem *item = NULL, tmp_item = {0}; int totitem = 0; const int data_type = RNA_enum_get(ptr, "data_type"); if (!C) { /* needed for docs and i18n tools */ return rna_enum_dt_layers_select_src_items; } RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ACTIVE_SRC); RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ALL_SRC); if (data_type == DT_TYPE_MDEFORMVERT) { Object *ob_src = CTX_data_active_object(C); if (BKE_object_pose_armature_get(ob_src)) { RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_SELECT); RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_DEFORM); } if (ob_src) { bDeformGroup *dg; int i; RNA_enum_item_add_separator(&item, &totitem); for (i = 0, dg = ob_src->defbase.first; dg; i++, dg = dg->next) { tmp_item.value = i; tmp_item.identifier = tmp_item.name = dg->name; RNA_enum_item_add(&item, &totitem, &tmp_item); } } } else if (data_type == DT_TYPE_SHAPEKEY) { /* TODO */ } else if (data_type == DT_TYPE_UV) { Object *ob_src = CTX_data_active_object(C); Scene *scene = CTX_data_scene(C); if (ob_src) { DerivedMesh *dm_src; CustomData *pdata; int num_data, i; /* XXX Is this OK? */ dm_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MTEXPOLY); pdata = dm_src->getPolyDataLayout(dm_src); num_data = CustomData_number_of_layers(pdata, CD_MTEXPOLY); RNA_enum_item_add_separator(&item, &totitem); for (i = 0; i < num_data; i++) { tmp_item.value = i; tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(pdata, CD_MTEXPOLY, i); RNA_enum_item_add(&item, &totitem, &tmp_item); } } } else if (data_type == DT_TYPE_VCOL) { Object *ob_src = CTX_data_active_object(C); Scene *scene = CTX_data_scene(C); if (ob_src) { DerivedMesh *dm_src; CustomData *ldata; int num_data, i; /* XXX Is this OK? */ dm_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPCOL); ldata = dm_src->getLoopDataLayout(dm_src); num_data = CustomData_number_of_layers(ldata, CD_MLOOPCOL); RNA_enum_item_add_separator(&item, &totitem); for (i = 0; i < num_data; i++) { tmp_item.value = i; tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(ldata, CD_MLOOPCOL, i); RNA_enum_item_add(&item, &totitem, &tmp_item); } } } RNA_enum_item_end(&item, &totitem); *r_free = true; return item; }
/** * Transfer data *layout* of selected types from source to destination object. * By default, it only creates new data layers if needed on \a ob_dst. * If \a use_delete is true, it will also delete data layers on \a ob_dst that do not match those from \a ob_src, * to get (as much as possible) exact copy of source data layout. */ void BKE_object_data_transfer_layout( Scene *scene, Object *ob_src, Object *ob_dst, const int data_types, const bool use_delete, const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX]) { DerivedMesh *dm_src; Mesh *me_dst; int i; const bool use_create = true; /* We always create needed layers here. */ CustomDataMask dm_src_mask = CD_MASK_BAREMESH; BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH)); me_dst = ob_dst->data; /* Get source DM.*/ dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types); dm_src = mesh_get_derived_final(scene, ob_src, dm_src_mask); if (!dm_src) { return; } /* Check all possible data types. */ for (i = 0; i < DT_TYPE_MAX; i++) { const int dtdata_type = 1 << i; int cddata_type; int fromlayers, tolayers, fromto_idx; if (!(data_types & dtdata_type)) { continue; } cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type); fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type); if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) { fromlayers = fromlayers_select[fromto_idx]; tolayers = tolayers_select[fromto_idx]; } else { fromlayers = tolayers = 0; } if (DT_DATATYPE_IS_VERT(dtdata_type)) { const int num_elem_dst = me_dst->totvert; data_transfer_layersmapping_generate( NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_VERT, cddata_type, 0, 0.0f, NULL, num_elem_dst, use_create, use_delete, fromlayers, tolayers); } if (DT_DATATYPE_IS_EDGE(dtdata_type)) { const int num_elem_dst = me_dst->totedge; data_transfer_layersmapping_generate( NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_EDGE, cddata_type, 0, 0.0f, NULL, num_elem_dst, use_create, use_delete, fromlayers, tolayers); } if (DT_DATATYPE_IS_LOOP(dtdata_type)) { const int num_elem_dst = me_dst->totloop; data_transfer_layersmapping_generate( NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_LOOP, cddata_type, 0, 0.0f, NULL, num_elem_dst, use_create, use_delete, fromlayers, tolayers); } if (DT_DATATYPE_IS_POLY(dtdata_type)) { const int num_elem_dst = me_dst->totpoly; data_transfer_layersmapping_generate( NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_POLY, cddata_type, 0, 0.0f, NULL, num_elem_dst, use_create, use_delete, fromlayers, tolayers); } } }
/* compute uv coordinates of mouse in face */ void imapaint_pick_uv(Scene *scene, Object *ob, Mesh *mesh, unsigned int faceindex, int *xy, float *uv) { DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX); MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf; int numfaces = dm->getNumFaces(dm), a; float p[2], w[3], absw, minabsw; MFace mf; MVert mv[4]; minabsw = 1e10; uv[0] = uv[1] = 0.0; /* test all faces in the derivedmesh with the original index of the picked face */ for(a = 0; a < numfaces; a++) { if(index[a] == faceindex) { dm->getFace(dm, a, &mf); dm->getVert(dm, mf.v1, &mv[0]); dm->getVert(dm, mf.v2, &mv[1]); dm->getVert(dm, mf.v3, &mv[2]); if(mf.v4) dm->getVert(dm, mf.v4, &mv[3]); tf= &tface[a]; p[0]= xy[0]; p[1]= xy[1]; if(mf.v4) { /* the triangle with the largest absolute values is the one with the most negative weights */ imapaint_tri_weights(ob, mv[0].co, mv[1].co, mv[3].co, p, w); absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]); if(absw < minabsw) { uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[3][0]*w[2]; uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[3][1]*w[2]; minabsw = absw; } imapaint_tri_weights(ob, mv[1].co, mv[2].co, mv[3].co, p, w); absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]); if(absw < minabsw) { uv[0]= tf->uv[1][0]*w[0] + tf->uv[2][0]*w[1] + tf->uv[3][0]*w[2]; uv[1]= tf->uv[1][1]*w[0] + tf->uv[2][1]*w[1] + tf->uv[3][1]*w[2]; minabsw = absw; } } else { imapaint_tri_weights(ob, mv[0].co, mv[1].co, mv[2].co, p, w); absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]); if(absw < minabsw) { uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[2][0]*w[2]; uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[2][1]*w[2]; minabsw = absw; } } } } dm->release(dm); }
bool BKE_object_data_transfer_dm( Scene *scene, Object *ob_src, Object *ob_dst, DerivedMesh *dm_dst, const int data_types, bool use_create, const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode, SpaceTransform *space_transform, const float max_distance, const float ray_radius, const float islands_handling_precision, const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX], const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup, ReportList *reports) { #define VDATA 0 #define EDATA 1 #define LDATA 2 #define PDATA 3 #define DATAMAX 4 DerivedMesh *dm_src; Mesh *me_dst, *me_src; bool dirty_nors_dst = true; /* Assumed always true if not using a dm as destination. */ int i; MDeformVert *mdef = NULL; int vg_idx = -1; float *weights[DATAMAX] = {NULL}; MeshPairRemap geom_map[DATAMAX] = {{0}}; bool geom_map_init[DATAMAX] = {0}; ListBase lay_map = {NULL}; bool changed = false; const bool use_delete = false; /* We never delete data layers from destination here. */ CustomDataMask dm_src_mask = CD_MASK_BAREMESH; BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH)); me_dst = ob_dst->data; me_src = ob_src->data; if (dm_dst) { dirty_nors_dst = (dm_dst->dirty & DM_DIRTY_NORMALS) != 0; use_create = false; /* Never create needed custom layers on DM (modifier case). */ } if (vgroup_name) { if (dm_dst) { mdef = dm_dst->getVertDataArray(dm_dst, CD_MDEFORMVERT); } else { mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT); } if (mdef) { vg_idx = defgroup_name_index(ob_dst, vgroup_name); } } /* Get source DM.*/ dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types); /* XXX Hack! In case this is being evaluated from dm stack, we cannot compute final dm, * can lead to infinite recursion in case of dependency cycles of DataTransfer modifiers... * Issue is, this means we cannot be sure to have requested cd layers in source. */ dm_src = dm_dst ? ob_src->derivedFinal : mesh_get_derived_final(scene, ob_src, dm_src_mask); if (!dm_src) { return changed; } /* Check all possible data types. * Note item mappings and dest mix weights are cached. */ for (i = 0; i < DT_TYPE_MAX; i++) { const int dtdata_type = 1 << i; int cddata_type; int fromlayers, tolayers, fromto_idx; if (!(data_types & dtdata_type)) { continue; } data_transfer_dtdata_type_preprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, dtdata_type, dirty_nors_dst, (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh); cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type); fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type); if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) { fromlayers = fromlayers_select[fromto_idx]; tolayers = tolayers_select[fromto_idx]; } else { fromlayers = tolayers = 0; } if (DT_DATATYPE_IS_VERT(dtdata_type)) { MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; if (!geom_map_init[VDATA]) { const int num_verts_src = dm_src->getNumVerts(dm_src); if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != num_verts_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of vertices, " "'Topology' mapping cannot be used in this case"); return changed; } if (ELEM(0, num_verts_dst, num_verts_src)) { BKE_report(reports, RPT_ERROR, "Source or destination meshes do not have any vertices, cannot transfer vertex data"); return changed; } BKE_mesh_remap_calc_verts_from_dm( map_vert_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, dirty_nors_dst, dm_src, &geom_map[VDATA]); geom_map_init[VDATA] = true; } if (mdef && vg_idx != -1 && !weights[VDATA]) { weights[VDATA] = MEM_mallocN(sizeof(*(weights[VDATA])) * (size_t)num_verts_dst, __func__); BKE_defvert_extract_vgroup_to_vertweights(mdef, vg_idx, num_verts_dst, weights[VDATA], invert_vgroup); } if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_VERT, cddata_type, mix_mode, mix_factor, weights[VDATA], num_verts_dst, use_create, use_delete, fromlayers, tolayers)) { CustomDataTransferLayerMap *lay_mapit; changed = (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[VDATA], lay_mapit); } BLI_freelistN(&lay_map); } } if (DT_DATATYPE_IS_EDGE(dtdata_type)) { MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; if (!geom_map_init[EDATA]) { const int num_edges_src = dm_src->getNumEdges(dm_src); if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != num_edges_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of edges, " "'Topology' mapping cannot be used in this case"); return changed; } if (ELEM(0, num_edges_dst, num_edges_src)) { BKE_report(reports, RPT_ERROR, "Source or destination meshes do not have any edges, cannot transfer edge data"); return changed; } BKE_mesh_remap_calc_edges_from_dm( map_edge_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, edges_dst, num_edges_dst, dirty_nors_dst, dm_src, &geom_map[EDATA]); geom_map_init[EDATA] = true; } if (mdef && vg_idx != -1 && !weights[EDATA]) { weights[EDATA] = MEM_mallocN(sizeof(*weights[EDATA]) * (size_t)num_edges_dst, __func__); BKE_defvert_extract_vgroup_to_edgeweights( mdef, vg_idx, num_verts_dst, edges_dst, num_edges_dst, weights[EDATA], invert_vgroup); } if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_EDGE, cddata_type, mix_mode, mix_factor, weights[EDATA], num_edges_dst, use_create, use_delete, fromlayers, tolayers)) { CustomDataTransferLayerMap *lay_mapit; changed = (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[EDATA], lay_mapit); } BLI_freelistN(&lay_map); } } if (DT_DATATYPE_IS_LOOP(dtdata_type)) { MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata; MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type); if (!geom_map_init[LDATA]) { const int num_loops_src = dm_src->getNumLoops(dm_src); if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != num_loops_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of face corners, " "'Topology' mapping cannot be used in this case"); return changed; } if (ELEM(0, num_loops_dst, num_loops_src)) { BKE_report(reports, RPT_ERROR, "Source or destination meshes do not have any polygons, cannot transfer loop data"); return changed; } BKE_mesh_remap_calc_loops_from_dm( map_loop_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, edges_dst, num_edges_dst, loops_dst, num_loops_dst, polys_dst, num_polys_dst, ldata_dst, pdata_dst, (me_dst->flag & ME_AUTOSMOOTH) != 0, me_dst->smoothresh, dirty_nors_dst, dm_src, (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh, island_callback, islands_handling_precision, &geom_map[LDATA]); geom_map_init[LDATA] = true; } if (mdef && vg_idx != -1 && !weights[LDATA]) { weights[LDATA] = MEM_mallocN(sizeof(*weights[LDATA]) * (size_t)num_loops_dst, __func__); BKE_defvert_extract_vgroup_to_loopweights( mdef, vg_idx, num_verts_dst, loops_dst, num_loops_dst, weights[LDATA], invert_vgroup); } if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_LOOP, cddata_type, mix_mode, mix_factor, weights[LDATA], num_loops_dst, use_create, use_delete, fromlayers, tolayers)) { CustomDataTransferLayerMap *lay_mapit; changed = (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[LDATA], lay_mapit); } BLI_freelistN(&lay_map); } } if (DT_DATATYPE_IS_POLY(dtdata_type)) { MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; if (!geom_map_init[PDATA]) { const int num_polys_src = dm_src->getNumPolys(dm_src); if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != num_polys_src)) { BKE_report(reports, RPT_ERROR, "Source and destination meshes do not have the same amount of faces, " "'Topology' mapping cannot be used in this case"); return changed; } if (ELEM(0, num_polys_dst, num_polys_src)) { BKE_report(reports, RPT_ERROR, "Source or destination meshes do not have any polygons, cannot transfer poly data"); return changed; } BKE_mesh_remap_calc_polys_from_dm( map_poly_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, loops_dst, num_loops_dst, polys_dst, num_polys_dst, pdata_dst, dirty_nors_dst, dm_src, &geom_map[PDATA]); geom_map_init[PDATA] = true; } if (mdef && vg_idx != -1 && !weights[PDATA]) { weights[PDATA] = MEM_mallocN(sizeof(*weights[PDATA]) * (size_t)num_polys_dst, __func__); BKE_defvert_extract_vgroup_to_polyweights( mdef, vg_idx, num_verts_dst, loops_dst, num_loops_dst, polys_dst, num_polys_dst, weights[PDATA], invert_vgroup); } if (data_transfer_layersmapping_generate( &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_POLY, cddata_type, mix_mode, mix_factor, weights[PDATA], num_polys_dst, use_create, use_delete, fromlayers, tolayers)) { CustomDataTransferLayerMap *lay_mapit; changed = (lay_map.first != NULL); for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) { CustomData_data_transfer(&geom_map[PDATA], lay_mapit); } BLI_freelistN(&lay_map); } } data_transfer_dtdata_type_postprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, dtdata_type, changed); } for (i = 0; i < DATAMAX; i++) { BKE_mesh_remap_free(&geom_map[i]); MEM_SAFE_FREE(weights[i]); } return changed; #undef VDATA #undef EDATA #undef LDATA #undef PDATA #undef DATAMAX }
/* compute uv coordinates of mouse in face */ void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const int xy[2], float uv[2]) { DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); MTFace *tface = dm->getTessFaceDataArray(dm, CD_MTFACE), *tf; int numfaces = dm->getNumTessFaces(dm), a, findex; float p[2], w[3], absw, minabsw; MFace mf; MVert mv[4]; /* double lookup */ const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); if (index_mf_to_mpoly == NULL) { index_mp_to_orig = NULL; } minabsw = 1e10; uv[0] = uv[1] = 0.0; /* test all faces in the derivedmesh with the original index of the picked face */ for (a = 0; a < numfaces; a++) { findex = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a; if (findex == faceindex) { dm->getTessFace(dm, a, &mf); dm->getVert(dm, mf.v1, &mv[0]); dm->getVert(dm, mf.v2, &mv[1]); dm->getVert(dm, mf.v3, &mv[2]); if (mf.v4) dm->getVert(dm, mf.v4, &mv[3]); tf = &tface[a]; p[0] = xy[0]; p[1] = xy[1]; if (mf.v4) { /* the triangle with the largest absolute values is the one * with the most negative weights */ imapaint_tri_weights(ob, mv[0].co, mv[1].co, mv[3].co, p, w); absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]); if (absw < minabsw) { uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[3][0] * w[2]; uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[3][1] * w[2]; minabsw = absw; } imapaint_tri_weights(ob, mv[1].co, mv[2].co, mv[3].co, p, w); absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]); if (absw < minabsw) { uv[0] = tf->uv[1][0] * w[0] + tf->uv[2][0] * w[1] + tf->uv[3][0] * w[2]; uv[1] = tf->uv[1][1] * w[0] + tf->uv[2][1] * w[1] + tf->uv[3][1] * w[2]; minabsw = absw; } } else { imapaint_tri_weights(ob, mv[0].co, mv[1].co, mv[2].co, p, w); absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]); if (absw < minabsw) { uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[2][0] * w[2]; uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[2][1] * w[2]; minabsw = absw; } } } } dm->release(dm); }
void GeometryExporter::operator()(Object *ob) { // XXX don't use DerivedMesh, Mesh instead? #if 0 DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH); #endif bool use_instantiation = this->export_settings->use_object_instantiation; Mesh *me = bc_get_mesh_copy( mScene, ob, this->export_settings->export_mesh_type, this->export_settings->apply_modifiers, this->export_settings->triangulate); Mesh *mesh = (Mesh *) ob->data; me->flag = mesh->flag; std::string geom_id = get_geometry_id(ob, use_instantiation); std::vector<Normal> nor; std::vector<BCPolygonNormalsIndices> norind; // Skip if linked geometry was already exported from another reference if (use_instantiation && exportedGeometry.find(geom_id) != exportedGeometry.end()) { return; } std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob); exportedGeometry.insert(geom_id); bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL); create_normals(nor, norind, me); // openMesh(geoId, geoName, meshId) openMesh(geom_id, geom_name); // writes <source> for vertex coords createVertsSource(geom_id, me); // writes <source> for normal coords createNormalsSource(geom_id, me, nor); bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE); // writes <source> for uv coords if mesh has uv coords if (has_uvs) { createTexcoordsSource(geom_id, me); } if (has_color) { createVertexColorSource(geom_id, me); } // <vertices> COLLADASW::Vertices verts(mSW); verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX)); COLLADASW::InputList &input_list = verts.getInputList(); COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION)); input_list.push_back(input); verts.add(); createLooseEdgeList(ob, me, geom_id); // Only create Polylists if number of faces > 0 if (me->totface > 0) { // XXX slow if (ob->totcol) { for (int a = 0; a < ob->totcol; a++) { createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind); } } else { createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind); } } closeMesh(); if (me->flag & ME_TWOSIDED) { mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>"); } closeGeometry(); if (this->export_settings->include_shapekeys) { Key * key = BKE_key_from_object(ob); if (key) { KeyBlock * kb = (KeyBlock *)key->block.first; //skip the basis kb = kb->next; for (; kb; kb = kb->next) { BKE_keyblock_convert_to_mesh(kb, me); export_key_mesh(ob, me, kb); } } } BKE_libblock_free_us(G.main, me); }
/* compute uv coordinates of mouse in face */ static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const int xy[2], float uv[2]) { DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); MTFace *tf_base, *tf; Material *ma; TexPaintSlot *slot; int numfaces = dm->getNumTessFaces(dm), a, findex; float p[2], w[3], absw, minabsw; MFace mf; MVert mv[4]; float matrix[4][4], proj[4][4]; GLint view[4]; /* compute barycentric coordinates */ /* double lookup */ const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); if (index_mf_to_mpoly == NULL) { index_mp_to_orig = NULL; } /* get the needed opengl matrices */ glGetIntegerv(GL_VIEWPORT, view); glGetFloatv(GL_MODELVIEW_MATRIX, (float *)matrix); glGetFloatv(GL_PROJECTION_MATRIX, (float *)proj); view[0] = view[1] = 0; mul_m4_m4m4(matrix, matrix, ob->obmat); mul_m4_m4m4(matrix, proj, matrix); minabsw = 1e10; uv[0] = uv[1] = 0.0; /* test all faces in the derivedmesh with the original index of the picked face */ for (a = 0; a < numfaces; a++) { findex = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a; if (findex == faceindex) { dm->getTessFace(dm, a, &mf); ma = dm->mat[mf.mat_nr]; slot = &ma->texpaintslot[ma->paint_active_slot]; dm->getVert(dm, mf.v1, &mv[0]); dm->getVert(dm, mf.v2, &mv[1]); dm->getVert(dm, mf.v3, &mv[2]); if (mf.v4) dm->getVert(dm, mf.v4, &mv[3]); if (!slot->uvname || !(tf_base = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, slot->uvname))) tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE); tf = &tf_base[a]; p[0] = xy[0]; p[1] = xy[1]; if (mf.v4) { /* the triangle with the largest absolute values is the one * with the most negative weights */ imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[3].co, p, w); absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]); if (absw < minabsw) { uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[3][0] * w[2]; uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[3][1] * w[2]; minabsw = absw; } imapaint_tri_weights(matrix, view, mv[1].co, mv[2].co, mv[3].co, p, w); absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]); if (absw < minabsw) { uv[0] = tf->uv[1][0] * w[0] + tf->uv[2][0] * w[1] + tf->uv[3][0] * w[2]; uv[1] = tf->uv[1][1] * w[0] + tf->uv[2][1] * w[1] + tf->uv[3][1] * w[2]; minabsw = absw; } } else { imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[2].co, p, w); absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]); if (absw < minabsw) { uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[2][0] * w[2]; uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[2][1] * w[2]; minabsw = absw; } } } } dm->release(dm); }
void GeometryExporter::operator()(Object *ob) { // XXX don't use DerivedMesh, Mesh instead? #if 0 DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH); #endif Mesh *me = (Mesh*)ob->data; std::string geom_id = get_geometry_id(ob); std::string geom_name = id_name(ob->data); std::vector<Normal> nor; std::vector<Face> norind; // Skip if linked geometry was already exported from another reference if (exportedGeometry.find(geom_id) != exportedGeometry.end()) return; exportedGeometry.insert(geom_id); bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL); create_normals(nor, norind, me); // openMesh(geoId, geoName, meshId) openMesh(geom_id, geom_name); // writes <source> for vertex coords createVertsSource(geom_id, me); // writes <source> for normal coords createNormalsSource(geom_id, me, nor); bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE); // writes <source> for uv coords if mesh has uv coords if (has_uvs) createTexcoordsSource(geom_id, me); if (has_color) createVertexColorSource(geom_id, me); // <vertices> COLLADASW::Vertices verts(mSW); verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX)); COLLADASW::InputList &input_list = verts.getInputList(); COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION)); input_list.push_back(input); verts.add(); // XXX slow if (ob->totcol) { for(int a = 0; a < ob->totcol; a++) { createPolylist(a, has_uvs, has_color, ob, geom_id, norind); } } else { createPolylist(0, has_uvs, has_color, ob, geom_id, norind); } closeMesh(); if (me->flag & ME_TWOSIDED) { mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>"); } closeGeometry(); #if 0 dm->release(dm); #endif }
/* single_psys_from is optional, if NULL all psys of ob_from are copied */ static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, ParticleSystem *single_psys_from, Object *ob_to, int space) { ModifierData *md; ParticleSystem *psys_start = NULL, *psys, *psys_from; ParticleSystem **tmp_psys; DerivedMesh *final_dm; CustomDataMask cdmask; int i, totpsys; if (ob_to->type != OB_MESH) return false; if (!ob_to->data || ((ID *)ob_to->data)->lib) return false; /* For remapping we need a valid DM. * Because the modifiers are appended at the end it's safe to use * the final DM of the object without particles. * However, when evaluating the DM all the particle modifiers must be valid, * i.e. have the psys assigned already. * To break this hen/egg problem we create all psys separately first (to collect required customdata masks), * then create the DM, then add them to the object and make the psys modifiers ... */ #define PSYS_FROM_FIRST (single_psys_from ? single_psys_from : ob_from->particlesystem.first) #define PSYS_FROM_NEXT(cur) (single_psys_from ? NULL : (cur)->next) totpsys = single_psys_from ? 1 : BLI_listbase_count(&ob_from->particlesystem); tmp_psys = MEM_mallocN(sizeof(ParticleSystem*) * totpsys, "temporary particle system array"); cdmask = 0; for (psys_from = PSYS_FROM_FIRST, i = 0; psys_from; psys_from = PSYS_FROM_NEXT(psys_from), ++i) { psys = BKE_object_copy_particlesystem(psys_from); tmp_psys[i] = psys; if (psys_start == NULL) psys_start = psys; cdmask |= psys_emitter_customdata_mask(psys); } /* to iterate source and target psys in sync, * we need to know where the newly added psys start */ psys_start = totpsys > 0 ? tmp_psys[0] : NULL; /* get the DM (psys and their modifiers have not been appended yet) */ final_dm = mesh_get_derived_final(scene, ob_to, cdmask); /* now append psys to the object and make modifiers */ for (i = 0, psys_from = PSYS_FROM_FIRST; i < totpsys; ++i, psys_from = PSYS_FROM_NEXT(psys_from)) { ParticleSystemModifierData *psmd; psys = tmp_psys[i]; /* append to the object */ BLI_addtail(&ob_to->particlesystem, psys); /* add a particle system modifier for each system */ md = modifier_new(eModifierType_ParticleSystem); psmd = (ParticleSystemModifierData *)md; /* push on top of the stack, no use trying to reproduce old stack order */ BLI_addtail(&ob_to->modifiers, md); BLI_snprintf(md->name, sizeof(md->name), "ParticleSystem %i", i); modifier_unique_name(&ob_to->modifiers, (ModifierData *)psmd); psmd->psys = psys; psmd->dm = CDDM_copy(final_dm); CDDM_calc_normals(psmd->dm); DM_ensure_tessface(psmd->dm); if (psys_from->edit) copy_particle_edit(scene, ob_to, psys, psys_from); } MEM_freeN(tmp_psys); /* note: do this after creating DM copies for all the particle system modifiers, * the remapping otherwise makes final_dm invalid! */ for (psys = psys_start, psys_from = PSYS_FROM_FIRST, i = 0; psys; psys = psys->next, psys_from = PSYS_FROM_NEXT(psys_from), ++i) { float (*from_mat)[4], (*to_mat)[4]; switch (space) { case PAR_COPY_SPACE_OBJECT: from_mat = I; to_mat = I; break; case PAR_COPY_SPACE_WORLD: from_mat = ob_from->obmat; to_mat = ob_to->obmat; break; default: /* should not happen */ from_mat = to_mat = NULL; BLI_assert(false); break; } remap_hair_emitter(scene, ob_from, psys_from, ob_to, psys, psys->edit, from_mat, to_mat, psys_from->flag & PSYS_GLOBAL_HAIR, psys->flag & PSYS_GLOBAL_HAIR); /* tag for recalc */ // psys->recalc |= PSYS_RECALC_RESET; } #undef PSYS_FROM_FIRST #undef PSYS_FROM_NEXT DAG_id_tag_update(&ob_to->id, OB_RECALC_DATA); WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, ob_to); return true; }