static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], const float nor_f[3], const short nor_s[3]) { const VertexDupliData *vdd = userData; Object *inst_ob = vdd->inst_ob; DupliObject *dob; float obmat[4][4], space_mat[4][4]; /* obmat is transform to vertex */ get_duplivert_transform(co, nor_f, nor_s, vdd->use_rotation, inst_ob->trackflag, inst_ob->upflag, obmat); /* make offset relative to inst_ob using relative child transform */ mul_mat3_m4_v3((float (*)[4])vdd->child_imat, obmat[3]); /* apply obmat _after_ the local vertex transform */ mul_m4_m4m4(obmat, inst_ob->obmat, obmat); /* space matrix is constructed by removing obmat transform, * this yields the worldspace transform for recursive duplis */ mul_m4_m4m4(space_mat, obmat, inst_ob->imat); dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index, false, false); if (vdd->orco) copy_v3_v3(dob->orco, vdd->orco[index]); /* recursion */ make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index, false); }
/* OB_DUPLIGROUP */ static void make_duplis_group(const DupliContext *ctx) { bool for_render = ctx->eval_ctx->for_render; Object *ob = ctx->object; Group *group; GroupObject *go; float group_mat[4][4]; int id; bool animated, hide; if (ob->dup_group == NULL) return; group = ob->dup_group; /* combine group offset and obmat */ unit_m4(group_mat); sub_v3_v3(group_mat[3], group->dupli_ofs); mul_m4_m4m4(group_mat, ob->obmat, group_mat); /* don't access 'ob->obmat' from now on. */ /* handles animated groups */ /* we need to check update for objects that are not in scene... */ if (ctx->do_update) { /* note: update is optional because we don't always need object * transformations to be correct. Also fixes bug [#29616]. */ BKE_group_handle_recalc_and_update(ctx->eval_ctx, ctx->scene, ob, group); } animated = BKE_group_is_animated(group, ob); for (go = group->gobject.first, id = 0; go; go = go->next, id++) { /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */ if (go->ob != ob) { float mat[4][4]; /* group dupli offset, should apply after everything else */ mul_m4_m4m4(mat, group_mat, go->ob->obmat); /* check the group instance and object layers match, also that the object visible flags are ok. */ hide = (go->ob->lay & group->layer) == 0 || (for_render ? go->ob->restrictflag & OB_RESTRICT_RENDER : go->ob->restrictflag & OB_RESTRICT_VIEW); make_dupli(ctx, go->ob, mat, id, animated, hide); /* recursion */ make_recursive_duplis(ctx, go->ob, group_mat, id, animated); } } }
/* OB_DUPLIPARTS */ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem *psys) { Scene *scene = ctx->scene; Object *par = ctx->object; bool for_render = ctx->eval_ctx->mode == DAG_EVAL_RENDER; bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW); GroupObject *go; Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL; DupliObject *dob; ParticleDupliWeight *dw; ParticleSettings *part; ParticleData *pa; ChildParticle *cpa = NULL; ParticleKey state; ParticleCacheKey *cache; float ctime, pa_time, scale = 1.0f; float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0; float (*obmat)[4]; int a, b, hair = 0; int totpart, totchild, totgroup = 0 /*, pa_num */; const bool dupli_type_hack = !BKE_scene_use_new_shading_nodes(scene); int no_draw_flag = PARS_UNEXIST; if (psys == NULL) return; part = psys->part; if (part == NULL) return; if (!psys_check_enabled(par, psys)) return; if (!for_render) no_draw_flag |= PARS_NO_DISP; ctime = BKE_scene_frame_get(scene); /* NOTE: in old animsys, used parent object's timeoffset... */ totpart = psys->totpart; totchild = psys->totchild; BLI_srandom((unsigned int)(31415926 + psys->seed)); if ((psys->renderdata || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { ParticleSimulationData sim = {NULL}; sim.scene = scene; sim.ob = par; sim.psys = psys; sim.psmd = psys_get_modifier(par, psys); /* make sure emitter imat is in global coordinates instead of render view coordinates */ invert_m4_m4(par->imat, par->obmat); /* first check for loops (particle system object used as dupli object) */ if (part->ren_as == PART_DRAW_OB) { if (ELEM(part->dup_ob, NULL, par)) return; } else { /*PART_DRAW_GR */ if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->gobject)) return; if (BLI_findptr(&part->dup_group->gobject, par, offsetof(GroupObject, ob))) { return; } } /* if we have a hair particle system, use the path cache */ if (part->type == PART_HAIR) { if (psys->flag & PSYS_HAIR_DONE) hair = (totchild == 0 || psys->childcache) && psys->pathcache; if (!hair) return; /* we use cache, update totchild according to cached data */ totchild = psys->totchildcache; totpart = psys->totcached; } psys_check_group_weights(part); psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); /* gather list of objects or single object */ if (part->ren_as == PART_DRAW_GR) { if (ctx->do_update) { BKE_group_handle_recalc_and_update(ctx->eval_ctx, scene, par, part->dup_group); } if (part->draw & PART_DRAW_COUNT_GR) { for (dw = part->dupliweights.first; dw; dw = dw->next) totgroup += dw->count; } else { for (go = part->dup_group->gobject.first; go; go = go->next) totgroup++; } /* we also copy the actual objects to restore afterwards, since * BKE_object_where_is_calc_time will change the object which breaks transform */ oblist = MEM_callocN((size_t)totgroup * sizeof(Object *), "dupgroup object list"); obcopylist = MEM_callocN((size_t)totgroup * sizeof(Object), "dupgroup copy list"); if (part->draw & PART_DRAW_COUNT_GR && totgroup) { dw = part->dupliweights.first; for (a = 0; a < totgroup; dw = dw->next) { for (b = 0; b < dw->count; b++, a++) { oblist[a] = dw->ob; obcopylist[a] = *dw->ob; } } } else { go = part->dup_group->gobject.first; for (a = 0; a < totgroup; a++, go = go->next) { oblist[a] = go->ob; obcopylist[a] = *go->ob; } } } else { ob = part->dup_ob; obcopy = *ob; } if (totchild == 0 || part->draw & PART_DRAW_PARENT) a = 0; else a = totpart; for (pa = psys->particles; a < totpart + totchild; a++, pa++) { if (a < totpart) { /* handle parent particle */ if (pa->flag & no_draw_flag) continue; /* pa_num = pa->num; */ /* UNUSED */ pa_time = pa->time; size = pa->size; } else { /* handle child particle */ cpa = &psys->child[a - totpart]; /* pa_num = a; */ /* UNUSED */ pa_time = psys->particles[cpa->parent].time; size = psys_get_child_size(psys, cpa, ctime, NULL); } /* some hair paths might be non-existent so they can't be used for duplication */ if (hair && psys->pathcache && ((a < totpart && psys->pathcache[a]->segments < 0) || (a >= totpart && psys->childcache[a - totpart]->segments < 0))) { continue; } if (part->ren_as == PART_DRAW_GR) { /* prevent divide by zero below [#28336] */ if (totgroup == 0) continue; /* for groups, pick the object based on settings */ if (part->draw & PART_DRAW_RAND_GR) b = BLI_rand() % totgroup; else b = a % totgroup; ob = oblist[b]; obmat = oblist[b]->obmat; } else { obmat = ob->obmat; } if (hair) { /* hair we handle separate and compute transform based on hair keys */ if (a < totpart) { cache = psys->pathcache[a]; psys_get_dupli_path_transform(&sim, pa, NULL, cache, pamat, &scale); } else { cache = psys->childcache[a - totpart]; psys_get_dupli_path_transform(&sim, NULL, cpa, cache, pamat, &scale); } copy_v3_v3(pamat[3], cache->co); pamat[3][3] = 1.0f; } else { /* first key */ state.time = ctime; if (psys_get_particle_state(&sim, a, &state, 0) == 0) { continue; } else { float tquat[4]; normalize_qt_qt(tquat, state.rot); quat_to_mat4(pamat, tquat); copy_v3_v3(pamat[3], state.co); pamat[3][3] = 1.0f; } } if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { for (go = part->dup_group->gobject.first, b = 0; go; go = go->next, b++) { copy_m4_m4(tmat, oblist[b]->obmat); /* apply particle scale */ mul_mat3_m4_fl(tmat, size * scale); mul_v3_fl(tmat[3], size * scale); /* group dupli offset, should apply after everything else */ if (!is_zero_v3(part->dup_group->dupli_ofs)) sub_v3_v3(tmat[3], part->dup_group->dupli_ofs); /* individual particle transform */ mul_m4_m4m4(mat, pamat, tmat); dob = make_dupli(ctx, go->ob, mat, a, false, false); dob->particle_system = psys; if (use_texcoords) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } } else { /* to give ipos in object correct offset */ BKE_object_where_is_calc_time(scene, ob, ctime - pa_time); copy_v3_v3(vec, obmat[3]); obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f; /* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */ if ((part->draw & PART_DRAW_ROTATE_OB) == 0) { float xvec[3], q[4], size_mat[4][4], original_size[3]; mat4_to_size(original_size, obmat); size_to_mat4(size_mat, original_size); xvec[0] = -1.f; xvec[1] = xvec[2] = 0; vec_to_quat(q, xvec, ob->trackflag, ob->upflag); quat_to_mat4(obmat, q); obmat[3][3] = 1.0f; /* add scaling if requested */ if ((part->draw & PART_DRAW_NO_SCALE_OB) == 0) mul_m4_m4m4(obmat, obmat, size_mat); } else if (part->draw & PART_DRAW_NO_SCALE_OB) { /* remove scaling */ float size_mat[4][4], original_size[3]; mat4_to_size(original_size, obmat); size_to_mat4(size_mat, original_size); invert_m4(size_mat); mul_m4_m4m4(obmat, obmat, size_mat); } mul_m4_m4m4(tmat, pamat, obmat); mul_mat3_m4_fl(tmat, size * scale); copy_m4_m4(mat, tmat); if (part->draw & PART_DRAW_GLOBAL_OB) add_v3_v3v3(mat[3], mat[3], vec); dob = make_dupli(ctx, ob, mat, a, false, false); dob->particle_system = psys; if (use_texcoords) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); /* XXX blender internal needs this to be set to dupligroup to render * groups correctly, but we don't want this hack for cycles */ if (dupli_type_hack && ctx->group) dob->type = OB_DUPLIGROUP; } } /* restore objects since they were changed in BKE_object_where_is_calc_time */ if (part->ren_as == PART_DRAW_GR) { for (a = 0; a < totgroup; a++) *(oblist[a]) = obcopylist[a]; } else *ob = obcopy; } /* clean up */ if (oblist) MEM_freeN(oblist); if (obcopylist) MEM_freeN(obcopylist); if (psys->lattice_deform_data) { end_latt_deform(psys->lattice_deform_data); psys->lattice_deform_data = NULL; } }
static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Object *inst_ob) { FaceDupliData *fdd = userdata; MPoly *mpoly = fdd->mpoly, *mp; MLoop *mloop = fdd->mloop; MVert *mvert = fdd->mvert; float (*orco)[3] = fdd->orco; MLoopUV *mloopuv = fdd->mloopuv; int a, totface = fdd->totface; bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW); float child_imat[4][4]; DupliObject *dob; invert_m4_m4(inst_ob->imat, inst_ob->obmat); /* relative transform from parent to child space */ mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat); for (a = 0, mp = mpoly; a < totface; a++, mp++) { MLoop *loopstart = mloop + mp->loopstart; float space_mat[4][4], obmat[4][4]; if (UNLIKELY(mp->totloop < 3)) continue; /* obmat is transform to face */ get_dupliface_transform(mp, loopstart, mvert, fdd->use_scale, ctx->object->dupfacesca, obmat); /* make offset relative to inst_ob using relative child transform */ mul_mat3_m4_v3(child_imat, obmat[3]); /* XXX ugly hack to ensure same behavior as in master * this should not be needed, parentinv is not consistent * outside of parenting. */ { float imat[3][3]; copy_m3_m4(imat, inst_ob->parentinv); mul_m4_m3m4(obmat, imat, obmat); } /* apply obmat _after_ the local face transform */ mul_m4_m4m4(obmat, inst_ob->obmat, obmat); /* space matrix is constructed by removing obmat transform, * this yields the worldspace transform for recursive duplis */ mul_m4_m4m4(space_mat, obmat, inst_ob->imat); dob = make_dupli(ctx, inst_ob, obmat, a, false, false); if (use_texcoords) { float w = 1.0f / (float)mp->totloop; if (orco) { int j; for (j = 0; j < mp->totloop; j++) { madd_v3_v3fl(dob->orco, orco[loopstart[j].v], w); } } if (mloopuv) { int j; for (j = 0; j < mp->totloop; j++) { madd_v2_v2fl(dob->uv, mloopuv[mp->loopstart + j].uv, w); } } } /* recursion */ make_recursive_duplis(ctx, inst_ob, space_mat, a, false); } }
static void make_duplis_font(const DupliContext *ctx) { Object *par = ctx->object; GHash *family_gh; Object *ob; Curve *cu; struct CharTrans *ct, *chartransdata = NULL; float vec[3], obmat[4][4], pmat[4][4], fsize, xof, yof; int text_len, a; size_t family_len; const wchar_t *text = NULL; bool text_free = false; /* font dupliverts not supported inside groups */ if (ctx->group) return; copy_m4_m4(pmat, par->obmat); /* in par the family name is stored, use this to find the other objects */ BKE_vfont_to_curve_ex(G.main, par, FO_DUPLI, NULL, &text, &text_len, &text_free, &chartransdata); if (text == NULL || chartransdata == NULL) { return; } cu = par->data; fsize = cu->fsize; xof = cu->xof; yof = cu->yof; ct = chartransdata; /* cache result */ family_len = strlen(cu->family); family_gh = BLI_ghash_int_new_ex(__func__, 256); /* advance matching BLI_strncpy_wchar_from_utf8 */ for (a = 0; a < text_len; a++, ct++) { ob = find_family_object(cu->family, family_len, (unsigned int)text[a], family_gh); if (ob) { vec[0] = fsize * (ct->xof - xof); vec[1] = fsize * (ct->yof - yof); vec[2] = 0.0; mul_m4_v3(pmat, vec); copy_m4_m4(obmat, par->obmat); if (UNLIKELY(ct->rot != 0.0f)) { float rmat[4][4]; zero_v3(obmat[3]); unit_m4(rmat); rotate_m4(rmat, 'Z', -ct->rot); mul_m4_m4m4(obmat, obmat, rmat); } copy_v3_v3(obmat[3], vec); make_dupli(ctx, ob, obmat, a, false, false); } } if (text_free) { MEM_freeN((void *)text); } BLI_ghash_free(family_gh, NULL, NULL); MEM_freeN(chartransdata); }
/* OB_DUPLIFRAMES */ static void make_duplis_frames(const DupliContext *ctx) { Scene *scene = ctx->scene; Object *ob = ctx->object; extern int enable_cu_speed; /* object.c */ Object copyob; int cfrao = scene->r.cfra; int dupend = ob->dupend; /* dupliframes not supported inside groups */ if (ctx->group) 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 */ if (ob->transflag & OB_DUPLINOSPEED) enable_cu_speed = 0; /* special flag to avoid setting recalc flags to notify the depsgraph of * updates, as this is not a permanent change to the object */ ob->id.tag |= LIB_TAG_ANIM_NO_RECALC; for (scene->r.cfra = ob->dupsta; scene->r.cfra <= dupend; scene->r.cfra++) { 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 = scene->r.cfra - 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! */ BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra); make_dupli(ctx, ob, ob->obmat, scene->r.cfra, false, false); } } enable_cu_speed = 1; /* reset frame to original frame, then re-evaluate animation as above * as 2.5 animation data may have far-reaching consequences */ scene->r.cfra = cfrao; BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra); /* but, to make sure unkeyed object transforms are still sane, * let's copy object's original data back over */ *ob = copyob; }
/* OB_DUPLIGROUP */ static void make_duplis_group(const DupliContext *ctx) { bool for_render = (ctx->eval_ctx->mode == DAG_EVAL_RENDER); Object *ob = ctx->object; Group *group; GroupObject *go; float group_mat[4][4]; int id; bool animated, hide; if (ob->dup_group == NULL) return; group = ob->dup_group; /* combine group offset and obmat */ unit_m4(group_mat); sub_v3_v3(group_mat[3], group->dupli_ofs); mul_m4_m4m4(group_mat, ob->obmat, group_mat); /* don't access 'ob->obmat' from now on. */ /* handles animated groups */ /* we need to check update for objects that are not in scene... */ if (ctx->do_update) { /* note: update is optional because we don't always need object * transformations to be correct. Also fixes bug [#29616]. */ BKE_group_handle_recalc_and_update(ctx->eval_ctx, ctx->scene, ob, group); } animated = BKE_group_is_animated(group, ob); for (go = group->gobject.first, id = 0; go; go = go->next, id++) { /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */ if (go->ob != ob) { float mat[4][4]; /* Special case for instancing dupli-groups, see: T40051 * this object may be instanced via dupli-verts/faces, in this case we don't want to render * (blender convention), but _do_ show in the viewport. * * Regular objects work fine but not if we're instancing dupli-groups, * because the rules for rendering aren't applied to objects they instance. * We could recursively pass down the 'hide' flag instead, but that seems unnecessary. */ if (for_render && go->ob->parent && go->ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES)) { continue; } /* group dupli offset, should apply after everything else */ mul_m4_m4m4(mat, group_mat, go->ob->obmat); /* check the group instance and object layers match, also that the object visible flags are ok. */ hide = (go->ob->lay & group->layer) == 0 || (for_render ? go->ob->restrictflag & OB_RESTRICT_RENDER : go->ob->restrictflag & OB_RESTRICT_VIEW); make_dupli(ctx, go->ob, mat, id, animated, hide); /* recursion */ make_recursive_duplis(ctx, go->ob, group_mat, id, animated); } } }