Exemple #1
0
static int rna_Object_is_modified(Object *ob, Scene *scene, int settings)
{
	return BKE_object_is_modified(scene, ob) & settings;
}
Exemple #2
0
Mesh *BlenderSync::sync_mesh(BL::Depsgraph &b_depsgraph,
                             BL::Object &b_ob,
                             BL::Object &b_ob_instance,
                             bool object_updated,
                             bool show_self,
                             bool show_particles)
{
  /* test if we can instance or if the object is modified */
  BL::ID b_ob_data = b_ob.data();
  BL::ID key = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data;
  BL::Material material_override = view_layer.material_override;

  /* find shader indices */
  vector<Shader *> used_shaders;

  BL::Object::material_slots_iterator slot;
  for (b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
    if (material_override) {
      find_shader(material_override, used_shaders, scene->default_surface);
    }
    else {
      BL::ID b_material(slot->material());
      find_shader(b_material, used_shaders, scene->default_surface);
    }
  }

  if (used_shaders.size() == 0) {
    if (material_override)
      find_shader(material_override, used_shaders, scene->default_surface);
    else
      used_shaders.push_back(scene->default_surface);
  }

  /* test if we need to sync */
  int requested_geometry_flags = Mesh::GEOMETRY_NONE;
  if (view_layer.use_surfaces) {
    requested_geometry_flags |= Mesh::GEOMETRY_TRIANGLES;
  }
  if (view_layer.use_hair) {
    requested_geometry_flags |= Mesh::GEOMETRY_CURVES;
  }
  Mesh *mesh;

  if (!mesh_map.sync(&mesh, key)) {
    /* if transform was applied to mesh, need full update */
    if (object_updated && mesh->transform_applied)
      ;
    /* test if shaders changed, these can be object level so mesh
     * does not get tagged for recalc */
    else if (mesh->used_shaders != used_shaders)
      ;
    else if (requested_geometry_flags != mesh->geometry_flags)
      ;
    else {
      /* even if not tagged for recalc, we may need to sync anyway
       * because the shader needs different mesh attributes */
      bool attribute_recalc = false;

      foreach (Shader *shader, mesh->used_shaders)
        if (shader->need_update_mesh)
          attribute_recalc = true;

      if (!attribute_recalc)
        return mesh;
    }
  }

  /* ensure we only sync instanced meshes once */
  if (mesh_synced.find(mesh) != mesh_synced.end())
    return mesh;

  progress.set_sync_status("Synchronizing object", b_ob.name());

  mesh_synced.insert(mesh);

  /* create derived mesh */
  array<int> oldtriangles;
  array<Mesh::SubdFace> oldsubd_faces;
  array<int> oldsubd_face_corners;
  oldtriangles.steal_data(mesh->triangles);
  oldsubd_faces.steal_data(mesh->subd_faces);
  oldsubd_face_corners.steal_data(mesh->subd_face_corners);

  /* compares curve_keys rather than strands in order to handle quick hair
   * adjustments in dynamic BVH - other methods could probably do this better*/
  array<float3> oldcurve_keys;
  array<float> oldcurve_radius;
  oldcurve_keys.steal_data(mesh->curve_keys);
  oldcurve_radius.steal_data(mesh->curve_radius);

  mesh->clear();
  mesh->used_shaders = used_shaders;
  mesh->name = ustring(b_ob_data.name().c_str());

  if (requested_geometry_flags != Mesh::GEOMETRY_NONE) {
    /* Adaptive subdivision setup. Not for baking since that requires
     * exact mapping to the Blender mesh. */
    if (scene->bake_manager->get_baking()) {
      mesh->subdivision_type = Mesh::SUBDIVISION_NONE;
    }
    else {
      mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental);
    }

    /* For some reason, meshes do not need this... */
    bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);

    BL::Mesh b_mesh = object_to_mesh(
        b_data, b_ob, b_depsgraph, need_undeformed, mesh->subdivision_type);

    if (b_mesh) {
      /* Sync mesh itself. */
      if (view_layer.use_surfaces && show_self) {
        if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE)
          create_subd_mesh(scene, mesh, b_ob, b_mesh, used_shaders, dicing_rate, max_subdivisions);
        else
          create_mesh(scene, mesh, b_mesh, used_shaders, false);

        create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current());
      }

      /* Sync hair curves. */
      if (view_layer.use_hair && show_particles &&
          mesh->subdivision_type == Mesh::SUBDIVISION_NONE) {
        sync_curves(mesh, b_mesh, b_ob, false);
      }

      free_object_to_mesh(b_data, b_ob, b_mesh);
    }
  }
  mesh->geometry_flags = requested_geometry_flags;

  /* fluid motion */
  sync_mesh_fluid_motion(b_ob, scene, mesh);

  /* tag update */
  bool rebuild = (oldtriangles != mesh->triangles) || (oldsubd_faces != mesh->subd_faces) ||
                 (oldsubd_face_corners != mesh->subd_face_corners) ||
                 (oldcurve_keys != mesh->curve_keys) || (oldcurve_radius != mesh->curve_radius);

  mesh->tag_update(scene, rebuild);

  return mesh;
}
Exemple #3
0
void BlenderSync::sync_curve_settings()
{
  PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves");

  CurveSystemManager *curve_system_manager = scene->curve_system_manager;
  CurveSystemManager prev_curve_system_manager = *curve_system_manager;

  curve_system_manager->use_curves = get_boolean(csscene, "use_curves");

  curve_system_manager->primitive = (CurvePrimitiveType)get_enum(
      csscene, "primitive", CURVE_NUM_PRIMITIVE_TYPES, CURVE_LINE_SEGMENTS);
  curve_system_manager->curve_shape = (CurveShapeType)get_enum(
      csscene, "shape", CURVE_NUM_SHAPE_TYPES, CURVE_THICK);
  curve_system_manager->resolution = get_int(csscene, "resolution");
  curve_system_manager->subdivisions = get_int(csscene, "subdivisions");
  curve_system_manager->use_backfacing = !get_boolean(csscene, "cull_backfacing");

  /* Triangles */
  if (curve_system_manager->primitive == CURVE_TRIANGLES) {
    /* camera facing planes */
    if (curve_system_manager->curve_shape == CURVE_RIBBON) {
      curve_system_manager->triangle_method = CURVE_CAMERA_TRIANGLES;
      curve_system_manager->resolution = 1;
    }
    else if (curve_system_manager->curve_shape == CURVE_THICK) {
      curve_system_manager->triangle_method = CURVE_TESSELATED_TRIANGLES;
    }
  }
  /* Line Segments */
  else if (curve_system_manager->primitive == CURVE_LINE_SEGMENTS) {
    if (curve_system_manager->curve_shape == CURVE_RIBBON) {
      /* tangent shading */
      curve_system_manager->line_method = CURVE_UNCORRECTED;
      curve_system_manager->use_encasing = true;
      curve_system_manager->use_backfacing = false;
      curve_system_manager->use_tangent_normal_geometry = true;
    }
    else if (curve_system_manager->curve_shape == CURVE_THICK) {
      curve_system_manager->line_method = CURVE_ACCURATE;
      curve_system_manager->use_encasing = false;
      curve_system_manager->use_tangent_normal_geometry = false;
    }
  }
  /* Curve Segments */
  else if (curve_system_manager->primitive == CURVE_SEGMENTS) {
    if (curve_system_manager->curve_shape == CURVE_RIBBON) {
      curve_system_manager->primitive = CURVE_RIBBONS;
      curve_system_manager->use_backfacing = false;
    }
  }

  if (curve_system_manager->modified_mesh(prev_curve_system_manager)) {
    BL::BlendData::objects_iterator b_ob;

    for (b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
      if (object_is_mesh(*b_ob)) {
        BL::Object::particle_systems_iterator b_psys;
        for (b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end();
             ++b_psys) {
          if ((b_psys->settings().render_type() == BL::ParticleSettings::render_type_PATH) &&
              (b_psys->settings().type() == BL::ParticleSettings::type_HAIR)) {
            BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data();
            mesh_map.set_recalc(key);
            object_map.set_recalc(*b_ob);
          }
        }
      }
    }
  }

  if (curve_system_manager->modified(prev_curve_system_manager))
    curve_system_manager->tag_update(scene);
}
Exemple #4
0
Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
                             bool object_updated,
                             bool hide_tris)
{
	/* When viewport display is not needed during render we can force some
	 * caches to be releases from blender side in order to reduce peak memory
	 * footprint during synchronization process.
	 */
	const bool is_interface_locked = b_engine.render() &&
	                                 b_engine.render().use_lock_interface();
	const bool can_free_caches = BlenderSession::headless || is_interface_locked;

	/* test if we can instance or if the object is modified */
	BL::ID b_ob_data = b_ob.data();
	BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data;
	BL::Material material_override = render_layer.material_override;

	/* find shader indices */
	vector<uint> used_shaders;

	BL::Object::material_slots_iterator slot;
	for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
		if(material_override) {
			find_shader(material_override, used_shaders, scene->default_surface);
		}
		else {
			BL::ID b_material(slot->material());
			find_shader(b_material, used_shaders, scene->default_surface);
		}
	}

	if(used_shaders.size() == 0) {
		if(material_override)
			find_shader(material_override, used_shaders, scene->default_surface);
		else
			used_shaders.push_back(scene->default_surface);
	}
	
	/* test if we need to sync */
	int requested_geometry_flags = Mesh::GEOMETRY_NONE;
	if(render_layer.use_surfaces) {
		requested_geometry_flags |= Mesh::GEOMETRY_TRIANGLES;
	}
	if(render_layer.use_hair) {
		requested_geometry_flags |= Mesh::GEOMETRY_CURVES;
	}
	Mesh *mesh;

	if(!mesh_map.sync(&mesh, key)) {
		/* if transform was applied to mesh, need full update */
		if(object_updated && mesh->transform_applied);
		/* test if shaders changed, these can be object level so mesh
		 * does not get tagged for recalc */
		else if(mesh->used_shaders != used_shaders);
		else if(requested_geometry_flags != mesh->geometry_flags);
		else {
			/* even if not tagged for recalc, we may need to sync anyway
			 * because the shader needs different mesh attributes */
			bool attribute_recalc = false;

			foreach(uint shader, mesh->used_shaders)
				if(scene->shaders[shader]->need_update_attributes)
					attribute_recalc = true;

			if(!attribute_recalc)
				return mesh;
		}
	}

	/* ensure we only sync instanced meshes once */
	if(mesh_synced.find(mesh) != mesh_synced.end())
		return mesh;
	
	mesh_synced.insert(mesh);

	/* create derived mesh */
	PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");

	vector<Mesh::Triangle> oldtriangle = mesh->triangles;
	
	/* compares curve_keys rather than strands in order to handle quick hair
	 * adjustments in dynamic BVH - other methods could probably do this better*/
	vector<float4> oldcurve_keys = mesh->curve_keys;

	mesh->clear();
	mesh->used_shaders = used_shaders;
	mesh->name = ustring(b_ob_data.name().c_str());

	if(requested_geometry_flags != Mesh::GEOMETRY_NONE) {
		/* mesh objects does have special handle in the dependency graph,
		 * they're ensured to have properly updated.
		 *
		 * updating meshes here will end up having derived mesh referencing
		 * freed data from the blender side.
		 */
		if(preview && b_ob.type() != BL::Object::type_MESH)
			b_ob.update_from_editmode();

		bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
		BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);

		if(b_mesh) {
			if(render_layer.use_surfaces && !hide_tris) {
				if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
					create_subd_mesh(scene, mesh, b_mesh, &cmesh, used_shaders);
				else
					create_mesh(scene, mesh, b_mesh, used_shaders);

				create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current());
			}

			if(render_layer.use_hair)
				sync_curves(mesh, b_mesh, b_ob, false);

			if(can_free_caches) {
				b_ob.cache_release();
			}

			/* free derived mesh */
			b_data.meshes.remove(b_mesh);
		}
	}
	mesh->geometry_flags = requested_geometry_flags;

	/* displacement method */
	if(cmesh.data) {
		const int method = get_enum(cmesh, "displacement_method");

		if(method == 0 || !experimental)
			mesh->displacement_method = Mesh::DISPLACE_BUMP;
		else if(method == 1)
			mesh->displacement_method = Mesh::DISPLACE_TRUE;
		else
			mesh->displacement_method = Mesh::DISPLACE_BOTH;
	}

	/* tag update */
	bool rebuild = false;

	if(oldtriangle.size() != mesh->triangles.size())
		rebuild = true;
	else if(oldtriangle.size()) {
		if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
			rebuild = true;
	}

	if(oldcurve_keys.size() != mesh->curve_keys.size())
		rebuild = true;
	else if(oldcurve_keys.size()) {
		if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float4)*oldcurve_keys.size()) != 0)
			rebuild = true;
	}
	
	mesh->tag_update(scene, rebuild);

	return mesh;
}
Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris)
{
	/* test if we can instance or if the object is modified */
	BL::ID b_ob_data = b_ob.data();
	BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data;
	BL::Material material_override = render_layer.material_override;

	/* find shader indices */
	vector<uint> used_shaders;

	BL::Object::material_slots_iterator slot;
	for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
		if(material_override)
			find_shader(material_override, used_shaders, scene->default_surface);
		else
			find_shader(slot->material(), used_shaders, scene->default_surface);
	}

	if(used_shaders.size() == 0) {
		if(material_override)
			find_shader(material_override, used_shaders, scene->default_surface);
		else
			used_shaders.push_back(scene->default_surface);
	}
	
	/* test if we need to sync */
	Mesh *mesh;

	if(!mesh_map.sync(&mesh, key)) {
		
		/* if transform was applied to mesh, need full update */
		if(object_updated && mesh->transform_applied);
		/* test if shaders changed, these can be object level so mesh
		 * does not get tagged for recalc */
		else if(mesh->used_shaders != used_shaders);
		else {
			/* even if not tagged for recalc, we may need to sync anyway
			 * because the shader needs different mesh attributes */
			bool attribute_recalc = false;

			foreach(uint shader, mesh->used_shaders)
				if(scene->shaders[shader]->need_update_attributes)
					attribute_recalc = true;

			if(!attribute_recalc)
				return mesh;
		}
	}

	/* ensure we only sync instanced meshes once */
	if(mesh_synced.find(mesh) != mesh_synced.end())
		return mesh;
	
	mesh_synced.insert(mesh);

	/* create derived mesh */
	PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");

	vector<Mesh::Triangle> oldtriangle = mesh->triangles;
	
	/* compares curve_keys rather than strands in order to handle quick hair
	 * adjustsments in dynamic BVH - other methods could probably do this better*/
	vector<float4> oldcurve_keys = mesh->curve_keys;

	mesh->clear();
	mesh->used_shaders = used_shaders;
	mesh->name = ustring(b_ob_data.name().c_str());

	if(render_layer.use_surfaces || render_layer.use_hair) {
		if(preview)
			b_ob.update_from_editmode();

		bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
		BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);

		if(b_mesh) {
			if(render_layer.use_surfaces && !hide_tris) {
				if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
					create_subd_mesh(scene, mesh, b_mesh, &cmesh, used_shaders);
				else
					create_mesh(scene, mesh, b_mesh, used_shaders);

				create_mesh_volume_attributes(scene, b_ob, mesh);
			}

			if(render_layer.use_hair)
				sync_curves(mesh, b_mesh, b_ob, false);

			/* free derived mesh */
			b_data.meshes.remove(b_mesh);
		}
	}

	/* displacement method */
	if(cmesh.data) {
		const int method = RNA_enum_get(&cmesh, "displacement_method");

		if(method == 0 || !experimental)
			mesh->displacement_method = Mesh::DISPLACE_BUMP;
		else if(method == 1)
			mesh->displacement_method = Mesh::DISPLACE_TRUE;
		else
			mesh->displacement_method = Mesh::DISPLACE_BOTH;
	}

	/* tag update */
	bool rebuild = false;

	if(oldtriangle.size() != mesh->triangles.size())
		rebuild = true;
	else if(oldtriangle.size()) {
		if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
			rebuild = true;
	}

	if(oldcurve_keys.size() != mesh->curve_keys.size())
		rebuild = true;
	else if(oldcurve_keys.size()) {
		if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float4)*oldcurve_keys.size()) != 0)
			rebuild = true;
	}
	
	mesh->tag_update(scene, rebuild);

	return mesh;
}
Exemple #6
0
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Sync recalc flags from blender to OctaneRender. Actual update is done separate,
// so we can do it later on if doing it immediate is not suitable.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool BlenderSync::sync_recalc() {
    BL::BlendData::materials_iterator b_mat;
    for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat)
        if(b_mat->is_updated() || (b_mat->node_tree() && b_mat->node_tree().is_updated()))
            shader_map.set_recalc(*b_mat);

    //FIXME: Perhaps not needed...
    BL::BlendData::textures_iterator b_tex;
    for(b_data.textures.begin(b_tex); b_tex != b_data.textures.end(); ++b_tex)
        if(b_tex->is_updated() || (b_tex->node_tree() && b_tex->node_tree().is_updated()))
            shader_map.set_recalc(*b_tex);

    BL::BlendData::lamps_iterator b_lamp;
    for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp)
        if(b_lamp->is_updated() || (b_lamp->node_tree() && b_lamp->node_tree().is_updated()))
            shader_map.set_recalc(*b_lamp);

    BL::BlendData::objects_iterator b_ob;
    for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
        if(b_ob->is_updated()) {
            if(object_is_light(*b_ob)) light_object_map.set_recalc(*b_ob);
            else object_map.set_recalc(*b_ob);
        }

        BL::SmokeDomainSettings b_domain = BlenderSync::object_smoke_domain_find(*b_ob);
        if(b_domain && b_domain.cache_file_format() == BL::SmokeDomainSettings::cache_file_format_OPENVDB) { // Workaround, smoke is not tagged for update by BKE_scene_update_for_newframe()
            bool is_export = scene->session->b_session && scene->session->b_session->export_type != ::OctaneEngine::OctaneClient::SceneExportTypes::NONE;
            BL::ID b_ob_data = b_ob->data();
            PointerRNA oct_mesh = RNA_pointer_get(&b_ob_data.ptr, "octane");
            bool is_reshapable = scene->meshes_type == Mesh::RESHAPABLE_PROXY || (scene->meshes_type == Mesh::AS_IS && static_cast<Mesh::MeshType>(RNA_enum_get(&oct_mesh, "mesh_type")) == Mesh::RESHAPABLE_PROXY);

            if(is_export) {
                BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data();
                mesh_map.set_recalc(key);
            }
            else if((interactive && is_reshapable) || (!interactive && (scene->anim_mode == FULL || (scene->anim_mode == MOVABLE_PROXIES && is_reshapable)))) {
                BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data();
                mesh_map.set_recalc(key);
            }
        }
        else if(object_is_curve(*b_ob)) { // Workaround, curves are not tagged for update by BKE_scene_update_for_newframe()
            if(b_ob->is_updated_data() || b_ob->data().is_updated()) {
                BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data();
                mesh_map.set_recalc(key);
            }
            else {
                bool is_export = scene->session->b_session && scene->session->b_session->export_type != ::OctaneEngine::OctaneClient::SceneExportTypes::NONE;
                BL::ID b_ob_data = b_ob->data();
                PointerRNA oct_mesh = RNA_pointer_get(&b_ob_data.ptr, "octane");
                bool is_reshapable = scene->meshes_type == Mesh::RESHAPABLE_PROXY || (scene->meshes_type == Mesh::AS_IS && static_cast<Mesh::MeshType>(RNA_enum_get(&oct_mesh, "mesh_type")) == Mesh::RESHAPABLE_PROXY);

                if(is_export) {
                    BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data();
                    mesh_map.set_recalc(key);
                }
                else if((interactive && is_reshapable) || (!interactive && (scene->anim_mode == FULL || (scene->anim_mode == MOVABLE_PROXIES && is_reshapable)))) {
                    BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data();
                    mesh_map.set_recalc(key);
                }
            }
        }
        else if(object_is_mesh(*b_ob)) {
            if(b_ob->is_updated_data() || b_ob->data().is_updated()) {
                BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data();
                mesh_map.set_recalc(key);
            }
            else if(!interactive && BKE_object_is_modified(*b_ob)) { // Workaround, some modified meshes are not tagged for update by BKE_scene_update_for_newframe()
                bool is_export = scene->session->b_session && scene->session->b_session->export_type != ::OctaneEngine::OctaneClient::SceneExportTypes::NONE;
                BL::ID b_ob_data = b_ob->data();
                PointerRNA oct_mesh = RNA_pointer_get(&b_ob_data.ptr, "octane");
                bool is_reshapable = scene->meshes_type == Mesh::RESHAPABLE_PROXY || (scene->meshes_type == Mesh::AS_IS && static_cast<Mesh::MeshType>(RNA_enum_get(&oct_mesh, "mesh_type")) == Mesh::RESHAPABLE_PROXY);

                if(is_export) {
                    BL::ID key = *b_ob;
                    mesh_map.set_recalc(key);
                }
                else if(scene->anim_mode == FULL || (scene->anim_mode == MOVABLE_PROXIES && is_reshapable)) {
                    BL::ID key = *b_ob;
                    mesh_map.set_recalc(key);
                }
            }
        }
        else if(object_is_light(*b_ob)) {
            if(b_ob->is_updated_data() || b_ob->data().is_updated())
                light_map.set_recalc(b_ob->data());
        }
    }

    //BL::BlendData::meshes_iterator b_mesh;
    //for(b_data.meshes.begin(b_mesh); b_mesh != b_data.meshes.end(); ++b_mesh)
    //	if(b_mesh->is_updated() || b_mesh->is_updated_data())
    //		mesh_map.set_recalc(*b_mesh);

    BL::BlendData::worlds_iterator b_world;
    for(b_data.worlds.begin(b_world); b_world != b_data.worlds.end(); ++b_world) {
        if(world_map == b_world->ptr.data && (b_world->is_updated() || (b_world->node_tree() && b_world->node_tree().is_updated()))) {
            world_recalc = true;
        }
    }

    bool recalc =
        shader_map.has_recalc() ||
        object_map.has_recalc() ||
        light_map.has_recalc() ||
        mesh_map.has_recalc() ||
        BlendDataObjects_is_updated_get(&b_data.ptr) ||
        world_recalc;

    return recalc;
} //sync_recalc()