Point cache editing:

- Baked point caches for particles, cloth and softbody can now be edited in particle mode.
	* This overwrites the old cloth/sb cache editmode editing.
	* The type of editable system is chosen from a menu.
	* For particles the current particle system and it's current cache are used.
- Currently this only works for caches that are in memory, but some automatic conversion from disk to memory and back can be implemented later.
- All tools from hair editing can't be applied to point caches and are hidden in the tool panel and specials menu. Some functionality like subdividing paths can be later implemented in a slightly different way from how it works for hair.
- Code is not yet optimized for speed, so editing might be slow sometimes.

Known issues:
- Cloth doesn't update properly while in particle mode, due to the way cloth modifier currently works. Daniel can you check on this?
- As "particle mode" is not only for particles any more some other name would be in place?
- Better icons are needed for the path, point, and tip-modes as the current icons from mesh edit mode are quite misleading.
- Direct editing of point velocities is not yet implemented, but will be in the future.

Other changes:
- Hair editing doesn't require a "make editable" button press any more.
- Multiple caches in single particle system disables changing emission properties.
- Unified ui code for all point cache panels.
	* Defined in buttons_particle.py and imported for cloth, smoke & softbody.
- Proper disabling of properties in ui after baking point caches. (Daniel could you please make needed disable code for smoke panels as their functionality is not familiar to me.)
- Hair weight brush has been removed. Once hair dynamics is re-implemented I'll code a more useable alternative to the functionality.

Bug fixes:
- Unlinking particle settings crashed.
- Deleting the active object with particles in the scene crashed.
- Softbody didn't write point caches correctly on save.
This commit is contained in:
Janne Karhu 2009-08-29 15:20:36 +00:00
parent c03004f93e
commit 874d38eeb4
28 changed files with 2076 additions and 1957 deletions

View File

@ -2,13 +2,79 @@
import bpy
def particle_panel_enabled(psys):
return psys.point_cache.baked==False and psys.editable==False
return psys.point_cache.baked==False and psys.edited==False
def particle_panel_poll(context):
psys = context.particle_system
if psys==None: return False
if psys.settings==None: return False
return psys.settings.type in ('EMITTER', 'REACTOR', 'HAIR')
def point_cache_ui(self, cache, enabled, particles, smoke):
layout = self.layout
layout.set_context_pointer("PointCache", cache)
row = layout.row()
row.template_list(cache, "point_cache_list", cache, "active_point_cache_index", rows=2 )
col = row.column(align=True)
col.itemO("ptcache.add_new", icon='ICON_ZOOMIN', text="")
col.itemO("ptcache.remove", icon='ICON_ZOOMOUT', text="")
row = layout.row()
row.itemL(text="File Name:")
if particles:
row.itemR(cache, "external")
if cache.external:
split = layout.split(percentage=0.80)
split.itemR(cache, "name", text="")
split.itemR(cache, "index", text="")
layout.itemL(text="File Path:")
layout.itemR(cache, "filepath", text="")
layout.itemL(text=cache.info)
else:
layout.itemR(cache, "name", text="")
if not particles:
row = layout.row()
row.enabled = enabled
row.itemR(cache, "start_frame")
row.itemR(cache, "end_frame")
row = layout.row()
if cache.baked == True:
row.itemO("ptcache.free_bake", text="Free Bake")
else:
row.item_booleanO("ptcache.bake", "bake", True, text="Bake")
sub = row.row()
sub.enabled = (cache.frames_skipped or cache.outdated) and enabled
sub.itemO("ptcache.bake", "bake", False, text="Calculate to Current Frame")
row = layout.row()
row.enabled = enabled
row.itemO("ptcache.bake_from_cache", text="Current Cache to Bake")
row.itemR(cache, "step");
if not smoke:
row = layout.row()
sub = row.row()
sub.enabled = enabled
sub.itemR(cache, "quick_cache")
row.itemR(cache, "disk_cache")
layout.itemL(text=cache.info)
layout.itemS()
row = layout.row()
row.item_booleanO("ptcache.bake_all", "bake", True, text="Bake All Dynamics")
row.itemO("ptcache.free_bake_all", text="Free All Bakes")
layout.itemO("ptcache.bake_all", "bake", False, text="Update All Dynamics to current frame")
class ParticleButtonsPanel(bpy.types.Panel):
__space_type__ = 'PROPERTIES'
@ -38,7 +104,16 @@ class PARTICLE_PT_particles(ParticleButtonsPanel):
col.itemO("object.particle_system_add", icon='ICON_ZOOMIN', text="")
col.itemO("object.particle_system_remove", icon='ICON_ZOOMOUT', text="")
if psys:
if psys and not psys.settings:
split = layout.split(percentage=0.32)
col = split.column()
col.itemL(text="Name:")
col.itemL(text="Settings:")
col = split.column()
col.itemR(psys, "name", text="")
col.template_ID(psys, "settings", new="particle.new")
elif psys:
part = psys.settings
split = layout.split(percentage=0.32)
@ -69,10 +144,10 @@ class PARTICLE_PT_particles(ParticleButtonsPanel):
split = layout.split(percentage=0.65)
if part.type=='HAIR':
if psys.editable==True:
split.itemO("particle.editable_set", text="Free Edit")
if psys.edited==True:
split.itemO("particle.edited_clear", text="Free Edit")
else:
split.itemO("particle.editable_set", text="Make Editable")
split.itemL(text="")
row = split.row()
row.enabled = particle_panel_enabled(psys)
row.itemR(part, "hair_step")
@ -96,7 +171,7 @@ class PARTICLE_PT_emission(ParticleButtonsPanel):
psys = context.particle_system
part = psys.settings
layout.enabled = particle_panel_enabled(psys)
layout.enabled = particle_panel_enabled(psys) and not psys.multiple_caches
row = layout.row()
row.itemR(part, "amount")
@ -149,76 +224,8 @@ class PARTICLE_PT_cache(ParticleButtonsPanel):
layout = self.layout
psys = context.particle_system
part = psys.settings
cache = psys.point_cache
layout.set_context_pointer("PointCache", cache)
row = layout.row()
row.template_list(cache, "point_cache_list", cache, "active_point_cache_index", rows=2 )
col = row.column(align=True)
col.itemO("ptcache.add_new", icon='ICON_ZOOMIN', text="")
col.itemO("ptcache.remove", icon='ICON_ZOOMOUT', text="")
row = layout.row()
row.itemL(text="File Name:")
row.itemR(cache, "external")
if cache.external:
split = layout.split(percentage=0.80)
split.itemR(cache, "name", text="")
split.itemR(cache, "index", text="")
layout.itemL(text="File Path:")
layout.itemR(cache, "filepath", text="")
layout.itemL(text=cache.info)
#split = layout.split()
#col = split.column(align=True)
#col.itemR(part, "start")
#col.itemR(part, "end")
#col = split.column(align=True)
#col.itemR(part, "lifetime")
#col.itemR(part, "random_lifetime", slider=True)
else:
layout.itemR(cache, "name", text="")
row = layout.row()
if cache.baked == True:
row.itemO("ptcache.free_bake", text="Free Bake")
else:
row.item_booleanO("ptcache.bake", "bake", True, text="Bake")
subrow = row.row()
subrow.enabled = (cache.frames_skipped or cache.outdated) and particle_panel_enabled(psys)
subrow.itemO("ptcache.bake", "bake", False, text="Calculate to Current Frame")
row = layout.row()
row.enabled = particle_panel_enabled(psys)
row.itemO("ptcache.bake_from_cache", text="Current Cache to Bake")
row.itemR(cache, "step");
row = layout.row()
subrow = row.row()
subrow.enabled = particle_panel_enabled(psys)
subrow.itemR(cache, "quick_cache")
row.itemR(cache, "disk_cache")
layout.itemL(text=cache.info)
layout.itemS()
row = layout.row()
row.item_booleanO("ptcache.bake_all", "bake", True, text="Bake All Dynamics")
row.itemO("ptcache.free_bake_all", text="Free All Bakes")
layout.itemO("ptcache.bake_all", "bake", False, text="Update All Dynamics to current frame")
# for particles these are figured out automatically
#row.itemR(cache, "start_frame")
#row.itemR(cache, "end_frame")
point_cache_ui(self, psys.point_cache, particle_panel_enabled(psys), 1, 0)
class PARTICLE_PT_initial(ParticleButtonsPanel):
__label__ = "Velocity"

View File

@ -1,6 +1,11 @@
import bpy
from buttons_particle import point_cache_ui
def cloth_panel_enabled(md):
return md.point_cache.baked==False
class PhysicButtonsPanel(bpy.types.Panel):
__space_type__ = 'PROPERTIES'
__region_type__ = 'WINDOW'
@ -41,6 +46,8 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel):
split = layout.split()
split.active = cloth_panel_enabled(md)
col = split.column()
col.itemL(text="Quality:")
col.itemR(cloth, "quality", text="Steps",slider=True)
@ -85,53 +92,8 @@ class PHYSICS_PT_cloth_cache(PhysicButtonsPanel):
return (context.cloth != None)
def draw(self, context):
layout = self.layout
cache = context.cloth.point_cache
layout.set_context_pointer("PointCache", cache)
row = layout.row()
row.template_list(cache, "point_cache_list", cache, "active_point_cache_index", rows=2)
col = row.column(align=True)
col.itemO("ptcache.add_new", icon='ICON_ZOOMIN', text="")
col.itemO("ptcache.remove", icon='ICON_ZOOMOUT', text="")
row = layout.row()
row.itemR(cache, "name")
row = layout.row()
row.itemR(cache, "start_frame")
row.itemR(cache, "end_frame")
row = layout.row()
if cache.baked == True:
row.itemO("ptcache.free_bake", text="Free Bake")
else:
row.item_booleanO("ptcache.bake", "bake", True, text="Bake")
subrow = row.row()
subrow.enabled = cache.frames_skipped or cache.outdated
subrow.itemO("ptcache.bake", "bake", False, text="Calculate to Current Frame")
row = layout.row()
#row.enabled = particle_panel_enabled(psys)
row.itemO("ptcache.bake_from_cache", text="Current Cache to Bake")
row.itemR(cache, "step");
row = layout.row()
#row.enabled = particle_panel_enabled(psys)
row.itemR(cache, "quick_cache")
row.itemR(cache, "disk_cache")
layout.itemL(text=cache.info)
layout.itemS()
row = layout.row()
row.itemO("ptcache.bake_all", "bake", True, text="Bake All Dynamics")
row.itemO("ptcache.free_bake_all", text="Free All Bakes")
layout.itemO("ptcache.bake_all", "bake", False, text="Update All Dynamics to current frame")
md = context.cloth
point_cache_ui(self, md.point_cache, cloth_panel_enabled(md), 0, 0)
class PHYSICS_PT_cloth_collision(PhysicButtonsPanel):
__label__ = "Cloth Collision"
@ -143,7 +105,8 @@ class PHYSICS_PT_cloth_collision(PhysicButtonsPanel):
def draw_header(self, context):
layout = self.layout
cloth = context.cloth.collision_settings
layout.active = cloth_panel_enabled(context.cloth)
layout.itemR(cloth, "enable_collision", text="")
def draw(self, context):
@ -151,7 +114,7 @@ class PHYSICS_PT_cloth_collision(PhysicButtonsPanel):
cloth = context.cloth.collision_settings
split = layout.split()
layout.active = cloth.enable_collision
layout.active = cloth.enable_collision and cloth_panel_enabled(md)
col = split.column()
col.itemR(cloth, "collision_quality", slider=True, text="Quality")
@ -176,6 +139,7 @@ class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel):
layout = self.layout
cloth = context.cloth.settings
layout.active = cloth_panel_enabled(context.cloth)
layout.itemR(cloth, "stiffness_scaling", text="")
def draw(self, context):
@ -183,7 +147,7 @@ class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel):
ob = context.object
cloth = context.cloth.settings
layout.active = cloth.stiffness_scaling
layout.active = cloth.stiffness_scaling and cloth_panel_enabled(md)
split = layout.split()

View File

@ -1,6 +1,8 @@
import bpy
from buttons_particle import point_cache_ui
def smoke_panel_enabled_low(smd):
if smd.smoke_type == 'TYPE_DOMAIN':
return smd.domain.point_cache.baked==False
@ -139,48 +141,8 @@ class PHYSICS_PT_smoke_cache(PhysicButtonsPanel):
domain = md.domain_settings
cache = domain.point_cache
layout.set_context_pointer("PointCache", cache)
row = layout.row()
row.template_list(cache, "point_cache_list", cache, "active_point_cache_index")
col = row.column(align=True)
col.itemO("ptcache.add_new", icon='ICON_ZOOMIN', text="")
col.itemO("ptcache.remove", icon='ICON_ZOOMOUT', text="")
row = layout.row()
row.itemR(cache, "name")
row = layout.row()
row.itemR(cache, "start_frame")
row.itemR(cache, "end_frame")
row = layout.row()
if cache.baked == True:
row.itemO("ptcache.free_bake", text="Free Bake")
else:
row.item_booleanO("ptcache.bake", "bake", True, text="Bake")
subrow = row.row()
subrow.enabled = cache.frames_skipped or cache.outdated
subrow.itemO("ptcache.bake", "bake", False, text="Calculate to Current Frame")
row = layout.row()
#row.enabled = smoke_panel_enabled(psys)
row.itemO("ptcache.bake_from_cache", text="Current Cache to Bake")
row = layout.row()
#row.enabled = smoke_panel_enabled(psys)
layout.itemL(text=cache.info)
layout.itemS()
row = layout.row()
row.itemO("ptcache.bake_all", "bake", True, text="Bake All Dynamics")
row.itemO("ptcache.free_bake_all", text="Free All Bakes")
layout.itemO("ptcache.bake_all", "bake", False, text="Update All Dynamics to current frame")
point_cache_ui(self, cache, cache.baked==False, 0, 1)
class PHYSICS_PT_smoke_highres(PhysicButtonsPanel):
__label__ = "Smoke High Resolution"
__default_closed__ = True

View File

