blender_camera.cpp
blender_mesh.cpp
blender_object.cpp
- blender_particles.cpp
blender_curves.cpp
blender_logging.cpp
blender_python.cpp
del bpy.types.Scene.cycles_curves
-class CyclesCurveSettings(bpy.types.PropertyGroup):
- @classmethod
- def register(cls):
- bpy.types.ParticleSettings.cycles = PointerProperty(
- name="Cycles Hair Settings",
- description="Cycles hair settings",
- type=cls,
- )
- cls.radius_scale = FloatProperty(
- name="Radius Scaling",
- description="Multiplier of width properties",
- min=0.0, max=1000.0,
- default=0.01,
- )
- cls.root_width = FloatProperty(
- name="Root Size",
- description="Strand's width at root",
- min=0.0, max=1000.0,
- default=1.0,
- )
- cls.tip_width = FloatProperty(
- name="Tip Multiplier",
- description="Strand's width at tip",
- min=0.0, max=1000.0,
- default=0.0,
- )
- cls.shape = FloatProperty(
- name="Strand Shape",
- description="Strand shape parameter",
- min=-1.0, max=1.0,
- default=0.0,
- )
- cls.use_closetip = BoolProperty(
- name="Close tip",
- description="Set tip radius to zero",
- default=True,
- )
-
- @classmethod
- def unregister(cls):
- del bpy.types.ParticleSettings.cycles
-
-
def register():
bpy.utils.register_class(CyclesRenderSettings)
bpy.utils.register_class(CyclesCameraSettings)
bpy.utils.register_class(CyclesVisibilitySettings)
bpy.utils.register_class(CyclesMeshSettings)
bpy.utils.register_class(CyclesCurveRenderSettings)
- bpy.utils.register_class(CyclesCurveSettings)
def unregister():
bpy.utils.unregister_class(CyclesMeshSettings)
bpy.utils.unregister_class(CyclesVisibilitySettings)
bpy.utils.unregister_class(CyclesCurveRenderSettings)
- bpy.utils.unregister_class(CyclesCurveSettings)
layout.template_color_ramp(mapping, "color_ramp", expand=True)
-class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel):
- bl_label = "Textures"
- bl_context = "particle"
- bl_options = {'DEFAULT_CLOSED'}
-
- @classmethod
- def poll(cls, context):
- psys = context.particle_system
- return psys and CyclesButtonsPanel.poll(context)
-
- def draw(self, context):
- layout = self.layout
-
- psys = context.particle_system
- part = psys.settings
-
- row = layout.row()
- row.template_list("TEXTURE_UL_texslots", "", part, "texture_slots", part, "active_texture_index", rows=2)
-
- col = row.column(align=True)
- col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
- col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
- col.menu("TEXTURE_MT_specials", icon='DOWNARROW_HLT', text="")
-
- if not part.active_texture:
- layout.template_ID(part, "active_texture", new="texture.new")
- else:
- slot = part.texture_slots[part.active_texture_index]
- layout.template_ID(slot, "texture", new="texture.new")
-
-
class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel):
bl_label = "Cycles Hair Rendering"
bl_context = "particle"
col.prop(cscene, "debug_use_opencl_debug", text="Debug")
-class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel):
- bl_label = "Cycles Hair Settings"
- bl_context = "particle"
-
- @classmethod
- def poll(cls, context):
- scene = context.scene
- ccscene = scene.cycles_curves
- psys = context.particle_system
- use_curves = ccscene.use_curves and psys
- return CyclesButtonsPanel.poll(context) and use_curves and psys.settings.type == 'HAIR'
-
- def draw(self, context):
- layout = self.layout
-
- psys = context.particle_settings
- cpsys = psys.cycles
-
- row = layout.row()
- row.prop(cpsys, "shape", text="Shape")
-
- layout.label(text="Thickness:")
- row = layout.row()
- row.prop(cpsys, "root_width", text="Root")
- row.prop(cpsys, "tip_width", text="Tip")
-
- row = layout.row()
- row.prop(cpsys, "radius_scale", text="Scaling")
- row.prop(cpsys, "use_closetip", text="Close tip")
-
-
class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel):
bl_label = "Simplify"
bl_context = "scene"
col = split.column()
col.label(text="Viewport:")
col.prop(rd, "simplify_subdivision", text="Subdivision")
- col.prop(rd, "simplify_child_particles", text="Child Particles")
col = split.column()
col.label(text="Render:")
col.prop(rd, "simplify_subdivision_render", text="Subdivision")
- col.prop(rd, "simplify_child_particles_render", text="Child Particles")
col = layout.column()
col.prop(cscene, "use_camera_cull")
"TEXTURE_PT_ocean",
"TEXTURE_PT_influence",
"TEXTURE_PT_colors",
- "PARTICLE_PT_context_particles",
- "PARTICLE_PT_custom_props",
- "PARTICLE_PT_emission",
- "PARTICLE_PT_hair_dynamics",
- "PARTICLE_PT_cache",
- "PARTICLE_PT_velocity",
- "PARTICLE_PT_rotation",
- "PARTICLE_PT_physics",
"SCENE_PT_rigid_body_world",
"SCENE_PT_rigid_body_cache",
"SCENE_PT_rigid_body_field_weights",
- "PARTICLE_PT_boidbrain",
- "PARTICLE_PT_render",
- "PARTICLE_PT_draw",
- "PARTICLE_PT_children",
- "PARTICLE_PT_field_weights",
- "PARTICLE_PT_force_fields",
- "PARTICLE_PT_vertexgroups",
"MATERIAL_PT_custom_props",
"MATERIAL_PT_freestyle_line",
"BONE_PT_custom_props",
void interp_weights(float t, float data[4]);
float shaperadius(float shape, float root, float tip, float time);
void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData);
-bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num);
-bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num);
-bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background);
void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData);
void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
float3 RotCam, bool is_ortho);
curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t);
}
-bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background)
-{
- int curvenum = 0;
- int keyno = 0;
-
- if(!(mesh && b_mesh && b_ob && CData))
- return false;
-
- Transform tfm = get_transform(b_ob->matrix_world());
- Transform itfm = transform_quick_inverse(tfm);
-
- BL::Object::modifiers_iterator b_mod;
- for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
- if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
- BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
-
- if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
- int shader = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1);
- int draw_step = background ? b_part.render_step() : b_part.draw_step();
- int totparts = b_psys.particles.length();
- int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
- int totcurves = totchild;
-
- if(b_part.child_type() == 0 || totchild == 0)
- totcurves += totparts;
-
- if(totcurves == 0)
- continue;
-
- int ren_step = (1 << draw_step) + 1;
- if(b_part.kink() == BL::ParticleSettings::kink_SPIRAL)
- ren_step += b_part.kink_extra_steps();
-
- PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
-
- CData->psys_firstcurve.push_back_slow(curvenum);
- CData->psys_curvenum.push_back_slow(totcurves);
- CData->psys_shader.push_back_slow(shader);
-
- float radius = get_float(cpsys, "radius_scale") * 0.5f;
-
- CData->psys_rootradius.push_back_slow(radius * get_float(cpsys, "root_width"));
- CData->psys_tipradius.push_back_slow(radius * get_float(cpsys, "tip_width"));
- CData->psys_shape.push_back_slow(get_float(cpsys, "shape"));
- CData->psys_closetip.push_back_slow(get_boolean(cpsys, "use_closetip"));
-
- int pa_no = 0;
- if(!(b_part.child_type() == 0) && totchild != 0)
- pa_no = totparts;
-
- int num_add = (totparts+totchild - pa_no);
- CData->curve_firstkey.reserve(CData->curve_firstkey.size() + num_add);
- CData->curve_keynum.reserve(CData->curve_keynum.size() + num_add);
- CData->curve_length.reserve(CData->curve_length.size() + num_add);
- CData->curvekey_co.reserve(CData->curvekey_co.size() + num_add*ren_step);
- CData->curvekey_time.reserve(CData->curvekey_time.size() + num_add*ren_step);
-
- for(; pa_no < totparts+totchild; pa_no++) {
- int keynum = 0;
- CData->curve_firstkey.push_back_slow(keyno);
-
- float curve_length = 0.0f;
- float3 pcKey;
- for(int step_no = 0; step_no < ren_step; step_no++) {
- float nco[3];
- b_psys.co_hair(*b_ob, pa_no, step_no, nco);
- float3 cKey = make_float3(nco[0], nco[1], nco[2]);
- cKey = transform_point(&itfm, cKey);
- if(step_no > 0) {
- float step_length = len(cKey - pcKey);
- if(step_length == 0.0f)
- continue;
- curve_length += step_length;
- }
- CData->curvekey_co.push_back_slow(cKey);
- CData->curvekey_time.push_back_slow(curve_length);
- pcKey = cKey;
- keynum++;
- }
- keyno += keynum;
-
- CData->curve_keynum.push_back_slow(keynum);
- CData->curve_length.push_back_slow(curve_length);
- curvenum++;
- }
- }
- }
- }
-
- return true;
-}
-
-bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num)
-{
- if(!(mesh && b_mesh && b_ob && CData))
- return false;
-
- CData->curve_uv.clear();
-
- BL::Object::modifiers_iterator b_mod;
- for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
- if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
- BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
-
- if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
- int totparts = b_psys.particles.length();
- int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
- int totcurves = totchild;
-
- if(b_part.child_type() == 0 || totchild == 0)
- totcurves += totparts;
-
- if(totcurves == 0)
- continue;
-
- int pa_no = 0;
- if(!(b_part.child_type() == 0) && totchild != 0)
- pa_no = totparts;
-
- int num_add = (totparts+totchild - pa_no);
- CData->curve_uv.reserve(CData->curve_uv.size() + num_add);
-
- BL::ParticleSystem::particles_iterator b_pa;
- b_psys.particles.begin(b_pa);
- for(; pa_no < totparts+totchild; pa_no++) {
- /* Add UVs */
- BL::Mesh::tessface_uv_textures_iterator l;
- b_mesh->tessface_uv_textures.begin(l);
-
- float3 uv = make_float3(0.0f, 0.0f, 0.0f);
- if(b_mesh->tessface_uv_textures.length())
- b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
- CData->curve_uv.push_back_slow(uv);
-
- if(pa_no < totparts && b_pa != b_psys.particles.end())
- ++b_pa;
- }
- }
- }
- }
-
- return true;
-}
-
-bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num)
-{
- if(!(mesh && b_mesh && b_ob && CData))
- return false;
-
- CData->curve_vcol.clear();
-
- BL::Object::modifiers_iterator b_mod;
- for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
- if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
- BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
-
- if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
- int totparts = b_psys.particles.length();
- int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
- int totcurves = totchild;
-
- if(b_part.child_type() == 0 || totchild == 0)
- totcurves += totparts;
-
- if(totcurves == 0)
- continue;
-
- int pa_no = 0;
- if(!(b_part.child_type() == 0) && totchild != 0)
- pa_no = totparts;
-
- int num_add = (totparts+totchild - pa_no);
- CData->curve_vcol.reserve(CData->curve_vcol.size() + num_add);
-
- BL::ParticleSystem::particles_iterator b_pa;
- b_psys.particles.begin(b_pa);
- for(; pa_no < totparts+totchild; pa_no++) {
- /* Add vertex colors */
- BL::Mesh::tessface_vertex_colors_iterator l;
- b_mesh->tessface_vertex_colors.begin(l);
-
- float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
- if(b_mesh->tessface_vertex_colors.length())
- b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
- CData->curve_vcol.push_back_slow(vcol);
-
- if(pa_no < totparts && b_pa != b_psys.particles.end())
- ++b_pa;
- }
- }
- }
- }
-
- return true;
-}
-
-static void set_resolution(BL::Object *b_ob, BL::Scene *scene, bool render)
-{
- BL::Object::modifiers_iterator b_mod;
- for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
- if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && ((b_mod->show_viewport()) || (b_mod->show_render()))) {
- BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
- BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
- b_psys.set_resolution(*scene, *b_ob, (render)? 2: 1);
- }
- }
-}
-
void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
float3 RotCam, bool is_ortho)
{
}
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))
/* obtain general settings */
bool use_curves = scene->curve_system_manager->use_curves;
- if(!(use_curves && b_ob.mode() != b_ob.mode_PARTICLE_EDIT)) {
+ if(!use_curves) {
if(!motion)
mesh->compute_bounds();
return;
ParticleCurveData CData;
- if(!preview)
- set_resolution(&b_ob, &b_scene, true);
-
- ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, !preview);
-
/* add hair geometry to mesh */
if(primitive == CURVE_TRIANGLES) {
if(triangle_method == CURVE_CAMERA_TRIANGLES) {
if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
continue;
- ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, !preview, vcol_num);
-
if(primitive == CURVE_TRIANGLES) {
Attribute *attr_vcol = mesh->attributes.add(
ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
Attribute *attr_uv;
- ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, !preview, uv_num);
-
if(primitive == CURVE_TRIANGLES) {
if(active_render)
attr_uv = mesh->attributes.add(std, name);
}
}
- if(!preview)
- set_resolution(&b_ob, &b_scene, false);
-
mesh->compute_bounds();
}
bool parent_hide,
bool& hide_triangles)
{
- /* check if we should render or hide particle emitter */
- BL::Object::particle_systems_iterator b_psys;
-
- bool hair_present = false;
- bool show_emitter = false;
- bool hide_emitter = false;
bool hide_as_dupli_parent = false;
bool hide_as_dupli_child_original = false;
- 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))
- hair_present = true;
-
- if(b_psys->settings().use_render_emitter())
- show_emitter = true;
- else
- hide_emitter = true;
- }
-
- if(show_emitter)
- hide_emitter = false;
-
/* duplicators hidden by default, except dupliframes which duplicate self */
if(b_ob.is_duplicator())
if(top_level || b_ob.dupli_type() != BL::Object::dupli_type_FRAMES)
parent = parent.parent();
}
- hide_triangles = hide_emitter;
+ hide_triangles = false;
- if(show_emitter) {
- return false;
- }
- else if(hair_present) {
- return hide_as_dupli_child_original;
- }
- else {
- return (hide_as_dupli_parent || hide_as_dupli_child_original);
- }
+ return (hide_as_dupli_parent || hide_as_dupli_child_original);
}
static bool object_render_hide_duplis(BL::Object& b_ob)
light_map.pre_sync();
mesh_map.pre_sync();
object_map.pre_sync();
- particle_system_map.pre_sync();
motion_times.clear();
}
else {
BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup->persistent_id();
/* sync object and mesh or light data */
- Object *object = sync_object(b_ob,
- persistent_id.data,
- *b_dup,
- tfm,
- ob_layer,
- motion_time,
- hide_tris,
- use_camera_cull,
- camera_cull_margin,
- &use_portal);
-
- /* sync possible particle data, note particle_id
- * starts counting at 1, first is dummy particle */
- if(!motion && object) {
- sync_dupli_particle(b_ob, *b_dup, object);
- }
-
+ sync_object(b_ob,
+ persistent_id.data,
+ *b_dup,
+ tfm,
+ ob_layer,
+ motion_time,
+ hide_tris,
+ use_camera_cull,
+ camera_cull_margin,
+ &use_portal);
}
}
scene->mesh_manager->tag_update(scene);
if(object_map.post_sync())
scene->object_manager->tag_update(scene);
- if(particle_system_map.post_sync())
- scene->particle_system_manager->tag_update(scene);
}
if(motion)
+++ /dev/null
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "mesh.h"
-#include "object.h"
-#include "particles.h"
-
-#include "blender_sync.h"
-#include "blender_util.h"
-
-#include "util_foreach.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Utilities */
-
-bool BlenderSync::sync_dupli_particle(BL::Object& b_ob,
- BL::DupliObject& b_dup,
- Object *object)
-{
- /* test if this dupli was generated from a particle sytem */
- BL::ParticleSystem b_psys = b_dup.particle_system();
- if(!b_psys)
- return false;
-
- /* test if we need particle data */
- if(!object->mesh->need_attribute(scene, ATTR_STD_PARTICLE))
- return false;
-
- /* don't handle child particles yet */
- BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup.persistent_id();
-
- if(persistent_id[0] >= b_psys.particles.length())
- return false;
-
- /* find particle system */
- ParticleSystemKey key(b_ob, persistent_id);
- ParticleSystem *psys;
-
- bool first_use = !particle_system_map.is_used(key);
- bool need_update = particle_system_map.sync(&psys, b_ob, b_dup.object(), key);
-
- /* no update needed? */
- if(!need_update && !object->mesh->need_update && !scene->object_manager->need_update)
- return true;
-
- /* first time used in this sync loop? clear and tag update */
- if(first_use) {
- psys->particles.clear();
- psys->tag_update(scene);
- }
-
- /* add particle */
- BL::Particle b_pa = b_psys.particles[persistent_id[0]];
- Particle pa;
-
- pa.index = persistent_id[0];
- pa.age = b_scene.frame_current() - b_pa.birth_time();
- pa.lifetime = b_pa.lifetime();
- pa.location = get_float3(b_pa.location());
- pa.rotation = get_float4(b_pa.rotation());
- pa.size = b_pa.size();
- pa.velocity = get_float3(b_pa.velocity());
- pa.angular_velocity = get_float3(b_pa.angular_velocity());
-
- psys->particles.push_back_slow(pa);
-
- if(object->particle_index != psys->particles.size() - 1)
- scene->object_manager->tag_update(scene);
- object->particle_system = psys;
- object->particle_index = psys->particles.size() - 1;
-
- /* return that this object has particle data */
- return true;
-}
-
-CCL_NAMESPACE_END
object_map(&scene->objects),
mesh_map(&scene->meshes),
light_map(&scene->lights),
- particle_system_map(&scene->particle_systems),
world_map(NULL),
world_recalc(false),
scene(scene),
if(b_ob->is_updated_data() || b_ob->data().is_updated())
light_map.set_recalc(*b_ob);
}
-
- if(b_ob->is_updated_data()) {
- BL::Object::particle_systems_iterator b_psys;
- for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys)
- particle_system_map.set_recalc(*b_ob);
- }
}
bool dicing_prop_changed = false;
object_map.has_recalc() ||
light_map.has_recalc() ||
mesh_map.has_recalc() ||
- particle_system_map.has_recalc() ||
BlendDataObjects_is_updated_get(&b_data.ptr) ||
world_recalc;
int width, int height,
float motion_time);
- /* particles */
- bool sync_dupli_particle(BL::Object& b_ob,
- BL::DupliObject& b_dup,
- Object *object);
-
/* Images. */
void sync_images();
id_map<ObjectKey, Object> object_map;
id_map<void*, Mesh> mesh_map;
id_map<ObjectKey, Light> light_map;
- id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
set<Mesh*> mesh_synced;
set<Mesh*> mesh_motion_synced;
std::set<float> motion_times;
}
};
-/* Particle System Key */
-
-struct ParticleSystemKey {
- void *ob;
- int id[OBJECT_PERSISTENT_ID_SIZE];
-
- ParticleSystemKey(void *ob_, int id_[OBJECT_PERSISTENT_ID_SIZE])
- : ob(ob_)
- {
- if(id_)
- memcpy(id, id_, sizeof(id));
- else
- memset(id, 0, sizeof(id));
- }
-
- bool operator<(const ParticleSystemKey& k) const
- {
- /* first id is particle index, we don't compare that */
- if(ob < k.ob)
- return true;
- else if(ob == k.ob)
- return memcmp(id+1, k.id+1, sizeof(int)*(OBJECT_PERSISTENT_ID_SIZE-1)) < 0;
-
- return false;
- }
-};
-
CCL_NAMESPACE_END
#endif /* __BLENDER_UTIL_H__ */
#define OB_FLUIDSIM_OBSTACLE 8
#define OB_FLUIDSIM_INFLOW 16
#define OB_FLUIDSIM_OUTFLOW 32
-#define OB_FLUIDSIM_PARTICLE 64
+#define OB_FLUIDSIM_PARTICLE 64 /* DEPRECATED */
#define OB_FLUIDSIM_CONTROL 128
// defines for elbeemMesh->obstacleType below (low bits) high bits (>=64) are reserved for mFsSurfGenSetting flags which are defined in solver_class.h
+++ /dev/null
-import bpy
-psys = bpy.context.particle_system
-cloth = bpy.context.particle_system.cloth
-settings = bpy.context.particle_system.cloth.settings
-collision = bpy.context.particle_system.cloth.collision_settings
-
-settings.quality = 5
-settings.mass = 0.30000001192092896
-settings.bending_stiffness = 0.5
-psys.settings.bending_random = 0.0
-settings.bending_damping = 0.5
-settings.air_damping = 1.0
-settings.internal_friction = 0.0
-settings.density_target = 0.0
-settings.density_strength = 0.0
-settings.voxel_cell_size = 0.10000000149011612
-settings.pin_stiffness = 0.0
return mat
-class QuickFur(Operator):
- bl_idname = "object.quick_fur"
- bl_label = "Quick Fur"
- bl_options = {'REGISTER', 'UNDO'}
-
- density = EnumProperty(
- name="Fur Density",
- items=(('LIGHT', "Light", ""),
- ('MEDIUM', "Medium", ""),
- ('HEAVY', "Heavy", "")),
- default='MEDIUM',
- )
- view_percentage = IntProperty(
- name="View %",
- min=1, max=100,
- soft_min=1, soft_max=100,
- default=10,
- )
- length = FloatProperty(
- name="Length",
- min=0.001, max=100,
- soft_min=0.01, soft_max=10,
- default=0.1,
- )
-
- def execute(self, context):
- fake_context = context.copy()
- mesh_objects = [obj for obj in context.selected_objects
- if obj.type == 'MESH' and obj.mode == 'OBJECT']
-
- if not mesh_objects:
- self.report({'ERROR'}, "Select at least one mesh object")
- return {'CANCELLED'}
-
- mat = bpy.data.materials.new("Fur Material")
- mat.strand.tip_size = 0.25
- mat.strand.blend_distance = 0.5
-
- for obj in mesh_objects:
- fake_context["object"] = obj
- bpy.ops.object.particle_system_add(fake_context)
-
- psys = obj.particle_systems[-1]
- psys.settings.type = 'HAIR'
-
- if self.density == 'LIGHT':
- psys.settings.count = 100
- elif self.density == 'MEDIUM':
- psys.settings.count = 1000
- elif self.density == 'HEAVY':
- psys.settings.count = 10000
-
- psys.settings.child_nbr = self.view_percentage
- psys.settings.hair_length = self.length
- psys.settings.use_strand_primitive = True
- psys.settings.use_hair_bspline = True
- psys.settings.child_type = 'INTERPOLATED'
-
- obj.data.materials.append(mat)
- psys.settings.material = len(obj.data.materials)
-
- return {'FINISHED'}
-
-
-class QuickExplode(Operator):
- bl_idname = "object.quick_explode"
- bl_label = "Quick Explode"
- bl_options = {'REGISTER', 'UNDO'}
-
- style = EnumProperty(
- name="Explode Style",
- items=(('EXPLODE', "Explode", ""),
- ('BLEND', "Blend", "")),
- default='EXPLODE',
- )
- amount = IntProperty(
- name="Amount of pieces",
- min=2, max=10000,
- soft_min=2, soft_max=10000,
- default=100,
- )
- frame_duration = IntProperty(
- name="Duration",
- min=1, max=300000,
- soft_min=1, soft_max=10000,
- default=50,
- )
-
- frame_start = IntProperty(
- name="Start Frame",
- min=1, max=300000,
- soft_min=1, soft_max=10000,
- default=1,
- )
- frame_end = IntProperty(
- name="End Frame",
- min=1, max=300000,
- soft_min=1, soft_max=10000,
- default=10,
- )
-
- velocity = FloatProperty(
- name="Outwards Velocity",
- min=0, max=300000,
- soft_min=0, soft_max=10,
- default=1,
- )
-
- fade = BoolProperty(
- name="Fade",
- description="Fade the pieces over time",
- default=True,
- )
-
- def execute(self, context):
- fake_context = context.copy()
- obj_act = context.active_object
-
- if obj_act is None or obj_act.type != 'MESH':
- self.report({'ERROR'}, "Active object is not a mesh")
- return {'CANCELLED'}
-
- mesh_objects = [obj for obj in context.selected_objects
- if obj.type == 'MESH' and obj != obj_act]
- mesh_objects.insert(0, obj_act)
-
- if self.style == 'BLEND' and len(mesh_objects) != 2:
- self.report({'ERROR'}, "Select two mesh objects")
- self.style = 'EXPLODE'
- return {'CANCELLED'}
- elif not mesh_objects:
- self.report({'ERROR'}, "Select at least one mesh object")
- return {'CANCELLED'}
-
- for obj in mesh_objects:
- if obj.particle_systems:
- self.report({'ERROR'},
- "Object %r already has a "
- "particle system" % obj.name)
-
- return {'CANCELLED'}
-
- if self.fade:
- tex = bpy.data.textures.new("Explode fade", 'BLEND')
- tex.use_color_ramp = True
-
- if self.style == 'BLEND':
- tex.color_ramp.elements[0].position = 0.333
- tex.color_ramp.elements[1].position = 0.666
-
- tex.color_ramp.elements[0].color[3] = 1.0
- tex.color_ramp.elements[1].color[3] = 0.0
-
- if self.style == 'BLEND':
- from_obj = mesh_objects[1]
- to_obj = mesh_objects[0]
-
- for obj in mesh_objects:
- fake_context["object"] = obj
- bpy.ops.object.particle_system_add(fake_context)
-
- settings = obj.particle_systems[-1].settings
- settings.count = self.amount
- settings.frame_start = self.frame_start
- settings.frame_end = self.frame_end - self.frame_duration
- settings.lifetime = self.frame_duration
- settings.normal_factor = self.velocity
- settings.render_type = 'NONE'
-
- explode = obj.modifiers.new(name='Explode', type='EXPLODE')
- explode.use_edge_cut = True
-
- if self.fade:
- explode.show_dead = False
- uv = obj.data.uv_textures.new("Explode fade")
- explode.particle_uv = uv.name
-
- mat = object_ensure_material(obj, "Explode Fade")
-
- mat.use_transparency = True
- mat.use_transparent_shadows = True
- mat.alpha = 0.0
- mat.specular_alpha = 0.0
-
- tex_slot = mat.texture_slots.add()
-
- tex_slot.texture = tex
- tex_slot.texture_coords = 'UV'
- tex_slot.uv_layer = uv.name
-
- tex_slot.use_map_alpha = True
-
- if self.style == 'BLEND':
- if obj == to_obj:
- tex_slot.alpha_factor = -1.0
- elem = tex.color_ramp.elements[1]
- else:
- elem = tex.color_ramp.elements[0]
- # Keep already defined alpha!
- elem.color[:3] = mat.diffuse_color
- else:
- tex_slot.use_map_color_diffuse = False
-
- if self.style == 'BLEND':
- settings.physics_type = 'KEYED'
- settings.use_emit_random = False
- settings.rotation_mode = 'NOR'
-
- psys = obj.particle_systems[-1]
-
- fake_context["particle_system"] = obj.particle_systems[-1]
- bpy.ops.particle.new_target(fake_context)
- bpy.ops.particle.new_target(fake_context)
-
- if obj == from_obj:
- psys.targets[1].object = to_obj
- else:
- psys.targets[0].object = from_obj
- settings.normal_factor = -self.velocity
- explode.show_unborn = False
- explode.show_dead = True
- else:
- settings.factor_random = self.velocity
- settings.angular_velocity_factor = self.velocity / 10.0
-
- return {'FINISHED'}
-
- def invoke(self, context, event):
- self.frame_start = context.scene.frame_current
- self.frame_end = self.frame_start + self.frame_duration
- return self.execute(context)
-
-
def obj_bb_minmax(obj, min_co, max_co):
for i in range(0, 8):
bb_vec = obj.matrix_world * Vector(obj.bound_box[i])
preset_subdir = "fluid"
-class AddPresetHairDynamics(AddPresetBase, Operator):
- """Add or remove a Hair Dynamics Preset"""
- bl_idname = "particle.hair_dynamics_preset_add"
- bl_label = "Add Hair Dynamics Preset"
- preset_menu = "PARTICLE_MT_hair_dynamics_presets"
-
- preset_defines = [
- "psys = bpy.context.particle_system",
- "cloth = bpy.context.particle_system.cloth",
- "settings = bpy.context.particle_system.cloth.settings",
- "collision = bpy.context.particle_system.cloth.collision_settings",
- ]
-
- preset_subdir = "hair_dynamics"
-
- preset_values = [
- "settings.quality",
- "settings.mass",
- "settings.bending_stiffness",
- "psys.settings.bending_random",
- "settings.bending_damping",
- "settings.air_damping",
- "settings.internal_friction",
- "settings.density_target",
- "settings.density_strength",
- "settings.voxel_cell_size",
- "settings.pin_stiffness",
- ]
-
-
class AddPresetSunSky(AddPresetBase, Operator):
"""Add or remove a Sky & Atmosphere Preset"""
bl_idname = "lamp.sunsky_preset_add"
bpy.ops.armature.select_all(action='DESELECT')
elif active_object.mode == 'POSE':
bpy.ops.pose.select_all(action='DESELECT')
- elif active_object.mode == 'PARTICLE_EDIT':
- bpy.ops.particle.select_all(action='DESELECT')
else:
bpy.ops.object.select_all(action='DESELECT')
else:
"properties_object",
"properties_paint_common",
"properties_grease_pencil_common",
- "properties_particle",
"properties_physics_cloth",
"properties_physics_common",
"properties_physics_dynamicpaint",
col = split.column()
- def PARTICLE_INSTANCE(self, layout, ob, md):
- layout.prop(md, "object")
- layout.prop(md, "particle_system_index", text="Particle System")
-
- split = layout.split()
- col = split.column()
- col.label(text="Create From:")
- col.prop(md, "use_normal")
- col.prop(md, "use_children")
- col.prop(md, "use_size")
-
- col = split.column()
- col.label(text="Show Particles When:")
- col.prop(md, "show_alive")
- col.prop(md, "show_unborn")
- col.prop(md, "show_dead")
-
- layout.separator()
-
- layout.prop(md, "use_path", text="Create Along Paths")
-
- split = layout.split()
- split.active = md.use_path
- col = split.column()
- col.row().prop(md, "axis", expand=True)
- col.prop(md, "use_preserve_shape")
-
- col = split.column()
- col.prop(md, "position", slider=True)
- col.prop(md, "random_position", text="Random", slider=True)
-
- def PARTICLE_SYSTEM(self, layout, ob, md):
- layout.label(text="Settings can be found inside the Particle context")
-
def SCREW(self, layout, ob, md):
split = layout.split()
return toolsettings.image_paint
return None
- elif context.particle_edit_object:
- return toolsettings.particle_edit
return None
+++ /dev/null
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8 compliant>
-import bpy
-from bpy.types import Panel, Menu
-from rna_prop_ui import PropertyPanel
-from bpy.app.translations import pgettext_iface as iface_
-
-from bl_ui.properties_physics_common import (
- point_cache_ui,
- effector_weights_ui,
- basic_force_field_settings_ui,
- basic_force_field_falloff_ui,
- )
-
-
-def particle_panel_enabled(context, psys):
- if psys is None:
- return True
- phystype = psys.settings.physics_type
- if psys.settings.type in {'EMITTER', 'REACTOR'} and phystype in {'NO', 'KEYED'}:
- return True
- else:
- return (psys.point_cache.is_baked is False) and (not psys.is_edited) and (not context.particle_system_editable)
-
-
-def particle_panel_poll(cls, context):
- psys = context.particle_system
- engine = context.scene.render.engine
- settings = 0
-
- if psys:
- settings = psys.settings
- elif isinstance(context.space_data.pin_id, bpy.types.ParticleSettings):
- settings = context.space_data.pin_id
-
- if not settings:
- return False
-
- return settings.is_fluid is False and (engine in cls.COMPAT_ENGINES)
-
-
-def particle_get_settings(context):
- if context.particle_system:
- return context.particle_system.settings
- elif isinstance(context.space_data.pin_id, bpy.types.ParticleSettings):
- return context.space_data.pin_id
- return None
-
-
-class PARTICLE_MT_specials(Menu):
- bl_label = "Particle Specials"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- def draw(self, context):
- layout = self.layout
-
- props = layout.operator("particle.copy_particle_systems", text="Copy Active to Selected Objects")
- props.use_active = True
- props.remove_target_particles = False
-
- props = layout.operator("particle.copy_particle_systems", text="Copy All to Selected Objects")
- props.use_active = False
- props.remove_target_particles = True
-
-
-class PARTICLE_MT_hair_dynamics_presets(Menu):
- bl_label = "Hair Dynamics Presets"
- preset_subdir = "hair_dynamics"
- preset_operator = "script.execute_preset"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
- draw = Menu.draw_preset
-
-
-class ParticleButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "particle"
-
- @classmethod
- def poll(cls, context):
- return particle_panel_poll(cls, context)
-
-
-def find_modifier(ob, psys):
- for md in ob.modifiers:
- if md.type == 'PARTICLE_SYSTEM':
- if md.particle_system == psys:
- return md
-
-
-class PARTICLE_UL_particle_systems(bpy.types.UIList):
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index, flt_flag):
- ob = data
- psys = item
-
- if self.layout_type in {'DEFAULT', 'COMPACT'}:
- md = find_modifier(ob, psys)
-
- layout.prop(psys, "name", text="", emboss=False, icon_value=icon)
- if md:
- layout.prop(md, "show_render", emboss=False, icon_only=True, icon='RESTRICT_RENDER_OFF' if md.show_render else 'RESTRICT_RENDER_ON')
- layout.prop(md, "show_viewport", emboss=False, icon_only=True, icon='RESTRICT_VIEW_OFF' if md.show_viewport else 'RESTRICT_VIEW_ON')
-
- elif self.layout_type == 'GRID':
- layout.alignment = 'CENTER'
- layout.label(text="", icon_value=icon)
-
-
-class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel):
- bl_label = ""
- bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- engine = context.scene.render.engine
- return (context.particle_system or context.object or context.space_data.pin_id) and (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- if context.scene.render.engine == 'BLENDER_GAME':
- layout.label("Not available in the Game Engine")
- return
-
- ob = context.object
- psys = context.particle_system
- part = 0
-
- if ob:
- row = layout.row()
-
- row.template_list("PARTICLE_UL_particle_systems", "particle_systems", ob, "particle_systems",
- ob.particle_systems, "active_index", rows=1)
-
- col = row.column(align=True)
- col.operator("object.particle_system_add", icon='ZOOMIN', text="")
- col.operator("object.particle_system_remove", icon='ZOOMOUT', text="")
- col.menu("PARTICLE_MT_specials", icon='DOWNARROW_HLT', text="")
-
- if psys is None:
- part = particle_get_settings(context)
-
- layout.operator("object.particle_system_add", icon='ZOOMIN', text="New")
-
- if part is None:
- return
-
- layout.template_ID(context.space_data, "pin_id")
-
- if part.is_fluid:
- layout.label(text="Settings used for fluid")
- return
-
- layout.prop(part, "type", text="Type")
-
- elif not psys.settings:
- split = layout.split(percentage=0.32)
-
- col = split.column()
- col.label(text="Settings:")
-
- col = split.column()
- col.template_ID(psys, "settings", new="particle.new")
- else:
- part = psys.settings
-
- split = layout.split(percentage=0.32)
- col = split.column()
- if part.is_fluid is False:
- col.label(text="Settings:")
- col.label(text="Type:")
-
- col = split.column()
- if part.is_fluid is False:
- row = col.row()
- row.enabled = particle_panel_enabled(context, psys)
- row.template_ID(psys, "settings", new="particle.new")
-
- if part.is_fluid:
- layout.label(text=iface_("%d fluid particles for this frame") % part.count, translate=False)
- return
-
- row = col.row()
- row.enabled = particle_panel_enabled(context, psys)
- row.prop(part, "type", text="")
- row.prop(psys, "seed")
-
- if part:
- split = layout.split(percentage=0.65)
- if part.type == 'HAIR':
- if psys is not None and psys.is_edited:
- split.operator("particle.edited_clear", text="Free Edit")
- else:
- row = split.row()
- row.enabled = particle_panel_enabled(context, psys)
- row.prop(part, "regrow_hair")
- row.prop(part, "use_advanced_hair")
- row = split.row()
- row.enabled = particle_panel_enabled(context, psys)
- row.prop(part, "hair_step")
- if psys is not None and psys.is_edited:
- if psys.is_global_hair:
- row = layout.row(align=True)
- row.operator("particle.connect_hair").all = False
- row.operator("particle.connect_hair", text="Connect All").all = True
- else:
- row = layout.row(align=True)
- row.operator("particle.disconnect_hair").all = False
- row.operator("particle.disconnect_hair", text="Disconnect All").all = True
- elif psys is not None and part.type == 'REACTOR':
- split.enabled = particle_panel_enabled(context, psys)
- split.prop(psys, "reactor_target_object")
- split.prop(psys, "reactor_target_particle_system", text="Particle System")
-
-
-class PARTICLE_PT_emission(ParticleButtonsPanel, Panel):
- bl_label = "Emission"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- psys = context.particle_system
- settings = particle_get_settings(context)
-
- if settings is None:
- return False
- if settings.is_fluid:
- return False
- if particle_panel_poll(PARTICLE_PT_emission, context):
- return psys is None or not context.particle_system.point_cache.use_external
- return False
-
- def draw(self, context):
- layout = self.layout
-
- psys = context.particle_system
- part = particle_get_settings(context)
-
- layout.enabled = particle_panel_enabled(context, psys) and (psys is None or not psys.has_multiple_caches)
-
- row = layout.row()
- row.active = part.emit_from == 'VERT' or part.distribution != 'GRID'
- row.prop(part, "count")
-
- if part.type == 'HAIR':
- row.prop(part, "hair_length")
- if not part.use_advanced_hair:
- row = layout.row()
- row.prop(part, "use_modifier_stack")
- return
-
- if part.type != 'HAIR':
- split = layout.split()
-
- col = split.column(align=True)
- col.prop(part, "frame_start")
- col.prop(part, "frame_end")
-
- col = split.column(align=True)
- col.prop(part, "lifetime")
- col.prop(part, "lifetime_random", slider=True)
-
- layout.label(text="Emit From:")
- layout.prop(part, "emit_from", expand=True)
-
- row = layout.row()
- if part.emit_from == 'VERT':
- row.prop(part, "use_emit_random")
- elif part.distribution == 'GRID':
- row.prop(part, "invert_grid")
- row.prop(part, "hexagonal_grid")
- else:
- row.prop(part, "use_emit_random")
- row.prop(part, "use_even_distribution")
-
- if part.emit_from == 'FACE' or part.emit_from == 'VOLUME':
- layout.prop(part, "distribution", expand=True)
-
- row = layout.row()
- if part.distribution == 'JIT':
- row.prop(part, "userjit", text="Particles/Face")
- row.prop(part, "jitter_factor", text="Jittering Amount", slider=True)
- elif part.distribution == 'GRID':
- row.prop(part, "grid_resolution")
- row.prop(part, "grid_random", text="Random", slider=True)
-
- row = layout.row()
- row.prop(part, "use_modifier_stack")
-
-
-class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, Panel):
- bl_label = "Hair dynamics"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- psys = context.particle_system
- engine = context.scene.render.engine
- if psys is None:
- return False
- if psys.settings is None:
- return False
- return psys.settings.type == 'HAIR' and (engine in cls.COMPAT_ENGINES)
-
- def draw_header(self, context):
- psys = context.particle_system
- self.layout.prop(psys, "use_hair_dynamics", text="")
-
- def draw(self, context):
- layout = self.layout
-
- psys = context.particle_system
-
- if not psys.cloth:
- return
-
- cloth_md = psys.cloth
- cloth = cloth_md.settings
- result = cloth_md.solver_result
-
- layout.enabled = psys.use_hair_dynamics and psys.point_cache.is_baked is False
-
- row = layout.row(align=True)
- row.menu("PARTICLE_MT_hair_dynamics_presets", text=bpy.types.PARTICLE_MT_hair_dynamics_presets.bl_label)
- row.operator("particle.hair_dynamics_preset_add", text="", icon='ZOOMIN')
- row.operator("particle.hair_dynamics_preset_add", text="", icon='ZOOMOUT').remove_active = True
-
- split = layout.column()
-
- col = split.column()
- col.label(text="Structure")
- col.prop(cloth, "mass")
- sub = col.column(align=True)
- subsub = sub.row(align=True)
- subsub.prop(cloth, "bending_stiffness", text="Stiffness")
- subsub.prop(psys.settings, "bending_random", text="Random")
- sub.prop(cloth, "bending_damping", text="Damping")
- # XXX has no noticeable effect with stiff hair structure springs
- #col.prop(cloth, "spring_damping", text="Damping")
-
- split.separator()
-
- col = split.column()
- col.label(text="Volume")
- col.prop(cloth, "air_damping", text="Air Drag")
- col.prop(cloth, "internal_friction", slider=True)
- sub = col.column(align=True)
- sub.prop(cloth, "density_target", text="Density Target")
- sub.prop(cloth, "density_strength", slider=True, text="Strength")
- col.prop(cloth, "voxel_cell_size")
-
- split.separator()
-
- col = split.column()
- col.label(text="Pinning")
- col.prop(cloth, "pin_stiffness", text="Goal Strength")
-
- split.separator()
-
- col = split.column()
- col.label(text="Quality:")
- col.prop(cloth, "quality", text="Steps", slider=True)
-
- row = col.row()
- row.prop(psys.settings, "show_hair_grid", text="HairGrid")
-
- if result:
- box = layout.box()
-
- if not result.status:
- label = " "
- icon = 'NONE'
- elif result.status == {'SUCCESS'}:
- label = "Success"
- icon = 'NONE'
- elif result.status - {'SUCCESS'} == {'NO_CONVERGENCE'}:
- label = "No Convergence"
- icon = 'ERROR'
- else:
- label = "ERROR"
- icon = 'ERROR'
- box.label(label, icon=icon)
- box.label("Iterations: %d .. %d (avg. %d)" % (result.min_iterations, result.max_iterations, result.avg_iterations))
- box.label("Error: %.5f .. %.5f (avg. %.5f)" % (result.min_error, result.max_error, result.avg_error))
-
-
-class PARTICLE_PT_cache(ParticleButtonsPanel, Panel):
- bl_label = "Cache"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- psys = context.particle_system
- engine = context.scene.render.engine
- if psys is None:
- return False
- if psys.settings is None:
- return False
- if psys.settings.is_fluid:
- return False
- phystype = psys.settings.physics_type
- if phystype == 'NO' or phystype == 'KEYED':
- return False
- return (psys.settings.type in {'EMITTER', 'REACTOR'} or (psys.settings.type == 'HAIR' and (psys.use_hair_dynamics or psys.point_cache.is_baked))) and engine in cls.COMPAT_ENGINES
-
- def draw(self, context):
- psys = context.particle_system
-
- point_cache_ui(self, context, psys.point_cache, True, 'HAIR' if (psys.settings.type == 'HAIR') else 'PSYS')
-
-
-class PARTICLE_PT_velocity(ParticleButtonsPanel, Panel):
- bl_label = "Velocity"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- if particle_panel_poll(PARTICLE_PT_velocity, context):
- psys = context.particle_system
- settings = particle_get_settings(context)
-
- if settings.type == 'HAIR' and not settings.use_advanced_hair:
- return False
- return settings.physics_type != 'BOIDS' and (psys is None or not psys.point_cache.use_external)
- else:
- return False
-
- def draw(self, context):
- layout = self.layout
-
- psys = context.particle_system
- part = particle_get_settings(context)
-
- layout.enabled = particle_panel_enabled(context, psys)
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Emitter Geometry:")
- col.prop(part, "normal_factor")
- sub = col.column(align=True)
- sub.prop(part, "tangent_factor")
- sub.prop(part, "tangent_phase", slider=True)
-
- col = split.column()
- col.label(text="Emitter Object:")
- col.prop(part, "object_align_factor", text="")
-
- layout.label(text="Other:")
- row = layout.row()
- if part.emit_from == 'PARTICLE':
- row.prop(part, "particle_factor")
- else:
- row.prop(part, "object_factor", slider=True)
- row.prop(part, "factor_random")
-
- #if part.type=='REACTOR':
- # sub.prop(part, "reactor_factor")
- # sub.prop(part, "reaction_shape", slider=True)
-
-
-class PARTICLE_PT_rotation(ParticleButtonsPanel, Panel):
- bl_label = "Rotation"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- if particle_panel_poll(PARTICLE_PT_rotation, context):
- psys = context.particle_system
- settings = particle_get_settings(context)
-
- if settings.type == 'HAIR' and not settings.use_advanced_hair:
- return False
- return settings.physics_type != 'BOIDS' and (psys is None or not psys.point_cache.use_external)
- else:
- return False
-
- def draw_header(self, context):
- psys = context.particle_system
- if psys:
- part = psys.settings
- else:
- part = context.space_data.pin_id
-
- self.layout.prop(part, "use_rotations", text="")
-
- def draw(self, context):
- layout = self.layout
-
- psys = context.particle_system
- if psys:
- part = psys.settings
- else:
- part = context.space_data.pin_id
-
- layout.enabled = particle_panel_enabled(context, psys) and part.use_rotations
-
- layout.label(text="Initial Orientation:")
-
- split = layout.split()
-
- col = split.column(align=True)
- col.prop(part, "rotation_mode", text="")
- col.prop(part, "rotation_factor_random", slider=True, text="Random")
-
- col = split.column(align=True)
- col.prop(part, "phase_factor", slider=True)
- col.prop(part, "phase_factor_random", text="Random", slider=True)
-
- if part.type != 'HAIR':
- layout.label(text="Angular Velocity:")
-
- split = layout.split()
-
- col = split.column(align=True)
- col.prop(part, "angular_velocity_mode", text="")
- sub = col.column(align=True)
- sub.active = part.angular_velocity_mode != 'NONE'
- sub.prop(part, "angular_velocity_factor", text="")
-
- col = split.column()
- col.prop(part, "use_dynamic_rotation")
-
-
-class PARTICLE_PT_physics(ParticleButtonsPanel, Panel):
- bl_label = "Physics"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- if particle_panel_poll(PARTICLE_PT_physics, context):
- psys = context.particle_system
- settings = particle_get_settings(context)
-
- if settings.type == 'HAIR' and not settings.use_advanced_hair:
- return False
- return psys is None or not psys.point_cache.use_external
- else:
- return False
-
- def draw(self, context):
- layout = self.layout
-
- psys = context.particle_system
- part = particle_get_settings(context)
-
- layout.enabled = particle_panel_enabled(context, psys)
-
- layout.prop(part, "physics_type", expand=True)
-
- row = layout.row()
- col = row.column(align=True)
- col.prop(part, "particle_size")
- col.prop(part, "size_random", slider=True)
-
- if part.physics_type != 'NO':
- col = row.column(align=True)
- col.prop(part, "mass")
- col.prop(part, "use_multiply_size_mass", text="Multiply mass with size")
-
- if part.physics_type in {'NEWTON', 'FLUID'}:
- split = layout.split()
-
- col = split.column()
- col.label(text="Forces:")
- col.prop(part, "brownian_factor")
- col.prop(part, "drag_factor", slider=True)
- col.prop(part, "damping", slider=True)
-
- col = split.column()
- col.label(text="Integration:")
- col.prop(part, "integrator", text="")
- col.prop(part, "timestep")
- sub = col.row()
- sub.prop(part, "subframes")
- supports_courant = part.physics_type == 'FLUID'
- subsub = sub.row()
- subsub.enabled = supports_courant
- subsub.prop(part, "use_adaptive_subframes", text="")
- if supports_courant and part.use_adaptive_subframes:
- col.prop(part, "courant_target", text="Threshold")
-
- row = layout.row()
- row.prop(part, "use_size_deflect")
- row.prop(part, "use_die_on_collision")
-
- if part.physics_type == 'FLUID':
- fluid = part.fluid
-
- split = layout.split()
- sub = split.row()
- sub.prop(fluid, "solver", expand=True)
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Fluid properties:")
- col.prop(fluid, "stiffness", text="Stiffness")
- col.prop(fluid, "linear_viscosity", text="Viscosity")
- col.prop(fluid, "buoyancy", text="Buoyancy", slider=True)
-
- col = split.column()
- col.label(text="Advanced:")
-
- if fluid.solver == 'DDR':
- sub = col.row()
- sub.prop(fluid, "repulsion", slider=fluid.factor_repulsion)
- sub.prop(fluid, "factor_repulsion", text="")
-
- sub = col.row()
- sub.prop(fluid, "stiff_viscosity", slider=fluid.factor_stiff_viscosity)
- sub.prop(fluid, "factor_stiff_viscosity", text="")
-
- sub = col.row()
- sub.prop(fluid, "fluid_radius", slider=fluid.factor_radius)
- sub.prop(fluid, "factor_radius", text="")
-
- sub = col.row()
- sub.prop(fluid, "rest_density", slider=fluid.use_factor_density)
- sub.prop(fluid, "use_factor_density", text="")
-
- if fluid.solver == 'CLASSICAL':
- # With the classical solver, it is possible to calculate the
- # spacing between particles when the fluid is at rest. This
- # makes it easier to set stable initial conditions.
- particle_volume = part.mass / fluid.rest_density
- spacing = pow(particle_volume, 1.0 / 3.0)
- sub = col.row()
- sub.label(text="Spacing: %g" % spacing)
-
- elif fluid.solver == 'DDR':
- split = layout.split()
-
- col = split.column()
- col.label(text="Springs:")
- col.prop(fluid, "spring_force", text="Force")
- col.prop(fluid, "use_viscoelastic_springs")
- sub = col.column(align=True)
- sub.active = fluid.use_viscoelastic_springs
- sub.prop(fluid, "yield_ratio", slider=True)
- sub.prop(fluid, "plasticity", slider=True)
-
- col = split.column()
- col.label(text="Advanced:")
- sub = col.row()
- sub.prop(fluid, "rest_length", slider=fluid.factor_rest_length)
- sub.prop(fluid, "factor_rest_length", text="")
- col.label(text="")
- sub = col.column()
- sub.active = fluid.use_viscoelastic_springs
- sub.prop(fluid, "use_initial_rest_length")
- sub.prop(fluid, "spring_frames", text="Frames")
-
- elif part.physics_type == 'KEYED':
- split = layout.split()
- sub = split.column()
-
- row = layout.row()
- col = row.column()
- col.active = not psys.use_keyed_timing
- col.prop(part, "keyed_loops", text="Loops")
- if psys:
- row.prop(psys, "use_keyed_timing", text="Use Timing")
-
- layout.label(text="Keys:")
- elif part.physics_type == 'BOIDS':
- boids = part.boids
-
- row = layout.row()
- row.prop(boids, "use_flight")
- row.prop(boids, "use_land")
- row.prop(boids, "use_climb")
-
- split = layout.split()
-
- col = split.column(align=True)
- col.active = boids.use_flight
- col.prop(boids, "air_speed_max")
- col.prop(boids, "air_speed_min", slider=True)
- col.prop(boids, "air_acc_max", slider=True)
- col.prop(boids, "air_ave_max", slider=True)
- col.prop(boids, "air_personal_space")
- row = col.row(align=True)
- row.active = (boids.use_land or boids.use_climb) and boids.use_flight
- row.prop(boids, "land_smooth")
-
- col = split.column(align=True)
- col.active = boids.use_land or boids.use_climb
- col.prop(boids, "land_speed_max")
- col.prop(boids, "land_jump_speed")
- col.prop(boids, "land_acc_max", slider=True)
- col.prop(boids, "land_ave_max", slider=True)
- col.prop(boids, "land_personal_space")
- col.prop(boids, "land_stick_force")
-
- split = layout.split()
-
- col = split.column(align=True)
- col.label(text="Battle:")
- col.prop(boids, "health")
- col.prop(boids, "strength")
- col.prop(boids, "aggression")
- col.prop(boids, "accuracy")
- col.prop(boids, "range")
-
- col = split.column()
- col.label(text="Misc:")
- col.prop(boids, "bank", slider=True)
- col.prop(boids, "pitch", slider=True)
- col.prop(boids, "height", slider=True)
-
- if psys and part.physics_type in {'KEYED', 'BOIDS', 'FLUID'}:
- if part.physics_type == 'BOIDS':
- layout.label(text="Relations:")
- elif part.physics_type == 'FLUID':
- layout.label(text="Fluid interaction:")
-
- row = layout.row()
- row.template_list("UI_UL_list", "particle_targets", psys, "targets", psys, "active_particle_target_index", rows=4)
-
- col = row.column()
- sub = col.row()
- subsub = sub.column(align=True)
- subsub.operator("particle.new_target", icon='ZOOMIN', text="")
- subsub.operator("particle.target_remove", icon='ZOOMOUT', text="")
- sub = col.row()
- subsub = sub.column(align=True)
- subsub.operator("particle.target_move_up", icon='MOVE_UP_VEC', text="")
- subsub.operator("particle.target_move_down", icon='MOVE_DOWN_VEC', text="")
-
- key = psys.active_particle_target
- if key:
- row = layout.row()
- if part.physics_type == 'KEYED':
- col = row.column()
- #doesn't work yet
- #col.alert = key.valid
- col.prop(key, "object", text="")
- col.prop(key, "system", text="System")
- col = row.column()
- col.active = psys.use_keyed_timing
- col.prop(key, "time")
- col.prop(key, "duration")
- elif part.physics_type == 'BOIDS':
- sub = row.row()
- #doesn't work yet
- #sub.alert = key.valid
- sub.prop(key, "object", text="")
- sub.prop(key, "system", text="System")
-
- layout.prop(key, "alliance", expand=True)
- elif part.physics_type == 'FLUID':
- sub = row.row()
- #doesn't work yet
- #sub.alert = key.valid
- sub.prop(key, "object", text="")
- sub.prop(key, "system", text="System")
-
-
-class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel):
- bl_label = "Boid Brain"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- psys = context.particle_system
- settings = particle_get_settings(context)
- engine = context.scene.render.engine
-
- if settings is None:
- return False
- if psys is not None and psys.point_cache.use_external:
- return False
- return settings.physics_type == 'BOIDS' and engine in cls.COMPAT_ENGINES
-
- def draw(self, context):
- layout = self.layout
-
- boids = particle_get_settings(context).boids
-
- layout.enabled = particle_panel_enabled(context, context.particle_system)
-
- # Currently boids can only use the first state so these are commented out for now.
- #row = layout.row()
- #row.template_list("UI_UL_list", "particle_boids", boids, "states",
- # boids, "active_boid_state_index", compact="True")
- #col = row.row()
- #sub = col.row(align=True)
- #sub.operator("boid.state_add", icon='ZOOMIN', text="")
- #sub.operator("boid.state_del", icon='ZOOMOUT', text="")
- #sub = row.row(align=True)
- #sub.operator("boid.state_move_up", icon='MOVE_UP_VEC', text="")
- #sub.operator("boid.state_move_down", icon='MOVE_DOWN_VEC', text="")
-
- state = boids.active_boid_state
-
- #layout.prop(state, "name", text="State name")
-
- row = layout.row()
- row.prop(state, "ruleset_type")
- if state.ruleset_type == 'FUZZY':
- row.prop(state, "rule_fuzzy", slider=True)
- else:
- row.label(text="")
-
- row = layout.row()
- row.template_list("UI_UL_list", "particle_boids_rules", state, "rules", state, "active_boid_rule_index", rows=4)
-
- col = row.column()
- sub = col.row()
- subsub = sub.column(align=True)
- subsub.operator_menu_enum("boid.rule_add", "type", icon='ZOOMIN', text="")
- subsub.operator("boid.rule_del", icon='ZOOMOUT', text="")
- sub = col.row()
- subsub = sub.column(align=True)
- subsub.operator("boid.rule_move_up", icon='MOVE_UP_VEC', text="")
- subsub.operator("boid.rule_move_down", icon='MOVE_DOWN_VEC', text="")
-
- rule = state.active_boid_rule
-
- if rule:
- row = layout.row()
- row.prop(rule, "name", text="")
- #somebody make nice icons for boids here please! -jahka
- row.prop(rule, "use_in_air", icon='MOVE_UP_VEC', text="")
- row.prop(rule, "use_on_land", icon='MOVE_DOWN_VEC', text="")
-
- row = layout.row()
-
- if rule.type == 'GOAL':
- row.prop(rule, "object")
- row = layout.row()
- row.prop(rule, "use_predict")
- elif rule.type == 'AVOID':
- row.prop(rule, "object")
- row = layout.row()
- row.prop(rule, "use_predict")
- row.prop(rule, "fear_factor")
- elif rule.type == 'FOLLOW_PATH':
- row.label(text="Not yet functional")
- elif rule.type == 'AVOID_COLLISION':
- row.prop(rule, "use_avoid")
- row.prop(rule, "use_avoid_collision")
- row.prop(rule, "look_ahead")
- elif rule.type == 'FOLLOW_LEADER':
- row.prop(rule, "object", text="")
- row.prop(rule, "distance")
- row = layout.row()
- row.prop(rule, "use_line")
- sub = row.row()
- sub.active = rule.line
- sub.prop(rule, "queue_count")
- elif rule.type == 'AVERAGE_SPEED':
- row.prop(rule, "speed", slider=True)
- row.prop(rule, "wander", slider=True)
- row.prop(rule, "level", slider=True)
- elif rule.type == 'FIGHT':
- row.prop(rule, "distance")
- row.prop(rule, "flee_distance")
-
-
-class PARTICLE_PT_render(ParticleButtonsPanel, Panel):
- bl_label = "Render"
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- settings = particle_get_settings(context)
- engine = context.scene.render.engine
- if settings is None:
- return False
-
- return engine in cls.COMPAT_ENGINES
-
- def draw(self, context):
- layout = self.layout
-
- psys = context.particle_system
- part = particle_get_settings(context)
-
- if psys:
- row = layout.row()
- if part.render_type in {'OBJECT', 'GROUP'}:
- row.enabled = False
- row.prop(part, "material_slot", text="")
- row.prop(psys, "parent")
-
- split = layout.split()
-
- col = split.column()
- col.prop(part, "use_render_emitter")
- col.prop(part, "use_parent_particles")
-
- col = split.column()
- col.prop(part, "show_unborn")
- col.prop(part, "use_dead")
-
- layout.prop(part, "render_type", expand=True)
-
- split = layout.split()
-
- col = split.column()
-
- if part.render_type == 'LINE':
- col.prop(part, "line_length_tail")
- col.prop(part, "line_length_head")
-
- split.prop(part, "use_velocity_length")
- elif part.render_type == 'PATH':
- col.prop(part, "use_strand_primitive")
- sub = col.column()
- sub.active = (part.use_strand_primitive is False)
- sub.prop(part, "use_render_adaptive")
- sub = col.column()
- sub.active = part.use_render_adaptive or part.use_strand_primitive is True
- sub.prop(part, "adaptive_angle")
- sub = col.column()
- sub.active = (part.use_render_adaptive is True and part.use_strand_primitive is False)
- sub.prop(part, "adaptive_pixel")
- col.prop(part, "use_hair_bspline")
- col.prop(part, "render_step", text="Steps")
-
- col = split.column()
- col.label(text="Timing:")
- col.prop(part, "use_absolute_path_time")
-
- if part.type == 'HAIR' or psys.point_cache.is_baked:
- col.prop(part, "path_start", text="Start", slider=not part.use_absolute_path_time)
- else:
- col.prop(part, "trail_count")
-
- col.prop(part, "path_end", text="End", slider=not part.use_absolute_path_time)
- col.prop(part, "length_random", text="Random", slider=True)
-
- row = layout.row()
- col = row.column()
-
- if part.type == 'HAIR' and part.use_strand_primitive is True and part.child_type == 'INTERPOLATED':
- layout.prop(part, "use_simplify")
- if part.use_simplify is True:
- row = layout.row()
- row.prop(part, "simplify_refsize")
- row.prop(part, "simplify_rate")
- row.prop(part, "simplify_transition")
- row = layout.row()
- row.prop(part, "use_simplify_viewport")
- sub = row.row()
- sub.active = part.use_simplify_viewport is True
- sub.prop(part, "simplify_viewport")
-
- elif part.render_type == 'OBJECT':
- col.prop(part, "dupli_object")
- sub = col.row()
- sub.prop(part, "use_global_dupli")
- sub.prop(part, "use_rotation_dupli")
- sub.prop(part, "use_scale_dupli")
- elif part.render_type == 'GROUP':
- col.prop(part, "dupli_group")
- split = layout.split()
-
- col = split.column()
- col.prop(part, "use_whole_group")
- sub = col.column()
- sub.active = (part.use_whole_group is False)
- sub.prop(part, "use_group_pick_random")
- sub.prop(part, "use_group_count")
-
- col = split.column()
- sub = col.column()
- sub.active = (part.use_whole_group is False)
- sub.prop(part, "use_global_dupli")
- sub.prop(part, "use_rotation_dupli")
- sub.prop(part, "use_scale_dupli")
-
- if part.use_group_count and not part.use_whole_group:
- row = layout.row()
- row.template_list("UI_UL_list", "particle_dupli_weights", part, "dupli_weights",
- part, "active_dupliweight_index")
-
- col = row.column()
- sub = col.row()
- subsub = sub.column(align=True)
- subsub.operator("particle.dupliob_copy", icon='ZOOMIN', text="")
- subsub.operator("particle.dupliob_remove", icon='ZOOMOUT', text="")
- subsub.operator("particle.dupliob_move_up", icon='MOVE_UP_VEC', text="")
- subsub.operator("particle.dupliob_move_down", icon='MOVE_DOWN_VEC', text="")
-
- weight = part.active_dupliweight
- if weight:
- row = layout.row()
- row.prop(weight, "count")
-
- elif part.render_type == 'BILLBOARD':
- ob = context.object
-
- col.label(text="Align:")
-
- row = layout.row()
- row.prop(part, "billboard_align", expand=True)
- row.prop(part, "lock_billboard", text="Lock")
- row = layout.row()
- row.prop(part, "billboard_object")
-
- row = layout.row()
- col = row.column(align=True)
- col.label(text="Tilt:")
- col.prop(part, "billboard_tilt", text="Angle", slider=True)
- col.prop(part, "billboard_tilt_random", text="Random", slider=True)
- col = row.column()
- col.prop(part, "billboard_offset")
-
- row = layout.row()
- col = row.column()
- col.prop(part, "billboard_size", text="Scale")
- if part.billboard_align == 'VEL':
- col = row.column(align=True)
- col.label("Velocity Scale:")
- col.prop(part, "billboard_velocity_head", text="Head")
- col.prop(part, "billboard_velocity_tail", text="Tail")
-
- if psys:
- col = layout.column()
- col.prop_search(psys, "billboard_normal_uv", ob.data, "uv_textures")
- col.prop_search(psys, "billboard_time_index_uv", ob.data, "uv_textures")
-
- split = layout.split(percentage=0.33)
- split.label(text="Split UVs:")
- split.prop(part, "billboard_uv_split", text="Number of splits")
-
- if psys:
- col = layout.column()
- col.active = part.billboard_uv_split > 1
- col.prop_search(psys, "billboard_split_uv", ob.data, "uv_textures")
-
- row = col.row()
- row.label(text="Animate:")
- row.prop(part, "billboard_animation", text="")
- row.label(text="Offset:")
- row.prop(part, "billboard_offset_split", text="")
-
- if part.render_type == 'HALO' or part.render_type == 'LINE' or part.render_type == 'BILLBOARD':
- row = layout.row()
- col = row.column()
- col.prop(part, "trail_count")
- if part.trail_count > 1:
- col.prop(part, "use_absolute_path_time", text="Length in frames")
- col = row.column()
- col.prop(part, "path_end", text="Length", slider=not part.use_absolute_path_time)
- col.prop(part, "length_random", text="Random", slider=True)
- else:
- col = row.column()
- col.label(text="")
-
- if part.render_type in {'OBJECT', 'GROUP'} and not part.use_advanced_hair:
- row = layout.row(align=True)
- row.prop(part, "particle_size")
- row.prop(part, "size_random", slider=True)
-
-
-class PARTICLE_PT_draw(ParticleButtonsPanel, Panel):
- bl_label = "Display"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- settings = particle_get_settings(context)
- engine = context.scene.render.engine
- if settings is None:
- return False
- return engine in cls.COMPAT_ENGINES
-
- def draw(self, context):
- layout = self.layout
-
- psys = context.particle_system
- part = particle_get_settings(context)
-
- row = layout.row()
- row.prop(part, "draw_method", expand=True)
- row.prop(part, "show_guide_hairs")
-
- if part.draw_method == 'NONE' or (part.render_type == 'NONE' and part.draw_method == 'RENDER'):
- return
-
- path = (part.render_type == 'PATH' and part.draw_method == 'RENDER') or part.draw_method == 'PATH'
-
- row = layout.row()
- row.prop(part, "draw_percentage", slider=True)
- if part.draw_method != 'RENDER' or part.render_type == 'HALO':
- row.prop(part, "draw_size")
- else:
- row.label(text="")
-
- if part.draw_percentage != 100 and psys is not None:
- if part.type == 'HAIR':
- if psys.use_hair_dynamics and psys.point_cache.is_baked is False:
- layout.row().label(text="Display percentage makes dynamics inaccurate without baking!")
- else:
- phystype = part.physics_type
- if phystype != 'NO' and phystype != 'KEYED' and psys.point_cache.is_baked is False:
- layout.row().label(text="Display percentage makes dynamics inaccurate without baking!")
-
- row = layout.row()
- col = row.column()
- col.prop(part, "show_size")
- col.prop(part, "show_velocity")
- col.prop(part, "show_number")
- if part.physics_type == 'BOIDS':
- col.prop(part, "show_health")
-
- col = row.column(align=True)
- col.label(text="Color:")
- col.prop(part, "draw_color", text="")
- sub = col.row(align=True)
- sub.active = (part.draw_color in {'VELOCITY', 'ACCELERATION'})
- sub.prop(part, "color_maximum", text="Max")
-
- if path:
- col.prop(part, "draw_step")
-
-
-class PARTICLE_PT_children(ParticleButtonsPanel, Panel):
- bl_label = "Children"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- return particle_panel_poll(cls, context)
-
- def draw(self, context):
- layout = self.layout
-
- psys = context.particle_system
- part = particle_get_settings(context)
-
- layout.row().prop(part, "child_type", expand=True)
-
- if part.child_type == 'NONE':
- return
-
- row = layout.row()
-
- col = row.column(align=True)
- col.prop(part, "child_nbr", text="Display")
- col.prop(part, "rendered_child_count", text="Render")
-
- if part.child_type == 'INTERPOLATED':
- col = row.column()
- if psys:
- col.prop(psys, "child_seed", text="Seed")
- col.prop(part, "virtual_parents", slider=True)
- col.prop(part, "create_long_hair_children")
- else:
- col = row.column(align=True)
- col.prop(part, "child_size", text="Size")
- col.prop(part, "child_size_random", text="Random")
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Effects:")
-
- sub = col.column(align=True)
- sub.prop(part, "use_clump_curve")
- if part.use_clump_curve:
- sub.template_curve_mapping(part, "clump_curve")
- else:
- sub.prop(part, "clump_factor", slider=True)
- sub.prop(part, "clump_shape", slider=True)
- sub = col.column(align=True)
- sub.prop(part, "use_clump_noise")
- subsub = sub.column()
- subsub.enabled = part.use_clump_noise
- subsub.prop(part, "clump_noise_size")
-
- sub = col.column(align=True)
- sub.prop(part, "child_length", slider=True)
- sub.prop(part, "child_length_threshold", slider=True)
-
- if part.child_type == 'SIMPLE':
- sub = col.column(align=True)
- sub.prop(part, "child_radius", text="Radius")
- sub.prop(part, "child_roundness", text="Roundness", slider=True)
- if psys:
- sub.prop(psys, "child_seed", text="Seed")
- elif part.virtual_parents > 0.0:
- sub = col.column(align=True)
- sub.label(text="Parting not")
- sub.label(text="available with")
- sub.label(text="virtual parents")
- else:
- sub = col.column(align=True)
- sub.prop(part, "child_parting_factor", text="Parting", slider=True)
- sub.prop(part, "child_parting_min", text="Min")
- sub.prop(part, "child_parting_max", text="Max")
-
- col = split.column()
-
- col.prop(part, "use_roughness_curve")
- if part.use_roughness_curve:
- sub = col.column()
- sub.template_curve_mapping(part, "roughness_curve")
- sub.prop(part, "roughness_1", text="Roughness")
- sub.prop(part, "roughness_1_size", text="Size")
- else:
- col.label(text="Roughness:")
-
- sub = col.column(align=True)
- sub.prop(part, "roughness_1", text="Uniform")
- sub.prop(part, "roughness_1_size", text="Size")
-
- sub = col.column(align=True)
- sub.prop(part, "roughness_endpoint", "Endpoint")
- sub.prop(part, "roughness_end_shape")
-
- sub = col.column(align=True)
- sub.prop(part, "roughness_2", text="Random")
- sub.prop(part, "roughness_2_size", text="Size")
- sub.prop(part, "roughness_2_threshold", slider=True)
-
- layout.row().label(text="Kink:")
- layout.row().prop(part, "kink", expand=True)
-
- split = layout.split()
- split.active = part.kink != 'NO'
-
- if part.kink == 'SPIRAL':
- col = split.column()
- sub = col.column(align=True)
- sub.prop(part, "kink_amplitude", text="Radius")
- sub.prop(part, "kink_amplitude_random", text="Random", slider=True)
- sub = col.column(align=True)
- sub.prop(part, "kink_axis")
- sub.prop(part, "kink_axis_random", text="Random", slider=True)
- col = split.column(align=True)
- col.prop(part, "kink_frequency", text="Frequency")
- col.prop(part, "kink_shape", text="Shape", slider=True)
- col.prop(part, "kink_extra_steps", text="Steps")
- else:
- col = split.column()
- sub = col.column(align=True)
- sub.prop(part, "kink_amplitude")
- sub.prop(part, "kink_amplitude_clump", text="Clump", slider=True)
- col.prop(part, "kink_flat", slider=True)
- col = split.column(align=True)
- col.prop(part, "kink_frequency")
- col.prop(part, "kink_shape", slider=True)
-
-
-class PARTICLE_PT_field_weights(ParticleButtonsPanel, Panel):
- bl_label = "Field Weights"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- return particle_panel_poll(cls, context)
-
- def draw(self, context):
- part = particle_get_settings(context)
- effector_weights_ui(self, context, part.effector_weights, 'PSYS')
-
- if part.type == 'HAIR':
- row = self.layout.row()
- row.prop(part.effector_weights, "apply_to_hair_growing")
- row.prop(part, "apply_effector_to_children")
- row = self.layout.row()
- row.prop(part, "effect_hair", slider=True)
-
-
-class PARTICLE_PT_force_fields(ParticleButtonsPanel, Panel):
- bl_label = "Force Field Settings"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- part = particle_get_settings(context)
-
- row = layout.row()
- row.prop(part, "use_self_effect")
- row.prop(part, "effector_amount", text="Amount")
-
- split = layout.split(percentage=0.2)
- split.label(text="Type 1:")
- split.prop(part.force_field_1, "type", text="")
- basic_force_field_settings_ui(self, context, part.force_field_1)
- if part.force_field_1.type != 'NONE':
- layout.label(text="Falloff:")
- basic_force_field_falloff_ui(self, context, part.force_field_1)
-
- if part.force_field_1.type != 'NONE':
- layout.label(text="")
-
- split = layout.split(percentage=0.2)
- split.label(text="Type 2:")
- split.prop(part.force_field_2, "type", text="")
- basic_force_field_settings_ui(self, context, part.force_field_2)
- if part.force_field_2.type != 'NONE':
- layout.label(text="Falloff:")
- basic_force_field_falloff_ui(self, context, part.force_field_2)
-
-
-class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, Panel):
- bl_label = "Vertex Groups"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- if context.particle_system is None:
- return False
- return particle_panel_poll(cls, context)
-
- def draw(self, context):
- layout = self.layout
-
- ob = context.object
- psys = context.particle_system
-
- col = layout.column()
- row = col.row(align=True)
- row.prop_search(psys, "vertex_group_density", ob, "vertex_groups", text="Density")
- row.prop(psys, "invert_vertex_group_density", text="", toggle=True, icon='ARROW_LEFTRIGHT')
-
- row = col.row(align=True)
- row.prop_search(psys, "vertex_group_length", ob, "vertex_groups", text="Length")
- row.prop(psys, "invert_vertex_group_length", text="", toggle=True, icon='ARROW_LEFTRIGHT')
-
- row = col.row(align=True)
- row.prop_search(psys, "vertex_group_clump", ob, "vertex_groups", text="Clump")
- row.prop(psys, "invert_vertex_group_clump", text="", toggle=True, icon='ARROW_LEFTRIGHT')
-
- row = col.row(align=True)
- row.prop_search(psys, "vertex_group_kink", ob, "vertex_groups", text="Kink")
- row.prop(psys, "invert_vertex_group_kink", text="", toggle=True, icon='ARROW_LEFTRIGHT')
-
- row = col.row(align=True)
- row.prop_search(psys, "vertex_group_roughness_1", ob, "vertex_groups", text="Roughness 1")
- row.prop(psys, "invert_vertex_group_roughness_1", text="", toggle=True, icon='ARROW_LEFTRIGHT')
-
- row = col.row(align=True)
- row.prop_search(psys, "vertex_group_roughness_2", ob, "vertex_groups", text="Roughness 2")
- row.prop(psys, "invert_vertex_group_roughness_2", text="", toggle=True, icon='ARROW_LEFTRIGHT')
-
- row = col.row(align=True)
- row.prop_search(psys, "vertex_group_roughness_end", ob, "vertex_groups", text="Roughness End")
- row.prop(psys, "invert_vertex_group_roughness_end", text="", toggle=True, icon='ARROW_LEFTRIGHT')
-
- # Commented out vertex groups don't work and are still waiting for better implementation
- # row = layout.row()
- # row.prop_search(psys, "vertex_group_velocity", ob, "vertex_groups", text="Velocity")
- # row.prop(psys, "invert_vertex_group_velocity", text="")
-
- # row = layout.row()
- # row.prop_search(psys, "vertex_group_size", ob, "vertex_groups", text="Size")
- # row.prop(psys, "invert_vertex_group_size", text="")
-
- # row = layout.row()
- # row.prop_search(psys, "vertex_group_tangent", ob, "vertex_groups", text="Tangent")
- # row.prop(psys, "invert_vertex_group_tangent", text="")
-
- # row = layout.row()
- # row.prop_search(psys, "vertex_group_rotation", ob, "vertex_groups", text="Rotation")
- # row.prop(psys, "invert_vertex_group_rotation", text="")
-
- # row = layout.row()
- # row.prop_search(psys, "vertex_group_field", ob, "vertex_groups", text="Field")
- # row.prop(psys, "invert_vertex_group_field", text="")
-
-
-class PARTICLE_PT_custom_props(ParticleButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER'}
- _context_path = "particle_system.settings"
- _property_type = bpy.types.ParticleSettings
-
-if __name__ == "__main__": # only for live edit.
- bpy.utils.register_module(__name__)
from bpy.types import Menu, Panel
from bl_ui.properties_physics_common import (
- point_cache_ui,
effector_weights_ui,
)
-def cloth_panel_enabled(md):
- return md.point_cache.is_baked is False
-
-
class CLOTH_MT_presets(Menu):
bl_label = "Cloth Presets"
preset_subdir = "cloth"
split = layout.split()
- split.active = cloth_panel_enabled(md)
-
col = split.column()
col.label(text="Presets:")
col.prop_search(cloth, "rest_shape_key", key, "key_blocks", text="")
-class PHYSICS_PT_cloth_cache(PhysicButtonsPanel, Panel):
- bl_label = "Cloth Cache"
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw(self, context):
- md = context.cloth
- point_cache_ui(self, context, md.point_cache, cloth_panel_enabled(md), 'CLOTH')
-
-
class PHYSICS_PT_cloth_collision(PhysicButtonsPanel, Panel):
bl_label = "Cloth Collision"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
cloth = context.cloth.collision_settings
- self.layout.active = cloth_panel_enabled(context.cloth)
self.layout.prop(cloth, "use_collision", text="")
def draw(self, context):
md = context.cloth
ob = context.object
- layout.active = cloth.use_collision and cloth_panel_enabled(md)
+ layout.active = cloth.use_collision
split = layout.split()
def draw_header(self, context):
cloth = context.cloth.settings
- self.layout.active = cloth_panel_enabled(context.cloth)
self.layout.prop(cloth, "use_stiffness_scale", text="")
def draw(self, context):
ob = context.object
cloth = context.cloth.settings
- layout.active = (cloth.use_stiffness_scale and cloth_panel_enabled(md))
+ layout.active = cloth.use_stiffness_scale
split = layout.split()
def draw_header(self, context):
cloth = context.cloth.settings
- self.layout.active = cloth_panel_enabled(context.cloth)
self.layout.prop(cloth, "use_sewing_springs", text="")
def draw(self, context):
ob = context.object
cloth = context.cloth.settings
- layout.active = (cloth.use_sewing_springs and cloth_panel_enabled(md))
+ layout.active = cloth.use_sewing_springs
layout.prop(cloth, "sewing_force_max", text="Sewing Force")
'CONSTRAINT') # RB_TODO needs better icon
-# cache-type can be 'PSYS' 'HAIR' 'SMOKE' etc
-
-def point_cache_ui(self, context, cache, enabled, cachetype):
- layout = self.layout
-
- layout.context_pointer_set("point_cache", cache)
-
- if not cachetype == 'RIGID_BODY':
- row = layout.row()
- row.template_list("UI_UL_list", "point_caches", cache, "point_caches",
- cache.point_caches, "active_index", rows=1)
- col = row.column(align=True)
- col.operator("ptcache.add", icon='ZOOMIN', text="")
- col.operator("ptcache.remove", icon='ZOOMOUT', text="")
-
- row = layout.row()
- if cachetype in {'PSYS', 'HAIR', 'SMOKE'}:
- row.prop(cache, "use_external")
-
- if cachetype == 'SMOKE':
- row.prop(cache, "use_library_path", "Use Lib Path")
-
- if cache.use_external:
- split = layout.split(percentage=0.35)
- col = split.column()
- col.label(text="Index Number:")
- col.label(text="File Path:")
-
- col = split.column()
- col.prop(cache, "index", text="")
- col.prop(cache, "filepath", text="")
-
- cache_info = cache.info
- if cache_info:
- layout.label(text=cache_info)
- else:
- if cachetype in {'SMOKE', 'DYNAMIC_PAINT'}:
- if not bpy.data.is_saved:
- layout.label(text="Cache is disabled until the file is saved")
- layout.enabled = False
-
- if not cache.use_external or cachetype == 'SMOKE':
- row = layout.row(align=True)
-
- if cachetype not in {'PSYS', 'DYNAMIC_PAINT'}:
- row.enabled = enabled
- row.prop(cache, "frame_start")
- row.prop(cache, "frame_end")
- if cachetype not in {'SMOKE', 'CLOTH', 'DYNAMIC_PAINT', 'RIGID_BODY'}:
- row.prop(cache, "frame_step")
-
- if cachetype != 'SMOKE':
- layout.label(text=cache.info)
-
- can_bake = True
-
- if cachetype not in {'SMOKE', 'DYNAMIC_PAINT', 'RIGID_BODY'}:
- split = layout.split()
- split.enabled = enabled and bpy.data.is_saved
-
- col = split.column()
- col.prop(cache, "use_disk_cache")
-
- col = split.column()
- col.active = cache.use_disk_cache
- col.prop(cache, "use_library_path", "Use Lib Path")
-
- row = layout.row()
- row.enabled = enabled and bpy.data.is_saved
- row.active = cache.use_disk_cache
- row.label(text="Compression:")
- row.prop(cache, "compression", expand=True)
-
- layout.separator()
-
- if cache.id_data.library and not cache.use_disk_cache:
- can_bake = False
-
- col = layout.column(align=True)
- col.label(text="Linked object baking requires Disk Cache to be enabled", icon='INFO')
- else:
- layout.separator()
-
- split = layout.split()
- split.active = can_bake
-
- col = split.column()
-
- if cache.is_baked is True:
- col.operator("ptcache.free_bake", text="Free Bake")
- else:
- col.operator("ptcache.bake", text="Bake").bake = True
-
- sub = col.row()
- sub.enabled = (cache.is_frame_skip or cache.is_outdated) and enabled
- sub.operator("ptcache.bake", text="Calculate To Frame").bake = False
-
- sub = col.column()
- sub.enabled = enabled
- sub.operator("ptcache.bake_from_cache", text="Current Cache to Bake")
-
- col = split.column()
- col.operator("ptcache.bake_all", text="Bake All Dynamics").bake = True
- col.operator("ptcache.free_bake_all", text="Free All Bakes")
- col.operator("ptcache.bake_all", text="Update All To Frame").bake = False
-
-
def effector_weights_ui(self, context, weights, weight_type):
layout = self.layout
from bpy.types import Panel, UIList
from bl_ui.properties_physics_common import (
- point_cache_ui,
effector_weights_ui,
)
col = split.column()
if not use_shading_nodes:
- sub = col.column()
- sub.active = (brush.paint_source != 'PARTICLE_SYSTEM')
- sub.prop(brush, "use_material")
- if brush.use_material and brush.paint_source != 'PARTICLE_SYSTEM' and not use_shading_nodes:
+ col.prop(brush, "use_material")
+ if brush.use_material and not use_shading_nodes:
col.prop(brush, "material", text="")
col.prop(brush, "paint_alpha", text="Alpha Factor")
else:
row.prop(surface, "shrink_speed")
-class PHYSICS_PT_dp_cache(PhysicButtonsPanel, Panel):
- bl_label = "Dynamic Paint Cache"
- bl_options = {'DEFAULT_CLOSED'}
-
- @classmethod
- def poll(cls, context):
- md = context.dynamic_paint
- rd = context.scene.render
- return (md and
- md.ui_type == 'CANVAS' and
- md.canvas_settings and
- md.canvas_settings.canvas_surfaces.active and
- md.canvas_settings.canvas_surfaces.active.is_cache_user and
- (not rd.use_game_engine))
-
- def draw(self, context):
- surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
- cache = surface.point_cache
-
- point_cache_ui(self, context, cache, (cache.is_baked is False), 'DYNAMIC_PAINT')
-
-
class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel):
bl_label = "Dynamic Paint Source"
col = split.column()
col.prop(brush, "paint_source")
- if brush.paint_source == 'PARTICLE_SYSTEM':
- col.prop_search(brush, "particle_system", ob, "particle_systems", text="")
- if brush.particle_system:
- col.label(text="Particle effect:")
- sub = col.column()
- sub.active = not brush.use_particle_radius
- sub.prop(brush, "solid_radius", text="Solid Radius")
- col.prop(brush, "use_particle_radius", text="Use Particle's Radius")
- col.prop(brush, "smooth_radius", text="Smooth radius")
-
if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE', 'POINT'}:
col.prop(brush, "paint_distance", text="Paint Distance")
split = layout.row().split(percentage=0.4)
from bpy.types import Panel
from bl_ui.properties_physics_common import (
- point_cache_ui,
effector_weights_ui,
)
split = layout.split()
- split.enabled = not domain.point_cache.is_baked
-
col = split.column()
col.label(text="Resolution:")
col.prop(domain, "resolution_max", text="Divisions")
col = split.column()
col.label(text="Flow Source:")
col.prop(flow, "smoke_flow_source", expand=False, text="")
- if flow.smoke_flow_source == 'PARTICLES':
- col.label(text="Particle System:")
- col.prop_search(flow, "particle_system", ob, "particle_systems", text="")
- col.prop(flow, "use_particle_size", text="Set Size")
- sub = col.column()
- sub.active = flow.use_particle_size
- sub.prop(flow, "particle_size")
- else:
+ if flow.smoke_flow_source == 'MESH':
col.prop(flow, "surface_distance")
col.prop(flow, "volume_density")
domain = context.smoke.domain_settings
split = layout.split()
- split.enabled = not domain.point_cache.is_baked
col = split.column(align=True)
col.label(text="Reaction:")
layout.active = domain.use_adaptive_domain
split = layout.split()
- split.enabled = (not domain.point_cache.is_baked)
col = split.column(align=True)
col.label(text="Resolution:")
layout.active = md.use_high_resolution
split = layout.split()
- split.enabled = not md.point_cache.is_baked
col = split.column()
col.label(text="Resolution:")
layout.prop(domain, "cache_file_format")
- if cache_file_format == 'POINTCACHE':
- layout.label(text="Compression:")
- layout.prop(domain, "point_cache_compress_type", expand=True)
- elif cache_file_format == 'OPENVDB':
+ if cache_file_format == 'OPENVDB':
if not bpy.app.build_options.openvdb:
layout.label("Built without OpenVDB support")
return
row.label("Data Depth:")
row.prop(domain, "data_depth", expand=True, text="Data Depth")
- cache = domain.point_cache
- point_cache_ui(self, context, cache, (cache.is_baked is False), 'SMOKE')
-
class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, Panel):
bl_label = "Smoke Field Weights"
from bpy.types import Panel
from bl_ui.properties_physics_common import (
- point_cache_ui,
effector_weights_ui,
)
-def softbody_panel_enabled(md):
- return (md.point_cache.is_baked is False)
-
-
class PhysicButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
# General
split = layout.split()
- split.enabled = softbody_panel_enabled(md)
col = split.column()
col.label(text="Object:")
col.prop(softbody, "speed")
-class PHYSICS_PT_softbody_cache(PhysicButtonsPanel, Panel):
- bl_label = "Soft Body Cache"
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw(self, context):
- md = context.soft_body
- point_cache_ui(self, context, md.point_cache, softbody_panel_enabled(md), 'SOFTBODY')
-
-
class PHYSICS_PT_softbody_goal(PhysicButtonsPanel, Panel):
bl_label = "Soft Body Goal"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
softbody = context.soft_body.settings
- self.layout.active = softbody_panel_enabled(context.soft_body)
self.layout.prop(softbody, "use_goal", text="")
def draw(self, context):
softbody = md.settings
ob = context.object
- layout.active = softbody.use_goal and softbody_panel_enabled(md)
+ layout.active = softbody.use_goal
split = layout.split()
def draw_header(self, context):
softbody = context.soft_body.settings
- self.layout.active = softbody_panel_enabled(context.soft_body)
self.layout.prop(softbody, "use_edges", text="")
def draw(self, context):
softbody = md.settings
ob = context.object
- layout.active = softbody.use_edges and softbody_panel_enabled(md)
+ layout.active = softbody.use_edges
split = layout.split()
def draw_header(self, context):
softbody = context.soft_body.settings
- self.layout.active = softbody_panel_enabled(context.soft_body)
self.layout.prop(softbody, "use_self_collision", text="")
def draw(self, context):
md = context.soft_body
softbody = md.settings
- layout.active = softbody.use_self_collision and softbody_panel_enabled(md)
+ layout.active = softbody.use_self_collision
layout.label(text="Collision Ball Size Calculation:")
layout.prop(softbody, "collision_type", expand=True)
md = context.soft_body
softbody = md.settings
- layout.active = softbody_panel_enabled(md)
-
# Solver
split = layout.split()
from rna_prop_ui import PropertyPanel
from bl_ui.properties_physics_common import (
- point_cache_ui,
effector_weights_ui,
)
col.prop(rbw, "solver_iterations", text="Solver Iterations")
-class SCENE_PT_rigid_body_cache(SceneButtonsPanel, Panel):
- bl_label = "Rigid Body Cache"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- @classmethod
- def poll(cls, context):
- rd = context.scene.render
- scene = context.scene
- return scene and scene.rigidbody_world and (rd.engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
- scene = context.scene
- rbw = scene.rigidbody_world
-
- point_cache_ui(self, context, rbw.point_cache, rbw.point_cache.is_baked is False and rbw.enabled, 'RIGID_BODY')
-
-
class SCENE_PT_rigid_body_field_weights(SceneButtonsPanel, Panel):
bl_label = "Rigid Body Field Weights"
bl_options = {'DEFAULT_CLOSED'}
col = split.column()
col.label(text="Viewport:")
col.prop(rd, "simplify_subdivision", text="Subdivision")
- col.prop(rd, "simplify_child_particles", text="Child Particles")
col = split.column()
col.label(text="Render:")
col.prop(rd, "simplify_subdivision_render", text="Subdivision")
- col.prop(rd, "simplify_child_particles_render", text="Child Particles")
col.prop(rd, "simplify_shadow_samples", text="Shadow Samples")
col.prop(rd, "simplify_ao_sss", text="AO and SSS")
col.prop(rd, "use_simplify_triangulate")
Lamp,
Material,
Object,
- ParticleSettings,
Texture,
World,
)
if idblock:
return idblock
- if context.particle_system:
- idblock = context.particle_system.settings
-
return idblock
context.lamp or
context.texture or
context.line_style or
- context.particle_system or
- isinstance(context.space_data.pin_id, ParticleSettings) or
context.texture_user) and
(engine in cls.COMPAT_ENGINES))
split = layout.split()
col = split.column()
- if pd.point_source == 'PARTICLE_SYSTEM':
- col.label(text="Object:")
- col.prop(pd, "object", text="")
-
- sub = col.column()
- sub.enabled = bool(pd.object)
- if pd.object:
- sub.label(text="System:")
- sub.prop_search(pd, "particle_system", pd.object, "particle_systems", text="")
- sub.label(text="Cache:")
- sub.prop(pd, "particle_cache_space", text="")
- else:
+ if pd.point_source == 'OBJECT':
col.label(text="Object:")
col.prop(pd, "object", text="")
col.label(text="Cache:")
col.separator()
col.label(text="Color Source:")
- if pd.point_source == 'PARTICLE_SYSTEM':
- col.prop(pd, "particle_color_source", text="")
- if pd.particle_color_source in {'PARTICLE_SPEED', 'PARTICLE_VELOCITY'}:
- col.prop(pd, "speed_scale")
- if pd.particle_color_source in {'PARTICLE_SPEED', 'PARTICLE_AGE'}:
- layout.template_color_ramp(pd, "color_ramp", expand=True)
- else:
+ if pd.point_source == 'OBJECT':
col.prop(pd, "vertex_color_source", text="")
if pd.vertex_color_source == 'VERTEX_COLOR':
if pd.object and pd.object.data:
col.prop(pd, "falloff", text="")
if pd.falloff == 'SOFT':
col.prop(pd, "falloff_soft")
- if pd.falloff == 'PARTICLE_VELOCITY':
- col.prop(pd, "falloff_speed_scale")
col.prop(pd, "use_falloff_curve")
col = split.column()
factor_but(col, "use_map_zenith_up", "zenith_up_factor", "Zenith Up")
factor_but(col, "use_map_zenith_down", "zenith_down_factor", "Zenith Down")
- elif isinstance(idblock, ParticleSettings):
- split = layout.split()
-
- col = split.column()
- col.label(text="General:")
- factor_but(col, "use_map_time", "time_factor", "Time")
- factor_but(col, "use_map_life", "life_factor", "Lifetime")
- factor_but(col, "use_map_density", "density_factor", "Density")
- factor_but(col, "use_map_size", "size_factor", "Size")
-
- col = split.column()
- col.label(text="Physics:")
- factor_but(col, "use_map_velocity", "velocity_factor", "Velocity")
- factor_but(col, "use_map_damp", "damp_factor", "Damp")
- factor_but(col, "use_map_gravity", "gravity_factor", "Gravity")
- factor_but(col, "use_map_field", "field_factor", "Force Fields")
-
- layout.label(text="Hair:")
-
- split = layout.split()
-
- col = split.column()
- factor_but(col, "use_map_length", "length_factor", "Length")
- factor_but(col, "use_map_clump", "clump_factor", "Clump")
-
- col = split.column()
- factor_but(col, "use_map_kink_amp", "kink_amp_factor", "Kink Amplitude")
- factor_but(col, "use_map_kink_freq", "kink_freq_factor", "Kink Frequency")
- factor_but(col, "use_map_rough", "rough_factor", "Rough")
elif isinstance(idblock, FreestyleLineStyle):
split = layout.split()
layout.separator()
- if not isinstance(idblock, ParticleSettings):
- split = layout.split()
+ split = layout.split()
- col = split.column()
- col.prop(tex, "blend_type", text="Blend")
- col.prop(tex, "use_rgb_to_intensity")
- # color is used on gray-scale textures even when use_rgb_to_intensity is disabled.
- col.prop(tex, "color", text="")
+ col = split.column()
+ col.prop(tex, "blend_type", text="Blend")
+ col.prop(tex, "use_rgb_to_intensity")
+ # color is used on gray-scale textures even when use_rgb_to_intensity is disabled.
+ col.prop(tex, "color", text="")
- col = split.column()
- col.prop(tex, "invert", text="Negative")
- col.prop(tex, "use_stencil")
+ col = split.column()
+ col.prop(tex, "invert", text="Negative")
+ col.prop(tex, "use_stencil")
if isinstance(idblock, Material) or isinstance(idblock, World):
col.prop(tex, "default_value", text="DVar", slider=True)
row.prop(dopesheet, "show_lattices", text="")
if bpy.data.armatures:
row.prop(dopesheet, "show_armatures", text="")
- if bpy.data.particles:
- row.prop(dopesheet, "show_particles", text="")
if bpy.data.speakers:
row.prop(dopesheet, "show_speakers", text="")
if bpy.data.linestyles:
col = layout.column()
col.enabled = st.show_cache
col.prop(st, "cache_softbody")
- col.prop(st, "cache_particles")
col.prop(st, "cache_cloth")
col.prop(st, "cache_smoke")
col.prop(st, "cache_dynamicpaint")
col.prop(edit, "use_duplicate_texture", text="Texture")
#col.prop(edit, "use_duplicate_fcurve", text="F-Curve")
col.prop(edit, "use_duplicate_action", text="Action")
- col.prop(edit, "use_duplicate_particle", text="Particle")
class USERPREF_PT_system(Panel):
if obj:
mode = obj.mode
- # Particle edit
- if mode == 'PARTICLE_EDIT':
- row.prop(toolsettings.particle_edit, "select_mode", text="", expand=True)
# Occlude geometry
- if ((view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'} and (mode == 'PARTICLE_EDIT' or (mode == 'EDIT' and obj.type == 'MESH'))) or
+ if ((view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'} and (mode == 'EDIT' and obj.type == 'MESH')) or
(mode == 'WEIGHT_PAINT')):
row.prop(view, "use_occlude_geometry", text="")
row.prop(toolsettings, "proportional_edit", icon_only=True)
if toolsettings.proportional_edit != 'DISABLED':
row.prop(toolsettings, "proportional_edit_falloff", icon_only=True)
- elif mode in {'EDIT', 'PARTICLE_EDIT'}:
+ elif mode == 'EDIT':
row = layout.row(align=True)
row.prop(toolsettings, "proportional_edit", icon_only=True)
if toolsettings.proportional_edit != 'DISABLED':
layout.operator("object.select_pattern", text="Select Pattern...")
-class VIEW3D_MT_select_particle(Menu):
- bl_label = "Select"
-
- def draw(self, context):
- layout = self.layout
-
- layout.operator("view3d.select_border")
-
- layout.separator()
-
- layout.operator("particle.select_all").action = 'TOGGLE'
- layout.operator("particle.select_linked")
- layout.operator("particle.select_all", text="Inverse").action = 'INVERT'
-
- layout.separator()
-
- layout.operator("particle.select_more")
- layout.operator("particle.select_less")
-
- layout.separator()
-
- layout.operator("particle.select_random")
-
- layout.separator()
-
- layout.operator("particle.select_roots", text="Roots")
- layout.operator("particle.select_tips", text="Tips")
-
-
class VIEW3D_MT_edit_mesh_select_similar(Menu):
bl_label = "Select Similar"
props = layout.operator("paint.mask_lasso_gesture", text="Lasso Mask")
-# ********** Particle menu **********
-
-
-class VIEW3D_MT_particle(Menu):
- bl_label = "Particle"
-
- def draw(self, context):
- layout = self.layout
-
- particle_edit = context.tool_settings.particle_edit
-
- layout.operator("ed.undo")
- layout.operator("ed.redo")
- layout.operator("ed.undo_history")
-
- layout.separator()
-
- layout.operator("particle.mirror")
-
- layout.separator()
-
- layout.operator("particle.remove_doubles")
- layout.operator("particle.delete")
-
- if particle_edit.select_mode == 'POINT':
- layout.operator("particle.subdivide")
-
layout.operator("particle.unify_length")
- layout.operator("particle.rekey")
- layout.operator("particle.weight_set")
-
- layout.separator()
-
- layout.menu("VIEW3D_MT_particle_showhide")
-
-
-class VIEW3D_MT_particle_specials(Menu):
- bl_label = "Specials"
-
- def draw(self, context):
- layout = self.layout
-
- particle_edit = context.tool_settings.particle_edit
-
- layout.operator("particle.rekey")
- layout.operator("particle.delete")
- layout.operator("particle.remove_doubles")
layout.operator("particle.unify_length")
-
- if particle_edit.select_mode == 'POINT':
- layout.operator("particle.subdivide")
-
- layout.operator("particle.weight_set")
- layout.separator()
-
- layout.operator("particle.mirror")
-
- if particle_edit.select_mode == 'POINT':
- layout.separator()
- layout.operator("particle.select_roots")
- layout.operator("particle.select_tips")
-
- layout.separator()
-
- layout.operator("particle.select_random")
-
- layout.separator()
-
- layout.operator("particle.select_more")
- layout.operator("particle.select_less")
-
- layout.separator()
-
- layout.operator("particle.select_all").action = 'TOGGLE'
- layout.operator("particle.select_linked")
- layout.operator("particle.select_all", text="Inverse").action = 'INVERT'
-
-
-class VIEW3D_MT_particle_showhide(ShowHideMenu, Menu):
- _operator_name = "particle"
-
# ********** Pose Menu **********
settings = self.paint_settings(context)
brush = settings.brush
- if not context.particle_edit_object:
- col = layout.split().column()
- col.template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8)
-
- # Particle Mode #
- if context.particle_edit_object:
- tool = settings.tool
-
- layout.column().prop(settings, "tool", expand=True)
-
- if tool != 'NONE':
- col = layout.column()
- col.prop(brush, "size", slider=True)
- if tool != 'ADD':
- col.prop(brush, "strength", slider=True)
-
- if tool == 'ADD':
- col.prop(brush, "count")
- col = layout.column()
- col.prop(settings, "use_default_interpolate")
- col.prop(brush, "steps", slider=True)
- col.prop(settings, "default_key_count", slider=True)
- elif tool == 'LENGTH':
- layout.prop(brush, "length_mode", expand=True)
- elif tool == 'PUFF':
- layout.prop(brush, "puff_mode", expand=True)
- layout.prop(brush, "use_puff_volume")
+ col = layout.split().column()
+ col.template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8)
# Sculpt Mode #
- elif context.sculpt_object and brush:
+ if context.sculpt_object and brush:
capabilities = brush.sculpt_capabilities
col = layout.column()
@classmethod
def poll(cls, context):
settings = cls.paint_settings(context)
- return (settings is not None) and (not isinstance(settings, bpy.types.ParticleEdit))
+ return (settings is not None)
def draw(self, context):
layout = self.layout
props.value = i
-class VIEW3D_PT_tools_particlemode(View3DPanel, Panel):
- """Default tools for particle mode"""
- bl_context = "particlemode"
- bl_label = "Options"
- bl_category = "Tools"
-
- def draw(self, context):
- layout = self.layout
-
- pe = context.tool_settings.particle_edit
- ob = pe.object
-
- layout.prop(pe, "type", text="")
-
- ptcache = None
-
- if pe.type == 'PARTICLES':
- if ob.particle_systems:
- if len(ob.particle_systems) > 1:
- layout.template_list("UI_UL_list", "particle_systems", ob, "particle_systems",
- ob.particle_systems, "active_index", rows=2, maxrows=3)
-
- ptcache = ob.particle_systems.active.point_cache
- else:
- for md in ob.modifiers:
- if md.type == pe.type:
- ptcache = md.point_cache
-
- if ptcache and len(ptcache.point_caches) > 1:
- layout.template_list("UI_UL_list", "particles_point_caches", ptcache, "point_caches",
- ptcache.point_caches, "active_index", rows=2, maxrows=3)
-
- if not pe.is_editable:
- layout.label(text="Point cache must be baked")
- layout.label(text="in memory to enable editing!")
-
- col = layout.column(align=True)
- if pe.is_hair:
- col.active = pe.is_editable
- col.prop(pe, "use_emitter_deflect", text="Deflect emitter")
- sub = col.row(align=True)
- sub.active = pe.use_emitter_deflect
- sub.prop(pe, "emitter_distance", text="Distance")
-
- col = layout.column(align=True)
- col.active = pe.is_editable
- col.label(text="Keep:")
- col.prop(pe, "use_preserve_length", text="Lengths")
- col.prop(pe, "use_preserve_root", text="Root")
- if not pe.is_hair:
- col.label(text="Correct:")
- col.prop(pe, "use_auto_velocity", text="Velocity")
- col.prop(ob.data, "use_mirror_x")
-
- col.prop(pe, "shape_object")
- col.operator("particle.shape_cut")
-
- col = layout.column(align=True)
- col.active = pe.is_editable
- col.label(text="Draw:")
- col.prop(pe, "draw_step", text="Path Steps")
- if pe.is_hair:
- col.prop(pe, "show_particles", text="Children")
- else:
- if pe.type == 'PARTICLES':
- col.prop(pe, "show_particles", text="Particles")
- col.prop(pe, "use_fade_time")
- sub = col.row(align=True)
- sub.active = pe.use_fade_time
- sub.prop(pe, "fade_frames", slider=True)
-
-
# Grease Pencil drawing tools
class VIEW3D_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
bl_space_type = 'VIEW_3D'
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_actuator_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_anim_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_armature_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_boid_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_brush_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_camera_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cloth_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_object_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_outliner_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_packedFile_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_particle_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_property_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_rigidbody_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_scene_types.h
+++ /dev/null
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2009 by Janne Karhu.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __BKE_BOIDS_H__
-#define __BKE_BOIDS_H__
-
-/** \file BKE_boids.h
- * \ingroup bke
- * \since 2009
- * \author Janne Karhu
- */
-
-#include "DNA_boid_types.h"
-
-struct RNG;
-
-typedef struct BoidBrainData {
- struct ParticleSimulationData *sim;
- struct ParticleSettings *part;
- float timestep, cfra, dfra;
- float wanted_co[3], wanted_speed;
-
- /* Goal stuff */
- struct Object *goal_ob;
- float goal_co[3];
- float goal_nor[3];
- float goal_priority;
-
- struct RNG *rng;
-} BoidBrainData;
-
-void boids_precalc_rules(struct ParticleSettings *part, float cfra);
-void boid_brain(BoidBrainData *bbd, int p, struct ParticleData *pa);
-void boid_body(BoidBrainData *bbd, struct ParticleData *pa);
-void boid_default_settings(BoidSettings *boids);
-BoidRule *boid_new_rule(int type);
-BoidState *boid_new_state(BoidSettings *boids);
-BoidState *boid_duplicate_state(BoidSettings *boids, BoidState *state);
-void boid_free_settings(BoidSettings *boids);
-BoidSettings *boid_copy_settings(BoidSettings *boids);
-BoidState *boid_get_current_state(BoidSettings *boids);
-#endif
void bvhtree_update_from_cloth(struct ClothModifierData *clmd, bool moving);
void bvhselftree_update_from_cloth(struct ClothModifierData *clmd, bool moving);
-// needed for button_object.c
-void cloth_clear_cache (struct Object *ob, struct ClothModifierData *clmd, float framenr );
-
// needed for cloth.c
int cloth_add_spring (struct ClothModifierData *clmd, unsigned int indexA, unsigned int indexB, float restlength, int spring_type);
CTX_MODE_PAINT_WEIGHT,
CTX_MODE_PAINT_VERTEX,
CTX_MODE_PAINT_TEXTURE,
- CTX_MODE_PARTICLE,
CTX_MODE_OBJECT
};
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd);
void dynamicPaint_freeSurfaceData(struct DynamicPaintSurface *surface);
-void dynamicPaint_cacheUpdateFrames(struct DynamicPaintSurface *surface);
bool dynamicPaint_surfaceHasColorPreview(struct DynamicPaintSurface *surface);
bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, struct Object *ob, int output);
void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface);
struct Scene;
struct ListBase;
struct Group;
-struct ParticleSimulationData;
-struct ParticleData;
-struct ParticleKey;
+struct PointCacheKey;
struct EffectorWeights *BKE_add_effector_weights(struct Group *group);
struct PartDeflect *object_add_collision_fields(int type);
unsigned int flag;
int index;
-
- struct ParticleSystem *psys; /* particle system the point belongs to */
} EffectedPoint;
typedef struct GuideEffectorData {
struct Scene *scene;
struct Object *ob;
- struct ParticleSystem *psys;
struct SurfaceModifierData *surmd;
struct PartDeflect *pd;
} EffectorCache;
void free_partdeflect(struct PartDeflect *pd);
-struct ListBase *pdInitEffectors(struct Scene *scene, struct Object *ob_src, struct ParticleSystem *psys_src, struct EffectorWeights *weights, bool precalc);
+struct ListBase *pdInitEffectors(struct Scene *scene, struct Object *ob_src, struct EffectorWeights *weights, bool precalc);
void pdEndEffectors(struct ListBase **effectors);
void pdPrecalculateEffectors(struct ListBase *effectors);
void pdDoEffectors(struct ListBase *effectors, struct ListBase *colliders, struct EffectorWeights *weights, struct EffectedPoint *point, float *force, float *impulse);
-void pd_point_from_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, struct EffectedPoint *point);
void pd_point_from_loc(struct Scene *scene, float *loc, float *vel, int index, struct EffectedPoint *point);
void pd_point_from_soft(struct Scene *scene, float *loc, float *vel, int index, struct EffectedPoint *point);
-/* needed for boids */
-float effector_falloff(struct EffectorCache *eff, struct EffectorData *efd, struct EffectedPoint *point, struct EffectorWeights *weights);
int closest_point_on_surface(SurfaceModifierData *surmd, const float co[3], float surface_co[3], float surface_nor[3], float surface_vel[3]);
int get_effector_data(struct EffectorCache *eff, struct EffectorData *efd, struct EffectedPoint *point, int real_velocity);
struct ListBase *which_libbase(struct Main *mainlib, short type);
-#define MAX_LIBARRAY 34
+#define MAX_LIBARRAY 33
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
/* Main API */
ListBase action;
ListBase nodetree;
ListBase brush;
- ListBase particle;
ListBase palettes;
ListBase paintcurves;
ListBase wm;
bool modifiers_isModifierEnabled(struct Object *ob, int modifierType);
bool modifiers_isSoftbodyEnabled(struct Object *ob);
bool modifiers_isClothEnabled(struct Object *ob);
-bool modifiers_isParticleEnabled(struct Object *ob);
struct Object *modifiers_isDeformedByArmature(struct Object *ob);
struct Object *modifiers_isDeformedByLattice(struct Object *ob);
void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src);
struct SoftBody *copy_softbody(const struct SoftBody *sb, bool copy_caches);
struct BulletSoftBody *copy_bulletsoftbody(struct BulletSoftBody *sb);
-struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys);
-void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src);
void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src);
-void BKE_object_free_particlesystems(struct Object *ob);
void BKE_object_free_softbody(struct Object *ob);
void BKE_object_free_bulletsoftbody(struct Object *ob);
void BKE_object_free_curve_cache(struct Object *ob);
+++ /dev/null
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2007 by Janne Karhu.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Adaptive time step
- * Classical SPH
- * Copyright 2011-2012 AutoCRC
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __BKE_PARTICLE_H__
-#define __BKE_PARTICLE_H__
-
-/** \file BKE_particle.h
- * \ingroup bke
- */
-
-#include "BLI_utildefines.h"
-
-#include "DNA_particle_types.h"
-#include "DNA_object_types.h"
-
-#include "BKE_customdata.h"
-
-struct ParticleSystemModifierData;
-struct ParticleSystem;
-struct ParticleKey;
-struct ParticleSettings;
-
-struct Main;
-struct Object;
-struct Scene;
-struct DerivedMesh;
-struct ModifierData;
-struct MTFace;
-struct MCol;
-struct MFace;
-struct MVert;
-struct LatticeDeformData;
-struct LinkNode;
-struct KDTree;
-struct RNG;
-struct BVHTreeRay;
-struct BVHTreeRayHit;
-struct EdgeHash;
-
-#define PARTICLE_P ParticleData * pa; int p
-#define LOOP_PARTICLES for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++)
-#define LOOP_EXISTING_PARTICLES for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) if (!(pa->flag & PARS_UNEXIST))
-#define LOOP_SHOWN_PARTICLES for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) if (!(pa->flag & (PARS_UNEXIST | PARS_NO_DISP)))
-/* OpenMP: Can only advance one variable within loop definition. */
-#define LOOP_DYNAMIC_PARTICLES for (p = 0; p < psys->totpart; p++) if ((pa = psys->particles + p)->state.time > 0.0f)
-
-/* fast but sure way to get the modifier*/
-#define PARTICLE_PSMD ParticleSystemModifierData * psmd = sim->psmd ? sim->psmd : psys_get_modifier(sim->ob, sim->psys)
-
-/* common stuff that many particle functions need */
-typedef struct ParticleSimulationData {
- struct Scene *scene;
- struct Object *ob;
- struct ParticleSystem *psys;
- struct ParticleSystemModifierData *psmd;
- struct ListBase *colliders;
- /* Courant number. This is used to implement an adaptive time step. Only the
- * maximum value per time step is important. Only sph_integrate makes use of
- * this at the moment. Other solvers could, too. */
- float courant_num;
-} ParticleSimulationData;
-
-typedef struct SPHData {
- ParticleSystem *psys[10];
- ParticleData *pa;
- float mass;
- struct EdgeHash *eh;
- float *gravity;
- float hfac;
- /* Average distance to neighbours (other particles in the support domain),
- * for calculating the Courant number (adaptive time step). */
- int pass;
- float element_size;
- float flow[3];
-
- /* Integrator callbacks. This allows different SPH implementations. */
- void (*force_cb) (void *sphdata_v, ParticleKey *state, float *force, float *impulse);
- void (*density_cb) (void *rangedata_v, int index, const float co[3], float squared_dist);
-} SPHData;
-
-typedef struct ParticleTexture {
- float ivel; /* used in reset */
- float time, life, exist, size; /* used in init */
- float damp, gravity, field; /* used in physics */
- float length, clump, kink_freq, kink_amp, effector; /* used in path caching */
- float rough1, rough2, roughe; /* used in path caching */
-} ParticleTexture;
-
-typedef struct ParticleSeam {
- float v0[3], v1[3];
- float nor[3], dir[3], tan[3];
- float length2;
-} ParticleSeam;
-
-typedef struct ParticleCacheKey {
- float co[3];
- float vel[3];
- float rot[4];
- float col[3];
- float time;
- int segments;
-} ParticleCacheKey;
-
-typedef struct ParticleThreadContext {
- /* shared */
- struct ParticleSimulationData sim;
- struct DerivedMesh *dm;
- struct Material *ma;
-
- /* distribution */
- struct KDTree *tree;
-
- struct ParticleSeam *seams;
- int totseam;
-
- float *jit, *jitoff, *weight;
- float maxweight;
- int *index, *skip, jitlevel;
-
- int cfrom, distr;
-
- struct ParticleData *tpars;
-
- /* path caching */
- int editupdate, between, segments, extra_segments;
- int totchild, totparent, parent_pass;
-
- float cfra;
-
- float *vg_length, *vg_clump, *vg_kink;
- float *vg_rough1, *vg_rough2, *vg_roughe;
- float *vg_effector;
-
- struct CurveMapping *clumpcurve;
- struct CurveMapping *roughcurve;
-} ParticleThreadContext;
-
-typedef struct ParticleTask {
- ParticleThreadContext *ctx;
- struct RNG *rng, *rng_path;
- int begin, end;
-} ParticleTask;
-
-typedef struct ParticleBillboardData {
- struct Object *ob;
- float vec[3], vel[3];
- float offset[2];
- float size[2];
- float tilt, random, time;
- int uv[3];
- int lock, num;
- int totnum;
- int lifetime;
- short align, uv_split, anim, split_offset;
-} ParticleBillboardData;
-
-typedef struct ParticleCollisionElement {
- /* pointers to original data */
- float *x[3], *v[3];
-
- /* values interpolated from original data*/
- float x0[3], x1[3], x2[3], p[3];
-
- /* results for found intersection point */
- float nor[3], vel[3], uv[2];
-
- /* count of original data (1-4) */
- int tot;
-
- /* index of the collision face */
- int index;
-
- /* flags for inversed normal / particle already inside element at start */
- short inv_nor, inside;
-} ParticleCollisionElement;
-
-/* container for moving data between deflet_particle and particle_intersect_face */
-typedef struct ParticleCollision {
- struct Object *current;
- struct Object *hit;
- struct Object *prev;
- struct Object *skip;
- struct Object *emitter;
-
- struct CollisionModifierData *md; // collision modifier for current object;
-
- float f; // time factor of previous collision, needed for substracting face velocity
- float fac1, fac2;
-
- float cfra, old_cfra;
-
- float original_ray_length; //original length of co2-co1, needed for collision time evaluation
-
- int prev_index;
-
- ParticleCollisionElement pce;
-
- /* total_time is the amount of time in this subframe
- * inv_total_time is the opposite
- * inv_timestep is the inverse of the amount of time in this frame */
- float total_time, inv_total_time, inv_timestep;
-
- float radius;
- float co1[3], co2[3];
- float ve1[3], ve2[3];
-
- float acc[3], boid_z;
-
- int boid;
-} ParticleCollision;
-
-typedef struct ParticleDrawData {
- float *vdata, *vd; /* vertice data */
- float *ndata, *nd; /* normal data */
- float *cdata, *cd; /* color data */
- float *vedata, *ved; /* velocity data */
- float *ma_col;
- int tot_vec_size, flag;
- int totpoint, totve;
-} ParticleDrawData;
-
-#define PARTICLE_DRAW_DATA_UPDATED 1
-
-#define PSYS_FRAND_COUNT 1024
-extern unsigned int PSYS_FRAND_SEED_OFFSET[PSYS_FRAND_COUNT];
-extern unsigned int PSYS_FRAND_SEED_MULTIPLIER[PSYS_FRAND_COUNT];
-extern float PSYS_FRAND_BASE[PSYS_FRAND_COUNT];
-
-void psys_init_rng(void);
-
-BLI_INLINE float psys_frand(ParticleSystem *psys, unsigned int seed)
-{
- /* XXX far from ideal, this simply scrambles particle random numbers a bit
- * to avoid obvious correlations.
- * Can't use previous psys->frand arrays because these require initialization
- * inside psys_check_enabled, which wreaks havok in multithreaded depgraph updates.
- */
- unsigned int offset = PSYS_FRAND_SEED_OFFSET[psys->seed % PSYS_FRAND_COUNT];
- unsigned int multiplier = PSYS_FRAND_SEED_MULTIPLIER[psys->seed % PSYS_FRAND_COUNT];
- return PSYS_FRAND_BASE[(offset + seed * multiplier) % PSYS_FRAND_COUNT];
-}
-
-BLI_INLINE void psys_frand_vec(ParticleSystem *psys, unsigned int seed, float vec[3])
-{
- unsigned int offset = PSYS_FRAND_SEED_OFFSET[psys->seed % PSYS_FRAND_COUNT];
- unsigned int multiplier = PSYS_FRAND_SEED_MULTIPLIER[psys->seed % PSYS_FRAND_COUNT];
- vec[0] = PSYS_FRAND_BASE[(offset + (seed + 0) * multiplier) % PSYS_FRAND_COUNT];
- vec[1] = PSYS_FRAND_BASE[(offset + (seed + 1) * multiplier) % PSYS_FRAND_COUNT];
- vec[2] = PSYS_FRAND_BASE[(offset + (seed + 2) * multiplier) % PSYS_FRAND_COUNT];
-}
-
-/* ----------- functions needed outside particlesystem ---------------- */
-/* particle.c */
-int count_particles(struct ParticleSystem *psys);
-int count_particles_mod(struct ParticleSystem *psys, int totgr, int cur);
-
-int psys_get_child_number(struct Scene *scene, struct ParticleSystem *psys);
-int psys_get_tot_child(struct Scene *scene, struct ParticleSystem *psys);
-
-struct ParticleSystem *psys_get_current(struct Object *ob);
-/* for rna */
-short psys_get_current_num(struct Object *ob);
-void psys_set_current_num(Object *ob, int index);
-/* UNUSED */
-// struct Object *psys_find_object(struct Scene *scene, struct ParticleSystem *psys);
-
-struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim);
-
-bool psys_in_edit_mode(struct Scene *scene, struct ParticleSystem *psys);
-bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys);
-bool psys_check_edited(struct ParticleSystem *psys);
-
-void psys_check_group_weights(struct ParticleSettings *part);
-int psys_uses_gravity(struct ParticleSimulationData *sim);
-
-/* free */
-void BKE_particlesettings_free(struct ParticleSettings *part);
-void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit);
-void psys_free(struct Object *ob, struct ParticleSystem *psys);
-
-void psys_render_set(struct Object *ob, struct ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], int winx, int winy, int timeoffset);
-void psys_render_restore(struct Object *ob, struct ParticleSystem *psys);
-bool psys_render_simplify_params(struct ParticleSystem *psys, struct ChildParticle *cpa, float *params);
-
-void psys_interpolate_uvs(const struct MTFace *tface, int quad, const float w[4], float uvco[2]);
-void psys_interpolate_mcol(const struct MCol *mcol, int quad, const float w[4], struct MCol *mc);
-
-void copy_particle_key(struct ParticleKey *to, struct ParticleKey *from, int time);
-
-CustomDataMask psys_emitter_customdata_mask(struct ParticleSystem *psys);
-void psys_particle_on_emitter(struct ParticleSystemModifierData *psmd, int distr, int index, int index_dmcache,
- float fuv[4], float foffset, float vec[3], float nor[3],
- float utan[3], float vtan[3], float orco[3], float ornor[3]);
-struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct ParticleSystem *psys);
-
-struct ModifierData *object_add_particle_system(struct Scene *scene, struct Object *ob, const char *name);
-void object_remove_particle_system(struct Scene *scene, struct Object *ob);
-struct ParticleSettings *psys_new_settings(const char *name, struct Main *main);
-struct ParticleSettings *BKE_particlesettings_copy(struct ParticleSettings *part);
-void BKE_particlesettings_make_local(struct ParticleSettings *part);
-
-void psys_reset(struct ParticleSystem *psys, int mode);
-
-void psys_find_parents(struct ParticleSimulationData *sim);
-
-void psys_cache_paths(struct ParticleSimulationData *sim, float cfra);
-void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra);
-void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, int editupdate);
-int do_guides(struct ParticleSettings *part, struct ListBase *effectors, ParticleKey *state, int pa_num, float time);
-void precalc_guides(struct ParticleSimulationData *sim, struct ListBase *effectors);
-float psys_get_timestep(struct ParticleSimulationData *sim);
-float psys_get_child_time(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *birthtime, float *dietime);
-float psys_get_child_size(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *pa_time);
-void psys_get_particle_on_path(struct ParticleSimulationData *sim, int pa_num, struct ParticleKey *state, const bool vel);
-int psys_get_particle_state(struct ParticleSimulationData *sim, int p, struct ParticleKey *state, int always);
-
-/* child paths */
-void BKE_particlesettings_clump_curve_init(struct ParticleSettings *part);
-void BKE_particlesettings_rough_curve_init(struct ParticleSettings *part);
-void psys_apply_child_modifiers(struct ParticleThreadContext *ctx, struct ListBase *modifiers,
- struct ChildParticle *cpa, struct ParticleTexture *ptex, const float orco[3], const float ornor[3], float hairmat[4][4],
- struct ParticleCacheKey *keys, struct ParticleCacheKey *parent_keys, const float parent_orco[3]);
-
-void psys_sph_init(struct ParticleSimulationData *sim, struct SPHData *sphdata);
-void psys_sph_finalise(struct SPHData *sphdata);
-void psys_sph_density(struct BVHTree *tree, struct SPHData *data, float co[3], float vars[2]);
-
-/* for anim.c */
-void psys_get_dupli_texture(struct ParticleSystem *psys, struct ParticleSettings *part,
- struct ParticleSystemModifierData *psmd, struct ParticleData *pa, struct ChildParticle *cpa,
- float uv[2], float orco[3]);
-void psys_get_dupli_path_transform(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ChildParticle *cpa,
- struct ParticleCacheKey *cache, float mat[4][4], float *scale);
-
-void psys_thread_context_init(struct ParticleThreadContext *ctx, struct ParticleSimulationData *sim);
-void psys_thread_context_free(struct ParticleThreadContext *ctx);
-void psys_tasks_create(struct ParticleThreadContext *ctx, int startpart, int endpart, struct ParticleTask **r_tasks, int *r_numtasks);
-void psys_tasks_free(struct ParticleTask *tasks, int numtasks);
-
-void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]);
-void psys_apply_hair_lattice(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
-
-/* particle_system.c */
-struct ParticleSystem *psys_get_target_system(struct Object *ob, struct ParticleTarget *pt);
-void psys_count_keyed_targets(struct ParticleSimulationData *sim);
-void psys_update_particle_tree(struct ParticleSystem *psys, float cfra);
-void psys_changed_type(struct Object *ob, struct ParticleSystem *psys);
-
-void psys_make_temp_pointcache(struct Object *ob, struct ParticleSystem *psys);
-void psys_get_pointcache_start_end(struct Scene *scene, ParticleSystem *psys, int *sfra, int *efra);
-
-void psys_check_boid_data(struct ParticleSystem *psys);
-
-void psys_get_birth_coords(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, float dtime, float cfra);
-
-void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
-
-/* Callback format for performing operations on ID-pointers for particle systems */
-typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys, struct ID **idpoin, void *userdata, int cd_flag);
-
-void BKE_particlesystem_id_loop(struct ParticleSystem *psys, ParticleSystemIDFunc func, void *userdata);
-
-/* ----------- functions needed only inside particlesystem ------------ */
-/* particle.c */
-void psys_disable_all(struct Object *ob);
-void psys_enable_all(struct Object *ob);
-
-void free_hair(struct Object *ob, struct ParticleSystem *psys, int dynamics);
-void free_keyed_keys(struct ParticleSystem *psys);
-void psys_free_particles(struct ParticleSystem *psys);
-void psys_free_children(struct ParticleSystem *psys);
-
-void psys_interpolate_particle(short type, struct ParticleKey keys[4], float dt, struct ParticleKey *result, bool velocity);
-void psys_vec_rot_to_face(struct DerivedMesh *dm, struct ParticleData *pa, float vec[3]);
-void psys_mat_hair_to_object(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]);
-void psys_mat_hair_to_global(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]);
-void psys_mat_hair_to_orco(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]);
-
-float psys_get_dietime_from_cache(struct PointCache *cache, int index);
-
-void psys_free_pdd(struct ParticleSystem *psys);
-
-float *psys_cache_vgroup(struct DerivedMesh *dm, struct ParticleSystem *psys, int vgroup);
-void psys_get_texture(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleTexture *ptex, int event, float cfra);
-void psys_interpolate_face(struct MVert *mvert, struct MFace *mface, struct MTFace *tface,
- float (*orcodata)[3], float w[4], float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3]);
-float psys_particle_value_from_verts(struct DerivedMesh *dm, short from, struct ParticleData *pa, float *values);
-void psys_get_from_key(struct ParticleKey *key, float loc[3], float vel[3], float rot[4], float *time);
-
-/* BLI_bvhtree_ray_cast callback */
-void BKE_psys_collision_neartest_cb(void *userdata, int index, const struct BVHTreeRay *ray, struct BVHTreeRayHit *hit);
-void psys_particle_on_dm(struct DerivedMesh *dm_final, int from, int index, int index_dmcache,
- const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3]);
-
-/* particle_system.c */
-void distribute_particles(struct ParticleSimulationData *sim, int from);
-void initialize_particle(struct ParticleSimulationData *sim, struct ParticleData *pa);
-void psys_calc_dmcache(struct Object *ob, struct DerivedMesh *dm_final, struct DerivedMesh *dm_deformed, struct ParticleSystem *psys);
-int psys_particle_dm_face_lookup(struct DerivedMesh *dm_final, struct DerivedMesh *dm_deformed, int findex, const float fw[4], struct LinkNode **poly_nodes);
-
-void reset_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, float dtime, float cfra);
-
-float psys_get_current_display_percentage(struct ParticleSystem *psys);
-
-typedef struct ParticleRenderElem {
- int curchild, totchild, reduce;
- float lambda, t, scalemin, scalemax;
-} ParticleRenderElem;
-
-typedef struct ParticleRenderData {
- ChildParticle *child;
- ParticleCacheKey **pathcache;
- ParticleCacheKey **childcache;
- ListBase pathcachebufs, childcachebufs;
- int totchild, totcached, totchildcache;
- struct DerivedMesh *dm;
- int totdmvert, totdmedge, totdmface;
-
- float mat[4][4];
- float viewmat[4][4], winmat[4][4];
- int winx, winy;
-
- int do_simplify;
- int timeoffset;
- ParticleRenderElem *elems;
-
- /* ORIGINDEX */
- const int *index_mf_to_mpoly;
- const int *index_mp_to_orig;
-} ParticleRenderData;
-
-/* psys_reset */
-#define PSYS_RESET_ALL 1
-#define PSYS_RESET_DEPSGRAPH 2
-/* #define PSYS_RESET_CHILDREN 3 */ /*UNUSED*/
-#define PSYS_RESET_CACHE_MISS 4
-
-/* index_dmcache */
-#define DMCACHE_NOTFOUND -1
-#define DMCACHE_ISCHILD -2
-
-/* **** Depsgraph evaluation **** */
-
-struct EvaluationContext;
-
-void BKE_particle_system_eval(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob,
- struct ParticleSystem *psys);
-
-#endif
+++ /dev/null
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2006 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Campbell Barton <ideasman42@gmail.com>
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __BKE_POINTCACHE_H__
-#define __BKE_POINTCACHE_H__
-
-/** \file BKE_pointcache.h
- * \ingroup bke
- */
-
-#include "DNA_ID.h"
-#include "DNA_dynamicpaint_types.h"
-#include "DNA_object_force.h"
-#include "DNA_boid_types.h"
-#include <stdio.h> /* for FILE */
-
-/* Point cache clearing option, for BKE_ptcache_id_clear, before
- * and after are non inclusive (they wont remove the cfra) */
-#define PTCACHE_CLEAR_ALL 0
-#define PTCACHE_CLEAR_FRAME 1
-#define PTCACHE_CLEAR_BEFORE 2
-#define PTCACHE_CLEAR_AFTER 3
-
-/* Point cache reset options */
-#define PTCACHE_RESET_DEPSGRAPH 0
-#define PTCACHE_RESET_BAKED 1
-#define PTCACHE_RESET_OUTDATED 2
-/* #define PTCACHE_RESET_FREE 3 */ /*UNUSED*/
-
-/* Add the blendfile name after blendcache_ */
-#define PTCACHE_EXT ".bphys"
-#define PTCACHE_PATH "blendcache_"
-
-/* File open options, for BKE_ptcache_file_open */
-#define PTCACHE_FILE_READ 0
-#define PTCACHE_FILE_WRITE 1
-#define PTCACHE_FILE_UPDATE 2
-
-/* PTCacheID types */
-#define PTCACHE_TYPE_SOFTBODY 0
-#define PTCACHE_TYPE_PARTICLES 1
-#define PTCACHE_TYPE_CLOTH 2
-#define PTCACHE_TYPE_SMOKE_DOMAIN 3
-#define PTCACHE_TYPE_SMOKE_HIGHRES 4
-#define PTCACHE_TYPE_DYNAMICPAINT 5
-#define PTCACHE_TYPE_RIGIDBODY 6
-
-/* high bits reserved for flags that need to be stored in file */
-#define PTCACHE_TYPEFLAG_COMPRESS (1 << 16)
-#define PTCACHE_TYPEFLAG_EXTRADATA (1 << 17)
-
-#define PTCACHE_TYPEFLAG_TYPEMASK 0x0000FFFF
-#define PTCACHE_TYPEFLAG_FLAGMASK 0xFFFF0000
-
-/* PTCache read return code */
-#define PTCACHE_READ_EXACT 1
-#define PTCACHE_READ_INTERPOLATED 2
-#define PTCACHE_READ_OLD 3
-
-/* Structs */
-struct ClothModifierData;
-struct ListBase;
-struct Main;
-struct Object;
-struct ParticleKey;
-struct ParticleSystem;
-struct PointCache;
-struct Scene;
-struct SmokeModifierData;
-struct SoftBody;
-struct RigidBodyWorld;
-
-struct OpenVDBReader;
-struct OpenVDBWriter;
-
-/* temp structure for read/write */
-typedef struct PTCacheData {
- unsigned int index;
- float loc[3];
- float vel[3];
- float rot[4];
- float ave[3];
- float size;
- float times[3];
- struct BoidData boids;
-} PTCacheData;
-
-typedef struct PTCacheFile {
- FILE *fp;
-
- int frame, old_format;
- unsigned int totpoint, type;
- unsigned int data_types, flag;
-
- struct PTCacheData data;
- void *cur[BPHYS_TOT_DATA];
-} PTCacheFile;
-
-#define PTCACHE_VEL_PER_SEC 1
-
-enum {
- PTCACHE_FILE_PTCACHE = 0,
- PTCACHE_FILE_OPENVDB = 1,
-};
-
-typedef struct PTCacheID {
- struct PTCacheID *next, *prev;
-
- struct Scene *scene;
- struct Object *ob;
- void *calldata;
- unsigned int type, file_type;
- unsigned int stack_index;
- unsigned int flag;
-
- unsigned int default_step;
- unsigned int max_step;
-
- /* flags defined in DNA_object_force.h */
- unsigned int data_types, info_types;
-
- /* copies point data to cache data */
- int (*write_point)(int index, void *calldata, void **data, int cfra);
- /* copies cache cata to point data */
- void (*read_point)(int index, void *calldata, void **data, float cfra, float *old_data);
- /* interpolated between previously read point data and cache data */
- void (*interpolate_point)(int index, void *calldata, void **data, float cfra, float cfra1, float cfra2, float *old_data);
-
- /* copies point data to cache data */
- int (*write_stream)(PTCacheFile *pf, void *calldata);
- /* copies cache cata to point data */
- int (*read_stream)(PTCacheFile *pf, void *calldata);
-
- /* copies point data to cache data */
- int (*write_openvdb_stream)(struct OpenVDBWriter *writer, void *calldata);
- /* copies cache cata to point data */
- int (*read_openvdb_stream)(struct OpenVDBReader *reader, void *calldata);
-
- /* copies custom extradata to cache data */
- void (*write_extra_data)(void *calldata, struct PTCacheMem *pm, int cfra);
- /* copies custom extradata to cache data */
- void (*read_extra_data)(void *calldata, struct PTCacheMem *pm, float cfra);
- /* copies custom extradata to cache data */
- void (*interpolate_extra_data)(void *calldata, struct PTCacheMem *pm, float cfra, float cfra1, float cfra2);
-
- /* total number of simulated points (the cfra parameter is just for using same function pointer with totwrite) */
- int (*totpoint)(void *calldata, int cfra);
- /* report error if number of points does not match */
- void (*error)(void *calldata, const char *message);
- /* number of points written for current cache frame */
- int (*totwrite)(void *calldata, int cfra);
-
- int (*write_header)(PTCacheFile *pf);
- int (*read_header)(PTCacheFile *pf);
-
- struct PointCache *cache;
- /* used for setting the current cache from ptcaches list */
- struct PointCache **cache_ptr;
- struct ListBase *ptcaches;
-} PTCacheID;
-
-typedef struct PTCacheBaker {
- struct Main *main;
- struct Scene *scene;
- int bake;
- int render;
- int anim_init;
- int quick_step;
- struct PTCacheID pid;
-
- void (*update_progress)(void *data, float progress, int *cancel);
- void *bake_job;
-} PTCacheBaker;
-
-/* PTCacheEditKey->flag */
-#define PEK_SELECT 1
-#define PEK_TAG 2
-#define PEK_HIDE 4
-#define PEK_USE_WCO 8
-
-typedef struct PTCacheEditKey {
- float *co;
- float *vel;
- float *rot;
- float *time;
-
- float world_co[3];
- float ftime;
- float length;
- short flag;
-} PTCacheEditKey;
-
-/* PTCacheEditPoint->flag */
-#define PEP_TAG 1
-#define PEP_EDIT_RECALC 2
-#define PEP_TRANSFORM 4
-#define PEP_HIDE 8
-
-typedef struct PTCacheEditPoint {
- struct PTCacheEditKey *keys;
- int totkey;
- short flag;
-} PTCacheEditPoint;
-
-typedef struct PTCacheUndo {
- struct PTCacheUndo *next, *prev;
- struct PTCacheEditPoint *points;
-
- /* particles stuff */
- struct ParticleData *particles;
- struct KDTree *emitter_field;
- float *emitter_cosnos;
- int psys_flag;
-
- /* cache stuff */
- struct ListBase mem_cache;
-
- int totpoint;
- char name[64];
-} PTCacheUndo;
-
-typedef struct PTCacheEdit {
- ListBase undo;
- struct PTCacheUndo *curundo;
- PTCacheEditPoint *points;
-
- struct PTCacheID pid;
-
- /* particles stuff */
- struct ParticleSystem *psys;
- struct KDTree *emitter_field;
- float *emitter_cosnos; /* localspace face centers and normals (average of its verts), from the derived mesh */
- int *mirror_cache;
-
- struct ParticleCacheKey **pathcache; /* path cache (runtime) */
- ListBase pathcachebufs;
-
- int totpoint, totframes, totcached, edited;
-
- unsigned char sel_col[3];
- unsigned char nosel_col[3];
-} PTCacheEdit;
-
-/* Particle functions */
-void BKE_ptcache_make_particle_key(struct ParticleKey *key, int index, void **data, float time);
-
-/**************** Creating ID's ****************************/
-void BKE_ptcache_id_from_softbody(PTCacheID *pid, struct Object *ob, struct SoftBody *sb);
-void BKE_ptcache_id_from_particles(PTCacheID *pid, struct Object *ob, struct ParticleSystem *psys);
-void BKE_ptcache_id_from_cloth(PTCacheID *pid, struct Object *ob, struct ClothModifierData *clmd);
-void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd);
-void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, struct Object *ob, struct DynamicPaintSurface *surface);
-void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, struct Object *ob, struct RigidBodyWorld *rbw);
-
-void BKE_ptcache_ids_from_object(struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis);
-
-/***************** Global funcs ****************************/
-void BKE_ptcache_remove(void);
-
-/************ ID specific functions ************************/
-void BKE_ptcache_id_clear(PTCacheID *id, int mode, unsigned int cfra);
-int BKE_ptcache_id_exist(PTCacheID *id, int cfra);
-int BKE_ptcache_id_reset(struct Scene *scene, PTCacheID *id, int mode);
-void BKE_ptcache_id_time(PTCacheID *pid, struct Scene *scene, float cfra, int *startframe, int *endframe, float *timescale);
-int BKE_ptcache_object_reset(struct Scene *scene, struct Object *ob, int mode);
-
-void BKE_ptcache_update_info(PTCacheID *pid);
-
-/*********** General cache reading/writing ******************/
-
-/* Size of cache data type. */
-int BKE_ptcache_data_size(int data_type);
-
-/* Is point with indes in memory cache */
-int BKE_ptcache_mem_index_find(struct PTCacheMem *pm, unsigned int index);
-
-/* Memory cache read/write helpers. */
-void BKE_ptcache_mem_pointers_init(struct PTCacheMem *pm);
-void BKE_ptcache_mem_pointers_incr(struct PTCacheMem *pm);
-int BKE_ptcache_mem_pointers_seek(int point_index, struct PTCacheMem *pm);
-
-/* Main cache reading call. */
-int BKE_ptcache_read(PTCacheID *pid, float cfra);
-
-/* Main cache writing call. */
-int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra);
-
-/******************* Allocate & free ***************/
-struct PointCache *BKE_ptcache_add(struct ListBase *ptcaches);
-void BKE_ptcache_free_mem(struct ListBase *mem_cache);
-void BKE_ptcache_free(struct PointCache *cache);
-void BKE_ptcache_free_list(struct ListBase *ptcaches);
-struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const struct ListBase *ptcaches_old, bool copy_data);
-
-/********************** Baking *********************/
-
-/* Bakes cache with cache_step sized jumps in time, not accurate but very fast. */
-void BKE_ptcache_quick_cache_all(struct Main *bmain, struct Scene *scene);
-
-/* Bake cache or simulate to current frame with settings defined in the baker. */
-void BKE_ptcache_bake(struct PTCacheBaker *baker);
-
-/* Convert disk cache to memory cache. */
-void BKE_ptcache_disk_to_mem(struct PTCacheID *pid);
-
-/* Convert memory cache to disk cache. */
-void BKE_ptcache_mem_to_disk(struct PTCacheID *pid);
-
-/* Convert disk cache to memory cache and vice versa. Clears the cache that was converted. */
-void BKE_ptcache_toggle_disk_cache(struct PTCacheID *pid);
-
-/* Rename all disk cache files with a new name. Doesn't touch the actual content of the files. */
-void BKE_ptcache_disk_cache_rename(struct PTCacheID *pid, const char *name_src, const char *name_dst);
-
-/* Loads simulation from external (disk) cache files. */
-void BKE_ptcache_load_external(struct PTCacheID *pid);
-
-/* Set correct flags after successful simulation step */
-void BKE_ptcache_validate(struct PointCache *cache, int framenr);
-
-/* Set correct flags after unsuccessful simulation step */
-void BKE_ptcache_invalidate(struct PointCache *cache);
-
-#endif
void BKE_rigidbody_aftertrans_update(struct Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle);
void BKE_rigidbody_sync_transforms(struct RigidBodyWorld *rbw, struct Object *ob, float ctime);
bool BKE_rigidbody_check_sim_running(struct RigidBodyWorld *rbw, float ctime);
-void BKE_rigidbody_cache_reset(struct RigidBodyWorld *rbw);
void BKE_rigidbody_rebuild_world(struct Scene *scene, float ctime);
void BKE_rigidbody_do_simulation(struct Scene *scene, float ctime);
void BKE_sca_actuators_id_loop(struct ListBase *atclist, SCAActuatorIDFunc func, void *userdata);
-const char *sca_state_name_get(Object *ob, short bit);
+const char *sca_state_name_get(struct Object *ob, short bit);
#endif
/* pass NULL to unlink again */
extern void sbSetInterruptCallBack(int (*f)(void));
-extern void SB_estimate_transform(Object *ob, float lloc[3], float lrot[3][3], float lscale[3][3]);
+extern void SB_estimate_transform(struct Object *ob, float lloc[3], float lrot[3][3], float lscale[3][3]);
#endif
struct Material;
struct MTex;
struct OceanTex;
-struct ParticleSettings;
struct PointDensity;
struct Tex;
struct TexMapping;
struct Tex *give_current_linestyle_texture(struct FreestyleLineStyle *linestyle);
struct Tex *give_current_world_texture(struct World *world);
struct Tex *give_current_brush_texture(struct Brush *br);
-struct Tex *give_current_particle_texture(struct ParticleSettings *part);
struct bNode *give_current_material_texture_node(struct Material *ma);
void set_current_material_texture(struct Material *ma, struct Tex *tex);
void set_current_lamp_texture(struct Lamp *la, struct Tex *tex);
void set_current_linestyle_texture(struct FreestyleLineStyle *linestyle, struct Tex *tex);
-void set_current_particle_texture(struct ParticleSettings *part, struct Tex *tex);
bool has_current_material_texture(struct Material *ma);
intern/blender_undo.c
intern/blendfile.c
intern/bmfont.c
- intern/boids.c
intern/bpath.c
intern/brush.c
intern/bullet.c
intern/outliner_treehash.c
intern/packedFile.c
intern/paint.c
- intern/particle.c
- intern/particle_child.c
- intern/particle_distribute.c
- intern/particle_system.c
intern/pbvh.c
intern/pbvh_bmesh.c
- intern/pointcache.c
intern/property.c
intern/report.c
intern/rigidbody.c
BKE_blendfile.h
BKE_bmfont.h
BKE_bmfont_types.h
- BKE_boids.h
BKE_bpath.h
BKE_brush.h
BKE_bullet.h
BKE_outliner_treehash.h
BKE_packedFile.h
BKE_paint.h
- BKE_particle.h
BKE_pbvh.h
- BKE_pointcache.h
BKE_property.h
BKE_report.h
BKE_rigidbody.h
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_key_types.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BKE_curve.h"
#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_object.h"
-#include "BKE_particle.h"
#include "BKE_scene.h"
#include "BKE_anim.h"
#include "BKE_report.h"
case ID_OB:
case ID_ME: case ID_MB: case ID_CU: case ID_AR: case ID_LT:
case ID_KE:
- case ID_PA:
case ID_MA: case ID_TE: case ID_NT:
case ID_LA: case ID_CA: case ID_WO:
case ID_LS:
/* meshes */
ANIMDATA_IDS_CB(mainptr->mesh.first);
- /* particles */
- ANIMDATA_IDS_CB(mainptr->particle.first);
-
/* speakers */
ANIMDATA_IDS_CB(mainptr->speaker.first);
/* meshes */
RENAMEFIX_ANIM_IDS(mainptr->mesh.first);
- /* particles */
- RENAMEFIX_ANIM_IDS(mainptr->particle.first);
-
/* speakers */
RENAMEFIX_ANIM_IDS(mainptr->speaker.first);
/* meshes */
EVAL_ANIM_IDS(main->mesh.first, ADT_RECALC_ANIM);
- /* particles */
- EVAL_ANIM_IDS(main->particle.first, ADT_RECALC_ANIM);
-
/* speakers */
EVAL_ANIM_IDS(main->speaker.first, ADT_RECALC_ANIM);
+++ /dev/null
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2009 by Janne Karhu.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/boids.c
- * \ingroup bke
- */
-
-
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_object_force.h"
-#include "DNA_scene_types.h"
-
-#include "BLI_rand.h"
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_kdtree.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_collision.h"
-#include "BKE_effect.h"
-#include "BKE_boids.h"
-#include "BKE_particle.h"
-
-#include "BKE_modifier.h"
-
-#include "RNA_enum_types.h"
-
-typedef struct BoidValues {
- float max_speed, max_acc;
- float max_ave, min_speed;
- float personal_space, jump_speed;
-} BoidValues;
-
-static int apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness);
-
-static int rule_none(BoidRule *UNUSED(rule), BoidBrainData *UNUSED(data), BoidValues *UNUSED(val), ParticleData *UNUSED(pa))
-{
- return 0;
-}
-
-static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
-{
- BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid*) rule;
- BoidSettings *boids = bbd->part->boids;
- BoidParticle *bpa = pa->boid;
- EffectedPoint epoint;
- ListBase *effectors = bbd->sim->psys->effectors;
- EffectorCache *cur, *eff = NULL;
- EffectorCache temp_eff;
- EffectorData efd, cur_efd;
- float mul = (rule->type == eBoidRuleType_Avoid ? 1.0 : -1.0);
- float priority = 0.0f, len = 0.0f;
- int ret = 0;
-
- int p = 0;
- efd.index = cur_efd.index = &p;
-
- pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
-
- /* first find out goal/predator with highest priority */
- if (effectors) for (cur = effectors->first; cur; cur=cur->next) {
- Object *eob = cur->ob;
- PartDeflect *pd = cur->pd;
-
- if (gabr->ob && (rule->type != eBoidRuleType_Goal || gabr->ob != bpa->ground)) {
- if (gabr->ob == eob) {
- /* TODO: effectors with multiple points */
- if (get_effector_data(cur, &efd, &epoint, 0)) {
- if (cur->pd && cur->pd->forcefield == PFIELD_BOID)
- priority = mul * pd->f_strength * effector_falloff(cur, &efd, &epoint, bbd->part->effector_weights);
- else
- priority = 1.0;
-
- eff = cur;
- }
- break;
- }
- }
- else if (rule->type == eBoidRuleType_Goal && eob == bpa->ground) {
- /* skip current object */
- }
- else if (pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f && get_effector_data(cur, &cur_efd, &epoint, 0)) {
- float temp = mul * pd->f_strength * effector_falloff(cur, &cur_efd, &epoint, bbd->part->effector_weights);
-
- if (temp == 0.0f) {
- /* do nothing */
- }
- else if (temp > priority) {
- priority = temp;
- eff = cur;
- efd = cur_efd;
- len = efd.distance;
- }
- /* choose closest object with same priority */
- else if (temp == priority && efd.distance < len) {
- eff = cur;
- efd = cur_efd;
- len = efd.distance;
- }
- }
- }
-
- /* if the object doesn't have effector data we have to fake it */
- if (eff == NULL && gabr->ob) {
- memset(&temp_eff, 0, sizeof(EffectorCache));
- temp_eff.ob = gabr->ob;
- temp_eff.scene = bbd->sim->scene;
- eff = &temp_eff;
- get_effector_data(eff, &efd, &epoint, 0);
- priority = 1.0f;
- }
-
- /* then use that effector */
- if (priority > (rule->type==eBoidRuleType_Avoid ? gabr->fear_factor : 0.0f)) { /* with avoid, factor is "fear factor" */
- Object *eob = eff->ob;
- PartDeflect *pd = eff->pd;
- float surface = (pd && pd->shape == PFIELD_SHAPE_SURFACE) ? 1.0f : 0.0f;
-
- if (gabr->options & BRULE_GOAL_AVOID_PREDICT) {
- /* estimate future location of target */
- get_effector_data(eff, &efd, &epoint, 1);
-
- mul_v3_fl(efd.vel, efd.distance / (val->max_speed * bbd->timestep));
- add_v3_v3(efd.loc, efd.vel);
- sub_v3_v3v3(efd.vec_to_point, pa->prev_state.co, efd.loc);
- efd.distance = len_v3(efd.vec_to_point);
- }
-
- if (rule->type == eBoidRuleType_Goal && boids->options & BOID_ALLOW_CLIMB && surface!=0.0f) {
- if (!bbd->goal_ob || bbd->goal_priority < priority) {
- bbd->goal_ob = eob;
- copy_v3_v3(bbd->goal_co, efd.loc);
- copy_v3_v3(bbd->goal_nor, efd.nor);
- }
- }
- else if (rule->type == eBoidRuleType_Avoid && bpa->data.mode == eBoidMode_Climbing &&
- priority > 2.0f * gabr->fear_factor) {
- /* detach from surface and try to fly away from danger */
- negate_v3_v3(efd.vec_to_point, bpa->gravity);
- }
-
- copy_v3_v3(bbd->wanted_co, efd.vec_to_point);
- mul_v3_fl(bbd->wanted_co, mul);
-
- bbd->wanted_speed = val->max_speed * priority;
-
- /* with goals factor is approach velocity factor */
- if (rule->type == eBoidRuleType_Goal && boids->landing_smoothness > 0.0f) {
- float len2 = 2.0f*len_v3(pa->prev_state.vel);
-
- surface *= pa->size * boids->height;
-
- if (len2 > 0.0f && efd.distance - surface < len2) {
- len2 = (efd.distance - surface)/len2;
- bbd->wanted_speed *= powf(len2, boids->landing_smoothness);
- }
- }
-
- ret = 1;
- }
-
- return ret;
-}
-
-static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
-{
- const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
- BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision*) rule;
- KDTreeNearest *ptn = NULL;
- ParticleTarget *pt;
- BoidParticle *bpa = pa->boid;
- ColliderCache *coll;
- float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
- float co1[3], vel1[3], co2[3], vel2[3];
- float len, t, inp, t_min = 2.0f;
- int n, neighbors = 0, nearest = 0;
- int ret = 0;
-
- //check deflector objects first
- if (acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) {
- ParticleCollision col;
- BVHTreeRayHit hit;
- float radius = val->personal_space * pa->size, ray_dir[3];
-
- memset(&col, 0, sizeof(ParticleCollision));
-
- copy_v3_v3(col.co1, pa->prev_state.co);
- add_v3_v3v3(col.co2, pa->prev_state.co, pa->prev_state.vel);
- sub_v3_v3v3(ray_dir, col.co2, col.co1);
- mul_v3_fl(ray_dir, acbr->look_ahead);
- col.f = 0.0f;
- hit.index = -1;
- hit.dist = col.original_ray_length = normalize_v3(ray_dir);
-
- /* find out closest deflector object */
- for (coll = bbd->sim->colliders->first; coll; coll=coll->next) {
- /* don't check with current ground object */
- if (coll->ob == bpa->ground)
- continue;
-
- col.current = coll->ob;
- col.md = coll->collmd;
-
- if (col.md && col.md->bvhtree) {
- BLI_bvhtree_ray_cast_ex(
- col.md->bvhtree, col.co1, ray_dir, radius, &hit,
- BKE_psys_collision_neartest_cb, &col, raycast_flag);
- }
- }
- /* then avoid that object */
- if (hit.index>=0) {
- t = hit.dist/col.original_ray_length;
-
- /* avoid head-on collision */
- if (dot_v3v3(col.pce.nor, pa->prev_state.ave) < -0.99f) {
- /* don't know why, but uneven range [0.0, 1.0] */
- /* works much better than even [-1.0, 1.0] */
- bbd->wanted_co[0] = BLI_rng_get_float(bbd->rng);
- bbd->wanted_co[1] = BLI_rng_get_float(bbd->rng);
- bbd->wanted_co[2] = BLI_rng_get_float(bbd->rng);
- }
- else {
- copy_v3_v3(bbd->wanted_co, col.pce.nor);
- }
-
- mul_v3_fl(bbd->wanted_co, (1.0f - t) * val->personal_space * pa->size);
-
- bbd->wanted_speed = sqrtf(t) * len_v3(pa->prev_state.vel);
- bbd->wanted_speed = MAX2(bbd->wanted_speed, val->min_speed);
-
- return 1;
- }
- }
-
- //check boids in own system
- if (acbr->options & BRULE_ACOLL_WITH_BOIDS) {
- neighbors = BLI_kdtree_range_search__normal(
- bbd->sim->psys->tree, pa->prev_state.co, pa->prev_state.ave,
- &ptn, acbr->look_ahead * len_v3(pa->prev_state.vel));
- if (neighbors > 1) for (n=1; n<neighbors; n++) {
- copy_v3_v3(co1, pa->prev_state.co);
- copy_v3_v3(vel1, pa->prev_state.vel);
- copy_v3_v3(co2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.co);
- copy_v3_v3(vel2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.vel);
-
- sub_v3_v3v3(loc, co1, co2);
-
- sub_v3_v3v3(vec, vel1, vel2);
-
- inp = dot_v3v3(vec, vec);
-
- /* velocities not parallel */
- if (inp != 0.0f) {
- t = -dot_v3v3(loc, vec)/inp;
- /* cpa is not too far in the future so investigate further */
- if (t > 0.0f && t < t_min) {
- madd_v3_v3fl(co1, vel1, t);
- madd_v3_v3fl(co2, vel2, t);
-
- sub_v3_v3v3(vec, co2, co1);
-
- len = normalize_v3(vec);
-
- /* distance of cpa is close enough */
- if (len < 2.0f * val->personal_space * pa->size) {
- t_min = t;
-
- mul_v3_fl(vec, len_v3(vel1));
- mul_v3_fl(vec, (2.0f - t)/2.0f);
- sub_v3_v3v3(bbd->wanted_co, vel1, vec);
- bbd->wanted_speed = len_v3(bbd->wanted_co);
- ret = 1;
- }
- }
- }
- }
- }
- if (ptn) { MEM_freeN(ptn); ptn=NULL; }
-
- /* check boids in other systems */
- for (pt=bbd->sim->psys->targets.first; pt; pt=pt->next) {
- ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
-
- if (epsys) {
- BLI_assert(epsys->tree != NULL);
- neighbors = BLI_kdtree_range_search__normal(
- epsys->tree, pa->prev_state.co, pa->prev_state.ave,
- &ptn, acbr->look_ahead * len_v3(pa->prev_state.vel));
-
- if (neighbors > 0) for (n=0; n<neighbors; n++) {
- copy_v3_v3(co1, pa->prev_state.co);
- copy_v3_v3(vel1, pa->prev_state.vel);
- copy_v3_v3(co2, (epsys->particles + ptn[n].index)->prev_state.co);
- copy_v3_v3(vel2, (epsys->particles + ptn[n].index)->prev_state.vel);
-
- sub_v3_v3v3(loc, co1, co2);
-
- sub_v3_v3v3(vec, vel1, vel2);
-
- inp = dot_v3v3(vec, vec);
-
- /* velocities not parallel */
- if (inp != 0.0f) {
- t = -dot_v3v3(loc, vec)/inp;
- /* cpa is not too far in the future so investigate further */
- if (t > 0.0f && t < t_min) {
- madd_v3_v3fl(co1, vel1, t);
- madd_v3_v3fl(co2, vel2, t);
-
- sub_v3_v3v3(vec, co2, co1);
-
- len = normalize_v3(vec);
-
- /* distance of cpa is close enough */
- if (len < 2.0f * val->personal_space * pa->size) {
- t_min = t;
-
- mul_v3_fl(vec, len_v3(vel1));
- mul_v3_fl(vec, (2.0f - t)/2.0f);
- sub_v3_v3v3(bbd->wanted_co, vel1, vec);
- bbd->wanted_speed = len_v3(bbd->wanted_co);
- ret = 1;
- }
- }
- }
- }
-
- if (ptn) { MEM_freeN(ptn); ptn=NULL; }
- }
- }
-
-
- if (ptn && nearest==0)
- MEM_freeN(ptn);
-
- return ret;
-}
-static int rule_separate(BoidRule *UNUSED(rule), BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
-{
- KDTreeNearest *ptn = NULL;
- ParticleTarget *pt;
- float len = 2.0f * val->personal_space * pa->size + 1.0f;
- float vec[3] = {0.0f, 0.0f, 0.0f};
- int neighbors = BLI_kdtree_range_search(
- bbd->sim->psys->tree, pa->prev_state.co,
- &ptn, 2.0f * val->personal_space * pa->size);
- int ret = 0;
-
- if (neighbors > 1 && ptn[1].dist!=0.0f) {
- sub_v3_v3v3(vec, pa->prev_state.co, bbd->sim->psys->particles[ptn[1].index].state.co);
- mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[1].dist) / ptn[1].dist);
- add_v3_v3(bbd->wanted_co, vec);
- bbd->wanted_speed = val->max_speed;
- len = ptn[1].dist;
- ret = 1;
- }
- if (ptn) { MEM_freeN(ptn); ptn=NULL; }
-
- /* check other boid systems */
- for (pt=bbd->sim->psys->targets.first; pt; pt=pt->next) {
- ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
-
- if (epsys) {
- neighbors = BLI_kdtree_range_search(
- epsys->tree, pa->prev_state.co,
- &ptn, 2.0f * val->personal_space * pa->size);
-
- if (neighbors > 0 && ptn[0].dist < len) {
- sub_v3_v3v3(vec, pa->prev_state.co, ptn[0].co);
- mul_v3_fl(vec, (2.0f * val->personal_space * pa->size - ptn[0].dist) / ptn[1].dist);
- add_v3_v3(bbd->wanted_co, vec);
- bbd->wanted_speed = val->max_speed;
- len = ptn[0].dist;
- ret = 1;
- }
-
- if (ptn) { MEM_freeN(ptn); ptn=NULL; }
- }
- }
- return ret;
-}
-static int rule_flock(BoidRule *UNUSED(rule), BoidBrainData *bbd, BoidValues *UNUSED(val), ParticleData *pa)
-{
- KDTreeNearest ptn[11];
- float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
- int neighbors = BLI_kdtree_find_nearest_n__normal(bbd->sim->psys->tree, pa->state.co, pa->prev_state.ave, ptn, 11);
- int n;
- int ret = 0;
-
- if (neighbors > 1) {
- for (n=1; n<neighbors; n++) {
- add_v3_v3(loc, bbd->sim->psys->particles[ptn[n].index].prev_state.co);
- add_v3_v3(vec, bbd->sim->psys->particles[ptn[n].index].prev_state.vel);
- }
-
- mul_v3_fl(loc, 1.0f/((float)neighbors - 1.0f));
- mul_v3_fl(vec, 1.0f/((float)neighbors - 1.0f));
-
- sub_v3_v3(loc, pa->prev_state.co);
- sub_v3_v3(vec, pa->prev_state.vel);
-
- add_v3_v3(bbd->wanted_co, vec);
- add_v3_v3(bbd->wanted_co, loc);
- bbd->wanted_speed = len_v3(bbd->wanted_co);
-
- ret = 1;
- }
- return ret;
-}
-static int rule_follow_leader(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
-{
- BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*) rule;
- float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
- float mul, len;
- int n = (flbr->queue_size <= 1) ? bbd->sim->psys->totpart : flbr->queue_size;
- int i, ret = 0, p = pa - bbd->sim->psys->particles;
-
- if (flbr->ob) {
- float vec2[3], t;
-
- /* first check we're not blocking the leader */
- sub_v3_v3v3(vec, flbr->loc, flbr->oloc);
- mul_v3_fl(vec, 1.0f/bbd->timestep);
-
- sub_v3_v3v3(loc, pa->prev_state.co, flbr->oloc);
-
- mul = dot_v3v3(vec, vec);
-
- /* leader is not moving */
- if (mul < 0.01f) {
- len = len_v3(loc);
- /* too close to leader */
- if (len < 2.0f * val->personal_space * pa->size) {
- copy_v3_v3(bbd->wanted_co, loc);
- bbd->wanted_speed = val->max_speed;
- return 1;
- }
- }
- else {
- t = dot_v3v3(loc, vec)/mul;
-
- /* possible blocking of leader in near future */
- if (t > 0.0f && t < 3.0f) {
- copy_v3_v3(vec2, vec);
- mul_v3_fl(vec2, t);
-
- sub_v3_v3v3(vec2, loc, vec2);
-
- len = len_v3(vec2);
-
- if (len < 2.0f * val->personal_space * pa->size) {
- copy_v3_v3(bbd->wanted_co, vec2);
- bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f;
- return 1;
- }
- }
- }
-
- /* not blocking so try to follow leader */
- if (p && flbr->options & BRULE_LEADER_IN_LINE) {
- copy_v3_v3(vec, bbd->sim->psys->particles[p-1].prev_state.vel);
- copy_v3_v3(loc, bbd->sim->psys->particles[p-1].prev_state.co);
- }
- else {
- copy_v3_v3(loc, flbr->oloc);
- sub_v3_v3v3(vec, flbr->loc, flbr->oloc);
- mul_v3_fl(vec, 1.0f/bbd->timestep);
- }
-
- /* fac is seconds behind leader */
- madd_v3_v3fl(loc, vec, -flbr->distance);
-
- sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
- bbd->wanted_speed = len_v3(bbd->wanted_co);
-
- ret = 1;
- }
- else if (p % n) {
- float vec2[3], t, t_min = 3.0f;
-
- /* first check we're not blocking any leaders */
- for (i = 0; i< bbd->sim->psys->totpart; i+=n) {
- copy_v3_v3(vec, bbd->sim->psys->particles[i].prev_state.vel);
-
- sub_v3_v3v3(loc, pa->prev_state.co, bbd->sim->psys->particles[i].prev_state.co);
-
- mul = dot_v3v3(vec, vec);
-
- /* leader is not moving */
- if (mul < 0.01f) {
- len = len_v3(loc);
- /* too close to leader */
- if (len < 2.0f * val->personal_space * pa->size) {
- copy_v3_v3(bbd->wanted_co, loc);
- bbd->wanted_speed = val->max_speed;
- return 1;
- }
- }
- else {
- t = dot_v3v3(loc, vec)/mul;
-
- /* possible blocking of leader in near future */
- if (t > 0.0f && t < t_min) {
- copy_v3_v3(vec2, vec);
- mul_v3_fl(vec2, t);
-
- sub_v3_v3v3(vec2, loc, vec2);
-
- len = len_v3(vec2);
-
- if (len < 2.0f * val->personal_space * pa->size) {
- t_min = t;
- copy_v3_v3(bbd->wanted_co, loc);
- bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f;
- ret = 1;
- }
- }
- }
- }
-
- if (ret) return 1;
-
- /* not blocking so try to follow leader */
- if (flbr->options & BRULE_LEADER_IN_LINE) {
- copy_v3_v3(vec, bbd->sim->psys->particles[p-1].prev_state.vel);
- copy_v3_v3(loc, bbd->sim->psys->particles[p-1].prev_state.co);
- }
- else {
- copy_v3_v3(vec, bbd->sim->psys->particles[p - p%n].prev_state.vel);
- copy_v3_v3(loc, bbd->sim->psys->particles[p - p%n].prev_state.co);
- }
-
- /* fac is seconds behind leader */
- madd_v3_v3fl(loc, vec, -flbr->distance);
-
- sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
- bbd->wanted_speed = len_v3(bbd->wanted_co);
-
- ret = 1;
- }
-
- return ret;
-}
-static int rule_average_speed(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
-{
- BoidParticle *bpa = pa->boid;
- BoidRuleAverageSpeed *asbr = (BoidRuleAverageSpeed*)rule;
- float vec[3] = {0.0f, 0.0f, 0.0f};
-
- if (asbr->wander > 0.0f) {
- /* abuse pa->r_ave for wandering */
- bpa->wander[0] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng));
- bpa->wander[1] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng));
- bpa->wander[2] += asbr->wander * (-1.0f + 2.0f * BLI_rng_get_float(bbd->rng));
-
- normalize_v3(bpa->wander);
-
- copy_v3_v3(vec, bpa->wander);
-
- mul_qt_v3(pa->prev_state.rot, vec);
-
- copy_v3_v3(bbd->wanted_co, pa->prev_state.ave);
-
- mul_v3_fl(bbd->wanted_co, 1.1f);
-
- add_v3_v3(bbd->wanted_co, vec);
-
- /* leveling */
- if (asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) {
- project_v3_v3v3(vec, bbd->wanted_co, bbd->sim->scene->physics_settings.gravity);
- mul_v3_fl(vec, asbr->level);
- sub_v3_v3(bbd->wanted_co, vec);
- }
- }
- else {
- copy_v3_v3(bbd->wanted_co, pa->prev_state.ave);
-
- /* may happen at birth */
- if (dot_v2v2(bbd->wanted_co, bbd->wanted_co)==0.0f) {
- bbd->wanted_co[0] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng));
- bbd->wanted_co[1] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng));
- bbd->wanted_co[2] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng));
- }
-
- /* leveling */
- if (asbr->level > 0.0f && psys_uses_gravity(bbd->sim)) {
- project_v3_v3v3(vec, bbd->wanted_co, bbd->sim->scene->physics_settings.gravity);
- mul_v3_fl(vec, asbr->level);
- sub_v3_v3(bbd->wanted_co, vec);
- }
-
- }
- bbd->wanted_speed = asbr->speed * val->max_speed;
-
- return 1;
-}
-static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
-{
- BoidRuleFight *fbr = (BoidRuleFight*)rule;
- KDTreeNearest *ptn = NULL;
- ParticleTarget *pt;
- ParticleData *epars;
- ParticleData *enemy_pa = NULL;
- BoidParticle *bpa;
- /* friends & enemies */
- float closest_enemy[3] = {0.0f, 0.0f, 0.0f};
- float closest_dist = fbr->distance + 1.0f;
- float f_strength = 0.0f, e_strength = 0.0f;
- float health = 0.0f;
- int n, ret = 0;
-
- /* calculate own group strength */
- int neighbors = BLI_kdtree_range_search(
- bbd->sim->psys->tree, pa->prev_state.co,
- &ptn, fbr->distance);
- for (n=0; n<neighbors; n++) {
- bpa = bbd->sim->psys->particles[ptn[n].index].boid;
- health += bpa->data.health;
- }
-
- f_strength += bbd->part->boids->strength * health;
-
- if (ptn) { MEM_freeN(ptn); ptn=NULL; }
-
- /* add other friendlies and calculate enemy strength and find closest enemy */
- for (pt=bbd->sim->psys->targets.first; pt; pt=pt->next) {
- ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
- if (epsys) {
- epars = epsys->particles;
-
- neighbors = BLI_kdtree_range_search(
- epsys->tree, pa->prev_state.co,
- &ptn, fbr->distance);
-
- health = 0.0f;
-
- for (n=0; n<neighbors; n++) {
- bpa = epars[ptn[n].index].boid;
- health += bpa->data.health;
-
- if (n==0 && pt->mode==PTARGET_MODE_ENEMY && ptn[n].dist < closest_dist) {
- copy_v3_v3(closest_enemy, ptn[n].co);
- closest_dist = ptn[n].dist;
- enemy_pa = epars + ptn[n].index;
- }
- }
- if (pt->mode==PTARGET_MODE_ENEMY)
- e_strength += epsys->part->boids->strength * health;
- else if (pt->mode==PTARGET_MODE_FRIEND)
- f_strength += epsys->part->boids->strength * health;
-
- if (ptn) { MEM_freeN(ptn); ptn=NULL; }
- }
- }
- /* decide action if enemy presence found */
- if (e_strength > 0.0f) {
- sub_v3_v3v3(bbd->wanted_co, closest_enemy, pa->prev_state.co);
-
- /* attack if in range */
- if (closest_dist <= bbd->part->boids->range + pa->size + enemy_pa->size) {
- float damage = BLI_rng_get_float(bbd->rng);
- float enemy_dir[3];
-
- normalize_v3_v3(enemy_dir, bbd->wanted_co);
-
- /* fight mode */
- bbd->wanted_speed = 0.0f;
-
- /* must face enemy to fight */
- if (dot_v3v3(pa->prev_state.ave, enemy_dir)>0.5f) {
- bpa = enemy_pa->boid;
- bpa->data.health -= bbd->part->boids->strength * bbd->timestep * ((1.0f-bbd->part->boids->accuracy)*damage + bbd->part->boids->accuracy);
- }
- }
- else {
- /* approach mode */
- bbd->wanted_speed = val->max_speed;
- }
-
- /* check if boid doesn't want to fight */
- bpa = pa->boid;
- if (bpa->data.health/bbd->part->boids->health * bbd->part->boids->aggression < e_strength / f_strength) {
- /* decide to flee */
- if (closest_dist < fbr->flee_distance * fbr->distance) {
- negate_v3(bbd->wanted_co);
- bbd->wanted_speed = val->max_speed;
- }
- else { /* wait for better odds */
- bbd->wanted_speed = 0.0f;
- }
- }
-
- ret = 1;
- }
-
- return ret;
-}
-
-typedef int (*boid_rule_cb)(BoidRule *rule, BoidBrainData *data, BoidValues *val, ParticleData *pa);
-
-static boid_rule_cb boid_rules[] = {
- rule_none,
- rule_goal_avoid,
- rule_goal_avoid,
- rule_avoid_collision,
- rule_separate,
- rule_flock,
- rule_follow_leader,
- rule_average_speed,
- rule_fight,
- //rule_help,
- //rule_protect,
- //rule_hide,
- //rule_follow_path,
- //rule_follow_wall
-};
-
-static void set_boid_values(BoidValues *val, BoidSettings *boids, ParticleData *pa)
-{
- BoidParticle *bpa = pa->boid;
-
- if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
- val->max_speed = boids->land_max_speed * bpa->data.health/boids->health;
- val->max_acc = boids->land_max_acc * val->max_speed;
- val->max_ave = boids->land_max_ave * (float)M_PI * bpa->data.health/boids->health;
- val->min_speed = 0.0f; /* no minimum speed on land */
- val->personal_space = boids->land_personal_space;
- val->jump_speed = boids->land_jump_speed * bpa->data.health/boids->health;
- }
- else {
- val->max_speed = boids->air_max_speed * bpa->data.health/boids->health;
- val->max_acc = boids->air_max_acc * val->max_speed;
- val->max_ave = boids->air_max_ave * (float)M_PI * bpa->data.health/boids->health;
- val->min_speed = boids->air_min_speed * boids->air_max_speed;
- val->personal_space = boids->air_personal_space;
- val->jump_speed = 0.0f; /* no jumping in air */
- }
-}
-
-static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float ground_co[3], float ground_nor[3])
-{
- const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
- BoidParticle *bpa = pa->boid;
-
- if (bpa->data.mode == eBoidMode_Climbing) {
- SurfaceModifierData *surmd = NULL;
- float x[3], v[3];
-
- surmd = (SurfaceModifierData *)modifiers_findByType(bpa->ground, eModifierType_Surface );
-
- /* take surface velocity into account */
- closest_point_on_surface(surmd, pa->state.co, x, NULL, v);
- add_v3_v3(x, v);
-
- /* get actual position on surface */
- closest_point_on_surface(surmd, x, ground_co, ground_nor, NULL);
-
- return bpa->ground;
- }
- else {
- float zvec[3] = {0.0f, 0.0f, 2000.0f};
- ParticleCollision col;
- ColliderCache *coll;
- BVHTreeRayHit hit;
- float radius = 0.0f, t, ray_dir[3];
-
- if (!bbd->sim->colliders)
- return NULL;
-
- memset(&col, 0, sizeof(ParticleCollision));
-
- /* first try to find below boid */
- copy_v3_v3(col.co1, pa->state.co);
- sub_v3_v3v3(col.co2, pa->state.co, zvec);
- sub_v3_v3v3(ray_dir, col.co2, col.co1);
- col.f = 0.0f;
- hit.index = -1;
- hit.dist = col.original_ray_length = normalize_v3(ray_dir);
- col.pce.inside = 0;
-
- for (coll = bbd->sim->colliders->first; coll; coll = coll->next) {
- col.current = coll->ob;
- col.md = coll->collmd;
- col.fac1 = col.fac2 = 0.f;
-
- if (col.md && col.md->bvhtree) {
- BLI_bvhtree_ray_cast_ex(
- col.md->bvhtree, col.co1, ray_dir, radius, &hit,
- BKE_psys_collision_neartest_cb, &col, raycast_flag);
- }
- }
- /* then use that object */
- if (hit.index>=0) {
- t = hit.dist/col.original_ray_length;
- interp_v3_v3v3(ground_co, col.co1, col.co2, t);
- normalize_v3_v3(ground_nor, col.pce.nor);
- return col.hit;
- }
-
- /* couldn't find below, so find upmost deflector object */
- add_v3_v3v3(col.co1, pa->state.co, zvec);
- sub_v3_v3v3(col.co2, pa->state.co, zvec);
- sub_v3_v3(col.co2, zvec);
- sub_v3_v3v3(ray_dir, col.co2, col.co1);
- col.f = 0.0f;
- hit.index = -1;
- hit.dist = col.original_ray_length = normalize_v3(ray_dir);
-
- for (coll = bbd->sim->colliders->first; coll; coll = coll->next) {
- col.current = coll->ob;
- col.md = coll->collmd;
-
- if (col.md && col.md->bvhtree) {
- BLI_bvhtree_ray_cast_ex(
- col.md->bvhtree, col.co1, ray_dir, radius, &hit,
- BKE_psys_collision_neartest_cb, &col, raycast_flag);
- }
- }
- /* then use that object */
- if (hit.index>=0) {
- t = hit.dist/col.original_ray_length;
- interp_v3_v3v3(ground_co, col.co1, col.co2, t);
- normalize_v3_v3(ground_nor, col.pce.nor);
- return col.hit;
- }
-
- /* default to z=0 */
- copy_v3_v3(ground_co, pa->state.co);
- ground_co[2] = 0;
- ground_nor[0] = ground_nor[1] = 0.0f;
- ground_nor[2] = 1.0f;
- return NULL;
- }
-}
-static int boid_rule_applies(ParticleData *pa, BoidSettings *UNUSED(boids), BoidRule *rule)
-{
- BoidParticle *bpa = pa->boid;
-
- if (rule==NULL)
- return 0;
-
- if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing) && rule->flag & BOIDRULE_ON_LAND)
- return 1;
-
- if (bpa->data.mode==eBoidMode_InAir && rule->flag & BOIDRULE_IN_AIR)
- return 1;
-
- return 0;
-}
-void boids_precalc_rules(ParticleSettings *part, float cfra)
-{
- BoidState *state = part->boids->states.first;
- BoidRule *rule;
- for (; state; state=state->next) {
- for (rule = state->rules.first; rule; rule=rule->next) {
- if (rule->type==eBoidRuleType_FollowLeader) {
- BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*) rule;
-
- if (flbr->ob && flbr->cfra != cfra) {
- /* save object locations for velocity calculations */
- copy_v3_v3(flbr->oloc, flbr->loc);
- copy_v3_v3(flbr->loc, flbr->ob->obmat[3]);
- flbr->cfra = cfra;
- }
- }
- }
- }
-}
-static void boid_climb(BoidSettings *boids, ParticleData *pa, float *surface_co, float *surface_nor)
-{
- BoidParticle *bpa = pa->boid;
- float nor[3], vel[3];
- copy_v3_v3(nor, surface_nor);
-
- /* gather apparent gravity */
- madd_v3_v3fl(bpa->gravity, surface_nor, -1.0f);
- normalize_v3(bpa->gravity);
-
- /* raise boid it's size from surface */
- mul_v3_fl(nor, pa->size * boids->height);
- add_v3_v3v3(pa->state.co, surface_co, nor);
-
- /* remove normal component from velocity */
- project_v3_v3v3(vel, pa->state.vel, surface_nor);
- sub_v3_v3v3(pa->state.vel, pa->state.vel, vel);
-}
-static float boid_goal_signed_dist(float *boid_co, float *goal_co, float *goal_nor)
-{
- float vec[3];
-
- sub_v3_v3v3(vec, boid_co, goal_co);
-
- return dot_v3v3(vec, goal_nor);
-}
-/* wanted_co is relative to boid location */
-static int apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness)
-{
- if (rule==NULL)
- return 0;
-
- if (boid_rule_applies(pa, bbd->part->boids, rule)==0)
- return 0;
-
- if (boid_rules[rule->type](rule, bbd, val, pa)==0)
- return 0;
-
- if (fuzziness < 0.0f || compare_len_v3v3(bbd->wanted_co, pa->prev_state.vel, fuzziness * len_v3(pa->prev_state.vel))==0)
- return 1;
- else
- return 0;
-}
-static BoidState *get_boid_state(BoidSettings *boids, ParticleData *pa)
-{
- BoidState *state = boids->states.first;
- BoidParticle *bpa = pa->boid;
-
- for (; state; state=state->next) {
- if (state->id==bpa->data.state_id)
- return state;
- }
-
- /* for some reason particle isn't at a valid state */
- state = boids->states.first;
- if (state)
- bpa->data.state_id = state->id;
-
- return state;
-}
-//static int boid_condition_is_true(BoidCondition *cond)
-//{
-// /* TODO */
-// return 0;
-//}
-
-/* determines the velocity the boid wants to have */
-void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
-{
- BoidRule *rule;
- BoidSettings *boids = bbd->part->boids;
- BoidValues val;
- BoidState *state = get_boid_state(boids, pa);
- BoidParticle *bpa = pa->boid;
- ParticleSystem *psys = bbd->sim->psys;
- int rand;
- //BoidCondition *cond;
-
- if (bpa->data.health <= 0.0f) {
- pa->alive = PARS_DYING;
- pa->dietime = bbd->cfra;
- return;
- }
-
- //planned for near future
- //cond = state->conditions.first;
- //for (; cond; cond=cond->next) {
- // if (boid_condition_is_true(cond)) {
- // pa->boid->state_id = cond->state_id;
- // state = get_boid_state(boids, pa);
- // break; /* only first true condition is used */
- // }
- //}
-
- zero_v3(bbd->wanted_co);
- bbd->wanted_speed = 0.0f;
-
- /* create random seed for every particle & frame */
- rand = (int)(psys_frand(psys, psys->seed + p) * 1000);
- rand = (int)(psys_frand(psys, (int)bbd->cfra + rand) * 1000);
-
- set_boid_values(&val, bbd->part->boids, pa);
-
- /* go through rules */
- switch (state->ruleset_type) {
- case eBoidRulesetType_Fuzzy:
- {
- for (rule = state->rules.first; rule; rule = rule->next) {
- if (apply_boid_rule(bbd, rule, &val, pa, state->rule_fuzziness))
- break; /* only first nonzero rule that comes through fuzzy rule is applied */
- }
- break;
- }
- case eBoidRulesetType_Random:
- {
- /* use random rule for each particle (always same for same particle though) */
- const int n = BLI_listbase_count(&state->rules);
- if (n) {
- rule = BLI_findlink(&state->rules, rand % n);
- apply_boid_rule(bbd, rule, &val, pa, -1.0);
- }
- break;
- }
- case eBoidRulesetType_Average:
- {
- float wanted_co[3] = {0.0f, 0.0f, 0.0f}, wanted_speed = 0.0f;
- int n = 0;
- for (rule = state->rules.first; rule; rule=rule->next) {
- if (apply_boid_rule(bbd, rule, &val, pa, -1.0f)) {
- add_v3_v3(wanted_co, bbd->wanted_co);
- wanted_speed += bbd->wanted_speed;
- n++;
- zero_v3(bbd->wanted_co);
- bbd->wanted_speed = 0.0f;
- }
- }
-
- if (n > 1) {
- mul_v3_fl(wanted_co, 1.0f/(float)n);
- wanted_speed /= (float)n;
- }
-
- copy_v3_v3(bbd->wanted_co, wanted_co);
- bbd->wanted_speed = wanted_speed;
- break;
- }
-
- }
-
- /* decide on jumping & liftoff */
- if (bpa->data.mode == eBoidMode_OnLand) {
- /* fuzziness makes boids capable of misjudgement */
- float mul = 1.0f + state->rule_fuzziness;
-
- if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) {
- float cvel[3], dir[3];
-
- copy_v3_v3(dir, pa->prev_state.ave);
- normalize_v2(dir);
-
- copy_v3_v3(cvel, bbd->wanted_co);
- normalize_v2(cvel);
-
- if (dot_v2v2(cvel, dir) > 0.95f / mul)
- bpa->data.mode = eBoidMode_Liftoff;
- }
- else if (val.jump_speed > 0.0f) {
- float jump_v[3];
- int jump = 0;
-
- /* jump to get to a location */
- if (bbd->wanted_co[2] > 0.0f) {
- float cvel[3], dir[3];
- float z_v, ground_v, cur_v;
- float len;
-
- copy_v3_v3(dir, pa->prev_state.ave);
- normalize_v2(dir);
-
- copy_v3_v3(cvel, bbd->wanted_co);
- normalize_v2(cvel);
-
- len = len_v2(pa->prev_state.vel);
-
- /* first of all, are we going in a suitable direction? */
- /* or at a suitably slow speed */
- if (dot_v2v2(cvel, dir) > 0.95f / mul || len <= state->rule_fuzziness) {
- /* try to reach goal at highest point of the parabolic path */
- cur_v = len_v2(pa->prev_state.vel);
- z_v = sasqrt(-2.0f * bbd->sim->scene->physics_settings.gravity[2] * bbd->wanted_co[2]);
- ground_v = len_v2(bbd->wanted_co)*sasqrt(-0.5f * bbd->sim->scene->physics_settings.gravity[2] / bbd->wanted_co[2]);
-
- len = sasqrt((ground_v-cur_v)*(ground_v-cur_v) + z_v*z_v);
-
- if (len < val.jump_speed * mul || bbd->part->boids->options & BOID_ALLOW_FLIGHT) {
- jump = 1;
-
- len = MIN2(len, val.jump_speed);
-
- copy_v3_v3(jump_v, dir);
- jump_v[2] = z_v;
- mul_v3_fl(jump_v, ground_v);
-
- normalize_v3(jump_v);
- mul_v3_fl(jump_v, len);
- add_v2_v2v2(jump_v, jump_v, pa->prev_state.vel);
- }
- }
- }
-
- /* jump to go faster */
- if (jump == 0 && val.jump_speed > val.max_speed && bbd->wanted_speed > val.max_speed) {
-
- }
-
- if (jump) {
- copy_v3_v3(pa->prev_state.vel, jump_v);
- bpa->data.mode = eBoidMode_Falling;
- }
- }
- }
-}
-/* tries to realize the wanted velocity taking all constraints into account */
-void boid_body(BoidBrainData *bbd, ParticleData *pa)
-{
- BoidSettings *boids = bbd->part->boids;
- BoidParticle *bpa = pa->boid;
- BoidValues val;
- EffectedPoint epoint;
- float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3];
- float dvec[3], bvec[3];
- float new_dir[3], new_speed;
- float old_dir[3], old_speed;
- float wanted_dir[3];
- float q[4], mat[3][3]; /* rotation */
- float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f};
- float force[3] = {0.0f, 0.0f, 0.0f};
- float pa_mass=bbd->part->mass, dtime=bbd->dfra*bbd->timestep;
-
- set_boid_values(&val, boids, pa);
-
- /* make sure there's something in new velocity, location & rotation */
- copy_particle_key(&pa->state, &pa->prev_state, 0);
-
- if (bbd->part->flag & PART_SIZEMASS)
- pa_mass*=pa->size;
-
- /* if boids can't fly they fall to the ground */
- if ((boids->options & BOID_ALLOW_FLIGHT)==0 && ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)==0 && psys_uses_gravity(bbd->sim))
- bpa->data.mode = eBoidMode_Falling;
-
- if (bpa->data.mode == eBoidMode_Falling) {
- /* Falling boids are only effected by gravity. */
- acc[2] = bbd->sim->scene->physics_settings.gravity[2];
- }
- else {
- /* figure out acceleration */
- float landing_level = 2.0f;
- float level = landing_level + 1.0f;
- float new_vel[3];
-
- if (bpa->data.mode == eBoidMode_Liftoff) {
- bpa->data.mode = eBoidMode_InAir;
- bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
- }
- else if (bpa->data.mode == eBoidMode_InAir && boids->options & BOID_ALLOW_LAND) {
- /* auto-leveling & landing if close to ground */
-
- bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
-
- /* level = how many particle sizes above ground */
- level = (pa->prev_state.co[2] - ground_co[2])/(2.0f * pa->size) - 0.5f;
-
- landing_level = - boids->landing_smoothness * pa->prev_state.vel[2] * pa_mass;
-
- if (pa->prev_state.vel[2] < 0.0f) {
- if (level < 1.0f) {
- bbd->wanted_co[0] = bbd->wanted_co[1] = bbd->wanted_co[2] = 0.0f;
- bbd->wanted_speed = 0.0f;
- bpa->data.mode = eBoidMode_Falling;
- }
- else if (level < landing_level) {
- bbd->wanted_speed *= (level - 1.0f)/landing_level;
- bbd->wanted_co[2] *= (level - 1.0f)/landing_level;
- }
- }
- }
-
- copy_v3_v3(old_dir, pa->prev_state.ave);
- new_speed = normalize_v3_v3(wanted_dir, bbd->wanted_co);
-
- /* first check if we have valid direction we want to go towards */
- if (new_speed == 0.0f) {
- copy_v3_v3(new_dir, old_dir);
- }
- else {
- float old_dir2[2], wanted_dir2[2], nor[3], angle;
- copy_v2_v2(old_dir2, old_dir);
- normalize_v2(old_dir2);
- copy_v2_v2(wanted_dir2, wanted_dir);
- normalize_v2(wanted_dir2);
-
- /* choose random direction to turn if wanted velocity */
- /* is directly behind regardless of z-coordinate */
- if (dot_v2v2(old_dir2, wanted_dir2) < -0.99f) {
- wanted_dir[0] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng));
- wanted_dir[1] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng));
- wanted_dir[2] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng));
- normalize_v3(wanted_dir);
- }
-
- /* constrain direction with maximum angular velocity */
- angle = saacos(dot_v3v3(old_dir, wanted_dir));
- angle = min_ff(angle, val.max_ave);
-
- cross_v3_v3v3(nor, old_dir, wanted_dir);
- axis_angle_to_quat(q, nor, angle);
- copy_v3_v3(new_dir, old_dir);
- mul_qt_v3(q, new_dir);
- normalize_v3(new_dir);
-
- /* save direction in case resulting velocity too small */
- axis_angle_to_quat(q, nor, angle*dtime);
- copy_v3_v3(pa->state.ave, old_dir);
- mul_qt_v3(q, pa->state.ave);
- normalize_v3(pa->state.ave);
- }
-
- /* constrain speed with maximum acceleration */
- old_speed = len_v3(pa->prev_state.vel);
-
- if (bbd->wanted_speed < old_speed)
- new_speed = MAX2(bbd->wanted_speed, old_speed - val.max_acc);
- else
- new_speed = MIN2(bbd->wanted_speed, old_speed + val.max_acc);
-
- /* combine direction and speed */
- copy_v3_v3(new_vel, new_dir);
- mul_v3_fl(new_vel, new_speed);
-
- /* maintain minimum flying velocity if not landing */
- if (level >= landing_level) {
- float len2 = dot_v2v2(new_vel, new_vel);
- float root;
-
- len2 = MAX2(len2, val.min_speed*val.min_speed);
- root = sasqrt(new_speed*new_speed - len2);
-
- new_vel[2] = new_vel[2] < 0.0f ? -root : root;
-
- normalize_v2(new_vel);
- mul_v2_fl(new_vel, sasqrt(len2));
- }
-
- /* finally constrain speed to max speed */
- new_speed = normalize_v3(new_vel);
- mul_v3_fl(new_vel, MIN2(new_speed, val.max_speed));
-
- /* get acceleration from difference of velocities */
- sub_v3_v3v3(acc, new_vel, pa->prev_state.vel);
-
- /* break acceleration to components */
- project_v3_v3v3(tan_acc, acc, pa->prev_state.ave);
- sub_v3_v3v3(nor_acc, acc, tan_acc);
- }
-
-