static void generate_vert_coordinates( DerivedMesh *dm, Object *ob, Object *ob_center, const float offset[3], const int num_verts, float (*r_cos)[3], float r_size[3]) { float min_co[3], max_co[3]; float diff[3]; bool do_diff = false; INIT_MINMAX(min_co, max_co); dm->getVertCos(dm, r_cos); /* Get size (i.e. deformation of the spheroid generating normals), either from target object, or own geometry. */ if (ob_center) { /* Not we are not interested in signs here - they are even troublesome actually, due to security clamping! */ abs_v3_v3(r_size, ob_center->size); } else { minmax_v3v3_v3_array(min_co, max_co, r_cos, num_verts); /* Set size. */ sub_v3_v3v3(r_size, max_co, min_co); } /* Error checks - we do not want one or more of our sizes to be null! */ if (is_zero_v3(r_size)) { r_size[0] = r_size[1] = r_size[2] = 1.0f; } else { CLAMP_MIN(r_size[0], FLT_EPSILON); CLAMP_MIN(r_size[1], FLT_EPSILON); CLAMP_MIN(r_size[2], FLT_EPSILON); } if (ob_center) { float inv_obmat[4][4]; /* Translate our coordinates so that center of ob_center is at (0, 0, 0). */ /* Get ob_center (world) coordinates in ob local coordinates. * No need to take into account ob_center's space here, see T44027. */ invert_m4_m4(inv_obmat, ob->obmat); mul_v3_m4v3(diff, inv_obmat, ob_center->obmat[3]); negate_v3(diff); do_diff = true; } else if (!is_zero_v3(offset)) { negate_v3_v3(diff, offset); do_diff = true; } /* Else, no need to change coordinates! */ if (do_diff) { int i = num_verts; while (i--) { add_v3_v3(r_cos[i], diff); } } }
MINLINE float dot_v3v3v3(const float p[3], const float a[3], const float b[3]) { float vec1[3], vec2[3]; sub_v3_v3v3(vec1, a, p); sub_v3_v3v3(vec2, b, p); if (is_zero_v3(vec1) || is_zero_v3(vec2)) { return 0.0f; } return dot_v3v3(vec1, vec2); }
/* adjust bone roll to align Z axis with vector * vec is in local space and is normalized */ float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const short axis_only) { float mat[3][3], nor[3]; sub_v3_v3v3(nor, bone->tail, bone->head); vec_roll_to_mat3(nor, 0.0f, mat); /* check the bone isn't aligned with the axis */ if (!is_zero_v3(align_axis) && angle_v3v3(align_axis, mat[2]) > FLT_EPSILON) { float vec[3], align_axis_proj[3], roll; /* project the new_up_axis along the normal */ project_v3_v3v3(vec, align_axis, nor); sub_v3_v3v3(align_axis_proj, align_axis, vec); if (axis_only) { if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI / 2.0)) { negate_v3(align_axis_proj); } } roll = angle_v3v3(align_axis_proj, mat[2]); cross_v3_v3v3(vec, mat[2], align_axis_proj); if (dot_v3v3(vec, nor) < 0) { roll = -roll; } return roll; } return 0.0f; }
/* axis vector suffers from precision errors, use this function to ensure */ static void quat__axis_angle_sanitize(float axis[3], float *angle) { if (axis) { if (is_zero_v3(axis) || !finite(axis[0]) || !finite(axis[1]) || !finite(axis[2])) { axis[0] = 1.0f; axis[1] = 0.0f; axis[2] = 0.0f; } else if (EXPP_FloatsAreEqual(axis[0], 0.0f, 10) && EXPP_FloatsAreEqual(axis[1], 0.0f, 10) && EXPP_FloatsAreEqual(axis[2], 0.0f, 10)) { axis[0] = 1.0f; } } if (angle) { if (!finite(*angle)) { *angle = 0.0f; } } }
static bool stroke_elem_project_fallback( const struct CurveDrawData *cdd, const int mval_i[2], const float mval_fl[2], const float surface_offset, const float radius, const float location_fallback_depth[3], float r_location_world[3], float r_location_local[3], float r_normal_world[3], float r_normal_local[3]) { bool is_depth_found = stroke_elem_project( cdd, mval_i, mval_fl, surface_offset, radius, r_location_world, r_normal_world); if (is_depth_found == false) { ED_view3d_win_to_3d(cdd->vc.v3d, cdd->vc.ar, location_fallback_depth, mval_fl, r_location_world); zero_v3(r_normal_local); } mul_v3_m4v3(r_location_local, cdd->vc.obedit->imat, r_location_world); if (!is_zero_v3(r_normal_world)) { copy_v3_v3(r_normal_local, r_normal_world); mul_transposed_mat3_m4_v3(cdd->vc.obedit->obmat, r_normal_local); normalize_v3(r_normal_local); } else { zero_v3(r_normal_local); } return is_depth_found; }
static void applyObjectConstraintVec(TransInfo *t, TransDataContainer *tc, TransData *td, const float in[3], float out[3], float pvec[3]) { copy_v3_v3(out, in); if (t->con.mode & CON_APPLY) { if (!td) { mul_m3_v3(t->con.pmtx, out); const int dims = getConstraintSpaceDimension(t); if (dims == 2) { if (!is_zero_v3(out)) { if (!isPlaneProjectionViewAligned(t)) { planeProjection(t, in, out); } } } else if (dims == 1) { float c[3]; if (t->con.mode & CON_AXIS0) { copy_v3_v3(c, t->con.mtx[0]); } else if (t->con.mode & CON_AXIS1) { copy_v3_v3(c, t->con.mtx[1]); } else if (t->con.mode & CON_AXIS2) { copy_v3_v3(c, t->con.mtx[2]); } axisProjection(t, c, in, out); } postConstraintChecks(t, out, pvec); copy_v3_v3(out, pvec); } else { int i = 0; out[0] = out[1] = out[2] = 0.0f; if (t->con.mode & CON_AXIS0) { out[0] = in[i++]; } if (t->con.mode & CON_AXIS1) { out[1] = in[i++]; } if (t->con.mode & CON_AXIS2) { out[2] = in[i++]; } mul_m3_v3(td->axismtx, out); if (t->flag & T_EDIT) { mul_m3_v3(tc->mat3_unit, out); } } } }
static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int persistent_id[MAX_DUPLI_RECUR], int level, short flag) { DupliObject *dob; Group *group; GroupObject *go; float mat[4][4], tmat[4][4], id; if (ob->dup_group == NULL) return; group = ob->dup_group; /* simple preventing of too deep nested groups */ if (level > MAX_DUPLI_RECUR) return; /* handles animated groups, and */ /* we need to check update for objects that are not in scene... */ if (flag & DUPLILIST_DO_UPDATE) { /* note: update is optional because we don't always need object * transformations to be correct. Also fixes bug [#29616]. */ group_handle_recalc_and_update(scene, ob, group); } if (group_is_animated(ob, group)) flag |= DUPLILIST_ANIMATED; for (go = group->gobject.first, id = 0; go; go = go->next, id++) { /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */ if (go->ob != ob) { /* group dupli offset, should apply after everything else */ if (!is_zero_v3(group->dupli_ofs)) { copy_m4_m4(tmat, go->ob->obmat); sub_v3_v3v3(tmat[3], tmat[3], group->dupli_ofs); mult_m4_m4m4(mat, ob->obmat, tmat); } else { mult_m4_m4m4(mat, ob->obmat, go->ob->obmat); } dob = new_dupli_object(lb, go->ob, mat, ob->lay, persistent_id, level, id, OB_DUPLIGROUP, flag); /* check the group instance and object layers match, also that the object visible flags are ok. */ if ((dob->origlay & group->layer) == 0 || ((G.is_rendering == FALSE) && dob->ob->restrictflag & OB_RESTRICT_VIEW) || ((G.is_rendering == TRUE) && dob->ob->restrictflag & OB_RESTRICT_RENDER)) { dob->no_draw = TRUE; } if (go->ob->transflag & OB_DUPLI) { copy_m4_m4(dob->ob->obmat, dob->mat); object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, persistent_id, level + 1, id, flag); copy_m4_m4(dob->ob->obmat, dob->omat); } } } }
bool validSnappingNormal(TransInfo *t) { if (validSnap(t)) { if (!is_zero_v3(t->tsnap.snapNormal)) { return true; } } return false; }
void setBoneRollFromNormal(EditBone *bone, const float no[3], float UNUSED(invmat[4][4]), float tmat[3][3]) { if (no != NULL && !is_zero_v3(no)) { float normal[3]; copy_v3_v3(normal, no); mul_m3_v3(tmat, normal); bone->roll = ED_rollBoneToVector(bone, normal, false); } }
static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, int animated) { DupliObject *dob; Group *group; GroupObject *go; float mat[4][4], tmat[4][4]; if (ob->dup_group==NULL) return; group= ob->dup_group; /* simple preventing of too deep nested groups */ if (level>MAX_DUPLI_RECUR) return; /* handles animated groups, and */ /* we need to check update for objects that are not in scene... */ group_handle_recalc_and_update(scene, ob, group); animated= animated || group_is_animated(ob, group); for (go= group->gobject.first; go; go= go->next) { /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */ if (go->ob!=ob) { /* group dupli offset, should apply after everything else */ if (!is_zero_v3(group->dupli_ofs)) { copy_m4_m4(tmat, go->ob->obmat); sub_v3_v3v3(tmat[3], tmat[3], group->dupli_ofs); mult_m4_m4m4(mat, ob->obmat, tmat); } else { mult_m4_m4m4(mat, ob->obmat, go->ob->obmat); } dob= new_dupli_object(lb, go->ob, mat, ob->lay, 0, OB_DUPLIGROUP, animated); /* check the group instance and object layers match, also that the object visible flags are ok. */ if ( (dob->origlay & group->layer)==0 || (G.rendering==0 && dob->ob->restrictflag & OB_RESTRICT_VIEW) || (G.rendering && dob->ob->restrictflag & OB_RESTRICT_RENDER) ) { dob->no_draw= 1; } else { dob->no_draw= 0; } if (go->ob->transflag & OB_DUPLI) { copy_m4_m4(dob->ob->obmat, dob->mat); object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, level+1, animated); copy_m4_m4(dob->ob->obmat, dob->omat); } } } }
void init_tex_mapping(TexMapping *texmap) { float smat[3][3], rmat[3][3], mat[3][3], proj[3][3]; if (texmap->projx == PROJ_X && texmap->projy == PROJ_Y && texmap->projz == PROJ_Z && is_zero_v3(texmap->loc) && is_zero_v3(texmap->rot) && is_one_v3(texmap->size)) { unit_m4(texmap->mat); texmap->flag |= TEXMAP_UNIT_MATRIX; } else { /* axis projection */ zero_m3(proj); if (texmap->projx != PROJ_N) proj[texmap->projx - 1][0] = 1.0f; if (texmap->projy != PROJ_N) proj[texmap->projy - 1][1] = 1.0f; if (texmap->projz != PROJ_N) proj[texmap->projz - 1][2] = 1.0f; /* scale */ size_to_mat3(smat, texmap->size); /* rotation */ /* TexMapping rotation are now in radians. */ eul_to_mat3(rmat, texmap->rot); /* compose it all */ mul_m3_m3m3(mat, rmat, smat); mul_m3_m3m3(mat, proj, mat); /* translation */ copy_m4_m3(texmap->mat, mat); copy_v3_v3(texmap->mat[3], texmap->loc); texmap->flag &= ~TEXMAP_UNIT_MATRIX; } }
static void stroke_elem_pressure_set(const struct CurveDrawData *cdd, struct StrokeElem *selem, float pressure) { if ((cdd->project.surface_offset != 0.0f) && !cdd->project.use_surface_offset_absolute && !is_zero_v3(selem->normal_local)) { const float adjust = stroke_elem_radius_from_pressure(cdd, pressure) - stroke_elem_radius_from_pressure(cdd, selem->pressure); madd_v3_v3fl(selem->location_local, selem->normal_local, adjust); mul_v3_m4v3(selem->location_world, cdd->vc.obedit->obmat, selem->location_local); } selem->pressure = pressure; }
static void vpaint_proj_dm_map_cosnos_init__map_cb( void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]) { struct VertProjHandle *vp_handle = userData; CoNo *co_no = &vp_handle->vcosnos[index]; /* check if we've been here before (normal should not be 0) */ if (!is_zero_v3(co_no->no)) { /* remember that multiple dm verts share the same source vert */ vp_handle->use_update = true; return; } copy_v3_v3(co_no->co, co); if (no_f) { copy_v3_v3(co_no->no, no_f); } else { normal_short_to_float_v3(co_no->no, no_s); } }
static void applyAxisConstraintVec(TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, const float in[3], float out[3], float pvec[3]) { copy_v3_v3(out, in); if (!td && t->con.mode & CON_APPLY) { mul_m3_v3(t->con.pmtx, out); // With snap, a projection is alright, no need to correct for view alignment if (!validSnap(t)) { const int dims = getConstraintSpaceDimension(t); if (dims == 2) { if (!is_zero_v3(out)) { if (!isPlaneProjectionViewAligned(t)) { planeProjection(t, in, out); } } } else if (dims == 1) { float c[3]; if (t->con.mode & CON_AXIS0) { copy_v3_v3(c, t->con.mtx[0]); } else if (t->con.mode & CON_AXIS1) { copy_v3_v3(c, t->con.mtx[1]); } else if (t->con.mode & CON_AXIS2) { copy_v3_v3(c, t->con.mtx[2]); } axisProjection(t, c, in, out); } } postConstraintChecks(t, out, pvec); } }
static void cloth_continuum_step(ClothModifierData *clmd, float dt) { ClothSimSettings *parms = clmd->sim_parms; Cloth *cloth = clmd->clothObject; Implicit_Data *data = cloth->implicit; int mvert_num = cloth->mvert_num; ClothVertex *vert; const float fluid_factor = 0.95f; /* blend between PIC and FLIP methods */ float smoothfac = parms->velocity_smooth; /* XXX FIXME arbitrary factor!!! this should be based on some intuitive value instead, * like number of hairs per cell and time decay instead of "strength" */ float density_target = parms->density_target; float density_strength = parms->density_strength; float gmin[3], gmax[3]; int i; /* clear grid info */ zero_v3_int(clmd->hair_grid_res); zero_v3(clmd->hair_grid_min); zero_v3(clmd->hair_grid_max); clmd->hair_grid_cellsize = 0.0f; hair_get_boundbox(clmd, gmin, gmax); /* gather velocities & density */ if (smoothfac > 0.0f || density_strength > 0.0f) { HairGrid *grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_cell_size, gmin, gmax); cloth_continuum_fill_grid(grid, cloth); /* main hair continuum solver */ BPH_hair_volume_solve_divergence(grid, dt, density_target, density_strength); for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) { float x[3], v[3], nv[3]; /* calculate volumetric velocity influence */ BPH_mass_spring_get_position(data, i, x); BPH_mass_spring_get_new_velocity(data, i, v); BPH_hair_volume_grid_velocity(grid, x, v, fluid_factor, nv); interp_v3_v3v3(nv, v, nv, smoothfac); /* apply on hair data */ BPH_mass_spring_set_new_velocity(data, i, nv); } /* store basic grid info in the modifier data */ BPH_hair_volume_grid_geometry(grid, &clmd->hair_grid_cellsize, clmd->hair_grid_res, clmd->hair_grid_min, clmd->hair_grid_max); #if 0 /* DEBUG hair velocity vector field */ { const int size = 64; int i, j; float offset[3], a[3], b[3]; const int axis = 0; const float shift = 0.0f; copy_v3_v3(offset, clmd->hair_grid_min); zero_v3(a); zero_v3(b); offset[axis] = shift * clmd->hair_grid_cellsize; a[(axis+1) % 3] = clmd->hair_grid_max[(axis+1) % 3] - clmd->hair_grid_min[(axis+1) % 3]; b[(axis+2) % 3] = clmd->hair_grid_max[(axis+2) % 3] - clmd->hair_grid_min[(axis+2) % 3]; BKE_sim_debug_data_clear_category(clmd->debug_data, "grid velocity"); for (j = 0; j < size; ++j) { for (i = 0; i < size; ++i) { float x[3], v[3], gvel[3], gvel_smooth[3], gdensity; madd_v3_v3v3fl(x, offset, a, (float)i / (float)(size-1)); madd_v3_v3fl(x, b, (float)j / (float)(size-1)); zero_v3(v); BPH_hair_volume_grid_interpolate(grid, x, &gdensity, gvel, gvel_smooth, NULL, NULL); // BKE_sim_debug_data_add_circle(clmd->debug_data, x, gdensity, 0.7, 0.3, 1, "grid density", i, j, 3111); if (!is_zero_v3(gvel) || !is_zero_v3(gvel_smooth)) { float dvel[3]; sub_v3_v3v3(dvel, gvel_smooth, gvel); // BKE_sim_debug_data_add_vector(clmd->debug_data, x, gvel, 0.4, 0, 1, "grid velocity", i, j, 3112); // BKE_sim_debug_data_add_vector(clmd->debug_data, x, gvel_smooth, 0.6, 1, 1, "grid velocity", i, j, 3113); BKE_sim_debug_data_add_vector(clmd->debug_data, x, dvel, 0.4, 1, 0.7, "grid velocity", i, j, 3114); #if 0 if (gdensity > 0.0f) { float col0[3] = {0.0, 0.0, 0.0}; float col1[3] = {0.0, 1.0, 0.0}; float col[3]; interp_v3_v3v3(col, col0, col1, CLAMPIS(gdensity * clmd->sim_parms->density_strength, 0.0, 1.0)); // BKE_sim_debug_data_add_circle(clmd->debug_data, x, gdensity * clmd->sim_parms->density_strength, 0, 1, 0.4, "grid velocity", i, j, 3115); // BKE_sim_debug_data_add_dot(clmd->debug_data, x, col[0], col[1], col[2], "grid velocity", i, j, 3115); BKE_sim_debug_data_add_circle(clmd->debug_data, x, 0.01f, col[0], col[1], col[2], "grid velocity", i, j, 3115); } #endif } } } } #endif BPH_hair_volume_free_vertex_grid(grid); } }
/* OB_DUPLIPARTS */ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem *psys) { Scene *scene = ctx->scene; Object *par = ctx->object; bool for_render = ctx->eval_ctx->mode == DAG_EVAL_RENDER; bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW); GroupObject *go; Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL; DupliObject *dob; ParticleDupliWeight *dw; ParticleSettings *part; ParticleData *pa; ChildParticle *cpa = NULL; ParticleKey state; ParticleCacheKey *cache; float ctime, pa_time, scale = 1.0f; float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0; float (*obmat)[4]; int a, b, hair = 0; int totpart, totchild, totgroup = 0 /*, pa_num */; const bool dupli_type_hack = !BKE_scene_use_new_shading_nodes(scene); int no_draw_flag = PARS_UNEXIST; if (psys == NULL) return; part = psys->part; if (part == NULL) return; if (!psys_check_enabled(par, psys)) return; if (!for_render) no_draw_flag |= PARS_NO_DISP; ctime = BKE_scene_frame_get(scene); /* NOTE: in old animsys, used parent object's timeoffset... */ totpart = psys->totpart; totchild = psys->totchild; BLI_srandom((unsigned int)(31415926 + psys->seed)); if ((psys->renderdata || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { ParticleSimulationData sim = {NULL}; sim.scene = scene; sim.ob = par; sim.psys = psys; sim.psmd = psys_get_modifier(par, psys); /* make sure emitter imat is in global coordinates instead of render view coordinates */ invert_m4_m4(par->imat, par->obmat); /* first check for loops (particle system object used as dupli object) */ if (part->ren_as == PART_DRAW_OB) { if (ELEM(part->dup_ob, NULL, par)) return; } else { /*PART_DRAW_GR */ if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->gobject)) return; if (BLI_findptr(&part->dup_group->gobject, par, offsetof(GroupObject, ob))) { return; } } /* if we have a hair particle system, use the path cache */ if (part->type == PART_HAIR) { if (psys->flag & PSYS_HAIR_DONE) hair = (totchild == 0 || psys->childcache) && psys->pathcache; if (!hair) return; /* we use cache, update totchild according to cached data */ totchild = psys->totchildcache; totpart = psys->totcached; } psys_check_group_weights(part); psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); /* gather list of objects or single object */ if (part->ren_as == PART_DRAW_GR) { if (ctx->do_update) { BKE_group_handle_recalc_and_update(ctx->eval_ctx, scene, par, part->dup_group); } if (part->draw & PART_DRAW_COUNT_GR) { for (dw = part->dupliweights.first; dw; dw = dw->next) totgroup += dw->count; } else { for (go = part->dup_group->gobject.first; go; go = go->next) totgroup++; } /* we also copy the actual objects to restore afterwards, since * BKE_object_where_is_calc_time will change the object which breaks transform */ oblist = MEM_callocN((size_t)totgroup * sizeof(Object *), "dupgroup object list"); obcopylist = MEM_callocN((size_t)totgroup * sizeof(Object), "dupgroup copy list"); if (part->draw & PART_DRAW_COUNT_GR && totgroup) { dw = part->dupliweights.first; for (a = 0; a < totgroup; dw = dw->next) { for (b = 0; b < dw->count; b++, a++) { oblist[a] = dw->ob; obcopylist[a] = *dw->ob; } } } else { go = part->dup_group->gobject.first; for (a = 0; a < totgroup; a++, go = go->next) { oblist[a] = go->ob; obcopylist[a] = *go->ob; } } } else { ob = part->dup_ob; obcopy = *ob; } if (totchild == 0 || part->draw & PART_DRAW_PARENT) a = 0; else a = totpart; for (pa = psys->particles; a < totpart + totchild; a++, pa++) { if (a < totpart) { /* handle parent particle */ if (pa->flag & no_draw_flag) continue; /* pa_num = pa->num; */ /* UNUSED */ pa_time = pa->time; size = pa->size; } else { /* handle child particle */ cpa = &psys->child[a - totpart]; /* pa_num = a; */ /* UNUSED */ pa_time = psys->particles[cpa->parent].time; size = psys_get_child_size(psys, cpa, ctime, NULL); } /* some hair paths might be non-existent so they can't be used for duplication */ if (hair && psys->pathcache && ((a < totpart && psys->pathcache[a]->segments < 0) || (a >= totpart && psys->childcache[a - totpart]->segments < 0))) { continue; } if (part->ren_as == PART_DRAW_GR) { /* prevent divide by zero below [#28336] */ if (totgroup == 0) continue; /* for groups, pick the object based on settings */ if (part->draw & PART_DRAW_RAND_GR) b = BLI_rand() % totgroup; else b = a % totgroup; ob = oblist[b]; obmat = oblist[b]->obmat; } else { obmat = ob->obmat; } if (hair) { /* hair we handle separate and compute transform based on hair keys */ if (a < totpart) { cache = psys->pathcache[a]; psys_get_dupli_path_transform(&sim, pa, NULL, cache, pamat, &scale); } else { cache = psys->childcache[a - totpart]; psys_get_dupli_path_transform(&sim, NULL, cpa, cache, pamat, &scale); } copy_v3_v3(pamat[3], cache->co); pamat[3][3] = 1.0f; } else { /* first key */ state.time = ctime; if (psys_get_particle_state(&sim, a, &state, 0) == 0) { continue; } else { float tquat[4]; normalize_qt_qt(tquat, state.rot); quat_to_mat4(pamat, tquat); copy_v3_v3(pamat[3], state.co); pamat[3][3] = 1.0f; } } if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { for (go = part->dup_group->gobject.first, b = 0; go; go = go->next, b++) { copy_m4_m4(tmat, oblist[b]->obmat); /* apply particle scale */ mul_mat3_m4_fl(tmat, size * scale); mul_v3_fl(tmat[3], size * scale); /* group dupli offset, should apply after everything else */ if (!is_zero_v3(part->dup_group->dupli_ofs)) sub_v3_v3(tmat[3], part->dup_group->dupli_ofs); /* individual particle transform */ mul_m4_m4m4(mat, pamat, tmat); dob = make_dupli(ctx, go->ob, mat, a, false, false); dob->particle_system = psys; if (use_texcoords) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } } else { /* to give ipos in object correct offset */ BKE_object_where_is_calc_time(scene, ob, ctime - pa_time); copy_v3_v3(vec, obmat[3]); obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f; /* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */ if ((part->draw & PART_DRAW_ROTATE_OB) == 0) { float xvec[3], q[4], size_mat[4][4], original_size[3]; mat4_to_size(original_size, obmat); size_to_mat4(size_mat, original_size); xvec[0] = -1.f; xvec[1] = xvec[2] = 0; vec_to_quat(q, xvec, ob->trackflag, ob->upflag); quat_to_mat4(obmat, q); obmat[3][3] = 1.0f; /* add scaling if requested */ if ((part->draw & PART_DRAW_NO_SCALE_OB) == 0) mul_m4_m4m4(obmat, obmat, size_mat); } else if (part->draw & PART_DRAW_NO_SCALE_OB) { /* remove scaling */ float size_mat[4][4], original_size[3]; mat4_to_size(original_size, obmat); size_to_mat4(size_mat, original_size); invert_m4(size_mat); mul_m4_m4m4(obmat, obmat, size_mat); } mul_m4_m4m4(tmat, pamat, obmat); mul_mat3_m4_fl(tmat, size * scale); copy_m4_m4(mat, tmat); if (part->draw & PART_DRAW_GLOBAL_OB) add_v3_v3v3(mat[3], mat[3], vec); dob = make_dupli(ctx, ob, mat, a, false, false); dob->particle_system = psys; if (use_texcoords) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); /* XXX blender internal needs this to be set to dupligroup to render * groups correctly, but we don't want this hack for cycles */ if (dupli_type_hack && ctx->group) dob->type = OB_DUPLIGROUP; } } /* restore objects since they were changed in BKE_object_where_is_calc_time */ if (part->ren_as == PART_DRAW_GR) { for (a = 0; a < totgroup; a++) *(oblist[a]) = obcopylist[a]; } else *ob = obcopy; } /* clean up */ if (oblist) MEM_freeN(oblist); if (obcopylist) MEM_freeN(obcopylist); if (psys->lattice_deform_data) { end_latt_deform(psys->lattice_deform_data); psys->lattice_deform_data = NULL; } }
static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo) { float loc[3]; float rot[4]; float scale[3]; /* only update if rigid body exists */ if (rbo->physics_object == NULL) return; if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) { DerivedMesh *dm = ob->derivedDeform; if (dm) { MVert *mvert = dm->getVertArray(dm); int totvert = dm->getNumVerts(dm); BoundBox *bb = BKE_object_boundbox_get(ob); RB_shape_trimesh_update(rbo->physics_shape, (float *)mvert, totvert, sizeof(MVert), bb->vec[0], bb->vec[6]); } } mat4_decompose(loc, rot, scale, ob->obmat); /* update scale for all objects */ RB_body_set_scale(rbo->physics_object, scale); /* compensate for embedded convex hull collision margin */ if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && rbo->shape == RB_SHAPE_CONVEXH) RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo) * MIN3(scale[0], scale[1], scale[2])); /* make transformed objects temporarily kinmatic so that they can be moved by the user during simulation */ if (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ) { RB_body_set_kinematic_state(rbo->physics_object, TRUE); RB_body_set_mass(rbo->physics_object, 0.0f); } /* update rigid body location and rotation for kinematic bodies */ if (rbo->flag & RBO_FLAG_KINEMATIC || (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) { RB_body_activate(rbo->physics_object); RB_body_set_loc_rot(rbo->physics_object, loc, rot); } /* update influence of effectors - but don't do it on an effector */ /* only dynamic bodies need effector update */ else if (rbo->type == RBO_TYPE_ACTIVE && ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) { EffectorWeights *effector_weights = rbw->effector_weights; EffectedPoint epoint; ListBase *effectors; /* get effectors present in the group specified by effector_weights */ effectors = pdInitEffectors(scene, ob, NULL, effector_weights); if (effectors) { float eff_force[3] = {0.0f, 0.0f, 0.0f}; float eff_loc[3], eff_vel[3]; /* create dummy 'point' which represents last known position of object as result of sim */ // XXX: this can create some inaccuracies with sim position, but is probably better than using unsimulated vals? RB_body_get_position(rbo->physics_object, eff_loc); RB_body_get_linear_velocity(rbo->physics_object, eff_vel); pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint); /* calculate net force of effectors, and apply to sim object * - we use 'central force' since apply force requires a "relative position" which we don't have... */ pdDoEffectors(effectors, NULL, effector_weights, &epoint, eff_force, NULL); if (G.f & G_DEBUG) printf("\tapplying force (%f,%f,%f) to '%s'\n", eff_force[0], eff_force[1], eff_force[2], ob->id.name + 2); /* activate object in case it is deactivated */ if (!is_zero_v3(eff_force)) RB_body_activate(rbo->physics_object); RB_body_apply_central_force(rbo->physics_object, eff_force); } else if (G.f & G_DEBUG) printf("\tno forces to apply to '%s'\n", ob->id.name + 2); /* cleanup */ pdEndEffectors(&effectors); } /* NOTE: passive objects don't need to be updated since they don't move */ /* NOTE: no other settings need to be explicitly updated here, * since RNA setters take care of the rest :) */ }
static void axisProjection(TransInfo *t, const float axis[3], const float in[3], float out[3]) { float norm[3], vec[3], factor, angle; float t_con_center[3]; if (is_zero_v3(in)) { return; } copy_v3_v3(t_con_center, t->center_global); /* checks for center being too close to the view center */ viewAxisCorrectCenter(t, t_con_center); angle = fabsf(angle_v3v3(axis, t->viewinv[2])); if (angle > (float)M_PI_2) { angle = (float)M_PI - angle; } angle = RAD2DEGF(angle); /* For when view is parallel to constraint... will cause NaNs otherwise * So we take vertical motion in 3D space and apply it to the * constraint axis. Nice for camera grab + MMB */ if (angle < 5.0f) { project_v3_v3v3(vec, in, t->viewinv[1]); factor = dot_v3v3(t->viewinv[1], vec) * 2.0f; /* since camera distance is quite relative, use quadratic relationship. holding shift can compensate */ if (factor < 0.0f) factor *= -factor; else factor *= factor; copy_v3_v3(out, axis); normalize_v3(out); mul_v3_fl(out, -factor); /* -factor makes move down going backwards */ } else { float v[3], i1[3], i2[3]; float v2[3], v4[3]; float norm_center[3]; float plane[3]; getViewVector(t, t_con_center, norm_center); cross_v3_v3v3(plane, norm_center, axis); project_v3_v3v3(vec, in, plane); sub_v3_v3v3(vec, in, vec); add_v3_v3v3(v, vec, t_con_center); getViewVector(t, v, norm); /* give arbitrary large value if projection is impossible */ factor = dot_v3v3(axis, norm); if (1.0f - fabsf(factor) < 0.0002f) { copy_v3_v3(out, axis); if (factor > 0) { mul_v3_fl(out, 1000000000.0f); } else { mul_v3_fl(out, -1000000000.0f); } } else { add_v3_v3v3(v2, t_con_center, axis); add_v3_v3v3(v4, v, norm); isect_line_line_v3(t_con_center, v2, v, v4, i1, i2); sub_v3_v3v3(v, i2, v); sub_v3_v3v3(out, i1, t_con_center); /* possible some values become nan when * viewpoint and object are both zero */ if (!finite(out[0])) out[0] = 0.0f; if (!finite(out[1])) out[1] = 0.0f; if (!finite(out[2])) out[2] = 0.0f; } } }
static int walkApply_ndof(bContext *C, WalkInfo *walk) { /* shorthand for oft-used variables */ wmNDOFMotionData *ndof = walk->ndof; const float dt = ndof->dt; RegionView3D *rv3d = walk->rv3d; const int flag = U.ndof_flag; #if 0 bool do_rotate = (flag & NDOF_SHOULD_ROTATE) && (walk->pan_view == false); bool do_translate = (flag & (NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM)) != 0; #endif bool do_rotate = true; bool do_translate = true; float view_inv[4]; invert_qt_qt(view_inv, rv3d->viewquat); rv3d->rot_angle = 0.0f; /* disable onscreen rotation doo-dad */ if (do_translate) { const float forward_sensitivity = 1.0f; const float vertical_sensitivity = 0.4f; const float lateral_sensitivity = 0.6f; float speed = 10.0f; /* blender units per second */ /* ^^ this is ok for default cube scene, but should scale with.. something */ float trans[3] = {lateral_sensitivity * ndof->tvec[0], vertical_sensitivity * ndof->tvec[1], forward_sensitivity * ndof->tvec[2]}; if (walk->is_slow) speed *= 0.2f; mul_v3_fl(trans, speed * dt); /* transform motion from view to world coordinates */ mul_qt_v3(view_inv, trans); if (flag & NDOF_FLY_HELICOPTER) { /* replace world z component with device y (yes it makes sense) */ trans[2] = speed * dt * vertical_sensitivity * ndof->tvec[1]; } if (rv3d->persp == RV3D_CAMOB) { /* respect camera position locks */ Object *lock_ob = ED_view3d_cameracontrol_object_get(walk->v3d_camera_control); if (lock_ob->protectflag & OB_LOCK_LOCX) trans[0] = 0.0f; if (lock_ob->protectflag & OB_LOCK_LOCY) trans[1] = 0.0f; if (lock_ob->protectflag & OB_LOCK_LOCZ) trans[2] = 0.0f; } if (!is_zero_v3(trans)) { /* move center of view opposite of hand motion (this is camera mode, not object mode) */ sub_v3_v3(rv3d->ofs, trans); do_translate = true; } else { do_translate = false; } } if (do_rotate) { const float turn_sensitivity = 1.0f; float rotation[4]; float axis[3]; float angle = turn_sensitivity * ndof_to_axis_angle(ndof, axis); if (fabsf(angle) > 0.0001f) { do_rotate = true; if (walk->is_slow) angle *= 0.2f; /* transform rotation axis from view to world coordinates */ mul_qt_v3(view_inv, axis); /* apply rotation to view */ axis_angle_to_quat(rotation, axis, angle); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation); if (flag & NDOF_LOCK_HORIZON) { /* force an upright viewpoint * TODO: make this less... sudden */ float view_horizon[3] = {1.0f, 0.0f, 0.0f}; /* view +x */ float view_direction[3] = {0.0f, 0.0f, -1.0f}; /* view -z (into screen) */ /* find new inverse since viewquat has changed */ invert_qt_qt(view_inv, rv3d->viewquat); /* could apply reverse rotation to existing view_inv to save a few cycles */ /* transform view vectors to world coordinates */ mul_qt_v3(view_inv, view_horizon); mul_qt_v3(view_inv, view_direction); /* find difference between view & world horizons * true horizon lives in world xy plane, so look only at difference in z */ angle = -asinf(view_horizon[2]); #ifdef NDOF_WALK_DEBUG printf("lock horizon: adjusting %.1f degrees\n\n", RAD2DEG(angle)); #endif /* rotate view so view horizon = world horizon */ axis_angle_to_quat(rotation, view_direction, angle); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation); } rv3d->view = RV3D_VIEW_USER; } else { do_rotate = false; } } if (do_translate || do_rotate) { walk->redraw = true; if (rv3d->persp == RV3D_CAMOB) { walkMoveCamera(C, walk, do_rotate, do_translate); } } return OPERATOR_FINISHED; }
static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level, int animated) { GroupObject *go; Object *ob=NULL, **oblist=NULL, obcopy, *obcopylist=NULL; DupliObject *dob; ParticleDupliWeight *dw; ParticleSettings *part; ParticleData *pa; ChildParticle *cpa=NULL; ParticleKey state; ParticleCacheKey *cache; float ctime, pa_time, scale = 1.0f; float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size=0.0; float (*obmat)[4], (*oldobmat)[4]; int a, b, counter, hair = 0; int totpart, totchild, totgroup=0 /*, pa_num */; int no_draw_flag = PARS_UNEXIST; if (psys==NULL) return; /* simple preventing of too deep nested groups */ if (level>MAX_DUPLI_RECUR) return; part=psys->part; if (part==NULL) return; if (!psys_check_enabled(par, psys)) return; if (G.rendering == 0) no_draw_flag |= PARS_NO_DISP; ctime = BKE_curframe(scene); /* NOTE: in old animsys, used parent object's timeoffset... */ totpart = psys->totpart; totchild = psys->totchild; BLI_srandom(31415926 + psys->seed); if ((psys->renderdata || part->draw_as==PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { ParticleSimulationData sim= {NULL}; sim.scene= scene; sim.ob= par; sim.psys= psys; sim.psmd= psys_get_modifier(par, psys); /* make sure emitter imat is in global coordinates instead of render view coordinates */ invert_m4_m4(par->imat, par->obmat); /* first check for loops (particle system object used as dupli object) */ if (part->ren_as == PART_DRAW_OB) { if (ELEM(part->dup_ob, NULL, par)) return; } else { /*PART_DRAW_GR */ if (part->dup_group == NULL || part->dup_group->gobject.first == NULL) return; for (go=part->dup_group->gobject.first; go; go=go->next) if (go->ob == par) return; } /* if we have a hair particle system, use the path cache */ if (part->type == PART_HAIR) { if (psys->flag & PSYS_HAIR_DONE) hair= (totchild == 0 || psys->childcache) && psys->pathcache; if (!hair) return; /* we use cache, update totchild according to cached data */ totchild = psys->totchildcache; totpart = psys->totcached; } psys_check_group_weights(part); psys->lattice = psys_get_lattice(&sim); /* gather list of objects or single object */ if (part->ren_as==PART_DRAW_GR) { group_handle_recalc_and_update(scene, par, part->dup_group); if (part->draw & PART_DRAW_COUNT_GR) { for (dw=part->dupliweights.first; dw; dw=dw->next) totgroup += dw->count; } else { for (go=part->dup_group->gobject.first; go; go=go->next) totgroup++; } /* we also copy the actual objects to restore afterwards, since * where_is_object_time will change the object which breaks transform */ oblist = MEM_callocN(totgroup*sizeof(Object *), "dupgroup object list"); obcopylist = MEM_callocN(totgroup*sizeof(Object), "dupgroup copy list"); if (part->draw & PART_DRAW_COUNT_GR && totgroup) { dw = part->dupliweights.first; for (a=0; a<totgroup; dw=dw->next) { for (b=0; b<dw->count; b++, a++) { oblist[a] = dw->ob; obcopylist[a] = *dw->ob; } } } else { go = part->dup_group->gobject.first; for (a=0; a<totgroup; a++, go=go->next) { oblist[a] = go->ob; obcopylist[a] = *go->ob; } } } else { ob = part->dup_ob; obcopy = *ob; } if (totchild==0 || part->draw & PART_DRAW_PARENT) a = 0; else a = totpart; for (pa=psys->particles,counter=0; a<totpart+totchild; a++,pa++,counter++) { if (a<totpart) { /* handle parent particle */ if (pa->flag & no_draw_flag) continue; /* pa_num = pa->num; */ /* UNUSED */ pa_time = pa->time; size = pa->size; } else { /* handle child particle */ cpa = &psys->child[a - totpart]; /* pa_num = a; */ /* UNUSED */ pa_time = psys->particles[cpa->parent].time; size = psys_get_child_size(psys, cpa, ctime, NULL); } /* some hair paths might be non-existent so they can't be used for duplication */ if (hair && ((a < totpart && psys->pathcache[a]->steps < 0) || (a >= totpart && psys->childcache[a-totpart]->steps < 0))) continue; if (part->ren_as==PART_DRAW_GR) { /* prevent divide by zero below [#28336] */ if (totgroup == 0) continue; /* for groups, pick the object based on settings */ if (part->draw&PART_DRAW_RAND_GR) b= BLI_rand() % totgroup; else b= a % totgroup; ob = oblist[b]; obmat = oblist[b]->obmat; oldobmat = obcopylist[b].obmat; } else { obmat= ob->obmat; oldobmat= obcopy.obmat; } if (hair) { /* hair we handle separate and compute transform based on hair keys */ if (a < totpart) { cache = psys->pathcache[a]; psys_get_dupli_path_transform(&sim, pa, NULL, cache, pamat, &scale); } else { cache = psys->childcache[a-totpart]; psys_get_dupli_path_transform(&sim, NULL, cpa, cache, pamat, &scale); } copy_v3_v3(pamat[3], cache->co); pamat[3][3]= 1.0f; } else { /* first key */ state.time = ctime; if (psys_get_particle_state(&sim, a, &state, 0) == 0) { continue; } else { float tquat[4]; normalize_qt_qt(tquat, state.rot); quat_to_mat4(pamat, tquat); copy_v3_v3(pamat[3], state.co); pamat[3][3]= 1.0f; } } if (part->ren_as==PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { for (go= part->dup_group->gobject.first, b=0; go; go= go->next, b++) { copy_m4_m4(tmat, oblist[b]->obmat); /* apply particle scale */ mul_mat3_m4_fl(tmat, size*scale); mul_v3_fl(tmat[3], size*scale); /* group dupli offset, should apply after everything else */ if (!is_zero_v3(part->dup_group->dupli_ofs)) sub_v3_v3v3(tmat[3], tmat[3], part->dup_group->dupli_ofs); /* individual particle transform */ mult_m4_m4m4(tmat, pamat, tmat); if (par_space_mat) mult_m4_m4m4(mat, par_space_mat, tmat); else copy_m4_m4(mat, tmat); dob= new_dupli_object(lb, go->ob, mat, par->lay, counter, OB_DUPLIPARTS, animated); copy_m4_m4(dob->omat, obcopylist[b].obmat); if (G.rendering) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } } else { /* to give ipos in object correct offset */ where_is_object_time(scene, ob, ctime-pa_time); copy_v3_v3(vec, obmat[3]); obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f; /* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */ if ((part->draw & PART_DRAW_ROTATE_OB) == 0) { float xvec[3], q[4]; xvec[0] = -1.f; xvec[1] = xvec[2] = 0; vec_to_quat(q, xvec, ob->trackflag, ob->upflag); quat_to_mat4(obmat, q); obmat[3][3]= 1.0f; } /* Normal particles and cached hair live in global space so we need to * remove the real emitter's transformation before 2nd order duplication. */ if (par_space_mat && GS(id->name) != ID_GR) mult_m4_m4m4(mat, psys->imat, pamat); else copy_m4_m4(mat, pamat); mult_m4_m4m4(tmat, mat, obmat); mul_mat3_m4_fl(tmat, size*scale); if (par_space_mat) mult_m4_m4m4(mat, par_space_mat, tmat); else copy_m4_m4(mat, tmat); if (part->draw & PART_DRAW_GLOBAL_OB) add_v3_v3v3(mat[3], mat[3], vec); dob= new_dupli_object(lb, ob, mat, ob->lay, counter, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, animated); copy_m4_m4(dob->omat, oldobmat); if (G.rendering) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } } /* restore objects since they were changed in where_is_object_time */ if (part->ren_as==PART_DRAW_GR) { for (a=0; a<totgroup; a++) *(oblist[a])= obcopylist[a]; } else *ob= obcopy; } /* clean up */ if (oblist) MEM_freeN(oblist); if (obcopylist) MEM_freeN(obcopylist); if (psys->lattice) { end_latt_deform(psys->lattice); psys->lattice = NULL; } }
void init_tex_mapping(TexMapping *texmap) { float smat[4][4], rmat[4][4], tmat[4][4], proj[4][4], size[3]; if (texmap->projx == PROJ_X && texmap->projy == PROJ_Y && texmap->projz == PROJ_Z && is_zero_v3(texmap->loc) && is_zero_v3(texmap->rot) && is_one_v3(texmap->size)) { unit_m4(texmap->mat); texmap->flag |= TEXMAP_UNIT_MATRIX; } else { /* axis projection */ zero_m4(proj); proj[3][3] = 1.0f; if (texmap->projx != PROJ_N) proj[texmap->projx - 1][0] = 1.0f; if (texmap->projy != PROJ_N) proj[texmap->projy - 1][1] = 1.0f; if (texmap->projz != PROJ_N) proj[texmap->projz - 1][2] = 1.0f; /* scale */ copy_v3_v3(size, texmap->size); if (ELEM(texmap->type, TEXMAP_TYPE_TEXTURE, TEXMAP_TYPE_NORMAL)) { /* keep matrix invertible */ if (fabsf(size[0]) < 1e-5f) size[0] = signf(size[0]) * 1e-5f; if (fabsf(size[1]) < 1e-5f) size[1] = signf(size[1]) * 1e-5f; if (fabsf(size[2]) < 1e-5f) size[2] = signf(size[2]) * 1e-5f; } size_to_mat4(smat, texmap->size); /* rotation */ eul_to_mat4(rmat, texmap->rot); /* translation */ unit_m4(tmat); copy_v3_v3(tmat[3], texmap->loc); if (texmap->type == TEXMAP_TYPE_TEXTURE) { /* to transform a texture, the inverse transform needs * to be applied to the texture coordinate */ mul_serie_m4(texmap->mat, tmat, rmat, smat, 0, 0, 0, 0, 0); invert_m4(texmap->mat); } else if (texmap->type == TEXMAP_TYPE_POINT) { /* forward transform */ mul_serie_m4(texmap->mat, tmat, rmat, smat, 0, 0, 0, 0, 0); } else if (texmap->type == TEXMAP_TYPE_VECTOR) { /* no translation for vectors */ mul_m4_m4m4(texmap->mat, rmat, smat); } else if (texmap->type == TEXMAP_TYPE_NORMAL) { /* no translation for normals, and inverse transpose */ mul_m4_m4m4(texmap->mat, rmat, smat); invert_m4(texmap->mat); transpose_m4(texmap->mat); } /* projection last */ mul_m4_m4m4(texmap->mat, texmap->mat, proj); texmap->flag &= ~TEXMAP_UNIT_MATRIX; } }
static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) { if (t->spacetype == SPACE_VIEW3D) { float loc[3]; float no[3]; float mval[2]; bool found = false; float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here mval[0] = t->mval[0]; mval[1] = t->mval[1]; if (t->tsnap.mode == SCE_SNAP_MODE_VOLUME) { found = peelObjectsTransform( t, mval, (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0, loc, no, NULL); } else { zero_v3(no); /* objects won't set this */ found = snapObjectsTransform( t, mval, &dist_px, loc, no); } if (found == true) { float tangent[3]; sub_v2_v2v2(tangent, loc, t->tsnap.snapPoint); tangent[2] = 0.0f; if (!is_zero_v3(tangent)) { copy_v3_v3(t->tsnap.snapTangent, tangent); } copy_v3_v3(t->tsnap.snapPoint, loc); copy_v3_v3(t->tsnap.snapNormal, no); t->tsnap.status |= POINT_INIT; } else { t->tsnap.status &= ~POINT_INIT; } } else if (t->spacetype == SPACE_IMAGE && t->obedit != NULL && t->obedit->type == OB_MESH) { /* same as above but for UV's */ Image *ima = ED_space_image(t->sa->spacedata.first); float co[2]; UI_view2d_region_to_view(&t->ar->v2d, t->mval[0], t->mval[1], &co[0], &co[1]); if (ED_uvedit_nearest_uv(t->scene, t->obedit, ima, co, t->tsnap.snapPoint)) { t->tsnap.snapPoint[0] *= t->aspect[0]; t->tsnap.snapPoint[1] *= t->aspect[1]; t->tsnap.status |= POINT_INIT; } else { t->tsnap.status &= ~POINT_INIT; } } else if (t->spacetype == SPACE_NODE) { float loc[2]; float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here char node_border; if (snapNodesTransform(t, t->mval, t->tsnap.modeSelect, loc, &dist_px, &node_border)) { copy_v2_v2(t->tsnap.snapPoint, loc); t->tsnap.snapNodeBorder = node_border; t->tsnap.status |= POINT_INIT; } else { t->tsnap.status &= ~POINT_INIT; } } }