Keyed physics refresh:
[blender-staging.git] / source / blender / editors / space_buttons / buttons_ops.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_curve_types.h"
34 #include "DNA_object_types.h"
35 #include "DNA_material_types.h"
36 #include "DNA_texture_types.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_world_types.h"
39
40 #include "BKE_context.h"
41 #include "BKE_depsgraph.h"
42 #include "BKE_font.h"
43 #include "BKE_library.h"
44 #include "BKE_main.h"
45 #include "BKE_material.h"
46 #include "BKE_particle.h"
47 #include "BKE_texture.h"
48 #include "BKE_utildefines.h"
49 #include "BKE_world.h"
50
51 #include "BLI_editVert.h"
52 #include "BLI_listbase.h"
53
54 #include "RNA_access.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58
59 #include "ED_curve.h"
60 #include "ED_mesh.h"
61
62 #include "buttons_intern.h"     // own include
63
64 /********************** material slot operators *********************/
65
66 static int material_slot_add_exec(bContext *C, wmOperator *op)
67 {
68         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
69
70         if(!ob)
71                 return OPERATOR_CANCELLED;
72
73         object_add_material_slot(ob);
74         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
75         
76         return OPERATOR_FINISHED;
77 }
78
79 void OBJECT_OT_material_slot_add(wmOperatorType *ot)
80 {
81         /* identifiers */
82         ot->name= "Add Material Slot";
83         ot->idname= "OBJECT_OT_material_slot_add";
84         
85         /* api callbacks */
86         ot->exec= material_slot_add_exec;
87
88         /* flags */
89         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
90 }
91
92 static int material_slot_remove_exec(bContext *C, wmOperator *op)
93 {
94         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
95
96         if(!ob)
97                 return OPERATOR_CANCELLED;
98
99         object_remove_material_slot(ob);
100         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
101         
102         return OPERATOR_FINISHED;
103 }
104
105 void OBJECT_OT_material_slot_remove(wmOperatorType *ot)
106 {
107         /* identifiers */
108         ot->name= "Remove Material Slot";
109         ot->idname= "OBJECT_OT_material_slot_remove";
110         
111         /* api callbacks */
112         ot->exec= material_slot_remove_exec;
113
114         /* flags */
115         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
116 }
117
118 static int material_slot_assign_exec(bContext *C, wmOperator *op)
119 {
120         Scene *scene= CTX_data_scene(C);
121         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
122
123         if(!ob)
124                 return OPERATOR_CANCELLED;
125
126         if(ob && ob->actcol>0) {
127                 if(ob->type == OB_MESH) {
128                         EditMesh *em= ((Mesh*)ob->data)->edit_mesh;
129                         EditFace *efa;
130
131                         if(em) {
132                                 for(efa= em->faces.first; efa; efa=efa->next)
133                                         if(efa->f & SELECT)
134                                                 efa->mat_nr= ob->actcol-1;
135                         }
136                 }
137                 else if(ELEM(ob->type, OB_CURVE, OB_SURF)) {
138                         ListBase *editnurb= ((Curve*)ob->data)->editnurb;
139                         Nurb *nu;
140
141                         if(editnurb) {
142                                 for(nu= editnurb->first; nu; nu= nu->next)
143                                         if(isNurbsel(nu))
144                                                 nu->mat_nr= nu->charidx= ob->actcol-1;
145                         }
146                 }
147                 else if(ob->type == OB_FONT) {
148                         EditFont *ef= ((Curve*)ob->data)->editfont;
149                 int i, selstart, selend;
150
151                         if(ef && BKE_font_getselection(ob, &selstart, &selend)) {
152                                 for(i=selstart; i<=selend; i++)
153                                         ef->textbufinfo[i].mat_nr = ob->actcol-1;
154                         }
155                 }
156         }
157
158     DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
159     WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
160         
161         return OPERATOR_FINISHED;
162 }
163
164 void OBJECT_OT_material_slot_assign(wmOperatorType *ot)
165 {
166         /* identifiers */
167         ot->name= "Assign Material Slot";
168         ot->idname= "OBJECT_OT_material_slot_assign";
169         
170         /* api callbacks */
171         ot->exec= material_slot_assign_exec;
172
173         /* flags */
174         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
175 }
176
177 static int material_slot_de_select(bContext *C, int select)
178 {
179         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
180
181         if(!ob)
182                 return OPERATOR_CANCELLED;
183
184         if(ob->type == OB_MESH) {
185                 EditMesh *em= ((Mesh*)ob->data)->edit_mesh;
186
187                 if(em) {
188                         if(select)
189                                 EM_select_by_material(em, ob->actcol-1);
190                         else
191                                 EM_deselect_by_material(em, ob->actcol-1);
192                 }
193         }
194         else if ELEM(ob->type, OB_CURVE, OB_SURF) {
195                 ListBase *editnurb= ((Curve*)ob->data)->editnurb;
196                 Nurb *nu;
197                 BPoint *bp;
198                 BezTriple *bezt;
199                 int a;
200
201                 for(nu= editnurb->first; nu; nu=nu->next) {
202                         if(nu->mat_nr==ob->actcol-1) {
203                                 if(nu->bezt) {
204                                         a= nu->pntsu;
205                                         bezt= nu->bezt;
206                                         while(a--) {
207                                                 if(bezt->hide==0) {
208                                                         if(select) {
209                                                                 bezt->f1 |= SELECT;
210                                                                 bezt->f2 |= SELECT;
211                                                                 bezt->f3 |= SELECT;
212                                                         }
213                                                         else {
214                                                                 bezt->f1 &= ~SELECT;
215                                                                 bezt->f2 &= ~SELECT;
216                                                                 bezt->f3 &= ~SELECT;
217                                                         }
218                                                 }
219                                                 bezt++;
220                                         }
221                                 }
222                                 else if(nu->bp) {
223                                         a= nu->pntsu*nu->pntsv;
224                                         bp= nu->bp;
225                                         while(a--) {
226                                                 if(bp->hide==0) {
227                                                         if(select) bp->f1 |= SELECT;
228                                                         else bp->f1 &= ~SELECT;
229                                                 }
230                                                 bp++;
231                                         }
232                                 }
233                         }
234                 }
235         }
236
237     WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
238
239         return OPERATOR_FINISHED;
240 }
241
242 static int material_slot_select_exec(bContext *C, wmOperator *op)
243 {
244         return material_slot_de_select(C, 1);
245 }
246
247 void OBJECT_OT_material_slot_select(wmOperatorType *ot)
248 {
249         /* identifiers */
250         ot->name= "Select Material Slot";
251         ot->idname= "OBJECT_OT_material_slot_select";
252         
253         /* api callbacks */
254         ot->exec= material_slot_select_exec;
255
256         /* flags */
257         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
258 }
259
260 static int material_slot_deselect_exec(bContext *C, wmOperator *op)
261 {
262         return material_slot_de_select(C, 0);
263 }
264
265 void OBJECT_OT_material_slot_deselect(wmOperatorType *ot)
266 {
267         /* identifiers */
268         ot->name= "Deselect Material Slot";
269         ot->idname= "OBJECT_OT_material_slot_deselect";
270         
271         /* api callbacks */
272         ot->exec= material_slot_deselect_exec;
273
274         /* flags */
275         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
276 }
277
278 /********************** new material operator *********************/
279
280 static int new_material_exec(bContext *C, wmOperator *op)
281 {
282         Material *ma= CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
283         Object *ob;
284         PointerRNA ptr;
285         int index;
286
287         /* add or copy material */
288         if(ma)
289                 ma= copy_material(ma);
290         else
291                 ma= add_material("Material");
292
293         ma->id.us--; /* compensating for us++ in assign_material */
294
295         /* attempt to assign to material slot */
296         ptr= CTX_data_pointer_get_type(C, "material_slot", &RNA_MaterialSlot);
297
298         if(ptr.data) {
299                 ob= ptr.id.data;
300                 index= (Material**)ptr.data - ob->mat;
301
302                 assign_material(ob, ma, index+1);
303
304                 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
305         }
306
307         WM_event_add_notifier(C, NC_MATERIAL|NA_ADDED, ma);
308         
309         return OPERATOR_FINISHED;
310 }
311
312 void MATERIAL_OT_new(wmOperatorType *ot)
313 {
314         /* identifiers */
315         ot->name= "New Material";
316         ot->idname= "MATERIAL_OT_new";
317         
318         /* api callbacks */
319         ot->exec= new_material_exec;
320
321         /* flags */
322         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
323 }
324
325 /********************** new texture operator *********************/
326
327 static int new_texture_exec(bContext *C, wmOperator *op)
328 {
329         Tex *tex= CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
330         ID *id;
331         MTex *mtex;
332         PointerRNA ptr;
333
334         /* add or copy texture */
335         if(tex)
336                 tex= copy_texture(tex);
337         else
338                 tex= add_texture("Texture");
339
340         id_us_min(&tex->id);
341
342         /* attempt to assign to texture slot */
343         ptr= CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot);
344
345         if(ptr.data) {
346                 id= ptr.id.data;
347                 mtex= ptr.data;
348
349                 if(mtex) {
350                         if(mtex->tex)
351                                 id_us_min(&mtex->tex->id);
352                         mtex->tex= tex;
353                         id_us_plus(&tex->id);
354                 }
355
356                 /* XXX nodes, notifier .. */
357         }
358
359         WM_event_add_notifier(C, NC_TEXTURE|NA_ADDED, tex);
360         
361         return OPERATOR_FINISHED;
362 }
363
364 void TEXTURE_OT_new(wmOperatorType *ot)
365 {
366         /* identifiers */
367         ot->name= "New Texture";
368         ot->idname= "TEXTURE_OT_new";
369         
370         /* api callbacks */
371         ot->exec= new_texture_exec;
372
373         /* flags */
374         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
375 }
376
377 /********************** new world operator *********************/
378
379 static int new_world_exec(bContext *C, wmOperator *op)
380 {
381         Scene *scene= CTX_data_scene(C);
382         World *wo= CTX_data_pointer_get_type(C, "world", &RNA_World).data;
383
384         /* add or copy world */
385         if(wo)
386                 wo= copy_world(wo);
387         else
388                 wo= add_world("World");
389
390         /* assign to scene */
391         if(scene->world)
392                 id_us_min(&scene->world->id);
393         scene->world= wo;
394
395         WM_event_add_notifier(C, NC_WORLD|NA_ADDED, wo);
396         
397         return OPERATOR_FINISHED;
398 }
399
400 void WORLD_OT_new(wmOperatorType *ot)
401 {
402         /* identifiers */
403         ot->name= "New World";
404         ot->idname= "WORLD_OT_new";
405         
406         /* api callbacks */
407         ot->exec= new_world_exec;
408
409         /* flags */
410         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
411 }
412
413
414
415 /********************** particle system slot operators *********************/
416
417 static int particle_system_add_exec(bContext *C, wmOperator *op)
418 {
419         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
420         Scene *scene = CTX_data_scene(C);
421
422         if(!scene || !ob)
423                 return OPERATOR_CANCELLED;
424
425         object_add_particle_system(scene, ob);
426         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
427         
428         return OPERATOR_FINISHED;
429 }
430
431 void OBJECT_OT_particle_system_add(wmOperatorType *ot)
432 {
433         /* identifiers */
434         ot->name= "Add Particle System Slot";
435         ot->idname= "OBJECT_OT_particle_system_add";
436         
437         /* api callbacks */
438         ot->exec= particle_system_add_exec;
439
440         /* flags */
441         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
442 }
443
444 static int particle_system_remove_exec(bContext *C, wmOperator *op)
445 {
446         Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
447         Scene *scene = CTX_data_scene(C);
448
449         if(!scene || !ob)
450                 return OPERATOR_CANCELLED;
451
452         object_remove_particle_system(scene, ob);
453         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
454         
455         return OPERATOR_FINISHED;
456 }
457
458 void OBJECT_OT_particle_system_remove(wmOperatorType *ot)
459 {
460         /* identifiers */
461         ot->name= "Remove Particle System Slot";
462         ot->idname= "OBJECT_OT_particle_system_remove";
463         
464         /* api callbacks */
465         ot->exec= particle_system_remove_exec;
466
467         /* flags */
468         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
469 }
470
471 /********************** new particle settings operator *********************/
472
473 static int new_particle_settings_exec(bContext *C, wmOperator *op)
474 {
475         Scene *scene = CTX_data_scene(C);
476         Main *bmain= CTX_data_main(C);
477         ParticleSystem *psys;
478         ParticleSettings *part = NULL;
479         Object *ob;
480         PointerRNA ptr;
481
482         ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
483
484         psys = ptr.data;
485
486         /* add or copy particle setting */
487         if(psys->part)
488                 part= psys_copy_settings(psys->part);
489         else
490                 part= psys_new_settings("PSys", bmain);
491
492         ob= ptr.id.data;
493
494         if(psys->part)
495                 psys->part->id.us--;
496
497         psys->part = part;
498
499         DAG_scene_sort(scene);
500         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
501
502         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
503         
504         return OPERATOR_FINISHED;
505 }
506
507 void PARTICLE_OT_new(wmOperatorType *ot)
508 {
509         /* identifiers */
510         ot->name= "New Particle Settings";
511         ot->idname= "PARTICLE_OT_new";
512         
513         /* api callbacks */
514         ot->exec= new_particle_settings_exec;
515
516         /* flags */
517         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
518 }
519
520 /********************** keyed particle target operators *********************/
521
522 static int new_keyed_particle_target_exec(bContext *C, wmOperator *op)
523 {
524         Scene *scene = CTX_data_scene(C);
525         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
526         ParticleSystem *psys= ptr.data;
527         Object *ob = ptr.id.data;
528
529         KeyedParticleTarget *kpt;
530
531         if(!psys)
532                 return OPERATOR_CANCELLED;
533
534         kpt = psys->keyed_targets.first;
535         for(; kpt; kpt=kpt->next)
536                 kpt->flag &= ~KEYED_TARGET_CURRENT;
537
538         kpt = MEM_callocN(sizeof(KeyedParticleTarget), "keyed particle target");
539
540         kpt->flag |= KEYED_TARGET_CURRENT;
541         kpt->psys = 1;
542
543         BLI_addtail(&psys->keyed_targets, kpt);
544
545         DAG_scene_sort(scene);
546         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
547
548         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
549         
550         return OPERATOR_FINISHED;
551 }
552
553 void PARTICLE_OT_new_keyed_target(wmOperatorType *ot)
554 {
555         /* identifiers */
556         ot->name= "New Keyed Particle Target";
557         ot->idname= "PARTICLE_OT_new_keyed_target";
558         
559         /* api callbacks */
560         ot->exec= new_keyed_particle_target_exec;
561
562         /* flags */
563         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
564 }
565
566 static int remove_keyed_particle_target_exec(bContext *C, wmOperator *op)
567 {
568         Scene *scene = CTX_data_scene(C);
569         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
570         ParticleSystem *psys= ptr.data;
571         Object *ob = ptr.id.data;
572
573         KeyedParticleTarget *kpt;
574
575         if(!psys)
576                 return OPERATOR_CANCELLED;
577
578         kpt = psys->keyed_targets.first;
579         for(; kpt; kpt=kpt->next) {
580                 if(kpt->flag & KEYED_TARGET_CURRENT) {
581                         BLI_remlink(&psys->keyed_targets, kpt);
582                         MEM_freeN(kpt);
583                         break;
584                 }
585
586         }
587         kpt = psys->keyed_targets.last;
588
589         if(kpt)
590                 kpt->flag |= KEYED_TARGET_CURRENT;
591
592         DAG_scene_sort(scene);
593         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
594
595         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
596         
597         return OPERATOR_FINISHED;
598 }
599
600 void PARTICLE_OT_remove_keyed_target(wmOperatorType *ot)
601 {
602         /* identifiers */
603         ot->name= "Remove Keyed Particle Target";
604         ot->idname= "PARTICLE_OT_remove_keyed_target";
605         
606         /* api callbacks */
607         ot->exec= remove_keyed_particle_target_exec;
608
609         /* flags */
610         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
611 }
612
613 /************************ move up modifier operator *********************/
614
615 static int keyed_target_move_up_exec(bContext *C, wmOperator *op)
616 {
617         Scene *scene= CTX_data_scene(C);
618         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
619         ParticleSystem *psys= ptr.data;
620         Object *ob = ptr.id.data;
621         KeyedParticleTarget *kpt;
622
623         if(!psys)
624                 return OPERATOR_CANCELLED;
625         
626         kpt = psys->keyed_targets.first;
627         for(; kpt; kpt=kpt->next) {
628                 if(kpt->flag & KEYED_TARGET_CURRENT && kpt->prev) {
629                         BLI_remlink(&psys->keyed_targets, kpt);
630                         BLI_insertlink(&psys->keyed_targets, kpt->prev->prev, kpt);
631
632                         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
633                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
634                         break;
635                 }
636         }
637         
638         return OPERATOR_FINISHED;
639 }
640
641 void PARTICLE_OT_keyed_target_move_up(wmOperatorType *ot)
642 {
643         ot->name= "Move Up Keyed Target";
644         ot->description= "Move keyed particle target up in the list.";
645         ot->idname= "PARTICLE_OT_keyed_target_move_up";
646
647         ot->exec= keyed_target_move_up_exec;
648         
649         /* flags */
650         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
651 }
652
653 /************************ move down modifier operator *********************/
654
655 static int keyed_target_move_down_exec(bContext *C, wmOperator *op)
656 {
657         Scene *scene= CTX_data_scene(C);
658         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
659         ParticleSystem *psys= ptr.data;
660         Object *ob = ptr.id.data;
661         KeyedParticleTarget *kpt;
662
663         if(!psys)
664                 return OPERATOR_CANCELLED;
665         kpt = psys->keyed_targets.first;
666         for(; kpt; kpt=kpt->next) {
667                 if(kpt->flag & KEYED_TARGET_CURRENT && kpt->next) {
668                         BLI_remlink(&psys->keyed_targets, kpt);
669                         BLI_insertlink(&psys->keyed_targets, kpt->next, kpt);
670
671                         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
672                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
673                         break;
674                 }
675         }
676         
677         return OPERATOR_FINISHED;
678 }
679
680 void PARTICLE_OT_keyed_target_move_down(wmOperatorType *ot)
681 {
682         ot->name= "Move Down Keyed Target";
683         ot->description= "Move keyed particle target down in the list.";
684         ot->idname= "PARTICLE_OT_keyed_target_move_down";
685
686         ot->exec= keyed_target_move_down_exec;
687         
688         /* flags */
689         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
690 }
691