@ -1,6 +1,11 @@
import bpy
from buttons_particle import point_cache_ui
def softbody_panel_enabled(md):
return md.point_cache.baked==False
class PhysicButtonsPanel(bpy.types.Panel):
__space_type__ = 'PROPERTIES'
__region_type__ = 'WINDOW'
@ -41,6 +46,7 @@ class PHYSICS_PT_softbody(PhysicButtonsPanel):
# General
split = layout.split()
split.enabled = softbody_panel_enabled(md)
col = split.column()
col.itemL(text="Object:")
@ -60,52 +66,9 @@ class PHYSICS_PT_softbody_cache(PhysicButtonsPanel):
return (context.soft_body)
def draw(self, context):
layout = self.layout
cache = context.soft_body.point_cache
layout.set_context_pointer("PointCache", cache)
row = layout.row()
row.template_list(cache, "point_cache_list", cache, "active_point_cache_index", rows=2)
col = row.column(align=True)
col.itemO("ptcache.add_new", icon='ICON_ZOOMIN', text="")
col.itemO("ptcache.remove", icon='ICON_ZOOMOUT', text="")
row = layout.row()
row.itemR(cache, "name")
row = layout.row()
row.itemR(cache, "start_frame")
row.itemR(cache, "end_frame")
row = layout.row()
if cache.baked == True:
row.itemO("ptcache.free_bake", text="Free Bake")
else:
row.item_booleanO("ptcache.bake", "bake", True, text="Bake")
sub = row.row()
sub.enabled = cache.frames_skipped or cache.outdated
sub.itemO("ptcache.bake", "bake", False, text="Calculate to Current Frame")
md = context.soft_body
point_cache_ui(self, md.point_cache, softbody_panel_enabled(md), 0, 0)
row = layout.row()
row.itemO("ptcache.bake_from_cache", text="Current Cache to Bake")
row.itemR(cache, "step");
row = layout.row()
row.itemR(cache, "quick_cache")
row.itemR(cache, "disk_cache")
layout.itemL(text=cache.info)
layout.itemS()
row = layout.row()
row.itemO("ptcache.bake_all", "bake", True, text="Bake All Dynamics")
row.itemO("ptcache.free_bake_all", text="Free All Bakes")
layout.itemO("ptcache.bake_all", "bake", False, text="Update All Dynamics to current frame")
class PHYSICS_PT_softbody_goal(PhysicButtonsPanel):
__label__ = "Soft Body Goal"
@ -117,6 +80,7 @@ class PHYSICS_PT_softbody_goal(PhysicButtonsPanel):
softbody = context.soft_body.settings
layout.active = softbody_panel_enabled(context.soft_body)
layout.itemR(softbody, "use_goal", text="")
def draw(self, context):
@ -129,7 +93,7 @@ class PHYSICS_PT_softbody_goal(PhysicButtonsPanel):
if md:
softbody = md.settings
layout.active = softbody.use_goal
layout.active = softbody.use_goal and softbody_panel_enabled(md)
# Goal
split = layout.split()
@ -159,6 +123,7 @@ class PHYSICS_PT_softbody_edge(PhysicButtonsPanel):
softbody = context.soft_body.settings
layout.active = softbody_panel_enabled(context.soft_body)
layout.itemR(softbody, "use_edges", text="")
def draw(self, context):
@ -170,7 +135,7 @@ class PHYSICS_PT_softbody_edge(PhysicButtonsPanel):
if md:
softbody = md.settings
layout.active = softbody.use_edges
layout.active = softbody.use_edges and softbody_panel_enabled(md)
split = layout.split()
@ -209,6 +174,7 @@ class PHYSICS_PT_softbody_collision(PhysicButtonsPanel):
softbody = context.soft_body.settings
layout.active = softbody_panel_enabled(context.soft_body)
layout.itemR(softbody, "self_collision", text="")
def draw(self, context):
@ -220,7 +186,7 @@ class PHYSICS_PT_softbody_collision(PhysicButtonsPanel):
if md:
softbody = md.settings
layout.active = softbody.self_collision
layout.active = softbody.self_collision and softbody_panel_enabled(md)
layout.itemL(text="Collision Type:")
layout.itemR(softbody, "collision_type", expand=True)
@ -245,6 +211,8 @@ class PHYSICS_PT_softbody_solver(PhysicButtonsPanel):
if md:
softbody = md.settings
layout.active = softbody_panel_enabled(md)
# Solver
split = layout.split()

View File

@ -362,8 +362,10 @@ class VIEW3D_PT_tools_brush(PaintPanel):
col = layout.column(align=True)
col.item_enumR(settings, "tool", 'DRAW')
col.item_enumR(settings, "tool", 'SOFTEN')
col.item_enumR(settings, "tool", 'CLONE')
col.item_enumR(settings, "tool", 'SMEAR')
if settings.use_projection:
col.item_enumR(settings, "tool", 'CLONE')
else:
col.item_enumR(settings, "tool", 'SMEAR')
col = layout.column()
col.itemR(brush, "color", text="")
@ -426,9 +428,9 @@ class VIEW3D_PT_tools_brush_stroke(PaintPanel):
if not texture_paint:
layout.itemR(brush, "smooth_stroke")
col = layout.column()
col.active = brush.smooth_stroke
col.itemR(brush, "smooth_stroke_radius", text="Radius", slider=True)
col.itemR(brush, "smooth_stroke_factor", text="Factor", slider=True)
col.itemR(brush, "airbrush")
col.itemR(brush, "anchored")
col.itemR(brush, "rake")
layout.itemR(brush, "space")
row = layout.row(align=True)
@ -538,22 +540,12 @@ class VIEW3D_PT_tools_vertexpaint(View3DPanel):
# col.itemR(vpaint, "mul", text="")
# ********** options for projection paint ****************
# ********** default tools for texturepaint ****************
class VIEW3D_PT_tools_projectpaint(View3DPanel):
class VIEW3D_PT_tools_texturepaint(View3DPanel):
__context__ = "texturepaint"
__label__ = "Project Paint"
def poll(self, context):
return context.tool_settings.image_paint.tool != 'SMEAR'
def draw_header(self, context):
layout = self.layout
ipaint = context.tool_settings.image_paint
__label__ = "Options"
layout.itemR(ipaint, "use_projection", text="")
def draw(self, context):
layout = self.layout
@ -562,6 +554,7 @@ class VIEW3D_PT_tools_projectpaint(View3DPanel):
use_projection= ipaint.use_projection
col = layout.column()
col.itemR(ipaint, "use_projection")
sub = col.column()
sub.active = use_projection
sub.itemR(ipaint, "use_occlude")
@ -606,22 +599,58 @@ class VIEW3D_PT_tools_particlemode(View3DPanel):
def draw(self, context):
layout = self.layout
pe = context.tool_settings.particle_edit
ob = pe.object
col = layout.column(align=True)
col.itemR(pe, "emitter_deflect", text="Deflect")
sub = col.row()
sub.active = pe.emitter_deflect
sub.itemR(pe, "emitter_distance", text="Distance")
row = layout.row()
row.itemL(text="Edit:")
row.itemR(pe, "type", text="")
if pe.type == 'PARTICLES':
if ob.particle_systems:
if len(ob.particle_systems) > 1:
layout.template_list(ob, "particle_systems", ob, "active_particle_system_index", type='ICONS')
ptcache = ob.particle_systems[ob.active_particle_system_index].point_cache
else:
for md in ob.modifiers:
if md.type==pe.type:
ptcache = md.point_cache
if ptcache and len(ptcache.point_cache_list) > 1:
layout.template_list(ptcache, "point_cache_list", ptcache, "active_point_cache_index", type='ICONS')
if not pe.editable:
layout.itemL(text="Point cache must be baked")
layout.itemL(text="to enable editing!")
col = layout.column(align=True)
if pe.hair:
col.active = pe.editable
col.itemR(pe, "emitter_deflect", text="Deflect emitter")
sub = col.row()
sub.active = pe.emitter_deflect
sub.itemR(pe, "emitter_distance", text="Distance")
col = layout.column(align=True)
col.active = pe.editable
col.itemL(text="Keep:")
col.itemR(pe, "keep_lengths", text="Lenghts")
col.itemR(pe, "keep_root", text="Root")
if not pe.hair:
col.itemL(text="Correct:")
col.itemR(pe, "auto_velocity", text="Velocity")
col = layout.column(align=True)
col.itemL(text="Display:")
col.itemR(pe, "show_time", text="Time")
col.itemR(pe, "show_children", text="Children")
col.active = pe.editable
col.itemL(text="Draw:")
col.itemR(pe, "draw_step", text="Path Steps")
if pe.type == 'PARTICLES':
col.itemR(pe, "draw_particles", text="Particles")
col.itemR(pe, "fade_time")
sub = col.row()
sub.active = pe.fade_time
sub.itemR(pe, "fade_frames", slider=True)
bpy.types.register(VIEW3D_PT_tools_objectmode)
bpy.types.register(VIEW3D_PT_tools_meshedit)
@ -638,5 +667,5 @@ bpy.types.register(VIEW3D_PT_tools_brush_curve)
bpy.types.register(VIEW3D_PT_sculpt_options)
bpy.types.register(VIEW3D_PT_tools_vertexpaint)
bpy.types.register(VIEW3D_PT_tools_weightpaint)
bpy.types.register(VIEW3D_PT_tools_projectpaint)
bpy.types.register(VIEW3D_PT_tools_texturepaint)
bpy.types.register(VIEW3D_PT_tools_particlemode)

View File

@ -109,46 +109,10 @@ typedef struct ParticleCacheKey{
float vel[3];
float rot[4];
float col[3];
float time;
int steps;
} ParticleCacheKey;
typedef struct ParticleEditKey{
float *co;
float *vel;
float *rot;
float *time;
float world_co[3];
float length;
short flag;
} ParticleEditKey;
typedef struct ParticleUndo {
struct ParticleUndo *next, *prev;
struct ParticleEditKey **keys;
struct KDTree *emitter_field;
struct ParticleData *particles;
float *emitter_cosnos;
int totpart, totkeys;
char name[64];
} ParticleUndo;
typedef struct ParticleEdit {
ListBase undo;
struct ParticleUndo *curundo;
ParticleEditKey **keys;
int totkeys;
int *mirror_cache;
struct KDTree *emitter_field;
float *emitter_cosnos;
char sel_col[3];
char nosel_col[3];
} ParticleEdit;
typedef struct ParticleThreadContext {
/* shared */
struct Scene *scene;
@ -240,7 +204,7 @@ int psys_check_enabled(struct Object *ob, struct ParticleSystem *psys);
void psys_free_boid_rules(struct ListBase *list);
void psys_free_settings(struct ParticleSettings *part);
void free_child_path_cache(struct ParticleSystem *psys);
void psys_free_path_cache(struct ParticleSystem *psys);
void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit);
void free_hair(struct ParticleSystem *psys, int softbody);
void free_keyed_keys(struct ParticleSystem *psys);
void psys_free(struct Object * ob, struct ParticleSystem * psys);
@ -271,9 +235,9 @@ void psys_reset(struct ParticleSystem *psys, int mode);
void psys_find_parents(struct Object *ob, struct ParticleSystemModifierData *psmd, struct ParticleSystem *psys);
void psys_cache_paths(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, float cfra, int editupdate);
void psys_cache_paths(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, float cfra);
void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra);
void psys_cache_child_paths(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, float cfra, int editupdate);
void psys_update_world_cos(struct Object *ob, struct ParticleSystem *psys);
int do_guide(struct Scene *scene, struct ParticleKey *state, int pa_num, float time, struct ListBase *lb);
float psys_get_size(struct Object *ob, struct Material *ma, struct ParticleSystemModifierData *psmd, struct IpoCurve *icu_size, struct ParticleSystem *psys, struct ParticleSettings *part, struct ParticleData *pa, float *vg_size);
float psys_get_timestep(struct ParticleSettings *part);
@ -359,12 +323,6 @@ void reset_particle(struct Scene *scene, struct ParticleData *pa, struct Particl
#define PSYS_EC_PARTICLE 4
#define PSYS_EC_REACTOR 8
/* ParticleEditKey->flag */
#define PEK_SELECT 1
#define PEK_TO_SELECT 2
#define PEK_TAG 4
#define PEK_HIDE 8
/* index_dmcache */
#define DMCACHE_NOTFOUND -1
#define DMCACHE_ISCHILD -2

View File

@ -101,6 +101,8 @@ typedef struct PTCacheFile {
void *cur[BPHYS_TOT_DATA];
} PTCacheFile;
#define PTCACHE_VEL_PER_SEC 1
typedef struct PTCacheID {
struct PTCacheID *next, *prev;
@ -109,6 +111,7 @@ typedef struct PTCacheID {
void *calldata;
int type;
int stack_index;
int flag;
/* flags defined in DNA_object_force.h */
unsigned int data_types, info_types;
@ -151,6 +154,75 @@ typedef struct PTCacheBaker {
void *progresscontext;
} 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;
/* 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 ParticleData *particles;
struct KDTree *emitter_field;
float *emitter_cosnos;
int *mirror_cache;
struct ParticleCacheKey **pathcache; /* path cache (runtime) */
ListBase pathcachebufs;
int totpoint, totframes, totcached, edited;
char sel_col[3];
char nosel_col[3];
} PTCacheEdit;
/* Particle functions */
void BKE_ptcache_make_particle_key(struct ParticleKey *key, int index, void **data, float time);
@ -179,6 +251,10 @@ void BKE_ptcache_update_info(PTCacheID *pid);
/* Size of cache data type. */
int BKE_ptcache_data_size(int data_type);
/* Memory cache read/write helpers. */
void BKE_ptcache_mem_init_pointers(struct PTCacheMem *pm);
void BKE_ptcache_mem_incr_pointers(struct PTCacheMem *pm);
/* Copy a specific data type from cache data to point data. */
void BKE_ptcache_data_get(void **data, int type, int index, void *to);
@ -197,7 +273,7 @@ int BKE_ptcache_get_continue_physics(void);
/******************* Allocate & free ***************/
struct PointCache *BKE_ptcache_add(struct ListBase *ptcaches);
void BKE_ptache_free_mem(struct PointCache *cache);
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, struct ListBase *ptcaches_old);

View File

@ -347,7 +347,7 @@ void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr)
BKE_ptcache_id_from_cloth(&pid, ob, clmd);
// don't do anything as long as we're in editmode!
if(pid.cache->flag & PTCACHE_BAKE_EDIT_ACTIVE)
if(pid.cache->edit && ob->mode & OB_MODE_PARTICLE_EDIT)
return;
BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_AFTER, framenr);

