/** * \param dm Mesh to calculate normals for. * \param face_nors Precalculated face normals. * \param r_vert_nors Return vert normals. */ static void dm_calc_normal(DerivedMesh *dm, float (*face_nors)[3], float (*r_vert_nors)[3]) { int i, numVerts, numEdges, numFaces; MPoly *mpoly, *mp; MLoop *mloop, *ml; MEdge *medge, *ed; MVert *mvert, *mv; numVerts = dm->getNumVerts(dm); numEdges = dm->getNumEdges(dm); numFaces = dm->getNumPolys(dm); mpoly = dm->getPolyArray(dm); medge = dm->getEdgeArray(dm); mvert = dm->getVertArray(dm); mloop = dm->getLoopArray(dm); /* we don't want to overwrite any referenced layers */ /* Doesn't work here! */ #if 0 mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, numVerts); cddm->mvert = mv; #endif mv = mvert; mp = mpoly; { EdgeFaceRef *edge_ref_array = MEM_callocN(sizeof(EdgeFaceRef) * (size_t)numEdges, "Edge Connectivity"); EdgeFaceRef *edge_ref; float edge_normal[3]; /* This loop adds an edge hash if its not there, and adds the face index */ for (i = 0; i < numFaces; i++, mp++) { int j; ml = mloop + mp->loopstart; for (j = 0; j < mp->totloop; j++, ml++) { /* --- add edge ref to face --- */ edge_ref = &edge_ref_array[ml->e]; if (!edgeref_is_init(edge_ref)) { edge_ref->f1 = i; edge_ref->f2 = -1; } else if ((edge_ref->f1 != -1) && (edge_ref->f2 == -1)) { edge_ref->f2 = i; } else { /* 3+ faces using an edge, we can't handle this usefully */ edge_ref->f1 = edge_ref->f2 = -1; #ifdef USE_NONMANIFOLD_WORKAROUND medge[ml->e].flag |= ME_EDGE_TMP_TAG; #endif } /* --- done --- */ } } for (i = 0, ed = medge, edge_ref = edge_ref_array; i < numEdges; i++, ed++, edge_ref++) { /* Get the edge vert indices, and edge value (the face indices that use it) */ if (edgeref_is_init(edge_ref) && (edge_ref->f1 != -1)) { if (edge_ref->f2 != -1) { /* We have 2 faces using this edge, calculate the edges normal * using the angle between the 2 faces as a weighting */ #if 0 add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]); normalize_v3(edge_normal); mul_v3_fl(edge_normal, angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2])); #else mid_v3_v3v3_angle_weighted(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]); #endif } else { /* only one face attached to that edge */ /* an edge without another attached- the weight on this is undefined */ copy_v3_v3(edge_normal, face_nors[edge_ref->f1]); } add_v3_v3(r_vert_nors[ed->v1], edge_normal); add_v3_v3(r_vert_nors[ed->v2], edge_normal); } } MEM_freeN(edge_ref_array); } /* normalize vertex normals and assign */ for (i = 0; i < numVerts; i++, mv++) { if (normalize_v3(r_vert_nors[i]) == 0.0f) { normal_short_to_float_v3(r_vert_nors[i], mv->no); } } }
PyObject* BL_ArmatureChannel::py_attr_get_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef) { bPoseChannel* pchan = static_cast<bPoseChannel*>(self_v); // decompose the pose matrix in euler rotation float rest_mat[3][3]; float pose_mat[3][3]; float joint_mat[3][3]; float joints[3]; float norm; double sa, ca; // get rotation in armature space copy_m3_m4(pose_mat, pchan->pose_mat); normalize_m3(pose_mat); if (pchan->parent) { // bone has a parent, compute the rest pose of the bone taking actual pose of parent mul_m3_m3m4(rest_mat, pchan->bone->bone_mat, pchan->parent->pose_mat); normalize_m3(rest_mat); } else { // otherwise, the bone matrix in armature space is the rest pose copy_m3_m4(rest_mat, pchan->bone->arm_mat); } // remove the rest pose to get the joint movement transpose_m3(rest_mat); mul_m3_m3m3(joint_mat, rest_mat, pose_mat); joints[0] = joints[1] = joints[2] = 0.f; // returns a 3 element list that gives corresponding joint int flag = 0; if (!(pchan->ikflag & BONE_IK_NO_XDOF)) flag |= 1; if (!(pchan->ikflag & BONE_IK_NO_YDOF)) flag |= 2; if (!(pchan->ikflag & BONE_IK_NO_ZDOF)) flag |= 4; switch (flag) { case 0: // fixed joint break; case 1: // X only mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat); joints[1] = joints[2] = 0.f; break; case 2: // Y only mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat); joints[0] = joints[2] = 0.f; break; case 3: // X+Y mat3_to_eulO( joints, EULER_ORDER_ZYX,joint_mat); joints[2] = 0.f; break; case 4: // Z only mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat); joints[0] = joints[1] = 0.f; break; case 5: // X+Z // decompose this as an equivalent rotation vector in X/Z plane joints[0] = joint_mat[1][2]; joints[2] = -joint_mat[1][0]; norm = normalize_v3(joints); if (norm < FLT_EPSILON) { norm = (joint_mat[1][1] < 0.f) ? M_PI : 0.f; } else { norm = acos(joint_mat[1][1]); } mul_v3_fl(joints, norm); break; case 6: // Y+Z mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat); joints[0] = 0.f; break; case 7: // X+Y+Z // equivalent axis joints[0] = (joint_mat[1][2]-joint_mat[2][1])*0.5f; joints[1] = (joint_mat[2][0]-joint_mat[0][2])*0.5f; joints[2] = (joint_mat[0][1]-joint_mat[1][0])*0.5f; sa = len_v3(joints); ca = (joint_mat[0][0]+joint_mat[1][1]+joint_mat[1][1]-1.0f)*0.5f; if (sa > FLT_EPSILON) { norm = atan2(sa,ca)/sa; } else { if (ca < 0.0) { norm = M_PI; mul_v3_fl(joints,0.f); if (joint_mat[0][0] > 0.f) { joints[0] = 1.0f; } else if (joint_mat[1][1] > 0.f) { joints[1] = 1.0f; } else { joints[2] = 1.0f; } } else { norm = 0.0; } } mul_v3_fl(joints,norm); break; } return newVectorObject(joints, 3, Py_NEW, NULL); }
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]; 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_deform_data = psys_create_lattice_deform_data(&sim); if (psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) { float min[3], max[3]; INIT_MINMAX(min, max); dm->getMinMax(dm, min, max); min_co = min[track]; max_co = max[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++) { float prev_dir[3]; float frame[4]; /* frame orientation quaternion */ /* 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); /* Incrementally Rotating Frame (Bishop Frame) */ if (k == 0) { float hairmat[4][4]; float mat[3][3]; if (first_particle + p < psys->totpart) pa = psys->particles + first_particle + p; else { ChildParticle *cpa = psys->child + (p - psys->totpart); pa = psys->particles + cpa->parent; } psys_mat_hair_to_global(sim.ob, sim.psmd->dm, sim.psys->part->from, pa, hairmat); copy_m3_m4(mat, hairmat); /* to quaternion */ mat3_to_quat(frame, mat); /* note: direction is same as normal vector currently, * but best to keep this separate so the frame can be * rotated later if necessary */ copy_v3_v3(prev_dir, state.vel); } else { float rot[4]; /* incrementally rotate along bend direction */ rotation_between_vecs_to_quat(rot, prev_dir, state.vel); mul_qt_qtqt(frame, rot, frame); copy_v3_v3(prev_dir, state.vel); } copy_qt_qt(state.rot, frame); #if 0 /* Absolute Frame (Frenet Frame) */ if (state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) { unit_qt(state.rot); } else { float cross[3]; 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])); } #endif } 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_deform_data) { end_latt_deform(psys->lattice_deform_data); psys->lattice_deform_data = NULL; } if (size) MEM_freeN(size); result->dirty |= DM_DIRTY_NORMALS; return result; }
static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float UNUSED(framenr), int first) { int i = 0; MVert *mvert = NULL; ClothVertex *verts = NULL; float (*shapekey_rest)[3] = NULL; float tnull[3] = {0, 0, 0}; Cloth *cloth = NULL; float maxdist = 0; // If we have a clothObject, free it. if ( clmd->clothObject != NULL ) { cloth_free_modifier ( clmd ); if (G.debug_value > 0) printf("cloth_free_modifier cloth_from_object\n"); } // Allocate a new cloth object. clmd->clothObject = MEM_callocN ( sizeof ( Cloth ), "cloth" ); if ( clmd->clothObject ) { clmd->clothObject->old_solver_type = 255; // clmd->clothObject->old_collision_type = 255; cloth = clmd->clothObject; clmd->clothObject->edgeset = NULL; } else if (!clmd->clothObject) { modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject"); return 0; } // mesh input objects need DerivedMesh if ( !dm ) return 0; cloth_from_mesh ( clmd, dm ); // create springs clmd->clothObject->springs = NULL; clmd->clothObject->numsprings = -1; if ( clmd->sim_parms->shapekey_rest ) shapekey_rest = dm->getVertDataArray ( dm, CD_CLOTH_ORCO ); mvert = dm->getVertArray (dm); verts = clmd->clothObject->verts; // set initial values for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) { if (first) { copy_v3_v3(verts->x, mvert[i].co); mul_m4_v3(ob->obmat, verts->x); if ( shapekey_rest ) { verts->xrest= shapekey_rest[i]; mul_m4_v3(ob->obmat, verts->xrest); } else verts->xrest = verts->x; } /* no GUI interface yet */ verts->mass = clmd->sim_parms->mass; verts->impulse_count = 0; if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) verts->goal= clmd->sim_parms->defgoal; else verts->goal= 0.0f; verts->flags = 0; copy_v3_v3 ( verts->xold, verts->x ); copy_v3_v3 ( verts->xconst, verts->x ); copy_v3_v3 ( verts->txold, verts->x ); copy_v3_v3 ( verts->tx, verts->x ); mul_v3_fl(verts->v, 0.0f); verts->impulse_count = 0; copy_v3_v3 ( verts->impulse, tnull ); } // apply / set vertex groups // has to be happen before springs are build! cloth_apply_vgroup (clmd, dm); if ( !cloth_build_springs ( clmd, dm ) ) { cloth_free_modifier ( clmd ); modifier_setError(&(clmd->modifier), "Cannot build springs"); printf("cloth_free_modifier cloth_build_springs\n"); return 0; } for ( i = 0; i < dm->getNumVerts(dm); i++) { if ((!(cloth->verts[i].flags & CLOTH_VERT_FLAG_PINNED)) && (cloth->verts[i].goal > ALMOST_ZERO)) { cloth_add_spring (clmd, i, i, 0.0, CLOTH_SPRING_TYPE_GOAL); } } // init our solver if ( solvers [clmd->sim_parms->solver_type].init ) { solvers [clmd->sim_parms->solver_type].init ( ob, clmd ); } if (!first) implicit_set_positions(clmd); clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel) ); for (i = 0; i < dm->getNumVerts(dm); i++) { maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0f)); } clmd->clothObject->bvhselftree = bvhselftree_build_from_cloth ( clmd, maxdist ); return 1; }
int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int real_velocity) { float cfra = eff->scene->r.cfra; int ret = 0; if (eff->pd && eff->pd->shape==PFIELD_SHAPE_SURFACE && eff->surmd) { /* closest point in the object surface is an effector */ float vec[3]; /* using velocity corrected location allows for easier sliding over effector surface */ copy_v3_v3(vec, point->vel); mul_v3_fl(vec, point->vel_to_frame); add_v3_v3(vec, point->loc); ret = closest_point_on_surface(eff->surmd, vec, efd->loc, efd->nor, real_velocity ? efd->vel : NULL); efd->size = 0.0f; } else if (eff->pd && eff->pd->shape==PFIELD_SHAPE_POINTS) { if (eff->ob->derivedFinal) { DerivedMesh *dm = eff->ob->derivedFinal; dm->getVertCo(dm, *efd->index, efd->loc); dm->getVertNo(dm, *efd->index, efd->nor); mul_m4_v3(eff->ob->obmat, efd->loc); mul_mat3_m4_v3(eff->ob->obmat, efd->nor); normalize_v3(efd->nor); efd->size = 0.0f; /**/ ret = 1; } } else if (eff->psys) { ParticleData *pa = eff->psys->particles + *efd->index; ParticleKey state; /* exclude the particle itself for self effecting particles */ if (eff->psys == point->psys && *efd->index == point->index) { /* pass */ } else { ParticleSimulationData sim= {NULL}; sim.scene= eff->scene; sim.ob= eff->ob; sim.psys= eff->psys; /* TODO: time from actual previous calculated frame (step might not be 1) */ state.time = cfra - 1.0f; ret = psys_get_particle_state(&sim, *efd->index, &state, 0); /* TODO */ //if (eff->pd->forcefiled == PFIELD_HARMONIC && ret==0) { // if (pa->dietime < eff->psys->cfra) // eff->flag |= PE_VELOCITY_TO_IMPULSE; //} copy_v3_v3(efd->loc, state.co); /* rather than use the velocity use rotated x-axis (defaults to velocity) */ efd->nor[0] = 1.f; efd->nor[1] = efd->nor[2] = 0.f; mul_qt_v3(state.rot, efd->nor); if (real_velocity) copy_v3_v3(efd->vel, state.vel); efd->size = pa->size; } } else { /* use center of object for distance calculus */ Object *ob = eff->ob; Object obcopy = *ob; /* use z-axis as normal*/ normalize_v3_v3(efd->nor, ob->obmat[2]); if (eff->pd && eff->pd->shape == PFIELD_SHAPE_PLANE) { float temp[3], translate[3]; sub_v3_v3v3(temp, point->loc, ob->obmat[3]); project_v3_v3v3(translate, temp, efd->nor); /* for vortex the shape chooses between old / new force */ if (eff->pd->forcefield == PFIELD_VORTEX) add_v3_v3v3(efd->loc, ob->obmat[3], translate); else /* normally efd->loc is closest point on effector xy-plane */ sub_v3_v3v3(efd->loc, point->loc, translate); } else { copy_v3_v3(efd->loc, ob->obmat[3]); } if (real_velocity) copy_v3_v3(efd->vel, eff->velocity); *eff->ob = obcopy; efd->size = 0.0f; ret = 1; } if (ret) { sub_v3_v3v3(efd->vec_to_point, point->loc, efd->loc); efd->distance = len_v3(efd->vec_to_point); /* rest length for harmonic effector, will have to see later if this could be extended to other effectors */ if (eff->pd && eff->pd->forcefield == PFIELD_HARMONIC && eff->pd->f_size) mul_v3_fl(efd->vec_to_point, (efd->distance-eff->pd->f_size)/efd->distance); if (eff->flag & PE_USE_NORMAL_DATA) { copy_v3_v3(efd->vec_to_point2, efd->vec_to_point); copy_v3_v3(efd->nor2, efd->nor); } else { /* for some effectors we need the object center every time */ sub_v3_v3v3(efd->vec_to_point2, point->loc, eff->ob->obmat[3]); normalize_v3_v3(efd->nor2, eff->ob->obmat[2]); } } return ret; }
static int walkApply(bContext *C, WalkInfo *walk) { #define WALK_ROTATE_FAC 2.2f /* more is faster */ #define WALK_TOP_LIMIT DEG2RADF(85.0f) #define WALK_BOTTOM_LIMIT DEG2RADF(-80.0f) #define WALK_MOVE_SPEED base_speed #define WALK_BOOST_FACTOR ((void)0, walk->speed_factor) /* walk mode - Ctrl+Shift+F * a walk loop where the user can move move the view as if they are in a walk game */ RegionView3D *rv3d = walk->rv3d; ARegion *ar = walk->ar; float mat[3][3]; /* 3x3 copy of the view matrix so we can move along the view axis */ float dvec[3] = {0.0f, 0.0f, 0.0f}; /* this is the direction that's added to the view offset per redraw */ /* Camera Uprighting variables */ float upvec[3] = {0.0f, 0.0f, 0.0f}; /* stores the view's up vector */ int moffset[2]; /* mouse offset from the views center */ float tmp_quat[4]; /* used for rotating the view */ #ifdef NDOF_WALK_DEBUG { static unsigned int iteration = 1; printf("walk timer %d\n", iteration++); } #endif { /* mouse offset from the center */ copy_v2_v2_int(moffset, walk->moffset); /* apply moffset so we can re-accumulate */ walk->moffset[0] = 0; walk->moffset[1] = 0; /* revert mouse */ if (walk->is_reversed) { moffset[1] = -moffset[1]; } /* Should we redraw? */ if ((walk->active_directions) || moffset[0] || moffset[1] || walk->teleport.state == WALK_TELEPORT_STATE_ON || walk->gravity_state != WALK_GRAVITY_STATE_OFF) { float dvec_tmp[3]; /* time how fast it takes for us to redraw, * this is so simple scenes don't walk too fast */ double time_current; float time_redraw; #ifdef NDOF_WALK_DRAW_TOOMUCH walk->redraw = 1; #endif time_current = PIL_check_seconds_timer(); time_redraw = (float)(time_current - walk->time_lastdraw); walk->time_lastdraw = time_current; /* base speed in m/s */ walk->speed = WALK_MOVE_SPEED; if (walk->is_fast) { walk->speed *= WALK_BOOST_FACTOR; } else if (walk->is_slow) { walk->speed *= 1.0f / WALK_BOOST_FACTOR; } copy_m3_m4(mat, rv3d->viewinv); { /* rotate about the X axis- look up/down */ if (moffset[1]) { float angle; float y; /* relative offset */ y = (float) moffset[1] / ar->winy; /* speed factor */ y *= WALK_ROTATE_FAC; /* user adjustement factor */ y *= walk->mouse_speed; /* clamp the angle limits */ /* it ranges from 90.0f to -90.0f */ angle = -asinf(rv3d->viewmat[2][2]); if (angle > WALK_TOP_LIMIT && y > 0.0f) y = 0.0f; else if (angle < WALK_BOTTOM_LIMIT && y < 0.0f) y = 0.0f; copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f); mul_m3_v3(mat, upvec); /* Rotate about the relative up vec */ axis_angle_to_quat(tmp_quat, upvec, -y); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); } /* rotate about the Y axis- look left/right */ if (moffset[0]) { float x; /* if we're upside down invert the moffset */ copy_v3_fl3(upvec, 0.0f, 1.0f, 0.0f); mul_m3_v3(mat, upvec); if (upvec[2] < 0.0f) moffset[0] = -moffset[0]; /* relative offset */ x = (float) moffset[0] / ar->winx; /* speed factor */ x *= WALK_ROTATE_FAC; /* user adjustement factor */ x *= walk->mouse_speed; copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f); /* Rotate about the relative up vec */ axis_angle_normalized_to_quat(tmp_quat, upvec, x); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); } } /* WASD - 'move' translation code */ if ((walk->active_directions) && (walk->gravity_state == WALK_GRAVITY_STATE_OFF)) { short direction; zero_v3(dvec); if ((walk->active_directions & WALK_BIT_FORWARD) || (walk->active_directions & WALK_BIT_BACKWARD)) { direction = 0; if ((walk->active_directions & WALK_BIT_FORWARD)) direction += 1; if ((walk->active_directions & WALK_BIT_BACKWARD)) direction -= 1; copy_v3_fl3(dvec_tmp, 0.0f, 0.0f, direction); mul_m3_v3(mat, dvec_tmp); if (walk->navigation_mode == WALK_MODE_GRAVITY) { dvec_tmp[2] = 0.0f; } normalize_v3(dvec_tmp); add_v3_v3(dvec, dvec_tmp); } if ((walk->active_directions & WALK_BIT_LEFT) || (walk->active_directions & WALK_BIT_RIGHT)) { direction = 0; if ((walk->active_directions & WALK_BIT_LEFT)) direction += 1; if ((walk->active_directions & WALK_BIT_RIGHT)) direction -= 1; dvec_tmp[0] = direction * rv3d->viewinv[0][0]; dvec_tmp[1] = direction * rv3d->viewinv[0][1]; dvec_tmp[2] = 0.0f; normalize_v3(dvec_tmp); add_v3_v3(dvec, dvec_tmp); } if ((walk->active_directions & WALK_BIT_UP) || (walk->active_directions & WALK_BIT_DOWN)) { if (walk->navigation_mode == WALK_MODE_FREE) { direction = 0; if ((walk->active_directions & WALK_BIT_UP)) direction -= 1; if ((walk->active_directions & WALK_BIT_DOWN)) direction = 1; copy_v3_fl3(dvec_tmp, 0.0f, 0.0f, direction); add_v3_v3(dvec, dvec_tmp); } } /* apply movement */ mul_v3_fl(dvec, walk->speed * time_redraw); } /* stick to the floor */ if (walk->navigation_mode == WALK_MODE_GRAVITY && ELEM(walk->gravity_state, WALK_GRAVITY_STATE_OFF, WALK_GRAVITY_STATE_START)) { bool ret; float ray_distance; float difference = -100.0f; float fall_distance; ret = walk_floor_distance_get(C, rv3d, walk, dvec, &ray_distance); if (ret) { difference = walk->view_height - ray_distance; } /* the distance we would fall naturally smoothly enough that we * can manually drop the object without activating gravity */ fall_distance = time_redraw * walk->speed * WALK_BOOST_FACTOR; if (fabsf(difference) < fall_distance) { /* slope/stairs */ dvec[2] -= difference; /* in case we switched from FREE to GRAVITY too close to the ground */ if (walk->gravity_state == WALK_GRAVITY_STATE_START) walk->gravity_state = WALK_GRAVITY_STATE_OFF; } else { /* hijack the teleport variables */ walk->teleport.initial_time = PIL_check_seconds_timer(); walk->gravity_state = WALK_GRAVITY_STATE_ON; walk->teleport.duration = 0.0f; copy_v3_v3(walk->teleport.origin, walk->rv3d->viewinv[3]); copy_v2_v2(walk->teleport.direction, dvec); } } /* Falling or jumping) */ if (ELEM(walk->gravity_state, WALK_GRAVITY_STATE_ON, WALK_GRAVITY_STATE_JUMP)) { float t; float z_cur, z_new; bool ret; float ray_distance, difference = -100.0f; /* delta time */ t = (float)(PIL_check_seconds_timer() - walk->teleport.initial_time); /* keep moving if we were moving */ copy_v2_v2(dvec, walk->teleport.direction); z_cur = walk->rv3d->viewinv[3][2]; z_new = walk->teleport.origin[2] - getFreeFallDistance(walk->gravity, t) * walk->grid; /* jump */ z_new += t * walk->speed_jump * walk->grid; /* duration is the jump duration */ if (t > walk->teleport.duration) { /* check to see if we are landing */ ret = walk_floor_distance_get(C, rv3d, walk, dvec, &ray_distance); if (ret) { difference = walk->view_height - ray_distance; } if (difference > 0.0f) { /* quit falling, lands at "view_height" from the floor */ dvec[2] -= difference; walk->gravity_state = WALK_GRAVITY_STATE_OFF; walk->speed_jump = 0.0f; } else { /* keep falling */ dvec[2] = z_cur - z_new; } } else { /* keep going up (jump) */ dvec[2] = z_cur - z_new; } } /* Teleport */ else if (walk->teleport.state == WALK_TELEPORT_STATE_ON) { float t; /* factor */ float new_loc[3]; float cur_loc[3]; /* linear interpolation */ t = (float)(PIL_check_seconds_timer() - walk->teleport.initial_time); t /= walk->teleport.duration; /* clamp so we don't go past our limit */ if (t >= 1.0f) { t = 1.0f; walk->teleport.state = WALK_TELEPORT_STATE_OFF; walk_navigation_mode_set(C, walk, walk->teleport.navigation_mode); } mul_v3_v3fl(new_loc, walk->teleport.direction, t); add_v3_v3(new_loc, walk->teleport.origin); copy_v3_v3(cur_loc, walk->rv3d->viewinv[3]); sub_v3_v3v3(dvec, cur_loc, new_loc); } if (rv3d->persp == RV3D_CAMOB) { Object *lock_ob = ED_view3d_cameracontrol_object_get(walk->v3d_camera_control); if (lock_ob->protectflag & OB_LOCK_LOCX) dvec[0] = 0.0f; if (lock_ob->protectflag & OB_LOCK_LOCY) dvec[1] = 0.0f; if (lock_ob->protectflag & OB_LOCK_LOCZ) dvec[2] = 0.0f; } /* scale the movement to the scene size */ mul_v3_v3fl(dvec_tmp, dvec, walk->grid); add_v3_v3(rv3d->ofs, dvec_tmp); if (rv3d->persp == RV3D_CAMOB) { const bool do_rotate = (moffset[0] || moffset[1]); const bool do_translate = (walk->speed != 0.0f); walkMoveCamera(C, walk, do_rotate, do_translate); } } else { /* we're not redrawing but we need to update the time else the view will jump */ walk->time_lastdraw = PIL_check_seconds_timer(); } /* end drawing */ copy_v3_v3(walk->dvec_prev, dvec); } return OPERATOR_FINISHED; #undef WALK_ROTATE_FAC #undef WALK_ZUP_CORRECT_FAC #undef WALK_ZUP_CORRECT_ACCEL #undef WALK_SMOOTH_FAC #undef WALK_TOP_LIMIT #undef WALK_BOTTOM_LIMIT #undef WALK_MOVE_SPEED #undef WALK_BOOST_FACTOR }
static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) { Object *obedit = CTX_data_edit_object(C); Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); TransVertStore tvs = {NULL}; TransVert *tv; float bmat[3][3], vec[3], min[3], max[3], centroid[3]; int count, a; count = 0; INIT_MINMAX(min, max); zero_v3(centroid); if (obedit) { if (ED_transverts_check_obedit(obedit)) ED_transverts_create_from_obedit(&tvs, obedit, TM_ALL_JOINTS | TM_SKIP_HANDLES); if (tvs.transverts_tot == 0) { return false; } copy_m3_m4(bmat, obedit->obmat); tv = tvs.transverts; for (a = 0; a < tvs.transverts_tot; a++, tv++) { copy_v3_v3(vec, tv->loc); mul_m3_v3(bmat, vec); add_v3_v3(vec, obedit->obmat[3]); add_v3_v3(centroid, vec); minmax_v3v3_v3(min, max, vec); } if (v3d->around == V3D_CENTROID) { mul_v3_fl(centroid, 1.0f / (float)tvs.transverts_tot); copy_v3_v3(cursor, centroid); } else { mid_v3_v3v3(cursor, min, max); } ED_transverts_free(&tvs); } else { Object *obact = CTX_data_active_object(C); if (obact && (obact->mode & OB_MODE_POSE)) { bArmature *arm = obact->data; bPoseChannel *pchan; for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) { if (arm->layer & pchan->bone->layer) { if (pchan->bone->flag & BONE_SELECTED) { copy_v3_v3(vec, pchan->pose_head); mul_m4_v3(obact->obmat, vec); add_v3_v3(centroid, vec); minmax_v3v3_v3(min, max, vec); count++; } } } } else { CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { copy_v3_v3(vec, ob->obmat[3]); /* special case for camera -- snap to bundles */ if (ob->type == OB_CAMERA) { /* snap to bundles should happen only when bundles are visible */ if (v3d->flag2 & V3D_SHOW_RECONSTRUCTION) { bundle_midpoint(scene, ob, vec); } } add_v3_v3(centroid, vec); minmax_v3v3_v3(min, max, vec); count++; } CTX_DATA_END; } if (count == 0) { return false; } if (v3d->around == V3D_CENTROID) { mul_v3_fl(centroid, 1.0f / (float)count); copy_v3_v3(cursor, centroid); } else { mid_v3_v3v3(cursor, min, max); } }
void applyGridAbsolute(TransInfo *t) { float grid_size = 0.0f; GearsType grid_action; TransData *td; float (*obmat)[4] = NULL; bool use_obmat = false; int i; if (!(activeSnap(t) && (ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID)))) return; grid_action = BIG_GEARS; if (t->modifiers & MOD_PRECISION) grid_action = SMALL_GEARS; switch (grid_action) { case NO_GEARS: grid_size = t->snap_spatial[0]; break; case BIG_GEARS: grid_size = t->snap_spatial[1]; break; case SMALL_GEARS: grid_size = t->snap_spatial[2]; break; } /* early exit on unusable grid size */ if (grid_size == 0.0f) return; if (t->flag & (T_EDIT | T_POSE)) { Object *ob = t->obedit ? t->obedit : t->poseobj; obmat = ob->obmat; use_obmat = true; } for (i = 0, td = t->data; i < t->total; i++, td++) { float iloc[3], loc[3], tvec[3]; if (td->flag & TD_NOACTION) break; if (td->flag & TD_SKIP) continue; if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) continue; copy_v3_v3(iloc, td->loc); if (use_obmat) { mul_m4_v3(obmat, iloc); } else if (t->flag & T_OBJECT) { td->ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME; BKE_object_handle_update(G.main->eval_ctx, t->scene, td->ob); copy_v3_v3(iloc, td->ob->obmat[3]); } mul_v3_v3fl(loc, iloc, 1.0f / grid_size); loc[0] = roundf(loc[0]); loc[1] = roundf(loc[1]); loc[2] = roundf(loc[2]); mul_v3_fl(loc, grid_size); sub_v3_v3v3(tvec, loc, iloc); mul_m3_v3(td->smtx, tvec); add_v3_v3(td->loc, tvec); } }
int nextLengthSubdivision(ToolSettings *toolsettings, BArcIterator *iter, int start, int end, float head[3], float p[3]) { float lengthLimit = toolsettings->skgen_length_limit; int same = 1; int i; i = start + 1; while (i <= end) { float *vec0; float *vec1; IT_peek(iter, i - 1); vec0 = iter->p; IT_peek(iter, i); vec1 = iter->p; /* If lengthLimit hits the current segment */ if (len_v3v3(vec1, head) > lengthLimit) { if (same == 0) { float dv[3], off[3]; float a, b, c, f; /* Solve quadratic distance equation */ sub_v3_v3v3(dv, vec1, vec0); a = dot_v3v3(dv, dv); sub_v3_v3v3(off, vec0, head); b = 2 * dot_v3v3(dv, off); c = dot_v3v3(off, off) - (lengthLimit * lengthLimit); f = (-b + (float)sqrt(b * b - 4 * a * c)) / (2 * a); //printf("a %f, b %f, c %f, f %f\n", a, b, c, f); if (isnan(f) == 0 && f < 1.0f) { copy_v3_v3(p, dv); mul_v3_fl(p, f); add_v3_v3(p, vec0); } else { copy_v3_v3(p, vec1); } } else { float dv[3]; sub_v3_v3v3(dv, vec1, vec0); normalize_v3(dv); copy_v3_v3(p, dv); mul_v3_fl(p, lengthLimit); add_v3_v3(p, head); } return i - 1; /* restart at lower bound */ } else { i++; same = 0; // Reset same } } return -1; }
/* * Function adapted from David Eberly's distance tools (LGPL) * http://www.geometrictools.com/LibFoundation/Distance/Distance.html */ float nearest_point_in_tri_surface_squared( const float v0[3], const float v1[3], const float v2[3], const float p[3], int *v, int *e, float nearest[3]) { float diff[3]; float e0[3]; float e1[3]; float A00; float A01; float A11; float B0; float B1; float C; float Det; float S; float T; float sqrDist; int lv = -1, le = -1; sub_v3_v3v3(diff, v0, p); sub_v3_v3v3(e0, v1, v0); sub_v3_v3v3(e1, v2, v0); A00 = dot_v3v3(e0, e0); A01 = dot_v3v3(e0, e1); A11 = dot_v3v3(e1, e1); B0 = dot_v3v3(diff, e0); B1 = dot_v3v3(diff, e1); C = dot_v3v3(diff, diff); Det = fabsf(A00 * A11 - A01 * A01); S = A01 * B1 - A11 * B0; T = A01 * B0 - A00 * B1; if (S + T <= Det) { if (S < 0.0f) { if (T < 0.0f) { /* Region 4 */ if (B0 < 0.0f) { T = 0.0f; if (-B0 >= A00) { S = 1.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if (fabsf(A00) > FLT_EPSILON) S = -B0 / A00; else S = 0.0f; sqrDist = B0 * S + C; le = 0; } } else { S = 0.0f; if (B1 >= 0.0f) { T = 0.0f; sqrDist = C; lv = 0; } else if (-B1 >= A11) { T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { if (fabsf(A11) > FLT_EPSILON) T = -B1 / A11; else T = 0.0f; sqrDist = B1 * T + C; le = 1; } } } else { /* Region 3 */ S = 0.0f; if (B1 >= 0.0f) { T = 0.0f; sqrDist = C; lv = 0; } else if (-B1 >= A11) { T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { if (fabsf(A11) > FLT_EPSILON) T = -B1 / A11; else T = 0.0; sqrDist = B1 * T + C; le = 1; } } } else if (T < 0.0f) { /* Region 5 */ T = 0.0f; if (B0 >= 0.0f) { S = 0.0f; sqrDist = C; lv = 0; } else if (-B0 >= A00) { S = 1.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if (fabsf(A00) > FLT_EPSILON) S = -B0 / A00; else S = 0.0f; sqrDist = B0 * S + C; le = 0; } } else { /* Region 0 */ /* Minimum at interior lv */ float invDet; if (fabsf(Det) > FLT_EPSILON) invDet = 1.0f / Det; else invDet = 0.0f; S *= invDet; T *= invDet; sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) + T * (A01 * S + A11 * T + 2.0f * B1) + C; } } else { float tmp0, tmp1, numer, denom; if (S < 0.0f) { /* Region 2 */ tmp0 = A01 + B0; tmp1 = A11 + B1; if (tmp1 > tmp0) { numer = tmp1 - tmp0; denom = A00 - 2.0f * A01 + A11; if (numer >= denom) { S = 1.0f; T = 0.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if (fabsf(denom) > FLT_EPSILON) S = numer / denom; else S = 0.0f; T = 1.0f - S; sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) + T * (A01 * S + A11 * T + 2.0f * B1) + C; le = 2; } } else { S = 0.0f; if (tmp1 <= 0.0f) { T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else if (B1 >= 0.0f) { T = 0.0f; sqrDist = C; lv = 0; } else { if (fabsf(A11) > FLT_EPSILON) T = -B1 / A11; else T = 0.0f; sqrDist = B1 * T + C; le = 1; } } } else if (T < 0.0f) { /* Region 6 */ tmp0 = A01 + B1; tmp1 = A00 + B0; if (tmp1 > tmp0) { numer = tmp1 - tmp0; denom = A00 - 2.0f * A01 + A11; if (numer >= denom) { T = 1.0f; S = 0.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { if (fabsf(denom) > FLT_EPSILON) T = numer / denom; else T = 0.0f; S = 1.0f - T; sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) + T * (A01 * S + A11 * T + 2.0f * B1) + C; le = 2; } } else { T = 0.0f; if (tmp1 <= 0.0f) { S = 1.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else if (B0 >= 0.0f) { S = 0.0f; sqrDist = C; lv = 0; } else { if (fabsf(A00) > FLT_EPSILON) S = -B0 / A00; else S = 0.0f; sqrDist = B0 * S + C; le = 0; } } } else { /* Region 1 */ numer = A11 + B1 - A01 - B0; if (numer <= 0.0f) { S = 0.0f; T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { denom = A00 - 2.0f * A01 + A11; if (numer >= denom) { S = 1.0f; T = 0.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if (fabsf(denom) > FLT_EPSILON) S = numer / denom; else S = 0.0f; T = 1.0f - S; sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) + T * (A01 * S + A11 * T + 2.0f * B1) + C; le = 2; } } } } /* Account for numerical round-off error */ if (sqrDist < FLT_EPSILON) sqrDist = 0.0f; { float w[3], x[3], y[3], z[3]; copy_v3_v3(w, v0); copy_v3_v3(x, e0); mul_v3_fl(x, S); copy_v3_v3(y, e1); mul_v3_fl(y, T); add_v3_v3v3(z, w, x); add_v3_v3v3(z, z, y); //sub_v3_v3v3(d, p, z); copy_v3_v3(nearest, z); //d = p - ( v0 + S * e0 + T * e1 ); } *v = lv; *e = le; return sqrDist; }
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, *pars = NULL; MFace *mface, *orig_mface; MVert *mvert, *orig_mvert; int i, totvert, totpart = 0, totface, maxvert, maxface, first_particle = 0; 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; DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */ 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) { int p; 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); } } } pars = psys->particles; totvert = dm->getNumVerts(dm); totface = dm->getNumTessFaces(dm); maxvert = totvert * totpart; maxface = totface * totpart; 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, dm->getNumEdges(dm) * totpart, maxface, 0, 0); mvert = result->getVertArray(result); orig_mvert = dm->getVertArray(dm); for (i = 0; i < maxvert; i++) { MVert *inMV; MVert *mv = mvert + i; ParticleKey state; inMV = orig_mvert + i % totvert; DM_copy_vert_data(dm, result, i % totvert, i, 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]; 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) { BLI_srandom(psys->seed + (i / totvert) % totpart); ran = pimd->random_position * BLI_frand(); } 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 + i / totvert, &state, 1); normalize_v3(state.vel); /* TODO: incremental rotations somehow */ if (state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) { state.rot[0] = 1; state.rot[1] = state.rot[2] = state.rot[3] = 0.0f; } 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 + i / totvert, &state, 1); } mul_qt_v3(state.rot, mv->co); if (pimd->flag & eParticleInstanceFlag_UseSize) mul_v3_fl(mv->co, size[i / totvert]); add_v3_v3(mv->co, state.co); } mface = result->getTessFaceArray(result); orig_mface = dm->getTessFaceArray(dm); for (i = 0; i < maxface; i++) { MFace *inMF; MFace *mf = mface + i; if (pimd->flag & eParticleInstanceFlag_Parents) { if (i / totface >= psys->totpart) { if (psys->part->childtype == PART_CHILD_PARTICLES) { pa = psys->particles + (psys->child + i / totface - psys->totpart)->parent; } else { pa = NULL; } } else { pa = pars + i / totface; } } else { if (psys->part->childtype == PART_CHILD_PARTICLES) { pa = psys->particles + (psys->child + i / totface)->parent; } else { pa = NULL; } } if (pa) { if (pa->alive == PARS_UNBORN && (pimd->flag & eParticleInstanceFlag_Unborn) == 0) continue; if (pa->alive == PARS_ALIVE && (pimd->flag & eParticleInstanceFlag_Alive) == 0) continue; if (pa->alive == PARS_DEAD && (pimd->flag & eParticleInstanceFlag_Dead) == 0) continue; } inMF = orig_mface + i % totface; DM_copy_poly_data(dm, result, i % totface, i, 1); *mf = *inMF; mf->v1 += (i / totface) * totvert; mf->v2 += (i / totface) * totvert; mf->v3 += (i / totface) * totvert; if (mf->v4) { mf->v4 += (i / totface) * totvert; } } CDDM_calc_edges_tessface(result); if (psys->lattice) { end_latt_deform(psys->lattice); psys->lattice = NULL; } if (size) MEM_freeN(size); CDDM_tessfaces_to_faces(result); /*builds ngon faces from tess (mface) faces*/ CDDM_calc_normals(result); return result; }
static void createFacepa(ExplodeModifierData *emd, ParticleSystemModifierData *psmd, DerivedMesh *dm) { ParticleSystem *psys = psmd->psys; MFace *fa = NULL, *mface = NULL; MVert *mvert = NULL; ParticleData *pa; KDTree *tree; RNG *rng; float center[3], co[3]; int *facepa = NULL, *vertpa = NULL, totvert = 0, totface = 0, totpart = 0; int i, p, v1, v2, v3, v4 = 0; mvert = dm->getVertArray(dm); mface = dm->getTessFaceArray(dm); totface = dm->getNumTessFaces(dm); totvert = dm->getNumVerts(dm); totpart = psmd->psys->totpart; rng = BLI_rng_new_srandom(psys->seed); if (emd->facepa) MEM_freeN(emd->facepa); facepa = emd->facepa = MEM_callocN(sizeof(int) * totface, "explode_facepa"); vertpa = MEM_callocN(sizeof(int) * totvert, "explode_vertpa"); /* initialize all faces & verts to no particle */ for (i = 0; i < totface; i++) facepa[i] = totpart; for (i = 0; i < totvert; i++) vertpa[i] = totpart; /* set protected verts */ if (emd->vgroup) { MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); if (dvert) { const int defgrp_index = emd->vgroup - 1; for (i = 0; i < totvert; i++, dvert++) { float val = BLI_rng_get_float(rng); val = (1.0f - emd->protect) * val + emd->protect * 0.5f; if (val < defvert_find_weight(dvert, defgrp_index)) vertpa[i] = -1; } } } /* make tree of emitter locations */ tree = BLI_kdtree_new(totpart); for (p = 0, pa = psys->particles; p < totpart; p++, pa++) { psys_particle_on_emitter(psmd, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, NULL, NULL, NULL, NULL, NULL); BLI_kdtree_insert(tree, p, co); } BLI_kdtree_balance(tree); /* set face-particle-indexes to nearest particle to face center */ for (i = 0, fa = mface; i < totface; i++, fa++) { add_v3_v3v3(center, mvert[fa->v1].co, mvert[fa->v2].co); add_v3_v3(center, mvert[fa->v3].co); if (fa->v4) { add_v3_v3(center, mvert[fa->v4].co); mul_v3_fl(center, 0.25); } else mul_v3_fl(center, 1.0f / 3.0f); p = BLI_kdtree_find_nearest(tree, center, NULL); v1 = vertpa[fa->v1]; v2 = vertpa[fa->v2]; v3 = vertpa[fa->v3]; if (fa->v4) v4 = vertpa[fa->v4]; if (v1 >= 0 && v2 >= 0 && v3 >= 0 && (fa->v4 == 0 || v4 >= 0)) facepa[i] = p; if (v1 >= 0) vertpa[fa->v1] = p; if (v2 >= 0) vertpa[fa->v2] = p; if (v3 >= 0) vertpa[fa->v3] = p; if (fa->v4 && v4 >= 0) vertpa[fa->v4] = p; } if (vertpa) MEM_freeN(vertpa); BLI_kdtree_free(tree); BLI_rng_free(rng); }
static DerivedMesh *explodeMesh(ExplodeModifierData *emd, ParticleSystemModifierData *psmd, Scene *scene, Object *ob, DerivedMesh *to_explode) { DerivedMesh *explode, *dm = to_explode; MFace *mf = NULL, *mface; /* ParticleSettings *part=psmd->psys->part; */ /* UNUSED */ ParticleSimulationData sim = {NULL}; ParticleData *pa = NULL, *pars = psmd->psys->particles; ParticleKey state, birth; EdgeHash *vertpahash; EdgeHashIterator *ehi; float *vertco = NULL, imat[4][4]; float rot[4]; float cfra; /* float timestep; */ const int *facepa = emd->facepa; int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0; int i, v, u; unsigned int ed_v1, ed_v2, mindex = 0; MTFace *mtface = NULL, *mtf; totface = dm->getNumTessFaces(dm); totvert = dm->getNumVerts(dm); mface = dm->getTessFaceArray(dm); totpart = psmd->psys->totpart; sim.scene = scene; sim.ob = ob; sim.psys = psmd->psys; sim.psmd = psmd; /* timestep = psys_get_timestep(&sim); */ cfra = BKE_scene_frame_get(scene); /* hash table for vertice <-> particle relations */ vertpahash = BLI_edgehash_new(__func__); for (i = 0; i < totface; i++) { if (facepa[i] != totpart) { pa = pars + facepa[i]; if ((pa->alive == PARS_UNBORN && (emd->flag & eExplodeFlag_Unborn) == 0) || (pa->alive == PARS_ALIVE && (emd->flag & eExplodeFlag_Alive) == 0) || (pa->alive == PARS_DEAD && (emd->flag & eExplodeFlag_Dead) == 0)) { delface++; continue; } } /* do mindex + totvert to ensure the vertex index to be the first * with BLI_edgehashIterator_getKey */ if (facepa[i] == totpart || cfra < (pars + facepa[i])->time) mindex = totvert + totpart; else mindex = totvert + facepa[i]; mf = &mface[i]; /* set face vertices to exist in particle group */ BLI_edgehash_reinsert(vertpahash, mf->v1, mindex, NULL); BLI_edgehash_reinsert(vertpahash, mf->v2, mindex, NULL); BLI_edgehash_reinsert(vertpahash, mf->v3, mindex, NULL); if (mf->v4) BLI_edgehash_reinsert(vertpahash, mf->v4, mindex, NULL); } /* make new vertice indexes & count total vertices after duplication */ ehi = BLI_edgehashIterator_new(vertpahash); for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { BLI_edgehashIterator_setValue(ehi, SET_INT_IN_POINTER(totdup)); totdup++; } BLI_edgehashIterator_free(ehi); /* the final duplicated vertices */ explode = CDDM_from_template_ex(dm, totdup, 0, totface - delface, 0, 0, CD_MASK_DERIVEDMESH | CD_MASK_FACECORNERS); mtface = CustomData_get_layer_named(&explode->faceData, CD_MTFACE, emd->uvname); /*dupvert = CDDM_get_verts(explode);*/ /* getting back to object space */ invert_m4_m4(imat, ob->obmat); psmd->psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); /* duplicate & displace vertices */ ehi = BLI_edgehashIterator_new(vertpahash); for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { MVert source; MVert *dest; /* get particle + vertex from hash */ BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2); ed_v2 -= totvert; v = GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi)); dm->getVert(dm, ed_v1, &source); dest = CDDM_get_vert(explode, v); DM_copy_vert_data(dm, explode, ed_v1, v, 1); *dest = source; if (ed_v2 != totpart) { /* get particle */ pa = pars + ed_v2; psys_get_birth_coords(&sim, pa, &birth, 0, 0); state.time = cfra; psys_get_particle_state(&sim, ed_v2, &state, 1); vertco = CDDM_get_vert(explode, v)->co; mul_m4_v3(ob->obmat, vertco); sub_v3_v3(vertco, birth.co); /* apply rotation, size & location */ sub_qt_qtqt(rot, state.rot, birth.rot); mul_qt_v3(rot, vertco); if (emd->flag & eExplodeFlag_PaSize) mul_v3_fl(vertco, pa->size); add_v3_v3(vertco, state.co); mul_m4_v3(imat, vertco); } } BLI_edgehashIterator_free(ehi); /*map new vertices to faces*/ for (i = 0, u = 0; i < totface; i++) { MFace source; int orig_v4; if (facepa[i] != totpart) { pa = pars + facepa[i]; if (pa->alive == PARS_UNBORN && (emd->flag & eExplodeFlag_Unborn) == 0) continue; if (pa->alive == PARS_ALIVE && (emd->flag & eExplodeFlag_Alive) == 0) continue; if (pa->alive == PARS_DEAD && (emd->flag & eExplodeFlag_Dead) == 0) continue; } dm->getTessFace(dm, i, &source); mf = CDDM_get_tessface(explode, u); orig_v4 = source.v4; if (facepa[i] != totpart && cfra < pa->time) mindex = totvert + totpart; else mindex = totvert + facepa[i]; source.v1 = edgecut_get(vertpahash, source.v1, mindex); source.v2 = edgecut_get(vertpahash, source.v2, mindex); source.v3 = edgecut_get(vertpahash, source.v3, mindex); if (source.v4) source.v4 = edgecut_get(vertpahash, source.v4, mindex); DM_copy_tessface_data(dm, explode, i, u, 1); *mf = source; /* override uv channel for particle age */ if (mtface) { float age = (cfra - pa->time) / pa->lifetime; /* Clamp to this range to avoid flipping to the other side of the coordinates. */ CLAMP(age, 0.001f, 0.999f); mtf = mtface + u; mtf->uv[0][0] = mtf->uv[1][0] = mtf->uv[2][0] = mtf->uv[3][0] = age; mtf->uv[0][1] = mtf->uv[1][1] = mtf->uv[2][1] = mtf->uv[3][1] = 0.5f; } test_index_face(mf, &explode->faceData, u, (orig_v4 ? 4 : 3)); u++; } /* cleanup */ BLI_edgehash_free(vertpahash, NULL); /* finalization */ CDDM_calc_edges_tessface(explode); CDDM_tessfaces_to_faces(explode); explode->dirty |= DM_DIRTY_NORMALS; if (psmd->psys->lattice_deform_data) { end_latt_deform(psmd->psys->lattice_deform_data); psmd->psys->lattice_deform_data = NULL; } return explode; }
/** * This function converts an object space normal map to a tangent space normal map for a given low poly mesh */ void RE_bake_normal_world_to_tangent( const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], Mesh *me, const BakeNormalSwizzle normal_swizzle[3], float mat[4][4]) { size_t i; TriTessFace *triangles; DerivedMesh *dm = CDDM_from_mesh(me); triangles = mesh_calc_tri_tessface(me, true, dm); BLI_assert(num_pixels >= 3); for (i = 0; i < num_pixels; i++) { TriTessFace *triangle; float tangents[3][3]; float normals[3][3]; float signs[3]; int j; float tangent[3]; float normal[3]; float binormal[3]; float sign; float u, v, w; float tsm[3][3]; /* tangent space matrix */ float itsm[3][3]; size_t offset; float nor[3]; /* texture normal */ bool is_smooth; int primitive_id = pixel_array[i].primitive_id; offset = i * depth; if (primitive_id == -1) { copy_v3_fl3(&result[offset], 0.5f, 0.5f, 1.0f); continue; } triangle = &triangles[primitive_id]; is_smooth = triangle->is_smooth; for (j = 0; j < 3; j++) { const TSpace *ts; if (is_smooth) normal_short_to_float_v3(normals[j], triangle->mverts[j]->no); else normal[j] = triangle->normal[j]; ts = triangle->tspace[j]; copy_v3_v3(tangents[j], ts->tangent); signs[j] = ts->sign; } u = pixel_array[i].uv[0]; v = pixel_array[i].uv[1]; w = 1.0f - u - v; /* normal */ if (is_smooth) interp_barycentric_tri_v3(normals, u, v, normal); /* tangent */ interp_barycentric_tri_v3(tangents, u, v, tangent); /* sign */ /* The sign is the same at all face vertices for any non degenerate face. * Just in case we clamp the interpolated value though. */ sign = (signs[0] * u + signs[1] * v + signs[2] * w) < 0 ? (-1.0f) : 1.0f; /* binormal */ /* B = sign * cross(N, T) */ cross_v3_v3v3(binormal, normal, tangent); mul_v3_fl(binormal, sign); /* populate tangent space matrix */ copy_v3_v3(tsm[0], tangent); copy_v3_v3(tsm[1], binormal); copy_v3_v3(tsm[2], normal); /* texture values */ normal_uncompress(nor, &result[offset]); /* converts from world space to local space */ mul_transposed_mat3_m4_v3(mat, nor); invert_m3_m3(itsm, tsm); mul_m3_v3(itsm, nor); normalize_v3(nor); /* save back the values */ normal_compress(&result[offset], nor, normal_swizzle); } /* garbage collection */ MEM_freeN(triangles); if (dm) dm->release(dm); }
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, GPUTexture *tex, float min[3], float max[3], int res[3], float dx, float UNUSED(base_scale), float viewnormal[3], GPUTexture *tex_shadow, GPUTexture *tex_flame) { int i, j, k, n, good_index; float d /*, d0 */ /* UNUSED */, dd, ds; float *points = NULL; int numpoints = 0; float cor[3] = {1.0f, 1.0f, 1.0f}; int gl_depth = 0, gl_blend = 0; /* draw slices of smoke is adapted from c++ code authored * by: Johannes Schmid and Ingemar Rask, 2006, [email protected] */ float cv[][3] = { {1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f}, {1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f} }; /* edges have the form edges[n][0][xyz] + t*edges[n][1][xyz] */ float edges[12][2][3] = { {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}}, {{1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, 1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, -1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, -1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}} }; unsigned char *spec_data; float *spec_pixels; GPUTexture *tex_spec; /* Fragment program to calculate the view3d of smoke */ /* using 4 textures, density, shadow, flame and flame spectrum */ const char *shader_basic = "!!ARBfp1.0\n" "PARAM dx = program.local[0];\n" "PARAM darkness = program.local[1];\n" "PARAM render = program.local[2];\n" "PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n" "TEMP temp, shadow, flame, spec, value;\n" "TEX temp, fragment.texcoord[0], texture[0], 3D;\n" "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n" "TEX flame, fragment.texcoord[0], texture[2], 3D;\n" "TEX spec, flame.r, texture[3], 1D;\n" /* calculate shading factor from density */ "MUL value.r, temp.a, darkness.a;\n" "MUL value.r, value.r, dx.r;\n" "MUL value.r, value.r, f.r;\n" "EX2 temp, -value.r;\n" /* alpha */ "SUB temp.a, 1.0, temp.r;\n" /* shade colors */ "MUL temp.r, temp.r, shadow.r;\n" "MUL temp.g, temp.g, shadow.r;\n" "MUL temp.b, temp.b, shadow.r;\n" "MUL temp.r, temp.r, darkness.r;\n" "MUL temp.g, temp.g, darkness.g;\n" "MUL temp.b, temp.b, darkness.b;\n" /* for now this just replace smoke shading if rendering fire */ "CMP result.color, render.r, temp, spec;\n" "END\n"; /* color shader */ const char *shader_color = "!!ARBfp1.0\n" "PARAM dx = program.local[0];\n" "PARAM darkness = program.local[1];\n" "PARAM render = program.local[2];\n" "PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};\n" "TEMP temp, shadow, flame, spec, value;\n" "TEX temp, fragment.texcoord[0], texture[0], 3D;\n" "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n" "TEX flame, fragment.texcoord[0], texture[2], 3D;\n" "TEX spec, flame.r, texture[3], 1D;\n" /* unpremultiply volume texture */ "RCP value.r, temp.a;\n" "MUL temp.r, temp.r, value.r;\n" "MUL temp.g, temp.g, value.r;\n" "MUL temp.b, temp.b, value.r;\n" /* calculate shading factor from density */ "MUL value.r, temp.a, darkness.a;\n" "MUL value.r, value.r, dx.r;\n" "MUL value.r, value.r, f.r;\n" "EX2 value.r, -value.r;\n" /* alpha */ "SUB temp.a, 1.0, value.r;\n" /* shade colors */ "MUL temp.r, temp.r, shadow.r;\n" "MUL temp.g, temp.g, shadow.r;\n" "MUL temp.b, temp.b, shadow.r;\n" "MUL temp.r, temp.r, value.r;\n" "MUL temp.g, temp.g, value.r;\n" "MUL temp.b, temp.b, value.r;\n" /* for now this just replace smoke shading if rendering fire */ "CMP result.color, render.r, temp, spec;\n" "END\n"; GLuint prog; float size[3]; if (!tex) { printf("Could not allocate 3D texture for 3D View smoke drawing.\n"); return; } #ifdef DEBUG_DRAW_TIME TIMEIT_START(draw); #endif /* generate flame spectrum texture */ #define SPEC_WIDTH 256 #define FIRE_THRESH 7 #define MAX_FIRE_ALPHA 0.06f #define FULL_ON_FIRE 100 spec_data = malloc(SPEC_WIDTH * 4 * sizeof(unsigned char)); flame_get_spectrum(spec_data, SPEC_WIDTH, 1500, 3000); spec_pixels = malloc(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float)); for (i = 0; i < 16; i++) { for (j = 0; j < 16; j++) { for (k = 0; k < SPEC_WIDTH; k++) { int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4; if (k >= FIRE_THRESH) { spec_pixels[index] = ((float)spec_data[k * 4]) / 255.0f; spec_pixels[index + 1] = ((float)spec_data[k * 4 + 1]) / 255.0f; spec_pixels[index + 2] = ((float)spec_data[k * 4 + 2]) / 255.0f; spec_pixels[index + 3] = MAX_FIRE_ALPHA * ( (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH)); } else { spec_pixels[index] = spec_pixels[index + 1] = spec_pixels[index + 2] = spec_pixels[index + 3] = 0.0f; } } } } tex_spec = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL); sub_v3_v3v3(size, max, min); /* maxx, maxy, maxz */ cv[0][0] = max[0]; cv[0][1] = max[1]; cv[0][2] = max[2]; /* minx, maxy, maxz */ cv[1][0] = min[0]; cv[1][1] = max[1]; cv[1][2] = max[2]; /* minx, miny, maxz */ cv[2][0] = min[0]; cv[2][1] = min[1]; cv[2][2] = max[2]; /* maxx, miny, maxz */ cv[3][0] = max[0]; cv[3][1] = min[1]; cv[3][2] = max[2]; /* maxx, maxy, minz */ cv[4][0] = max[0]; cv[4][1] = max[1]; cv[4][2] = min[2]; /* minx, maxy, minz */ cv[5][0] = min[0]; cv[5][1] = max[1]; cv[5][2] = min[2]; /* minx, miny, minz */ cv[6][0] = min[0]; cv[6][1] = min[1]; cv[6][2] = min[2]; /* maxx, miny, minz */ cv[7][0] = max[0]; cv[7][1] = min[1]; cv[7][2] = min[2]; copy_v3_v3(edges[0][0], cv[4]); /* maxx, maxy, minz */ copy_v3_v3(edges[1][0], cv[5]); /* minx, maxy, minz */ copy_v3_v3(edges[2][0], cv[6]); /* minx, miny, minz */ copy_v3_v3(edges[3][0], cv[7]); /* maxx, miny, minz */ copy_v3_v3(edges[4][0], cv[3]); /* maxx, miny, maxz */ copy_v3_v3(edges[5][0], cv[2]); /* minx, miny, maxz */ copy_v3_v3(edges[6][0], cv[6]); /* minx, miny, minz */ copy_v3_v3(edges[7][0], cv[7]); /* maxx, miny, minz */ copy_v3_v3(edges[8][0], cv[1]); /* minx, maxy, maxz */ copy_v3_v3(edges[9][0], cv[2]); /* minx, miny, maxz */ copy_v3_v3(edges[10][0], cv[6]); /* minx, miny, minz */ copy_v3_v3(edges[11][0], cv[5]); /* minx, maxy, minz */ // printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]); // printf("min[2]: %f, max[2]: %f\n", min[2], max[2]); edges[0][1][2] = size[2]; edges[1][1][2] = size[2]; edges[2][1][2] = size[2]; edges[3][1][2] = size[2]; edges[4][1][1] = size[1]; edges[5][1][1] = size[1]; edges[6][1][1] = size[1]; edges[7][1][1] = size[1]; edges[8][1][0] = size[0]; edges[9][1][0] = size[0]; edges[10][1][0] = size[0]; edges[11][1][0] = size[0]; glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend); glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth); glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); /* find cube vertex that is closest to the viewer */ for (i = 0; i < 8; i++) { float x, y, z; x = cv[i][0] - viewnormal[0] * size[0] * 0.5f; y = cv[i][1] - viewnormal[1] * size[1] * 0.5f; z = cv[i][2] - viewnormal[2] * size[2] * 0.5f; if ((x >= min[0]) && (x <= max[0]) && (y >= min[1]) && (y <= max[1]) && (z >= min[2]) && (z <= max[2])) { break; } } if (i >= 8) { /* fallback, avoid using buffer over-run */ i = 0; } // printf("i: %d\n", i); // printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]); if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program")) { glEnable(GL_FRAGMENT_PROGRAM_ARB); glGenProgramsARB(1, &prog); glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog); /* set shader */ if (sds->active_fields & SM_ACTIVE_COLORS) glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_color), shader_color); else glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_basic), shader_basic); /* cell spacing */ glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0); /* custom parameter for smoke style (higher = thicker) */ if (sds->active_fields & SM_ACTIVE_COLORS) glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 1.0, 1.0, 1.0, 10.0); else glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0); } else printf("Your gfx card does not support 3D View smoke drawing.\n"); GPU_texture_bind(tex, 0); if (tex_shadow) GPU_texture_bind(tex_shadow, 1); else printf("No volume shadow\n"); if (tex_flame) { GPU_texture_bind(tex_flame, 2); GPU_texture_bind(tex_spec, 3); } if (!GPU_non_power_of_two_support()) { cor[0] = (float)res[0] / (float)power_of_2_max_i(res[0]); cor[1] = (float)res[1] / (float)power_of_2_max_i(res[1]); cor[2] = (float)res[2] / (float)power_of_2_max_i(res[2]); } /* our slices are defined by the plane equation a*x + b*y +c*z + d = 0 * (a,b,c), the plane normal, are given by viewdir * d is the parameter along the view direction. the first d is given by * inserting previously found vertex into the plane equation */ /* d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); */ /* UNUSED */ ds = (fabsf(viewnormal[0]) * size[0] + fabsf(viewnormal[1]) * size[1] + fabsf(viewnormal[2]) * size[2]); dd = max_fff(sds->global_size[0], sds->global_size[1], sds->global_size[2]) / 128.f; n = 0; good_index = i; // printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds); points = MEM_callocN(sizeof(float) * 12 * 3, "smoke_points_preview"); while (1) { float p0[3]; float tmp_point[3], tmp_point2[3]; if (dd * (float)n > ds) break; copy_v3_v3(tmp_point, viewnormal); mul_v3_fl(tmp_point, -dd * ((ds / dd) - (float)n)); add_v3_v3v3(tmp_point2, cv[good_index], tmp_point); d = dot_v3v3(tmp_point2, viewnormal); // printf("my d: %f\n", d); /* intersect_edges returns the intersection points of all cube edges with * the given plane that lie within the cube */ numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges); // printf("points: %d\n", numpoints); if (numpoints > 2) { copy_v3_v3(p0, points); /* sort points to get a convex polygon */ for (i = 1; i < numpoints - 1; i++) { for (j = i + 1; j < numpoints; j++) { if (!convex(p0, viewnormal, &points[j * 3], &points[i * 3])) { float tmp2[3]; copy_v3_v3(tmp2, &points[j * 3]); copy_v3_v3(&points[j * 3], &points[i * 3]); copy_v3_v3(&points[i * 3], tmp2); } } } /* render fire slice */ glBlendFunc(GL_SRC_ALPHA, GL_ONE); glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, 1.0, 0.0, 0.0, 0.0); glBegin(GL_POLYGON); glColor3f(1.0, 1.0, 1.0); for (i = 0; i < numpoints; i++) { glTexCoord3d((points[i * 3 + 0] - min[0]) * cor[0] / size[0], (points[i * 3 + 1] - min[1]) * cor[1] / size[1], (points[i * 3 + 2] - min[2]) * cor[2] / size[2]); glVertex3f(points[i * 3 + 0] / fabsf(ob->size[0]), points[i * 3 + 1] / fabsf(ob->size[1]), points[i * 3 + 2] / fabsf(ob->size[2])); } glEnd(); /* render smoke slice */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, -1.0, 0.0, 0.0, 0.0); glBegin(GL_POLYGON); glColor3f(1.0, 1.0, 1.0); for (i = 0; i < numpoints; i++) { glTexCoord3d((points[i * 3 + 0] - min[0]) * cor[0] / size[0], (points[i * 3 + 1] - min[1]) * cor[1] / size[1], (points[i * 3 + 2] - min[2]) * cor[2] / size[2]); glVertex3f(points[i * 3 + 0] / fabsf(ob->size[0]), points[i * 3 + 1] / fabsf(ob->size[1]), points[i * 3 + 2] / fabsf(ob->size[2])); } glEnd(); } n++; } #ifdef DEBUG_DRAW_TIME printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw)); TIMEIT_END(draw); #endif if (tex_shadow) GPU_texture_unbind(tex_shadow); GPU_texture_unbind(tex); if (tex_flame) { GPU_texture_unbind(tex_flame); GPU_texture_unbind(tex_spec); } GPU_texture_free(tex_spec); free(spec_data); free(spec_pixels); if (GLEW_ARB_fragment_program) { glDisable(GL_FRAGMENT_PROGRAM_ARB); glDeleteProgramsARB(1, &prog); } MEM_freeN(points); if (!gl_blend) { glDisable(GL_BLEND); } if (gl_depth) { glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); } }
int voxeldatatex(struct Tex *tex, const float texvec[3], struct TexResult *texres) { int retval = TEX_INT; VoxelData *vd = tex->vd; float co[3], offset[3] = {0.5, 0.5, 0.5}; if (vd->dataset==NULL) { texres->tin = 0.0f; return 0; } /* scale lookup from 0.0-1.0 (original location) to -1.0, 1.0, consistent with image texture tex coords */ /* in implementation this works backwards, bringing sample locations from -1.0, 1.0 * to the range 0.0, 1.0, before looking up in the voxel structure. */ copy_v3_v3(co, texvec); mul_v3_fl(co, 0.5f); add_v3_v3(co, offset); /* co is now in the range 0.0, 1.0 */ switch (vd->extend) { case TEX_CLIP: { if ((co[0] < 0.f || co[0] > 1.f) || (co[1] < 0.f || co[1] > 1.f) || (co[2] < 0.f || co[2] > 1.f)) { texres->tin = 0.f; return retval; } break; } case TEX_REPEAT: { co[0] = co[0] - floorf(co[0]); co[1] = co[1] - floorf(co[1]); co[2] = co[2] - floorf(co[2]); break; } case TEX_EXTEND: { CLAMP(co[0], 0.f, 1.f); CLAMP(co[1], 0.f, 1.f); CLAMP(co[2], 0.f, 1.f); break; } } switch (vd->interp_type) { case TEX_VD_NEARESTNEIGHBOR: texres->tin = voxel_sample_nearest(vd->dataset, vd->resol, co); break; case TEX_VD_LINEAR: texres->tin = voxel_sample_trilinear(vd->dataset, vd->resol, co); break; case TEX_VD_QUADRATIC: texres->tin = voxel_sample_triquadratic(vd->dataset, vd->resol, co); break; case TEX_VD_TRICUBIC_CATROM: case TEX_VD_TRICUBIC_BSPLINE: texres->tin = voxel_sample_tricubic(vd->dataset, vd->resol, co, (vd->interp_type == TEX_VD_TRICUBIC_BSPLINE)); break; } texres->tin *= vd->int_multiplier; BRICONT; texres->tr = texres->tin; texres->tg = texres->tin; texres->tb = texres->tin; texres->ta = texres->tin; BRICONTRGB; return retval; }
static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const wmEvent *event) { if (event->type == TIMER && event->customdata == walk->timer) { walk->redraw = true; } else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { walk->moffset[0] += event->mval[0] - walk->prev_mval[0]; walk->moffset[1] += event->mval[1] - walk->prev_mval[1]; copy_v2_v2_int(walk->prev_mval, event->mval); if ((walk->center_mval[0] != event->mval[0]) || (walk->center_mval[1] != event->mval[1])) { walk->redraw = true; if (wm_event_is_last_mousemove(event)) { wmWindow *win = CTX_wm_window(C); #ifdef __APPLE__ if ((abs(walk->prev_mval[0] - walk->center_mval[0]) > walk->center_mval[0] / 2) || (abs(walk->prev_mval[1] - walk->center_mval[1]) > walk->center_mval[1] / 2)) #endif { WM_cursor_warp(win, walk->ar->winrct.xmin + walk->center_mval[0], walk->ar->winrct.ymin + walk->center_mval[1]); copy_v2_v2_int(walk->prev_mval, walk->center_mval); } } } } else if (event->type == NDOF_MOTION) { /* do these automagically get delivered? yes. */ // puts("ndof motion detected in walk mode!"); // static const char *tag_name = "3D mouse position"; const wmNDOFMotionData *incoming_ndof = event->customdata; switch (incoming_ndof->progress) { case P_STARTING: /* start keeping track of 3D mouse position */ #ifdef NDOF_WALK_DEBUG puts("start keeping track of 3D mouse position"); #endif /* fall-through */ case P_IN_PROGRESS: /* update 3D mouse position */ #ifdef NDOF_WALK_DEBUG putchar('.'); fflush(stdout); #endif if (walk->ndof == NULL) { // walk->ndof = MEM_mallocN(sizeof(wmNDOFMotionData), tag_name); walk->ndof = MEM_dupallocN(incoming_ndof); // walk->ndof = malloc(sizeof(wmNDOFMotionData)); } else { memcpy(walk->ndof, incoming_ndof, sizeof(wmNDOFMotionData)); } break; case P_FINISHING: /* stop keeping track of 3D mouse position */ #ifdef NDOF_WALK_DEBUG puts("stop keeping track of 3D mouse position"); #endif if (walk->ndof) { MEM_freeN(walk->ndof); // free(walk->ndof); walk->ndof = NULL; } /* update the time else the view will jump when 2D mouse/timer resume */ walk->time_lastdraw = PIL_check_seconds_timer(); break; default: break; /* should always be one of the above 3 */ } } /* handle modal keymap first */ else if (event->type == EVT_MODAL_MAP) { switch (event->val) { case WALK_MODAL_CANCEL: walk->state = WALK_CANCEL; break; case WALK_MODAL_CONFIRM: walk->state = WALK_CONFIRM; break; case WALK_MODAL_ACCELERATE: base_speed *= 1.0f + (walk->is_slow ? 0.01f : 0.1f); break; case WALK_MODAL_DECELERATE: base_speed /= 1.0f + (walk->is_slow ? 0.01f : 0.1f); break; /* implement WASD keys */ case WALK_MODAL_DIR_FORWARD: walk->active_directions |= WALK_BIT_FORWARD; break; case WALK_MODAL_DIR_BACKWARD: walk->active_directions |= WALK_BIT_BACKWARD; break; case WALK_MODAL_DIR_LEFT: walk->active_directions |= WALK_BIT_LEFT; break; case WALK_MODAL_DIR_RIGHT: walk->active_directions |= WALK_BIT_RIGHT; break; case WALK_MODAL_DIR_UP: walk->active_directions |= WALK_BIT_UP; break; case WALK_MODAL_DIR_DOWN: walk->active_directions |= WALK_BIT_DOWN; break; case WALK_MODAL_DIR_FORWARD_STOP: walk->active_directions &= ~WALK_BIT_FORWARD; break; case WALK_MODAL_DIR_BACKWARD_STOP: walk->active_directions &= ~WALK_BIT_BACKWARD; break; case WALK_MODAL_DIR_LEFT_STOP: walk->active_directions &= ~WALK_BIT_LEFT; break; case WALK_MODAL_DIR_RIGHT_STOP: walk->active_directions &= ~WALK_BIT_RIGHT; break; case WALK_MODAL_DIR_UP_STOP: walk->active_directions &= ~WALK_BIT_UP; break; case WALK_MODAL_DIR_DOWN_STOP: walk->active_directions &= ~WALK_BIT_DOWN; break; case WALK_MODAL_FAST_ENABLE: walk->is_fast = true; break; case WALK_MODAL_FAST_DISABLE: walk->is_fast = false; break; case WALK_MODAL_SLOW_ENABLE: walk->is_slow = true; break; case WALK_MODAL_SLOW_DISABLE: walk->is_slow = false; break; #define JUMP_SPEED_MIN 1.0f #define JUMP_TIME_MAX 0.2f /* s */ #define JUMP_SPEED_MAX sqrtf(2.0f * walk->gravity * walk->jump_height) case WALK_MODAL_JUMP_STOP: if (walk->gravity_state == WALK_GRAVITY_STATE_JUMP) { float t; /* delta time */ t = (float)(PIL_check_seconds_timer() - walk->teleport.initial_time); /* reduce the veolocity, if JUMP wasn't hold for long enough */ t = min_ff(t, JUMP_TIME_MAX); walk->speed_jump = JUMP_SPEED_MIN + t * (JUMP_SPEED_MAX - JUMP_SPEED_MIN) / JUMP_TIME_MAX; /* when jumping, duration is how long it takes before we start going down */ walk->teleport.duration = getVelocityZeroTime(walk->gravity, walk->speed_jump); /* no more increase of jump speed */ walk->gravity_state = WALK_GRAVITY_STATE_ON; } break; case WALK_MODAL_JUMP: if ((walk->navigation_mode == WALK_MODE_GRAVITY) && (walk->gravity_state == WALK_GRAVITY_STATE_OFF) && (walk->teleport.state == WALK_TELEPORT_STATE_OFF)) { /* no need to check for ground, * walk->gravity wouldn't be off * if we were over a hole */ walk->gravity_state = WALK_GRAVITY_STATE_JUMP; walk->speed_jump = JUMP_SPEED_MAX; walk->teleport.initial_time = PIL_check_seconds_timer(); copy_v3_v3(walk->teleport.origin, walk->rv3d->viewinv[3]); /* using previous vec because WASD keys are not called when SPACE is */ copy_v2_v2(walk->teleport.direction, walk->dvec_prev); /* when jumping, duration is how long it takes before we start going down */ walk->teleport.duration = getVelocityZeroTime(walk->gravity, walk->speed_jump); } break; case WALK_MODAL_TELEPORT: { float loc[3], nor[3]; float distance; bool ret = walk_ray_cast(C, walk->rv3d, walk, loc, nor, &distance); /* in case we are teleporting middle way from a jump */ walk->speed_jump = 0.0f; if (ret) { WalkTeleport *teleport = &walk->teleport; teleport->state = WALK_TELEPORT_STATE_ON; teleport->initial_time = PIL_check_seconds_timer(); teleport->duration = U.walk_navigation.teleport_time; teleport->navigation_mode = walk->navigation_mode; walk_navigation_mode_set(C, walk, WALK_MODE_FREE); copy_v3_v3(teleport->origin, walk->rv3d->viewinv[3]); /* stop the camera from a distance (camera height) */ normalize_v3(nor); mul_v3_fl(nor, walk->view_height); add_v3_v3(loc, nor); sub_v3_v3v3(teleport->direction, loc, teleport->origin); } else { walk->teleport.state = WALK_TELEPORT_STATE_OFF; } break; } #undef JUMP_SPEED_MAX #undef JUMP_TIME_MAX #undef JUMP_SPEED_MIN case WALK_MODAL_TOGGLE: if (walk->navigation_mode == WALK_MODE_GRAVITY) { walk_navigation_mode_set(C, walk, WALK_MODE_FREE); } else { /* WALK_MODE_FREE */ walk_navigation_mode_set(C, walk, WALK_MODE_GRAVITY); } break; } } }
int voxeldatatex(struct Tex *tex, const float texvec[3], struct TexResult *texres) { VoxelData *vd = tex->vd; float co[3], offset[3] = {0.5, 0.5, 0.5}, a; int retval = (vd->data_type == TEX_VD_RGBA_PREMUL) ? TEX_RGB : TEX_INT; int depth = (vd->data_type == TEX_VD_RGBA_PREMUL) ? 4 : 1; int ch; if (vd->dataset == NULL) { texres->tin = 0.0f; return 0; } /* scale lookup from 0.0-1.0 (original location) to -1.0, 1.0, consistent with image texture tex coords */ /* in implementation this works backwards, bringing sample locations from -1.0, 1.0 * to the range 0.0, 1.0, before looking up in the voxel structure. */ copy_v3_v3(co, texvec); mul_v3_fl(co, 0.5f); add_v3_v3(co, offset); /* co is now in the range 0.0, 1.0 */ switch (vd->extend) { case TEX_CLIP: { if ((co[0] < 0.f || co[0] > 1.f) || (co[1] < 0.f || co[1] > 1.f) || (co[2] < 0.f || co[2] > 1.f)) { texres->tin = 0.f; return retval; } break; } case TEX_REPEAT: { co[0] = co[0] - floorf(co[0]); co[1] = co[1] - floorf(co[1]); co[2] = co[2] - floorf(co[2]); break; } case TEX_EXTEND: { CLAMP(co[0], 0.f, 1.f); CLAMP(co[1], 0.f, 1.f); CLAMP(co[2], 0.f, 1.f); break; } } for (ch = 0; ch < depth; ch++) { float *dataset = vd->dataset + ch*vd->resol[0]*vd->resol[1]*vd->resol[2]; float *result = &texres->tin; if (vd->data_type == TEX_VD_RGBA_PREMUL) { switch (ch) { case 0: result = &texres->tr; break; case 1: result = &texres->tg; break; case 2: result = &texres->tb; break; } } switch (vd->interp_type) { case TEX_VD_NEARESTNEIGHBOR: *result = BLI_voxel_sample_nearest(dataset, vd->resol, co); break; case TEX_VD_LINEAR: *result = BLI_voxel_sample_trilinear(dataset, vd->resol, co); break; case TEX_VD_QUADRATIC: *result = BLI_voxel_sample_triquadratic(dataset, vd->resol, co); break; case TEX_VD_TRICUBIC_CATROM: case TEX_VD_TRICUBIC_BSPLINE: *result = BLI_voxel_sample_tricubic(dataset, vd->resol, co, (vd->interp_type == TEX_VD_TRICUBIC_BSPLINE)); break; } } a = texres->tin; texres->tin *= vd->int_multiplier; BRICONT; if (vd->data_type == TEX_VD_RGBA_PREMUL) { /* unmultiply */ if (a>0.001f) { texres->tr /= a; texres->tg /= a; texres->tb /= a; } texres->talpha = 1; } else { texres->tr = texres->tin; texres->tg = texres->tin; texres->tb = texres->tin; } texres->ta = texres->tin; BRICONTRGB; return retval; }
static void compute_gradient_screen(RenderData *rd, NodeKeyingScreenData *keyingscreen_data, MovieClip *clip, CompBuf *screenbuf) { MovieClipUser user = {0}; MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *track; VoronoiTriangulationPoint *triangulated_points; VoronoiSite *sites; ImBuf *ibuf; ListBase *tracksbase; ListBase edges = {NULL, NULL}; int sites_total, triangulated_points_total, triangles_total; int (*triangles)[3]; int i, x, y; float *rect = screenbuf->rect; if (keyingscreen_data->tracking_object[0]) { MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, keyingscreen_data->tracking_object); if (!object) return; tracksbase = BKE_tracking_object_get_tracks(tracking, object); } else tracksbase = BKE_tracking_get_active_tracks(tracking); sites_total = BLI_countlist(tracksbase); if (!sites_total) return; BKE_movieclip_user_set_frame(&user, rd->cfra); ibuf = BKE_movieclip_get_ibuf(clip, &user); sites = MEM_callocN(sizeof(VoronoiSite) * sites_total, "keyingscreen voronoi sites"); track = tracksbase->first; i = 0; while (track) { VoronoiSite *site = &sites[i]; MovieTrackingMarker *marker = BKE_tracking_marker_get(track, rd->cfra); ImBuf *pattern_ibuf = BKE_tracking_get_pattern_imbuf(ibuf, track, marker, TRUE, FALSE); int j; zero_v3(site->color); if (pattern_ibuf) { for (j = 0; j < pattern_ibuf->x * pattern_ibuf->y; j++) { if (pattern_ibuf->rect_float) { add_v3_v3(site->color, &pattern_ibuf->rect_float[4 * j]); } else { unsigned char *rrgb = (unsigned char *)pattern_ibuf->rect; site->color[0] += srgb_to_linearrgb((float)rrgb[4 * j + 0] / 255.0f); site->color[1] += srgb_to_linearrgb((float)rrgb[4 * j + 1] / 255.0f); site->color[2] += srgb_to_linearrgb((float)rrgb[4 * j + 2] / 255.0f); } } mul_v3_fl(site->color, 1.0f / (pattern_ibuf->x * pattern_ibuf->y)); IMB_freeImBuf(pattern_ibuf); } site->co[0] = marker->pos[0] * screenbuf->x; site->co[1] = marker->pos[1] * screenbuf->y; track = track->next; i++; } IMB_freeImBuf(ibuf); BLI_voronoi_compute(sites, sites_total, screenbuf->x, screenbuf->y, &edges); BLI_voronoi_triangulate(sites, sites_total, &edges, screenbuf->x, screenbuf->y, &triangulated_points, &triangulated_points_total, &triangles, &triangles_total); for (y = 0; y < screenbuf->y; y++) { for (x = 0; x < screenbuf->x; x++) { int index = 4 * (y * screenbuf->x + x); rect[index + 0] = rect[index + 1] = rect[index + 2] = 0.0f; rect[index + 3] = 1.0f; for (i = 0; i < triangles_total; i++) { int *triangle = triangles[i]; VoronoiTriangulationPoint *a = &triangulated_points[triangle[0]], *b = &triangulated_points[triangle[1]], *c = &triangulated_points[triangle[2]]; float co[2] = {x, y}, w[3]; if (barycentric_coords_v2(a->co, b->co, c->co, co, w)) { if (barycentric_inside_triangle_v2(w)) { rect[index + 0] += a->color[0] * w[0] + b->color[0] * w[1] + c->color[0] * w[2]; rect[index + 1] += a->color[1] * w[0] + b->color[1] * w[1] + c->color[1] * w[2]; rect[index + 2] += a->color[2] * w[0] + b->color[2] * w[1] + c->color[2] * w[2]; } } } } } MEM_freeN(triangulated_points); MEM_freeN(triangles); MEM_freeN(sites); BLI_freelistN(&edges); }
/** * \return a face index in \a faces and set \a r_is_flip if the face is flipped away from the center. */ static int recalc_face_normals_find_index(BMesh *bm, BMFace **faces, const int faces_len, bool *r_is_flip) { const float eps = FLT_EPSILON; float cent_area_accum = 0.0f; float cent[3]; const float cent_fac = 1.0f / (float)faces_len; bool is_flip = false; int f_start_index; int i; /* Search for the best loop. Members are compared in-order defined here. */ struct { /* Squared distance from the center to the loops vertex 'l->v'. * The normalized direction between the center and this vertex is also used for the dot-products below. */ float dist_sq; /* Signed dot product using the normalized edge vector, * (best of 'l->prev->v' or 'l->next->v'). */ float edge_dot; /* Unsigned dot product using the loop-normal * (sign is used to check if we need to flip) */ float loop_dot; } best, test; UNUSED_VARS_NDEBUG(bm); zero_v3(cent); /* first calculate the center */ for (i = 0; i < faces_len; i++) { float f_cent[3]; const float f_area = BM_face_calc_area(faces[i]); BM_face_calc_center_mean_weighted(faces[i], f_cent); madd_v3_v3fl(cent, f_cent, cent_fac * f_area); cent_area_accum += f_area; BLI_assert(BMO_face_flag_test(bm, faces[i], FACE_TEMP) == 0); BLI_assert(BM_face_is_normal_valid(faces[i])); } if (cent_area_accum != 0.0f) { mul_v3_fl(cent, 1.0f / cent_area_accum); } /* Distances must start above zero, * or we can't do meaningful calculations based on the direction to the center */ best.dist_sq = eps; best.edge_dot = best.loop_dot = -FLT_MAX; /* used in degenerate cases only */ f_start_index = 0; /** * Find the outer-most vertex, comparing distance to the center, * then the outer-most loop attached to that vertex. * * Important this is correctly detected, * where casting a ray from the center wont hit any loops past this one. * Otherwise the result may be incorrect. */ for (i = 0; i < faces_len; i++) { BMLoop *l_iter, *l_first; l_iter = l_first = BM_FACE_FIRST_LOOP(faces[i]); do { bool is_best_dist_sq; float dir[3]; sub_v3_v3v3(dir, l_iter->v->co, cent); test.dist_sq = len_squared_v3(dir); is_best_dist_sq = (test.dist_sq > best.dist_sq); if (is_best_dist_sq || (test.dist_sq == best.dist_sq)) { float edge_dir_pair[2][3]; mul_v3_fl(dir, 1.0f / sqrtf(test.dist_sq)); sub_v3_v3v3(edge_dir_pair[0], l_iter->next->v->co, l_iter->v->co); sub_v3_v3v3(edge_dir_pair[1], l_iter->prev->v->co, l_iter->v->co); if ((normalize_v3(edge_dir_pair[0]) > eps) && (normalize_v3(edge_dir_pair[1]) > eps)) { bool is_best_edge_dot; test.edge_dot = max_ff(dot_v3v3(dir, edge_dir_pair[0]), dot_v3v3(dir, edge_dir_pair[1])); is_best_edge_dot = (test.edge_dot > best.edge_dot); if (is_best_dist_sq || is_best_edge_dot || (test.edge_dot == best.edge_dot)) { float loop_dir[3]; cross_v3_v3v3(loop_dir, edge_dir_pair[0], edge_dir_pair[1]); if (normalize_v3(loop_dir) > eps) { float loop_dir_dot; /* Highly unlikely the furthest loop is also the concave part of an ngon, * but it can be contrived with _very_ non-planar faces - so better check. */ if (UNLIKELY(dot_v3v3(loop_dir, l_iter->f->no) < 0.0f)) { negate_v3(loop_dir); } loop_dir_dot = dot_v3v3(dir, loop_dir); test.loop_dot = fabsf(loop_dir_dot); if (is_best_dist_sq || is_best_edge_dot || (test.loop_dot > best.loop_dot)) { best = test; f_start_index = i; is_flip = (loop_dir_dot < 0.0f); } } } } } } while ((l_iter = l_iter->next) != l_first); } *r_is_flip = is_flip; return f_start_index; }
Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type, int newob) { static int xzproj = 0; /* this function calls itself... */ ListBase *editnurb = object_editcurve_get(obedit); RegionView3D *rv3d = ED_view3d_context_rv3d(C); Nurb *nu = NULL; BezTriple *bezt; BPoint *bp; Curve *cu = (Curve *)obedit->data; float vec[3], zvec[3] = {0.0f, 0.0f, 1.0f}; float umat[4][4], viewmat[4][4]; float fac; int a, b; const float grid = 1.0f; const int cutype = (type & CU_TYPE); // poly, bezier, nurbs, etc const int stype = (type & CU_PRIMITIVE); const int force_3d = ((Curve *)obedit->data)->flag & CU_3D; /* could be adding to an existing 3D curve */ unit_m4(umat); unit_m4(viewmat); if (rv3d) { copy_m4_m4(viewmat, rv3d->viewmat); copy_v3_v3(zvec, rv3d->viewinv[2]); } BKE_nurbList_flag_set(editnurb, 0); /* these types call this function to return a Nurb */ if (stype != CU_PRIM_TUBE && stype != CU_PRIM_DONUT) { nu = (Nurb *)MEM_callocN(sizeof(Nurb), "addNurbprim"); nu->type = cutype; nu->resolu = cu->resolu; nu->resolv = cu->resolv; } switch (stype) { case CU_PRIM_CURVE: /* curve */ nu->resolu = cu->resolu; if (cutype == CU_BEZIER) { if (!force_3d) nu->flag |= CU_2D; nu->pntsu = 2; nu->bezt = (BezTriple *)MEM_callocN(2 * sizeof(BezTriple), "addNurbprim1"); bezt = nu->bezt; bezt->h1 = bezt->h2 = HD_ALIGN; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; bezt->radius = 1.0; bezt->vec[1][0] += -grid; bezt->vec[0][0] += -1.5f * grid; bezt->vec[0][1] += -0.5f * grid; bezt->vec[2][0] += -0.5f * grid; bezt->vec[2][1] += 0.5f * grid; for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); bezt++; bezt->h1 = bezt->h2 = HD_ALIGN; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; bezt->radius = bezt->weight = 1.0; bezt->vec[0][0] = 0; bezt->vec[0][1] = 0; bezt->vec[1][0] = grid; bezt->vec[1][1] = 0; bezt->vec[2][0] = grid * 2; bezt->vec[2][1] = 0; for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); BKE_nurb_handles_calc(nu); } else { nu->pntsu = 4; nu->pntsv = 1; nu->orderu = 4; nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 4, "addNurbprim3"); bp = nu->bp; for (a = 0; a < 4; a++, bp++) { bp->vec[3] = 1.0; bp->f1 = SELECT; bp->radius = bp->weight = 1.0; } bp = nu->bp; bp->vec[0] += -1.5f * grid; bp++; bp->vec[0] += -grid; bp->vec[1] += grid; bp++; bp->vec[0] += grid; bp->vec[1] += grid; bp++; bp->vec[0] += 1.5f * grid; bp = nu->bp; for (a = 0; a < 4; a++, bp++) mul_m4_v3(mat, bp->vec); if (cutype == CU_NURBS) { nu->knotsu = NULL; /* nurbs_knot_calc_u allocates */ BKE_nurb_knot_calc_u(nu); } } break; case CU_PRIM_PATH: /* 5 point path */ nu->pntsu = 5; nu->pntsv = 1; nu->orderu = 5; nu->flagu = CU_NURB_ENDPOINT; /* endpoint */ nu->resolu = cu->resolu; nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 5, "addNurbprim3"); bp = nu->bp; for (a = 0; a < 5; a++, bp++) { bp->vec[3] = 1.0; bp->f1 = SELECT; bp->radius = bp->weight = 1.0; } bp = nu->bp; bp->vec[0] += -2.0f * grid; bp++; bp->vec[0] += -grid; bp++; bp++; bp->vec[0] += grid; bp++; bp->vec[0] += 2.0f * grid; bp = nu->bp; for (a = 0; a < 5; a++, bp++) mul_m4_v3(mat, bp->vec); if (cutype == CU_NURBS) { nu->knotsu = NULL; /* nurbs_knot_calc_u allocates */ BKE_nurb_knot_calc_u(nu); } break; case CU_PRIM_CIRCLE: /* circle */ nu->resolu = cu->resolu; if (cutype == CU_BEZIER) { if (!force_3d) nu->flag |= CU_2D; nu->pntsu = 4; nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * 4, "addNurbprim1"); nu->flagu = CU_NURB_CYCLIC; bezt = nu->bezt; bezt->h1 = bezt->h2 = HD_AUTO; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; bezt->vec[1][0] += -grid; for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); bezt->radius = bezt->weight = 1.0; bezt++; bezt->h1 = bezt->h2 = HD_AUTO; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; bezt->vec[1][1] += grid; for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); bezt->radius = bezt->weight = 1.0; bezt++; bezt->h1 = bezt->h2 = HD_AUTO; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; bezt->vec[1][0] += grid; for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); bezt->radius = bezt->weight = 1.0; bezt++; bezt->h1 = bezt->h2 = HD_AUTO; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; bezt->vec[1][1] += -grid; for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); bezt->radius = bezt->weight = 1.0; BKE_nurb_handles_calc(nu); } else if (cutype == CU_NURBS) { /* nurb */ nu->pntsu = 8; nu->pntsv = 1; nu->orderu = 4; nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 8, "addNurbprim6"); nu->flagu = CU_NURB_CYCLIC; bp = nu->bp; for (a = 0; a < 8; a++) { bp->f1 = SELECT; if (xzproj == 0) { bp->vec[0] += nurbcircle[a][0] * grid; bp->vec[1] += nurbcircle[a][1] * grid; } else { bp->vec[0] += 0.25f * nurbcircle[a][0] * grid - 0.75f * grid; bp->vec[2] += 0.25f * nurbcircle[a][1] * grid; } if (a & 1) bp->vec[3] = 0.25 * M_SQRT2; else bp->vec[3] = 1.0; mul_m4_v3(mat, bp->vec); bp->radius = bp->weight = 1.0; bp++; } BKE_nurb_knot_calc_u(nu); } break; case CU_PRIM_PATCH: /* 4x4 patch */ if (cutype == CU_NURBS) { /* nurb */ nu->pntsu = 4; nu->pntsv = 4; nu->orderu = 4; nu->orderv = 4; nu->flag = CU_SMOOTH; nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * (4 * 4), "addNurbprim6"); nu->flagu = 0; nu->flagv = 0; bp = nu->bp; for (a = 0; a < 4; a++) { for (b = 0; b < 4; b++) { bp->f1 = SELECT; fac = (float)a - 1.5f; bp->vec[0] += fac * grid; fac = (float)b - 1.5f; bp->vec[1] += fac * grid; if ((a == 1 || a == 2) && (b == 1 || b == 2)) { bp->vec[2] += grid; } mul_m4_v3(mat, bp->vec); bp->vec[3] = 1.0; bp++; } } BKE_nurb_knot_calc_u(nu); BKE_nurb_knot_calc_v(nu); } break; case CU_PRIM_TUBE: /* Cylinder */ if (cutype == CU_NURBS) { nu = add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */ nu->resolu = cu->resolu; nu->flag = CU_SMOOTH; BLI_addtail(editnurb, nu); /* temporal for extrude and translate */ vec[0] = vec[1] = 0.0; vec[2] = -grid; mul_mat3_m4_v3(mat, vec); ed_editnurb_translate_flag(editnurb, SELECT, vec); ed_editnurb_extrude_flag(cu->editnurb, SELECT); mul_v3_fl(vec, -2.0f); ed_editnurb_translate_flag(editnurb, SELECT, vec); BLI_remlink(editnurb, nu); a = nu->pntsu * nu->pntsv; bp = nu->bp; while (a-- > 0) { bp->f1 |= SELECT; bp++; } } break; case CU_PRIM_SPHERE: /* sphere */ if (cutype == CU_NURBS) { float tmp_cent[3] = {0.f, 0.f, 0.f}; float tmp_vec[3] = {0.f, 0.f, 1.f}; nu->pntsu = 5; nu->pntsv = 1; nu->orderu = 3; nu->resolu = cu->resolu; nu->resolv = cu->resolv; nu->flag = CU_SMOOTH; nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 5, "addNurbprim6"); nu->flagu = 0; bp = nu->bp; for (a = 0; a < 5; a++) { bp->f1 = SELECT; bp->vec[0] += nurbcircle[a][0] * grid; bp->vec[2] += nurbcircle[a][1] * grid; if (a & 1) bp->vec[3] = 0.5 * M_SQRT2; else bp->vec[3] = 1.0; mul_m4_v3(mat, bp->vec); bp++; } nu->flagu = CU_NURB_BEZIER; BKE_nurb_knot_calc_u(nu); BLI_addtail(editnurb, nu); /* temporal for spin */ if (newob && (U.flag & USER_ADD_VIEWALIGNED) == 0) ed_editnurb_spin(umat, obedit, tmp_vec, tmp_cent); else if ((U.flag & USER_ADD_VIEWALIGNED)) ed_editnurb_spin(viewmat, obedit, zvec, mat[3]); else ed_editnurb_spin(umat, obedit, tmp_vec, mat[3]); BKE_nurb_knot_calc_v(nu); a = nu->pntsu * nu->pntsv; bp = nu->bp; while (a-- > 0) { bp->f1 |= SELECT; bp++; } BLI_remlink(editnurb, nu); } break; case CU_PRIM_DONUT: /* torus */ if (cutype == CU_NURBS) { float tmp_cent[3] = {0.f, 0.f, 0.f}; float tmp_vec[3] = {0.f, 0.f, 1.f}; xzproj = 1; nu = add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */ xzproj = 0; nu->resolu = cu->resolu; nu->resolv = cu->resolv; nu->flag = CU_SMOOTH; BLI_addtail(editnurb, nu); /* temporal for spin */ /* same as above */ if (newob && (U.flag & USER_ADD_VIEWALIGNED) == 0) ed_editnurb_spin(umat, obedit, tmp_vec, tmp_cent); else if ((U.flag & USER_ADD_VIEWALIGNED)) ed_editnurb_spin(viewmat, obedit, zvec, mat[3]); else ed_editnurb_spin(umat, obedit, tmp_vec, mat[3]); BLI_remlink(editnurb, nu); a = nu->pntsu * nu->pntsv; bp = nu->bp; while (a-- > 0) { bp->f1 |= SELECT; bp++; } } break; default: /* should never happen */ BLI_assert(!"invalid nurbs type"); return NULL; } BLI_assert(nu != NULL); if (nu) { /* should always be set */ nu->flag |= CU_SMOOTH; cu->actnu = BLI_listbase_count(editnurb); cu->actvert = CU_ACT_NONE; BKE_nurb_test2D(nu); } return nu; }
static void cloth_hair_update_bending_targets(ClothModifierData *clmd) { Cloth *cloth = clmd->clothObject; LinkNode *search = NULL; float hair_frame[3][3], dir_old[3], dir_new[3]; int prev_mn; /* to find hair chains */ if (!clmd->hairdata) return; /* XXX Note: we need to propagate frames from the root up, * but structural hair springs are stored in reverse order. * The bending springs however are then inserted in the same * order as vertices again ... * This messy situation can be resolved when solver data is * generated directly from a dedicated hair system. */ prev_mn = -1; for (search = cloth->springs; search; search = search->next) { ClothSpring *spring = search->link; ClothHairData *hair_ij, *hair_kl; bool is_root = spring->kl != prev_mn; if (spring->type != CLOTH_SPRING_TYPE_BENDING_ANG) { continue; } hair_ij = &clmd->hairdata[spring->ij]; hair_kl = &clmd->hairdata[spring->kl]; if (is_root) { /* initial hair frame from root orientation */ copy_m3_m3(hair_frame, hair_ij->rot); /* surface normal is the initial direction, * parallel transport then keeps it aligned to the hair direction */ copy_v3_v3(dir_new, hair_frame[2]); } copy_v3_v3(dir_old, dir_new); sub_v3_v3v3(dir_new, cloth->verts[spring->mn].x, cloth->verts[spring->kl].x); normalize_v3(dir_new); #if 0 if (clmd->debug_data && (spring->ij == 0 || spring->ij == 1)) { float a[3], b[3]; copy_v3_v3(a, cloth->verts[spring->kl].x); // BKE_sim_debug_data_add_dot(clmd->debug_data, cloth_vert ? cloth_vert->x : key->co, 1, 1, 0, "frames", 8246, p, k); mul_v3_v3fl(b, hair_frame[0], clmd->sim_parms->avg_spring_len); BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 1, 0, 0, "frames", 8247, spring->kl, spring->mn); mul_v3_v3fl(b, hair_frame[1], clmd->sim_parms->avg_spring_len); BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 0, 1, 0, "frames", 8248, spring->kl, spring->mn); mul_v3_v3fl(b, hair_frame[2], clmd->sim_parms->avg_spring_len); BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 0, 0, 1, "frames", 8249, spring->kl, spring->mn); } #endif /* get local targets for kl/mn vertices by putting rest targets into the current frame, * then multiply with the rest length to get the actual goals */ mul_v3_m3v3(spring->target, hair_frame, hair_kl->rest_target); mul_v3_fl(spring->target, spring->restlen); /* move frame to next hair segment */ cloth_parallel_transport_hair_frame(hair_frame, dir_old, dir_new); prev_mn = spring->mn; } }
/* only creates a table for a single channel in CurveMapping */ static void curvemap_make_table(CurveMap *cuma, const rctf *clipr) { CurveMapPoint *cmp = cuma->curve; BezTriple *bezt; float *fp, *allpoints, *lastpoint, curf, range; int a, totpoint; if (cuma->curve == NULL) return; /* default rect also is table range */ cuma->mintable = clipr->xmin; cuma->maxtable = clipr->xmax; /* hrmf... we now rely on blender ipo beziers, these are more advanced */ bezt = MEM_callocN(cuma->totpoint * sizeof(BezTriple), "beztarr"); for (a = 0; a < cuma->totpoint; a++) { cuma->mintable = min_ff(cuma->mintable, cmp[a].x); cuma->maxtable = max_ff(cuma->maxtable, cmp[a].x); bezt[a].vec[1][0] = cmp[a].x; bezt[a].vec[1][1] = cmp[a].y; if (cmp[a].flag & CUMA_VECTOR) bezt[a].h1 = bezt[a].h2 = HD_VECT; else bezt[a].h1 = bezt[a].h2 = HD_AUTO; } for (a = 0; a < cuma->totpoint; a++) { if (a == 0) calchandle_curvemap(bezt, NULL, bezt + 1, 0); else if (a == cuma->totpoint - 1) calchandle_curvemap(bezt + a, bezt + a - 1, NULL, 0); else calchandle_curvemap(bezt + a, bezt + a - 1, bezt + a + 1, 0); } /* first and last handle need correction, instead of pointing to center of next/prev, * we let it point to the closest handle */ if (cuma->totpoint > 2) { float hlen, nlen, vec[3]; if (bezt[0].h2 == HD_AUTO) { hlen = len_v3v3(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */ /* clip handle point */ copy_v3_v3(vec, bezt[1].vec[0]); if (vec[0] < bezt[0].vec[1][0]) vec[0] = bezt[0].vec[1][0]; sub_v3_v3(vec, bezt[0].vec[1]); nlen = len_v3(vec); if (nlen > FLT_EPSILON) { mul_v3_fl(vec, hlen / nlen); add_v3_v3v3(bezt[0].vec[2], vec, bezt[0].vec[1]); sub_v3_v3v3(bezt[0].vec[0], bezt[0].vec[1], vec); } } a = cuma->totpoint - 1; if (bezt[a].h2 == HD_AUTO) { hlen = len_v3v3(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */ /* clip handle point */ copy_v3_v3(vec, bezt[a - 1].vec[2]); if (vec[0] > bezt[a].vec[1][0]) vec[0] = bezt[a].vec[1][0]; sub_v3_v3(vec, bezt[a].vec[1]); nlen = len_v3(vec); if (nlen > FLT_EPSILON) { mul_v3_fl(vec, hlen / nlen); add_v3_v3v3(bezt[a].vec[0], vec, bezt[a].vec[1]); sub_v3_v3v3(bezt[a].vec[2], bezt[a].vec[1], vec); } } } /* make the bezier curve */ if (cuma->table) MEM_freeN(cuma->table); totpoint = (cuma->totpoint - 1) * CM_RESOL; fp = allpoints = MEM_callocN(totpoint * 2 * sizeof(float), "table"); for (a = 0; a < cuma->totpoint - 1; a++, fp += 2 * CM_RESOL) { correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a + 1].vec[0], bezt[a + 1].vec[1]); BKE_curve_forward_diff_bezier(bezt[a].vec[1][0], bezt[a].vec[2][0], bezt[a + 1].vec[0][0], bezt[a + 1].vec[1][0], fp, CM_RESOL - 1, 2 * sizeof(float)); BKE_curve_forward_diff_bezier(bezt[a].vec[1][1], bezt[a].vec[2][1], bezt[a + 1].vec[0][1], bezt[a + 1].vec[1][1], fp + 1, CM_RESOL - 1, 2 * sizeof(float)); } /* store first and last handle for extrapolation, unit length */ cuma->ext_in[0] = bezt[0].vec[0][0] - bezt[0].vec[1][0]; cuma->ext_in[1] = bezt[0].vec[0][1] - bezt[0].vec[1][1]; range = sqrt(cuma->ext_in[0] * cuma->ext_in[0] + cuma->ext_in[1] * cuma->ext_in[1]); cuma->ext_in[0] /= range; cuma->ext_in[1] /= range; a = cuma->totpoint - 1; cuma->ext_out[0] = bezt[a].vec[1][0] - bezt[a].vec[2][0]; cuma->ext_out[1] = bezt[a].vec[1][1] - bezt[a].vec[2][1]; range = sqrt(cuma->ext_out[0] * cuma->ext_out[0] + cuma->ext_out[1] * cuma->ext_out[1]); cuma->ext_out[0] /= range; cuma->ext_out[1] /= range; /* cleanup */ MEM_freeN(bezt); range = CM_TABLEDIV * (cuma->maxtable - cuma->mintable); cuma->range = 1.0f / range; /* now make a table with CM_TABLE equal x distances */ fp = allpoints; lastpoint = allpoints + 2 * (totpoint - 1); cmp = MEM_callocN((CM_TABLE + 1) * sizeof(CurveMapPoint), "dist table"); for (a = 0; a <= CM_TABLE; a++) { curf = cuma->mintable + range * (float)a; cmp[a].x = curf; /* get the first x coordinate larger than curf */ while (curf >= fp[0] && fp != lastpoint) { fp += 2; } if (fp == allpoints || (curf >= fp[0] && fp == lastpoint)) cmp[a].y = curvemap_calc_extend(cuma, curf, allpoints, lastpoint); else { float fac1 = fp[0] - fp[-2]; float fac2 = fp[0] - curf; if (fac1 > FLT_EPSILON) fac1 = fac2 / fac1; else fac1 = 0.0f; cmp[a].y = fac1 * fp[-1] + (1.0f - fac1) * fp[1]; } } MEM_freeN(allpoints); cuma->table = cmp; }
struct CharTrans *BKE_vfont_to_curve(Main *bmain, Scene *scene, Object *ob, int mode) { VFont *vfont, *oldvfont; VFontData *vfd = NULL; Curve *cu; CharInfo *info = NULL, *custrinfo; TextBox *tb; VChar *che; struct CharTrans *chartransdata = NULL, *ct; float *f, xof, yof, xtrax, linedist, *linedata, *linedata2, *linedata3, *linedata4; float twidth, maxlen = 0; int i, slen, j; int curbox; int selstart, selend; int utf8len; short cnr = 0, lnr = 0, wsnr = 0; wchar_t *mem, *tmp, ascii; /* remark: do calculations including the trailing '\0' of a string * because the cursor can be at that location */ if (ob->type != OB_FONT) return NULL; /* Set font data */ cu = (Curve *) ob->data; vfont = cu->vfont; if (cu->str == NULL) return NULL; if (vfont == NULL) return NULL; /* Create unicode string */ utf8len = BLI_strlen_utf8(cu->str); mem = MEM_callocN(((utf8len + 1) * sizeof(wchar_t)), "convertedmem"); BLI_strncpy_wchar_from_utf8(mem, cu->str, utf8len + 1); /* Count the wchar_t string length */ slen = wcslen(mem); if (cu->ulheight == 0.0f) cu->ulheight = 0.05f; if (cu->strinfo == NULL) /* old file */ cu->strinfo = MEM_callocN((slen + 4) * sizeof(CharInfo), "strinfo compat"); custrinfo = cu->strinfo; if (cu->editfont) custrinfo = cu->editfont->textbufinfo; if (cu->tb == NULL) cu->tb = MEM_callocN(MAXTEXTBOX * sizeof(TextBox), "TextBox compat"); vfd = vfont_get_data(bmain, vfont); /* The VFont Data can not be found */ if (!vfd) { if (mem) MEM_freeN(mem); return NULL; } /* calc offset and rotation of each char */ ct = chartransdata = (struct CharTrans *)MEM_callocN((slen + 1) * sizeof(struct CharTrans), "buildtext"); /* We assume the worst case: 1 character per line (is freed at end anyway) */ linedata = MEM_mallocN(sizeof(float) * (slen * 2 + 1), "buildtext2"); linedata2 = MEM_mallocN(sizeof(float) * (slen * 2 + 1), "buildtext3"); linedata3 = MEM_callocN(sizeof(float) * (slen * 2 + 1), "buildtext4"); linedata4 = MEM_callocN(sizeof(float) * (slen * 2 + 1), "buildtext5"); linedist = cu->linedist; xof = cu->xof + (cu->tb[0].x / cu->fsize); yof = cu->yof + (cu->tb[0].y / cu->fsize); xtrax = 0.5f * cu->spacing - 0.5f; oldvfont = NULL; for (i = 0; i < slen; i++) custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK); if (cu->selboxes) MEM_freeN(cu->selboxes); cu->selboxes = NULL; if (BKE_vfont_select_get(ob, &selstart, &selend)) cu->selboxes = MEM_callocN((selend - selstart + 1) * sizeof(SelBox), "font selboxes"); tb = &(cu->tb[0]); curbox = 0; for (i = 0; i <= slen; i++) { makebreak: /* Characters in the list */ info = &(custrinfo[i]); ascii = mem[i]; if (info->flag & CU_CHINFO_SMALLCAPS) { ascii = towupper(ascii); if (mem[i] != ascii) { mem[i] = ascii; info->flag |= CU_CHINFO_SMALLCAPS_CHECK; } } vfont = which_vfont(cu, info); if (vfont == NULL) break; che = find_vfont_char(vfd, ascii); /* * The character wasn't in the current curve base so load it * But if the font is built-in then do not try loading since * whole font is in the memory already */ if (che == NULL && BKE_vfont_is_builtin(vfont) == FALSE) { BLI_vfontchar_from_freetypefont(vfont, ascii); } /* Try getting the character again from the list */ che = find_vfont_char(vfd, ascii); /* No VFont found */ if (vfont == NULL) { if (mem) MEM_freeN(mem); MEM_freeN(chartransdata); return NULL; } if (vfont != oldvfont) { vfd = vfont_get_data(bmain, vfont); oldvfont = vfont; } /* VFont Data for VFont couldn't be found */ if (!vfd) { if (mem) MEM_freeN(mem); MEM_freeN(chartransdata); return NULL; } twidth = char_width(cu, che, info); /* Calculate positions */ if ((tb->w != 0.0f) && (ct->dobreak == 0) && (((xof - (tb->x / cu->fsize) + twidth) * cu->fsize) > tb->w + cu->xof * cu->fsize)) { // fprintf(stderr, "linewidth exceeded: %c%c%c...\n", mem[i], mem[i+1], mem[i+2]); for (j = i; j && (mem[j] != '\n') && (mem[j] != '\r') && (chartransdata[j].dobreak == 0); j--) { if (mem[j] == ' ' || mem[j] == '-') { ct -= (i - (j - 1)); cnr -= (i - (j - 1)); if (mem[j] == ' ') wsnr--; if (mem[j] == '-') wsnr++; i = j - 1; xof = ct->xof; ct[1].dobreak = 1; custrinfo[i + 1].flag |= CU_CHINFO_WRAP; goto makebreak; } if (chartransdata[j].dobreak) { // fprintf(stderr, "word too long: %c%c%c...\n", mem[j], mem[j+1], mem[j+2]); ct->dobreak = 1; custrinfo[i + 1].flag |= CU_CHINFO_WRAP; ct -= 1; cnr -= 1; i--; xof = ct->xof; goto makebreak; } } } if (ascii == '\n' || ascii == '\r' || ascii == 0 || ct->dobreak) { ct->xof = xof; ct->yof = yof; ct->linenr = lnr; ct->charnr = cnr; yof -= linedist; maxlen = max_ff(maxlen, (xof - tb->x / cu->fsize)); linedata[lnr] = xof - tb->x / cu->fsize; linedata2[lnr] = cnr; linedata3[lnr] = tb->w / cu->fsize; linedata4[lnr] = wsnr; if ((tb->h != 0.0f) && ((-(yof - (tb->y / cu->fsize))) > ((tb->h / cu->fsize) - (linedist * cu->fsize)) - cu->yof) && (cu->totbox > (curbox + 1)) ) { maxlen = 0; tb++; curbox++; yof = cu->yof + tb->y / cu->fsize; } /* XXX, has been unused for years, need to check if this is useful, r4613 r5282 - campbell */ #if 0 if (ascii == '\n' || ascii == '\r') xof = cu->xof; else xof = cu->xof + (tb->x / cu->fsize); #else xof = cu->xof + (tb->x / cu->fsize); #endif lnr++; cnr = 0; wsnr = 0; } else if (ascii == 9) { /* TAB */ float tabfac; ct->xof = xof; ct->yof = yof; ct->linenr = lnr; ct->charnr = cnr++; tabfac = (xof - cu->xof + 0.01f); tabfac = 2.0f * ceilf(tabfac / 2.0f); xof = cu->xof + tabfac; } else { SelBox *sb = NULL; float wsfac; ct->xof = xof; ct->yof = yof; ct->linenr = lnr; ct->charnr = cnr++; if (cu->selboxes && (i >= selstart) && (i <= selend)) { sb = &(cu->selboxes[i - selstart]); sb->y = yof * cu->fsize - linedist * cu->fsize * 0.1f; sb->h = linedist * cu->fsize; sb->w = xof * cu->fsize; } if (ascii == 32) { wsfac = cu->wordspace; wsnr++; } else { wsfac = 1.0f; } /* Set the width of the character */ twidth = char_width(cu, che, info); xof += (twidth * wsfac * (1.0f + (info->kern / 40.0f)) ) + xtrax; if (sb) { sb->w = (xof * cu->fsize) - sb->w; } } ct++; } cu->lines = 1; ct = chartransdata; tmp = mem; for (i = 0; i <= slen; i++, tmp++, ct++) { ascii = *tmp; if (ascii == '\n' || ascii == '\r' || ct->dobreak) cu->lines++; } /* linedata is now: width of line * linedata2 is now: number of characters * linedata3 is now: maxlen of that line * linedata4 is now: number of whitespaces of line */ if (cu->spacemode != CU_LEFT) { ct = chartransdata; if (cu->spacemode == CU_RIGHT) { for (i = 0; i < lnr; i++) linedata[i] = linedata3[i] - linedata[i]; for (i = 0; i <= slen; i++) { ct->xof += linedata[ct->linenr]; ct++; } } else if (cu->spacemode == CU_MIDDLE) { for (i = 0; i < lnr; i++) linedata[i] = (linedata3[i] - linedata[i]) / 2; for (i = 0; i <= slen; i++) { ct->xof += linedata[ct->linenr]; ct++; } } else if ((cu->spacemode == CU_FLUSH) && (cu->tb[0].w != 0.0f)) { for (i = 0; i < lnr; i++) if (linedata2[i] > 1) linedata[i] = (linedata3[i] - linedata[i]) / (linedata2[i] - 1); for (i = 0; i <= slen; i++) { for (j = i; (!ELEM3(mem[j], '\0', '\n', '\r')) && (chartransdata[j].dobreak == 0) && (j < slen); j++) { /* do nothing */ } // if ((mem[j] != '\r') && (mem[j] != '\n') && (mem[j])) { ct->xof += ct->charnr * linedata[ct->linenr]; // } ct++; } } else if ((cu->spacemode == CU_JUSTIFY) && (cu->tb[0].w != 0.0f)) { float curofs = 0.0f; for (i = 0; i <= slen; i++) { for (j = i; (mem[j]) && (mem[j] != '\n') && (mem[j] != '\r') && (chartransdata[j].dobreak == 0) && (j < slen); j++) { /* pass */ } if ((mem[j] != '\r') && (mem[j] != '\n') && ((chartransdata[j].dobreak != 0))) { if (mem[i] == ' ') curofs += (linedata3[ct->linenr] - linedata[ct->linenr]) / linedata4[ct->linenr]; ct->xof += curofs; } if (mem[i] == '\n' || mem[i] == '\r' || chartransdata[i].dobreak) curofs = 0; ct++; } } } /* TEXT ON CURVE */ /* Note: Only OB_CURVE objects could have a path */ if (cu->textoncurve && cu->textoncurve->type == OB_CURVE) { Curve *cucu = cu->textoncurve->data; int oldflag = cucu->flag; cucu->flag |= (CU_PATH + CU_FOLLOW); if (cucu->path == NULL) BKE_displist_make_curveTypes(scene, cu->textoncurve, 0); if (cucu->path) { float distfac, imat[4][4], imat3[3][3], cmat[3][3]; float minx, maxx, miny, maxy; float timeofs, sizefac; invert_m4_m4(imat, ob->obmat); copy_m3_m4(imat3, imat); copy_m3_m4(cmat, cu->textoncurve->obmat); mul_m3_m3m3(cmat, cmat, imat3); sizefac = normalize_v3(cmat[0]) / cu->fsize; minx = miny = 1.0e20f; maxx = maxy = -1.0e20f; ct = chartransdata; for (i = 0; i <= slen; i++, ct++) { if (minx > ct->xof) minx = ct->xof; if (maxx < ct->xof) maxx = ct->xof; if (miny > ct->yof) miny = ct->yof; if (maxy < ct->yof) maxy = ct->yof; } /* we put the x-coordinaat exact at the curve, the y is rotated */ /* length correction */ distfac = sizefac * cucu->path->totdist / (maxx - minx); timeofs = 0.0f; if (distfac > 1.0f) { /* path longer than text: spacemode involves */ distfac = 1.0f / distfac; if (cu->spacemode == CU_RIGHT) { timeofs = 1.0f - distfac; } else if (cu->spacemode == CU_MIDDLE) { timeofs = (1.0f - distfac) / 2.0f; } else if (cu->spacemode == CU_FLUSH) { distfac = 1.0f; } } else { distfac = 1.0; } distfac /= (maxx - minx); timeofs += distfac * cu->xof; /* not cyclic */ ct = chartransdata; for (i = 0; i <= slen; i++, ct++) { float ctime, dtime, vec[4], tvec[4], rotvec[3]; float si, co; /* rotate around center character */ ascii = mem[i]; che = find_vfont_char(vfd, ascii); twidth = char_width(cu, che, info); dtime = distfac * 0.5f * twidth; ctime = timeofs + distfac * (ct->xof - minx); CLAMP(ctime, 0.0f, 1.0f); /* calc the right loc AND the right rot separately */ /* vec, tvec need 4 items */ where_on_path(cu->textoncurve, ctime, vec, tvec, NULL, NULL, NULL); where_on_path(cu->textoncurve, ctime + dtime, tvec, rotvec, NULL, NULL, NULL); mul_v3_fl(vec, sizefac); ct->rot = (float)M_PI - atan2f(rotvec[1], rotvec[0]); si = sinf(ct->rot); co = cosf(ct->rot); yof = ct->yof; ct->xof = vec[0] + si * yof; ct->yof = vec[1] + co * yof; } cucu->flag = oldflag; } } if (cu->selboxes) { ct = chartransdata; for (i = 0; i <= selend; i++, ct++) { if (i >= selstart) { cu->selboxes[i - selstart].x = ct->xof * cu->fsize; cu->selboxes[i - selstart].y = ct->yof * cu->fsize; } } } if (mode == FO_CURSUP || mode == FO_CURSDOWN || mode == FO_PAGEUP || mode == FO_PAGEDOWN) { /* 2: curs up * 3: curs down */ ct = chartransdata + cu->pos; if ((mode == FO_CURSUP || mode == FO_PAGEUP) && ct->linenr == 0) { /* pass */ } else if ((mode == FO_CURSDOWN || mode == FO_PAGEDOWN) && ct->linenr == lnr) { /* pass */ } else { switch (mode) { case FO_CURSUP: lnr = ct->linenr - 1; break; case FO_CURSDOWN: lnr = ct->linenr + 1; break; case FO_PAGEUP: lnr = ct->linenr - 10; break; case FO_PAGEDOWN: lnr = ct->linenr + 10; break; } cnr = ct->charnr; /* seek for char with lnr en cnr */ cu->pos = 0; ct = chartransdata; for (i = 0; i < slen; i++) { if (ct->linenr == lnr) { if ((ct->charnr == cnr) || ((ct + 1)->charnr == 0)) { break; } } else if (ct->linenr > lnr) { break; } cu->pos++; ct++; } } } /* cursor first */ if (cu->editfont) { float si, co; ct = chartransdata + cu->pos; si = sinf(ct->rot); co = cosf(ct->rot); f = cu->editfont->textcurs[0]; f[0] = cu->fsize * (-0.1f * co + ct->xof); f[1] = cu->fsize * ( 0.1f * si + ct->yof); f[2] = cu->fsize * ( 0.1f * co + ct->xof); f[3] = cu->fsize * (-0.1f * si + ct->yof); f[4] = cu->fsize * ( 0.1f * co + 0.8f * si + ct->xof); f[5] = cu->fsize * (-0.1f * si + 0.8f * co + ct->yof); f[6] = cu->fsize * (-0.1f * co + 0.8f * si + ct->xof); f[7] = cu->fsize * ( 0.1f * si + 0.8f * co + ct->yof); } MEM_freeN(linedata); MEM_freeN(linedata2); MEM_freeN(linedata3); MEM_freeN(linedata4); if (mode == FO_SELCHANGE) { MEM_freeN(chartransdata); MEM_freeN(mem); return NULL; } if (mode == FO_EDIT) { /* make nurbdata */ BKE_nurbList_free(&cu->nurb); ct = chartransdata; if (cu->sepchar == 0) { for (i = 0; i < slen; i++) { unsigned long cha = (uintptr_t) mem[i]; info = &(custrinfo[i]); if (info->mat_nr > (ob->totcol)) { /* printf("Error: Illegal material index (%d) in text object, setting to 0\n", info->mat_nr); */ info->mat_nr = 0; } /* We do not want to see any character for \n or \r */ if (cha != '\n' && cha != '\r') buildchar(bmain, cu, cha, info, ct->xof, ct->yof, ct->rot, i); if ((info->flag & CU_CHINFO_UNDERLINE) && (cu->textoncurve == NULL) && (cha != '\n') && (cha != '\r')) { float ulwidth, uloverlap = 0.0f; if ((i < (slen - 1)) && (mem[i + 1] != '\n') && (mem[i + 1] != '\r') && ((mem[i + 1] != ' ') || (custrinfo[i + 1].flag & CU_CHINFO_UNDERLINE)) && ((custrinfo[i + 1].flag & CU_CHINFO_WRAP) == 0)) { uloverlap = xtrax + 0.1f; } /* Find the character, the characters has to be in the memory already * since character checking has been done earlier already. */ che = find_vfont_char(vfd, cha); twidth = char_width(cu, che, info); ulwidth = cu->fsize * ((twidth * (1.0f + (info->kern / 40.0f))) + uloverlap); build_underline(cu, ct->xof * cu->fsize, ct->yof * cu->fsize + (cu->ulpos - 0.05f) * cu->fsize, ct->xof * cu->fsize + ulwidth, ct->yof * cu->fsize + (cu->ulpos - 0.05f) * cu->fsize - cu->ulheight * cu->fsize, i, info->mat_nr); } ct++; } } else { int outta = 0; for (i = 0; (i < slen) && (outta == 0); i++) { ascii = mem[i]; info = &(custrinfo[i]); if (cu->sepchar == (i + 1)) { float vecyo[3]; vecyo[0] = ct->xof; vecyo[1] = ct->yof; vecyo[2] = 0.0f; mem[0] = ascii; mem[1] = 0; custrinfo[0] = *info; cu->pos = 1; cu->len = 1; mul_v3_m4v3(ob->loc, ob->obmat, vecyo); outta = 1; cu->sepchar = 0; } ct++; } } } if (mode == FO_DUPLI) { MEM_freeN(mem); return chartransdata; } if (mem) MEM_freeN(mem); MEM_freeN(chartransdata); return NULL; }
static void do_physical_effector(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, float *total_force) { PartDeflect *pd = eff->pd; RNG *rng = pd->rng; float force[3] = {0, 0, 0}; float temp[3]; float fac; float strength = pd->f_strength; float damp = pd->f_damp; float noise_factor = pd->f_noise; if (noise_factor > 0.0f) { strength += wind_func(rng, noise_factor); if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG)) damp += wind_func(rng, noise_factor); } copy_v3_v3(force, efd->vec_to_point); switch (pd->forcefield) { case PFIELD_WIND: copy_v3_v3(force, efd->nor); mul_v3_fl(force, strength * efd->falloff); break; case PFIELD_FORCE: normalize_v3(force); mul_v3_fl(force, strength * efd->falloff); break; case PFIELD_VORTEX: /* old vortex force */ if (pd->shape == PFIELD_SHAPE_POINT) { cross_v3_v3v3(force, efd->nor, efd->vec_to_point); normalize_v3(force); mul_v3_fl(force, strength * efd->distance * efd->falloff); } else { /* new vortex force */ cross_v3_v3v3(temp, efd->nor2, efd->vec_to_point2); mul_v3_fl(temp, strength * efd->falloff); cross_v3_v3v3(force, efd->nor2, temp); mul_v3_fl(force, strength * efd->falloff); madd_v3_v3fl(temp, point->vel, -point->vel_to_sec); add_v3_v3(force, temp); } break; case PFIELD_MAGNET: if (eff->pd->shape == PFIELD_SHAPE_POINT) /* magnetic field of a moving charge */ cross_v3_v3v3(temp, efd->nor, efd->vec_to_point); else copy_v3_v3(temp, efd->nor); normalize_v3(temp); mul_v3_fl(temp, strength * efd->falloff); cross_v3_v3v3(force, point->vel, temp); mul_v3_fl(force, point->vel_to_sec); break; case PFIELD_HARMONIC: mul_v3_fl(force, -strength * efd->falloff); copy_v3_v3(temp, point->vel); mul_v3_fl(temp, -damp * 2.0f * (float)sqrt(fabs(strength)) * point->vel_to_sec); add_v3_v3(force, temp); break; case PFIELD_CHARGE: mul_v3_fl(force, point->charge * strength * efd->falloff); break; case PFIELD_LENNARDJ: fac = pow((efd->size + point->size) / efd->distance, 6.0); fac = - fac * (1.0f - fac) / efd->distance; /* limit the repulsive term drastically to avoid huge forces */ fac = ((fac>2.0f) ? 2.0f : fac); mul_v3_fl(force, strength * fac); break; case PFIELD_BOID: /* Boid field is handled completely in boids code. */ return; case PFIELD_TURBULENCE: if (pd->flag & PFIELD_GLOBAL_CO) { copy_v3_v3(temp, point->loc); } else { add_v3_v3v3(temp, efd->vec_to_point2, efd->nor2); } force[0] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[0], temp[1], temp[2], 2, 0, 2); force[1] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[1], temp[2], temp[0], 2, 0, 2); force[2] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[2], temp[0], temp[1], 2, 0, 2); mul_v3_fl(force, strength * efd->falloff); break; case PFIELD_DRAG: copy_v3_v3(force, point->vel); fac = normalize_v3(force) * point->vel_to_sec; strength = MIN2(strength, 2.0f); damp = MIN2(damp, 2.0f); mul_v3_fl(force, -efd->falloff * fac * (strength * fac + damp)); break; case PFIELD_SMOKEFLOW: zero_v3(force); if (pd->f_source) { float density; if ((density = smoke_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) { float influence = strength * efd->falloff; if (pd->flag & PFIELD_SMOKE_DENSITY) influence *= density; mul_v3_fl(force, influence); /* apply flow */ madd_v3_v3fl(total_force, point->vel, -pd->f_flow * influence); } } break; } if (pd->flag & PFIELD_DO_LOCATION) { madd_v3_v3fl(total_force, force, 1.0f/point->vel_to_sec); if (ELEM3(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW)==0 && pd->f_flow != 0.0f) { madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff); } } if (point->ave) zero_v3(point->ave); if (pd->flag & PFIELD_DO_ROTATION && point->ave && point->rot) { float xvec[3] = {1.0f, 0.0f, 0.0f}; float dave[3]; mul_qt_v3(point->rot, xvec); cross_v3_v3v3(dave, xvec, force); if (pd->f_flow != 0.0f) { madd_v3_v3fl(dave, point->ave, -pd->f_flow * efd->falloff); } add_v3_v3(point->ave, dave); } }
static void axisProjection(TransInfo *t, float axis[3], float in[3], float out[3]) { float norm[3], vec[3], factor, angle; float t_con_center[3]; if (in[0] == 0.0f && in[1] == 0.0f && in[2] == 0.0f) return; copy_v3_v3(t_con_center, t->con.center); /* 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.0f) { 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; } } }
void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint) { Material *ma; StrandBuffer *strandbuf; float *simplify; float p[4][3], data[4], cross[3], w, dx, dy, t; int type; strandbuf= sseg->buffer; ma= sseg->buffer->ma; t= spoint->t; type= (strandbuf->flag & R_STRAND_BSPLINE)? KEY_BSPLINE: KEY_CARDINAL; copy_v3_v3(p[0], sseg->v[0]->co); copy_v3_v3(p[1], sseg->v[1]->co); copy_v3_v3(p[2], sseg->v[2]->co); copy_v3_v3(p[3], sseg->v[3]->co); if (sseg->obi->flag & R_TRANSFORMED) { mul_m4_v3(sseg->obi->mat, p[0]); mul_m4_v3(sseg->obi->mat, p[1]); mul_m4_v3(sseg->obi->mat, p[2]); mul_m4_v3(sseg->obi->mat, p[3]); } if (t == 0.0f) { copy_v3_v3(spoint->co, p[1]); spoint->strandco= sseg->v[1]->strandco; spoint->dtstrandco= (sseg->v[2]->strandco - sseg->v[0]->strandco); if (sseg->v[0] != sseg->v[1]) spoint->dtstrandco *= 0.5f; } else if (t == 1.0f) { copy_v3_v3(spoint->co, p[2]); spoint->strandco= sseg->v[2]->strandco; spoint->dtstrandco= (sseg->v[3]->strandco - sseg->v[1]->strandco); if (sseg->v[3] != sseg->v[2]) spoint->dtstrandco *= 0.5f; } else { key_curve_position_weights(t, data, type); spoint->co[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0]; spoint->co[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1]; spoint->co[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2]; spoint->strandco= (1.0f-t)*sseg->v[1]->strandco + t*sseg->v[2]->strandco; } key_curve_tangent_weights(t, data, type); spoint->dtco[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0]; spoint->dtco[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1]; spoint->dtco[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2]; normalize_v3_v3(spoint->tan, spoint->dtco); normalize_v3_v3(spoint->nor, spoint->co); negate_v3(spoint->nor); spoint->width= strand_eval_width(ma, spoint->strandco); /* simplification */ simplify= RE_strandren_get_simplify(strandbuf->obr, sseg->strand, 0); spoint->alpha= (simplify)? simplify[1]: 1.0f; /* outer points */ cross_v3_v3v3(cross, spoint->co, spoint->tan); w= spoint->co[2]*strandbuf->winmat[2][3] + strandbuf->winmat[3][3]; dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]/w; dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]/w; w= sqrt(dx*dx + dy*dy); if (w > 0.0f) { if (strandbuf->flag & R_STRAND_B_UNITS) { const float crosslen= len_v3(cross); w= 2.0f*crosslen*strandbuf->minwidth/w; if (spoint->width < w) { spoint->alpha= spoint->width/w; spoint->width= w; } if (simplify) /* squared because we only change width, not length */ spoint->width *= simplify[0]*simplify[0]; mul_v3_fl(cross, spoint->width*0.5f/crosslen); } else mul_v3_fl(cross, spoint->width/w); } sub_v3_v3v3(spoint->co1, spoint->co, cross); add_v3_v3v3(spoint->co2, spoint->co, cross); copy_v3_v3(spoint->dsco, cross); }
static void setNearestAxis3d(TransInfo *t) { float zfac; float mvec[3], axis[3], proj[3]; float len[3]; int i, icoord[2]; /* calculate mouse movement */ mvec[0] = (float)(t->mval[0] - t->con.imval[0]); mvec[1] = (float)(t->mval[1] - t->con.imval[1]); mvec[2] = 0.0f; /* we need to correct axis length for the current zoomlevel of view, * this to prevent projected values to be clipped behind the camera * and to overflow the short integers. * The formula used is a bit stupid, just a simplification of the subtraction * of two 2D points 30 pixels apart (that's the last factor in the formula) after * projecting them with window_to_3d_delta and then get the length of that vector. */ zfac = t->persmat[0][3] * t->center[0] + t->persmat[1][3] * t->center[1] + t->persmat[2][3] * t->center[2] + t->persmat[3][3]; zfac = len_v3(t->persinv[0]) * 2.0f / t->ar->winx * zfac * 30.0f; for (i = 0; i < 3; i++) { copy_v3_v3(axis, t->con.mtx[i]); mul_v3_fl(axis, zfac); /* now we can project to get window coordinate */ add_v3_v3(axis, t->con.center); projectIntView(t, axis, icoord); axis[0] = (float)(icoord[0] - t->center2d[0]); axis[1] = (float)(icoord[1] - t->center2d[1]); axis[2] = 0.0f; if (normalize_v3(axis) != 0.0f) { project_v3_v3v3(proj, mvec, axis); sub_v3_v3v3(axis, mvec, proj); len[i] = normalize_v3(axis); } else { len[i] = 10000000000.0f; } } if (len[0] <= len[1] && len[0] <= len[2]) { if (t->modifiers & MOD_CONSTRAINT_PLANE) { t->con.mode |= (CON_AXIS1 | CON_AXIS2); BLI_snprintf(t->con.text, sizeof(t->con.text), " locking %s X axis", t->spacename); } else { t->con.mode |= CON_AXIS0; BLI_snprintf(t->con.text, sizeof(t->con.text), " along %s X axis", t->spacename); } } else if (len[1] <= len[0] && len[1] <= len[2]) { if (t->modifiers & MOD_CONSTRAINT_PLANE) { t->con.mode |= (CON_AXIS0 | CON_AXIS2); BLI_snprintf(t->con.text, sizeof(t->con.text), " locking %s Y axis", t->spacename); } else { t->con.mode |= CON_AXIS1; BLI_snprintf(t->con.text, sizeof(t->con.text), " along %s Y axis", t->spacename); } } else if (len[2] <= len[1] && len[2] <= len[0]) { if (t->modifiers & MOD_CONSTRAINT_PLANE) { t->con.mode |= (CON_AXIS0 | CON_AXIS1); BLI_snprintf(t->con.text, sizeof(t->con.text), " locking %s Z axis", t->spacename); } else { t->con.mode |= CON_AXIS2; BLI_snprintf(t->con.text, sizeof(t->con.text), " along %s Z axis", t->spacename); } } }
/* 0 == do center, 1 == center new, 2 == center cursor */ void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int centermode, int around) { Object *obedit = scene->obedit; // XXX get from context EditBone *ebone; bArmature *arm = ob->data; float cent[3]; /* Put the armature into editmode */ if (ob != obedit) { ED_armature_to_edit(ob); obedit = NULL; /* we cant use this so behave as if there is no obedit */ } /* Find the centerpoint */ if (centermode == 2) { copy_v3_v3(cent, cursor); invert_m4_m4(ob->imat, ob->obmat); mul_m4_v3(ob->imat, cent); } else { if (around == V3D_CENTROID) { int total = 0; zero_v3(cent); for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { total += 2; add_v3_v3(cent, ebone->head); add_v3_v3(cent, ebone->tail); } if (total) { mul_v3_fl(cent, 1.0f / (float)total); } } else { float min[3], max[3]; INIT_MINMAX(min, max); for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { minmax_v3v3_v3(min, max, ebone->head); minmax_v3v3_v3(min, max, ebone->tail); } mid_v3_v3v3(cent, min, max); } } /* Do the adjustments */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { sub_v3_v3(ebone->head, cent); sub_v3_v3(ebone->tail, cent); } /* Turn the list into an armature */ if (obedit == NULL) { ED_armature_from_edit(ob); ED_armature_edit_free(ob); } /* Adjust object location for new centerpoint */ if (centermode && obedit == NULL) { mul_mat3_m4_v3(ob->obmat, cent); /* ommit translation part */ add_v3_v3(ob->loc, cent); } }
static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(quad), int x, int y, float UNUSED(u), float UNUSED(v), float *tvn, float *ttang) { BakeShade *bs = handle; ShadeSample *ssamp = &bs->ssamp; ShadeResult shr; VlakRen *vlr = shi->vlr; shade_input_init_material(shi); if (bs->type == RE_BAKE_AO) { ambient_occlusion(shi); if (R.r.bake_flag & R_BAKE_NORMALIZE) { copy_v3_v3(shr.combined, shi->ao); } else { zero_v3(shr.combined); environment_lighting_apply(shi, &shr); } } else { if (bs->type == RE_BAKE_SHADOW) /* Why do shadows set the color anyhow?, ignore material color for baking */ shi->r = shi->g = shi->b = 1.0f; shade_input_set_shade_texco(shi); /* only do AO for a full bake (and obviously AO bakes) * AO for light bakes is a leftover and might not be needed */ if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT)) shade_samples_do_AO(ssamp); if (shi->mat->nodetree && shi->mat->use_nodes) { ntreeShaderExecTree(shi->mat->nodetree, shi, &shr); shi->mat = vlr->mat; /* shi->mat is being set in nodetree */ } else shade_material_loop(shi, &shr); if (bs->type == RE_BAKE_NORMALS) { float nor[3]; copy_v3_v3(nor, shi->vn); if (R.r.bake_normal_space == R_BAKE_SPACE_CAMERA) { /* pass */ } else if (R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) { float mat[3][3], imat[3][3]; /* bitangent */ if (tvn && ttang) { copy_v3_v3(mat[0], ttang); cross_v3_v3v3(mat[1], tvn, ttang); mul_v3_fl(mat[1], ttang[3]); copy_v3_v3(mat[2], tvn); } else { copy_v3_v3(mat[0], shi->nmaptang); cross_v3_v3v3(mat[1], shi->nmapnorm, shi->nmaptang); mul_v3_fl(mat[1], shi->nmaptang[3]); copy_v3_v3(mat[2], shi->nmapnorm); } invert_m3_m3(imat, mat); mul_m3_v3(imat, nor); } else if (R.r.bake_normal_space == R_BAKE_SPACE_OBJECT) mul_mat3_m4_v3(ob->imat_ren, nor); /* ob->imat_ren includes viewinv! */ else if (R.r.bake_normal_space == R_BAKE_SPACE_WORLD) mul_mat3_m4_v3(R.viewinv, nor); normalize_v3(nor); /* in case object has scaling */ /* The invert of the red channel is to make * the normal map compliant with the outside world. * It needs to be done because in Blender * the normal used in the renderer points inward. It is generated * this way in calc_vertexnormals(). Should this ever change * this negate must be removed. * * there is also a small 1e-5f bias for precision issues. otherwise * we randomly get 127 or 128 for neutral colors. we choose 128 * because it is the convention flat color. * */ shr.combined[0] = (-nor[0]) / 2.0f + 0.5f + 1e-5f; shr.combined[1] = nor[1] / 2.0f + 0.5f + 1e-5f; shr.combined[2] = nor[2] / 2.0f + 0.5f + 1e-5f; } else if (bs->type == RE_BAKE_TEXTURE) { copy_v3_v3(shr.combined, &shi->r); shr.alpha = shi->alpha; } else if (bs->type == RE_BAKE_SHADOW) { copy_v3_v3(shr.combined, shr.shad); shr.alpha = shi->alpha; } else if (bs->type == RE_BAKE_SPEC_COLOR) { copy_v3_v3(shr.combined, &shi->specr); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_SPEC_INTENSITY) { copy_v3_fl(shr.combined, shi->spec); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_MIRROR_COLOR) { copy_v3_v3(shr.combined, &shi->mirr); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_MIRROR_INTENSITY) { copy_v3_fl(shr.combined, shi->ray_mirror); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_ALPHA) { copy_v3_fl(shr.combined, shi->alpha); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_EMIT) { copy_v3_fl(shr.combined, shi->emit); shr.alpha = 1.0f; } else if (bs->type == RE_BAKE_VERTEX_COLORS) { copy_v3_v3(shr.combined, shi->vcol); shr.alpha = shi->vcol[3]; } } if (bs->rect_float && !bs->vcol) { float *col = bs->rect_float + 4 * (bs->rectx * y + x); copy_v3_v3(col, shr.combined); if (bs->type == RE_BAKE_ALL || bs->type == RE_BAKE_TEXTURE || bs->type == RE_BAKE_VERTEX_COLORS) { col[3] = shr.alpha; } else { col[3] = 1.0; } } else { /* Target is char (LDR). */ unsigned char col[4]; if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) { float rgb[3]; copy_v3_v3(rgb, shr.combined); if (R.scene_color_manage) { /* Vertex colors have no way to specify color space, so they * default to sRGB. */ if (!bs->vcol) IMB_colormanagement_scene_linear_to_colorspace_v3(rgb, bs->rect_colorspace); else linearrgb_to_srgb_v3_v3(rgb, rgb); } rgb_float_to_uchar(col, rgb); } else { rgb_float_to_uchar(col, shr.combined); } if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE, RE_BAKE_VERTEX_COLORS)) { col[3] = FTOCHAR(shr.alpha); } else { col[3] = 255; } if (bs->vcol) { /* Vertex color baking. Vcol has no useful alpha channel (it exists * but is used only for vertex painting). */ bs->vcol->r = col[0]; bs->vcol->g = col[1]; bs->vcol->b = col[2]; } else { unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x); copy_v4_v4_char((char *)imcol, (char *)col); } } if (bs->rect_mask) { bs->rect_mask[bs->rectx * y + x] = FILTER_MASK_USED; } if (bs->do_update) { *bs->do_update = true; } }