static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *scene, struct Object *ob, DagNode *obNode) { SmokeModifierData *smd = (SmokeModifierData *) md; Base *base; if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) { if (smd->domain->fluid_group || smd->domain->coll_group) { GroupObject *go = NULL; if (smd->domain->fluid_group) for (go = smd->domain->fluid_group->gobject.first; go; go = go->next) { if (go->ob) { SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke); /* check for initialized smoke object */ if (smd2 && (smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) { DagNode *curNode = dag_get_node(forest, go->ob); dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Smoke Flow"); } } } if (smd->domain->coll_group) for (go = smd->domain->coll_group->gobject.first; go; go = go->next) { if (go->ob) { SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke); /* check for initialized smoke object */ if (smd2 && (smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) { DagNode *curNode = dag_get_node(forest, go->ob); dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Smoke Coll"); } } } } else { base = scene->base.first; for (; base; base = base->next) { SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(base->object, eModifierType_Smoke); if (smd2 && (((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) || ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll))) { DagNode *curNode = dag_get_node(forest, base->object); dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Smoke Flow/Coll"); } } } /* add relation to all "smoke flow" force fields */ base = scene->base.first; for (; base; base = base->next) { if (base->object->pd && base->object->pd->forcefield == PFIELD_SMOKEFLOW && base->object->pd->f_source == ob) { DagNode *node2 = dag_get_node(forest, base->object); dag_add_relation(forest, obNode, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Source Object"); } } } }
static char *view3d_modeselect_pup(Scene *scene) { Object *ob= OBACT; static char string[256]; const char *title= N_("Mode: %t"); char *str = string; if(U.transopts&USER_TR_IFACE) title= BLF_gettext(title); BLI_strncpy(str, title, sizeof(string)); str += modeselect_addmode(str, N_("Object Mode"), OB_MODE_OBJECT, ICON_OBJECT_DATA); if(ob==NULL || ob->data==NULL) return string; if(ob->id.lib) return string; if(!((ID *)ob->data)->lib) { /* if active object is editable */ if ( ((ob->type == OB_MESH) || (ob->type == OB_CURVE) || (ob->type == OB_SURF) || (ob->type == OB_FONT) || (ob->type == OB_MBALL) || (ob->type == OB_LATTICE))) { str += modeselect_addmode(str, N_("Edit Mode"), OB_MODE_EDIT, ICON_EDITMODE_HLT); } else if (ob->type == OB_ARMATURE) { if (ob->mode & OB_MODE_POSE) str += modeselect_addmode(str, N_("Edit Mode"), OB_MODE_EDIT|OB_MODE_POSE, ICON_EDITMODE_HLT); else str += modeselect_addmode(str, N_("Edit Mode"), OB_MODE_EDIT, ICON_EDITMODE_HLT); } if (ob->type == OB_MESH) { str += modeselect_addmode(str, N_("Sculpt Mode"), OB_MODE_SCULPT, ICON_SCULPTMODE_HLT); str += modeselect_addmode(str, N_("Vertex Paint"), OB_MODE_VERTEX_PAINT, ICON_VPAINT_HLT); str += modeselect_addmode(str, N_("Texture Paint"), OB_MODE_TEXTURE_PAINT, ICON_TPAINT_HLT); str += modeselect_addmode(str, N_("Weight Paint"), OB_MODE_WEIGHT_PAINT, ICON_WPAINT_HLT); } } /* if active object is an armature */ if (ob->type==OB_ARMATURE) { str += modeselect_addmode(str, N_("Pose Mode"), OB_MODE_POSE, ICON_POSE_HLT); } if (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) || modifiers_findByType(ob, eModifierType_Softbody)) { str += modeselect_addmode(str, N_("Particle Mode"), OB_MODE_PARTICLE_EDIT, ICON_PARTICLEMODE); } (void)str; return (string); }
static char *view3d_modeselect_pup(Scene *scene) { Object *ob= OBACT; static char string[256]; static char formatstr[] = "|%s %%x%d %%i%d"; char *str = string; str += sprintf(str, "Mode: %%t"); str += sprintf(str, formatstr, "Object Mode", OB_MODE_OBJECT, ICON_OBJECT_DATA); if(ob==NULL || ob->data==NULL) return string; if(ob->id.lib) return string; if(!((ID *)ob->data)->lib) { /* if active object is editable */ if ( ((ob->type == OB_MESH) || (ob->type == OB_CURVE) || (ob->type == OB_SURF) || (ob->type == OB_FONT) || (ob->type == OB_MBALL) || (ob->type == OB_LATTICE))) { str += sprintf(str, formatstr, "Edit Mode", OB_MODE_EDIT, ICON_EDITMODE_HLT); } else if (ob->type == OB_ARMATURE) { if (ob->mode & OB_MODE_POSE) str += sprintf(str, formatstr, "Edit Mode", OB_MODE_EDIT|OB_MODE_POSE, ICON_EDITMODE_HLT); else str += sprintf(str, formatstr, "Edit Mode", OB_MODE_EDIT, ICON_EDITMODE_HLT); } if (ob->type == OB_MESH) { str += sprintf(str, formatstr, "Sculpt Mode", OB_MODE_SCULPT, ICON_SCULPTMODE_HLT); str += sprintf(str, formatstr, "Vertex Paint", OB_MODE_VERTEX_PAINT, ICON_VPAINT_HLT); str += sprintf(str, formatstr, "Texture Paint", OB_MODE_TEXTURE_PAINT, ICON_TPAINT_HLT); str += sprintf(str, formatstr, "Weight Paint", OB_MODE_WEIGHT_PAINT, ICON_WPAINT_HLT); } } /* if active object is an armature */ if (ob->type==OB_ARMATURE) { str += sprintf(str, formatstr, "Pose Mode", OB_MODE_POSE, ICON_POSE_HLT); } if (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) || modifiers_findByType(ob, eModifierType_Softbody)) { str += sprintf(str, formatstr, "Particle Mode", OB_MODE_PARTICLE_EDIT, ICON_PARTICLEMODE); } (void)str; return (string); }
static void updateDepgraph( ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { ClothModifierData *clmd = (ClothModifierData*) md; Base *base; if(clmd) { for(base = scene->base.first; base; base= base->next) { Object *ob1= base->object; if(ob1 != ob) { CollisionModifierData *coll_clmd = (CollisionModifierData *)modifiers_findByType(ob1, eModifierType_Collision); if(coll_clmd) { DagNode *curNode = dag_get_node(forest, ob1); dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Cloth Collision"); } } } } }
/* * Bake Dynamic Paint image sequence surface */ static int dynamicPaint_initBake(struct bContext *C, struct wmOperator *op) { DynamicPaintModifierData *pmd = NULL; DynamicPaintCanvasSettings *canvas; Object *ob = ED_object_context(C); int status = 0; double timer = PIL_check_seconds_timer(); DynamicPaintSurface *surface; /* * Get modifier data */ pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint); if (!pmd) { BKE_report(op->reports, RPT_ERROR, "Bake failed: no Dynamic Paint modifier found"); return 0; } /* Make sure we're dealing with a canvas */ canvas = pmd->canvas; if (!canvas) { BKE_report(op->reports, RPT_ERROR, "Bake failed: invalid canvas"); return 0; } surface = get_activeSurface(canvas); /* Set state to baking and init surface */ canvas->error[0] = '\0'; canvas->flags |= MOD_DPAINT_BAKING; G.is_break = FALSE; /* reset blender_test_break*/ /* Bake Dynamic Paint */ status = dynamicPaint_bakeImageSequence(C, surface, ob); /* Clear bake */ canvas->flags &= ~MOD_DPAINT_BAKING; WM_cursor_restore(CTX_wm_window(C)); dynamicPaint_freeSurfaceData(surface); /* Bake was successful: * Report for ended bake and how long it took */ if (status) { /* Format time string */ char time_str[30]; double time = PIL_check_seconds_timer() - timer; BLI_timestr(time, time_str); /* Show bake info */ BKE_reportf(op->reports, RPT_INFO, "Bake complete! (%s)", time_str); } else { if (strlen(canvas->error)) { /* If an error occurred */ BKE_reportf(op->reports, RPT_ERROR, "Bake failed: %s", canvas->error); } else { /* User canceled the bake */ BKE_report(op->reports, RPT_WARNING, "Baking canceled!"); } } return status; }
static int surface_slot_remove_exec(bContext *C, wmOperator *UNUSED(op)) { DynamicPaintModifierData *pmd = NULL; Object *obj_ctx = ED_object_context(C); DynamicPaintCanvasSettings *canvas; DynamicPaintSurface *surface; int id = 0; /* Make sure we're dealing with a canvas */ pmd = (DynamicPaintModifierData *)modifiers_findByType(obj_ctx, eModifierType_DynamicPaint); if (!pmd || !pmd->canvas) return OPERATOR_CANCELLED; canvas = pmd->canvas; surface = canvas->surfaces.first; /* find active surface and remove it */ for (; surface; surface = surface->next) { if (id == canvas->active_sur) { canvas->active_sur -= 1; dynamicPaint_freeSurface(surface); break; } id++; } dynamicPaint_resetPreview(canvas); DAG_id_tag_update(&obj_ctx->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obj_ctx); return OPERATOR_FINISHED; }
static void updateDepgraph( ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { FluidsimModifierData *fluidmd = (FluidsimModifierData *) md; Base *base; if (fluidmd && fluidmd->fss) { if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) { for (base = scene->base.first; base; base = base->next) { Object *ob1 = base->object; if (ob1 != ob) { FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(ob1, eModifierType_Fluidsim); /* only put dependencies from NON-DOMAIN fluids in here */ if (fluidmdtmp && fluidmdtmp->fss && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN)) { DagNode *curNode = dag_get_node(forest, ob1); dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Fluidsim Object"); } } } } } }
static int type_toggle_exec(bContext *C, wmOperator *op) { Object *cObject = ED_object_context(C); Scene *scene = CTX_data_scene(C); DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint); int type = RNA_enum_get(op->ptr, "type"); if (!pmd) return OPERATOR_CANCELLED; /* if type is already enabled, toggle it off */ if (type == MOD_DYNAMICPAINT_TYPE_CANVAS && pmd->canvas) { dynamicPaint_freeCanvas(pmd); } else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH && pmd->brush) { dynamicPaint_freeBrush(pmd); } /* else create a new type */ else { if (!dynamicPaint_createType(pmd, type, scene)) return OPERATOR_CANCELLED; } /* update dependency */ DAG_id_tag_update(&cObject->id, OB_RECALC_DATA); DAG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, cObject); return OPERATOR_FINISHED; }
static int surface_slot_add_exec(bContext *C, wmOperator *UNUSED(op)) { DynamicPaintModifierData *pmd = NULL; Object *cObject = ED_object_context(C); DynamicPaintCanvasSettings *canvas; DynamicPaintSurface *surface; /* Make sure we're dealing with a canvas */ pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint); if (!pmd || !pmd->canvas) return OPERATOR_CANCELLED; canvas = pmd->canvas; surface = dynamicPaint_createNewSurface(canvas, CTX_data_scene(C)); if (!surface) return OPERATOR_CANCELLED; /* set preview for this surface only and set active */ canvas->active_sur = 0; for (surface = surface->prev; surface; surface = surface->prev) { surface->flags &= ~MOD_DPAINT_PREVIEW; canvas->active_sur++; } return OPERATOR_FINISHED; }
static void set_vertex_channel(float *channel, float time, struct Scene *scene, struct FluidObject *fobj, int i) { Object *ob = fobj->object; FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); float *verts; int *tris=NULL, numVerts=0, numTris=0; int modifierIndex = BLI_findindex(&ob->modifiers, fluidmd); int framesize = (3*fobj->numVerts) + 1; int j; if (channel == NULL) return; initElbeemMesh(scene, ob, &numVerts, &verts, &numTris, &tris, 1, modifierIndex); /* don't allow mesh to change number of verts in anim sequence */ if (numVerts != fobj->numVerts) { MEM_freeN(channel); channel = NULL; return; } /* fill frame of channel with vertex locations */ for (j=0; j < (3*numVerts); j++) { channel[i*framesize + j] = verts[j]; } channel[i*framesize + framesize-1] = time; MEM_freeN(verts); MEM_freeN(tris); }
static char *rna_ClothCollisionSettings_path(PointerRNA *ptr) { Object *ob= (Object*)ptr->id.data; ModifierData *md= modifiers_findByType(ob, eModifierType_Cloth); return md ? BLI_sprintfN("modifiers[\"%s\"].collision_settings", md->name) : NULL; }
static int fluid_validate_scene(ReportList *reports, Scene *scene, Object *fsDomain) { Base *base; Object *newdomain = NULL; int channelObjCount = 0; int fluidInputCount = 0; for(base=scene->base.first; base; base= base->next) { Object *ob = base->object; FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); /* only find objects with fluid modifiers */ if (!fluidmdtmp || ob->type != OB_MESH) continue; if(fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) { /* if no initial domain object given, find another potential domain */ if (!fsDomain) { newdomain = ob; } /* if there's more than one domain, cancel */ else if (fsDomain && ob != fsDomain) { BKE_report(reports, RPT_ERROR, "There should be only one domain object."); return 0; } } /* count number of objects needed for animation channels */ if ( !ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE) ) channelObjCount++; /* count number of fluid input objects */ if (ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW)) fluidInputCount++; } if (newdomain) fsDomain = newdomain; if (!fsDomain) { BKE_report(reports, RPT_ERROR, "No domain object found."); return 0; } if (channelObjCount>=255) { BKE_report(reports, RPT_ERROR, "Cannot bake with more then 256 objects."); return 0; } if (fluidInputCount == 0) { BKE_report(reports, RPT_ERROR, "No fluid input objects in the scene."); return 0; } return 1; }
static void rna_FluidSettings_update_type(Main *bmain, Scene *scene, PointerRNA *ptr) { Object *ob = (Object*)ptr->id.data; FluidsimModifierData *fluidmd; ParticleSystemModifierData *psmd; ParticleSystem *psys; ParticleSettings *part; fluidmd = (FluidsimModifierData*)modifiers_findByType(ob, eModifierType_Fluidsim); fluidmd->fss->flag &= ~OB_FLUIDSIM_REVERSE; /* clear flag */ /* remove fluidsim particle system */ if (fluidmd->fss->type & OB_FLUIDSIM_PARTICLE) { for (psys = ob->particlesystem.first; psys; psys = psys->next) if (psys->part->type == PART_FLUID) break; if (ob->type == OB_MESH && !psys) { /* add particle system */ part = psys_new_settings("ParticleSettings", bmain); psys = MEM_callocN(sizeof(ParticleSystem), "particle_system"); part->type = PART_FLUID; psys->part = part; psys->pointcache = BKE_ptcache_add(&psys->ptcaches); psys->flag |= PSYS_ENABLED; BLI_strncpy(psys->name, "FluidParticles", sizeof(psys->name)); BLI_addtail(&ob->particlesystem,psys); /* add modifier */ psmd = (ParticleSystemModifierData*)modifier_new(eModifierType_ParticleSystem); BLI_strncpy(psmd->modifier.name, "FluidParticleSystem", sizeof(psmd->modifier.name)); psmd->psys = psys; BLI_addtail(&ob->modifiers, psmd); modifier_unique_name(&ob->modifiers, (ModifierData *)psmd); } } else { for (psys = ob->particlesystem.first; psys; psys = psys->next) { if (psys->part->type == PART_FLUID) { /* clear modifier */ psmd = psys_get_modifier(ob, psys); BLI_remlink(&ob->modifiers, psmd); modifier_free((ModifierData *)psmd); /* clear particle system */ BLI_remlink(&ob->particlesystem, psys); psys_free(ob, psys); } } } rna_fluid_update(bmain, scene, ptr); }
static void rna_cloth_pinning_changed(Main *bmain, Scene *scene, PointerRNA *ptr) { Object *ob= (Object*)ptr->id.data; // ClothSimSettings *settings = (ClothSimSettings*)ptr->data; ClothModifierData *clmd = (ClothModifierData*)modifiers_findByType(ob, eModifierType_Cloth); cloth_free_modifier(clmd); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_main_add_notifier(NC_OBJECT|ND_MODIFIER, ob); }
/* * Bake Dynamic Paint image sequence surface */ static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op) { DynamicPaintModifierData *pmd = NULL; DynamicPaintCanvasSettings *canvas; Object *ob = ED_object_context(C); Scene *scene = CTX_data_scene(C); DynamicPaintSurface *surface; /* * Get modifier data */ pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint); if (!pmd) { BKE_report(op->reports, RPT_ERROR, "Bake failed: no Dynamic Paint modifier found"); return OPERATOR_CANCELLED; } /* Make sure we're dealing with a canvas */ canvas = pmd->canvas; if (!canvas) { BKE_report(op->reports, RPT_ERROR, "Bake failed: invalid canvas"); return OPERATOR_CANCELLED; } surface = get_activeSurface(canvas); /* Set state to baking and init surface */ canvas->error[0] = '\0'; canvas->flags |= MOD_DPAINT_BAKING; DynamicPaintBakeJob *job = MEM_mallocN(sizeof(DynamicPaintBakeJob), "DynamicPaintBakeJob"); job->bmain = CTX_data_main(C); job->scene = scene; job->ob = ob; job->canvas = canvas; job->surface = surface; wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Dynamic Paint Bake", WM_JOB_PROGRESS, WM_JOB_TYPE_DPAINT_BAKE); WM_jobs_customdata_set(wm_job, job, dpaint_bake_free); WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER); WM_jobs_callbacks(wm_job, dpaint_bake_startjob, NULL, NULL, dpaint_bake_endjob); WM_set_locked_interface(CTX_wm_manager(C), true); /* Bake Dynamic Paint */ WM_jobs_start(CTX_wm_manager(C), wm_job); return OPERATOR_FINISHED; }
static void rna_fluid_find_enframe(Main *bmain, Scene *scene, PointerRNA *ptr) { Object *ob = ptr->id.data; FluidsimModifierData *fluidmd = (FluidsimModifierData*)modifiers_findByType(ob, eModifierType_Fluidsim); if (fluidmd->fss->flag & OB_FLUIDSIM_REVERSE) { fluidmd->fss->lastgoodframe = fluidsim_find_lastframe(ob, fluidmd->fss); } else { fluidmd->fss->lastgoodframe = -1; } rna_fluid_update(bmain, scene, ptr); }
static char *rna_ClothCollisionSettings_path(PointerRNA *ptr) { Object *ob = (Object *)ptr->id.data; ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth); if (md) { char name_esc[sizeof(md->name) * 2]; BLI_strescape(name_esc, md->name, sizeof(name_esc)); return BLI_sprintfN("modifiers[\"%s\"].collision_settings", name_esc); } else { return NULL; } }
static void time_draw_caches_keyframes(Main *bmain, Scene *scene, View2D *v2d, bool onlysel) { CacheFile *cache_file; for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) { cache_file->draw_flag &= ~CACHEFILE_KEYFRAME_DRAWN; } for (Base *base = scene->base.first; base; base = base->next) { Object *ob = base->object; ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache); if (md) { MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; cache_file = mcmd->cache_file; if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) { continue; } cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN; time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel); } for (bConstraint *con = ob->constraints.first; con; con = con->next) { if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) { continue; } bTransformCacheConstraint *data = con->data; cache_file = data->cache_file; if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) { continue; } cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN; time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel); } } }
static void init_frame_hair(VoxelData *vd, int UNUSED(cfra)) { Object *ob; ModifierData *md; vd->dataset = NULL; if (vd->object == NULL) return; ob = vd->object; if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_ParticleSystem))) { ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md; if (pmd->psys && pmd->psys->clmd) { vd->ok |= BPH_cloth_solver_get_texture_data(ob, pmd->psys->clmd, vd); } } }
static int output_toggle_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); Scene *scene = CTX_data_scene(C); DynamicPaintSurface *surface; DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint); int output= RNA_enum_get(op->ptr, "output"); /* currently only 1/0 */ if (!pmd || !pmd->canvas) return OPERATOR_CANCELLED; surface = get_activeSurface(pmd->canvas); /* if type is already enabled, toggle it off */ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { int exists = dynamicPaint_outputLayerExists(surface, ob, output); const char *name; if (output == 0) name = surface->output_name; else name = surface->output_name2; /* Vertex Color Layer */ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { if (!exists) ED_mesh_color_add(C, scene, ob, ob->data, name, 1); else ED_mesh_color_remove_named(C, ob, ob->data, name); } /* Vertex Weight Layer */ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) { if (!exists) { ED_vgroup_add_name(ob, name); } else { bDeformGroup *defgroup = defgroup_find_name(ob, name); if (defgroup) ED_vgroup_delete(ob, defgroup); } } } return OPERATOR_FINISHED; }
static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *scene, Object *ob, struct DepsNodeHandle *node) { ClothModifierData *clmd = (ClothModifierData *)md; if (clmd != NULL) { Base *base; for (base = scene->base.first; base; base = base->next) { Object *ob1 = base->object; if (ob1 != ob) { CollisionModifierData *coll_clmd = (CollisionModifierData *)modifiers_findByType(ob1, eModifierType_Collision); if (coll_clmd) { DEG_add_object_relation(node, ob1, DEG_OB_COMP_TRANSFORM, "Cloth Modifier"); } } } } }
static void precalculate_effector(EffectorCache *eff) { unsigned int cfra = (unsigned int)(eff->scene->r.cfra >= 0 ? eff->scene->r.cfra : -eff->scene->r.cfra); if (!eff->pd->rng) eff->pd->rng = BLI_rng_new(eff->pd->seed + cfra); else BLI_rng_srandom(eff->pd->rng, eff->pd->seed + cfra); if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type==OB_CURVE) { Curve *cu= eff->ob->data; if (cu->flag & CU_PATH) { if (eff->ob->curve_cache == NULL || eff->ob->curve_cache->path==NULL || eff->ob->curve_cache->path->data==NULL) BKE_displist_make_curveTypes(eff->scene, eff->ob, 0); if (eff->ob->curve_cache->path && eff->ob->curve_cache->path->data) { where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL); mul_m4_v3(eff->ob->obmat, eff->guide_loc); mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir); } } } else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) { eff->surmd = (SurfaceModifierData *)modifiers_findByType( eff->ob, eModifierType_Surface ); if (eff->ob->type == OB_CURVE) eff->flag |= PE_USE_NORMAL_DATA; } else if (eff->psys) psys_update_particle_tree(eff->psys, eff->scene->r.cfra); /* Store object velocity */ if (eff->ob) { float old_vel[3]; BKE_object_where_is_calc_time(eff->scene, eff->ob, cfra - 1.0f); copy_v3_v3(old_vel, eff->ob->obmat[3]); BKE_object_where_is_calc_time(eff->scene, eff->ob, cfra); sub_v3_v3v3(eff->velocity, eff->ob->obmat[3], old_vel); } }
/* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */ void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file) { for (Base *base = scene->base.first; base; base = base->next) { Object *ob = base->object; ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache); if (md) { MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; if (cache_file == mcmd->cache_file) { #ifdef WITH_ALEMBIC if (mcmd->reader != NULL) { CacheReader_free(mcmd->reader); } #endif mcmd->reader = NULL; } } for (bConstraint *con = ob->constraints.first; con; con = con->next) { if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) { continue; } bTransformCacheConstraint *data = con->data; if (cache_file == data->cache_file) { #ifdef WITH_ALEMBIC if (data->reader != NULL) { CacheReader_free(data->reader); } #endif data->reader = NULL; } } } }
int modifiers_isParticleEnabled(Object *ob) { ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleSystem); return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)); }
int modifiers_isClothEnabled(Object *ob) { ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth); return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)); }
ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type) { ModifierData *md=NULL, *new_md=NULL; ModifierTypeInfo *mti = modifierType_getInfo(type); /* only geometry objects should be able to get modifiers [#25291] */ if(!ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to Object '%s'", ob->id.name+2); return NULL; } if(mti->flags&eModifierTypeFlag_Single) { if(modifiers_findByType(ob, type)) { BKE_report(reports, RPT_WARNING, "Only one modifier of this type allowed"); return NULL; } } if(type == eModifierType_ParticleSystem) { /* don't need to worry about the new modifier's name, since that is set to the number * of particle systems which shouldn't have too many duplicates */ new_md = object_add_particle_system(scene, ob, name); } else { /* get new modifier data to add */ new_md= modifier_new(type); if(mti->flags&eModifierTypeFlag_RequiresOriginalData) { md = ob->modifiers.first; while(md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) md = md->next; BLI_insertlinkbefore(&ob->modifiers, md, new_md); } else BLI_addtail(&ob->modifiers, new_md); if(name) BLI_strncpy(new_md->name, name, sizeof(new_md->name)); /* make sure modifier data has unique name */ modifier_unique_name(&ob->modifiers, new_md); /* special cases */ if(type == eModifierType_Softbody) { if(!ob->soft) { ob->soft= sbNew(scene); ob->softflag |= OB_SB_GOAL|OB_SB_EDGES; } } else if(type == eModifierType_Collision) { if(!ob->pd) ob->pd= object_add_collision_fields(0); ob->pd->deflect= 1; DAG_scene_sort(bmain, scene); } else if(type == eModifierType_Surface) DAG_scene_sort(bmain, scene); else if(type == eModifierType_Multires) /* set totlvl from existing MDISPS layer if object already had it */ multiresModifier_set_levels_from_disps((MultiresModifierData *)new_md, ob); } DAG_id_tag_update(&ob->id, OB_RECALC_DATA); return new_md; }
int buttons_context(const bContext *C, const char *member, bContextDataResult *result) { SpaceButs *sbuts = CTX_wm_space_buts(C); ButsContextPath *path = sbuts ? sbuts->path : NULL; if (!path) return 0; /* here we handle context, getting data from precomputed path */ if (CTX_data_dir(member)) { /* in case of new shading system we skip texture_slot, complex python * UI script logic depends on checking if this is available */ if (sbuts->texuser) CTX_data_dir_set(result, buttons_context_dir + 1); else CTX_data_dir_set(result, buttons_context_dir); return 1; } else if (CTX_data_equals(member, "scene")) { /* Do not return one here if scene not found in path, in this case we want to get default context scene! */ return set_pointer_type(path, result, &RNA_Scene); } else if (CTX_data_equals(member, "world")) { set_pointer_type(path, result, &RNA_World); return 1; } else if (CTX_data_equals(member, "object")) { set_pointer_type(path, result, &RNA_Object); return 1; } else if (CTX_data_equals(member, "mesh")) { set_pointer_type(path, result, &RNA_Mesh); return 1; } else if (CTX_data_equals(member, "armature")) { set_pointer_type(path, result, &RNA_Armature); return 1; } else if (CTX_data_equals(member, "lattice")) { set_pointer_type(path, result, &RNA_Lattice); return 1; } else if (CTX_data_equals(member, "curve")) { set_pointer_type(path, result, &RNA_Curve); return 1; } else if (CTX_data_equals(member, "meta_ball")) { set_pointer_type(path, result, &RNA_MetaBall); return 1; } else if (CTX_data_equals(member, "lamp")) { set_pointer_type(path, result, &RNA_Lamp); return 1; } else if (CTX_data_equals(member, "camera")) { set_pointer_type(path, result, &RNA_Camera); return 1; } else if (CTX_data_equals(member, "speaker")) { set_pointer_type(path, result, &RNA_Speaker); return 1; } else if (CTX_data_equals(member, "material")) { set_pointer_type(path, result, &RNA_Material); return 1; } else if (CTX_data_equals(member, "texture")) { ButsContextTexture *ct = sbuts->texuser; if (ct) { /* new shading system */ CTX_data_pointer_set(result, &ct->texture->id, &RNA_Texture, ct->texture); } else { /* old shading system */ set_pointer_type(path, result, &RNA_Texture); } return 1; } else if (CTX_data_equals(member, "material_slot")) { PointerRNA *ptr = get_pointer_type(path, &RNA_Object); if (ptr) { Object *ob = ptr->data; if (ob && OB_TYPE_SUPPORT_MATERIAL(ob->type) && ob->totcol) { /* a valid actcol isn't ensured [#27526] */ int matnr = ob->actcol - 1; if (matnr < 0) matnr = 0; CTX_data_pointer_set(result, &ob->id, &RNA_MaterialSlot, &ob->mat[matnr]); } } return 1; } else if (CTX_data_equals(member, "texture_user")) { ButsContextTexture *ct = sbuts->texuser; if (!ct) return -1; /* old shading system (found but not available) */ if (ct->user && ct->user->ptr.data) { ButsTextureUser *user = ct->user; CTX_data_pointer_set(result, user->ptr.id.data, user->ptr.type, user->ptr.data); } return 1; } else if (CTX_data_equals(member, "texture_user_property")) { ButsContextTexture *ct = sbuts->texuser; if (!ct) return -1; /* old shading system (found but not available) */ if (ct->user && ct->user->ptr.data) { ButsTextureUser *user = ct->user; CTX_data_pointer_set(result, NULL, &RNA_Property, user->prop); } return 1; } else if (CTX_data_equals(member, "texture_node")) { ButsContextTexture *ct = sbuts->texuser; if (ct) { /* new shading system */ if (ct->user && ct->user->node) { CTX_data_pointer_set(result, &ct->user->ntree->id, &RNA_Node, ct->user->node); } return 1; } else { /* old shading system */ PointerRNA *ptr; if ((ptr = get_pointer_type(path, &RNA_Material))) { Material *ma = ptr->data; if (ma) { bNode *node = give_current_material_texture_node(ma); CTX_data_pointer_set(result, &ma->nodetree->id, &RNA_Node, node); } } return 1; } } else if (CTX_data_equals(member, "texture_slot")) { ButsContextTexture *ct = sbuts->texuser; PointerRNA *ptr; /* Particles slots are used in both old and new textures handling. */ if ((ptr = get_pointer_type(path, &RNA_ParticleSystem))) { ParticleSettings *part = ((ParticleSystem *)ptr->data)->part; if (part) CTX_data_pointer_set(result, &part->id, &RNA_ParticleSettingsTextureSlot, part->mtex[(int)part->texact]); } else if (ct) { return 0; /* new shading system */ } else if ((ptr = get_pointer_type(path, &RNA_Material))) { Material *ma = ptr->data; /* if we have a node material, get slot from material in material node */ if (ma && ma->use_nodes && ma->nodetree) { /* if there's an active texture node in the node tree, * then that texture is in context directly, without a texture slot */ if (give_current_material_texture_node(ma)) return 0; ma = give_node_material(ma); if (ma) CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]); else return 0; } else if (ma) { CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]); } } else if ((ptr = get_pointer_type(path, &RNA_Lamp))) { Lamp *la = ptr->data; if (la) CTX_data_pointer_set(result, &la->id, &RNA_LampTextureSlot, la->mtex[(int)la->texact]); } else if ((ptr = get_pointer_type(path, &RNA_World))) { World *wo = ptr->data; if (wo) CTX_data_pointer_set(result, &wo->id, &RNA_WorldTextureSlot, wo->mtex[(int)wo->texact]); } else if ((ptr = get_pointer_type(path, &RNA_FreestyleLineStyle))) { FreestyleLineStyle *ls = ptr->data; if (ls) CTX_data_pointer_set(result, &ls->id, &RNA_LineStyleTextureSlot, ls->mtex[(int)ls->texact]); } return 1; } else if (CTX_data_equals(member, "bone")) { set_pointer_type(path, result, &RNA_Bone); return 1; } else if (CTX_data_equals(member, "edit_bone")) { set_pointer_type(path, result, &RNA_EditBone); return 1; } else if (CTX_data_equals(member, "pose_bone")) { set_pointer_type(path, result, &RNA_PoseBone); return 1; } else if (CTX_data_equals(member, "particle_system")) { set_pointer_type(path, result, &RNA_ParticleSystem); return 1; } else if (CTX_data_equals(member, "particle_system_editable")) { if (PE_poll((bContext *)C)) set_pointer_type(path, result, &RNA_ParticleSystem); else CTX_data_pointer_set(result, NULL, &RNA_ParticleSystem, NULL); return 1; } else if (CTX_data_equals(member, "particle_settings")) { /* only available when pinned */ PointerRNA *ptr = get_pointer_type(path, &RNA_ParticleSettings); if (ptr && ptr->data) { CTX_data_pointer_set(result, ptr->id.data, &RNA_ParticleSettings, ptr->data); return 1; } else { /* get settings from active particle system instead */ ptr = get_pointer_type(path, &RNA_ParticleSystem); if (ptr && ptr->data) { ParticleSettings *part = ((ParticleSystem *)ptr->data)->part; CTX_data_pointer_set(result, ptr->id.data, &RNA_ParticleSettings, part); return 1; } } set_pointer_type(path, result, &RNA_ParticleSettings); return 1; } else if (CTX_data_equals(member, "cloth")) { PointerRNA *ptr = get_pointer_type(path, &RNA_Object); if (ptr && ptr->data) { Object *ob = ptr->data; ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth); CTX_data_pointer_set(result, &ob->id, &RNA_ClothModifier, md); return 1; } } else if (CTX_data_equals(member, "soft_body")) { PointerRNA *ptr = get_pointer_type(path, &RNA_Object); if (ptr && ptr->data) { Object *ob = ptr->data; ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody); CTX_data_pointer_set(result, &ob->id, &RNA_SoftBodyModifier, md); return 1; } } else if (CTX_data_equals(member, "fluid")) { PointerRNA *ptr = get_pointer_type(path, &RNA_Object); if (ptr && ptr->data) { Object *ob = ptr->data; ModifierData *md = modifiers_findByType(ob, eModifierType_Fluidsim); CTX_data_pointer_set(result, &ob->id, &RNA_FluidSimulationModifier, md); return 1; } } else if (CTX_data_equals(member, "smoke")) { PointerRNA *ptr = get_pointer_type(path, &RNA_Object); if (ptr && ptr->data) { Object *ob = ptr->data; ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke); CTX_data_pointer_set(result, &ob->id, &RNA_SmokeModifier, md); return 1; } } else if (CTX_data_equals(member, "collision")) { PointerRNA *ptr = get_pointer_type(path, &RNA_Object); if (ptr && ptr->data) { Object *ob = ptr->data; ModifierData *md = modifiers_findByType(ob, eModifierType_Collision); CTX_data_pointer_set(result, &ob->id, &RNA_CollisionModifier, md); return 1; } } else if (CTX_data_equals(member, "brush")) { set_pointer_type(path, result, &RNA_Brush); return 1; } else if (CTX_data_equals(member, "dynamic_paint")) { PointerRNA *ptr = get_pointer_type(path, &RNA_Object); if (ptr && ptr->data) { Object *ob = ptr->data; ModifierData *md = modifiers_findByType(ob, eModifierType_DynamicPaint); CTX_data_pointer_set(result, &ob->id, &RNA_DynamicPaintModifier, md); return 1; } } else if (CTX_data_equals(member, "line_style")) { set_pointer_type(path, result, &RNA_FreestyleLineStyle); return 1; } else { return 0; /* not found */ } return -1; /* found but not available */ }
static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par, int heat, const bool mirror) { /* This functions implements the automatic computation of vertex group * weights, either through envelopes or using a heat equilibrium. * * This function can be called both when parenting a mesh to an armature, * or in weightpaint + posemode. In the latter case selection is taken * into account and vertex weights can be mirrored. * * The mesh vertex positions used are either the final deformed coords * from the derivedmesh in weightpaint mode, the final subsurf coords * when parenting, or simply the original mesh coords. */ bArmature *arm = par->data; Bone **bonelist, *bone; bDeformGroup **dgrouplist, **dgroupflip; bDeformGroup *dgroup; bPoseChannel *pchan; Mesh *mesh; Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = NULL; float (*root)[3], (*tip)[3], (*verts)[3]; int *selected; int numbones, vertsfilled = 0, i, j, segments = 0; int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT); struct { Object *armob; void *list; int heat; } looper_data; looper_data.armob = par; looper_data.heat = heat; looper_data.list = NULL; /* count the number of skinnable bones */ numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb); if (numbones == 0) return; if (BKE_object_defgroup_data_create(ob->data) == NULL) return; /* create an array of pointer to bones that are skinnable * and fill it with all of the skinnable bones */ bonelist = MEM_callocN(numbones * sizeof(Bone *), "bonelist"); looper_data.list = bonelist; bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb); /* create an array of pointers to the deform groups that * correspond to the skinnable bones (creating them * as necessary. */ dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist"); dgroupflip = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgroupflip"); looper_data.list = dgrouplist; bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb); /* create an array of root and tip positions transformed into * global coords */ root = MEM_callocN(numbones * sizeof(float) * 3, "root"); tip = MEM_callocN(numbones * sizeof(float) * 3, "tip"); selected = MEM_callocN(numbones * sizeof(int), "selected"); for (j = 0; j < numbones; ++j) { bone = bonelist[j]; dgroup = dgrouplist[j]; /* handle bbone */ if (heat) { if (segments == 0) { segments = 1; bbone = NULL; if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) { if (bone->segments > 1) { segments = bone->segments; b_bone_spline_setup(pchan, 1, bbone_array); bbone = bbone_array; } } } segments--; } /* compute root and tip */ if (bbone) { mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]); if ((segments + 1) < bone->segments) { mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]); } else { copy_v3_v3(tip[j], bone->arm_tail); } } else { copy_v3_v3(root[j], bone->arm_head); copy_v3_v3(tip[j], bone->arm_tail); } mul_m4_v3(par->obmat, root[j]); mul_m4_v3(par->obmat, tip[j]); /* set selected */ if (wpmode) { if ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED)) selected[j] = 1; } else selected[j] = 1; /* find flipped group */ if (dgroup && mirror) { char name_flip[MAXBONENAME]; BKE_deform_flip_side_name(name_flip, dgroup->name, false); dgroupflip[j] = defgroup_find_name(ob, name_flip); } } /* create verts */ mesh = (Mesh *)ob->data; verts = MEM_callocN(mesh->totvert * sizeof(*verts), "closestboneverts"); if (wpmode) { /* if in weight paint mode, use final verts from derivedmesh */ DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); if (dm->foreachMappedVert) { mesh_get_mapped_verts_coords(dm, verts, mesh->totvert); vertsfilled = 1; } dm->release(dm); } else if (modifiers_findByType(ob, eModifierType_Subsurf)) { /* is subsurf on? Lets use the verts on the limit surface then. * = same amount of vertices as mesh, but vertices moved to the * subsurfed position, like for 'optimal'. */ subsurf_calculate_limit_positions(mesh, verts); vertsfilled = 1; } /* transform verts to global space */ for (i = 0; i < mesh->totvert; i++) { if (!vertsfilled) copy_v3_v3(verts[i], mesh->mvert[i].co); mul_m4_v3(ob->obmat, verts[i]); } /* compute the weights based on gathered vertices and bones */ if (heat) { const char *error = NULL; heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip, root, tip, selected, &error); if (error) { BKE_report(reports, RPT_WARNING, error); } } else { envelope_bone_weighting(ob, mesh, verts, numbones, bonelist, dgrouplist, dgroupflip, root, tip, selected, mat4_to_scale(par->obmat)); } /* only generated in some cases but can call anyway */ ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e'); /* free the memory allocated */ MEM_freeN(bonelist); MEM_freeN(dgrouplist); MEM_freeN(dgroupflip); MEM_freeN(root); MEM_freeN(tip); MEM_freeN(selected); MEM_freeN(verts); }
static int bake( Render *re, Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports, const ScenePassType pass_type, const int margin, const BakeSaveMode save_mode, const bool is_clear, const bool is_split_materials, const bool is_automatic_name, const bool is_selected_to_active, const bool is_cage, const float cage_extrusion, const int normal_space, const BakeNormalSwizzle normal_swizzle[], const char *custom_cage, const char *filepath, const int width, const int height, const char *identifier, ScrArea *sa, const char *uv_layer) { int op_result = OPERATOR_CANCELLED; bool ok = false; Object *ob_cage = NULL; BakeHighPolyData *highpoly = NULL; int tot_highpoly = 0; char restrict_flag_low = ob_low->restrictflag; char restrict_flag_cage = 0; Mesh *me_low = NULL; Mesh *me_cage = NULL; float *result = NULL; BakePixel *pixel_array_low = NULL; BakePixel *pixel_array_high = NULL; const bool is_save_internal = (save_mode == R_BAKE_SAVE_INTERNAL); const bool is_noncolor = is_noncolor_pass(pass_type); const int depth = RE_pass_depth(pass_type); BakeImages bake_images = {NULL}; size_t num_pixels; int tot_materials; RE_bake_engine_set_engine_parameters(re, bmain, scene); if (!RE_bake_has_engine(re)) { BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); goto cleanup; } tot_materials = ob_low->totcol; if (uv_layer && uv_layer[0] != '\0') { Mesh *me = (Mesh *)ob_low->data; if (CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer) == -1) { BKE_reportf(reports, RPT_ERROR, "No UV layer named \"%s\" found in the object \"%s\"", uv_layer, ob_low->id.name + 2); goto cleanup; } } if (tot_materials == 0) { if (is_save_internal) { BKE_report(reports, RPT_ERROR, "No active image found, add a material or bake to an external file"); goto cleanup; } else if (is_split_materials) { BKE_report(reports, RPT_ERROR, "No active image found, add a material or bake without the Split Materials option"); goto cleanup; } else { /* baking externally without splitting materials */ tot_materials = 1; } } /* we overallocate in case there is more materials than images */ bake_images.data = MEM_mallocN(sizeof(BakeImage) * tot_materials, "bake images dimensions (width, height, offset)"); bake_images.lookup = MEM_mallocN(sizeof(int) * tot_materials, "bake images lookup (from material to BakeImage)"); build_image_lookup(bmain, ob_low, &bake_images); if (is_save_internal) { num_pixels = initialize_internal_images(&bake_images, reports); if (num_pixels == 0) { goto cleanup; } } else { /* when saving extenally always use the size specified in the UI */ num_pixels = (size_t)width * (size_t)height * bake_images.size; for (int i = 0; i < bake_images.size; i++) { bake_images.data[i].width = width; bake_images.data[i].height = height; bake_images.data[i].offset = (is_split_materials ? num_pixels : 0); bake_images.data[i].image = NULL; } if (!is_split_materials) { /* saving a single image */ for (int i = 0; i < tot_materials; i++) { bake_images.lookup[i] = 0; } } } if (is_selected_to_active) { CollectionPointerLink *link; tot_highpoly = 0; for (link = selected_objects->first; link; link = link->next) { Object *ob_iter = link->ptr.data; if (ob_iter == ob_low) continue; tot_highpoly ++; } if (is_cage && custom_cage[0] != '\0') { ob_cage = BLI_findstring(&bmain->object, custom_cage, offsetof(ID, name) + 2); if (ob_cage == NULL || ob_cage->type != OB_MESH) { BKE_report(reports, RPT_ERROR, "No valid cage object"); goto cleanup; } else { restrict_flag_cage = ob_cage->restrictflag; ob_cage->restrictflag |= OB_RESTRICT_RENDER; } } } pixel_array_low = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly"); pixel_array_high = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly"); result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels"); /* get the mesh as it arrives in the renderer */ me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); BKE_mesh_split_faces(me_low); /* populate the pixel array with the face data */ if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false) RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images, uv_layer); /* else populate the pixel array with the 'cage' mesh (the smooth version of the mesh) */ if (is_selected_to_active) { CollectionPointerLink *link; ModifierData *md, *nmd; ListBase modifiers_tmp, modifiers_original; int i = 0; /* prepare cage mesh */ if (ob_cage) { me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 0, 0); BKE_mesh_split_faces(me_cage); if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) { BKE_report(reports, RPT_ERROR, "Invalid cage object, the cage mesh must have the same number " "of faces as the active object"); goto cleanup; } } else if (is_cage) { modifiers_original = ob_low->modifiers; BLI_listbase_clear(&modifiers_tmp); for (md = ob_low->modifiers.first; md; md = md->next) { /* Edge Split cannot be applied in the cage, * the cage is supposed to have interpolated normals * between the faces unless the geometry is physically * split. So we create a copy of the low poly mesh without * the eventual edge split.*/ if (md->type == eModifierType_EdgeSplit) continue; nmd = modifier_new(md->type); BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); modifier_copyData(md, nmd); BLI_addtail(&modifiers_tmp, nmd); } /* temporarily replace the modifiers */ ob_low->modifiers = modifiers_tmp; /* get the cage mesh as it arrives in the renderer */ me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); BKE_mesh_split_faces(me_cage); RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); } highpoly = MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects"); /* populate highpoly array */ for (link = selected_objects->first; link; link = link->next) { TriangulateModifierData *tmd; Object *ob_iter = link->ptr.data; if (ob_iter == ob_low) continue; /* initialize highpoly_data */ highpoly[i].ob = ob_iter; highpoly[i].restrict_flag = ob_iter->restrictflag; /* triangulating so BVH returns the primitive_id that will be used for rendering */ highpoly[i].tri_mod = ED_object_modifier_add( reports, bmain, scene, highpoly[i].ob, "TmpTriangulate", eModifierType_Triangulate); tmd = (TriangulateModifierData *)highpoly[i].tri_mod; tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED; tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP; highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 0, 0); highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER; BKE_mesh_split_faces(highpoly[i].me); /* lowpoly to highpoly transformation matrix */ copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); invert_m4_m4(highpoly[i].imat, highpoly[i].obmat); highpoly[i].is_flip_object = is_negative_m4(highpoly[i].ob->obmat); i++; } BLI_assert(i == tot_highpoly); ob_low->restrictflag |= OB_RESTRICT_RENDER; /* populate the pixel arrays with the corresponding face data for each high poly object */ if (!RE_bake_pixels_populate_from_objects( me_low, pixel_array_low, pixel_array_high, highpoly, tot_highpoly, num_pixels, ob_cage != NULL, cage_extrusion, ob_low->obmat, (ob_cage ? ob_cage->obmat : ob_low->obmat), me_cage)) { BKE_report(reports, RPT_ERROR, "Error handling selected objects"); goto cage_cleanup; } /* the baking itself */ for (i = 0; i < tot_highpoly; i++) { ok = RE_bake_engine(re, highpoly[i].ob, i, pixel_array_high, num_pixels, depth, pass_type, result); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2); goto cage_cleanup; } } cage_cleanup: /* reverting data back */ if ((ob_cage == NULL) && is_cage) { ob_low->modifiers = modifiers_original; while ((md = BLI_pophead(&modifiers_tmp))) { modifier_free(md); } } if (!ok) { goto cleanup; } } else { /* make sure low poly renders */ ob_low->restrictflag &= ~OB_RESTRICT_RENDER; if (RE_bake_has_engine(re)) { ok = RE_bake_engine(re, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, result); } else { BKE_report(reports, RPT_ERROR, "Current render engine does not support baking"); goto cleanup; } } /* normal space conversion * the normals are expected to be in world space, +X +Y +Z */ if (ok && pass_type == SCE_PASS_NORMAL) { switch (normal_space) { case R_BAKE_SPACE_WORLD: { /* Cycles internal format */ if ((normal_swizzle[0] == R_BAKE_POSX) && (normal_swizzle[1] == R_BAKE_POSY) && (normal_swizzle[2] == R_BAKE_POSZ)) { break; } else { RE_bake_normal_world_to_world(pixel_array_low, num_pixels, depth, result, normal_swizzle); } break; } case R_BAKE_SPACE_OBJECT: { RE_bake_normal_world_to_object(pixel_array_low, num_pixels, depth, result, ob_low, normal_swizzle); break; } case R_BAKE_SPACE_TANGENT: { if (is_selected_to_active) { RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_low, normal_swizzle, ob_low->obmat); } else { /* from multiresolution */ Mesh *me_nores = NULL; ModifierData *md = NULL; int mode; md = modifiers_findByType(ob_low, eModifierType_Multires); if (md) { mode = md->mode; md->mode &= ~eModifierMode_Render; } me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0); BKE_mesh_split_faces(me_nores); RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer); RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat); BKE_libblock_free(bmain, me_nores); if (md) md->mode = mode; } break; } default: break; } } if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem baking object \"%s\"", ob_low->id.name + 2); op_result = OPERATOR_CANCELLED; } else { /* save the results */ for (int i = 0; i < bake_images.size; i++) { BakeImage *bk_image = &bake_images.data[i]; if (is_save_internal) { ok = write_internal_bake_pixels( bk_image->image, pixel_array_low + bk_image->offset, result + bk_image->offset * depth, bk_image->width, bk_image->height, margin, is_clear, is_noncolor); /* might be read by UI to set active image for display */ bake_update_image(sa, bk_image->image); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem saving the bake map internally for object \"%s\"", ob_low->id.name + 2); op_result = OPERATOR_CANCELLED; } else { BKE_report(reports, RPT_INFO, "Baking map saved to internal image, save it externally or pack it"); op_result = OPERATOR_FINISHED; } } /* save externally */ else { BakeData *bake = &scene->r.bake; char name[FILE_MAX]; BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false, NULL); if (is_automatic_name) { BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_"); BLI_path_suffix(name, FILE_MAX, identifier, "_"); } if (is_split_materials) { if (bk_image->image) { BLI_path_suffix(name, FILE_MAX, bk_image->image->id.name + 2, "_"); } else { if (ob_low->mat[i]) { BLI_path_suffix(name, FILE_MAX, ob_low->mat[i]->id.name + 2, "_"); } else if (me_low->mat[i]) { BLI_path_suffix(name, FILE_MAX, me_low->mat[i]->id.name + 2, "_"); } else { /* if everything else fails, use the material index */ char tmp[4]; sprintf(tmp, "%d", i % 1000); BLI_path_suffix(name, FILE_MAX, tmp, "_"); } } } /* save it externally */ ok = write_external_bake_pixels( name, pixel_array_low + bk_image->offset, result + bk_image->offset * depth, bk_image->width, bk_image->height, margin, &bake->im_format, is_noncolor); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name); op_result = OPERATOR_CANCELLED; } else { BKE_reportf(reports, RPT_INFO, "Baking map written to \"%s\"", name); op_result = OPERATOR_FINISHED; } if (!is_split_materials) { break; } } } } if (is_save_internal) refresh_images(&bake_images); cleanup: if (highpoly) { int i; for (i = 0; i < tot_highpoly; i++) { highpoly[i].ob->restrictflag = highpoly[i].restrict_flag; if (highpoly[i].tri_mod) ED_object_modifier_remove(reports, bmain, highpoly[i].ob, highpoly[i].tri_mod); if (highpoly[i].me) BKE_libblock_free(bmain, highpoly[i].me); } MEM_freeN(highpoly); } ob_low->restrictflag = restrict_flag_low; if (ob_cage) ob_cage->restrictflag = restrict_flag_cage; if (pixel_array_low) MEM_freeN(pixel_array_low); if (pixel_array_high) MEM_freeN(pixel_array_high); if (bake_images.data) MEM_freeN(bake_images.data); if (bake_images.lookup) MEM_freeN(bake_images.lookup); if (result) MEM_freeN(result); if (me_low) BKE_libblock_free(bmain, me_low); if (me_cage) BKE_libblock_free(bmain, me_cage); return op_result; }
static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job) { Scene *scene= CTX_data_scene(C); int i; FluidsimSettings *domainSettings; char debugStrBuffer[256]; int gridlevels = 0; const char *relbase= modifier_path_relbase(fsDomain); const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP; const char *suffixSurface = FLUID_SUFFIX_SURFACE; char targetDir[FILE_MAX]; // store & modify output settings char targetFile[FILE_MAX]; // temp. store filename from targetDir for access int outStringsChanged = 0; // modified? copy back before baking float domainMat[4][4]; float invDomMat[4][4]; int noFrames; int origFrame = scene->r.cfra; FluidAnimChannels *channels = MEM_callocN(sizeof(FluidAnimChannels), "fluid domain animation channels"); ListBase *fobjects = MEM_callocN(sizeof(ListBase), "fluid objects"); FluidsimModifierData *fluidmd = NULL; Mesh *mesh = NULL; FluidBakeJob *fb; elbeemSimulationSettings *fsset= MEM_callocN(sizeof(elbeemSimulationSettings), "Fluid sim settings"); fb= MEM_callocN(sizeof(FluidBakeJob), "fluid bake job"); if (getenv(strEnvName)) { int dlevel = atoi(getenv(strEnvName)); elbeemSetDebugLevel(dlevel); BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::msg: Debug messages activated due to envvar '%s'\n", strEnvName); elbeemDebugOut(debugStrBuffer); } /* make sure it corresponds to startFrame setting (old: noFrames = scene->r.efra - scene->r.sfra +1) */; noFrames = scene->r.efra - 0; if (noFrames<=0) { BKE_report(reports, RPT_ERROR, "No frames to export (check your animation range settings)"); fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* check scene for sane object/modifier settings */ if (!fluid_validate_scene(reports, scene, fsDomain)) { fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* these both have to be valid, otherwise we wouldn't be here */ fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim); domainSettings = fluidmd->fss; mesh = fsDomain->data; domainSettings->bakeStart = 1; domainSettings->bakeEnd = scene->r.efra; // calculate bounding box fluid_get_bb(mesh->mvert, mesh->totvert, fsDomain->obmat, domainSettings->bbStart, domainSettings->bbSize); // reset last valid frame domainSettings->lastgoodframe = -1; /* delete old baked files */ fluidsim_delete_until_lastframe(domainSettings, relbase); /* rough check of settings... */ if (domainSettings->previewresxyz > domainSettings->resolutionxyz) { BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", domainSettings->previewresxyz, domainSettings->resolutionxyz); elbeemDebugOut(debugStrBuffer); domainSettings->previewresxyz = domainSettings->resolutionxyz; } // set adaptive coarsening according to resolutionxyz // this should do as an approximation, with in/outflow // doing this more accurate would be overkill // perhaps add manual setting? if (domainSettings->maxRefine <0) { if (domainSettings->resolutionxyz>128) { gridlevels = 2; } else if (domainSettings->resolutionxyz > 64) { gridlevels = 1; } else { gridlevels = 0; } } else { gridlevels = domainSettings->maxRefine; } BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name, gridlevels); elbeemDebugOut(debugStrBuffer); /* ******** prepare output file paths ******** */ outStringsChanged = fluid_init_filepaths(fsDomain, targetDir, targetFile, debugStrBuffer); channels->length = scene->r.efra; // DG TODO: why using endframe and not "noFrames" here? .. because "noFrames" is buggy too? (not using sfra) channels->aniFrameTime = (double)((double)domainSettings->animEnd - (double)domainSettings->animStart) / (double)noFrames; /* ******** initialize and allocate animation channels ******** */ fluid_init_all_channels(C, fsDomain, domainSettings, channels, fobjects); /* reset to original current frame */ scene->r.cfra = origFrame; ED_update_for_newframe(CTX_data_main(C), scene, 1); /* ******** init domain object's matrix ******** */ copy_m4_m4(domainMat, fsDomain->obmat); if (!invert_m4_m4(invDomMat, domainMat)) { BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::error - Invalid obj matrix?\n"); elbeemDebugOut(debugStrBuffer); BKE_report(reports, RPT_ERROR, "Invalid object matrix"); fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* ******** start writing / exporting ******** */ // use .tmp, don't overwrite/delete original file BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp); // make sure these directories exist as well if (outStringsChanged) { BLI_make_existing_file(targetFile); } /* ******** export domain to elbeem ******** */ elbeemResetSettings(fsset); fsset->version = 1; fsset->threads = (domainSettings->threads == 0) ? BKE_scene_num_threads(scene) : domainSettings->threads; // setup global settings copy_v3_v3(fsset->geoStart, domainSettings->bbStart); copy_v3_v3(fsset->geoSize, domainSettings->bbSize); // simulate with 50^3 fsset->resolutionxyz = (int)domainSettings->resolutionxyz; fsset->previewresxyz = (int)domainSettings->previewresxyz; fsset->realsize = get_fluid_size_m(scene, fsDomain, domainSettings); fsset->viscosity = get_fluid_viscosity(domainSettings); get_fluid_gravity(fsset->gravity, scene, domainSettings); // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz fsset->animStart = domainSettings->animStart; fsset->aniFrameTime = channels->aniFrameTime; fsset->noOfFrames = noFrames; // is otherwise subtracted in parser BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixSurface); // defaults for compressibility and adaptive grids fsset->gstar = domainSettings->gstar; fsset->maxRefine = domainSettings->maxRefine; // check <-> gridlevels fsset->generateParticles = domainSettings->generateParticles; fsset->numTracerParticles = domainSettings->generateTracers; fsset->surfaceSmoothing = domainSettings->surfaceSmoothing; fsset->surfaceSubdivs = domainSettings->surfaceSubdivs; fsset->farFieldSize = domainSettings->farFieldSize; BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath)); // domain channels fsset->channelSizeFrameTime = fsset->channelSizeViscosity = fsset->channelSizeGravity = channels->length; fsset->channelFrameTime = channels->DomainTime; fsset->channelViscosity = channels->DomainViscosity; fsset->channelGravity = channels->DomainGravity; fsset->runsimCallback = &runSimulationCallback; fsset->runsimUserData = fb; if (domainSettings->typeFlags & OB_FSBND_NOSLIP) fsset->domainobsType = FLUIDSIM_OBSTACLE_NOSLIP; else if (domainSettings->typeFlags&OB_FSBND_PARTSLIP) fsset->domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP; else if (domainSettings->typeFlags&OB_FSBND_FREESLIP) fsset->domainobsType = FLUIDSIM_OBSTACLE_FREESLIP; fsset->domainobsPartslip = domainSettings->partSlipValue; /* use domainobsType also for surface generation flag (bit: >=64) */ if (domainSettings->typeFlags & OB_FSSG_NOOBS) fsset->mFsSurfGenSetting = FLUIDSIM_FSSG_NOOBS; else fsset->mFsSurfGenSetting = 0; // "normal" mode fsset->generateVertexVectors = (domainSettings->domainNovecgen==0); // init blender domain transform matrix { int j; for (i=0; i<4; i++) { for (j=0; j<4; j++) { fsset->surfaceTrafo[i*4+j] = invDomMat[j][i]; } } } /* ******** init solver with settings ******** */ elbeemInit(); elbeemAddDomain(fsset); /* ******** export all fluid objects to elbeem ******** */ export_fluid_objects(fobjects, scene, channels->length); /* custom data for fluid bake job */ fb->settings = fsset; if (do_job) { wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Fluid Simulation", WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_SIM_FLUID); /* setup job */ WM_jobs_customdata_set(wm_job, fb, fluidbake_free); WM_jobs_timer(wm_job, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME); WM_jobs_callbacks(wm_job, fluidbake_startjob, NULL, NULL, fluidbake_endjob); WM_jobs_start(CTX_wm_manager(C), wm_job); } else { short dummy_stop = 0, dummy_do_update = 0; float dummy_progress = 0.0f; /* blocking, use with exec() */ fluidbake_startjob((void *)fb, &dummy_stop, &dummy_do_update, &dummy_progress); fluidbake_endjob((void *)fb); fluidbake_free((void *)fb); } /* ******** free stored animation data ******** */ fluidbake_free_data(channels, fobjects, NULL, NULL); // elbeemFree(); return 1; }