View File

@ -321,7 +321,7 @@ int psys_ob_has_hair(Object *ob)
}
int psys_in_edit_mode(Scene *scene, ParticleSystem *psys)
{
return ((scene->basact->object->mode & OB_MODE_PARTICLE_EDIT) && psys==psys_get_current((scene->basact)->object) && psys->edit);
return (scene->basact && (scene->basact->object->mode & OB_MODE_PARTICLE_EDIT) && psys==psys_get_current((scene->basact)->object) && (psys->edit || psys->pointcache->edit));
}
int psys_check_enabled(Object *ob, ParticleSystem *psys)
{
@ -406,13 +406,20 @@ void free_child_path_cache(ParticleSystem *psys)
psys->childcache = NULL;
psys->totchildcache = 0;
}
void psys_free_path_cache(ParticleSystem *psys)
void psys_free_path_cache(ParticleSystem *psys, PTCacheEdit *edit)
{
psys_free_path_cache_buffers(psys->pathcache, &psys->pathcachebufs);
psys->pathcache= NULL;
psys->totcached= 0;
if(edit) {
psys_free_path_cache_buffers(edit->pathcache, &edit->pathcachebufs);
edit->pathcache= NULL;
edit->totcached= 0;
}
else {
psys_free_path_cache_buffers(psys->pathcache, &psys->pathcachebufs);
psys->pathcache= NULL;
psys->totcached= 0;
free_child_path_cache(psys);
free_child_path_cache(psys);
}
}
void psys_free_children(ParticleSystem *psys)
{
@ -431,14 +438,14 @@ void psys_free(Object *ob, ParticleSystem * psys)
int nr = 0;
ParticleSystem * tpsys;
psys_free_path_cache(psys);
psys_free_path_cache(psys, NULL);
free_hair(psys, 1);
free_keyed_keys(psys);
if(psys->edit && psys->free_edit)
psys->free_edit(psys);
psys->free_edit(psys->edit);
if(psys->particles){
if(psys->particles->boid)
@ -645,7 +652,7 @@ void psys_render_restore(Object *ob, ParticleSystem *psys)
psmd->dm->release(psmd->dm);
}
psys_free_path_cache(psys);
psys_free_path_cache(psys, NULL);
if(psys->child){
MEM_freeN(psys->child);
@ -953,17 +960,25 @@ void psys_interpolate_particle(short type, ParticleKey keys[4], float dt, Partic
typedef struct ParticleInterpolationData {
ParticleKey *kkey[2];
HairKey *hkey[2];
BodyPoint *bp[2];
int keyed;
ParticleKey *kkey[2];
SoftBody *soft;
int keyed, cached;
BodyPoint *bp[2];
PointCache *cache;
PTCacheEditPoint *epoint;
PTCacheEditKey *ekey[2];
float birthtime, dietime;
int bspline;
} ParticleInterpolationData;
/* Assumes pointcache->mem_cache exists, so for disk cached particles call psys_make_temp_pointcache() before use */
static void get_pointcache_keys_for_time(Object *ob, ParticleSystem *psys, int index, float t, ParticleKey *key1, ParticleKey *key2)
static void get_pointcache_keys_for_time(Object *ob, PointCache *cache, int index, float t, ParticleKey *key1, ParticleKey *key2)
{
PointCache *cache = psys->pointcache;
static PTCacheMem *pm = NULL; /* not thread safe */
if(index < 0) { /* initialize */
@ -990,22 +1005,27 @@ static void get_pointcache_keys_for_time(Object *ob, ParticleSystem *psys, int i
static void init_particle_interpolation(Object *ob, ParticleSystem *psys, ParticleData *pa, ParticleInterpolationData *pind)
{
if(pind->keyed) {
pind->kkey[0] = pa->keys;
if(pind->epoint) {
PTCacheEditPoint *point = pind->epoint;
if(pa->totkey > 1)
pind->kkey[1] = pa->keys + 1;
else
pind->kkey[1] = NULL;
pind->ekey[0] = point->keys;
pind->ekey[1] = point->totkey > 1 ? point->keys + 1 : NULL;
pind->birthtime = *(point->keys->time);
pind->dietime = *((point->keys + point->totkey - 1)->time);
}
else if(pind->keyed) {
pind->kkey[0] = pa->keys;
pind->kkey[1] = pa->totkey > 1 ? pa->keys + 1 : NULL;
pind->birthtime = pa->keys->time;
pind->dietime = (pa->keys + pa->totkey - 1)->time;
}
else if(pind->cached) {
get_pointcache_keys_for_time(ob, psys, -1, 0.0f, NULL, NULL);
else if(pind->cache) {
get_pointcache_keys_for_time(ob, pind->cache, -1, 0.0f, NULL, NULL);
pind->birthtime = pa->time;
pind->dietime = pa->dietime;
pind->birthtime = pa ? pa->time : pind->cache->startframe;
pind->dietime = pa ? pa->dietime : pind->cache->endframe;
}
else {
pind->hkey[0] = pa->hair;
@ -1020,6 +1040,14 @@ static void init_particle_interpolation(Object *ob, ParticleSystem *psys, Partic
pind->bp[1] = pind->soft->bpoint + pa->bpi + 1;
}
}
static void edit_to_particle(ParticleKey *key, PTCacheEditKey *ekey)
{
VECCOPY(key->co, ekey->co);
if(ekey->vel) {
VECCOPY(key->vel, ekey->vel);
}
key->time = *(ekey->time);
}
static void hair_to_particle(ParticleKey *key, HairKey *hkey)
{
VECCOPY(key->co, hkey->co);
@ -1033,11 +1061,24 @@ static void bp_to_particle(ParticleKey *key, BodyPoint *bp, HairKey *hkey)
static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData *pa, float t, float frs_sec, ParticleInterpolationData *pind, ParticleKey *result)
{
PTCacheEditPoint *point = pind->epoint;
ParticleKey keys[4];
int point_vel = (point && point->keys->vel);
float real_t, dfra, keytime;
/* interpret timing and find keys */
if(pind->keyed) {
if(point) {
if(result->time < 0.0f)
real_t = -result->time;
else
real_t = *(pind->ekey[0]->time) + t * (*(pind->ekey[0][point->totkey-1].time) - *(pind->ekey[0]->time));
while(*(pind->ekey[1]->time) < real_t)
pind->ekey[1]++;
pind->ekey[0] = pind->ekey[1] - 1;
}
else if(pind->keyed) {
/* we have only one key, so let's use that */
if(pind->kkey[1]==NULL) {
copy_particle_key(result, pind->kkey[0], 1);
@ -1074,7 +1115,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
pind->kkey[0] = pind->kkey[1] - 1;
}
else if(pind->cached) {
else if(pind->cache) {
if(result->time < 0.0f) /* flag for time in frames */
real_t = -result->time;
else
@ -1095,7 +1136,11 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
}
/* set actual interpolation keys */
if(pind->soft) {
if(point) {
edit_to_particle(keys + 1, pind->ekey[0]);
edit_to_particle(keys + 2, pind->ekey[1]);
}
else if(pind->soft) {
pind->bp[0] = pind->bp[1] - 1;
bp_to_particle(keys + 1, pind->bp[0], pind->hkey[0]);
bp_to_particle(keys + 2, pind->bp[1], pind->hkey[1]);
@ -1104,8 +1149,8 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
memcpy(keys + 1, pind->kkey[0], sizeof(ParticleKey));
memcpy(keys + 2, pind->kkey[1], sizeof(ParticleKey));
}
else if(pind->cached) {
get_pointcache_keys_for_time(NULL, psys, p, real_t, keys+1, keys+2);
else if(pind->cache) {
get_pointcache_keys_for_time(NULL, pind->cache, p, real_t, keys+1, keys+2);
}
else {
hair_to_particle(keys + 1, pind->hkey[0]);
@ -1113,8 +1158,14 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
}
/* set secondary interpolation keys for hair */
if(!pind->keyed && !pind->cached) {
if(pind->soft) {
if(!pind->keyed && !pind->cache && !point_vel) {
if(point) {
if(pind->ekey[0] != point->keys)
edit_to_particle(keys, pind->ekey[0] - 1);
else
edit_to_particle(keys, pind->ekey[0]);
}
else if(pind->soft) {
if(pind->hkey[0] != pa->hair)
bp_to_particle(keys, pind->bp[0] - 1, pind->hkey[0] - 1);
else
@ -1127,7 +1178,13 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
hair_to_particle(keys, pind->hkey[0]);
}
if(pind->soft) {
if(point) {
if(pind->ekey[1] != point->keys + point->totkey - 1)
edit_to_particle(keys + 3, pind->ekey[1] + 1);
else
edit_to_particle(keys + 3, pind->ekey[1]);
}
else if(pind->soft) {
if(pind->hkey[1] != pa->hair + pa->totkey - 1)
bp_to_particle(keys + 3, pind->bp[1] + 1, pind->hkey[1] + 1);
else
@ -1145,19 +1202,19 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
keytime = (real_t - keys[1].time) / dfra;
/* convert velocity to timestep size */
if(pind->keyed || pind->cached){
if(pind->keyed || pind->cache || point_vel){
VecMulf(keys[1].vel, dfra / frs_sec);
VecMulf(keys[2].vel, dfra / frs_sec);
QuatInterpol(result->rot,keys[1].rot,keys[2].rot,keytime);
}
/* now we should have in chronologiacl order k1<=k2<=t<=k3<=k4 with keytime between [0,1]->[k2,k3] (k1 & k4 used for cardinal & bspline interpolation)*/
psys_interpolate_particle((pind->keyed || pind->cached) ? -1 /* signal for cubic interpolation */
: ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL)
psys_interpolate_particle((pind->keyed || pind->cache || point_vel) ? -1 /* signal for cubic interpolation */
: (pind->bspline ? KEY_BSPLINE : KEY_CARDINAL)
,keys, keytime, result, 1);
/* the velocity needs to be converted back from cubic interpolation */
if(pind->keyed || pind->cached)
if(pind->keyed || pind->cache || point_vel)
VecMulf(result->vel, frs_sec / dfra);
}
/************************************************/
@ -1610,7 +1667,7 @@ ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys)
}
}
}
return 0;
return NULL;
}
/************************************************/
/* Particles on a shape */
@ -2129,7 +2186,7 @@ int psys_threads_init_path(ParticleThread *threads, Scene *scene, float cfra, in
/*---start figuring out what is actually wanted---*/
if(psys_in_edit_mode(scene, psys))
if(psys->renderdata==0 && (psys->edit==NULL || pset->flag & PE_SHOW_CHILD)==0)
if(psys->renderdata==0 && (psys->edit==NULL || pset->flag & PE_DRAW_PART)==0)
totchild=0;
if(totchild && part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){
@ -2245,7 +2302,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
needupdate= 0;
w= 0;
while(w<4 && cpa->pa[w]>=0) {
if(psys->particles[cpa->pa[w]].flag & PARS_EDIT_RECALC) {
if(psys->edit->points[cpa->pa[w]].flag & PEP_EDIT_RECALC) {
needupdate= 1;
break;
}
@ -2288,7 +2345,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa,
}
else{
if(ctx->editupdate && !(part->flag & PART_BRANCHING)) {
if(!(psys->particles[cpa->parent].flag & PARS_EDIT_RECALC))
if(!(psys->edit->points[cpa->parent].flag & PEP_EDIT_RECALC))
return;
memset(keys, 0, sizeof(*keys)*(ctx->steps+1));
@ -2557,24 +2614,20 @@ void psys_cache_child_paths(Scene *scene, Object *ob, ParticleSystem *psys, floa
/* -Usefull for making use of opengl vertex arrays for super fast strand drawing. */
/* -Makes child strands possible and creates them too into the cache. */
/* -Cached path data is also used to determine cut position for the editmode tool. */
void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra, int editupdate)
void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra)
{
ParticleCacheKey *ca, **cache=psys->pathcache;
ParticleCacheKey *ca, **cache= psys->pathcache;
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
ParticleEditSettings *pset = &scene->toolsettings->particle;
ParticleSettings *part = psys->part;
ParticleEditSettings *pset = &scene->toolsettings->particle;
ParticleData *pa;
ParticleData *pa = psys->particles;
ParticleKey result;
ParticleEdit *edit = 0;
ParticleEditKey *ekey = 0;
SoftBody *soft = 0;
SoftBody *soft = NULL;
BodyPoint *bp[2] = {NULL, NULL};
Material *ma;
ParticleInterpolationData pind;
float birthtime = 0.0, dietime = 0.0;
@ -2583,132 +2636,98 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
float prev_tangent[3], hairmat[4][4];
float rotmat[3][3];
int k,i;
int steps = (int)pow(2.0, (double)psys->part->draw_step);
int steps = (int)pow(2.0, (double)(psys->renderdata ? part->ren_step : part->draw_step));
int totpart = psys->totpart;
float sel_col[3];
float nosel_col[3];
float length, vec[3];
float *vg_effector= NULL, effector=0.0f;
float *vg_length= NULL, pa_length=1.0f;
int keyed, baked;
/* we don't have anything valid to create paths from so let's quit here */
if((psys->flag & PSYS_HAIR_DONE)==0 && (psys->flag & PSYS_KEYED)==0 && (psys->pointcache->flag & PTCACHE_BAKED)==0)
if(!(psys->flag & PSYS_HAIR_DONE) && !(psys->flag & PSYS_KEYED) && !(psys->pointcache->flag & PTCACHE_BAKED))
return;
if(psys_in_edit_mode(scene, psys))
if(psys->renderdata==0 && (psys->edit==NULL || pset->flag & PE_DRAW_PART)==0)
return;
BLI_srandom(psys->seed);
keyed = psys->flag & PSYS_KEYED;
baked = psys->pointcache->flag & PTCACHE_BAKED;
if(psys->renderdata) {
steps = (int)pow(2.0, (double)psys->part->ren_step);
}
else if(psys_in_edit_mode(scene, psys)) {
edit=psys->edit;
//timed = edit->draw_timed;
/* clear out old and create new empty path cache */
psys_free_path_cache(psys, NULL);
cache= psys->pathcache= psys_alloc_path_cache_buffers(&psys->pathcachebufs, totpart, steps+1);
if(pset->brushtype == PE_BRUSH_WEIGHT) {
sel_col[0] = sel_col[1] = sel_col[2] = 1.0f;
nosel_col[0] = nosel_col[1] = nosel_col[2] = 0.0f;
}
else{
sel_col[0] = (float)edit->sel_col[0] / 255.0f;
sel_col[1] = (float)edit->sel_col[1] / 255.0f;
sel_col[2] = (float)edit->sel_col[2] / 255.0f;
nosel_col[0] = (float)edit->nosel_col[0] / 255.0f;
nosel_col[1] = (float)edit->nosel_col[1] / 255.0f;
nosel_col[2] = (float)edit->nosel_col[2] / 255.0f;
}
}
if(editupdate && psys->pathcache && totpart == psys->totcached) {
cache = psys->pathcache;
}
else {
/* clear out old and create new empty path cache */
psys_free_path_cache(psys);
cache= psys_alloc_path_cache_buffers(&psys->pathcachebufs, totpart, steps+1);
psys->pathcache= cache;
}
if(edit==NULL && psys->soft && psys->softflag & OB_SB_ENABLE) {
if(psys->soft && psys->softflag & OB_SB_ENABLE) {
soft = psys->soft;
if(!soft->bpoint)
soft= NULL;
}
psys->lattice = psys_get_lattice(scene, ob, psys);
ma= give_current_material(ob, psys->part->omat);
if(ma && (psys->part->draw & PART_DRAW_MAT_COL))
VECCOPY(col, &ma->r)
if(psys->part->from!=PART_FROM_PARTICLE) {
if(!(psys->part->flag & PART_CHILD_EFFECT))
vg_effector = psys_cache_vgroup(psmd->dm, psys, PSYS_VG_EFFECTOR);
if(!edit && !psys->totchild)
if(!psys->totchild)
vg_length = psys_cache_vgroup(psmd->dm, psys, PSYS_VG_LENGTH);
}
/*---first main loop: create all actual particles' paths---*/
for(i=0,pa=psys->particles; i<totpart; i++, pa++){
if(psys && edit==NULL && (pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST)) {
for(i=0; i<totpart; i++, pa++){
if(pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST) {
if(soft)
bp[0] += pa->totkey; /* TODO use of initialized value? */
continue;
}
if(editupdate && !(pa->flag & PARS_EDIT_RECALC)) continue;
else memset(cache[i], 0, sizeof(*cache[i])*(steps+1));
if(!edit && !psys->totchild) {
if(!psys->totchild) {
pa_length = 1.0f - part->randlength * 0.5 * (1.0f + pa->r_ave[0]);
if(vg_length)
pa_length *= psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_length);
}
pind.keyed = keyed;
pind.cache = baked ? psys->pointcache : NULL;
pind.soft = soft;
pind.epoint = NULL;
pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE);
memset(cache[i], 0, sizeof(*cache[i])*(steps+1));
cache[i]->steps = steps;
if(edit)
ekey = edit->keys[i];
/*--get the first data points--*/
pind.keyed = keyed;
pind.cached = baked;
pind.soft = soft;
init_particle_interpolation(ob, psys, pa, &pind);
/* hairmat is needed for for non-hair particle too so we get proper rotations */
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
VECCOPY(rotmat[0], hairmat[2]);
VECCOPY(rotmat[1], hairmat[1]);
VECCOPY(rotmat[2], hairmat[0]);
if(!edit) {
if(part->draw & PART_ABS_PATH_TIME) {
birthtime = MAX2(pind.birthtime, part->path_start);
dietime = MIN2(pind.dietime, part->path_end);
}
else {
float tb = pind.birthtime;
birthtime = tb + part->path_start * (pind.dietime - tb);
dietime = tb + part->path_end * (pind.dietime - tb);
}
if(birthtime >= dietime) {
cache[i]->steps = -1;
continue;
}
dietime = birthtime + pa_length * (dietime - birthtime);
if(part->draw & PART_ABS_PATH_TIME) {
birthtime = MAX2(pind.birthtime, part->path_start);
dietime = MIN2(pind.dietime, part->path_end);
}
else
/* XXX brecht: don't know if this code from 2.4 is correct
* still, but makes hair appear again in particle mode */
dietime= pind.hkey[0][pa->totkey-1].time;
else {
float tb = pind.birthtime;
birthtime = tb + part->path_start * (pind.dietime - tb);
dietime = tb + part->path_end * (pind.dietime - tb);
}
if(birthtime >= dietime) {
cache[i]->steps = -1;
continue;
}
dietime = birthtime + pa_length * (dietime - birthtime);
/*--interpolate actual path from data points--*/
for(k=0, ca=cache[i]; k<=steps; k++, ca++){
@ -2726,40 +2745,8 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
}
VECCOPY(ca->co, result.co);
/* selection coloring in edit mode */
if(edit){
if(pset->brushtype==PE_BRUSH_WEIGHT){
if(k==steps)
VecLerpf(ca->col, nosel_col, sel_col, pind.hkey[0]->weight);
else
VecLerpf(ca->col, nosel_col, sel_col,
(1.0f - keytime) * pind.hkey[0]->weight + keytime * pind.hkey[1]->weight);
}
else{
if((ekey + (pind.hkey[0] - pa->hair))->flag & PEK_SELECT){
if((ekey + (pind.hkey[1] - pa->hair))->flag & PEK_SELECT){
VECCOPY(ca->col, sel_col);
}
else{
VecLerpf(ca->col, sel_col, nosel_col, keytime);
}
}
else{
if((ekey + (pind.hkey[1] - pa->hair))->flag & PEK_SELECT){
VecLerpf(ca->col, nosel_col, sel_col, keytime);
}
else{
VECCOPY(ca->col, nosel_col);
}
}
}
}
else{
VECCOPY(ca->col, col);
}
VECCOPY(ca->col, col);
}
/*--modify paths and calculate rotation & velocity--*/
@ -2772,16 +2759,16 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
for(k=0, ca=cache[i]; k<=steps; k++, ca++) {
/* apply effectors */
if(!(psys->part->flag & PART_CHILD_EFFECT) && edit==0 && k)
if(!(psys->part->flag & PART_CHILD_EFFECT) && k)
do_path_effectors(scene, ob, psys, i, ca, k, steps, cache[i]->co, effector, dfra, cfra, &length, vec);
/* apply guide curves to path data */
if(edit==0 && psys->effectors.first && (psys->part->flag & PART_CHILD_EFFECT)==0)
if(psys->effectors.first && (psys->part->flag & PART_CHILD_EFFECT)==0)
/* ca is safe to cast, since only co and vel are used */
do_guide(scene, (ParticleKey*)ca, i, (float)k/(float)steps, &psys->effectors);
/* apply lattice */
if(psys->lattice && edit==0)
if(psys->lattice)
calc_latt_deform(psys->lattice, ca->co, 1.0f);
/* figure out rotation */
@ -2810,8 +2797,8 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
cosangle= Inpf(tangent, prev_tangent);
/* note we do the comparison on cosangle instead of
* angle, since floating point accuracy makes it give
* different results across platforms */
* angle, since floating point accuracy makes it give
* different results across platforms */
if(cosangle > 0.999999f) {
QUATCOPY((ca - 1)->rot, (ca - 2)->rot);
}
@ -2856,6 +2843,124 @@ void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra
if(vg_length)
MEM_freeN(vg_length);
}
void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cfra)
{
ParticleCacheKey *ca, **cache= edit->pathcache;
ParticleEditSettings *pset = &scene->toolsettings->particle;
PTCacheEditPoint *point = edit->points;
PTCacheEditKey *ekey = NULL;
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
ParticleSettings *part = psys ? psys->part : NULL;
ParticleData *pa = psys ? psys->particles : NULL;
ParticleInterpolationData pind;
ParticleKey result;
float birthtime = 0.0, dietime = 0.0;
float t, time = 0.0, keytime = 0.0, dfra = 1.0, frs_sec;
float hairmat[4][4];
int k,i;
int steps = (int)pow(2.0, (double)pset->draw_step);
int totpart = edit->totpoint;
float sel_col[3];
float nosel_col[3];
steps = MAX2(steps, 4);
if(!cache || edit->totpoint != edit->totcached) {
/* clear out old and create new empty path cache */
psys_free_path_cache(NULL, edit);
cache= edit->pathcache= psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, steps+1);
}
frs_sec = (psys || edit->pid.flag & PTCACHE_VEL_PER_SEC) ? 25.0f : 1.0f;
sel_col[0] = (float)edit->sel_col[0] / 255.0f;
sel_col[1] = (float)edit->sel_col[1] / 255.0f;
sel_col[2] = (float)edit->sel_col[2] / 255.0f;
nosel_col[0] = (float)edit->nosel_col[0] / 255.0f;
nosel_col[1] = (float)edit->nosel_col[1] / 255.0f;
nosel_col[2] = (float)edit->nosel_col[2] / 255.0f;
/*---first main loop: create all actual particles' paths---*/
for(i=0; i<totpart; i++, pa+=pa?1:0, point++){
if(edit->totcached && !(point->flag & PEP_EDIT_RECALC))
continue;
ekey = point->keys;
pind.keyed = 0;
pind.cache = NULL;
pind.soft = NULL;
pind.epoint = point;
pind.bspline = psys ? (psys->part->flag & PART_HAIR_BSPLINE) : 0;
memset(cache[i], 0, sizeof(*cache[i])*(steps+1));
cache[i]->steps = steps;
/*--get the first data points--*/
init_particle_interpolation(ob, psys, pa, &pind);
if(psys)
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
birthtime = pind.birthtime;
dietime = pind.dietime;
if(birthtime >= dietime) {
cache[i]->steps = -1;
continue;
}
/*--interpolate actual path from data points--*/
for(k=0, ca=cache[i]; k<=steps; k++, ca++){
time = (float)k / (float)steps;
t = birthtime + time * (dietime - birthtime);
result.time = -t;
do_particle_interpolation(psys, i, pa, t, frs_sec, &pind, &result);
/* non-hair points are allready in global space */
if(psys)
Mat4MulVecfl(hairmat, result.co);
VECCOPY(ca->co, result.co);
ca->vel[0] = ca->vel[1] = 0.0f;
ca->vel[1] = 1.0f;
/* selection coloring in edit mode */
if((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT){
if((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT){
VECCOPY(ca->col, sel_col);
}
else{
keytime = (t - (*pind.ekey[0]->time))/((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
VecLerpf(ca->col, sel_col, nosel_col, keytime);
}
}
else{
if((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT){
keytime = (t - (*pind.ekey[0]->time))/((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
VecLerpf(ca->col, nosel_col, sel_col, keytime);
}
else{
VECCOPY(ca->col, nosel_col);
}
}
ca->time = t;
}
}
edit->totcached = totpart;
}
/************************************************/
/* Particle Key handling */
/************************************************/
@ -3663,8 +3768,9 @@ void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, i
}
pind.keyed = keyed;
pind.cached = cached;
pind.cache = cached ? psys->pointcache : NULL;
pind.soft = NULL;
pind.epoint = NULL;
init_particle_interpolation(ob, psys, pa, &pind);
do_particle_interpolation(psys, p, pa, t, frs_sec, &pind, state);

View File

@ -127,7 +127,7 @@ void psys_reset(ParticleSystem *psys, int mode)
int i;
if(ELEM(mode, PSYS_RESET_ALL, PSYS_RESET_DEPSGRAPH)) {
if(mode == PSYS_RESET_ALL || !(part->type == PART_HAIR && (psys->flag & PSYS_EDITED))) {
if(mode == PSYS_RESET_ALL || !(part->type == PART_HAIR && (psys->edit && psys->edit->edited))) {
if(psys->particles) {
if(psys->particles->keys)
MEM_freeN(psys->particles->keys);
@ -145,6 +145,12 @@ void psys_reset(ParticleSystem *psys, int mode)
if(psys->reactevents.first)
BLI_freelistN(&psys->reactevents);
if(psys->edit && psys->free_edit) {
psys->free_edit(psys->edit);
psys->edit = NULL;
psys->free_edit = NULL;
}
}
}
else if(mode == PSYS_RESET_CACHE_MISS) {
@ -165,7 +171,7 @@ void psys_reset(ParticleSystem *psys, int mode)
psys->totchild= 0;
/* reset path cache */
psys_free_path_cache(psys);
psys_free_path_cache(psys, NULL);
/* reset point cache */
psys->pointcache->flag &= ~PTCACHE_SIMULATION_VALID;
@ -2274,7 +2280,7 @@ void psys_clear_temp_pointcache(ParticleSystem *psys)
if((psys->pointcache->flag & PTCACHE_DISK_CACHE)==0)
return;
BKE_ptache_free_mem(psys->pointcache);
BKE_ptcache_free_mem(&psys->pointcache->mem_cache);
}
void psys_get_pointcache_start_end(Scene *scene, ParticleSystem *psys, int *sfra, int *efra)
{
@ -3747,41 +3753,17 @@ static void psys_update_path_cache(Scene *scene, Object *ob, ParticleSystemModif
if((part->type==PART_HAIR || psys->flag&PSYS_KEYED || psys->pointcache->flag & PTCACHE_BAKED) && ( psys_in_edit_mode(scene, psys) || (part->type==PART_HAIR
|| (part->ren_as == PART_DRAW_PATH && (part->draw_as == PART_DRAW_REND || psys->renderdata))))){
psys_cache_paths(scene, ob, psys, cfra, 0);
psys_cache_paths(scene, ob, psys, cfra);
/* for render, child particle paths are computed on the fly */
if(part->childtype) {
if(((psys->totchild!=0)) || (psys_in_edit_mode(scene, psys) && (pset->flag&PE_SHOW_CHILD)))
if(((psys->totchild!=0)) || (psys_in_edit_mode(scene, psys) && (pset->flag&PE_DRAW_PART)))
if(!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE))
psys_cache_child_paths(scene, ob, psys, cfra, 0);
}
}
else if(psys->pathcache)
psys_free_path_cache(psys);
}
/* calculate and store key locations in world coordinates */
void psys_update_world_cos(Object *ob, ParticleSystem *psys)
{
ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
ParticleData *pa;
ParticleEditKey *key;
int i, k, totpart;
float hairmat[4][4];
if(psys==0 || psys->edit==0)
return;
totpart= psys->totpart;
for(i=0, pa=psys->particles; i<totpart; i++, pa++) {
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
for(k=0, key=psys->edit->keys[i]; k<pa->totkey; k++, key++) {
VECCOPY(key->world_co,key->co);
Mat4MulVecfl(hairmat, key->world_co);
}
}
psys_free_path_cache(psys, NULL);
}
static void hair_step(Scene *scene, Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra)
@ -3808,9 +3790,6 @@ static void hair_step(Scene *scene, Object *ob, ParticleSystemModifierData *psmd
psys_init_effectors(scene, ob, part->eff_group, psys);
if(psys->effectors.first)
precalc_effectors(scene, ob,psys,psmd,cfra);
if(psys_in_edit_mode(scene, psys))
psys_update_world_cos(ob, psys);
psys_update_path_cache(scene, ob,psmd,psys,cfra);
}
@ -4339,7 +4318,7 @@ static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, Particle
psys_update_path_cache(scene, ob, psmd, psys,(int)cfra);
}
else if(psys->pathcache)
psys_free_path_cache(psys);
psys_free_path_cache(psys, NULL);
/* cleanup */
if(vg_vel) MEM_freeN(vg_vel);
@ -4385,7 +4364,7 @@ static void psys_to_softbody(Scene *scene, Object *ob, ParticleSystem *psys)
static int hair_needs_recalc(ParticleSystem *psys)
{
if((psys->flag & PSYS_EDITED)==0 &&
if((!psys->edit || !psys->edit->edited) &&
((psys->flag & PSYS_HAIR_DONE)==0 || psys->recalc & PSYS_RECALC_RESET)) {
return 1;
}

View File

@ -434,6 +434,8 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p
pid->cache_ptr= &psys->pointcache;
pid->ptcaches= &psys->ptcaches;
pid->flag |= PTCACHE_VEL_PER_SEC;
pid->write_elem= ptcache_write_particle;
pid->write_stream = NULL;
pid->read_stream = NULL;
@ -800,14 +802,16 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob)
}
for(psys=ob->particlesystem.first; psys; psys=psys->next) {
pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
BKE_ptcache_id_from_particles(pid, ob, psys);
BLI_addtail(lb, pid);
if(psys->soft) {
if(psys->part) {
pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
BKE_ptcache_id_from_softbody(pid, ob, psys->soft);
BKE_ptcache_id_from_particles(pid, ob, psys);
BLI_addtail(lb, pid);
if(psys->soft) {
pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
BKE_ptcache_id_from_softbody(pid, ob, psys->soft);
BLI_addtail(lb, pid);
}
}
}
@ -1087,7 +1091,7 @@ static void ptcache_file_init_pointers(PTCacheFile *pf)
pf->cur[BPHYS_DATA_BOIDS] = data_types & (1<<BPHYS_DATA_BOIDS) ? &pf->data.boids : NULL;
}
static void ptcache_mem_init_pointers(PTCacheMem *pm)
void BKE_ptcache_mem_init_pointers(PTCacheMem *pm)
{
int data_types = pm->data_types;
int i;
@ -1096,7 +1100,7 @@ static void ptcache_mem_init_pointers(PTCacheMem *pm)
pm->cur[i] = data_types & (1<<i) ? pm->data[i] : NULL;
}
static void ptcache_mem_incr_pointers(PTCacheMem *pm)
void BKE_ptcache_mem_incr_pointers(PTCacheMem *pm)
{
int i;
@ -1249,12 +1253,12 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec)
return 0;
if(pm) {
ptcache_mem_init_pointers(pm);
BKE_ptcache_mem_init_pointers(pm);
totpoint = pm->totpoint;
index = pm->data_types & (1<<BPHYS_DATA_INDEX) ? pm->cur[BPHYS_DATA_INDEX] : &i;
}
if(pm2) {
ptcache_mem_init_pointers(pm2);
BKE_ptcache_mem_init_pointers(pm2);
totpoint2 = pm2->totpoint;
index2 = pm2->data_types & (1<<BPHYS_DATA_INDEX) ? pm2->cur[BPHYS_DATA_INDEX] : &i;
}
@ -1336,7 +1340,7 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec)
}
if(pm) {
ptcache_mem_incr_pointers(pm);
BKE_ptcache_mem_incr_pointers(pm);
index = pm->data_types & (1<<BPHYS_DATA_INDEX) ? pm->cur[BPHYS_DATA_INDEX] : &i;
}
}
@ -1387,7 +1391,7 @@ int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec)
}
if(pm2) {
ptcache_mem_incr_pointers(pm2);
BKE_ptcache_mem_incr_pointers(pm2);
index2 = pm2->data_types & (1<<BPHYS_DATA_INDEX) ? pm2->cur[BPHYS_DATA_INDEX] : &i;
}
}
@ -1559,11 +1563,11 @@ int BKE_ptcache_write_cache(PTCacheID *pid, int cfra)
pm->data_types = cfra ? pid->data_types : pid->info_types;
ptcache_alloc_data(pm);
ptcache_mem_init_pointers(pm);
BKE_ptcache_mem_init_pointers(pm);
for(i=0; i<totpoint; i++) {
if(pid->write_elem && pid->write_elem(i, pid->calldata, pm->cur))
ptcache_mem_incr_pointers(pm);
BKE_ptcache_mem_incr_pointers(pm);
}
//ptcache_make_index_array(pm, pid->totpoint(pid->calldata));
@ -1664,6 +1668,8 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra)
PTCacheMem *pm= pid->cache->mem_cache.first;
PTCacheMem *link= NULL;
pm= pid->cache->mem_cache.first;
if(mode == PTCACHE_CLEAR_ALL) {
pid->cache->last_exact = 0;
for(; pm; pm=pm->next)
@ -1863,7 +1869,7 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
else if(psys->recalc & PSYS_RECALC_REDO || psys->recalc & PSYS_RECALC_CHILD)
skip = 1;
if(skip == 0) {
if(skip == 0 && psys->part) {
BKE_ptcache_id_from_particles(&pid, ob, psys);
reset |= BKE_ptcache_id_reset(scene, &pid, mode);
}
@ -1968,9 +1974,9 @@ PointCache *BKE_ptcache_add(ListBase *ptcaches)
return cache;
}
void BKE_ptache_free_mem(PointCache *cache)
void BKE_ptcache_free_mem(ListBase *mem_cache)
{
PTCacheMem *pm = cache->mem_cache.first;
PTCacheMem *pm = mem_cache->first;
if(pm) {
for(; pm; pm=pm->next) {
@ -1979,22 +1985,25 @@ void BKE_ptache_free_mem(PointCache *cache)
MEM_freeN(pm->index_array);
}
BLI_freelistN(&cache->mem_cache);
BLI_freelistN(mem_cache);
}
}
void BKE_ptcache_free(PointCache *cache)
{
BKE_ptache_free_mem(cache);
BKE_ptcache_free_mem(&cache->mem_cache);
if(cache->edit && cache->free_edit)
cache->free_edit(cache->edit);
MEM_freeN(cache);
}
void BKE_ptcache_free_list(ListBase *ptcaches)
{
PointCache *cache = ptcaches->first;
for(; cache; cache=cache->next)
BKE_ptache_free_mem(cache);
BLI_freelistN(ptcaches);
while(cache) {
BLI_remlink(ptcaches, cache);
BKE_ptcache_free(cache);
cache = ptcaches->first;
}
}
static PointCache *ptcache_copy(PointCache *cache)
@ -2258,7 +2267,7 @@ void BKE_ptcache_disk_to_mem(PTCacheID *pid)
pm->frame = cfra;
ptcache_alloc_data(pm);
ptcache_mem_init_pointers(pm);
BKE_ptcache_mem_init_pointers(pm);
ptcache_file_init_pointers(pf);
for(i=0; i<pm->totpoint; i++) {
@ -2274,7 +2283,7 @@ void BKE_ptcache_disk_to_mem(PTCacheID *pid)
return;
}
ptcache_copy_data(pf->cur, pm->cur);
ptcache_mem_incr_pointers(pm);
BKE_ptcache_mem_incr_pointers(pm);
}
//ptcache_make_index_array(pm, pid->totpoint(pid->calldata));
@ -2305,7 +2314,7 @@ void BKE_ptcache_mem_to_disk(PTCacheID *pid)
pf->totpoint = pm->totpoint;
pf->type = pid->type;
ptcache_mem_init_pointers(pm);
BKE_ptcache_mem_init_pointers(pm);
ptcache_file_init_pointers(pf);
if(!ptcache_file_write_header_begin(pf) || !pid->write_header(pf)) {
@ -2325,7 +2334,7 @@ void BKE_ptcache_mem_to_disk(PTCacheID *pid)
ptcache_file_close(pf);
return;
}
ptcache_mem_incr_pointers(pm);
BKE_ptcache_mem_incr_pointers(pm);
}
ptcache_file_close(pf);

View File

@ -404,11 +404,13 @@ Scene *add_scene(char *name)
sce->unit.scale_length = 1.0f;
pset= &sce->toolsettings->particle;
pset->flag= PE_KEEP_LENGTHS|PE_LOCK_FIRST|PE_DEFLECT_EMITTER;
pset->flag= PE_KEEP_LENGTHS|PE_LOCK_FIRST|PE_DEFLECT_EMITTER|PE_AUTO_VELOCITY;
pset->emitterdist= 0.25f;
pset->totrekey= 5;
pset->totaddkey= 5;
pset->brushtype= PE_BRUSH_NONE;
pset->draw_step= 2;
pset->fade_frames= 2;
for(a=0; a<PE_TOT_BRUSH; a++) {
pset->brush[a].strength= 50;
pset->brush[a].size= 50;

View File

@ -2963,8 +2963,10 @@ static void direct_link_pointcache(FileData *fd, PointCache *cache)
else
cache->mem_cache.first = cache->mem_cache.last = NULL;
cache->flag &= ~(PTCACHE_SIMULATION_VALID|PTCACHE_BAKE_EDIT_ACTIVE);
cache->flag &= ~PTCACHE_SIMULATION_VALID;
cache->simframe= 0;
cache->edit= NULL;
cache->free_edit= NULL;
}
static void direct_link_pointcache_list(FileData *fd, ListBase *ptcaches, PointCache **ocache)
@ -3137,7 +3139,7 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
link_list(fd, &psys->targets);
psys->edit = 0;
psys->edit = NULL;
psys->free_edit = NULL;
psys->pathcache = 0;
psys->childcache = 0;

View File

@ -1208,7 +1208,7 @@ static void write_objects(WriteData *wd, ListBase *idbase)
writestruct(wd, DATA, "PartDeflect", 1, ob->pd);
writestruct(wd, DATA, "SoftBody", 1, ob->soft);
if(ob->soft) writestruct(wd, DATA, "PointCache", 1, ob->soft->pointcache);
if(ob->soft) write_pointcaches(wd, &ob->soft->ptcaches);
writestruct(wd, DATA, "BulletSoftBody", 1, ob->bsoft);
write_particlesystems(wd, &ob->particlesystem);

View File

@ -39,18 +39,16 @@ struct rcti;
struct wmWindowManager;
/* particle edit mode */
void PE_change_act(void *ob_v, void *act_v);
void PE_change_act_psys(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
int PE_can_edit(struct ParticleSystem *psys);
void PE_free_ptcache_edit(struct PTCacheEdit *edit);
int PE_start_edit(struct PTCacheEdit *edit);
/* access */
struct ParticleSystem *PE_get_current(struct Scene *scene, struct Object *ob);
short PE_get_current_num(struct Object *ob);
struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob);
int PE_minmax(struct Scene *scene, float *min, float *max);
struct ParticleEditSettings *PE_settings(Scene *scene);
/* update calls */
void PE_hide_keys_time(struct Scene *scene, struct ParticleSystem *psys, float cfra);
void PE_hide_keys_time(struct Scene *scene, struct PTCacheEdit *edit, float cfra);
void PE_update_object(struct Scene *scene, struct Object *ob, int useflag);
/* selection tools */

View File

@ -743,78 +743,6 @@ static void edge_drawflags(Mesh *me, EditMesh *em)
}
}
static int editmesh_pointcache_edit(Scene *scene, Object *ob, int totvert, PTCacheID *pid_p, float mat[][4], int load)
{
Cloth *cloth;
SoftBody *sb;
ClothModifierData *clmd;
PTCacheID pid, tmpid;
int cfra= (int)scene->r.cfra, found= 0;
pid.cache= NULL;
/* check for cloth */
if(modifiers_isClothEnabled(ob)) {
clmd= (ClothModifierData*)modifiers_findByType(ob, eModifierType_Cloth);
cloth= clmd->clothObject;
BKE_ptcache_id_from_cloth(&tmpid, ob, clmd);
/* verify vertex count and baked status */
if(cloth && (totvert == cloth->numverts)) {
if((tmpid.cache->flag & PTCACHE_BAKED) && (tmpid.cache->flag & PTCACHE_BAKE_EDIT)) {
pid= tmpid;
if(load && (pid.cache->flag & PTCACHE_BAKE_EDIT_ACTIVE))
found= 1;
}
}
}
/* check for softbody */
if(!found && ob->soft) {
sb= ob->soft;
BKE_ptcache_id_from_softbody(&tmpid, ob, sb);
/* verify vertex count and baked status */
if(sb->bpoint && (totvert == sb->totpoint)) {
if((tmpid.cache->flag & PTCACHE_BAKED) && (tmpid.cache->flag & PTCACHE_BAKE_EDIT)) {
pid= tmpid;
if(load && (pid.cache->flag & PTCACHE_BAKE_EDIT_ACTIVE))
found= 1;
}
}
}
/* if not making editmesh verify editing was active for this point cache */
if(load) {
if(found)
pid.cache->flag &= ~PTCACHE_BAKE_EDIT_ACTIVE;
else
return 0;
}
/* check if we have cache for this frame */
if(pid.cache && BKE_ptcache_id_exist(&pid, cfra)) {
*pid_p = pid;
if(load) {
Mat4CpyMat4(mat, ob->obmat);
}
else {
pid.cache->editframe= cfra;
pid.cache->flag |= PTCACHE_BAKE_EDIT_ACTIVE;
Mat4Invert(mat, ob->obmat); /* ob->imat is not up to date */
}
return 1;
}
return 0;
}
/* turns Mesh into editmesh */
void make_editMesh(Scene *scene, Object *ob)
{
@ -828,11 +756,8 @@ void make_editMesh(Scene *scene, Object *ob)
EditFace *efa;
EditEdge *eed;
EditSelection *ese;
PTCacheID pid;
Cloth *cloth;
SoftBody *sb;
float cacheco[3], cachemat[4][4], *co;
int tot, a, cacheedit= 0, eekadoodle= 0;
float *co;
int tot, a, eekadoodle= 0;
if(me->edit_mesh==NULL)
me->edit_mesh= MEM_callocN(sizeof(EditMesh), "editmesh");
@ -867,26 +792,10 @@ void make_editMesh(Scene *scene, Object *ob)
CustomData_copy(&me->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
mvert= me->mvert;
cacheedit= editmesh_pointcache_edit(scene, ob, tot, &pid, cachemat, 0);
evlist= (EditVert **)MEM_mallocN(tot*sizeof(void *),"evlist");
for(a=0; a<tot; a++, mvert++) {
if(cacheedit) {
if(pid.type == PTCACHE_TYPE_CLOTH) {
cloth= ((ClothModifierData*)pid.calldata)->clothObject;
VECCOPY(cacheco, cloth->verts[a].x)
}
else if(pid.type == PTCACHE_TYPE_SOFTBODY) {
sb= (SoftBody*)pid.calldata;
VECCOPY(cacheco, sb->bpoint[a].pos)
}
Mat4MulVecfl(cachemat, cacheco);
co= cacheco;
}
else
co= mvert->co;
co= mvert->co;
eve= addvertlist(em, co, NULL);
evlist[a]= eve;
@ -1011,11 +920,6 @@ void make_editMesh(Scene *scene, Object *ob)
if (EM_get_actFace(em, 0)==NULL) {
EM_set_actFace(em, em->faces.first ); /* will use the first face, this is so we alwats have an active face */
}
/* vertex coordinates change with cache edit, need to recalc */
if(cacheedit)
recalc_editnormals(em);
}
/* makes Mesh out of editmesh */
@ -1031,12 +935,8 @@ void load_editMesh(Scene *scene, Object *ob)
EditFace *efa, *efa_act;
EditEdge *eed;
EditSelection *ese;
SoftBody *sb;
Cloth *cloth;
ClothModifierData *clmd;
PTCacheID pid;
float *fp, *newkey, *oldkey, nor[3], cacheco[3], cachemat[4][4];
int i, a, ototvert, cacheedit= 0;
float *fp, *newkey, *oldkey, nor[3];
int i, a, ototvert;
/* this one also tests of edges are not in faces: */
/* eed->f2==0: not in face, f2==1: draw it */
@ -1090,48 +990,8 @@ void load_editMesh(Scene *scene, Object *ob)
eve= em->verts.first;
a= 0;
/* check for point cache editing */
cacheedit= editmesh_pointcache_edit(scene, ob, em->totvert, &pid, cachemat, 1);
while(eve) {
if(cacheedit) {
if(pid.type == PTCACHE_TYPE_CLOTH) {
clmd= (ClothModifierData*)pid.calldata;
cloth= clmd->clothObject;
/* assign position */
VECCOPY(cacheco, cloth->verts[a].x)
VECCOPY(cloth->verts[a].x, eve->co);
Mat4MulVecfl(cachemat, cloth->verts[a].x);
/* find plausible velocity, not physical correct but gives
* nicer results when commented */
VECSUB(cacheco, cloth->verts[a].x, cacheco);
VecMulf(cacheco, clmd->sim_parms->stepsPerFrame*10.0f);
VECADD(cloth->verts[a].v, cloth->verts[a].v, cacheco);
}
else if(pid.type == PTCACHE_TYPE_SOFTBODY) {
sb= (SoftBody*)pid.calldata;
/* assign position */
VECCOPY(cacheco, sb->bpoint[a].pos)
VECCOPY(sb->bpoint[a].pos, eve->co);
Mat4MulVecfl(cachemat, sb->bpoint[a].pos);
/* changing velocity for softbody doesn't seem to give
* good results? */
#if 0
VECSUB(cacheco, sb->bpoint[a].pos, cacheco);
VecMulf(cacheco, sb->minloops*10.0f);
VECADD(sb->bpoint[a].vec, sb->bpoint[a].pos, cacheco);
#endif
}
if(oldverts)
VECCOPY(mvert->co, oldverts[a].co)
}
else
VECCOPY(mvert->co, eve->co);
VECCOPY(mvert->co, eve->co);
mvert->mat_nr= 32767; /* what was this for, halos? */
@ -1155,10 +1015,6 @@ void load_editMesh(Scene *scene, Object *ob)
eve= eve->next;
mvert++;
}
/* write changes to cache */
if(cacheedit)
BKE_ptcache_write_cache(&pid, pid.cache->editframe);
/* the edges */
a= 0;

View File

@ -46,6 +46,7 @@
#include "ED_screen.h"
#include "ED_physics.h"
#include "ED_particle.h"
#include "UI_interface.h"
#include "UI_resources.h"
@ -184,8 +185,16 @@ static int ptcache_free_bake_exec(bContext *C, wmOperator *op)
{
PointerRNA ptr= CTX_data_pointer_get_type(C, "PointCache", &RNA_PointCache);
PointCache *cache= ptr.data;
cache->flag &= ~PTCACHE_BAKED;
if(cache->edit) {
if(!cache->edit->edited || 1) {// XXX okee("Lose changes done in particle mode?")) {
PE_free_ptcache_edit(cache->edit);
cache->edit = NULL;
cache->flag &= ~PTCACHE_BAKED;
}
}
else
cache->flag &= ~PTCACHE_BAKED;
return OPERATOR_FINISHED;
}

File diff suppressed because it is too large Load Diff

View File

@ -2120,9 +2120,7 @@ static int tree_element_active_psys(bContext *C, Scene *scene, TreeElement *te,
{
if(set) {
Object *ob= (Object *)tselem->id;
ParticleSystem *psys= te->directdata;
PE_change_act_psys(scene, ob, psys);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, ob);
// XXX extern_set_butspace(F7KEY, 0);

View File

@ -89,6 +89,7 @@
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_property.h"
#include "BKE_smoke.h"
#include "BKE_unit.h"
@ -3138,6 +3139,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
{
Object *ob=base->object;
ParticleSystemModifierData *psmd;
ParticleEditSettings *pset = PE_settings(scene);
ParticleSettings *part;
ParticleData *pars, *pa;
ParticleKey state, *states=0;
@ -3166,9 +3168,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if(pars==0) return;
// XXX what logic is this?
if(!scene->obedit && psys_in_edit_mode(scene, psys)
&& psys->flag & PSYS_HAIR_DONE && part->draw_as==PART_DRAW_PATH)
/* don't draw normal paths in edit mode */
if(psys_in_edit_mode(scene, psys) && (pset->flag & PE_DRAW_PART)==0)
return;
if(part->draw_as==PART_DRAW_NOT) return;
@ -3709,33 +3710,27 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
wmLoadMatrix(rv3d->viewmat);
}
static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, ParticleSystem *psys, int dt)
static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, PTCacheEdit *edit, int dt)
{
ParticleEdit *edit = psys->edit;
ParticleData *pa;
ParticleCacheKey **path;
ParticleEditKey *key;
ParticleCacheKey **cache, *path, *pkey;
PTCacheEditPoint *point;
PTCacheEditKey *key;
ParticleEditSettings *pset = PE_settings(scene);
int i, k, totpart = psys->totpart, totchild=0, timed = pset->draw_timed;
int i, k, totpoint = edit->totpoint, timed = pset->flag & PE_FADE_TIME ? pset->fade_frames : 0;
int steps;
char nosel[4], sel[4];
float sel_col[3];
float nosel_col[3];
char val[32];
float *pathcol = NULL, *pcol;
/* create path and child path cache if it doesn't exist already */
if(psys->pathcache==0){
PE_hide_keys_time(scene, psys,CFRA);
psys_cache_paths(scene, ob, psys, CFRA,0);
}
if(psys->pathcache==0)
if(edit->pathcache==0)
psys_cache_edit_paths(scene, ob, edit, CFRA);
if(edit->pathcache==0)
return;
if(pset->flag & PE_SHOW_CHILD && psys->part->draw_as == PART_DRAW_PATH) {
if(psys->childcache==0)
psys_cache_child_paths(scene, ob, psys, CFRA, 0);
}
else if(!(pset->flag & PE_SHOW_CHILD) && psys->childcache)
free_child_path_cache(psys);
PE_hide_keys_time(scene, edit, CFRA);
/* opengl setup */
if((v3d->flag & V3D_ZBUF_SELECT)==0)
@ -3751,65 +3746,50 @@ static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ob
nosel_col[1]=(float)nosel[1]/255.0f;
nosel_col[2]=(float)nosel[2]/255.0f;
if(psys->childcache)
totchild = psys->totchildcache;
/* draw paths */
if(timed)
if(timed) {
glEnable(GL_BLEND);
steps = (*edit->pathcache)->steps + 1;
pathcol = MEM_callocN(steps*4*sizeof(float), "particle path color data");
}
glEnableClientState(GL_VERTEX_ARRAY);
if(dt > OB_WIRE) {
/* solid shaded with lighting */
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
/* solid shaded with lighting */
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
}
else {
/* flat wire color */
glDisableClientState(GL_NORMAL_ARRAY);
glDisable(GL_LIGHTING);
UI_ThemeColor(TH_WIRE);
}
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
/* only draw child paths with lighting */
if(dt > OB_WIRE)
glEnable(GL_LIGHTING);
if(psys->part->draw_as == PART_DRAW_PATH) {
for(i=0, path=psys->childcache; i<totchild; i++,path++){
glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->co);
if(dt > OB_WIRE) {
glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), (*path)->vel);
glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->col);
/* draw paths without lighting */
cache=edit->pathcache;
for(i=0; i<totpoint; i++){
path = cache[i];
glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
if(timed) {
for(k=0, pcol=pathcol, pkey=path; k<steps; k++, pkey++, pcol+=4){
VECCOPY(pcol, pkey->col);
pcol[3] = 1.0f - fabs((float)CFRA - pkey->time)/(float)pset->fade_frames;
}
glDrawArrays(GL_LINE_STRIP, 0, (int)(*path)->steps + 1);
glColorPointer(4, GL_FLOAT, 4*sizeof(float), pathcol);
}
else
glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
}
if(dt > OB_WIRE)
glDisable(GL_LIGHTING);
if(pathcol) { MEM_freeN(pathcol); pathcol = pcol = NULL; }
if(pset->brushtype == PE_BRUSH_WEIGHT) {
glLineWidth(2.0f);
glEnableClientState(GL_COLOR_ARRAY);
glDisable(GL_LIGHTING);
}
/* draw parents last without lighting */
for(i=0, pa=psys->particles, path = psys->pathcache; i<totpart; i++, pa++, path++){
glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->co);
if(dt > OB_WIRE)
glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), (*path)->vel);
if(dt > OB_WIRE || pset->brushtype == PE_BRUSH_WEIGHT)
glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->col);
glDrawArrays(GL_LINE_STRIP, 0, (int)(*path)->steps + 1);
}
/* draw edit vertices */
if(pset->selectmode!=SCE_SELECT_PATH){
@ -3819,61 +3799,74 @@ static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ob
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
if(pset->selectmode==SCE_SELECT_POINT){
float *pd=0,*pdata=0;
float *cd=0,*cdata=0;
cd=cdata=MEM_callocN(edit->totkeys*(timed?4:3)*sizeof(float), "particle edit color data");
int totkeys = 0;
for (i=0, point=edit->points; i<totpoint; i++, point++)
if(!(point->flag & PEP_HIDE))
totkeys += point->totkey;
if(!edit->psys)
pd=pdata=MEM_callocN(totkeys*3*sizeof(float), "particle edit point data");
cd=cdata=MEM_callocN(totkeys*(timed?4:3)*sizeof(float), "particle edit color data");
for(i=0, point=edit->points; i<totpoint; i++, point++){
if(point->flag & PEP_HIDE)
continue;
for(k=0, key=point->keys; k<point->totkey; k++, key++){
if(pd) {
VECCOPY(pd, key->co);
pd += 3;
}
for(i=0, pa=psys->particles; i<totpart; i++, pa++){
for(k=0, key=edit->keys[i]; k<pa->totkey; k++, key++){
if(key->flag&PEK_SELECT){
VECCOPY(cd,sel_col);
}
else{
VECCOPY(cd,nosel_col);
}
if(timed)
*(cd+3) = (key->flag&PEK_HIDE)?0.0f:1.0f;
*(cd+3) = 1.0f - fabs((float)CFRA - *key->time)/(float)pset->fade_frames;
cd += (timed?4:3);
}
}
cd=cdata;
for(i=0, pa=psys->particles; i<totpart; i++, pa++){
if((pa->flag & PARS_HIDE)==0){
glVertexPointer(3, GL_FLOAT, sizeof(ParticleEditKey), edit->keys[i]->world_co);
glColorPointer((timed?4:3), GL_FLOAT, (timed?4:3)*sizeof(float), cd);
glDrawArrays(GL_POINTS, 0, pa->totkey);
}
cd += (timed?4:3) * pa->totkey;
pd=pdata;
for(i=0, point=edit->points; i<totpoint; i++, point++){
if(point->flag & PEP_HIDE)
continue;
if((pset->flag&PE_SHOW_TIME) && (pa->flag&PARS_HIDE)==0 && !(G.f & G_RENDER_SHADOW)){
for(k=0, key=edit->keys[i]+k; k<pa->totkey; k++, key++){
if(key->flag & PEK_HIDE) continue;
if(edit->psys)
glVertexPointer(3, GL_FLOAT, sizeof(PTCacheEditKey), point->keys->world_co);
else
glVertexPointer(3, GL_FLOAT, 3*sizeof(float), pd);
sprintf(val," %.1f",*key->time);
view3d_particle_text_draw_add(key->world_co[0], key->world_co[1], key->world_co[2], val, 0);
}
}
glColorPointer((timed?4:3), GL_FLOAT, (timed?4:3)*sizeof(float), cd);
glDrawArrays(GL_POINTS, 0, point->totkey);
pd += pd ? 3 * point->totkey : 0;
cd += (timed?4:3) * point->totkey;
}
if(cdata)
MEM_freeN(cdata);
cd=cdata=0;
if(pdata) { MEM_freeN(pdata); pd=pdata=0; }
if(cdata) { MEM_freeN(cdata); cd=cdata=0; }
}
else if(pset->selectmode == SCE_SELECT_END){
for(i=0, pa=psys->particles; i<totpart; i++, pa++){
if((pa->flag & PARS_HIDE)==0){
key = edit->keys[i] + pa->totkey - 1;
for(i=0, point=edit->points; i<totpoint; i++, point++){
if((point->flag & PEP_HIDE)==0){
key = point->keys + point->totkey - 1;
if(key->flag & PEK_SELECT)
glColor3fv(sel_col);
else
glColor3fv(nosel_col);
/* has to be like this.. otherwise selection won't work, have try glArrayElement later..*/
glBegin(GL_POINTS);
glVertex3fv(key->world_co);
glVertex3fv(key->flag & PEK_USE_WCO ? key->world_co : key->co);
glEnd();
if((pset->flag & PE_SHOW_TIME) && !(G.f & G_RENDER_SHADOW)){
sprintf(val," %.1f",*key->time);
view3d_particle_text_draw_add(key->world_co[0], key->world_co[1], key->world_co[2], val, 0);
}
}
}
}
@ -5298,11 +5291,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
for(psys=ob->particlesystem.first; psys; psys=psys->next)
draw_new_particle_system(scene, v3d, rv3d, base, psys, dt);
if(ob->mode & OB_MODE_PARTICLE_EDIT && ob==OBACT) {
psys= PE_get_current(scene, ob);
if(psys && !scene->obedit && psys_in_edit_mode(scene, psys))
draw_particle_edit(scene, v3d, rv3d, ob, psys, dt);
}
view3d_particle_text_draw(v3d, ar);
wmMultMatrix(ob->obmat);
@ -5310,6 +5298,21 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
//glDepthMask(GL_TRUE);
if(col) cpack(col);
}
if( (warning_recursive==0) &&
(flag & DRAW_PICKING)==0 &&
(!scene->obedit)
) {
if(ob->mode & OB_MODE_PARTICLE_EDIT && ob==OBACT) {
PTCacheEdit *edit = PE_get_current(scene, ob);
if(edit) {
wmLoadMatrix(rv3d->viewmat);
draw_ptcache_edit(scene, v3d, rv3d, ob, edit, dt);
wmMultMatrix(ob->obmat);
}
}
}
/* draw code for smoke */
{

View File

@ -1571,7 +1571,7 @@ static char *view3d_modeselect_pup(Scene *scene)
str += sprintf(str, formatstr, "Pose Mode", OB_MODE_POSE, ICON_POSE_HLT);
}
if (ob->particlesystem.first) {
if (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) || modifiers_findByType(ob, eModifierType_Softbody)) {
str += sprintf(str, formatstr, "Particle Mode", OB_MODE_PARTICLE_EDIT, ICON_PARTICLEMODE);
}
@ -1661,6 +1661,7 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event)
ScrArea *sa= CTX_wm_area(C);
View3D *v3d= sa->spacedata.first;
Object *obedit = CTX_data_edit_object(C);
Object *ob = CTX_data_active_object(C);
EditMesh *em= NULL;
int bit, ctrl= win->eventstate->ctrl, shift= win->eventstate->shift;
PointerRNA props_ptr;
@ -1759,14 +1760,17 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event)
case B_SEL_PATH:
ts->particle.selectmode= SCE_SELECT_PATH;
WM_event_add_notifier(C, NC_OBJECT, ob);
ED_undo_push(C, "Selectmode Set: Path");
break;
case B_SEL_POINT:
ts->particle.selectmode = SCE_SELECT_POINT;
WM_event_add_notifier(C, NC_OBJECT, ob);
ED_undo_push(C, "Selectmode Set: Point");
break;
case B_SEL_END:
ts->particle.selectmode = SCE_SELECT_END;
WM_event_add_notifier(C, NC_OBJECT, ob);
ED_undo_push(C, "Selectmode Set: End point");
break;

View File

@ -1617,31 +1617,32 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
TransDataExtension *tx;
Base *base = CTX_data_active_base(C);
Object *ob = CTX_data_active_object(C);
ParticleSystem *psys = PE_get_current(t->scene, ob);
ParticleSystemModifierData *psmd = NULL;
ParticleEditSettings *pset = PE_settings(t->scene);
ParticleData *pa = NULL;
ParticleEdit *edit;
ParticleEditKey *key;
PTCacheEdit *edit = PE_get_current(t->scene, ob);
ParticleSystem *psys = NULL;
ParticleSystemModifierData *psmd = NULL;
PTCacheEditPoint *point;
PTCacheEditKey *key;
float mat[4][4];
int i,k, totpart, transformparticle;
int i,k, transformparticle;
int count = 0, hasselected = 0;
int propmode = t->flag & T_PROP_EDIT;
if(psys==NULL || t->settings->particle.selectmode==SCE_SELECT_PATH) return;
if(edit==NULL || t->settings->particle.selectmode==SCE_SELECT_PATH) return;
psmd = psys_get_modifier(ob,psys);
psys = edit->psys;
if(psys)
psmd = psys_get_modifier(ob,psys);
edit = psys->edit;
totpart = psys->totpart;
base->flag |= BA_HAS_RECALC_DATA;
for(i=0, pa=psys->particles; i<totpart; i++, pa++) {
pa->flag &= ~PARS_TRANSFORM;
for(i=0, point=edit->points; i<edit->totpoint; i++, point++) {
point->flag &= ~PEP_TRANSFORM;
transformparticle= 0;
if((pa->flag & PARS_HIDE)==0) {
for(k=0, key=edit->keys[i]; k<pa->totkey; k++, key++) {
if((point->flag & PEP_HIDE)==0) {
for(k=0, key=point->keys; k<point->totkey; k++, key++) {
if((key->flag&PEK_HIDE)==0) {
if(key->flag&PEK_SELECT) {
hasselected= 1;
@ -1654,8 +1655,8 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
}
if(transformparticle) {
count += pa->totkey;
pa->flag |= PARS_TRANSFORM;
count += point->totkey;
point->flag |= PEP_TRANSFORM;
}
}
@ -1674,18 +1675,23 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
Mat4Invert(ob->imat,ob->obmat);
for(i=0, pa=psys->particles; i<totpart; i++, pa++) {
for(i=0, point=edit->points; i<edit->totpoint; i++, point++) {
TransData *head, *tail;
head = tail = td;
if(!(pa->flag & PARS_TRANSFORM)) continue;
if(!(point->flag & PEP_TRANSFORM)) continue;
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat);
if(psys)
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + i, mat);
for(k=0, key=edit->keys[i]; k<pa->totkey; k++, key++) {
VECCOPY(key->world_co, key->co);
Mat4MulVecfl(mat, key->world_co);
td->loc = key->world_co;
for(k=0, key=point->keys; k<point->totkey; k++, key++) {
if(psys) {
VECCOPY(key->world_co, key->co);
Mat4MulVecfl(mat, key->world_co);
td->loc = key->world_co;
}
else
td->loc = key->co;
VECCOPY(td->iloc, td->loc);
VECCOPY(td->center, td->loc);
@ -1713,7 +1719,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
if(k==0) tx->size = 0;
else tx->size = (key - 1)->time;
if(k == pa->totkey - 1) tx->quat = 0;
if(k == point->totkey - 1) tx->quat = 0;
else tx->quat = (key + 1)->time;
}
@ -1731,35 +1737,42 @@ void flushTransParticles(TransInfo *t)
{
Scene *scene = t->scene;
Object *ob = OBACT;
ParticleSystem *psys = PE_get_current(scene, ob);
PTCacheEdit *edit = PE_get_current(scene, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd;
ParticleData *pa;
ParticleEditKey *key;
PTCacheEditPoint *point;
PTCacheEditKey *key;
TransData *td;
float mat[4][4], imat[4][4], co[3];
int i, k, propmode = t->flag & T_PROP_EDIT;
psmd = psys_get_modifier(ob, psys);
if(psys)
psmd = psys_get_modifier(ob, psys);
/* we do transform in world space, so flush world space position
* back to particle local space */
* back to particle local space (only for hair particles) */
td= t->data;
for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++, td++) {
if(!(pa->flag & PARS_TRANSFORM)) continue;
for(i=0, point=edit->points; i<edit->totpoint; i++, point++, td++) {
if(!(point->flag & PEP_TRANSFORM)) continue;
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat);
Mat4Invert(imat,mat);
if(psys) {
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + i, mat);
Mat4Invert(imat,mat);
for(k=0, key=psys->edit->keys[i]; k<pa->totkey; k++, key++) {
VECCOPY(co, key->world_co);
Mat4MulVecfl(imat, co);
for(k=0, key=point->keys; k<point->totkey; k++, key++) {
VECCOPY(co, key->world_co);
Mat4MulVecfl(imat, co);
/* optimization for proportional edit */
if(!propmode || !FloatCompare(key->co, co, 0.0001f)) {
VECCOPY(key->co, co);
pa->flag |= PARS_EDIT_RECALC;
/* optimization for proportional edit */
if(!propmode || !FloatCompare(key->co, co, 0.0001f)) {
VECCOPY(key->co, co);
point->flag |= PEP_EDIT_RECALC;
}
}
}
else
point->flag |= PEP_EDIT_RECALC;
}
PE_update_object(scene, OBACT, 1);
@ -5256,7 +5269,8 @@ void createTransData(bContext *C, TransInfo *t)
}
CTX_DATA_END;
}
else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_can_edit(PE_get_current(scene, ob))) {
else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)
&& PE_start_edit(PE_get_current(scene, ob))) {
createTransParticleVerts(C, t);
if(t->data && t->flag & T_PROP_EDIT) {

View File

@ -62,6 +62,7 @@
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_utildefines.h"
#include "BLI_arithb.h"
@ -362,18 +363,19 @@ int calc_manipulator_stats(const bContext *C)
;
}
else if(ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
ParticleSystem *psys= PE_get_current(scene, ob);
ParticleData *pa = psys->particles;
ParticleEditKey *ek;
PTCacheEdit *edit= PE_get_current(scene, ob);
PTCacheEditPoint *point;
PTCacheEditKey *ek;
int k;
if(psys->edit) {
for(a=0; a<psys->totpart; a++,pa++) {
if(pa->flag & PARS_HIDE) continue;
if(edit) {
point = edit->points;
for(a=0; a<edit->totpoint; a++,point++) {
if(point->flag & PEP_HIDE) continue;
for(k=0, ek=psys->edit->keys[a]; k<pa->totkey; k++, ek++) {
for(k=0, ek=point->keys; k<point->totkey; k++, ek++) {
if(ek->flag & PEK_SELECT) {
calc_tw_center(scene, ek->world_co);
calc_tw_center(scene, ek->flag & PEK_USE_WCO ? ek->world_co : ek->co);
totsel++;
}
}

View File

@ -95,7 +95,7 @@ typedef struct PartDeflect {
typedef struct PTCacheMem {
struct PTCacheMem *next, *prev;
int frame, totpoint;
unsigned int data_types, rt;
unsigned int data_types, flag;
int *index_array; /* quick access to stored points with index */
void *data[8]; /* BPHYS_TOT_DATA */
@ -121,6 +121,9 @@ typedef struct PointCache {
char info[64];
char path[240]; /* file path */
struct ListBase mem_cache;
struct PTCacheEdit *edit;
void (*free_edit)(struct PTCacheEdit *edit); /* free callback */
} PointCache;
typedef struct SBVertex {
@ -300,8 +303,8 @@ typedef struct SoftBody {
#define PTCACHE_OUTDATED 2
#define PTCACHE_SIMULATION_VALID 4
#define PTCACHE_BAKING 8
#define PTCACHE_BAKE_EDIT 16
#define PTCACHE_BAKE_EDIT_ACTIVE 32
//#define PTCACHE_BAKE_EDIT 16
//#define PTCACHE_BAKE_EDIT_ACTIVE 32
#define PTCACHE_DISK_CACHE 64
#define PTCACHE_QUICK_CACHE 128
#define PTCACHE_FRAMES_SKIPPED 256

View File

@ -194,8 +194,8 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in
ParticleData *particles; /* (parent) particles */
ChildParticle *child; /* child particles */
struct ParticleEdit *edit; /* particle editmode (runtime) */
void (*free_edit)(struct ParticleSystem *sys); /* free callback */
struct PTCacheEdit *edit; /* particle editmode (runtime) */
void (*free_edit)(struct PTCacheEdit *edit); /* free callback */
struct ParticleCacheKey **pathcache; /* path cache (runtime) */
struct ParticleCacheKey **childcache; /* child cache (runtime) */
@ -419,7 +419,7 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in
#define PSYS_DELETE 256 /* remove particlesystem as soon as possible */
#define PSYS_HAIR_DONE 512
#define PSYS_KEYED 1024
#define PSYS_EDITED 2048
//#define PSYS_EDITED 2048
//#define PSYS_PROTECT_CACHE 4096
#define PSYS_DISABLED 8192
@ -427,11 +427,7 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in
#define PARS_UNEXIST 1
#define PARS_NO_DISP 2
#define PARS_STICKY 4
#define PARS_TRANSFORM 8
#define PARS_HIDE 16
#define PARS_TAG 32
#define PARS_REKEY 64
#define PARS_EDIT_RECALC 128
#define PARS_REKEY 8
/* pars->alive */
#define PARS_KILLED 0

View File

@ -488,10 +488,15 @@ typedef struct ParticleEditSettings {
ParticleBrushData brush[7]; /* 7 = PE_TOT_BRUSH */
void *paintcursor; /* runtime */
float emitterdist;
int draw_timed;
float emitterdist, rt;
int selectmode, pad;
int selectmode;
int edittype;
int draw_step, fade_frames;
struct Scene *scene;
struct Object *object;
} ParticleEditSettings;
typedef struct TransformOrientation {
@ -1042,9 +1047,10 @@ typedef enum SculptFlags {
#define PE_LOCK_FIRST 2
#define PE_DEFLECT_EMITTER 4
#define PE_INTERPOLATE_ADDED 8
#define PE_SHOW_CHILD 16
#define PE_SHOW_TIME 32
#define PE_DRAW_PART 16
#define PE_X_MIRROR 64
#define PE_FADE_TIME 128
#define PE_AUTO_VELOCITY 256
/* toolsetting->particle brushtype */
#define PE_BRUSH_NONE -1
@ -1053,11 +1059,15 @@ typedef enum SculptFlags {
#define PE_BRUSH_LENGTH 2
#define PE_BRUSH_PUFF 3
#define PE_BRUSH_ADD 4
#define PE_BRUSH_WEIGHT 5
#define PE_BRUSH_SMOOTH 6
#define PE_BRUSH_SMOOTH 5
/* this must equal ParticleEditSettings.brush array size */
#define PE_TOT_BRUSH 7
#define PE_TOT_BRUSH 6
/* tooksettings->particle edittype */
#define PE_TYPE_PARTICLES 0
#define PE_TYPE_SOFTBODY 1
#define PE_TYPE_CLOTH 2
/* toolsettings->retopo_mode */
#define RETOPO 1

View File

@ -98,6 +98,7 @@ EnumPropertyItem part_hair_ren_as_items[] = {
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BLI_arithb.h"
@ -436,7 +437,30 @@ static void rna_ParticleTarget_name_get(PointerRNA *ptr, char *str)
else
strcpy(str, "Invalid target!");
}
static int rna_ParticleSystem_multiple_caches_get(PointerRNA *ptr)
{
ParticleSystem *psys= (ParticleSystem*)ptr->data;
return (psys->ptcaches.first != psys->ptcaches.last);
}
static int rna_ParticleSystem_editable_get(PointerRNA *ptr)
{
ParticleSystem *psys= (ParticleSystem*)ptr->data;
if(psys->part && psys->part->type==PART_HAIR)
return (psys->flag & PSYS_HAIR_DONE);
else
return (psys->pointcache->flag & PTCACHE_BAKED);
}
static int rna_ParticleSystem_edited_get(PointerRNA *ptr)
{
ParticleSystem *psys= (ParticleSystem*)ptr->data;
if(psys->part && psys->part->type==PART_HAIR)
return (psys->edit && psys->edit->edited);
else
return (psys->pointcache->edit && psys->pointcache->edit->edited);
}
EnumPropertyItem from_items[] = {
{PART_FROM_VERT, "VERT", 0, "Vertexes", ""},
{PART_FROM_FACE, "FACE", 0, "Faces", ""},
@ -725,27 +749,10 @@ static void rna_def_particle(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", PARS_STICKY);
RNA_def_property_ui_text(prop, "sticky", "");
prop= RNA_def_property(srna, "transform", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PARS_TRANSFORM);
RNA_def_property_ui_text(prop, "transform", "");
prop= RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PARS_HIDE);
RNA_def_property_ui_text(prop, "hide", "");
prop= RNA_def_property(srna, "tag", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PARS_TAG);
RNA_def_property_ui_text(prop, "tag", "");
prop= RNA_def_property(srna, "rekey", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PARS_REKEY);
RNA_def_property_ui_text(prop, "rekey", "");
prop= RNA_def_property(srna, "edit_recalc", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PARS_EDIT_RECALC);
RNA_def_property_ui_text(prop, "edit_recalc", "");
prop= RNA_def_property(srna, "alive_state", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "alive");
RNA_def_property_enum_items(prop, alive_items);
@ -1907,11 +1914,6 @@ static void rna_def_particle_system(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "softflag", OB_SB_ENABLE);
RNA_def_property_ui_text(prop, "Use Soft Body", "Enable use of soft body for hair physics simulation.");
prop= RNA_def_property(srna, "editable", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PSYS_EDITED);
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* various checks needed */
RNA_def_property_ui_text(prop, "Editable", "For hair particle systems, finalize the hair to enable editing.");
/* reactor */
prop= RNA_def_property(srna, "reactor_target_object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "target_ob");
@ -2089,12 +2091,28 @@ static void rna_def_particle_system(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "PointCache");
RNA_def_property_ui_text(prop, "Point Cache", "");
prop= RNA_def_property(srna, "multiple_caches", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_ParticleSystem_multiple_caches_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Multiple Caches", "Particle system has multiple point caches");
/* offset ob */
prop= RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "parent");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Parent", "Use this object's coordinate system instead of global coordinate system.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_redo");
/* hair or cache editing */
prop= RNA_def_property(srna, "editable", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_ParticleSystem_editable_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Editable", "Particle system can be edited in particle mode");
prop= RNA_def_property(srna, "edited", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_ParticleSystem_edited_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Edited", "Particle system has been edited in particle mode");
}
void RNA_def_particle(BlenderRNA *brna)

View File

@ -33,8 +33,34 @@
#include "BKE_paint.h"
#include "WM_types.h"
static EnumPropertyItem particle_edit_hair_brush_items[] = {
{PE_BRUSH_NONE, "NONE", 0, "None", "Don't use any brush."},
{PE_BRUSH_COMB, "COMB", 0, "Comb", "Comb hairs."},
{PE_BRUSH_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth hairs."},
{PE_BRUSH_ADD, "ADD", 0, "Add", "Add hairs."},
{PE_BRUSH_LENGTH, "LENGTH", 0, "Length", "Make hairs longer or shorter."},
{PE_BRUSH_PUFF, "PUFF", 0, "Puff", "Make hairs stand up."},
{PE_BRUSH_CUT, "CUT", 0, "Cut", "Cut hairs."},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem particle_edit_cache_brush_items[] = {
{PE_BRUSH_NONE, "NONE", 0, "None", "Don't use any brush."},
{PE_BRUSH_COMB, "COMB", 0, "Comb", "Comb paths."},
{PE_BRUSH_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth paths."},
{PE_BRUSH_LENGTH, "LENGTH", 0, "Length", "Make paths longer or shorter."},
{0, NULL, 0, NULL, NULL}};
#ifdef RNA_RUNTIME
#include "BKE_context.h"
#include "BKE_pointcache.h"
#include "BKE_particle.h"
#include "BKE_depsgraph.h"
#include "ED_particle.h"
static PointerRNA rna_ParticleEdit_brush_get(PointerRNA *ptr)
{
ParticleEditSettings *pset= (ParticleEditSettings*)ptr->data;
@ -46,6 +72,7 @@ static PointerRNA rna_ParticleEdit_brush_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_ParticleBrush, brush);
}
static PointerRNA rna_ParticleBrush_curve_get(PointerRNA *ptr)
{
return rna_pointer_inherit_refine(ptr, &RNA_CurveMapping, NULL);
@ -74,6 +101,65 @@ static void rna_Paint_active_brush_set(PointerRNA *ptr, PointerRNA value)
paint_brush_set(ptr->data, value.data);
}
static void rna_ParticleEdit_redo(bContext *C, PointerRNA *ptr)
{
PTCacheEdit *edit = PE_get_current(CTX_data_scene(C), CTX_data_active_object(C));
if(!edit)
return;
psys_free_path_cache(NULL, edit);
}
static void rna_ParticleEdit_update(bContext *C, PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
if(ob)
DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
}
static EnumPropertyItem *rna_ParticleEdit_tool_itemf(bContext *C, PointerRNA *ptr, int *free)
{
Scene *scene= CTX_data_scene(C);
PTCacheEdit *edit;
if(C==NULL) {
EnumPropertyItem *item= NULL;
int totitem= 0;
/* needed for doc generation */
RNA_enum_items_add(&item, &totitem, particle_edit_hair_brush_items);
RNA_enum_item_end(&item, &totitem);
*free= 1;
return item;
}
edit = PE_get_current(scene, CTX_data_active_object(C));
if(edit && edit->psys)
return particle_edit_hair_brush_items;
return particle_edit_cache_brush_items;
}
static int rna_ParticleEdit_editable_get(PointerRNA *ptr)
{
ParticleEditSettings *pset= (ParticleEditSettings*)ptr->data;
return (pset->object && PE_get_current(pset->scene, pset->object));
}
static int rna_ParticleEdit_hair_get(PointerRNA *ptr)
{
ParticleEditSettings *pset= (ParticleEditSettings*)ptr->data;
PTCacheEdit *edit = PE_get_current(pset->scene, pset->object);
return (edit && edit->psys);
}
#else
static void rna_def_paint(BlenderRNA *brna)
@ -266,17 +352,6 @@ static void rna_def_particle_edit(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
static EnumPropertyItem tool_items[] = {
{PE_BRUSH_NONE, "NONE", 0, "None", "Don't use any brush."},
{PE_BRUSH_COMB, "COMB", 0, "Comb", "Comb hairs."},
{PE_BRUSH_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth hairs."},
{PE_BRUSH_WEIGHT, "WEIGHT", 0, "Weight", "Assign weight to hairs."},
{PE_BRUSH_ADD, "ADD", 0, "Add", "Add hairs."},
{PE_BRUSH_LENGTH, "LENGTH", 0, "Length", "Make hairs longer or shorter."},
{PE_BRUSH_PUFF, "PUFF", 0, "Puff", "Make hairs stand up."},
{PE_BRUSH_CUT, "CUT", 0, "Cut", "Cut hairs."},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem select_mode_items[] = {
{SCE_SELECT_PATH, "PATH", ICON_EDGESEL, "Path", ""}, // XXX icon
{SCE_SELECT_POINT, "POINT", ICON_VERTEXSEL, "Point", ""}, // XXX icon
@ -293,6 +368,14 @@ static void rna_def_particle_edit(BlenderRNA *brna)
{1, "SHRINK", 0, "Shrink", "Make hairs shorter."},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem edit_type_items[]= {
{PE_TYPE_PARTICLES, "PARTICLES", 0, "Particles", ""},
{PE_TYPE_SOFTBODY, "SOFT_BODY", 0, "Soft body", ""},
{PE_TYPE_CLOTH, "CLOTH", 0, "Cloth", ""},
{0, NULL, 0, NULL, NULL}
};
/* edit */
srna= RNA_def_struct(brna, "ParticleEdit", NULL);
@ -301,13 +384,15 @@ static void rna_def_particle_edit(BlenderRNA *brna)
prop= RNA_def_property(srna, "tool", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "brushtype");
RNA_def_property_enum_items(prop, tool_items);
RNA_def_property_enum_items(prop, particle_edit_hair_brush_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_ParticleEdit_tool_itemf");
RNA_def_property_ui_text(prop, "Tool", "");
prop= RNA_def_property(srna, "selection_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "selectmode");
RNA_def_property_enum_items(prop, select_mode_items);
RNA_def_property_ui_text(prop, "Selection Mode", "Particle select and display mode.");
RNA_def_property_update(prop, NC_OBJECT, "rna_ParticleEdit_update");
prop= RNA_def_property(srna, "keep_lengths", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_KEEP_LENGTHS);
@ -326,13 +411,19 @@ static void rna_def_particle_edit(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 10, 3);
RNA_def_property_ui_text(prop, "Emitter Distance", "Distance to keep particles away from the emitter.");
prop= RNA_def_property(srna, "show_time", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_SHOW_TIME);
RNA_def_property_ui_text(prop, "Show Time", "Show time values of the baked keys.");
prop= RNA_def_property(srna, "fade_time", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_FADE_TIME);
RNA_def_property_ui_text(prop, "Fade Time", "Fade paths and keys further away from current frame.");
RNA_def_property_update(prop, NC_OBJECT, "rna_ParticleEdit_update");
prop= RNA_def_property(srna, "show_children", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_SHOW_CHILD);
RNA_def_property_ui_text(prop, "Show Children", "Show child particles.");
prop= RNA_def_property(srna, "auto_velocity", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_AUTO_VELOCITY);
RNA_def_property_ui_text(prop, "Auto Velocity", "Calculate point velocities automatically.");
prop= RNA_def_property(srna, "draw_particles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_DRAW_PART);
RNA_def_property_ui_text(prop, "Draw Particles", "Draw actual particles.");
RNA_def_property_update(prop, NC_OBJECT, NULL);
prop= RNA_def_property(srna, "mirror_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_X_MIRROR);
@ -353,6 +444,37 @@ static void rna_def_particle_edit(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, "rna_ParticleEdit_brush_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Brush", "");
prop= RNA_def_property(srna, "draw_step", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 2, 10);
RNA_def_property_ui_text(prop, "Steps", "How many steps to draw the path with.");
RNA_def_property_update(prop, NC_OBJECT, "rna_ParticleEdit_redo");
prop= RNA_def_property(srna, "fade_frames", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 2, 100);
RNA_def_property_ui_text(prop, "Frames", "How many frames to fade.");
RNA_def_property_update(prop, NC_OBJECT, "rna_ParticleEdit_update");
prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "edittype");
RNA_def_property_enum_items(prop, edit_type_items);
RNA_def_property_ui_text(prop, "Type", "");
RNA_def_property_update(prop, NC_OBJECT, "rna_ParticleEdit_redo");
prop= RNA_def_property(srna, "editable", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_ParticleEdit_editable_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Editable", "A valid edit mode exists");
prop= RNA_def_property(srna, "hair", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_ParticleEdit_hair_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Hair", "Editing hair");
prop= RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Object", "The edited object");
/* brush */
srna= RNA_def_struct(brna, "ParticleBrush", NULL);