1 /* 2 * Copyright 2011-2013 Blender Foundation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef __BLENDER_ID_MAP_H__ 18 #define __BLENDER_ID_MAP_H__ 19 20 #include <string.h> 21 22 #include "render/geometry.h" 23 #include "render/scene.h" 24 25 #include "util/util_map.h" 26 #include "util/util_set.h" 27 #include "util/util_vector.h" 28 29 CCL_NAMESPACE_BEGIN 30 31 /* ID Map 32 * 33 * Utility class to map between Blender datablocks and Cycles data structures, 34 * and keep track of recalc tags from the dependency graph. */ 35 36 template<typename K, typename T> class id_map { 37 public: id_map(Scene * scene_)38 id_map(Scene *scene_) : scene(scene_) 39 { 40 } 41 ~id_map()42 ~id_map() 43 { 44 set<T *> nodes; 45 46 typename map<K, T *>::iterator jt; 47 for (jt = b_map.begin(); jt != b_map.end(); jt++) { 48 nodes.insert(jt->second); 49 } 50 51 scene->delete_nodes(nodes); 52 } 53 find(const BL::ID & id)54 T *find(const BL::ID &id) 55 { 56 return find(id.ptr.owner_id); 57 } 58 find(const K & key)59 T *find(const K &key) 60 { 61 if (b_map.find(key) != b_map.end()) { 62 T *data = b_map[key]; 63 return data; 64 } 65 66 return NULL; 67 } 68 set_recalc(const BL::ID & id)69 void set_recalc(const BL::ID &id) 70 { 71 b_recalc.insert(id.ptr.data); 72 } 73 set_recalc(void * id_ptr)74 void set_recalc(void *id_ptr) 75 { 76 b_recalc.insert(id_ptr); 77 } 78 has_recalc()79 bool has_recalc() 80 { 81 return !(b_recalc.empty()); 82 } 83 pre_sync()84 void pre_sync() 85 { 86 used_set.clear(); 87 } 88 89 /* Add new data. */ add(const K & key,T * data)90 void add(const K &key, T *data) 91 { 92 assert(find(key) == NULL); 93 b_map[key] = data; 94 used(data); 95 } 96 97 /* Update existing data. */ update(T * data,const BL::ID & id)98 bool update(T *data, const BL::ID &id) 99 { 100 return update(data, id, id); 101 } update(T * data,const BL::ID & id,const BL::ID & parent)102 bool update(T *data, const BL::ID &id, const BL::ID &parent) 103 { 104 bool recalc = (b_recalc.find(id.ptr.data) != b_recalc.end()); 105 if (parent.ptr.data && parent.ptr.data != id.ptr.data) { 106 recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end()); 107 } 108 used(data); 109 return recalc; 110 } 111 112 /* Combined add and update as needed. */ add_or_update(T ** r_data,const BL::ID & id)113 bool add_or_update(T **r_data, const BL::ID &id) 114 { 115 return add_or_update(r_data, id, id, id.ptr.owner_id); 116 } add_or_update(T ** r_data,const BL::ID & id,const K & key)117 bool add_or_update(T **r_data, const BL::ID &id, const K &key) 118 { 119 return add_or_update(r_data, id, id, key); 120 } add_or_update(T ** r_data,const BL::ID & id,const BL::ID & parent,const K & key)121 bool add_or_update(T **r_data, const BL::ID &id, const BL::ID &parent, const K &key) 122 { 123 T *data = find(key); 124 bool recalc; 125 126 if (!data) { 127 /* Add data if it didn't exist yet. */ 128 data = scene->create_node<T>(); 129 add(key, data); 130 recalc = true; 131 } 132 else { 133 /* check if updated needed. */ 134 recalc = update(data, id, parent); 135 } 136 137 *r_data = data; 138 return recalc; 139 } 140 141 /* Combined add or update for convenience. */ 142 is_used(const K & key)143 bool is_used(const K &key) 144 { 145 T *data = find(key); 146 return (data) ? used_set.find(data) != used_set.end() : false; 147 } 148 used(T * data)149 void used(T *data) 150 { 151 /* tag data as still in use */ 152 used_set.insert(data); 153 } 154 set_default(T * data)155 void set_default(T *data) 156 { 157 b_map[NULL] = data; 158 } 159 160 void post_sync(bool do_delete = true) 161 { 162 map<K, T *> new_map; 163 typedef pair<const K, T *> TMapPair; 164 typename map<K, T *>::iterator jt; 165 166 for (jt = b_map.begin(); jt != b_map.end(); jt++) { 167 TMapPair &pair = *jt; 168 169 if (do_delete && used_set.find(pair.second) == used_set.end()) { 170 scene->delete_node(pair.second); 171 } 172 else { 173 new_map[pair.first] = pair.second; 174 } 175 } 176 177 used_set.clear(); 178 b_recalc.clear(); 179 b_map = new_map; 180 } 181 key_to_scene_data()182 const map<K, T *> &key_to_scene_data() 183 { 184 return b_map; 185 } 186 187 protected: 188 map<K, T *> b_map; 189 set<T *> used_set; 190 set<void *> b_recalc; 191 Scene *scene; 192 }; 193 194 /* Object Key 195 * 196 * To uniquely identify instances, we use the parent, object and persistent instance ID. 197 * We also export separate object for a mesh and its particle hair. */ 198 199 enum { OBJECT_PERSISTENT_ID_SIZE = 8 /* MAX_DUPLI_RECUR in Blender. */ }; 200 201 struct ObjectKey { 202 void *parent; 203 int id[OBJECT_PERSISTENT_ID_SIZE]; 204 void *ob; 205 bool use_particle_hair; 206 ObjectKeyObjectKey207 ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_, bool use_particle_hair_) 208 : parent(parent_), ob(ob_), use_particle_hair(use_particle_hair_) 209 { 210 if (id_) 211 memcpy(id, id_, sizeof(id)); 212 else 213 memset(id, 0, sizeof(id)); 214 } 215 216 bool operator<(const ObjectKey &k) const 217 { 218 if (ob < k.ob) { 219 return true; 220 } 221 else if (ob == k.ob) { 222 if (parent < k.parent) { 223 return true; 224 } 225 else if (parent == k.parent) { 226 if (use_particle_hair < k.use_particle_hair) { 227 return true; 228 } 229 else if (use_particle_hair == k.use_particle_hair) { 230 return memcmp(id, k.id, sizeof(id)) < 0; 231 } 232 } 233 } 234 235 return false; 236 } 237 }; 238 239 /* Geometry Key 240 * 241 * We export separate geometry for a mesh and its particle hair, so key needs to 242 * distinguish between them. */ 243 244 struct GeometryKey { 245 void *id; 246 Geometry::Type geometry_type; 247 GeometryKeyGeometryKey248 GeometryKey(void *id, Geometry::Type geometry_type) : id(id), geometry_type(geometry_type) 249 { 250 } 251 252 bool operator<(const GeometryKey &k) const 253 { 254 if (id < k.id) { 255 return true; 256 } 257 else if (id == k.id) { 258 if (geometry_type < k.geometry_type) { 259 return true; 260 } 261 } 262 263 return false; 264 } 265 }; 266 267 /* Particle System Key */ 268 269 struct ParticleSystemKey { 270 void *ob; 271 int id[OBJECT_PERSISTENT_ID_SIZE]; 272 ParticleSystemKeyParticleSystemKey273 ParticleSystemKey(void *ob_, int id_[OBJECT_PERSISTENT_ID_SIZE]) : ob(ob_) 274 { 275 if (id_) 276 memcpy(id, id_, sizeof(id)); 277 else 278 memset(id, 0, sizeof(id)); 279 } 280 281 bool operator<(const ParticleSystemKey &k) const 282 { 283 /* first id is particle index, we don't compare that */ 284 if (ob < k.ob) 285 return true; 286 else if (ob == k.ob) 287 return memcmp(id + 1, k.id + 1, sizeof(int) * (OBJECT_PERSISTENT_ID_SIZE - 1)) < 0; 288 289 return false; 290 } 291 }; 292 293 CCL_NAMESPACE_END 294 295 #endif /* __BLENDER_ID_MAP_H__ */ 296