Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/object_dupli.c
| Show First 20 Lines • Show All 305 Lines • ▼ Show 20 Lines | static void make_duplis_collection(const DupliContext *ctx) | ||||
| FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | ||||
| } | } | ||||
| static const DupliGenerator gen_dupli_collection = { | static const DupliGenerator gen_dupli_collection = { | ||||
| OB_DUPLICOLLECTION, /* type */ | OB_DUPLICOLLECTION, /* type */ | ||||
| make_duplis_collection /* make_duplis */ | make_duplis_collection /* make_duplis */ | ||||
| }; | }; | ||||
| /* OB_DUPLIFRAMES */ | |||||
| static void make_duplis_frames(const DupliContext *ctx) | |||||
| { | |||||
| Depsgraph *depsgraph = ctx->depsgraph; | |||||
| Scene *scene = ctx->scene; | |||||
| Object *ob = ctx->object; | |||||
| Object copyob; | |||||
| int dupend = ob->dupend; | |||||
| /* dupliframes not supported inside collections */ | |||||
| if (ctx->collection) | |||||
| return; | |||||
| /* if we don't have any data/settings which will lead to object movement, | |||||
| * don't waste time trying, as it will all look the same... | |||||
| */ | |||||
| if (ob->parent == NULL && BLI_listbase_is_empty(&ob->constraints) && ob->adt == NULL) | |||||
| return; | |||||
| /* make a copy of the object's original data (before any dupli-data overwrites it) | |||||
| * as we'll need this to keep track of unkeyed data | |||||
| * - this doesn't take into account other data that can be reached from the object, | |||||
| * for example it's shapekeys or bones, hence the need for an update flush at the end | |||||
| */ | |||||
| copyob = *ob; | |||||
| /* duplicate over the required range */ | |||||
| const int dupli_transflag = (ob->transflag & OB_DUPLINOSPEED); | |||||
| for (int frame = ob->dupsta; frame <= dupend; frame++) { | |||||
| int ok = 1; | |||||
| /* - dupoff = how often a frames within the range shouldn't be made into duplis | |||||
| * - dupon = the length of each "skipping" block in frames | |||||
| */ | |||||
| if (ob->dupoff) { | |||||
| ok = frame - ob->dupsta; | |||||
| ok = ok % (ob->dupon + ob->dupoff); | |||||
| ok = (ok < ob->dupon); | |||||
| } | |||||
| if (ok) { | |||||
| /* WARNING: doing animation updates in this way is not terribly accurate, as the dependencies | |||||
| * and/or other objects which may affect this object's transforms are not updated either. | |||||
| * However, this has always been the way that this worked (i.e. pre 2.5), so I guess that it'll be fine! | |||||
| */ | |||||
| /* ob-eval will do drivers, so we don't need to do them */ | |||||
| BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, (float)frame, ADT_RECALC_ANIM); | |||||
| BKE_object_where_is_calc_time_for_dupli(depsgraph, scene, ob, (float)frame, dupli_transflag); | |||||
| make_dupli(ctx, ob, ob->obmat, frame); | |||||
| } | |||||
| } | |||||
| /* ob-eval will do drivers, so we don't need to do them */ | |||||
| const float original_ctime = DEG_get_ctime(depsgraph); | |||||
| BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, original_ctime, ADT_RECALC_ANIM); | |||||
| BKE_object_where_is_calc_time(depsgraph, scene, ob, original_ctime); | |||||
| /* but, to make sure unkeyed object transforms are still sane, | |||||
| * let's copy object's original data back over | |||||
| */ | |||||
| *ob = copyob; | |||||
| } | |||||
| static const DupliGenerator gen_dupli_frames = { | |||||
| OB_DUPLIFRAMES, /* type */ | |||||
| make_duplis_frames /* make_duplis */ | |||||
| }; | |||||
| /* OB_DUPLIVERTS */ | /* OB_DUPLIVERTS */ | ||||
| typedef struct VertexDupliData { | typedef struct VertexDupliData { | ||||
| Mesh *me_eval; | Mesh *me_eval; | ||||
| BMEditMesh *edit_btmesh; | BMEditMesh *edit_btmesh; | ||||
| int totvert; | int totvert; | ||||
| float (*orco)[3]; | float (*orco)[3]; | ||||
| bool use_rotation; | bool use_rotation; | ||||
| ▲ Show 20 Lines • Show All 396 Lines • ▼ Show 20 Lines | |||||
| static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem *psys) | static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem *psys) | ||||
| { | { | ||||
| Scene *scene = ctx->scene; | Scene *scene = ctx->scene; | ||||
| Object *par = ctx->object; | Object *par = ctx->object; | ||||
| eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); | eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); | ||||
| bool for_render = mode == DAG_EVAL_RENDER; | bool for_render = mode == DAG_EVAL_RENDER; | ||||
| bool use_texcoords = for_render; | bool use_texcoords = for_render; | ||||
| Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL; | Object *ob = NULL, **oblist = NULL; | ||||
| DupliObject *dob; | DupliObject *dob; | ||||
| ParticleDupliWeight *dw; | ParticleDupliWeight *dw; | ||||
| ParticleSettings *part; | ParticleSettings *part; | ||||
| ParticleData *pa; | ParticleData *pa; | ||||
| ChildParticle *cpa = NULL; | ChildParticle *cpa = NULL; | ||||
| ParticleKey state; | ParticleKey state; | ||||
| ParticleCacheKey *cache; | ParticleCacheKey *cache; | ||||
| float ctime, pa_time, scale = 1.0f; | float ctime, scale = 1.0f; | ||||
| float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0; | float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0; | ||||
| float (*obmat)[4]; | float (*obmat)[4]; | ||||
| int a, b, hair = 0; | int a, b, hair = 0; | ||||
| int totpart, totchild; | int totpart, totchild; | ||||
| int no_draw_flag = PARS_UNEXIST; | int no_draw_flag = PARS_UNEXIST; | ||||
| if (psys == NULL) return; | if (psys == NULL) return; | ||||
| ▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | if (part->ren_as == PART_DRAW_GR) { | ||||
| FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode) | FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode) | ||||
| { | { | ||||
| (void) object; | (void) object; | ||||
| totcollection++; | totcollection++; | ||||
| } | } | ||||
| FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | ||||
| } | } | ||||
| /* we also copy the actual objects to restore afterwards, since | |||||
| * BKE_object_where_is_calc_time will change the object which breaks transform */ | |||||
| oblist = MEM_callocN((size_t)totcollection * sizeof(Object *), "dupcollection object list"); | oblist = MEM_callocN((size_t)totcollection * sizeof(Object *), "dupcollection object list"); | ||||
| obcopylist = MEM_callocN((size_t)totcollection * sizeof(Object), "dupcollection copy list"); | |||||
| if (part->draw & PART_DRAW_COUNT_GR) { | if (part->draw & PART_DRAW_COUNT_GR) { | ||||
| a = 0; | a = 0; | ||||
| for (dw = part->dupliweights.first; dw; dw = dw->next) { | for (dw = part->dupliweights.first; dw; dw = dw->next) { | ||||
| FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode) | FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode) | ||||
| { | { | ||||
| if (dw->ob == object) { | if (dw->ob == object) { | ||||
| for (b = 0; b < dw->count; b++, a++) { | for (b = 0; b < dw->count; b++, a++) { | ||||
| oblist[a] = dw->ob; | oblist[a] = dw->ob; | ||||
| obcopylist[a] = *dw->ob; | |||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| a = 0; | a = 0; | ||||
| FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode) | FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode) | ||||
| { | { | ||||
| oblist[a] = object; | oblist[a] = object; | ||||
| obcopylist[a] = *object; | |||||
| a++; | a++; | ||||
| } | } | ||||
| FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| ob = part->dup_ob; | ob = part->dup_ob; | ||||
| obcopy = *ob; | |||||
| } | } | ||||
| if (totchild == 0 || part->draw & PART_DRAW_PARENT) | if (totchild == 0 || part->draw & PART_DRAW_PARENT) | ||||
| a = 0; | a = 0; | ||||
| else | else | ||||
| a = totpart; | a = totpart; | ||||
| for (pa = psys->particles; a < totpart + totchild; a++, pa++) { | for (pa = psys->particles; a < totpart + totchild; a++, pa++) { | ||||
| if (a < totpart) { | if (a < totpart) { | ||||
| /* handle parent particle */ | /* handle parent particle */ | ||||
| if (pa->flag & no_draw_flag) | if (pa->flag & no_draw_flag) | ||||
| continue; | continue; | ||||
| /* pa_num = pa->num; */ /* UNUSED */ | /* pa_num = pa->num; */ /* UNUSED */ | ||||
| pa_time = pa->time; | |||||
| size = pa->size; | size = pa->size; | ||||
| } | } | ||||
| else { | else { | ||||
| /* handle child particle */ | /* handle child particle */ | ||||
| cpa = &psys->child[a - totpart]; | cpa = &psys->child[a - totpart]; | ||||
| /* pa_num = a; */ /* UNUSED */ | /* pa_num = a; */ /* UNUSED */ | ||||
| pa_time = psys->particles[cpa->parent].time; | |||||
| size = psys_get_child_size(psys, cpa, ctime, NULL); | size = psys_get_child_size(psys, cpa, ctime, NULL); | ||||
| } | } | ||||
| /* some hair paths might be non-existent so they can't be used for duplication */ | /* some hair paths might be non-existent so they can't be used for duplication */ | ||||
| if (hair && psys->pathcache && | if (hair && psys->pathcache && | ||||
| ((a < totpart && psys->pathcache[a]->segments < 0) || | ((a < totpart && psys->pathcache[a]->segments < 0) || | ||||
| (a >= totpart && psys->childcache[a - totpart]->segments < 0))) | (a >= totpart && psys->childcache[a - totpart]->segments < 0))) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | for (pa = psys->particles; a < totpart + totchild; a++, pa++) { | ||||
| psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); | psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); | ||||
| } | } | ||||
| b++; | b++; | ||||
| } | } | ||||
| FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | ||||
| } | } | ||||
| else { | else { | ||||
| /* to give ipos in object correct offset */ | |||||
| BKE_object_where_is_calc_time(ctx->depsgraph, scene, ob, ctime - pa_time); | |||||
| copy_v3_v3(vec, obmat[3]); | copy_v3_v3(vec, obmat[3]); | ||||
| obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f; | obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f; | ||||
| /* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */ | /* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */ | ||||
| if ((part->draw & PART_DRAW_ROTATE_OB) == 0) { | if ((part->draw & PART_DRAW_ROTATE_OB) == 0) { | ||||
| float xvec[3], q[4], size_mat[4][4], original_size[3]; | float xvec[3], q[4], size_mat[4][4], original_size[3]; | ||||
| mat4_to_size(original_size, obmat); | mat4_to_size(original_size, obmat); | ||||
| Show All 30 Lines | for (pa = psys->particles; a < totpart + totchild; a++, pa++) { | ||||
| dob = make_dupli(ctx, ob, mat, a); | dob = make_dupli(ctx, ob, mat, a); | ||||
| dob->particle_system = psys; | dob->particle_system = psys; | ||||
| if (use_texcoords) | if (use_texcoords) | ||||
| psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); | psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); | ||||
| } | } | ||||
| } | } | ||||
| /* restore objects since they were changed in BKE_object_where_is_calc_time */ | |||||
| if (part->ren_as == PART_DRAW_GR) { | |||||
| for (a = 0; a < totcollection; a++) | |||||
| *(oblist[a]) = obcopylist[a]; | |||||
| } | |||||
| else | |||||
| *ob = obcopy; | |||||
| BLI_rng_free(rng); | BLI_rng_free(rng); | ||||
| } | } | ||||
| /* clean up */ | /* clean up */ | ||||
| if (oblist) | if (oblist) | ||||
| MEM_freeN(oblist); | MEM_freeN(oblist); | ||||
| if (obcopylist) | |||||
| MEM_freeN(obcopylist); | |||||
| if (psys->lattice_deform_data) { | if (psys->lattice_deform_data) { | ||||
| end_latt_deform(psys->lattice_deform_data); | end_latt_deform(psys->lattice_deform_data); | ||||
| psys->lattice_deform_data = NULL; | psys->lattice_deform_data = NULL; | ||||
| } | } | ||||
| } | } | ||||
| static void make_duplis_particles(const DupliContext *ctx) | static void make_duplis_particles(const DupliContext *ctx) | ||||
| Show All 40 Lines | else if (transflag & OB_DUPLIVERTS) { | ||||
| else if (ctx->object->type == OB_FONT) { | else if (ctx->object->type == OB_FONT) { | ||||
| return &gen_dupli_verts_font; | return &gen_dupli_verts_font; | ||||
| } | } | ||||
| } | } | ||||
| else if (transflag & OB_DUPLIFACES) { | else if (transflag & OB_DUPLIFACES) { | ||||
| if (ctx->object->type == OB_MESH) | if (ctx->object->type == OB_MESH) | ||||
| return &gen_dupli_faces; | return &gen_dupli_faces; | ||||
| } | } | ||||
| else if (transflag & OB_DUPLIFRAMES) { | |||||
| return &gen_dupli_frames; | |||||
| } | |||||
| else if (transflag & OB_DUPLICOLLECTION) { | else if (transflag & OB_DUPLICOLLECTION) { | ||||
| return &gen_dupli_collection; | return &gen_dupli_collection; | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| Show All 35 Lines | if (ob->transflag & OB_DUPLIVERTS) { | ||||
| Mesh *me = ob->data; | Mesh *me = ob->data; | ||||
| return me->totvert; | return me->totvert; | ||||
| } | } | ||||
| else | else | ||||
| return pdup; | return pdup; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if (ob->transflag & OB_DUPLIFRAMES) { | |||||
| int tot = ob->dupend - ob->dupsta; | |||||
| tot /= (ob->dupon + ob->dupoff); | |||||
| return tot * ob->dupon; | |||||
| } | |||||
| } | } | ||||
| return 1; | return 1; | ||||
| } | } | ||||