static DerivedMesh *doOcean(ModifierData *md, Object *ob, DerivedMesh *derivedData, int UNUSED(useRenderParams)) { OceanModifierData *omd = (OceanModifierData *) md; DerivedMesh *dm = NULL; OceanResult ocr; MVert *mverts, *mv; MLoop *mloops; int i, j; int num_verts; int num_faces; int cfra; /* use cached & inverted value for speed * expanded this would read... * * (axis / (omd->size * omd->spatial_size)) + 0.5f) */ #define OCEAN_CO(_size_co_inv, _v) ((_v * _size_co_inv) + 0.5f) const float size_co_inv = 1.0f / (omd->size * omd->spatial_size); /* update modifier */ if (omd->refresh & MOD_OCEAN_REFRESH_ADD) omd->ocean = BKE_add_ocean(); if (omd->refresh & MOD_OCEAN_REFRESH_RESET) init_ocean_modifier(omd); if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE) clear_cache_data(omd); omd->refresh = 0; /* do ocean simulation */ if (omd->cached == TRUE) { if (!omd->oceancache) init_cache_data(ob, omd); BKE_simulate_ocean_cache(omd->oceancache, md->scene->r.cfra); } else { simulate_ocean_modifier(omd); } if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) dm = generate_ocean_geometry(omd); else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) { dm = CDDM_copy(derivedData); } cfra = md->scene->r.cfra; CLAMP(cfra, omd->bakestart, omd->bakeend); cfra -= omd->bakestart; /* shift to 0 based */ num_verts = dm->getNumVerts(dm); num_faces = dm->getNumPolys(dm); mverts = dm->getVertArray(dm); mloops = dm->getLoopArray(dm); /* add vcols before displacement - allows lookup based on position */ if (omd->flag & MOD_OCEAN_GENERATE_FOAM) { int cdlayer = CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL); if (cdlayer < MAX_MCOL) { MLoopCol *mloopcols = CustomData_add_layer_named(&dm->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, num_faces * 4, omd->foamlayername); if (mloopcols) { /* unlikely to fail */ MLoopCol *mlcol; MPoly *mpolys = dm->getPolyArray(dm); MPoly *mp; float foam; for (i = 0, mp = mpolys; i < num_faces; i++, mp++) { j = mp->totloop - 1; /* highly unlikely */ if (j <= 0) continue; do { const float *co = mverts[mloops[mp->loopstart + j].v].co; const float u = OCEAN_CO(size_co_inv, co[0]); const float v = OCEAN_CO(size_co_inv, co[1]); if (omd->oceancache && omd->cached == TRUE) { BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v); foam = ocr.foam; CLAMP(foam, 0.0f, 1.0f); } else { BKE_ocean_eval_uv(omd->ocean, &ocr, u, v); foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage); } mlcol = &mloopcols[mp->loopstart + j]; mlcol->r = mlcol->g = mlcol->b = (char)(foam * 255); /* This needs to be set (render engine uses) */ mlcol->a = 255; } while (j--); } } } } /* displace the geometry */ /* #pragma omp parallel for private(i, ocr) if (omd->resolution > OMP_MIN_RES) */ for (i = 0, mv = mverts; i < num_verts; i++, mv++) { const float u = OCEAN_CO(size_co_inv, mv->co[0]); const float v = OCEAN_CO(size_co_inv, mv->co[1]); if (omd->oceancache && omd->cached == TRUE) BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v); else BKE_ocean_eval_uv(omd->ocean, &ocr, u, v); mv->co[2] += ocr.disp[1]; if (omd->chop_amount > 0.0f) { mv->co[0] += ocr.disp[0]; mv->co[1] += ocr.disp[2]; } } #undef OCEAN_CO return dm; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag flag) { DerivedMesh *dm = derivedData; DerivedMesh *result; ScrewModifierData *ltmd = (ScrewModifierData *) md; const bool use_render_params = (flag & MOD_APPLY_RENDER) != 0; int *origindex; int mpoly_index = 0; unsigned int step; unsigned int i, j; unsigned int i1, i2; unsigned int step_tot = use_render_params ? ltmd->render_steps : ltmd->steps; const bool do_flip = (ltmd->flag & MOD_SCREW_NORMAL_FLIP) != 0; const int quad_ord[4] = { do_flip ? 3 : 0, do_flip ? 2 : 1, do_flip ? 1 : 2, do_flip ? 0 : 3, }; const int quad_ord_ofs[4] = { do_flip ? 2 : 0, 1, do_flip ? 0 : 2, 3, }; unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0; const unsigned int totvert = (unsigned int)dm->getNumVerts(dm); const unsigned int totedge = (unsigned int)dm->getNumEdges(dm); const unsigned int totpoly = (unsigned int)dm->getNumPolys(dm); unsigned int *edge_poly_map = NULL; /* orig edge to orig poly */ unsigned int *vert_loop_map = NULL; /* orig vert to orig loop */ /* UV Coords */ const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV); MLoopUV **mloopuv_layers = BLI_array_alloca(mloopuv_layers, mloopuv_layers_tot); float uv_u_scale; float uv_v_minmax[2] = {FLT_MAX, -FLT_MAX}; float uv_v_range_inv; float uv_axis_plane[4]; char axis_char = 'X'; bool close; float angle = ltmd->angle; float screw_ofs = ltmd->screw_ofs; float axis_vec[3] = {0.0f, 0.0f, 0.0f}; float tmp_vec1[3], tmp_vec2[3]; float mat3[3][3]; float mtx_tx[4][4]; /* transform the coords by an object relative to this objects transformation */ float mtx_tx_inv[4][4]; /* inverted */ float mtx_tmp_a[4][4]; unsigned int vc_tot_linked = 0; short other_axis_1, other_axis_2; const float *tmpf1, *tmpf2; unsigned int edge_offset; MPoly *mpoly_orig, *mpoly_new, *mp_new; MLoop *mloop_orig, *mloop_new, *ml_new; MEdge *medge_orig, *med_orig, *med_new, *med_new_firstloop, *medge_new; MVert *mvert_new, *mvert_orig, *mv_orig, *mv_new, *mv_new_base; ScrewVertConnect *vc, *vc_tmp, *vert_connect = NULL; const char mpoly_flag = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) ? ME_SMOOTH : 0; /* don't do anything? */ if (!totvert) return CDDM_from_template(dm, 0, 0, 0, 0, 0); switch (ltmd->axis) { case 0: other_axis_1 = 1; other_axis_2 = 2; break; case 1: other_axis_1 = 0; other_axis_2 = 2; break; default: /* 2, use default to quiet warnings */ other_axis_1 = 0; other_axis_2 = 1; break; } axis_vec[ltmd->axis] = 1.0f; if (ltmd->ob_axis) { /* calc the matrix relative to the axis object */ invert_m4_m4(mtx_tmp_a, ob->obmat); copy_m4_m4(mtx_tx_inv, ltmd->ob_axis->obmat); mul_m4_m4m4(mtx_tx, mtx_tmp_a, mtx_tx_inv); /* calc the axis vec */ mul_mat3_m4_v3(mtx_tx, axis_vec); /* only rotation component */ normalize_v3(axis_vec); /* screw */ if (ltmd->flag & MOD_SCREW_OBJECT_OFFSET) { /* find the offset along this axis relative to this objects matrix */ float totlen = len_v3(mtx_tx[3]); if (totlen != 0.0f) { float zero[3] = {0.0f, 0.0f, 0.0f}; float cp[3]; screw_ofs = closest_to_line_v3(cp, mtx_tx[3], zero, axis_vec); } else { screw_ofs = 0.0f; } } /* angle */ #if 0 /* cant incluide this, not predictable enough, though quite fun. */ if (ltmd->flag & MOD_SCREW_OBJECT_ANGLE) { float mtx3_tx[3][3]; copy_m3_m4(mtx3_tx, mtx_tx); float vec[3] = {0, 1, 0}; float cross1[3]; float cross2[3]; cross_v3_v3v3(cross1, vec, axis_vec); mul_v3_m3v3(cross2, mtx3_tx, cross1); { float c1[3]; float c2[3]; float axis_tmp[3]; cross_v3_v3v3(c1, cross2, axis_vec); cross_v3_v3v3(c2, axis_vec, c1); angle = angle_v3v3(cross1, c2); cross_v3_v3v3(axis_tmp, cross1, c2); normalize_v3(axis_tmp); if (len_v3v3(axis_tmp, axis_vec) > 1.0f) angle = -angle; } } #endif } else { /* exis char is used by i_rotate*/ axis_char = (char)(axis_char + ltmd->axis); /* 'X' + axis */ /* useful to be able to use the axis vec in some cases still */ zero_v3(axis_vec); axis_vec[ltmd->axis] = 1.0f; } /* apply the multiplier */ angle *= (float)ltmd->iter; screw_ofs *= (float)ltmd->iter; uv_u_scale = 1.0f / (float)(step_tot); /* multiplying the steps is a bit tricky, this works best */ step_tot = ((step_tot + 1) * ltmd->iter) - (ltmd->iter - 1); /* will the screw be closed? * Note! smaller then FLT_EPSILON * 100 gives problems with float precision so its never closed. */ if (fabsf(screw_ofs) <= (FLT_EPSILON * 100.0f) && fabsf(fabsf(angle) - ((float)M_PI * 2.0f)) <= (FLT_EPSILON * 100.0f)) { close = 1; step_tot--; if (step_tot < 3) step_tot = 3; maxVerts = totvert * step_tot; /* -1 because we're joining back up */ maxEdges = (totvert * step_tot) + /* these are the edges between new verts */ (totedge * step_tot); /* -1 because vert edges join */ maxPolys = totedge * step_tot; screw_ofs = 0.0f; } else { close = 0; if (step_tot < 3) step_tot = 3; maxVerts = totvert * step_tot; /* -1 because we're joining back up */ maxEdges = (totvert * (step_tot - 1)) + /* these are the edges between new verts */ (totedge * step_tot); /* -1 because vert edges join */ maxPolys = totedge * (step_tot - 1); } if ((ltmd->flag & MOD_SCREW_UV_STRETCH_U) == 0) { uv_u_scale = (uv_u_scale / (float)ltmd->iter) * (angle / ((float)M_PI * 2.0f)); } result = CDDM_from_template(dm, (int)maxVerts, (int)maxEdges, 0, (int)maxPolys * 4, (int)maxPolys); /* copy verts from mesh */ mvert_orig = dm->getVertArray(dm); medge_orig = dm->getEdgeArray(dm); mvert_new = result->getVertArray(result); mpoly_new = result->getPolyArray(result); mloop_new = result->getLoopArray(result); medge_new = result->getEdgeArray(result); if (!CustomData_has_layer(&result->polyData, CD_ORIGINDEX)) { CustomData_add_layer(&result->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, (int)maxPolys); } origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX); DM_copy_vert_data(dm, result, 0, 0, (int)totvert); /* copy first otherwise this overwrites our own vertex normals */ if (mloopuv_layers_tot) { float zero_co[3] = {0}; plane_from_point_normal_v3(uv_axis_plane, zero_co, axis_vec); } if (mloopuv_layers_tot) { unsigned int uv_lay; for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) { mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, (int)uv_lay); } if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) { for (i = 0, mv_orig = mvert_orig; i < totvert; i++, mv_orig++) { const float v = dist_signed_squared_to_plane_v3(mv_orig->co, uv_axis_plane); uv_v_minmax[0] = min_ff(v, uv_v_minmax[0]); uv_v_minmax[1] = max_ff(v, uv_v_minmax[1]); } uv_v_minmax[0] = sqrtf_signed(uv_v_minmax[0]); uv_v_minmax[1] = sqrtf_signed(uv_v_minmax[1]); } uv_v_range_inv = uv_v_minmax[1] - uv_v_minmax[0]; uv_v_range_inv = uv_v_range_inv ? 1.0f / uv_v_range_inv : 0.0f; } /* Set the locations of the first set of verts */ mv_new = mvert_new; mv_orig = mvert_orig; /* Copy the first set of edges */ med_orig = medge_orig; med_new = medge_new; for (i = 0; i < totedge; i++, med_orig++, med_new++) { med_new->v1 = med_orig->v1; med_new->v2 = med_orig->v2; med_new->crease = med_orig->crease; med_new->flag = med_orig->flag & ~ME_LOOSEEDGE; } /* build polygon -> edge map */ if (totpoly) { MPoly *mp_orig; mpoly_orig = dm->getPolyArray(dm); mloop_orig = dm->getLoopArray(dm); edge_poly_map = MEM_mallocN(sizeof(*edge_poly_map) * totedge, __func__); memset(edge_poly_map, 0xff, sizeof(*edge_poly_map) * totedge); vert_loop_map = MEM_mallocN(sizeof(*vert_loop_map) * totvert, __func__); memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert); for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) { unsigned int loopstart = (unsigned int)mp_orig->loopstart; unsigned int loopend = loopstart + (unsigned int)mp_orig->totloop; MLoop *ml_orig = &mloop_orig[loopstart]; unsigned int k; for (k = loopstart; k < loopend; k++, ml_orig++) { edge_poly_map[ml_orig->e] = i; vert_loop_map[ml_orig->v] = k; /* also order edges based on faces */ if (medge_new[ml_orig->e].v1 != ml_orig->v) { SWAP(unsigned int, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2); } } } }
static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated) { Object *ob, *ob_iter; Base *base = NULL; DupliObject *dob; DerivedMesh *dm; Mesh *me = par->data; MLoopUV *mloopuv; MPoly *mpoly, *mp; MLoop *mloop; MVert *mvert; float pmat[4][4], imat[3][3], (*orco)[3] = NULL, w; int lay, oblay, totface, a; Scene *sce = NULL; Group *group = NULL; GroupObject *go = NULL; BMEditMesh *em; float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */ /* simple preventing of too deep nested groups */ if (level > MAX_DUPLI_RECUR) return; copy_m4_m4(pmat, par->obmat); em = me->edit_btmesh; if (em) { dm = editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH); } else { dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH); } totface = dm->getNumPolys(dm); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); mvert = dm->getVertArray(dm); if (G.rendering) { orco = (float(*)[3])BKE_mesh_orco_verts_get(par); BKE_mesh_orco_verts_transform(me, orco, me->totvert, 0); mloopuv = me->mloopuv; } else { orco = NULL; mloopuv = NULL; } /* having to loop on scene OR group objects is NOT FUN */ if (GS(id->name) == ID_SCE) { sce = (Scene *)id; lay = sce->lay; base = sce->base.first; } else { group = (Group *)id; lay = group->layer; go = group->gobject.first; } /* Start looping on Scene OR Group objects */ while (base || go) { if (sce) { ob_iter = base->object; oblay = base->lay; } else { ob_iter = go->ob; oblay = ob_iter->lay; } if (lay & oblay && scene->obedit != ob_iter) { ob = ob_iter->parent; while (ob) { if (ob == par) { ob = ob_iter; /* End Scene/Group object loop, below is generic */ /* par_space_mat - only used for groups so we can modify the space dupli's are in * when par_space_mat is NULL ob->obmat can be used instead of ob__obmat */ if (par_space_mat) mult_m4_m4m4(ob__obmat, par_space_mat, ob->obmat); else copy_m4_m4(ob__obmat, ob->obmat); copy_m3_m4(imat, ob->parentinv); /* mballs have a different dupli handling */ if (ob->type != OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */ for (a = 0, mp = mpoly; a < totface; a++, mp++) { int mv1; int mv2; int mv3; /* int mv4; */ /* UNUSED */ float *v1; float *v2; float *v3; /* float *v4; */ /* UNUSED */ float cent[3], quat[4], mat[3][3], mat3[3][3], tmat[4][4], obmat[4][4]; MLoop *loopstart = mloop + mp->loopstart; if (mp->totloop < 3) { /* highly unlikely but to be safe */ continue; } else { v1 = mvert[(mv1 = loopstart[0].v)].co; v2 = mvert[(mv2 = loopstart[1].v)].co; v3 = mvert[(mv3 = loopstart[2].v)].co; #if 0 if (mp->totloop > 3) { v4 = mvert[(mv4 = loopstart[3].v)].co; } #endif } /* translation */ BKE_mesh_calc_poly_center(mp, loopstart, mvert, cent); mul_m4_v3(pmat, cent); sub_v3_v3v3(cent, cent, pmat[3]); add_v3_v3(cent, ob__obmat[3]); copy_m4_m4(obmat, ob__obmat); copy_v3_v3(obmat[3], cent); /* rotation */ tri_to_quat(quat, v1, v2, v3); quat_to_mat3(mat, quat); /* scale */ if (par->transflag & OB_DUPLIFACES_SCALE) { float size = BKE_mesh_calc_poly_area(mp, loopstart, mvert, NULL); size = sqrtf(size) * par->dupfacesca; mul_m3_fl(mat, size); } copy_m3_m3(mat3, mat); mul_m3_m3m3(mat, imat, mat3); copy_m4_m4(tmat, obmat); mul_m4_m4m3(obmat, tmat, mat); dob = new_dupli_object(lb, ob, obmat, par->lay, a, OB_DUPLIFACES, animated); if (G.rendering) { w = 1.0f / (float)mp->totloop; if (orco) { int j; for (j = 0; j < mpoly->totloop; j++) { madd_v3_v3fl(dob->orco, orco[loopstart[j].v], w); } } if (mloopuv) { int j; for (j = 0; j < mpoly->totloop; j++) { madd_v2_v2fl(dob->orco, mloopuv[loopstart[j].v].uv, w); } } } if (ob->transflag & OB_DUPLI) { float tmpmat[4][4]; copy_m4_m4(tmpmat, ob->obmat); copy_m4_m4(ob->obmat, obmat); /* pretend we are really this mat */ object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, level + 1, animated); copy_m4_m4(ob->obmat, tmpmat); } } break; } ob = ob->parent; } } if (sce) base = base->next; /* scene loop */ else go = go->next; /* group loop */ } if (orco) MEM_freeN(orco); dm->release(dm); }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) { MaskModifierData *mmd = (MaskModifierData *)md; DerivedMesh *dm = derivedData, *result = NULL; GHash *vertHash = NULL, *edgeHash, *polyHash; GHashIterator *hashIter; MDeformVert *dvert = NULL, *dv; int numPolys = 0, numLoops = 0, numEdges = 0, numVerts = 0; int maxVerts, maxEdges, maxPolys; int i; MPoly *mpoly; MLoop *mloop; MPoly *mpoly_new; MLoop *mloop_new; MEdge *medge_new; MVert *mvert_new; int *loop_mapping; /* Overview of Method: * 1. Get the vertices that are in the vertexgroup of interest * 2. Filter out unwanted geometry (i.e. not in vertexgroup), by populating mappings with new vs old indices * 3. Make a new mesh containing only the mapping data */ /* get original number of verts, edges, and faces */ maxVerts = dm->getNumVerts(dm); maxEdges = dm->getNumEdges(dm); maxPolys = dm->getNumPolys(dm); /* check if we can just return the original mesh * - must have verts and therefore verts assigned to vgroups to do anything useful */ if (!(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) || (maxVerts == 0) || (ob->defbase.first == NULL) ) { return derivedData; } /* if mode is to use selected armature bones, aggregate the bone groups */ if (mmd->mode == MOD_MASK_MODE_ARM) { /* --- using selected bones --- */ GHash *vgroupHash; Object *oba = mmd->ob_arm; bPoseChannel *pchan; bDeformGroup *def; char *bone_select_array; int bone_select_tot = 0; const int defbase_tot = BLI_countlist(&ob->defbase); /* check that there is armature object with bones to use, otherwise return original mesh */ if (ELEM3(NULL, mmd->ob_arm, mmd->ob_arm->pose, ob->defbase.first)) return derivedData; bone_select_array = MEM_mallocN(defbase_tot * sizeof(char), "mask array"); for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { pchan = BKE_pose_channel_find_name(oba->pose, def->name); if (pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED)) { bone_select_array[i] = TRUE; bone_select_tot++; } else { bone_select_array[i] = FALSE; } } /* hashes for finding mapping of: * - vgroups to indices -> vgroupHash (string, int) * - bones to vgroup indices -> boneHash (index of vgroup, dummy) */ vgroupHash = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "mask vgroup gh"); /* build mapping of names of vertex groups to indices */ for (i = 0, def = ob->defbase.first; def; def = def->next, i++) BLI_ghash_insert(vgroupHash, def->name, SET_INT_IN_POINTER(i)); /* if no bones selected, free hashes and return original mesh */ if (bone_select_tot == 0) { BLI_ghash_free(vgroupHash, NULL, NULL); MEM_freeN(bone_select_array); return derivedData; } /* repeat the previous check, but for dverts */ dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); if (dvert == NULL) { BLI_ghash_free(vgroupHash, NULL, NULL); MEM_freeN(bone_select_array); return derivedData; } /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ vertHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask vert gh"); /* add vertices which exist in vertexgroups into vertHash for filtering */ for (i = 0, dv = dvert; i < maxVerts; i++, dv++) { MDeformWeight *dw = dv->dw; int j; for (j = dv->totweight; j > 0; j--, dw++) { if (dw->def_nr < defbase_tot) { if (bone_select_array[dw->def_nr]) { if (dw->weight != 0.0f) { break; } } } } /* check if include vert in vertHash */ if (mmd->flag & MOD_MASK_INV) { /* if this vert is in the vgroup, don't include it in vertHash */ if (dw) continue; } else { /* if this vert isn't in the vgroup, don't include it in vertHash */ if (!dw) continue; } /* add to ghash for verts (numVerts acts as counter for mapping) */ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts)); numVerts++; } /* free temp hashes */ BLI_ghash_free(vgroupHash, NULL, NULL); MEM_freeN(bone_select_array); } else { /* --- Using Nominated VertexGroup only --- */ int defgrp_index = defgroup_name_index(ob, mmd->vgroup); /* get dverts */ if (defgrp_index >= 0) dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); /* if no vgroup (i.e. dverts) found, return the initial mesh */ if ((defgrp_index < 0) || (dvert == NULL)) return dm; /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ vertHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask vert2 bh"); /* add vertices which exist in vertexgroup into ghash for filtering */ for (i = 0, dv = dvert; i < maxVerts; i++, dv++) { const int weight_set = defvert_find_weight(dv, defgrp_index) != 0.0f; /* check if include vert in vertHash */ if (mmd->flag & MOD_MASK_INV) { /* if this vert is in the vgroup, don't include it in vertHash */ if (weight_set) continue; } else { /* if this vert isn't in the vgroup, don't include it in vertHash */ if (!weight_set) continue; } /* add to ghash for verts (numVerts acts as counter for mapping) */ BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts)); numVerts++; } } /* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */ edgeHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask ed2 gh"); polyHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask fa2 gh"); mpoly = dm->getPolyArray(dm); mloop = dm->getLoopArray(dm); loop_mapping = MEM_callocN(sizeof(int) * maxPolys, "mask loopmap"); /* overalloc, assume all polys are seen */ /* loop over edges and faces, and do the same thing to * ensure that they only reference existing verts */ for (i = 0; i < maxEdges; i++) { MEdge me; dm->getEdge(dm, i, &me); /* only add if both verts will be in new mesh */ if (BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1)) && BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2))) { BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numEdges)); numEdges++; } } for (i = 0; i < maxPolys; i++) { MPoly *mp = &mpoly[i]; MLoop *ml = mloop + mp->loopstart; int ok = TRUE; int j; for (j = 0; j < mp->totloop; j++, ml++) { if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml->v))) { ok = FALSE; break; } } /* all verts must be available */ if (ok) { BLI_ghash_insert(polyHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numPolys)); loop_mapping[numPolys] = numLoops; numPolys++; numLoops += mp->totloop; } } /* now we know the number of verts, edges and faces, * we can create the new (reduced) mesh */ result = CDDM_from_template(dm, numVerts, numEdges, 0, numLoops, numPolys); mpoly_new = CDDM_get_polys(result); mloop_new = CDDM_get_loops(result); medge_new = CDDM_get_edges(result); mvert_new = CDDM_get_verts(result); /* using ghash-iterators, map data into new mesh */ /* vertices */ for (hashIter = BLI_ghashIterator_new(vertHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter) ) { MVert source; MVert *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); dm->getVert(dm, oldIndex, &source); dest = &mvert_new[newIndex]; DM_copy_vert_data(dm, result, oldIndex, newIndex, 1); *dest = source; } BLI_ghashIterator_free(hashIter); /* edges */ for (hashIter = BLI_ghashIterator_new(edgeHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter)) { MEdge source; MEdge *dest; int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); dm->getEdge(dm, oldIndex, &source); dest = &medge_new[newIndex]; source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1))); source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2))); DM_copy_edge_data(dm, result, oldIndex, newIndex, 1); *dest = source; } BLI_ghashIterator_free(hashIter); /* faces */ for (hashIter = BLI_ghashIterator_new(polyHash); !BLI_ghashIterator_isDone(hashIter); BLI_ghashIterator_step(hashIter) ) { int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); MPoly *source = &mpoly[oldIndex]; MPoly *dest = &mpoly_new[newIndex]; int oldLoopIndex = source->loopstart; int newLoopIndex = loop_mapping[newIndex]; MLoop *source_loop = &mloop[oldLoopIndex]; MLoop *dest_loop = &mloop_new[newLoopIndex]; DM_copy_poly_data(dm, result, oldIndex, newIndex, 1); DM_copy_loop_data(dm, result, oldLoopIndex, newLoopIndex, source->totloop); *dest = *source; dest->loopstart = newLoopIndex; for (i = 0; i < source->totloop; i++) { dest_loop[i].v = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source_loop[i].v))); dest_loop[i].e = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_INT_IN_POINTER(source_loop[i].e))); } } BLI_ghashIterator_free(hashIter); MEM_freeN(loop_mapping); /* why is this needed? - campbell */ /* recalculate normals */ CDDM_calc_normals(result); /* free hashes */ BLI_ghash_free(vertHash, NULL, NULL); BLI_ghash_free(edgeHash, NULL, NULL); BLI_ghash_free(polyHash, NULL, NULL); /* return the new mesh */ return result; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) { DerivedMesh *dm = derivedData, *result; ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; ParticleSimulationData sim; ParticleSystem *psys = NULL; ParticleData *pa = NULL; MPoly *mpoly, *orig_mpoly; MLoop *mloop, *orig_mloop; MVert *mvert, *orig_mvert; int totvert, totpoly, totloop /* , totedge */; int maxvert, maxpoly, maxloop, totpart = 0, first_particle = 0; int k, p, p_skip; short track = ob->trackflag % 3, trackneg, axis = pimd->axis; float max_co = 0.0, min_co = 0.0, temp_co[3], cross[3]; float *size = NULL; trackneg = ((ob->trackflag > 2) ? 1 : 0); if (pimd->ob == ob) { pimd->ob = NULL; return derivedData; } if (pimd->ob) { psys = BLI_findlink(&pimd->ob->particlesystem, pimd->psys - 1); if (psys == NULL || psys->totpart == 0) return derivedData; } else { return derivedData; } if (pimd->flag & eParticleInstanceFlag_Parents) totpart += psys->totpart; if (pimd->flag & eParticleInstanceFlag_Children) { if (totpart == 0) first_particle = psys->totpart; totpart += psys->totchild; } if (totpart == 0) return derivedData; sim.scene = md->scene; sim.ob = pimd->ob; sim.psys = psys; sim.psmd = psys_get_modifier(pimd->ob, psys); if (pimd->flag & eParticleInstanceFlag_UseSize) { float *si; si = size = MEM_callocN(totpart * sizeof(float), "particle size array"); if (pimd->flag & eParticleInstanceFlag_Parents) { for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++, si++) *si = pa->size; } if (pimd->flag & eParticleInstanceFlag_Children) { ChildParticle *cpa = psys->child; for (p = 0; p < psys->totchild; p++, cpa++, si++) { *si = psys_get_child_size(psys, cpa, 0.0f, NULL); } } } totvert = dm->getNumVerts(dm); totpoly = dm->getNumPolys(dm); totloop = dm->getNumLoops(dm); /* totedge = dm->getNumEdges(dm); */ /* UNUSED */ /* count particles */ maxvert = 0; maxpoly = 0; maxloop = 0; for (p = 0; p < totpart; p++) { if (particle_skip(pimd, psys, p)) continue; maxvert += totvert; maxpoly += totpoly; maxloop += totloop; } psys->lattice = psys_get_lattice(&sim); if (psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) { float min_r[3], max_r[3]; INIT_MINMAX(min_r, max_r); dm->getMinMax(dm, min_r, max_r); min_co = min_r[track]; max_co = max_r[track]; } result = CDDM_from_template(dm, maxvert, 0, 0, maxloop, maxpoly); mvert = result->getVertArray(result); orig_mvert = dm->getVertArray(dm); mpoly = result->getPolyArray(result); orig_mpoly = dm->getPolyArray(dm); mloop = result->getLoopArray(result); orig_mloop = dm->getLoopArray(dm); for (p = 0, p_skip = 0; p < totpart; p++) { /* skip particle? */ if (particle_skip(pimd, psys, p)) continue; /* set vertices coordinates */ for (k = 0; k < totvert; k++) { ParticleKey state; MVert *inMV; MVert *mv = mvert + p_skip * totvert + k; inMV = orig_mvert + k; DM_copy_vert_data(dm, result, k, p_skip * totvert + k, 1); *mv = *inMV; /*change orientation based on object trackflag*/ copy_v3_v3(temp_co, mv->co); mv->co[axis] = temp_co[track]; mv->co[(axis + 1) % 3] = temp_co[(track + 1) % 3]; mv->co[(axis + 2) % 3] = temp_co[(track + 2) % 3]; /* get particle state */ if ((psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) && (pimd->flag & eParticleInstanceFlag_Path)) { float ran = 0.0f; if (pimd->random_position != 0.0f) { ran = pimd->random_position * BLI_hash_frand(psys->seed + p); } if (pimd->flag & eParticleInstanceFlag_KeepShape) { state.time = pimd->position * (1.0f - ran); } else { state.time = (mv->co[axis] - min_co) / (max_co - min_co) * pimd->position * (1.0f - ran); if (trackneg) state.time = 1.0f - state.time; mv->co[axis] = 0.0; } psys_get_particle_on_path(&sim, first_particle + p, &state, 1); normalize_v3(state.vel); /* TODO: incremental rotations somehow */ if (state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) { unit_qt(state.rot); } else { float temp[3] = {0.0f, 0.0f, 0.0f}; temp[axis] = 1.0f; cross_v3_v3v3(cross, temp, state.vel); /* state.vel[axis] is the only component surviving from a dot product with the axis */ axis_angle_to_quat(state.rot, cross, saacos(state.vel[axis])); } } else { state.time = -1.0; psys_get_particle_state(&sim, first_particle + p, &state, 1); } mul_qt_v3(state.rot, mv->co); if (pimd->flag & eParticleInstanceFlag_UseSize) mul_v3_fl(mv->co, size[p]); add_v3_v3(mv->co, state.co); } /* create polys and loops */ for (k = 0; k < totpoly; k++) { MPoly *inMP = orig_mpoly + k; MPoly *mp = mpoly + p_skip * totpoly + k; DM_copy_poly_data(dm, result, k, p_skip * totpoly + k, 1); *mp = *inMP; mp->loopstart += p_skip * totloop; { MLoop *inML = orig_mloop + inMP->loopstart; MLoop *ml = mloop + mp->loopstart; int j = mp->totloop; DM_copy_loop_data(dm, result, inMP->loopstart, mp->loopstart, j); for (; j; j--, ml++, inML++) { ml->v = inML->v + (p_skip * totvert); } } } p_skip++; } CDDM_calc_edges(result); if (psys->lattice) { end_latt_deform(psys->lattice); psys->lattice = NULL; } if (size) MEM_freeN(size); result->dirty |= DM_DIRTY_NORMALS; return result; }
static DerivedMesh *doOcean(ModifierData *md, Object *ob, DerivedMesh *derivedData, int UNUSED(useRenderParams)) { OceanModifierData *omd = (OceanModifierData *) md; DerivedMesh *dm = NULL; OceanResult ocr; MVert *mverts; int cfra; int i, j; /* use cached & inverted value for speed * expanded this would read... * * (axis / (omd->size * omd->spatial_size)) + 0.5f) */ #define OCEAN_CO(_size_co_inv, _v) ((_v * _size_co_inv) + 0.5f) const float size_co_inv = 1.0f / (omd->size * omd->spatial_size); /* can happen in when size is small, avoid bad array lookups later and quit now */ if (!isfinite(size_co_inv)) { return derivedData; } /* update modifier */ if (omd->refresh & MOD_OCEAN_REFRESH_ADD) { omd->ocean = BKE_ocean_add(); } if (omd->refresh & MOD_OCEAN_REFRESH_RESET) { init_ocean_modifier(omd); } if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE) { clear_cache_data(omd); } omd->refresh = 0; /* do ocean simulation */ if (omd->cached == true) { if (!omd->oceancache) { init_cache_data(ob, omd); } BKE_ocean_simulate_cache(omd->oceancache, md->scene->r.cfra); } else { simulate_ocean_modifier(omd); } if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) { dm = generate_ocean_geometry(omd); DM_ensure_normals(dm); } else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) { dm = CDDM_copy(derivedData); } cfra = md->scene->r.cfra; CLAMP(cfra, omd->bakestart, omd->bakeend); cfra -= omd->bakestart; /* shift to 0 based */ mverts = dm->getVertArray(dm); /* add vcols before displacement - allows lookup based on position */ if (omd->flag & MOD_OCEAN_GENERATE_FOAM) { if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL) < MAX_MCOL) { const int num_polys = dm->getNumPolys(dm); const int num_loops = dm->getNumLoops(dm); MLoop *mloops = dm->getLoopArray(dm); MLoopCol *mloopcols = CustomData_add_layer_named( &dm->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, num_loops, omd->foamlayername); if (mloopcols) { /* unlikely to fail */ MPoly *mpolys = dm->getPolyArray(dm); MPoly *mp; for (i = 0, mp = mpolys; i < num_polys; i++, mp++) { MLoop *ml = &mloops[mp->loopstart]; MLoopCol *mlcol = &mloopcols[mp->loopstart]; for (j = mp->totloop; j--; ml++, mlcol++) { const float *vco = mverts[ml->v].co; const float u = OCEAN_CO(size_co_inv, vco[0]); const float v = OCEAN_CO(size_co_inv, vco[1]); float foam; if (omd->oceancache && omd->cached == true) { BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v); foam = ocr.foam; CLAMP(foam, 0.0f, 1.0f); } else { BKE_ocean_eval_uv(omd->ocean, &ocr, u, v); foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage); } mlcol->r = mlcol->g = mlcol->b = (char)(foam * 255); /* This needs to be set (render engine uses) */ mlcol->a = 255; } } } } } /* displace the geometry */ /* Note: tried to parallelized that one and previous foam loop, but gives 20% slower results... odd. */ { const int num_verts = dm->getNumVerts(dm); for (i = 0; i < num_verts; i++) { float *vco = mverts[i].co; const float u = OCEAN_CO(size_co_inv, vco[0]); const float v = OCEAN_CO(size_co_inv, vco[1]); if (omd->oceancache && omd->cached == true) { BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v); } else { BKE_ocean_eval_uv(omd->ocean, &ocr, u, v); } vco[2] += ocr.disp[1]; if (omd->chop_amount > 0.0f) { vco[0] += ocr.disp[0]; vco[1] += ocr.disp[2]; } } } #undef OCEAN_CO return dm; }