177912cd8f09a432bb952046421698c037f23a32
[blender-staging.git] / intern / cycles / blender / blender_particles.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include "mesh.h"
20 #include "particles.h"
21
22 #include "blender_sync.h"
23 #include "blender_util.h"
24
25 #include "util_foreach.h"
26
27 CCL_NAMESPACE_BEGIN
28
29 /* Utilities */
30
31
32 /* Particles Sync */
33
34 bool BlenderSync::psys_need_update(BL::ParticleSystem b_psys)
35 {
36         /* Particle data is only needed for
37          * a) Billboard render mode if object's own material uses particle info
38          * b) object/group render mode if any dupli object's material uses particle info
39          *
40          * Note: Meshes have to be synced at this point!
41          */
42         bool need_update = false;
43         
44         switch (b_psys.settings().render_type()) {
45                 /* XXX not implemented yet! 
46                  * billboards/strands would become part of the mesh data (?),
47                  * so the mesh attributes would store whether particle info is required.
48                  */
49                 #if 0
50                 case BL::ParticleSettings::render_type_BILLBOARD:
51                 case BL::ParticleSettings::render_type_PATH: {  /* for strand rendering */
52                         BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob.data();
53                         Mesh *mesh = mesh_map.find(key);
54                         if (mesh) {
55                                 need_update |= mesh->need_attribute(scene, ATTR_STD_PARTICLE) && mesh->need_update;
56                         }
57                         break;
58                 }
59                 #endif
60                 
61                 case BL::ParticleSettings::render_type_OBJECT: {
62                         BL::Object b_dupli_ob = b_psys.settings().dupli_object();
63                         if (b_dupli_ob) {
64                                 BL::ID key = (BKE_object_is_modified(b_dupli_ob))? b_dupli_ob: b_dupli_ob.data();
65                                 Mesh *mesh = mesh_map.find(key);
66                                 if (mesh) {
67                                         need_update |= mesh->need_attribute(scene, ATTR_STD_PARTICLE) && mesh->need_update;
68                                 }
69                         }
70                         break;
71                 }
72                 
73                 case BL::ParticleSettings::render_type_GROUP: {
74                         BL::Group b_dupli_group = b_psys.settings().dupli_group();
75                         if (b_dupli_group) {
76                                 BL::Group::objects_iterator b_gob;
77                                 for (b_dupli_group.objects.begin(b_gob); b_gob != b_dupli_group.objects.end(); ++b_gob) {
78                                         BL::ID key = (BKE_object_is_modified(*b_gob))? *b_gob: b_gob->data();
79                                         Mesh *mesh = mesh_map.find(key);
80                                         if (mesh) {
81                                                 need_update |= mesh->need_attribute(scene, ATTR_STD_PARTICLE) && mesh->need_update;
82                                         }
83                                 }
84                         }
85                         break;
86                 }
87                 
88                 default:
89                         /* avoid compiler warning */
90                         break;
91         }
92         
93         return need_update;
94 }
95
96 static bool use_particle_system(BL::ParticleSystem b_psys)
97 {
98         /* only use duplicator particles? disabled particle info for
99          * halo and billboard to reduce particle count.
100          * Probably not necessary since particles don't contain a huge amount
101          * of data compared to other textures.
102          */
103         #if 0
104         int render_type = b_psys->settings().render_type();
105         return (render_type == BL::ParticleSettings::render_type_OBJECT
106                 || render_type == BL::ParticleSettings::render_type_GROUP);
107         #endif
108         
109         return true;
110 }
111
112 static bool use_particle(BL::Particle b_pa)
113 {
114         return b_pa.is_exist() && b_pa.is_visible() &&
115                 (b_pa.alive_state()==BL::Particle::alive_state_ALIVE || b_pa.alive_state()==BL::Particle::alive_state_DYING);
116 }
117
118 static int psys_count_particles(BL::ParticleSystem b_psys)
119 {
120         int tot = 0;
121         BL::ParticleSystem::particles_iterator b_pa;
122         for(b_psys.particles.begin(b_pa); b_pa != b_psys.particles.end(); ++b_pa) {
123                 if(use_particle(*b_pa))
124                         ++tot;
125         }
126         return tot;
127 }
128
129 int BlenderSync::object_count_particles(BL::Object b_ob)
130 {
131         int tot = 0;
132         BL::Object::particle_systems_iterator b_psys;
133         for(b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end(); ++b_psys) {
134                 if (use_particle_system(*b_psys))
135                         tot += psys_count_particles(*b_psys);
136         }
137         return tot;
138 }
139
140 void BlenderSync::sync_particles(BL::Object b_ob, BL::ParticleSystem b_psys)
141 {
142         /* depending on settings the psys may not even be rendered */
143         if (!use_particle_system(b_psys))
144                 return;
145         
146         /* key to lookup particle system */
147         ParticleSystemKey key(b_ob, b_psys);
148         ParticleSystem *psys;
149         
150         /* test if we need to sync */
151         bool object_updated = false;
152         
153         if(particle_system_map.sync(&psys, b_ob, b_ob, key))
154                 object_updated = true;
155         
156         bool need_update = psys_need_update(b_psys);
157         
158         if (object_updated || need_update) {
159                 int tot = psys_count_particles(b_psys);
160                 psys->particles.clear();
161                 psys->particles.reserve(tot);
162                 
163                 int index = 0;
164                 BL::ParticleSystem::particles_iterator b_pa;
165                 for(b_psys.particles.begin(b_pa); b_pa != b_psys.particles.end(); ++b_pa) {
166                         if(use_particle(*b_pa)) {
167                                 Particle pa;
168                                 
169                                 pa.index = index;
170                                 pa.age = b_scene.frame_current() - b_pa->birth_time();
171                                 pa.lifetime = b_pa->lifetime();
172                                 pa.location = get_float3(b_pa->location());
173                                 pa.rotation = get_float4(b_pa->rotation());
174                                 pa.size = b_pa->size();
175                                 pa.velocity = get_float3(b_pa->velocity());
176                                 pa.angular_velocity = get_float3(b_pa->angular_velocity());
177                                 
178                                 psys->particles.push_back(pa);
179                         }
180                         
181                         ++index;
182                 }
183                 
184                 psys->tag_update(scene);
185         }
186 }
187
188 void BlenderSync::sync_particle_systems()
189 {
190         /* layer data */
191         uint scene_layer = render_layer.scene_layer;
192         
193         particle_system_map.pre_sync();
194
195         /* object loop */
196         BL::Scene::objects_iterator b_ob;
197         BL::Scene b_sce = b_scene;
198
199         for(; b_sce; b_sce = b_sce.background_set()) {
200                 for(b_sce.objects.begin(b_ob); b_ob != b_sce.objects.end(); ++b_ob) {
201                         bool hide = (render_layer.use_viewport_visibility)? b_ob->hide(): b_ob->hide_render();
202                         uint ob_layer = get_layer(b_ob->layers(), b_ob->layers_local_view(), object_is_light(*b_ob));
203                         CYCLES_LOCAL_LAYER_HACK(render_layer.use_localview, ob_layer);
204                         hide = hide || !(ob_layer & scene_layer);
205
206                         if(!hide) {
207                                 BL::Object::particle_systems_iterator b_psys;
208                                 for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys)
209                                         sync_particles(*b_ob, *b_psys);
210                         }
211                 }
212         }
213
214         /* handle removed data and modified pointers */
215         if(particle_system_map.post_sync())
216                 scene->particle_system_manager->tag_update(scene);
217 }
218
219 CCL_NAMESPACE_END