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