Sorry, three commits in one, became difficult to untangle..
[blender-staging.git] / source / blender / editors / physics / particle_boids.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 Janne Karhu.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <stdlib.h>
29
30 #include "MEM_guardedalloc.h"
31
32 #include "DNA_boid_types.h"
33 #include "DNA_particle_types.h"
34 #include "DNA_object_types.h"
35 #include "DNA_scene_types.h"
36
37 #include "BKE_boids.h"
38 #include "BKE_context.h"
39 #include "BKE_depsgraph.h"
40 #include "BKE_particle.h"
41
42 #include "BLI_listbase.h"
43 #include "RNA_access.h"
44 #include "RNA_enum_types.h"
45 #include "RNA_define.h"
46
47 #include "WM_api.h"
48 #include "WM_types.h"
49
50 #include "physics_intern.h"
51
52 /************************ add/del boid rule operators *********************/
53 static int rule_add_exec(bContext *C, wmOperator *op)
54 {
55         Scene *scene = CTX_data_scene(C);
56         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
57         ParticleSystem *psys= ptr.data;
58         Object *ob= ptr.id.data;
59         ParticleSettings *part;
60         int type= RNA_enum_get(op->ptr, "type");
61
62         BoidRule *rule;
63         BoidState *state;
64
65         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
66                 return OPERATOR_CANCELLED;
67
68         part = psys->part;
69
70         state = boid_get_current_state(part->boids);
71
72
73         for(rule=state->rules.first; rule; rule=rule->next)
74                 rule->flag &= ~BOIDRULE_CURRENT;
75
76         rule = boid_new_rule(type);
77         rule->flag |= BOIDRULE_CURRENT;
78
79         BLI_addtail(&state->rules, rule);
80
81         psys_flush_particle_settings(scene, part, PSYS_RECALC_RESET);
82         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
83         
84         return OPERATOR_FINISHED;
85 }
86
87 void BOID_OT_rule_add(wmOperatorType *ot)
88 {
89         /* identifiers */
90         ot->name= "Add Boid Rule";
91         ot->description = "Add a boid rule to the current boid state.";
92         ot->idname= "BOID_OT_rule_add";
93         
94         /* api callbacks */
95         ot->invoke= WM_menu_invoke;
96         ot->exec= rule_add_exec;
97         
98         /* flags */
99         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
100         
101         RNA_def_enum(ot->srna, "type", boidrule_type_items, 0, "Type", "");
102 }
103 static int rule_del_exec(bContext *C, wmOperator *op)
104 {
105         Scene *scene = CTX_data_scene(C);
106         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
107         ParticleSystem *psys= ptr.data;
108         Object *ob = ptr.id.data;
109         BoidRule *rule;
110         BoidState *state;
111
112         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
113                 return OPERATOR_CANCELLED;
114
115         state = boid_get_current_state(psys->part->boids);
116
117         
118         for(rule=state->rules.first; rule; rule=rule->next) {
119                 if(rule->flag & BOIDRULE_CURRENT) {
120                         BLI_remlink(&state->rules, rule);
121                         MEM_freeN(rule);
122                         break;
123                 }
124
125         }
126         rule = state->rules.first;
127
128         if(rule)
129                 rule->flag |= BOIDRULE_CURRENT;
130
131         DAG_scene_sort(scene);
132         psys_flush_particle_settings(scene, psys->part, PSYS_RECALC_RESET);
133
134         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
135         
136         return OPERATOR_FINISHED;
137 }
138
139 void BOID_OT_rule_del(wmOperatorType *ot)
140 {
141         /* identifiers */
142         ot->name= "Remove Boid Rule";
143         ot->idname= "BOID_OT_rule_del";
144         
145         /* api callbacks */
146         ot->exec= rule_del_exec;
147
148         /* flags */
149         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
150 }
151
152 /************************ move up/down boid rule operators *********************/
153 static int rule_move_up_exec(bContext *C, wmOperator *op)
154 {
155         Scene *scene= CTX_data_scene(C);
156         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
157         ParticleSystem *psys= ptr.data;
158         Object *ob = ptr.id.data;
159         BoidRule *rule;
160         BoidState *state;
161
162         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
163                 return OPERATOR_CANCELLED;
164         
165         state = boid_get_current_state(psys->part->boids);
166         for(rule = state->rules.first; rule; rule=rule->next) {
167                 if(rule->flag & BOIDRULE_CURRENT && rule->prev) {
168                         BLI_remlink(&state->rules, rule);
169                         BLI_insertlink(&state->rules, rule->prev->prev, rule);
170
171                         psys_flush_particle_settings(scene, psys->part, PSYS_RECALC_RESET);
172                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
173                         break;
174                 }
175         }
176         
177         return OPERATOR_FINISHED;
178 }
179
180 void BOID_OT_rule_move_up(wmOperatorType *ot)
181 {
182         ot->name= "Move Up Boid Rule";
183         ot->description= "Move boid rule up in the list.";
184         ot->idname= "BOID_OT_rule_move_up";
185
186         ot->exec= rule_move_up_exec;
187         
188         /* flags */
189         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
190 }
191
192 static int rule_move_down_exec(bContext *C, wmOperator *op)
193 {
194         Scene *scene= CTX_data_scene(C);
195         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
196         ParticleSystem *psys= ptr.data;
197         Object *ob = ptr.id.data;
198         BoidRule *rule;
199         BoidState *state;
200
201         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
202                 return OPERATOR_CANCELLED;
203         
204         state = boid_get_current_state(psys->part->boids);
205         for(rule = state->rules.first; rule; rule=rule->next) {
206                 if(rule->flag & BOIDRULE_CURRENT && rule->next) {
207                         BLI_remlink(&state->rules, rule);
208                         BLI_insertlink(&state->rules, rule->next, rule);
209
210                         psys_flush_particle_settings(scene, psys->part, PSYS_RECALC_RESET);
211                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
212                         break;
213                 }
214         }
215         
216         return OPERATOR_FINISHED;
217 }
218
219 void BOID_OT_rule_move_down(wmOperatorType *ot)
220 {
221         ot->name= "Move Down Boid Rule";
222         ot->description= "Move boid rule down in the list.";
223         ot->idname= "BOID_OT_rule_move_down";
224
225         ot->exec= rule_move_down_exec;
226         
227         /* flags */
228         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
229 }
230
231
232 /************************ add/del boid state operators *********************/
233 static int state_add_exec(bContext *C, wmOperator *op)
234 {
235         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
236         ParticleSystem *psys= ptr.data;
237         Object *ob= ptr.id.data;
238         ParticleSettings *part;
239         BoidState *state;
240
241         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
242                 return OPERATOR_CANCELLED;
243
244         part = psys->part;
245
246         for(state=part->boids->states.first; state; state=state->next)
247                 state->flag &= ~BOIDSTATE_CURRENT;
248
249         state = boid_new_state(part->boids);
250         state->flag |= BOIDSTATE_CURRENT;
251
252         BLI_addtail(&part->boids->states, state);
253
254         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
255         
256         return OPERATOR_FINISHED;
257 }
258
259 void BOID_OT_state_add(wmOperatorType *ot)
260 {
261         /* identifiers */
262         ot->name= "Add Boid State";
263         ot->description = "Add a boid state to the particle system.";
264         ot->idname= "BOID_OT_state_add";
265         
266         /* api callbacks */
267         ot->exec= state_add_exec;
268         
269         /* flags */
270         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
271 }
272 static int state_del_exec(bContext *C, wmOperator *op)
273 {
274         Scene *scene = CTX_data_scene(C);
275         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
276         ParticleSystem *psys= ptr.data;
277         Object *ob = ptr.id.data;
278         ParticleSettings *part;
279         BoidState *state;
280
281         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
282                 return OPERATOR_CANCELLED;
283
284         part = psys->part;
285         
286         for(state=part->boids->states.first; state; state=state->next) {
287                 if(state->flag & BOIDSTATE_CURRENT) {
288                         BLI_remlink(&part->boids->states, state);
289                         MEM_freeN(state);
290                         break;
291                 }
292
293         }
294
295         /* there must be at least one state */
296         if(!part->boids->states.first) {
297                 state = boid_new_state(part->boids);
298                 BLI_addtail(&part->boids->states, state);       
299         }
300         else
301                 state = part->boids->states.first;
302
303         state->flag |= BOIDSTATE_CURRENT;
304
305         DAG_scene_sort(scene);
306         psys_flush_particle_settings(scene, psys->part, PSYS_RECALC_RESET);
307
308         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
309         
310         return OPERATOR_FINISHED;
311 }
312
313 void BOID_OT_state_del(wmOperatorType *ot)
314 {
315         /* identifiers */
316         ot->name= "Remove Boid State";
317         ot->idname= "BOID_OT_state_del";
318         
319         /* api callbacks */
320         ot->exec= state_del_exec;
321
322         /* flags */
323         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
324 }
325
326 /************************ move up/down boid state operators *********************/
327 static int state_move_up_exec(bContext *C, wmOperator *op)
328 {
329         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
330         ParticleSystem *psys= ptr.data;
331         Object *ob = ptr.id.data;
332         BoidSettings *boids;
333         BoidState *state;
334
335         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
336                 return OPERATOR_CANCELLED;
337
338         boids = psys->part->boids;
339         
340         for(state = boids->states.first; state; state=state->next) {
341                 if(state->flag & BOIDSTATE_CURRENT && state->prev) {
342                         BLI_remlink(&boids->states, state);
343                         BLI_insertlink(&boids->states, state->prev->prev, state);
344                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
345                         break;
346                 }
347         }
348         
349         return OPERATOR_FINISHED;
350 }
351
352 void BOID_OT_state_move_up(wmOperatorType *ot)
353 {
354         ot->name= "Move Up Boid State";
355         ot->description= "Move boid state up in the list.";
356         ot->idname= "BOID_OT_state_move_up";
357
358         ot->exec= state_move_up_exec;
359         
360         /* flags */
361         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
362 }
363
364 static int state_move_down_exec(bContext *C, wmOperator *op)
365 {
366         Scene *scene= CTX_data_scene(C);
367         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
368         ParticleSystem *psys= ptr.data;
369         BoidSettings *boids;
370         BoidState *state;
371
372         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
373                 return OPERATOR_CANCELLED;
374
375         boids = psys->part->boids;
376         
377         for(state = boids->states.first; state; state=state->next) {
378                 if(state->flag & BOIDSTATE_CURRENT && state->next) {
379                         BLI_remlink(&boids->states, state);
380                         BLI_insertlink(&boids->states, state->next, state);
381                         psys_flush_particle_settings(scene, psys->part, PSYS_RECALC_RESET);
382                         break;
383                 }
384         }
385         
386         return OPERATOR_FINISHED;
387 }
388
389 void BOID_OT_state_move_down(wmOperatorType *ot)
390 {
391         ot->name= "Move Down Boid State";
392         ot->description= "Move boid state down in the list.";
393         ot->idname= "BOID_OT_state_move_down";
394
395         ot->exec= state_move_down_exec;
396         
397         /* flags */
398         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
399 }
400