diff options
author | Joseph Eagar <joeedh@gmail.com> | 2010-07-19 08:44:37 +0400 |
---|---|---|
committer | Joseph Eagar <joeedh@gmail.com> | 2010-07-19 08:44:37 +0400 |
commit | c11c196efadf5ef52293d782638497f86a209722 (patch) | |
tree | 43abcd60b2400d28db8686f4dbea68f17475ef58 /source/blender/editors/physics | |
parent | f54aa7811029c90b6071ccc9e27e57a758e5884d (diff) | |
parent | 7f083c45bee15f7540e2a35a725efe28fc962239 (diff) |
part 1 of merge from trunk at r30358; it compiles, but doesn't link quite yet :)
Diffstat (limited to 'source/blender/editors/physics')
-rw-r--r-- | source/blender/editors/physics/CMakeLists.txt | 47 | ||||
-rw-r--r-- | source/blender/editors/physics/particle_boids.c | 4 | ||||
-rw-r--r-- | source/blender/editors/physics/particle_edit.c | 150 | ||||
-rw-r--r-- | source/blender/editors/physics/particle_object.c | 38 | ||||
-rw-r--r-- | source/blender/editors/physics/physics_fluid.c | 1607 | ||||
-rw-r--r-- | source/blender/editors/physics/physics_intern.h | 4 | ||||
-rw-r--r-- | source/blender/editors/physics/physics_ops.c | 8 | ||||
-rw-r--r-- | source/blender/editors/physics/physics_pointcache.c | 45 |
8 files changed, 932 insertions, 971 deletions
diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt new file mode 100644 index 00000000000..ebe3f913508 --- /dev/null +++ b/source/blender/editors/physics/CMakeLists.txt @@ -0,0 +1,47 @@ +# $Id: CMakeLists.txt 12931 2007-12-17 18:20:48Z theeth $ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL LICENSE BLOCK ***** + +FILE(GLOB SRC *.c) + +SET(INC + ../include + ../../blenkernel + ../../blenlib + ../../makesdna + ../../makesrna + ../../windowmanager + ../../../../intern/elbeem/extern + ../../../../intern/guardedalloc +) + +IF(NOT WITH_ELBEEM) + ADD_DEFINITIONS(-DDISABLE_ELBEEM) +ENDIF(NOT WITH_ELBEEM) + +IF(WITH_OPENMP) + ADD_DEFINITIONS(-DPARALLEL=1) +ENDIF(WITH_OPENMP) + +IF(WIN32) + SET(INC ${INC} ${PTHREADS_INC}) +ENDIF(WIN32) + +BLENDERLIB(bf_editor_physics "${SRC}" "${INC}") diff --git a/source/blender/editors/physics/particle_boids.c b/source/blender/editors/physics/particle_boids.c index e738aa34d07..37de0d8f873 100644 --- a/source/blender/editors/physics/particle_boids.c +++ b/source/blender/editors/physics/particle_boids.c @@ -1,5 +1,5 @@ /** - * $Id: + * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -29,9 +29,7 @@ #include "MEM_guardedalloc.h" -#include "DNA_boid_types.h" #include "DNA_particle_types.h" -#include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BKE_boids.h" diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 71c18b35365..da0034ac2f9 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -36,15 +36,9 @@ #include "DNA_scene_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_force.h" -#include "DNA_object_types.h" -#include "DNA_vec_types.h" -#include "DNA_userdef_types.h" #include "DNA_view3d_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" -#include "DNA_windowmanager_types.h" #include "BKE_DerivedMesh.h" #include "BKE_depsgraph.h" @@ -66,7 +60,6 @@ #include "BLI_kdtree.h" #include "BLI_rand.h" -#include "PIL_time.h" #include "BIF_gl.h" #include "BIF_glutil.h" @@ -75,7 +68,6 @@ #include "ED_particle.h" #include "ED_view3d.h" -#include "UI_interface.h" #include "UI_resources.h" #include "WM_api.h" @@ -132,7 +124,7 @@ int PE_hair_poll(bContext *C) return (edit && edit->psys); } -int PE_poll_3dview(bContext *C) +int PE_poll_view3d(bContext *C) { return PE_poll(C) && CTX_wm_area(C)->spacetype == SPACE_VIEW3D && CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW; @@ -168,7 +160,7 @@ void PE_free_ptcache_edit(PTCacheEdit *edit) edit->emitter_field= 0; } - psys_free_path_cache(NULL, edit); + psys_free_path_cache(edit->psys, edit); MEM_freeN(edit); } @@ -211,7 +203,7 @@ static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create) pset->scene = scene; pset->object = ob; - BKE_ptcache_ids_from_object(&pidlist, ob); + BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0); /* in the case of only one editable thing, set pset->edittype accordingly */ if(pidlist.first && pidlist.first == pidlist.last) { @@ -831,9 +823,12 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys) edit= psys->edit; psmd= psys_get_modifier(ob, psys); - if(!edit->mirror_cache || !psmd->dm) + if(!psmd->dm) return; + if(!edit->mirror_cache) + PE_update_mirror_cache(ob, psys); + /* we delay settings the PARS_EDIT_RECALC for mirrored particles * to avoid doing mirror twice */ LOOP_POINTS { @@ -902,13 +897,13 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit) if(dot<dist_1st) { normalize_v3(dvec); mul_v3_fl(dvec,dist_1st-dot); - add_v3_v3v3(key->co,key->co,dvec); + add_v3_v3(key->co, dvec); } } else { normalize_v3(dvec); mul_v3_fl(dvec,dist_1st-dot); - add_v3_v3v3(key->co,key->co,dvec); + add_v3_v3(key->co, dvec); } if(k==1) dist_1st*=1.3333f; @@ -994,7 +989,7 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit) } if(k) { - add_v3_v3v3((key-1)->co,(key-1)->co,dv1); + add_v3_v3((key-1)->co, dv1); } VECADD(dv1,dv0,dv2); @@ -1326,7 +1321,7 @@ static int select_all_exec(bContext *C, wmOperator *op) } PE_update_selection(scene, ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; } @@ -1376,7 +1371,7 @@ int PE_mouse_particles(bContext *C, short *mval, int extend) for_mouse_hit_keys(&data, toggle_key_select, 1); /* nearest only */ PE_update_selection(scene, ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); return OPERATOR_FINISHED; } @@ -1385,11 +1380,14 @@ int PE_mouse_particles(bContext *C, short *mval, int extend) static void select_root(PEData *data, int point_index) { + if (data->edit->points[point_index].flag & PEP_HIDE) + return; + data->edit->points[point_index].keys->flag |= PEK_SELECT; data->edit->points[point_index].flag |= PEP_EDIT_RECALC; /* redraw selection only */ } -static int select_first_exec(bContext *C, wmOperator *op) +static int select_roots_exec(bContext *C, wmOperator *op) { PEData data; @@ -1397,19 +1395,19 @@ static int select_first_exec(bContext *C, wmOperator *op) foreach_point(&data, select_root); PE_update_selection(data.scene, data.ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); return OPERATOR_FINISHED; } -void PARTICLE_OT_select_first(wmOperatorType *ot) +void PARTICLE_OT_select_roots(wmOperatorType *ot) { /* identifiers */ - ot->name= "Select First"; - ot->idname= "PARTICLE_OT_select_first"; + ot->name= "Select Roots"; + ot->idname= "PARTICLE_OT_select_roots"; /* api callbacks */ - ot->exec= select_first_exec; + ot->exec= select_roots_exec; ot->poll= PE_poll; /* flags */ @@ -1421,11 +1419,15 @@ void PARTICLE_OT_select_first(wmOperatorType *ot) static void select_tip(PEData *data, int point_index) { PTCacheEditPoint *point = data->edit->points + point_index; + + if (point->flag & PEP_HIDE) + return; + point->keys[point->totkey - 1].flag |= PEK_SELECT; point->flag |= PEP_EDIT_RECALC; /* redraw selection only */ } -static int select_last_exec(bContext *C, wmOperator *op) +static int select_tips_exec(bContext *C, wmOperator *op) { PEData data; @@ -1433,19 +1435,19 @@ static int select_last_exec(bContext *C, wmOperator *op) foreach_point(&data, select_tip); PE_update_selection(data.scene, data.ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); return OPERATOR_FINISHED; } -void PARTICLE_OT_select_last(wmOperatorType *ot) +void PARTICLE_OT_select_tips(wmOperatorType *ot) { /* identifiers */ - ot->name= "Select Last"; - ot->idname= "PARTICLE_OT_select_last"; + ot->name= "Select Tips"; + ot->idname= "PARTICLE_OT_select_tips"; /* api callbacks */ - ot->exec= select_last_exec; + ot->exec= select_tips_exec; ot->poll= PE_poll; /* flags */ @@ -1473,7 +1475,7 @@ static int select_linked_exec(bContext *C, wmOperator *op) for_mouse_hit_keys(&data, select_keys, 1); /* nearest only */ PE_update_selection(data.scene, data.ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); return OPERATOR_FINISHED; } @@ -1499,7 +1501,7 @@ void PARTICLE_OT_select_linked(wmOperatorType *ot) /* api callbacks */ ot->exec= select_linked_exec; ot->invoke= select_linked_invoke; - ot->poll= PE_poll_3dview; + ot->poll= PE_poll_view3d; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; @@ -1539,7 +1541,7 @@ int PE_border_select(bContext *C, rcti *rect, int select, int extend) for_mouse_hit_keys(&data, select_key, 0); PE_update_selection(scene, ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; } @@ -1564,7 +1566,7 @@ int PE_circle_select(bContext *C, int selecting, short *mval, float rad) for_mouse_hit_keys(&data, select_key, 0); PE_update_selection(scene, ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; } @@ -1630,7 +1632,7 @@ int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select) } PE_update_selection(scene, ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; } @@ -1664,7 +1666,7 @@ static int hide_exec(bContext *C, wmOperator *op) } PE_update_selection(scene, ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; } @@ -1706,7 +1708,7 @@ static int reveal_exec(bContext *C, wmOperator *op) } PE_update_selection(scene, ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; } @@ -1764,7 +1766,7 @@ static int select_less_exec(bContext *C, wmOperator *op) foreach_point(&data, select_less_keys); PE_update_selection(data.scene, data.ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); return OPERATOR_FINISHED; } @@ -1825,7 +1827,7 @@ static int select_more_exec(bContext *C, wmOperator *op) foreach_point(&data, select_more_keys); PE_update_selection(data.scene, data.ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); return OPERATOR_FINISHED; } @@ -1862,7 +1864,7 @@ static int select_inverse_exec(bContext *C, wmOperator *op) } PE_update_selection(data.scene, data.ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); return OPERATOR_FINISHED; } @@ -1953,7 +1955,7 @@ static int rekey_exec(bContext *C, wmOperator *op) recalc_lengths(data.edit); PE_update_object(data.scene, data.ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, data.ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob); return OPERATOR_FINISHED; } @@ -2258,7 +2260,7 @@ static int subdivide_exec(bContext *C, wmOperator *op) recalc_lengths(data.edit); PE_update_object(data.scene, data.ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, data.ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob); return OPERATOR_FINISHED; } @@ -2346,7 +2348,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) BKE_reportf(op->reports, RPT_INFO, "Remove %d double particles.", totremoved); DAG_id_flush_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); return OPERATOR_FINISHED; } @@ -2381,21 +2383,22 @@ static int weight_set_exec(bContext *C, wmOperator *op) HairKey *hkey; float weight; ParticleBrushData *brush= &pset->brush[pset->brushtype]; - edit= psys->edit; + float factor= RNA_float_get(op->ptr, "factor"); - weight= (float)(brush->strength / 100.0f); + weight= brush->strength; + edit= psys->edit; LOOP_SELECTED_POINTS { ParticleData *pa= psys->particles + p; LOOP_SELECTED_KEYS { hkey= pa->hair + k; - hkey->weight= weight; + hkey->weight= interpf(weight, hkey->weight, factor); } } DAG_id_flush_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); return OPERATOR_FINISHED; } @@ -2412,6 +2415,8 @@ void PARTICLE_OT_weight_set(wmOperatorType *ot) /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_float(ot->srna, "factor", 1, 0, 1, "Factor", "", 0, 1); } /************************ cursor drawing *******************************/ @@ -2451,7 +2456,7 @@ static void toggle_particle_cursor(bContext *C, int enable) pset->paintcursor = NULL; } else if(enable) - pset->paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), PE_poll_3dview, brush_drawcursor, NULL); + pset->paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), PE_poll_view3d, brush_drawcursor, NULL); } /********************* radial control operator *********************/ @@ -2507,6 +2512,8 @@ static int brush_radial_control_exec(bContext *C, wmOperator *op) else if(mode == WM_RADIALCONTROL_STRENGTH) brush->strength= new_value; + WM_event_add_notifier(C, NC_WINDOW, NULL); + return OPERATOR_FINISHED; } @@ -2568,7 +2575,7 @@ static int delete_exec(bContext *C, wmOperator *op) } DAG_id_flush_update(&data.ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, data.ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob); return OPERATOR_FINISHED; } @@ -2727,7 +2734,7 @@ static int mirror_exec(bContext *C, wmOperator *op) PE_mirror_x(scene, ob, 0); update_world_cos(ob, edit); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); DAG_id_flush_update(&ob->id, OB_RECALC_DATA); return OPERATOR_FINISHED; @@ -2941,7 +2948,7 @@ static void brush_puff(PEData *data, int point_index) VECCOPY(co, key->co); mul_m4_v3(mat, co); length += len_v3v3(lastco, co); - if((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE)) { + if((data->select==0 || (key->flag & PEK_SELECT)) && !(key->flag & PEK_HIDE)) { VECADDFAC(kco, rootco, nor, length); /* blend between the current and straight position */ @@ -3356,7 +3363,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) data.mval= mval; data.rad= (float)brush->size; - data.combfac= (float)(brush->strength - 50) / 50.0f; + data.combfac= (brush->strength - 0.5f) * 2.0f; if(data.combfac < 0.0f) data.combfac= 1.0f - 9.0f * data.combfac; else @@ -3378,7 +3385,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) PE_set_view3d_data(C, &data); data.mval= mval; data.rad= (float)brush->size; - data.cutfac= (float)(brush->strength / 100.0f); + data.cutfac= brush->strength; if(selected) foreach_selected_point(&data, brush_cut); @@ -3402,7 +3409,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) data.mval= mval; data.rad= (float)brush->size; - data.growfac= (float)brush->strength / 5000.0f; + data.growfac= brush->strength / 50.0f; if(brush->invert ^ flip) data.growfac= 1.0f - data.growfac; @@ -3424,8 +3431,9 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) data.dm= psmd->dm; data.mval= mval; data.rad= (float)brush->size; + data.select= selected; - data.pufffac= (float)(brush->strength - 50) / 50.0f; + data.pufffac= (brush->strength - 0.5f) * 2.0f; if(data.pufffac < 0.0f) data.pufffac= 1.0f - 9.0f * data.pufffac; else @@ -3446,7 +3454,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) PE_set_view3d_data(C, &data); data.mval= mval; - added= brush_add(&data, brush->strength); + added= brush_add(&data, brush->count); if(pset->flag & PE_KEEP_LENGTHS) recalc_lengths(edit); @@ -3466,7 +3474,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) data.vec[0]= data.vec[1]= data.vec[2]= 0.0f; data.tot= 0; - data.smoothfac= (float)(brush->strength / 100.0f); + data.smoothfac= brush->strength; invert_m4_m4(ob->imat, ob->obmat); @@ -3489,7 +3497,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) data.mval= mval; data.rad= (float)brush->size; - data.weightfac = (float)(brush->strength / 100.0f); /* note that this will never be zero */ + data.weightfac = brush->strength; /* note that this will never be zero */ foreach_mouse_hit_key(&data, brush_weight, selected); } @@ -3511,7 +3519,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) else PE_update_object(scene, ob, 1); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); bedit->lastmouse[0]= mouse[0]; bedit->lastmouse[1]= mouse[1]; @@ -3608,7 +3616,7 @@ void PARTICLE_OT_brush_edit(wmOperatorType *ot) ot->invoke= brush_edit_invoke; ot->modal= brush_edit_modal; ot->cancel= brush_edit_cancel; - ot->poll= PE_poll_3dview; + ot->poll= PE_poll_view3d; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; @@ -3665,6 +3673,8 @@ static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) for(; pm; pm=pm->next) { for(i=0; i<BPHYS_TOT_DATA; i++) pm->data[i] = MEM_dupallocN(pm->data[i]); + + pm->index_array = MEM_dupallocN(pm->index_array); } } @@ -3739,6 +3749,8 @@ static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) for(i=0; i<BPHYS_TOT_DATA; i++) pm->data[i] = MEM_dupallocN(pm->data[i]); + pm->index_array = MEM_dupallocN(pm->index_array); + BKE_ptcache_mem_init_pointers(pm); LOOP_POINTS { @@ -4003,12 +4015,20 @@ static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, LOOP_POINTS { if(psys) { - pa = psys->particles + p; - if((pm->next && pm->next->frame < pa->time) - || (pm->prev && pm->prev->frame >= pa->dietime)) { - BKE_ptcache_mem_incr_pointers(pm); + if(pm->index_array) { + if(pm->index_array[p]) + BKE_ptcache_mem_seek_pointers(p, pm); + else continue; - } + } + else { + pa = psys->particles + p; + if((pm->next && pm->next->frame < pa->time) + || (pm->prev && pm->prev->frame >= pa->dietime)) { + BKE_ptcache_mem_incr_pointers(pm); + continue; + } + } } if(!point->totkey) { @@ -4118,7 +4138,7 @@ static int clear_edited_exec(bContext *C, wmOperator *op) psys->flag &= ~PSYS_EDITED; psys_reset(psys, PSYS_RESET_DEPSGRAPH); - WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); DAG_id_flush_update(&ob->id, OB_RECALC_DATA); } } diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index f590339b91d..bb30d30fd0e 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -1,5 +1,5 @@ /** - * $Id: + * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -32,10 +32,7 @@ #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" -#include "DNA_object_types.h" -#include "DNA_particle_types.h" #include "DNA_scene_types.h" -#include "DNA_windowmanager_types.h" #include "BLI_math.h" #include "BLI_listbase.h" @@ -72,7 +69,9 @@ static int particle_system_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; object_add_particle_system(scene, ob, NULL); - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob); return OPERATOR_FINISHED; } @@ -110,7 +109,8 @@ static int particle_system_remove_exec(bContext *C, wmOperator *op) if(scene->basact && scene->basact->object==ob) WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL); - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob); return OPERATOR_FINISHED; } @@ -169,7 +169,7 @@ static int new_particle_settings_exec(bContext *C, wmOperator *op) DAG_scene_sort(scene); DAG_id_flush_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob); return OPERATOR_FINISHED; } @@ -217,7 +217,7 @@ static int new_particle_target_exec(bContext *C, wmOperator *op) DAG_scene_sort(scene); DAG_id_flush_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob); return OPERATOR_FINISHED; } @@ -265,7 +265,7 @@ static int remove_particle_target_exec(bContext *C, wmOperator *op) DAG_scene_sort(scene); DAG_id_flush_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob); return OPERATOR_FINISHED; } @@ -303,7 +303,7 @@ static int target_move_up_exec(bContext *C, wmOperator *op) BLI_insertlink(&psys->targets, pt->prev->prev, pt); DAG_id_flush_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob); break; } } @@ -341,7 +341,7 @@ static int target_move_down_exec(bContext *C, wmOperator *op) BLI_insertlink(&psys->targets, pt->next, pt); DAG_id_flush_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob); break; } } @@ -379,7 +379,7 @@ static int dupliob_move_up_exec(bContext *C, wmOperator *op) BLI_remlink(&part->dupliweights, dw); BLI_insertlink(&part->dupliweights, dw->prev->prev, dw); - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, NULL); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, NULL); break; } } @@ -418,7 +418,7 @@ static int copy_particle_dupliob_exec(bContext *C, wmOperator *op) dw->flag |= PART_DUPLIW_CURRENT; BLI_addhead(&part->dupliweights, dw); - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, NULL); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, NULL); break; } } @@ -464,7 +464,7 @@ static int remove_particle_dupliob_exec(bContext *C, wmOperator *op) if(dw) dw->flag |= PART_DUPLIW_CURRENT; - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, NULL); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, NULL); return OPERATOR_FINISHED; } @@ -501,7 +501,7 @@ static int dupliob_move_down_exec(bContext *C, wmOperator *op) BLI_remlink(&part->dupliweights, dw); BLI_insertlink(&part->dupliweights, dw->next, dw); - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, NULL); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, NULL); break; } } @@ -526,6 +526,7 @@ void PARTICLE_OT_dupliob_move_down(wmOperatorType *ot) static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys); + ParticleEditSettings *pset= PE_settings(scene); ParticleData *pa; PTCacheEdit *edit; PTCacheEditPoint *point; @@ -565,6 +566,9 @@ static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys) psys->flag |= PSYS_GLOBAL_HAIR; + if(ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_PUFF)) + pset->brushtype = PE_BRUSH_NONE; + PE_update_object(scene, ob, 0); } @@ -589,7 +593,7 @@ static int disconnect_hair_exec(bContext *C, wmOperator *op) disconnect_hair(scene, ob, psys); } - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob); return OPERATOR_FINISHED; } @@ -728,7 +732,7 @@ static int connect_hair_exec(bContext *C, wmOperator *op) connect_hair(scene, ob, psys); } - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index 65701f89c4e..23f604d8c12 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -45,25 +45,17 @@ #include "MEM_guardedalloc.h" /* types */ -#include "DNA_curve_types.h" +#include "DNA_anim_types.h" +#include "DNA_action_types.h" #include "DNA_object_types.h" #include "DNA_object_fluidsim.h" -#include "DNA_key_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_lattice_types.h" -#include "DNA_scene_types.h" -#include "DNA_camera_types.h" -#include "DNA_screen_types.h" -#include "DNA_space_types.h" -#include "DNA_userdef_types.h" -#include "DNA_ipo_types.h" -#include "DNA_key_types.h" #include "BLI_blenlib.h" #include "BLI_threads.h" #include "BLI_math.h" +#include "BKE_animsys.h" +#include "BKE_armature.h" #include "BKE_blender.h" #include "BKE_context.h" #include "BKE_customdata.h" @@ -80,17 +72,15 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_softbody.h" +#include "BKE_unit.h" -#include "PIL_time.h" #include "LBM_fluidsim.h" #include "BIF_gl.h" -#include "ED_fluidsim.h" #include "ED_screen.h" -#include "WM_api.h" #include "WM_types.h" #include "physics_intern.h" // own include @@ -98,85 +88,110 @@ /* enable/disable overall compilation */ #ifndef DISABLE_ELBEEM -#if defined(__APPLE__) && (PARALLEL == 1) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2) -/* ************** libgomp (Apple gcc 4.2.1) TLS bug workaround *************** */ -#include <pthread.h> -extern pthread_key_t gomp_tls_key; -static void *thread_tls_data; -#endif +#include "WM_api.h" +#include "DNA_scene_types.h" +#include "DNA_ipo_types.h" +#include "DNA_mesh_types.h" -/* XXX */ -/* from header info.c */ -static int start_progress_bar(void) {return 0;}; -static void end_progress_bar(wmWindow *win) {WM_cursor_restore(win);}; -static void waitcursor(int val) {}; -static int progress_bar(wmWindow *win, float done, char *busy_info) { WM_timecursor(win,done*100); return 0;} -static int pupmenu() {return 0;} -/* XXX */ - - -double fluidsimViscosityPreset[6] = { - -1.0, /* unused */ - -1.0, /* manual */ - 1.0e-6, /* water */ - 5.0e-5, /* some (thick) oil */ - 2.0e-3, /* ca. honey */ - -1.0 /* end */ -}; - -char* fluidsimViscosityPresetString[6] = { - "UNUSED", /* unused */ - "UNUSED", /* manual */ - " = 1.0 * 10^-6", /* water */ - " = 5.0 * 10^-5", /* some (thick) oil */ - " = 2.0 * 10^-3", /* ca. honey */ - "INVALID" /* end */ -}; +#include "PIL_time.h" + + +static float get_fluid_viscosity(FluidsimSettings *settings) +{ + switch (settings->viscosityMode) { + case 0: /* unused */ + return -1.0; + case 2: /* water */ + return 1.0e-6; + case 3: /* some (thick) oil */ + return 5.0e-5; + case 4: /* ca. honey */ + return 2.0e-3; + case 1: /* manual */ + default: + return (1.0/pow(10.0, settings->viscosityExponent)) * settings->viscosityValue; + } +} + +static void get_fluid_gravity(float *gravity, Scene *scene, FluidsimSettings *fss) +{ + if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { + copy_v3_v3(gravity, scene->physics_settings.gravity); + } else { + copy_v3_v3(gravity, &fss->gravx); + } +} + +static float get_fluid_size_m(Scene *scene, Object *domainob, FluidsimSettings *fss) +{ + if (!scene->unit.system) { + return fss->realsize; + } else { + float dim[3]; + float longest_axis; + + object_get_dimensions(domainob, dim); + longest_axis = MAX3(dim[0], dim[1], dim[2]); + + return longest_axis * scene->unit.scale_length; + } +} + +static int fluid_is_animated_mesh(FluidsimSettings *fss) +{ + return ((fss->type == OB_FLUIDSIM_CONTROL) || fss->domainNovecgen); +} /* ********************** fluid sim settings struct functions ********************** */ +#if 0 /* helper function */ void fluidsimGetGeometryObjFilename(Object *ob, char *dst) { //, char *srcname) { //snprintf(dst,FILE_MAXFILE, "%s_cfgdata_%s.bobj.gz", srcname, ob->id.name); snprintf(dst,FILE_MAXFILE, "fluidcfgdata_%s.bobj.gz", ob->id.name); } +#endif - - -/* ******************************************************************************** */ /* ********************** fluid sim channel helper functions ********************** */ -/* ******************************************************************************** */ + +typedef struct FluidAnimChannels { + int length; + + double aniFrameTime; + + float *timeAtFrame; + float *DomainTime; + float *DomainGravity; + float *DomainViscosity; +} FluidAnimChannels; + +typedef struct FluidObject { + struct FluidObject *next, *prev; + + struct Object *object; + + float *Translation; + float *Rotation; + float *Scale; + float *Active; + + float *InitialVelocity; + + float *AttractforceStrength; + float *AttractforceRadius; + float *VelocityforceStrength; + float *VelocityforceRadius; + + float *VertexCache; + int numVerts, numTris; +} FluidObject; // no. of entries for the two channel sizes #define CHANNEL_FLOAT 1 #define CHANNEL_VEC 3 -#define FS_FREE_ONECHANNEL(c,str) { \ - if(c){ MEM_freeN(c); c=NULL; } \ -} // end ONE CHANN, debug: fprintf(stderr,"freeing " str " \n"); - -#define FS_FREE_CHANNELS { \ - FS_FREE_ONECHANNEL(timeAtIndex,"timeAtIndex");\ - FS_FREE_ONECHANNEL(timeAtFrame,"timeAtFrame");\ - FS_FREE_ONECHANNEL(channelDomainTime,"channelDomainTime"); \ - FS_FREE_ONECHANNEL(channelDomainGravity,"channelDomainGravity");\ - FS_FREE_ONECHANNEL(channelDomainViscosity,"channelDomainViscosity");\ - for(i=0;i<256;i++) { \ - FS_FREE_ONECHANNEL(channelObjMove[i][0],"channelObjMove0"); \ - FS_FREE_ONECHANNEL(channelObjMove[i][1],"channelObjMove1"); \ - FS_FREE_ONECHANNEL(channelObjMove[i][2],"channelObjMove2"); \ - FS_FREE_ONECHANNEL(channelObjInivel[i],"channelObjInivel"); \ - FS_FREE_ONECHANNEL(channelObjActive[i],"channelObjActive"); \ - FS_FREE_ONECHANNEL(channelAttractforceStrength[i],"channelAttractforceStrength"); \ - FS_FREE_ONECHANNEL(channelAttractforceRadius[i],"channelAttractforceRadius"); \ - FS_FREE_ONECHANNEL(channelVelocityforceStrength[i],"channelVelocityforceStrength"); \ - FS_FREE_ONECHANNEL(channelVelocityforceRadius[i],"channelVelocityforceRadius"); \ - } \ -} // end FS FREE CHANNELS - - // simplify channels before printing // for API this is done anyway upon init #if 0 @@ -207,341 +222,653 @@ static void fluidsimPrintChannel(FILE *file, float *channel, int paramsize, char } #endif -static void fluidsimInitChannel(Scene *scene, float **setchannel, int size, float *time, - int *icuIds, float *defaults, Ipo* ipo, int entries) + +/* Note: fluid anim channel data layout + * ------------------------------------ + * CHANNEL_FLOAT: + * frame 1 |frame 2 + * [dataF][time][dataF][time] + * + * CHANNEL_VEC: + * frame 1 |frame 2 + * [dataX][dataY][dataZ][time][dataX][dataY][dataZ][time] + * + */ + +static void init_time(FluidsimSettings *domainSettings, FluidAnimChannels *channels) { + int i; + + channels->timeAtFrame = MEM_callocN( (channels->length+1)*sizeof(float), "timeAtFrame channel"); + + channels->timeAtFrame[0] = channels->timeAtFrame[1] = domainSettings->animStart; // start at index 1 + + for(i=2; i<=channels->length; i++) { + channels->timeAtFrame[i] = channels->timeAtFrame[i-1] + channels->aniFrameTime; + } +} + +/* if this is slow, can replace with faster, less readable code */ +static void set_channel(float *channel, float time, float *value, int i, int size) +{ + if (size == CHANNEL_FLOAT) { + channel[(i * 2) + 0] = value[0]; + channel[(i * 2) + 1] = time; + } + else if (size == CHANNEL_VEC) { + channel[(i * 4) + 0] = value[0]; + channel[(i * 4) + 1] = value[1]; + channel[(i * 4) + 2] = value[2]; + channel[(i * 4) + 3] = time; + } +} - int i, j; - char *cstr = NULL; - float *channel = NULL; +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 = modifiers_indexInObject(ob, (ModifierData *)fluidmd); + int framesize = (3*fobj->numVerts) + 1; + int j; + + if (channel == NULL) + return; - cstr = "fluidsiminit_channelfloat"; - if(entries>1) cstr = "fluidsiminit_channelvec"; - channel = MEM_callocN( size* (entries+1)* sizeof(float), cstr ); + initElbeemMesh(scene, ob, &numVerts, &verts, &numTris, &tris, 1, modifierIndex); - /* defaults for now */ - for(j=0; j<entries; j++) { - for(i=1; i<=size; i++) { - channel[(i-1)*(entries+1) + j] = defaults[j]; - } + /* don't allow mesh to change number of verts in anim sequence */ + if (numVerts != fobj->numVerts) { + MEM_freeN(channel); + channel = NULL; + return; } - for(i=1; i<=size; i++) { - channel[(i-1)*(entries+1) + entries] = time[i]; + /* 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); +} - *setchannel = channel; +static void free_domain_channels(FluidAnimChannels *channels) +{ + if (!channels->timeAtFrame) + return; + MEM_freeN(channels->timeAtFrame); + channels->timeAtFrame = NULL; + MEM_freeN(channels->DomainGravity); + channels->DomainGravity = NULL; + MEM_freeN(channels->DomainViscosity); + channels->DomainViscosity = NULL; +} -#if 0 - /* goes away completely */ - int i,j; - IpoCurve* icus[3]; - char *cstr = NULL; - float *channel = NULL; - float aniFrlen = scene->r.framelen; - int current_frame = scene->r.cfra; - if((entries<1) || (entries>3)) { - printf("fluidsimInitChannel::Error - invalid no. of entries: %d\n",entries); - entries = 1; +static void free_all_fluidobject_channels(ListBase *fobjects) +{ + FluidObject *fobj; + + for (fobj=fobjects->first; fobj; fobj=fobj->next) { + if (fobj->Translation) { + MEM_freeN(fobj->Translation); + fobj->Translation = NULL; + MEM_freeN(fobj->Rotation); + fobj->Rotation = NULL; + MEM_freeN(fobj->Scale); + fobj->Scale = NULL; + MEM_freeN(fobj->Active); + fobj->Active = NULL; + MEM_freeN(fobj->InitialVelocity); + fobj->InitialVelocity = NULL; + } + + if (fobj->AttractforceStrength) { + MEM_freeN(fobj->AttractforceStrength); + fobj->AttractforceStrength = NULL; + MEM_freeN(fobj->AttractforceRadius); + fobj->AttractforceRadius = NULL; + MEM_freeN(fobj->VelocityforceStrength); + fobj->VelocityforceStrength = NULL; + MEM_freeN(fobj->VelocityforceRadius); + fobj->VelocityforceRadius = NULL; + } + + if (fobj->VertexCache) { + MEM_freeN(fobj->VertexCache); + fobj->VertexCache = NULL; + } } +} - cstr = "fluidsiminit_channelfloat"; - if(entries>1) cstr = "fluidsiminit_channelvec"; - channel = MEM_callocN( size* (entries+1)* sizeof(float), cstr ); +static void fluid_init_all_channels(bContext *C, Object *fsDomain, FluidsimSettings *domainSettings, FluidAnimChannels *channels, ListBase *fobjects) +{ + Scene *scene = CTX_data_scene(C); + Base *base; + int i; + int length = channels->length; + float eval_time; - if(ipo) { - for(j=0; j<entries; j++) icus[j] = find_ipocurve(ipo, icuIds[j] ); - } else { - for(j=0; j<entries; j++) icus[j] = NULL; - } + /* XXX: first init time channel - temporary for now */ + /* init time values (should be done after evaluating animated time curve) */ + init_time(domainSettings, channels); - for(j=0; j<entries; j++) { - if(icus[j]) { - for(i=1; i<=size; i++) { - /* Bugfix to make python drivers working - // which uses Blender.get("curframe") - */ - scene->r.cfra = floor(aniFrlen*((float)i)); + /* allocate domain animation channels */ + channels->DomainGravity = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "channel DomainGravity"); + channels->DomainViscosity = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "channel DomainViscosity"); + //channels->DomainTime = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "channel DomainTime"); + + /* allocate fluid objects */ + for (base=scene->base.first; base; base= base->next) { + Object *ob = base->object; + FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); + + if (fluidmd) { + FluidObject *fobj = MEM_callocN(sizeof(FluidObject), "Fluid Object"); + fobj->object = ob; + + if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) { + BLI_addtail(fobjects, fobj); + continue; + } + + fobj->Translation = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject Translation"); + fobj->Rotation = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject Rotation"); + fobj->Scale = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject Scale"); + fobj->Active = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject Active"); + fobj->InitialVelocity = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject InitialVelocity"); + + if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) { + fobj->AttractforceStrength = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject AttractforceStrength"); + fobj->AttractforceRadius = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject AttractforceRadius"); + fobj->VelocityforceStrength = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject VelocityforceStrength"); + fobj->VelocityforceRadius = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject VelocityforceRadius"); + } + + if (fluid_is_animated_mesh(fluidmd->fss)) { + float *verts=NULL; + int *tris=NULL, modifierIndex = modifiers_indexInObject(ob, (ModifierData *)fluidmd); + + initElbeemMesh(scene, ob, &fobj->numVerts, &verts, &fobj->numTris, &tris, 0, modifierIndex); + fobj->VertexCache = MEM_callocN( length *((fobj->numVerts*CHANNEL_VEC)+1) * sizeof(float), "fluidobject VertexCache"); - // XXX calc_icu(icus[j], aniFrlen*((float)i) ); - channel[(i-1)*(entries+1) + j] = icus[j]->curval; + MEM_freeN(verts); + MEM_freeN(tris); } - } else { - for(i=1; i<=size; i++) { channel[(i-1)*(entries+1) + j] = defaults[j]; } + + BLI_addtail(fobjects, fobj); } - //printf("fluidsimInitChannel entry:%d , ",j); for(i=1; i<=size; i++) { printf(" val%d:%f ",i, channel[(i-1)*(entries+1) + j] ); } printf(" \n"); // DEBUG } - // set time values - for(i=1; i<=size; i++) { - channel[(i-1)*(entries+1) + entries] = time[i]; + + /* now we loop over the frames and fill the allocated channels with data */ + for (i=0; i<channels->length; i++) { + FluidObject *fobj; + float viscosity, gravity[3]; + float timeAtFrame; + + eval_time = domainSettings->bakeStart + i; + timeAtFrame = channels->timeAtFrame[i+1]; + + /* XXX: This can't be used due to an anim sys optimisation that ignores recalc object animation, + * leaving it for the depgraph (this ignores object animation such as modifier properties though... :/ ) + * --> BKE_animsys_evaluate_all_animation(G.main, eval_time); + * This doesn't work with drivers: + * --> BKE_animsys_evaluate_animdata(&fsDomain->id, fsDomain->adt, eval_time, ADT_RECALC_ALL); + */ + + /* Modifying the global scene isn't nice, but we can do it in + * this part of the process before a threaded job is created */ + scene->r.cfra = (int)eval_time; + ED_update_for_newframe(C, 1); + + /* now scene data should be current according to animation system, so we fill the channels */ + + /* Domain properties - gravity/viscosity/time */ + get_fluid_gravity(gravity, scene, domainSettings); + set_channel(channels->DomainGravity, timeAtFrame, gravity, i, CHANNEL_VEC); + viscosity = get_fluid_viscosity(domainSettings); + set_channel(channels->DomainViscosity, timeAtFrame, &viscosity, i, CHANNEL_FLOAT); + // XXX : set_channel(channels->DomainTime, timeAtFrame, &time, i, CHANNEL_VEC); + + /* object movement */ + for (fobj=fobjects->first; fobj; fobj=fobj->next) { + Object *ob = fobj->object; + FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); + float active= (float)(fluidmd->fss->flag & OB_FLUIDSIM_ACTIVE); + float rot_d[3], rot_360[3] = {360.f, 360.f, 360.f}; + + if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) + continue; + + /* init euler rotation values and convert to elbeem format */ + BKE_rotMode_change_values(ob->quat, ob->rot, ob->rotAxis, &ob->rotAngle, ob->rotmode, ROT_MODE_EUL); + mul_v3_v3fl(rot_d, ob->rot, 180.f/M_PI); + sub_v3_v3v3(rot_d, rot_360, rot_d); + + set_channel(fobj->Translation, timeAtFrame, ob->loc, i, CHANNEL_VEC); + set_channel(fobj->Rotation, timeAtFrame, rot_d, i, CHANNEL_VEC); + set_channel(fobj->Scale, timeAtFrame, ob->size, i, CHANNEL_VEC); + set_channel(fobj->Active, timeAtFrame, &active, i, CHANNEL_FLOAT); + set_channel(fobj->InitialVelocity, timeAtFrame, &fluidmd->fss->iniVelx, i, CHANNEL_VEC); + + if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) { + set_channel(fobj->AttractforceStrength, timeAtFrame, &fluidmd->fss->attractforceStrength, i, CHANNEL_FLOAT); + set_channel(fobj->AttractforceRadius, timeAtFrame, &fluidmd->fss->attractforceRadius, i, CHANNEL_FLOAT); + set_channel(fobj->VelocityforceStrength, timeAtFrame, &fluidmd->fss->velocityforceStrength, i, CHANNEL_FLOAT); + set_channel(fobj->VelocityforceRadius, timeAtFrame, &fluidmd->fss->velocityforceRadius, i, CHANNEL_FLOAT); + } + + if (fluid_is_animated_mesh(fluidmd->fss)) { + set_vertex_channel(fobj->VertexCache, timeAtFrame, scene, fobj, i); + } + } } - scene->r.cfra = current_frame; - *setchannel = channel; -#endif } -static void fluidsimInitMeshChannel(bContext *C, float **setchannel, int size, Object *obm, int vertices, - float *time, int modifierIndex) +static void export_fluid_objects(ListBase *fobjects, Scene *scene, int length) { - Scene *scene= CTX_data_scene(C); - float *channel = NULL; - int mallsize = size* (3*vertices+1); - int frame,i; - int numVerts=0, numTris=0; - int setsize = 3*vertices+1; - - channel = MEM_callocN( mallsize* sizeof(float), "fluidsim_meshchannel" ); - - //fprintf(stderr,"\n\nfluidsimInitMeshChannel size%d verts%d mallsize%d \n\n\n",size,vertices,mallsize); - for(frame=1; frame<=size; frame++) { + FluidObject *fobj; + + for (fobj=fobjects->first; fobj; fobj=fobj->next) { + Object *ob = fobj->object; + FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); + int modifierIndex = modifiers_indexInObject(ob, (ModifierData *)fluidmd); + float *verts=NULL; int *tris=NULL; - scene->r.cfra = frame; - ED_update_for_newframe(C, 1); + int numVerts=0, numTris=0; + int deform = fluid_is_animated_mesh(fluidmd->fss); + + elbeemMesh fsmesh; + + if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) + continue; + + elbeemResetMesh( &fsmesh ); + + fsmesh.type = fluidmd->fss->type; + fsmesh.name = ob->id.name; + + initElbeemMesh(scene, ob, &numVerts, &verts, &numTris, &tris, 0, modifierIndex); + + fsmesh.numVertices = numVerts; + fsmesh.numTriangles = numTris; + fsmesh.vertices = verts; + fsmesh.triangles = tris; + + fsmesh.channelSizeTranslation = + fsmesh.channelSizeRotation = + fsmesh.channelSizeScale = + fsmesh.channelSizeInitialVel = + fsmesh.channelSizeActive = length; + + fsmesh.channelTranslation = fobj->Translation; + fsmesh.channelRotation = fobj->Rotation; + fsmesh.channelScale = fobj->Scale; + fsmesh.channelActive = fobj->Active; + + if( ELEM(fsmesh.type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW)) { + fsmesh.channelInitialVel = fobj->InitialVelocity; + fsmesh.localInivelCoords = ((fluidmd->fss->typeFlags & OB_FSINFLOW_LOCALCOORD)?1:0); + } + + if(fluidmd->fss->typeFlags & OB_FSBND_NOSLIP) + fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP; + else if(fluidmd->fss->typeFlags & OB_FSBND_PARTSLIP) + fsmesh.obstacleType = FLUIDSIM_OBSTACLE_PARTSLIP; + else if(fluidmd->fss->typeFlags & OB_FSBND_FREESLIP) + fsmesh.obstacleType = FLUIDSIM_OBSTACLE_FREESLIP; + + fsmesh.obstaclePartslip = fluidmd->fss->partSlipValue; + fsmesh.volumeInitType = fluidmd->fss->volumeInitType; + fsmesh.obstacleImpactFactor = fluidmd->fss->surfaceSmoothing; // misused value + + if (fsmesh.type == OB_FLUIDSIM_CONTROL) { + fsmesh.cpsTimeStart = fluidmd->fss->cpsTimeStart; + fsmesh.cpsTimeEnd = fluidmd->fss->cpsTimeEnd; + fsmesh.cpsQuality = fluidmd->fss->cpsQuality; + fsmesh.obstacleType = (fluidmd->fss->flag & OB_FLUIDSIM_REVERSE); + + fsmesh.channelSizeAttractforceRadius = + fsmesh.channelSizeVelocityforceStrength = + fsmesh.channelSizeVelocityforceRadius = + fsmesh.channelSizeAttractforceStrength = length; + + fsmesh.channelAttractforceStrength = fobj->AttractforceStrength; + fsmesh.channelAttractforceRadius = fobj->AttractforceRadius; + fsmesh.channelVelocityforceStrength = fobj->VelocityforceStrength; + fsmesh.channelVelocityforceRadius = fobj->VelocityforceRadius; + } + else { + fsmesh.channelAttractforceStrength = + fsmesh.channelAttractforceRadius = + fsmesh.channelVelocityforceStrength = + fsmesh.channelVelocityforceRadius = NULL; + } + + /* animated meshes */ + if(deform) { + fsmesh.channelSizeVertices = length; + fsmesh.channelVertices = fobj->VertexCache; + + // remove channels + fsmesh.channelTranslation = + fsmesh.channelRotation = + fsmesh.channelScale = NULL; + } + + elbeemAddMesh(&fsmesh); + + if(verts) MEM_freeN(verts); + if(tris) MEM_freeN(tris); + if(fsmesh.channelVertices) MEM_freeN(fsmesh.channelVertices); + } +} + +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); - initElbeemMesh(scene, obm, &numVerts, &verts, &numTris, &tris, 1, modifierIndex); - //fprintf(stderr,"\nfluidsimInitMeshChannel frame%d verts%d/%d \n\n",frame,vertices,numVerts); - for(i=0; i<3*vertices;i++) { - channel[(frame-1)*setsize + i] = verts[i]; - //fprintf(stdout," frame%d vert%d=%f \n",frame,i,verts[i]); - //if(i%3==2) fprintf(stdout,"\n"); + /* 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; + } } - channel[(frame-1)*setsize + setsize-1] = time[frame]; + + /* 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++; + } - MEM_freeN(verts); - MEM_freeN(tris); + 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; } - *setchannel = channel; + + if (fluidInputCount == 0) { + BKE_report(reports, RPT_ERROR, "No fluid input objects in the scene."); + return 0; + } + + return 1; } +#define FLUID_SUFFIX_CONFIG "fluidsim.cfg" +#define FLUID_SUFFIX_SURFACE "fluidsurface" + +static int fluid_init_filepaths(Object *fsDomain, char *targetDir, char *targetFile, char *debugStrBuffer) +{ + FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim); + FluidsimSettings *domainSettings= fluidmd->fss; + FILE *fileCfg; + int dirExist = 0; + char newSurfdataPath[FILE_MAXDIR+FILE_MAXFILE]; // modified output settings + char *suffixConfig = FLUID_SUFFIX_CONFIG; + int outStringsChanged = 0; + + // prepare names... + strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR); + strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR); + BLI_path_abs(targetDir, G.sce); // fixed #frame-no + + strcpy(targetFile, targetDir); + strcat(targetFile, suffixConfig); + strcat(targetFile,".tmp"); // dont overwrite/delete original file + // make sure all directories exist + // as the bobjs use the same dir, this only needs to be checked + // for the cfg output + BLI_make_existing_file(targetFile); + + // check selected directory + // simply try to open cfg file for writing to test validity of settings + fileCfg = fopen(targetFile, "w"); + if(fileCfg) { + dirExist = 1; fclose(fileCfg); + // remove cfg dummy from directory test + BLI_delete(targetFile, 0,0); + } + + if((strlen(targetDir)<1) || (!dirExist)) { + char blendDir[FILE_MAXDIR+FILE_MAXFILE]; + char blendFile[FILE_MAXDIR+FILE_MAXFILE]; + + // invalid dir, reset to current/previous + strcpy(blendDir, G.sce); + BLI_splitdirstring(blendDir, blendFile); + if(strlen(blendFile)>6){ + int len = strlen(blendFile); + if( (blendFile[len-6]=='.')&& (blendFile[len-5]=='b')&& (blendFile[len-4]=='l')&& + (blendFile[len-3]=='e')&& (blendFile[len-2]=='n')&& (blendFile[len-1]=='d') ){ + blendFile[len-6] = '\0'; + } + } + // todo... strip .blend ? + snprintf(newSurfdataPath,FILE_MAXFILE+FILE_MAXDIR,"//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name); + + snprintf(debugStrBuffer,256,"fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath); + elbeemDebugOut(debugStrBuffer); + outStringsChanged=1; + } + + // check if modified output dir is ok +#if 0 + if(outStringsChanged) { + char dispmsg[FILE_MAXDIR+FILE_MAXFILE+256]; + int selection=0; + strcpy(dispmsg,"Output settings set to: '"); + strcat(dispmsg, newSurfdataPath); + strcat(dispmsg, "'%t|Continue with changed settings%x1|Discard and abort%x0"); + + // ask user if thats what he/she wants... + selection = pupmenu(dispmsg); + if(selection<1) return 0; // 0 from menu, or -1 aborted + strcpy(targetDir, newSurfdataPath); + strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR); + BLI_path_abs(targetDir, G.sce); // fixed #frame-no + } +#endif + return outStringsChanged; +} + /* ******************************************************************************** */ -/* ********************** simulation thread ************************* */ +/* ********************** write fluidsim config to file ************************* */ /* ******************************************************************************** */ -static volatile int globalBakeState = 0; // 0 everything ok, -1 abort simulation, -2 sim error, 1 sim done -static volatile int globalBakeFrame = 0; -static volatile int g_break= 0; +typedef struct FluidBakeJob { + /* from wmJob */ + void *owner; + short *stop, *do_update; + float *progress; + int current_frame; + elbeemSimulationSettings *settings; +} FluidBakeJob; -// run simulation in seperate thread -static void *fluidsimSimulateThread(void *unused) { // *ptr) { - //char* fnameCfgPath = (char*)(ptr); - int ret=0; +static void fluidbake_free(void *customdata) +{ + FluidBakeJob *fb= customdata; + MEM_freeN(fb); +} + +/* called by fluidbake, only to check job 'stop' value */ +static int fluidbake_breakjob(void *customdata) +{ + //FluidBakeJob *fb= (FluidBakeJob *)customdata; + //return *(fb->stop); -#if defined(__APPLE__) && (PARALLEL == 1) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2) - // Workaround for Apple gcc 4.2.1 omp vs background thread bug - pthread_setspecific (gomp_tls_key, thread_tls_data); -#endif + /* this is not nice yet, need to make the jobs list template better + * for identifying/acting upon various different jobs */ + /* but for now we'll reuse the render break... */ + return (G.afbreek); +} - ret = elbeemSimulate(); - BLI_lock_thread(LOCK_CUSTOM1); - if(globalBakeState==0) { - if(ret==0) { - // if no error, set to normal exit - globalBakeState = 1; - } else { - // simulation failed, display error - globalBakeState = -2; - } - } - BLI_unlock_thread(LOCK_CUSTOM1); - return NULL; +/* called by fluidbake, wmJob sends notifier */ +static void fluidbake_updatejob(void *customdata, float progress) +{ + FluidBakeJob *fb= customdata; + + *(fb->do_update)= 1; + *(fb->progress)= progress; } +static void fluidbake_startjob(void *customdata, short *stop, short *do_update, float *progress) +{ + FluidBakeJob *fb= customdata; + + fb->stop= stop; + fb->do_update = do_update; + fb->progress = progress; + + G.afbreek= 0; /* XXX shared with render - replace with job 'stop' switch */ + + elbeemSimulate(); + *do_update= 1; + *stop = 0; +} -int runSimulationCallback(void *data, int status, int frame) { - //elbeemSimulationSettings *settings = (elbeemSimulationSettings*)data; - //printf("elbeem blender cb s%d, f%d, domainid:%d \n", status,frame, settings->domainId ); // DEBUG - int state = 0; - if(status==FLUIDSIM_CBSTATUS_NEWFRAME) { - BLI_lock_thread(LOCK_CUSTOM1); - globalBakeFrame = frame-1; - BLI_unlock_thread(LOCK_CUSTOM1); +static void fluidbake_endjob(void *customdata) +{ + FluidBakeJob *fb= customdata; + + if (fb->settings) { + MEM_freeN(fb->settings); + fb->settings = NULL; } +} + +int runSimulationCallback(void *data, int status, int frame) { + FluidBakeJob *fb = (FluidBakeJob *)data; + elbeemSimulationSettings *settings = fb->settings; - //if((frameCounter==3) && (!frameStop)) { frameStop=1; return 1; } - - BLI_lock_thread(LOCK_CUSTOM1); - state = globalBakeState; - BLI_unlock_thread(LOCK_CUSTOM1); + if (status == FLUIDSIM_CBSTATUS_NEWFRAME) { + fluidbake_updatejob(fb, frame / (float)settings->noOfFrames); + //printf("elbeem blender cb s%d, f%d, domainid:%d noOfFrames: %d \n", status,frame, settings->domainId, settings->noOfFrames ); // DEBUG + } - if(state!=0) { + if (fluidbake_breakjob(fb)) { return FLUIDSIM_CBRET_ABORT; } return FLUIDSIM_CBRET_CONTINUE; } +static void fluidbake_free_data(FluidAnimChannels *channels, ListBase *fobjects, elbeemSimulationSettings *fsset, FluidBakeJob *fb) +{ + free_domain_channels(channels); + MEM_freeN(channels); + channels = NULL; + + free_all_fluidobject_channels(fobjects); + BLI_freelistN(fobjects); + MEM_freeN(fobjects); + fobjects = NULL; + + if (fsset) { + MEM_freeN(fsset); + fsset = NULL; + } + + if (fb) { + MEM_freeN(fb); + fb = NULL; + } +} -/* ******************************************************************************** */ -/* ********************** write fluidsim config to file ************************* */ -/* ******************************************************************************** */ - -int fluidsimBake(bContext *C, ReportList *reports, Object *ob) +int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain) { Scene *scene= CTX_data_scene(C); - FILE *fileCfg; int i; - Object *fsDomain = NULL; FluidsimSettings *domainSettings; - Object *obit = NULL; /* object iterator */ - Base *base; - int origFrame = scene->r.cfra; + char debugStrBuffer[256]; - int dirExist = 0; + int gridlevels = 0; - int simAborted = 0; // was the simulation aborted by user? - int doExportOnly = 0; - char *exportEnvStr = "BLENDER_ELBEEMEXPORTONLY"; const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp - //char *channelNames[3] = { "translation","rotation","scale" }; + char *suffixConfig = FLUID_SUFFIX_CONFIG; + char *suffixSurface = FLUID_SUFFIX_SURFACE; - char *suffixConfig = "fluidsim.cfg"; - char *suffixSurface = "fluidsurface"; - char newSurfdataPath[FILE_MAXDIR+FILE_MAXFILE]; // modified output settings char targetDir[FILE_MAXDIR+FILE_MAXFILE]; // store & modify output settings char targetFile[FILE_MAXDIR+FILE_MAXFILE]; // temp. store filename from targetDir for access int outStringsChanged = 0; // modified? copy back before baking - int haveSomeFluid = 0; // check if any fluid objects are set - // config vars, inited before either export or run... - double calcViscosity = 0.0; - int noFrames; - double aniFrameTime; - float aniFrlen; - int channelObjCount; - float *bbStart = NULL; - float *bbSize = NULL; float domainMat[4][4]; float invDomMat[4][4]; - // channel data - int allchannelSize; // fixed by no. of frames - int startFrame = 1; // dont use scene->r.sfra here, always start with frame 1 - // easy frame -> sim time calc - float *timeAtFrame=NULL, *timeAtIndex=NULL; - // domain - float *channelDomainTime = NULL; - float *channelDomainViscosity = NULL; - float *channelDomainGravity = NULL; - // objects (currently max. 256 objs) - float *channelObjMove[256][3]; // object movments , 0=trans, 1=rot, 2=scale - float *channelObjInivel[256]; // initial velocities - float *channelObjActive[256]; // obj active channel - - /* fluid control channels */ - float *channelAttractforceStrength[256]; - float *channelAttractforceRadius[256]; - float *channelVelocityforceStrength[256]; - float *channelVelocityforceRadius[256]; + + 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; + wmJob *steve; + FluidBakeJob *fb; + elbeemSimulationSettings *fsset= MEM_callocN(sizeof(elbeemSimulationSettings), "Fluid sim settings"); + + steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Fluid Simulation", WM_JOB_PROGRESS); + fb= MEM_callocN(sizeof(FluidBakeJob), "fluid bake job"); + if(getenv(strEnvName)) { int dlevel = atoi(getenv(strEnvName)); elbeemSetDebugLevel(dlevel); snprintf(debugStrBuffer,256,"fluidsimBake::msg: Debug messages activated due to envvar '%s'\n",strEnvName); elbeemDebugOut(debugStrBuffer); } - if(getenv(exportEnvStr)) { - doExportOnly = atoi(getenv(exportEnvStr)); - snprintf(debugStrBuffer,256,"fluidsimBake::msg: Exporting mode set to '%d' due to envvar '%s'\n",doExportOnly, exportEnvStr); - elbeemDebugOut(debugStrBuffer); - } - - // make sure it corresponds to startFrame setting - // old: noFrames = scene->r.efra - scene->r.sfra +1; + + /* 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; } - - /* no object pointer, find in selected ones.. */ - if(!ob) { - for(base=scene->base.first; base; base= base->next) { - if ((base)->flag & SELECT) - { - FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); - - if(fluidmdtmp && (base->object->type==OB_MESH)) - { - if(fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) - { - ob = base->object; - break; - } - } - } - } - // no domains found? - if(!ob) return 0; - } - channelObjCount = 0; - for(base=scene->base.first; base; base= base->next) - { - FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); - obit = base->object; - if( fluidmdtmp && - (obit->type==OB_MESH) && - (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN) && // if has to match 3 places! // CHECKMATCH - (fluidmdtmp->fss->type != OB_FLUIDSIM_PARTICLE) ) - { - channelObjCount++; - } - } - - if (channelObjCount>=255) { - BKE_report(reports, RPT_ERROR, "Cannot bake with more then 256 objects."); - return 0; - } - - /* check if there's another domain... */ - for(base=scene->base.first; base; base= base->next) - { - FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); - obit = base->object; - if( fluidmdtmp &&(obit->type==OB_MESH)) - { - if(fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) - { - if(obit != ob) - { - BKE_report(reports, RPT_ERROR, "There should be only one domain object."); - return 0; - } - } - } - } - - // check if theres any fluid - // abort baking if not... - for(base=scene->base.first; base; base= base->next) - { - FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); - obit = base->object; - if( fluidmdtmp && - (obit->type==OB_MESH) && - ((fluidmdtmp->fss->type == OB_FLUIDSIM_FLUID) || - (fluidmdtmp->fss->type == OB_FLUIDSIM_INFLOW) )) - { - haveSomeFluid = 1; - break; - } - } - if(!haveSomeFluid) { - BKE_report(reports, RPT_ERROR, "No fluid objects in scene."); + /* 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 wouldnt be here */ - /* dont use ob here after...*/ - fsDomain = ob; - fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); + fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim); domainSettings = fluidmd->fss; - ob = NULL; 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); @@ -572,107 +899,26 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *ob) } snprintf(debugStrBuffer,256,"fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name , gridlevels ); elbeemDebugOut(debugStrBuffer); - - // prepare names... - strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR); - strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR); - BLI_convertstringcode(targetDir, G.sce); // fixed #frame-no - - strcpy(targetFile, targetDir); - strcat(targetFile, suffixConfig); - if(!doExportOnly) { strcat(targetFile,".tmp"); } // dont overwrite/delete original file - // make sure all directories exist - // as the bobjs use the same dir, this only needs to be checked - // for the cfg output - BLI_make_existing_file(targetFile); - - // check selected directory - // simply try to open cfg file for writing to test validity of settings - fileCfg = fopen(targetFile, "w"); - if(fileCfg) { - dirExist = 1; fclose(fileCfg); - // remove cfg dummy from directory test - if(!doExportOnly) { BLI_delete(targetFile, 0,0); } - } - - if((strlen(targetDir)<1) || (!dirExist)) { - char blendDir[FILE_MAXDIR+FILE_MAXFILE], blendFile[FILE_MAXDIR+FILE_MAXFILE]; - // invalid dir, reset to current/previous - strcpy(blendDir, G.sce); - BLI_splitdirstring(blendDir, blendFile); - if(strlen(blendFile)>6){ - int len = strlen(blendFile); - if( (blendFile[len-6]=='.')&& (blendFile[len-5]=='b')&& (blendFile[len-4]=='l')&& - (blendFile[len-3]=='e')&& (blendFile[len-2]=='n')&& (blendFile[len-1]=='d') ){ - blendFile[len-6] = '\0'; - } - } - // todo... strip .blend ? - snprintf(newSurfdataPath,FILE_MAXFILE+FILE_MAXDIR,"//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name); - - snprintf(debugStrBuffer,256,"fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath); - elbeemDebugOut(debugStrBuffer); - outStringsChanged=1; - } - - // check if modified output dir is ok - if(outStringsChanged) { - char dispmsg[FILE_MAXDIR+FILE_MAXFILE+256]; - int selection=0; - strcpy(dispmsg,"Output settings set to: '"); - strcat(dispmsg, newSurfdataPath); - strcat(dispmsg, "'%t|Continue with changed settings%x1|Discard and abort%x0"); - - // ask user if thats what he/she wants... - selection = pupmenu(dispmsg); - if(selection<1) return 0; // 0 from menu, or -1 aborted - strcpy(targetDir, newSurfdataPath); - strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR); - BLI_convertstringcode(targetDir, G.sce); // fixed #frame-no - } - // -------------------------------------------------------------------------------------------- - // dump data for start frame - // CHECK more reasonable to number frames according to blender? - // dump data for frame 0 - scene->r.cfra = startFrame; - ED_update_for_newframe(C, 1); - // init common export vars for both file export and run - for(i=0; i<256; i++) { - channelObjMove[i][0] = channelObjMove[i][1] = channelObjMove[i][2] = NULL; - channelObjInivel[i] = NULL; - channelObjActive[i] = NULL; - channelAttractforceStrength[i] = NULL; - channelAttractforceRadius[i] = NULL; - channelVelocityforceStrength[i] = NULL; - channelVelocityforceRadius[i] = NULL; - } - allchannelSize = scene->r.efra; // always use till last frame - aniFrameTime = (domainSettings->animEnd - domainSettings->animStart)/(double)noFrames; - // blender specific - scale according to map old/new settings in anim panel: - aniFrlen = scene->r.framelen; - if(domainSettings->viscosityMode==1) { - /* manual mode, visc=value/(10^-vexp) */ - calcViscosity = (1.0/pow(10.0,domainSettings->viscosityExponent)) * domainSettings->viscosityValue; - } else { - calcViscosity = fluidsimViscosityPreset[ domainSettings->viscosityMode ]; - } - - bbStart = domainSettings->bbStart; - bbSize = domainSettings->bbSize; + + /* ******** prepare output file paths ******** */ + outStringsChanged = fluid_init_filepaths(fsDomain, targetDir, targetFile, debugStrBuffer); + channels->length = scene->r.efra; + channels->aniFrameTime = (domainSettings->animEnd - domainSettings->animStart)/(double)noFrames; + + /* ******** initialise and allocate animation channels ******** */ + fluid_init_all_channels(C, fsDomain, domainSettings, channels, fobjects); - // always init + /* reset to original current frame */ + scene->r.cfra = origFrame; + ED_update_for_newframe(C, 1); + + + /* ---- XXX: No Time animation curve for now, leaving this code here for reference + { int timeIcu[1] = { FLUIDSIM_TIME }; float timeDef[1] = { 1. }; - int gravIcu[3] = { FLUIDSIM_GRAV_X, FLUIDSIM_GRAV_Y, FLUIDSIM_GRAV_Z }; - float gravDef[3]; - int viscIcu[1] = { FLUIDSIM_VISC }; - float viscDef[1] = { 1. }; - - gravDef[0] = domainSettings->gravx; - gravDef[1] = domainSettings->gravy; - gravDef[2] = domainSettings->gravz; // time channel is a bit special, init by hand... timeAtIndex = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatindex"); @@ -680,7 +926,7 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *ob) timeAtIndex[i] = (float)(i-startFrame); } fluidsimInitChannel(scene, &channelDomainTime, allchannelSize, timeAtIndex, timeIcu,timeDef, domainSettings->ipo, CHANNEL_FLOAT ); // NDEB - // time channel is a multiplicator for aniFrameTime + // time channel is a multiplicator for if(channelDomainTime) { for(i=0; i<allchannelSize; i++) { channelDomainTime[i*2+0] = aniFrameTime * channelDomainTime[i*2+0]; @@ -693,474 +939,112 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *ob) for(i=2; i<=allchannelSize; i++) { timeAtFrame[i] = timeAtFrame[i-1]+channelDomainTime[(i-1)*2+0]; } - } else { + fsset->} else { for(i=2; i<=allchannelSize; i++) { timeAtFrame[i] = timeAtFrame[i-1]+aniFrameTime; } } - fluidsimInitChannel(scene, &channelDomainViscosity, allchannelSize, timeAtFrame, viscIcu,viscDef, domainSettings->ipo, CHANNEL_FLOAT ); // NDEB - if(channelDomainViscosity) { - for(i=0; i<allchannelSize; i++) { channelDomainViscosity[i*2+0] = calcViscosity * channelDomainViscosity[i*2+0]; } - } - fluidsimInitChannel(scene, &channelDomainGravity, allchannelSize, timeAtFrame, gravIcu,gravDef, domainSettings->ipo, CHANNEL_VEC ); } // domain channel init - - // init obj movement channels - channelObjCount=0; - for(base=scene->base.first; base; base= base->next) - { - FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); - obit = base->object; + */ - if( fluidmdtmp && - (obit->type==OB_MESH) && - (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN) && // if has to match 3 places! // CHECKMATCH - (fluidmdtmp->fss->type != OB_FLUIDSIM_PARTICLE) ) { - - // cant use fluidsimInitChannel for obj channels right now, due - // to the special DXXX channels, and the rotation specialities - IpoCurve *icuex[3][3]; - //IpoCurve *par_icuex[3][3]; -#if 0 - int icuIds[3][3] = { - {OB_LOC_X, OB_LOC_Y, OB_LOC_Z}, - {OB_ROT_X, OB_ROT_Y, OB_ROT_Z}, - {OB_SIZE_X, OB_SIZE_Y, OB_SIZE_Z} - }; - int icudIds[3][3] = { - {OB_DLOC_X, OB_DLOC_Y, OB_DLOC_Z}, - {OB_DROT_X, OB_DROT_Y, OB_DROT_Z}, - {OB_DSIZE_X, OB_DSIZE_Y, OB_DSIZE_Z} - }; -#endif - // relative ipos - IpoCurve *icudex[3][3]; - //IpoCurve *par_icudex[3][3]; - int j,k; - float vals[3] = {0.0,0.0,0.0}; - int o = channelObjCount; - int inivelIcu[3] = { FLUIDSIM_VEL_X, FLUIDSIM_VEL_Y, FLUIDSIM_VEL_Z }; - float inivelDefs[3]; - int activeIcu[1] = { FLUIDSIM_ACTIVE }; - float activeDefs[1] = { 1 }; // default to on - - inivelDefs[0] = fluidmdtmp->fss->iniVelx; - inivelDefs[1] = fluidmdtmp->fss->iniVely; - inivelDefs[2] = fluidmdtmp->fss->iniVelz; - - // check & init loc,rot,size - for(j=0; j<3; j++) { - for(k=0; k<3; k++) { - // XXX prevent invalid memory access until this works - icuex[j][k]= NULL; - icudex[j][k]= NULL; - - // XXX icuex[j][k] = find_ipocurve(obit->ipo, icuIds[j][k] ); - // XXX icudex[j][k] = find_ipocurve(obit->ipo, icudIds[j][k] ); - // XXX lines below were already disabled! - //if(obit->parent) { - //par_icuex[j][k] = find_ipocurve(obit->parent->ipo, icuIds[j][k] ); - //par_icudex[j][k] = find_ipocurve(obit->parent->ipo, icudIds[j][k] ); - //} - } - } - - for(j=0; j<3; j++) { - channelObjMove[o][j] = MEM_callocN( allchannelSize*4*sizeof(float), "fluidsiminit_objmovchannel"); - for(i=1; i<=allchannelSize; i++) { - - for(k=0; k<3; k++) { - if(icuex[j][k]) { - // IPO exists, use it ... - // XXX calc_icu(icuex[j][k], aniFrlen*((float)i) ); - vals[k] = icuex[j][k]->curval; - if(obit->parent) { - // add parent transform, multiply scaling, add trafo&rot - //calc_icu(par_icuex[j][k], aniFrlen*((float)i) ); - //if(j==2) { vals[k] *= par_icuex[j][k]->curval; } - //else { vals[k] += par_icuex[j][k]->curval; } - } - } else { - // use defaults from static values - float setval=0.0; - if(j==0) { - setval = obit->loc[k]; - if(obit->parent){ setval += obit->parent->loc[k]; } - } else if(j==1) { - setval = ( 180.0*obit->rot[k] )/( 10.0*M_PI ); - if(obit->parent){ setval = ( 180.0*(obit->rot[k]+obit->parent->rot[k]) )/( 10.0*M_PI ); } - } else { - setval = obit->size[k]; - if(obit->parent){ setval *= obit->parent->size[k]; } - } - vals[k] = setval; - } - if(icudex[j][k]) { - // XXX calc_icu(icudex[j][k], aniFrlen*((float)i) ); - //vals[k] += icudex[j][k]->curval; - // add transform, multiply scaling, add trafo&rot - if(j==2) { vals[k] *= icudex[j][k]->curval; } - else { vals[k] += icudex[j][k]->curval; } - if(obit->parent) { - // add parent transform, multiply scaling, add trafo&rot - //calc_icu(par_icuex[j][k], aniFrlen*((float)i) ); - //if(j==2) { vals[k] *= par_icudex[j][k]->curval; } - //else { vals[k] += par_icudex[j][k]->curval; } - } - } - } // k - - for(k=0; k<3; k++) { - float set = vals[k]; - if(j==1) { // rot is downscaled by 10 for ipo !? - set = 360.0 - (10.0*set); - } - channelObjMove[o][j][(i-1)*4 + k] = set; - } // k - channelObjMove[o][j][(i-1)*4 + 3] = timeAtFrame[i]; - } - } - - { - int attrFSIcu[1] = { FLUIDSIM_ATTR_FORCE_STR }; - int attrFRIcu[1] = { FLUIDSIM_ATTR_FORCE_RADIUS }; - int velFSIcu[1] = { FLUIDSIM_VEL_FORCE_STR }; - int velFRIcu[1] = { FLUIDSIM_VEL_FORCE_RADIUS }; - - float attrFSDefs[1]; - float attrFRDefs[1]; - float velFSDefs[1]; - float velFRDefs[1]; - - attrFSDefs[0] = fluidmdtmp->fss->attractforceStrength; - attrFRDefs[0] = fluidmdtmp->fss->attractforceRadius; - velFSDefs[0] = fluidmdtmp->fss->velocityforceStrength; - velFRDefs[0] = fluidmdtmp->fss->velocityforceRadius; - - fluidsimInitChannel(scene, &channelAttractforceStrength[o], allchannelSize, timeAtFrame, attrFSIcu,attrFSDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT ); - fluidsimInitChannel(scene, &channelAttractforceRadius[o], allchannelSize, timeAtFrame, attrFRIcu,attrFRDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT ); - fluidsimInitChannel(scene, &channelVelocityforceStrength[o], allchannelSize, timeAtFrame, velFSIcu,velFSDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT ); - fluidsimInitChannel(scene, &channelVelocityforceRadius[o], allchannelSize, timeAtFrame, velFRIcu,velFRDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT ); - } - - fluidsimInitChannel(scene, &channelObjInivel[o], allchannelSize, timeAtFrame, inivelIcu,inivelDefs, fluidmdtmp->fss->ipo, CHANNEL_VEC ); - fluidsimInitChannel(scene, &channelObjActive[o], allchannelSize, timeAtFrame, activeIcu,activeDefs, fluidmdtmp->fss->ipo, CHANNEL_FLOAT ); - - - channelObjCount++; - - } - } - - // init trafo matrix + /* ******** init domain object's matrix ******** */ copy_m4_m4(domainMat, fsDomain->obmat); if(!invert_m4_m4(invDomMat, domainMat)) { snprintf(debugStrBuffer,256,"fluidsimBake::error - Invalid obj matrix?\n"); elbeemDebugOut(debugStrBuffer); BKE_report(reports, RPT_ERROR, "Invalid object matrix."); - // FIXME add fatal msg - FS_FREE_CHANNELS; + + fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } - // -------------------------------------------------------------------------------------------- - // start writing / exporting + /* ******** start writing / exporting ******** */ strcpy(targetFile, targetDir); strcat(targetFile, suffixConfig); - if(!doExportOnly) { strcat(targetFile,".tmp"); } // dont overwrite/delete original file + strcat(targetFile,".tmp"); // dont overwrite/delete original file + // make sure these directories exist as well if(outStringsChanged) { BLI_make_existing_file(targetFile); } - if(!doExportOnly) { - ListBase threads; + /* ******** export domain to elbeem ******** */ + elbeemResetSettings(fsset); + fsset->version = 1; - // perform simulation with El'Beem api and threads - elbeemSimulationSettings fsset; - elbeemResetSettings(&fsset); - fsset.version = 1; + // 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; - // setup global settings - for(i=0 ; i<3; i++) fsset.geoStart[i] = bbStart[i]; - for(i=0 ; i<3; i++) fsset.geoSize[i] = bbSize[i]; - - // simulate with 50^3 - fsset.resolutionxyz = (int)domainSettings->resolutionxyz; - fsset.previewresxyz = (int)domainSettings->previewresxyz; - // 10cm water domain - fsset.realsize = domainSettings->realsize; - fsset.viscosity = calcViscosity; - // earth gravity - fsset.gravity[0] = domainSettings->gravx; - fsset.gravity[1] = domainSettings->gravy; - fsset.gravity[2] = domainSettings->gravz; - // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz - fsset.animStart = domainSettings->animStart; - fsset.aniFrameTime = aniFrameTime; - fsset.noOfFrames = noFrames; // is otherwise subtracted in parser - strcpy(targetFile, targetDir); - strcat(targetFile, 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; - strcpy( fsset.outputPath, targetFile); - - // domain channels - fsset.channelSizeFrameTime = - fsset.channelSizeViscosity = - fsset.channelSizeGravity = allchannelSize; - fsset.channelFrameTime = channelDomainTime; - fsset.channelViscosity = channelDomainViscosity; - fsset.channelGravity = channelDomainGravity; - - fsset.runsimCallback = &runSimulationCallback; - fsset.runsimUserData = &fsset; - - 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; - fsset.generateVertexVectors = (domainSettings->domainNovecgen==0); - - // init blender trafo matrix - // fprintf(stderr,"elbeemInit - mpTrafo:\n"); - { int j; - for(i=0; i<4; i++) { - for(j=0; j<4; j++) { - fsset.surfaceTrafo[i*4+j] = invDomMat[j][i]; - // fprintf(stderr,"elbeemInit - mpTrafo %d %d = %f (%d) \n", i,j, fsset.surfaceTrafo[i*4+j] , (i*4+j) ); - } - } } + fsset->realsize = get_fluid_size_m(scene, fsDomain, domainSettings); + fsset->viscosity = get_fluid_viscosity(domainSettings); + get_fluid_gravity(fsset->gravity, scene, domainSettings); - // init solver with settings - elbeemInit(); - elbeemAddDomain(&fsset); - - // init objects - channelObjCount = 0; - for(base=scene->base.first; base; base= base->next) { - FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(base->object, eModifierType_Fluidsim); - obit = base->object; - //{ snprintf(debugStrBuffer,256,"DEBUG object name=%s, type=%d ...\n", obit->id.name, obit->type); elbeemDebugOut(debugStrBuffer); } // DEBUG - if( fluidmdtmp && // if has to match 3 places! // CHECKMATCH - (obit->type==OB_MESH) && - (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN) && - (fluidmdtmp->fss->type != OB_FLUIDSIM_PARTICLE)) - { - float *verts=NULL; - int *tris=NULL; - int numVerts=0, numTris=0; - int o = channelObjCount; - int deform = (fluidmdtmp->fss->domainNovecgen); // misused value - // todo - use blenderInitElbeemMesh - int modifierIndex = modifiers_indexInObject(obit, (ModifierData *)fluidmdtmp); - - elbeemMesh fsmesh; - elbeemResetMesh( &fsmesh ); - fsmesh.type = fluidmdtmp->fss->type; - // get name of object for debugging solver - fsmesh.name = obit->id.name; - - initElbeemMesh(scene, obit, &numVerts, &verts, &numTris, &tris, 0, modifierIndex); - fsmesh.numVertices = numVerts; - fsmesh.numTriangles = numTris; - fsmesh.vertices = verts; - fsmesh.triangles = tris; - - fsmesh.channelSizeTranslation = - fsmesh.channelSizeRotation = - fsmesh.channelSizeScale = - fsmesh.channelSizeInitialVel = - fsmesh.channelSizeActive = allchannelSize; - - fsmesh.channelTranslation = channelObjMove[o][0]; - fsmesh.channelRotation = channelObjMove[o][1]; - fsmesh.channelScale = channelObjMove[o][2]; - fsmesh.channelActive = channelObjActive[o]; - if( (fsmesh.type == OB_FLUIDSIM_FLUID) || - (fsmesh.type == OB_FLUIDSIM_INFLOW)) { - fsmesh.channelInitialVel = channelObjInivel[o]; - fsmesh.localInivelCoords = ((fluidmdtmp->fss->typeFlags&OB_FSINFLOW_LOCALCOORD)?1:0); - } - - if( (fluidmdtmp->fss->typeFlags&OB_FSBND_NOSLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP; - else if((fluidmdtmp->fss->typeFlags&OB_FSBND_PARTSLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_PARTSLIP; - else if((fluidmdtmp->fss->typeFlags&OB_FSBND_FREESLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_FREESLIP; - fsmesh.obstaclePartslip = fluidmdtmp->fss->partSlipValue; - fsmesh.volumeInitType = fluidmdtmp->fss->volumeInitType; - fsmesh.obstacleImpactFactor = fluidmdtmp->fss->surfaceSmoothing; // misused value - - if(fsmesh.type == OB_FLUIDSIM_CONTROL) - { - // control fluids will get exported as whole - deform = 1; - - fsmesh.cpsTimeStart = fluidmdtmp->fss->cpsTimeStart; - fsmesh.cpsTimeEnd = fluidmdtmp->fss->cpsTimeEnd; - fsmesh.cpsQuality = fluidmdtmp->fss->cpsQuality; - fsmesh.obstacleType = (fluidmdtmp->fss->flag & OB_FLUIDSIM_REVERSE); - - fsmesh.channelSizeAttractforceRadius = - fsmesh.channelSizeVelocityforceStrength = - fsmesh.channelSizeVelocityforceRadius = - fsmesh.channelSizeAttractforceStrength = allchannelSize; - - fsmesh.channelAttractforceStrength = channelAttractforceStrength[o]; - fsmesh.channelAttractforceRadius = channelAttractforceRadius[o]; - fsmesh.channelVelocityforceStrength = channelVelocityforceStrength[o]; - fsmesh.channelVelocityforceRadius = channelVelocityforceRadius[o]; - } - else - { - // set channels to 0 - fsmesh.channelAttractforceStrength = - fsmesh.channelAttractforceRadius = - fsmesh.channelVelocityforceStrength = - fsmesh.channelVelocityforceRadius = NULL; - } - - // animated meshes - if(deform) { - fsmesh.channelSizeVertices = allchannelSize; - fluidsimInitMeshChannel(C, &fsmesh.channelVertices, allchannelSize, obit, numVerts, timeAtFrame, modifierIndex); - scene->r.cfra = startFrame; - ED_update_for_newframe(C, 1); - // remove channels - fsmesh.channelTranslation = - fsmesh.channelRotation = - fsmesh.channelScale = NULL; - } - - elbeemAddMesh(&fsmesh); - - if(verts) MEM_freeN(verts); - if(tris) MEM_freeN(tris); - if(fsmesh.channelVertices) MEM_freeN(fsmesh.channelVertices); - channelObjCount++; - } // valid mesh - } // objects - //domainSettings->type = OB_FLUIDSIM_DOMAIN; // enable for bake display again - - // set to neutral, -1 means user abort, -2 means init error - globalBakeState = 0; - globalBakeFrame = 0; - -#if defined(__APPLE__) && (PARALLEL == 1) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2) - // Workaround for Apple gcc 4.2.1 omp vs background thread bug - thread_tls_data = pthread_getspecific(gomp_tls_key); -#endif - BLI_init_threads(&threads, fluidsimSimulateThread, 1); - BLI_insert_thread(&threads, targetFile); - - { - int done = 0; - float noFramesf = (float)noFrames; - float percentdone = 0.0, oldpercentdone = -1.0; - int lastRedraw = -1; - - g_break= 0; - G.afbreek= 0; /* blender_test_break uses this global */ - - start_progress_bar(); + // 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 - while(done==0) { - char busy_mess[80]; - - waitcursor(1); - - // lukep we add progress bar as an interim mesure - percentdone = globalBakeFrame / noFramesf; - if (percentdone != oldpercentdone) { - sprintf(busy_mess, "baking fluids %d / %d |||", globalBakeFrame, (int) noFramesf); - percentdone = percentdone < 0.0 ? 0.0:percentdone; - progress_bar(CTX_wm_window(C), percentdone, busy_mess ); - oldpercentdone = percentdone; - } - - //XXX no more need for longer delay to prevent frequent redrawing - PIL_sleep_ms(200); - - BLI_lock_thread(LOCK_CUSTOM1); - if(globalBakeState != 0) done = 1; // 1=ok, <0=error/abort - BLI_unlock_thread(LOCK_CUSTOM1); - - if (!G.background) { - g_break= blender_test_break(); - - if(g_break) - { - // abort... - BLI_lock_thread(LOCK_CUSTOM1); - - if(domainSettings) - domainSettings->lastgoodframe = startFrame+globalBakeFrame; - - done = -1; - globalBakeFrame = 0; - globalBakeState = -1; - simAborted = 1; - BLI_unlock_thread(LOCK_CUSTOM1); - break; - } - } - - // redraw the 3D for showing progress once in a while... - if(lastRedraw!=globalBakeFrame) { -#if 0 - ScrArea *sa; - scene->r.cfra = startFrame+globalBakeFrame; - lastRedraw = globalBakeFrame; - ED_update_for_newframe(C, 1); - sa= G.curscreen->areabase.first; - while(sa) { - if(sa->spacetype == SPACE_VIEW3D) { scrarea_do_windraw(sa); } - sa= sa->next; - } - screen_swapbuffers(); -#endif - } // redraw - } - end_progress_bar(CTX_wm_window(C)); + strcpy(targetFile, targetDir); + strcat(targetFile, 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; + strcpy( fsset->outputPath, targetFile); + + // 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; + 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]; } - BLI_end_threads(&threads); - } // El'Beem API init, thread creation - // -------------------------------------------------------------------------------------------- - else - { // write config file to be run with command line simulator - BKE_report(reports, RPT_WARNING, "Config file export not supported."); - } // config file export done! + } } - // -------------------------------------------------------------------------------------------- - FS_FREE_CHANNELS; - - // go back to "current" blender time - waitcursor(0); + /* ******** init solver with settings ******** */ + elbeemInit(); + elbeemAddDomain(fsset); - if(globalBakeState >= 0) - { - if(domainSettings) - domainSettings->lastgoodframe = startFrame+globalBakeFrame; - } + /* ******** export all fluid objects to elbeem ******** */ + export_fluid_objects(fobjects, scene, channels->length); - scene->r.cfra = origFrame; - ED_update_for_newframe(C, 1); + /* custom data for fluid bake job */ + fb->settings = fsset; + + /* setup job */ + WM_jobs_customdata(steve, fb, fluidbake_free); + WM_jobs_timer(steve, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME); + WM_jobs_callbacks(steve, fluidbake_startjob, NULL, NULL, fluidbake_endjob); + + WM_jobs_start(CTX_wm_manager(C), steve); - if(!simAborted) { - char elbeemerr[256]; + /* ******** free stored animation data ******** */ + fluidbake_free_data(channels, fobjects, NULL, NULL); - // check if some error occurred - if(globalBakeState==-2) { - elbeemGetErrorString(elbeemerr); - BKE_reportf(reports, RPT_ERROR, "Failed to initialize [Msg: %s]", elbeemerr); - return 0; - } // init error - } - // elbeemFree(); return 1; } @@ -1206,7 +1090,6 @@ static int fluid_bake_exec(bContext *C, wmOperator *op) { Object *ob= CTX_data_active_object(C); - // XXX TODO redraw, escape, non-blocking, .. if(!fluidsimBake(C, op->reports, ob)) return OPERATOR_CANCELLED; diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h index aa3a2e22e31..b3d11810c43 100644 --- a/source/blender/editors/physics/physics_intern.h +++ b/source/blender/editors/physics/physics_intern.h @@ -37,8 +37,8 @@ struct wmOperatorType; /* particle_edit.c */ void PARTICLE_OT_select_all(struct wmOperatorType *ot); -void PARTICLE_OT_select_first(struct wmOperatorType *ot); -void PARTICLE_OT_select_last(struct wmOperatorType *ot); +void PARTICLE_OT_select_roots(struct wmOperatorType *ot); +void PARTICLE_OT_select_tips(struct wmOperatorType *ot); void PARTICLE_OT_select_linked(struct wmOperatorType *ot); void PARTICLE_OT_select_less(struct wmOperatorType *ot); void PARTICLE_OT_select_more(struct wmOperatorType *ot); diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c index 55568c89e75..28839693e2c 100644 --- a/source/blender/editors/physics/physics_ops.c +++ b/source/blender/editors/physics/physics_ops.c @@ -1,5 +1,5 @@ /** - * $Id: + * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -27,7 +27,6 @@ #include <stdlib.h> -#include "DNA_windowmanager_types.h" #include "RNA_access.h" @@ -44,8 +43,8 @@ static void operatortypes_particle(void) { WM_operatortype_append(PARTICLE_OT_select_all); - WM_operatortype_append(PARTICLE_OT_select_first); - WM_operatortype_append(PARTICLE_OT_select_last); + WM_operatortype_append(PARTICLE_OT_select_roots); + WM_operatortype_append(PARTICLE_OT_select_tips); WM_operatortype_append(PARTICLE_OT_select_linked); WM_operatortype_append(PARTICLE_OT_select_less); WM_operatortype_append(PARTICLE_OT_select_more); @@ -101,6 +100,7 @@ static void keymap_particle(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "PARTICLE_OT_delete", XKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "PARTICLE_OT_delete", DELKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "PARTICLE_OT_delete", BACKSPACEKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "PARTICLE_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "PARTICLE_OT_hide", HKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c index 1359af5377f..8e53e3c6f50 100644 --- a/source/blender/editors/physics/physics_pointcache.c +++ b/source/blender/editors/physics/physics_pointcache.c @@ -32,9 +32,8 @@ #include "MEM_guardedalloc.h" #include "DNA_scene_types.h" -#include "DNA_object_force.h" -#include "DNA_modifier_types.h" +#include "BKE_anim.h" #include "BKE_context.h" #include "BKE_particle.h" #include "BKE_report.h" @@ -46,12 +45,8 @@ #include "BLI_blenlib.h" -#include "ED_screen.h" -#include "ED_physics.h" #include "ED_particle.h" -#include "UI_interface.h" -#include "UI_resources.h" #include "WM_api.h" #include "WM_types.h" @@ -76,7 +71,7 @@ static int ptcache_bake_all_poll(bContext *C) static int ptcache_poll(bContext *C) { - PointerRNA ptr= CTX_data_pointer_get_type(C, "PointCache", &RNA_PointCache); + PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache); return (ptr.data && ptr.id.data); } @@ -94,7 +89,7 @@ void bake_console_progress_end(void *arg) static int ptcache_bake_all_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); - wmWindow *win = CTX_wm_window(C); + wmWindow *win = G.background ? NULL : CTX_wm_window(C); PTCacheBaker baker; @@ -120,6 +115,7 @@ static int ptcache_bake_all_exec(bContext *C, wmOperator *op) BKE_ptcache_make_cache(&baker); WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene); + WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, NULL); return OPERATOR_FINISHED; } @@ -131,13 +127,15 @@ static int ptcache_free_bake_all_exec(bContext *C, wmOperator *op) ListBase pidlist; for(base=scene->base.first; base; base= base->next) { - BKE_ptcache_ids_from_object(&pidlist, base->object); + BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR); for(pid=pidlist.first; pid; pid=pid->next) { pid->cache->flag &= ~PTCACHE_BAKED; } BLI_freelistN(&pidlist); + + WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, base->object); } WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene); @@ -176,15 +174,15 @@ void PTCACHE_OT_free_bake_all(wmOperatorType *ot) static int ptcache_bake_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - wmWindow *win = CTX_wm_window(C); - PointerRNA ptr= CTX_data_pointer_get_type(C, "PointCache", &RNA_PointCache); + wmWindow *win = G.background ? NULL : CTX_wm_window(C); + PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache); Object *ob= ptr.id.data; PointCache *cache= ptr.data; PTCacheBaker baker; PTCacheID *pid; ListBase pidlist; - BKE_ptcache_ids_from_object(&pidlist, ob); + BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR); for(pid=pidlist.first; pid; pid=pid->next) { if(pid->cache == cache) @@ -216,13 +214,15 @@ static int ptcache_bake_exec(bContext *C, wmOperator *op) BLI_freelistN(&pidlist); WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene); + WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob); return OPERATOR_FINISHED; } static int ptcache_free_bake_exec(bContext *C, wmOperator *op) { - PointerRNA ptr= CTX_data_pointer_get_type(C, "PointCache", &RNA_PointCache); + PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache); PointCache *cache= ptr.data; + Object *ob= ptr.id.data; if(cache->edit) { if(!cache->edit->edited || 1) {// XXX okee("Lose changes done in particle mode?")) { @@ -233,15 +233,20 @@ static int ptcache_free_bake_exec(bContext *C, wmOperator *op) } else cache->flag &= ~PTCACHE_BAKED; + + WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob); return OPERATOR_FINISHED; } static int ptcache_bake_from_cache_exec(bContext *C, wmOperator *op) { - PointerRNA ptr= CTX_data_pointer_get_type(C, "PointCache", &RNA_PointCache); + PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache); PointCache *cache= ptr.data; + Object *ob= ptr.id.data; cache->flag |= PTCACHE_BAKED; + + WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob); return OPERATOR_FINISHED; } @@ -290,13 +295,13 @@ void PTCACHE_OT_bake_from_cache(wmOperatorType *ot) static int ptcache_add_new_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - PointerRNA ptr= CTX_data_pointer_get_type(C, "PointCache", &RNA_PointCache); + PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache); Object *ob= ptr.id.data; PointCache *cache= ptr.data; PTCacheID *pid; ListBase pidlist; - BKE_ptcache_ids_from_object(&pidlist, ob); + BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR); for(pid=pidlist.first; pid; pid=pid->next) { if(pid->cache == cache) { @@ -308,18 +313,20 @@ static int ptcache_add_new_exec(bContext *C, wmOperator *op) BLI_freelistN(&pidlist); WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene); + WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob); return OPERATOR_FINISHED; } static int ptcache_remove_exec(bContext *C, wmOperator *op) { - PointerRNA ptr= CTX_data_pointer_get_type(C, "PointCache", &RNA_PointCache); + PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache); + Scene *scene= CTX_data_scene(C); Object *ob= ptr.id.data; PointCache *cache= ptr.data; PTCacheID *pid; ListBase pidlist; - BKE_ptcache_ids_from_object(&pidlist, ob); + BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR); for(pid=pidlist.first; pid; pid=pid->next) { if(pid->cache == cache) { @@ -335,6 +342,8 @@ static int ptcache_remove_exec(bContext *C, wmOperator *op) } BLI_freelistN(&pidlist); + + WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob); return OPERATOR_FINISHED; } |