diff options
Diffstat (limited to 'source/blender/editors')
-rw-r--r-- | source/blender/editors/armature/editarmature_undo.c | 19 | ||||
-rw-r--r-- | source/blender/editors/curve/editcurve_undo.c | 12 | ||||
-rw-r--r-- | source/blender/editors/curve/editfont_undo.c | 17 | ||||
-rw-r--r-- | source/blender/editors/include/ED_mball.h | 1 | ||||
-rw-r--r-- | source/blender/editors/include/ED_util.h | 2 | ||||
-rw-r--r-- | source/blender/editors/lattice/editlattice_undo.c | 19 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_undo.c | 20 | ||||
-rw-r--r-- | source/blender/editors/metaball/editmball_undo.c | 19 | ||||
-rw-r--r-- | source/blender/editors/object/object_edit.c | 14 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_undo.c | 27 | ||||
-rw-r--r-- | source/blender/editors/undo/ed_undo.c | 2 | ||||
-rw-r--r-- | source/blender/editors/undo/memfile_undo.c | 5 | ||||
-rw-r--r-- | source/blender/editors/util/ed_util.c | 27 |
13 files changed, 124 insertions, 60 deletions
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c index 4a82a8fccee..4e3ab11a9f7 100644 --- a/source/blender/editors/armature/editarmature_undo.c +++ b/source/blender/editors/armature/editarmature_undo.c @@ -32,6 +32,7 @@ #include "BKE_context.h" #include "BKE_layer.h" +#include "BKE_main.h" #include "BKE_undo_system.h" #include "DEG_depsgraph.h" @@ -142,9 +143,7 @@ static bool armature_undosys_poll(bContext *C) return editarm_object_from_context(C) != NULL; } -static bool armature_undosys_step_encode(struct bContext *C, - struct Main *UNUSED(bmain), - UndoStep *us_p) +static bool armature_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p) { ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; @@ -165,17 +164,18 @@ static bool armature_undosys_step_encode(struct bContext *C, elem->obedit_ref.ptr = ob; bArmature *arm = elem->obedit_ref.ptr->data; undoarm_from_editarm(&elem->data, arm); + arm->needs_flush_to_id = 1; us->step.data_size += elem->data.undo_size; } MEM_freeN(objects); + + bmain->is_memfile_undo_flush_needed = true; + return true; } -static void armature_undosys_step_decode(struct bContext *C, - struct Main *UNUSED(bmain), - UndoStep *us_p, - int UNUSED(dir), - bool UNUSED(is_final)) +static void armature_undosys_step_decode( + struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final)) { ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; @@ -198,6 +198,7 @@ static void armature_undosys_step_decode(struct bContext *C, continue; } undoarm_to_editarm(&elem->data, arm); + arm->needs_flush_to_id = 1; DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); } @@ -205,6 +206,8 @@ static void armature_undosys_step_decode(struct bContext *C, ED_undo_object_set_active_or_warn( CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG); + bmain->is_memfile_undo_flush_needed = true; + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c index f21b4f06246..ff3a1386fd9 100644 --- a/source/blender/editors/curve/editcurve_undo.c +++ b/source/blender/editors/curve/editcurve_undo.c @@ -208,9 +208,7 @@ static bool curve_undosys_poll(bContext *C) return (obedit != NULL); } -static bool curve_undosys_step_encode(struct bContext *C, - struct Main *UNUSED(bmain), - UndoStep *us_p) +static bool curve_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p) { CurveUndoStep *us = (CurveUndoStep *)us_p; @@ -226,13 +224,18 @@ static bool curve_undosys_step_encode(struct bContext *C, for (uint i = 0; i < objects_len; i++) { Object *ob = objects[i]; + Curve *cu = ob->data; CurveUndoStep_Elem *elem = &us->elems[i]; elem->obedit_ref.ptr = ob; undocurve_from_editcurve(&elem->data, ob->data, ob->shapenr); + cu->editnurb->needs_flush_to_id = 1; us->step.data_size += elem->data.undo_size; } MEM_freeN(objects); + + bmain->is_memfile_undo_flush_needed = true; + return true; } @@ -260,6 +263,7 @@ static void curve_undosys_step_decode( continue; } undocurve_to_editcurve(bmain, &elem->data, obedit->data, &obedit->shapenr); + cu->editnurb->needs_flush_to_id = 1; DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); } @@ -267,6 +271,8 @@ static void curve_undosys_step_decode( ED_undo_object_set_active_or_warn( CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG); + bmain->is_memfile_undo_flush_needed = true; + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c index ae858ec4c24..26c0e5cf6c9 100644 --- a/source/blender/editors/curve/editfont_undo.c +++ b/source/blender/editors/curve/editfont_undo.c @@ -32,6 +32,7 @@ #include "BKE_context.h" #include "BKE_font.h" +#include "BKE_main.h" #include "BKE_undo_system.h" #include "DEG_depsgraph.h" @@ -341,23 +342,21 @@ static bool font_undosys_poll(bContext *C) return editfont_object_from_context(C) != NULL; } -static bool font_undosys_step_encode(struct bContext *C, - struct Main *UNUSED(bmain), - UndoStep *us_p) +static bool font_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p) { FontUndoStep *us = (FontUndoStep *)us_p; us->obedit_ref.ptr = editfont_object_from_context(C); Curve *cu = us->obedit_ref.ptr->data; undofont_from_editfont(&us->data, cu); us->step.data_size = us->data.undo_size; + cu->editfont->needs_flush_to_id = 1; + bmain->is_memfile_undo_flush_needed = true; + return true; } -static void font_undosys_step_decode(struct bContext *C, - struct Main *UNUSED(bmain), - UndoStep *us_p, - int UNUSED(dir), - bool UNUSED(is_final)) +static void font_undosys_step_decode( + struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final)) { /* TODO(campbell): undo_system: use low-level API to set mode. */ ED_object_mode_set(C, OB_MODE_EDIT); @@ -368,6 +367,8 @@ static void font_undosys_step_decode(struct bContext *C, Curve *cu = obedit->data; undofont_to_editfont(&us->data, cu); DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); + cu->editfont->needs_flush_to_id = 1; + bmain->is_memfile_undo_flush_needed = true; WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h index 8ffae0f2b66..5afb645d9e7 100644 --- a/source/blender/editors/include/ED_mball.h +++ b/source/blender/editors/include/ED_mball.h @@ -25,6 +25,7 @@ #define __ED_MBALL_H__ struct Base; +struct MetaBall; struct Object; struct UndoType; struct bContext; diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index 87f57b4e144..003e84bbf05 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -34,6 +34,8 @@ struct wmOperatorType; void ED_editors_init_for_undo(struct Main *bmain); void ED_editors_init(struct bContext *C); void ED_editors_exit(struct Main *bmain, bool do_undo_system); + +bool ED_editors_flush_edits_ex(struct Main *bmain, bool for_render, bool check_needs_flush); bool ED_editors_flush_edits(struct Main *bmain, bool for_render); void ED_spacedata_id_remap(struct ScrArea *sa, diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c index abc5224c4d6..2790e6b5558 100644 --- a/source/blender/editors/lattice/editlattice_undo.c +++ b/source/blender/editors/lattice/editlattice_undo.c @@ -39,6 +39,7 @@ #include "BKE_context.h" #include "BKE_layer.h" +#include "BKE_main.h" #include "BKE_undo_system.h" #include "DEG_depsgraph.h" @@ -154,9 +155,7 @@ static bool lattice_undosys_poll(bContext *C) return editlatt_object_from_context(C) != NULL; } -static bool lattice_undosys_step_encode(struct bContext *C, - struct Main *UNUSED(bmain), - UndoStep *us_p) +static bool lattice_undosys_step_encode(struct bContext *C, Main *bmain, UndoStep *us_p) { LatticeUndoStep *us = (LatticeUndoStep *)us_p; @@ -177,17 +176,18 @@ static bool lattice_undosys_step_encode(struct bContext *C, elem->obedit_ref.ptr = ob; Lattice *lt = ob->data; undolatt_from_editlatt(&elem->data, lt->editlatt); + lt->editlatt->needs_flush_to_id = 1; us->step.data_size += elem->data.undo_size; } MEM_freeN(objects); + + bmain->is_memfile_undo_flush_needed = true; + return true; } -static void lattice_undosys_step_decode(struct bContext *C, - struct Main *UNUSED(bmain), - UndoStep *us_p, - int UNUSED(dir), - bool UNUSED(is_final)) +static void lattice_undosys_step_decode( + struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final)) { LatticeUndoStep *us = (LatticeUndoStep *)us_p; @@ -210,6 +210,7 @@ static void lattice_undosys_step_decode(struct bContext *C, continue; } undolatt_to_editlatt(&elem->data, lt->editlatt); + lt->editlatt->needs_flush_to_id = 1; DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); } @@ -217,6 +218,8 @@ static void lattice_undosys_step_decode(struct bContext *C, ED_undo_object_set_active_or_warn( CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG); + bmain->is_memfile_undo_flush_needed = true; + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 7071258d8cf..44984251243 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -34,6 +34,7 @@ #include "BKE_context.h" #include "BKE_key.h" #include "BKE_layer.h" +#include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_editmesh.h" #include "BKE_undo_system.h" @@ -708,9 +709,7 @@ static bool mesh_undosys_poll(bContext *C) return editmesh_object_from_context(C) != NULL; } -static bool mesh_undosys_step_encode(struct bContext *C, - struct Main *UNUSED(bmain), - UndoStep *us_p) +static bool mesh_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p) { MeshUndoStep *us = (MeshUndoStep *)us_p; @@ -730,18 +729,20 @@ static bool mesh_undosys_step_encode(struct bContext *C, elem->obedit_ref.ptr = ob; Mesh *me = elem->obedit_ref.ptr->data; + BMEditMesh *em = me->edit_mesh; undomesh_from_editmesh(&elem->data, me->edit_mesh, me->key); + em->needs_flush_to_id = 1; us->step.data_size += elem->data.undo_size; } MEM_freeN(objects); + + bmain->is_memfile_undo_flush_needed = true; + return true; } -static void mesh_undosys_step_decode(struct bContext *C, - struct Main *UNUSED(bmain), - UndoStep *us_p, - int UNUSED(dir), - bool UNUSED(is_final)) +static void mesh_undosys_step_decode( + struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final)) { MeshUndoStep *us = (MeshUndoStep *)us_p; @@ -765,6 +766,7 @@ static void mesh_undosys_step_decode(struct bContext *C, } BMEditMesh *em = me->edit_mesh; undomesh_to_editmesh(&elem->data, em, obedit->data); + em->needs_flush_to_id = 1; DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); } @@ -775,6 +777,8 @@ static void mesh_undosys_step_decode(struct bContext *C, Scene *scene = CTX_data_scene(C); scene->toolsettings->selectmode = us->elems[0].data.selectmode; + bmain->is_memfile_undo_flush_needed = true; + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c index 9a95560ccdd..e8700e94e91 100644 --- a/source/blender/editors/metaball/editmball_undo.c +++ b/source/blender/editors/metaball/editmball_undo.c @@ -35,6 +35,7 @@ #include "BKE_context.h" #include "BKE_layer.h" +#include "BKE_main.h" #include "BKE_undo_system.h" #include "DEG_depsgraph.h" @@ -153,9 +154,7 @@ static bool mball_undosys_poll(bContext *C) return editmball_object_from_context(C) != NULL; } -static bool mball_undosys_step_encode(struct bContext *C, - struct Main *UNUSED(bmain), - UndoStep *us_p) +static bool mball_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p) { MBallUndoStep *us = (MBallUndoStep *)us_p; @@ -176,17 +175,18 @@ static bool mball_undosys_step_encode(struct bContext *C, elem->obedit_ref.ptr = ob; MetaBall *mb = ob->data; editmball_from_undomball(&elem->data, mb); + mb->needs_flush_to_id = 1; us->step.data_size += elem->data.undo_size; } MEM_freeN(objects); + + bmain->is_memfile_undo_flush_needed = true; + return true; } -static void mball_undosys_step_decode(struct bContext *C, - struct Main *UNUSED(bmain), - UndoStep *us_p, - int UNUSED(dir), - bool UNUSED(is_final)) +static void mball_undosys_step_decode( + struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final)) { MBallUndoStep *us = (MBallUndoStep *)us_p; @@ -209,6 +209,7 @@ static void mball_undosys_step_decode(struct bContext *C, continue; } undomball_to_editmball(&elem->data, mb); + mb->needs_flush_to_id = 1; DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY); } @@ -216,6 +217,8 @@ static void mball_undosys_step_decode(struct bContext *C, ED_undo_object_set_active_or_warn( CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG); + bmain->is_memfile_undo_flush_needed = true; + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 70d024c7902..be815fb0d10 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -514,6 +514,11 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f } } + char *needs_flush_ptr = BKE_object_data_editmode_flush_ptr_get(obedit->data); + if (needs_flush_ptr) { + *needs_flush_ptr = false; + } + return true; } @@ -616,10 +621,13 @@ bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MESH, NULL); } else if (ob->type == OB_ARMATURE) { + bArmature *arm = ob->data; ok = 1; - ED_armature_to_edit(ob->data); + ED_armature_to_edit(arm); /* to ensure all goes in restposition and without striding */ + arm->needs_flush_to_id = 0; + /* XXX: should this be ID_RECALC_GEOMETRY? */ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); @@ -632,9 +640,13 @@ bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_TEXT, scene); } else if (ob->type == OB_MBALL) { + MetaBall *mb = ob->data; + ok = 1; ED_mball_editmball_make(ob); + mb->needs_flush_to_id = 0; + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MBALL, scene); } else if (ob->type == OB_LATTICE) { diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index fc990c01bfb..052f2bd03a4 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -1027,6 +1027,8 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType /* list is manipulated by multiple threads, so we lock */ BLI_thread_lock(LOCK_CUSTOM1); + ss->needs_flush_to_id = 1; + if (ss->bm || ELEM(type, SCULPT_UNDO_DYNTOPO_BEGIN, SCULPT_UNDO_DYNTOPO_END)) { /* Dynamic topology stores only one undo node per stroke, * regardless of the number of PBVH nodes modified */ @@ -1142,17 +1144,6 @@ typedef struct SculptUndoStep { UndoSculpt data; } SculptUndoStep; -static bool sculpt_undosys_poll(bContext *C) -{ - Object *obact = CTX_data_active_object(C); - if (obact && obact->type == OB_MESH) { - if (obact && (obact->mode & OB_MODE_SCULPT)) { - return true; - } - } - return false; -} - static void sculpt_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p) { SculptUndoStep *us = (SculptUndoStep *)us_p; @@ -1161,7 +1152,7 @@ static void sculpt_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep } static bool sculpt_undosys_step_encode(struct bContext *UNUSED(C), - struct Main *UNUSED(bmain), + struct Main *bmain, UndoStep *us_p) { /* dummy, encoding is done along the way by adding tiles @@ -1174,6 +1165,11 @@ static bool sculpt_undosys_step_encode(struct bContext *UNUSED(C), us->step.use_memfile_step = true; } us->step.is_applied = true; + + if (!BLI_listbase_is_empty(&us->data.nodes)) { + bmain->is_memfile_undo_flush_needed = true; + } + return true; } @@ -1256,7 +1252,11 @@ static void sculpt_undosys_step_decode( me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, true, NULL); } - BLI_assert(sculpt_undosys_poll(C)); + + if (ob->sculpt) { + ob->sculpt->needs_flush_to_id = 1; + } + bmain->is_memfile_undo_flush_needed = true; } else { BLI_assert(0); @@ -1295,7 +1295,6 @@ void ED_sculpt_undo_geometry_end(struct Object *ob) void ED_sculpt_undosys_type(UndoType *ut) { ut->name = "Sculpt"; - ut->poll = sculpt_undosys_poll; ut->step_encode_init = sculpt_undosys_step_encode_init; ut->step_encode = sculpt_undosys_step_encode; ut->step_decode = sculpt_undosys_step_decode; diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c index 315a4c73e5f..9770b52158a 100644 --- a/source/blender/editors/undo/ed_undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -322,7 +322,7 @@ bool ED_undo_is_memfile_compatible(const bContext *C) if (view_layer != NULL) { Object *obact = OBACT(view_layer); if (obact != NULL) { - if (obact->mode & (OB_MODE_SCULPT | OB_MODE_EDIT)) { + if (obact->mode & OB_MODE_EDIT) { return false; } } diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c index f3e2ee92558..a5f30409aa6 100644 --- a/source/blender/editors/undo/memfile_undo.c +++ b/source/blender/editors/undo/memfile_undo.c @@ -28,6 +28,7 @@ #include "BKE_blender_undo.h" #include "BKE_context.h" #include "BKE_undo_system.h" +#include "BKE_main.h" #include "WM_api.h" #include "WM_types.h" @@ -74,6 +75,10 @@ static bool memfile_undosys_step_encode(struct bContext *UNUSED(C), /* Important we only use 'main' from the context (see: BKE_undosys_stack_init_from_main). */ UndoStack *ustack = ED_undo_stack_get(); + if (bmain->is_memfile_undo_flush_needed) { + ED_editors_flush_edits_ex(bmain, false, true); + } + /* can be NULL, use when set. */ MemFileUndoStep *us_prev = (MemFileUndoStep *)BKE_undosys_step_find_by_type( ustack, BKE_UNDOSYS_TYPE_MEMFILE); diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index f5548119e0a..1a33b50ff10 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -230,7 +230,7 @@ void ED_editors_exit(Main *bmain, bool do_undo_system) /* flush any temp data from object editing to DNA before writing files, * rendering, copying, etc. */ -bool ED_editors_flush_edits(Main *bmain, bool for_render) +bool ED_editors_flush_edits_ex(Main *bmain, bool for_render, bool check_needs_flush) { bool has_edited = false; Object *ob; @@ -244,6 +244,15 @@ bool ED_editors_flush_edits(Main *bmain, bool for_render) * Auto-save prevents this from happening but scripts * may cause a flush on saving: T53986. */ if ((ob->sculpt && ob->sculpt->cache) == 0) { + + { + char *needs_flush_ptr = &ob->sculpt->needs_flush_to_id; + if (check_needs_flush && (*needs_flush_ptr == 0)) { + continue; + } + *needs_flush_ptr = 0; + } + /* flush multires changes (for sculpt) */ multires_flush_sculpt_updates(ob); has_edited = true; @@ -260,15 +269,31 @@ bool ED_editors_flush_edits(Main *bmain, bool for_render) } } else if (ob->mode & OB_MODE_EDIT) { + + char *needs_flush_ptr = BKE_object_data_editmode_flush_ptr_get(ob->data); + if (needs_flush_ptr != NULL) { + if (check_needs_flush && (*needs_flush_ptr == 0)) { + continue; + } + *needs_flush_ptr = 0; + } + /* get editmode results */ has_edited = true; ED_object_editmode_load(bmain, ob); } } + bmain->is_memfile_undo_flush_needed = false; + return has_edited; } +bool ED_editors_flush_edits(Main *bmain, bool for_render) +{ + return ED_editors_flush_edits_ex(bmain, for_render, false); +} + /* ***** XXX: functions are using old blender names, cleanup later ***** */ /* now only used in 2d spaces, like time, ipo, nla, sima... */ |