|
Blender
V2.59
|
00001 /* 00002 * $Id: particle_edit.c 38102 2011-07-05 01:49:34Z jhk $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2007 by Janne Karhu. 00021 * All rights reserved. 00022 * 00023 * The Original Code is: all of this file. 00024 * 00025 * Contributor(s): none yet. 00026 * 00027 * ***** END GPL LICENSE BLOCK ***** 00028 */ 00029 00035 #include <stdlib.h> 00036 #include <math.h> 00037 #include <string.h> 00038 #include <assert.h> 00039 00040 #include "MEM_guardedalloc.h" 00041 00042 #include "DNA_scene_types.h" 00043 #include "DNA_mesh_types.h" 00044 #include "DNA_meshdata_types.h" 00045 #include "DNA_view3d_types.h" 00046 #include "DNA_screen_types.h" 00047 #include "DNA_space_types.h" 00048 00049 #include "BLI_math.h" 00050 #include "BLI_blenlib.h" 00051 #include "BLI_dynstr.h" 00052 #include "BLI_kdtree.h" 00053 #include "BLI_rand.h" 00054 #include "BLI_utildefines.h" 00055 00056 #include "BKE_DerivedMesh.h" 00057 #include "BKE_depsgraph.h" 00058 00059 #include "BKE_context.h" 00060 #include "BKE_global.h" 00061 #include "BKE_object.h" 00062 #include "BKE_mesh.h" 00063 #include "BKE_modifier.h" 00064 #include "BKE_particle.h" 00065 #include "BKE_report.h" 00066 #include "BKE_scene.h" 00067 00068 #include "BKE_pointcache.h" 00069 00070 #include "BIF_gl.h" 00071 #include "BIF_glutil.h" 00072 00073 #include "ED_physics.h" 00074 #include "ED_mesh.h" 00075 #include "ED_particle.h" 00076 #include "ED_view3d.h" 00077 00078 #include "UI_resources.h" 00079 00080 #include "WM_api.h" 00081 #include "WM_types.h" 00082 00083 #include "RNA_access.h" 00084 #include "RNA_define.h" 00085 00086 #include "physics_intern.h" 00087 00088 static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys); 00089 static void PTCacheUndo_clear(PTCacheEdit *edit); 00090 static void recalc_emitter_field(Object *ob, ParticleSystem *psys); 00091 00092 #define KEY_K PTCacheEditKey *key; int k 00093 #define POINT_P PTCacheEditPoint *point; int p 00094 #define LOOP_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) 00095 #define LOOP_VISIBLE_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(!(point->flag & PEP_HIDE)) 00096 #define LOOP_SELECTED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point_is_selected(point)) 00097 #define LOOP_UNSELECTED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(!point_is_selected(point)) 00098 #define LOOP_EDITED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point->flag & PEP_EDIT_RECALC) 00099 #define LOOP_TAGGED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point->flag & PEP_TAG) 00100 #define LOOP_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) 00101 #define LOOP_VISIBLE_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if(!(key->flag & PEK_HIDE)) 00102 #define LOOP_SELECTED_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE)) 00103 #define LOOP_TAGGED_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if(key->flag & PEK_TAG) 00104 00105 #define KEY_WCO (key->flag & PEK_USE_WCO ? key->world_co : key->co) 00106 00107 /**************************** utilities *******************************/ 00108 00109 int PE_poll(bContext *C) 00110 { 00111 Scene *scene= CTX_data_scene(C); 00112 Object *ob= CTX_data_active_object(C); 00113 00114 if(!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) 00115 return 0; 00116 00117 return (PE_get_current(scene, ob) != NULL); 00118 } 00119 00120 int PE_hair_poll(bContext *C) 00121 { 00122 Scene *scene= CTX_data_scene(C); 00123 Object *ob= CTX_data_active_object(C); 00124 PTCacheEdit *edit; 00125 00126 if(!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) 00127 return 0; 00128 00129 edit= PE_get_current(scene, ob); 00130 00131 return (edit && edit->psys); 00132 } 00133 00134 int PE_poll_view3d(bContext *C) 00135 { 00136 return PE_poll(C) && CTX_wm_area(C)->spacetype == SPACE_VIEW3D && 00137 CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW; 00138 } 00139 00140 void PE_free_ptcache_edit(PTCacheEdit *edit) 00141 { 00142 POINT_P; 00143 00144 if(edit==0) return; 00145 00146 PTCacheUndo_clear(edit); 00147 00148 if(edit->points) { 00149 LOOP_POINTS { 00150 if(point->keys) 00151 MEM_freeN(point->keys); 00152 } 00153 00154 MEM_freeN(edit->points); 00155 } 00156 00157 if(edit->mirror_cache) 00158 MEM_freeN(edit->mirror_cache); 00159 00160 if(edit->emitter_cosnos) { 00161 MEM_freeN(edit->emitter_cosnos); 00162 edit->emitter_cosnos= 0; 00163 } 00164 00165 if(edit->emitter_field) { 00166 BLI_kdtree_free(edit->emitter_field); 00167 edit->emitter_field= 0; 00168 } 00169 00170 psys_free_path_cache(edit->psys, edit); 00171 00172 MEM_freeN(edit); 00173 } 00174 00175 /************************************************/ 00176 /* Edit Mode Helpers */ 00177 /************************************************/ 00178 00179 int PE_start_edit(PTCacheEdit *edit) 00180 { 00181 if(edit) { 00182 edit->edited = 1; 00183 if(edit->psys) 00184 edit->psys->flag |= PSYS_EDITED; 00185 return 1; 00186 } 00187 00188 return 0; 00189 } 00190 00191 ParticleEditSettings *PE_settings(Scene *scene) 00192 { 00193 return scene->toolsettings ? &scene->toolsettings->particle : NULL; 00194 } 00195 00196 /* always gets atleast the first particlesystem even if PSYS_CURRENT flag is not set 00197 * 00198 * note: this function runs on poll, therefor it can runs many times a second 00199 * keep it fast! */ 00200 static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create) 00201 { 00202 ParticleEditSettings *pset= PE_settings(scene); 00203 PTCacheEdit *edit = NULL; 00204 ListBase pidlist; 00205 PTCacheID *pid; 00206 00207 if(pset==NULL || ob==NULL) 00208 return NULL; 00209 00210 pset->scene = scene; 00211 pset->object = ob; 00212 00213 BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0); 00214 00215 /* in the case of only one editable thing, set pset->edittype accordingly */ 00216 if(pidlist.first && pidlist.first == pidlist.last) { 00217 pid = pidlist.first; 00218 switch(pid->type) { 00219 case PTCACHE_TYPE_PARTICLES: 00220 pset->edittype = PE_TYPE_PARTICLES; 00221 break; 00222 case PTCACHE_TYPE_SOFTBODY: 00223 pset->edittype = PE_TYPE_SOFTBODY; 00224 break; 00225 case PTCACHE_TYPE_CLOTH: 00226 pset->edittype = PE_TYPE_CLOTH; 00227 break; 00228 } 00229 } 00230 00231 for(pid=pidlist.first; pid; pid=pid->next) { 00232 if(pset->edittype == PE_TYPE_PARTICLES && pid->type == PTCACHE_TYPE_PARTICLES) { 00233 ParticleSystem *psys = pid->calldata; 00234 00235 if(psys->flag & PSYS_CURRENT) { 00236 if(psys->part && psys->part->type == PART_HAIR) { 00237 if(psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) { 00238 if(create && !psys->pointcache->edit) 00239 PE_create_particle_edit(scene, ob, pid->cache, NULL); 00240 edit = pid->cache->edit; 00241 } 00242 else { 00243 if(create && !psys->edit && psys->flag & PSYS_HAIR_DONE) 00244 PE_create_particle_edit(scene, ob, NULL, psys); 00245 edit = psys->edit; 00246 } 00247 } 00248 else { 00249 if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) 00250 PE_create_particle_edit(scene, ob, pid->cache, psys); 00251 edit = pid->cache->edit; 00252 } 00253 00254 break; 00255 } 00256 } 00257 else if(pset->edittype == PE_TYPE_SOFTBODY && pid->type == PTCACHE_TYPE_SOFTBODY) { 00258 if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) 00259 PE_create_particle_edit(scene, ob, pid->cache, NULL); 00260 edit = pid->cache->edit; 00261 break; 00262 } 00263 else if(pset->edittype == PE_TYPE_CLOTH && pid->type == PTCACHE_TYPE_CLOTH) { 00264 if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) 00265 PE_create_particle_edit(scene, ob, pid->cache, NULL); 00266 edit = pid->cache->edit; 00267 break; 00268 } 00269 } 00270 00271 if(edit) 00272 edit->pid = *pid; 00273 00274 BLI_freelistN(&pidlist); 00275 00276 return edit; 00277 } 00278 00279 PTCacheEdit *PE_get_current(Scene *scene, Object *ob) 00280 { 00281 return pe_get_current(scene, ob, 0); 00282 } 00283 00284 PTCacheEdit *PE_create_current(Scene *scene, Object *ob) 00285 { 00286 return pe_get_current(scene, ob, 1); 00287 } 00288 00289 void PE_current_changed(Scene *scene, Object *ob) 00290 { 00291 if(ob->mode == OB_MODE_PARTICLE_EDIT) 00292 PE_create_current(scene, ob); 00293 } 00294 00295 void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra) 00296 { 00297 ParticleEditSettings *pset=PE_settings(scene); 00298 POINT_P; KEY_K; 00299 00300 00301 if(pset->flag & PE_FADE_TIME && pset->selectmode==SCE_SELECT_POINT) { 00302 LOOP_POINTS { 00303 LOOP_KEYS { 00304 if(fabs(cfra-*key->time) < pset->fade_frames) 00305 key->flag &= ~PEK_HIDE; 00306 else { 00307 key->flag |= PEK_HIDE; 00308 //key->flag &= ~PEK_SELECT; 00309 } 00310 } 00311 } 00312 } 00313 else { 00314 LOOP_POINTS { 00315 LOOP_KEYS { 00316 key->flag &= ~PEK_HIDE; 00317 } 00318 } 00319 } 00320 } 00321 00322 static int pe_x_mirror(Object *ob) 00323 { 00324 if(ob->type == OB_MESH) 00325 return (((Mesh*)ob->data)->editflag & ME_EDIT_MIRROR_X); 00326 00327 return 0; 00328 } 00329 00330 /****************** common struct passed to callbacks ******************/ 00331 00332 typedef struct PEData { 00333 ViewContext vc; 00334 bglMats mats; 00335 00336 Scene *scene; 00337 Object *ob; 00338 DerivedMesh *dm; 00339 PTCacheEdit *edit; 00340 00341 const int *mval; 00342 rcti *rect; 00343 float rad; 00344 float dist; 00345 float dval; 00346 int select; 00347 00348 float *dvec; 00349 float combfac; 00350 float pufffac; 00351 float cutfac; 00352 float smoothfac; 00353 float weightfac; 00354 float growfac; 00355 int totrekey; 00356 00357 int invert; 00358 int tot; 00359 float vec[3]; 00360 } PEData; 00361 00362 static void PE_set_data(bContext *C, PEData *data) 00363 { 00364 memset(data, 0, sizeof(*data)); 00365 00366 data->scene= CTX_data_scene(C); 00367 data->ob= CTX_data_active_object(C); 00368 data->edit= PE_get_current(data->scene, data->ob); 00369 } 00370 00371 static void PE_set_view3d_data(bContext *C, PEData *data) 00372 { 00373 PE_set_data(C, data); 00374 00375 view3d_set_viewcontext(C, &data->vc); 00376 /* note, the object argument means the modelview matrix does not account for the objects matrix, use viewmat rather than (obmat * viewmat) */ 00377 view3d_get_transformation(data->vc.ar, data->vc.rv3d, NULL, &data->mats); 00378 00379 if((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT)) { 00380 if(data->vc.v3d->flag & V3D_INVALID_BACKBUF) { 00381 /* needed or else the draw matrix can be incorrect */ 00382 view3d_operator_needs_opengl(C); 00383 00384 view3d_validate_backbuf(&data->vc); 00385 /* we may need to force an update here by setting the rv3d as dirty 00386 * for now it seems ok, but take care!: 00387 * rv3d->depths->dirty = 1; */ 00388 ED_view3d_depth_update(data->vc.ar); 00389 } 00390 } 00391 } 00392 00393 /*************************** selection utilities *******************************/ 00394 00395 static int key_test_depth(PEData *data, float co[3]) 00396 { 00397 View3D *v3d= data->vc.v3d; 00398 double ux, uy, uz; 00399 float depth; 00400 short wco[3], x,y; 00401 00402 /* nothing to do */ 00403 if((v3d->drawtype<=OB_WIRE) || (v3d->flag & V3D_ZBUF_SELECT)==0) 00404 return 1; 00405 00406 project_short(data->vc.ar, co, wco); 00407 00408 if(wco[0] == IS_CLIPPED) 00409 return 0; 00410 00411 gluProject(co[0],co[1],co[2], data->mats.modelview, data->mats.projection, 00412 (GLint *)data->mats.viewport, &ux, &uy, &uz); 00413 00414 x=wco[0]; 00415 y=wco[1]; 00416 00417 #if 0 /* works well but too slow on some systems [#23118] */ 00418 x+= (short)data->vc.ar->winrct.xmin; 00419 y+= (short)data->vc.ar->winrct.ymin; 00420 00421 /* PE_set_view3d_data calls this. no need to call here */ 00422 /* view3d_validate_backbuf(&data->vc); */ 00423 glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); 00424 #else /* faster to use depths, these are calculated in PE_set_view3d_data */ 00425 { 00426 ViewDepths *vd = data->vc.rv3d->depths; 00427 assert(vd && vd->depths); 00428 /* we know its not clipped */ 00429 depth= vd->depths[y * vd->w + x]; 00430 } 00431 #endif 00432 00433 if((float)uz - 0.00001f > depth) 00434 return 0; 00435 else 00436 return 1; 00437 } 00438 00439 static int key_inside_circle(PEData *data, float rad, float co[3], float *distance) 00440 { 00441 float dx, dy, dist; 00442 int sco[2]; 00443 00444 project_int(data->vc.ar, co, sco); 00445 00446 if(sco[0] == IS_CLIPPED) 00447 return 0; 00448 00449 dx= data->mval[0] - sco[0]; 00450 dy= data->mval[1] - sco[1]; 00451 dist= sqrt(dx*dx + dy*dy); 00452 00453 if(dist > rad) 00454 return 0; 00455 00456 if(key_test_depth(data, co)) { 00457 if(distance) 00458 *distance=dist; 00459 00460 return 1; 00461 } 00462 00463 return 0; 00464 } 00465 00466 static int key_inside_rect(PEData *data, float co[3]) 00467 { 00468 int sco[2]; 00469 00470 project_int(data->vc.ar, co,sco); 00471 00472 if(sco[0] == IS_CLIPPED) 00473 return 0; 00474 00475 if(sco[0] > data->rect->xmin && sco[0] < data->rect->xmax && 00476 sco[1] > data->rect->ymin && sco[1] < data->rect->ymax) 00477 return key_test_depth(data, co); 00478 00479 return 0; 00480 } 00481 00482 static int key_inside_test(PEData *data, float co[3]) 00483 { 00484 if(data->mval) 00485 return key_inside_circle(data, data->rad, co, NULL); 00486 else 00487 return key_inside_rect(data, co); 00488 } 00489 00490 static int point_is_selected(PTCacheEditPoint *point) 00491 { 00492 KEY_K; 00493 00494 if(point->flag & PEP_HIDE) 00495 return 0; 00496 00497 LOOP_SELECTED_KEYS { 00498 return 1; 00499 } 00500 00501 return 0; 00502 } 00503 00504 /*************************** iterators *******************************/ 00505 00506 typedef void (*ForPointFunc)(PEData *data, int point_index); 00507 typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index); 00508 typedef void (*ForKeyMatFunc)(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key); 00509 00510 static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, int nearest) 00511 { 00512 ParticleEditSettings *pset= PE_settings(data->scene); 00513 PTCacheEdit *edit= data->edit; 00514 POINT_P; KEY_K; 00515 int nearest_point, nearest_key; 00516 float dist= data->rad; 00517 00518 /* in path select mode we have no keys */ 00519 if(pset->selectmode==SCE_SELECT_PATH) 00520 return; 00521 00522 nearest_point= -1; 00523 nearest_key= -1; 00524 00525 LOOP_VISIBLE_POINTS { 00526 if(pset->selectmode == SCE_SELECT_END) { 00527 /* only do end keys */ 00528 key= point->keys + point->totkey-1; 00529 00530 if(nearest) { 00531 if(key_inside_circle(data, dist, KEY_WCO, &dist)) { 00532 nearest_point= p; 00533 nearest_key= point->totkey-1; 00534 } 00535 } 00536 else if(key_inside_test(data, KEY_WCO)) 00537 func(data, p, point->totkey-1); 00538 } 00539 else { 00540 /* do all keys */ 00541 LOOP_VISIBLE_KEYS { 00542 if(nearest) { 00543 if(key_inside_circle(data, dist, KEY_WCO, &dist)) { 00544 nearest_point= p; 00545 nearest_key= k; 00546 } 00547 } 00548 else if(key_inside_test(data, KEY_WCO)) 00549 func(data, p, k); 00550 } 00551 } 00552 } 00553 00554 /* do nearest only */ 00555 if(nearest && nearest_point > -1) 00556 func(data, nearest_point, nearest_key); 00557 } 00558 00559 static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selected) 00560 { 00561 ParticleEditSettings *pset= PE_settings(data->scene); 00562 PTCacheEdit *edit= data->edit; 00563 POINT_P; KEY_K; 00564 00565 /* all is selected in path mode */ 00566 if(pset->selectmode==SCE_SELECT_PATH) 00567 selected=0; 00568 00569 LOOP_VISIBLE_POINTS { 00570 if(pset->selectmode==SCE_SELECT_END) { 00571 /* only do end keys */ 00572 key= point->keys + point->totkey - 1; 00573 00574 if(selected==0 || key->flag & PEK_SELECT) 00575 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) 00576 func(data, p); 00577 } 00578 else { 00579 /* do all keys */ 00580 LOOP_VISIBLE_KEYS { 00581 if(selected==0 || key->flag & PEK_SELECT) { 00582 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) { 00583 func(data, p); 00584 break; 00585 } 00586 } 00587 } 00588 } 00589 } 00590 } 00591 00592 static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected) 00593 { 00594 PTCacheEdit *edit = data->edit; 00595 ParticleSystem *psys = edit->psys; 00596 ParticleSystemModifierData *psmd = NULL; 00597 ParticleEditSettings *pset= PE_settings(data->scene); 00598 POINT_P; KEY_K; 00599 float mat[4][4]= MAT4_UNITY, imat[4][4]= MAT4_UNITY; 00600 00601 if(edit->psys) 00602 psmd= psys_get_modifier(data->ob, edit->psys); 00603 00604 /* all is selected in path mode */ 00605 if(pset->selectmode==SCE_SELECT_PATH) 00606 selected= 0; 00607 00608 LOOP_VISIBLE_POINTS { 00609 if(pset->selectmode==SCE_SELECT_END) { 00610 /* only do end keys */ 00611 key= point->keys + point->totkey-1; 00612 00613 if(selected==0 || key->flag & PEK_SELECT) { 00614 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) { 00615 if(edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) { 00616 psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat); 00617 invert_m4_m4(imat,mat); 00618 } 00619 00620 func(data, mat, imat, p, point->totkey-1, key); 00621 } 00622 } 00623 } 00624 else { 00625 /* do all keys */ 00626 LOOP_VISIBLE_KEYS { 00627 if(selected==0 || key->flag & PEK_SELECT) { 00628 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) { 00629 if(edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) { 00630 psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat); 00631 invert_m4_m4(imat,mat); 00632 } 00633 00634 func(data, mat, imat, p, k, key); 00635 } 00636 } 00637 } 00638 } 00639 } 00640 } 00641 00642 static void foreach_selected_point(PEData *data, ForPointFunc func) 00643 { 00644 PTCacheEdit *edit = data->edit; 00645 POINT_P; 00646 00647 LOOP_SELECTED_POINTS { 00648 func(data, p); 00649 } 00650 } 00651 00652 static void foreach_selected_key(PEData *data, ForKeyFunc func) 00653 { 00654 PTCacheEdit *edit = data->edit; 00655 POINT_P; KEY_K; 00656 00657 LOOP_VISIBLE_POINTS { 00658 LOOP_SELECTED_KEYS { 00659 func(data, p, k); 00660 } 00661 } 00662 } 00663 00664 static void foreach_point(PEData *data, ForPointFunc func) 00665 { 00666 PTCacheEdit *edit = data->edit; 00667 POINT_P; 00668 00669 LOOP_POINTS { 00670 func(data, p); 00671 } 00672 } 00673 00674 static int count_selected_keys(Scene *scene, PTCacheEdit *edit) 00675 { 00676 ParticleEditSettings *pset= PE_settings(scene); 00677 POINT_P; KEY_K; 00678 int sel= 0; 00679 00680 LOOP_VISIBLE_POINTS { 00681 if(pset->selectmode==SCE_SELECT_POINT) { 00682 LOOP_SELECTED_KEYS { 00683 sel++; 00684 } 00685 } 00686 else if(pset->selectmode==SCE_SELECT_END) { 00687 key = point->keys + point->totkey - 1; 00688 if(key->flag & PEK_SELECT) 00689 sel++; 00690 } 00691 } 00692 00693 return sel; 00694 } 00695 00696 /************************************************/ 00697 /* Particle Edit Mirroring */ 00698 /************************************************/ 00699 00700 static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys) 00701 { 00702 PTCacheEdit *edit; 00703 ParticleSystemModifierData *psmd; 00704 KDTree *tree; 00705 KDTreeNearest nearest; 00706 HairKey *key; 00707 PARTICLE_P; 00708 float mat[4][4], co[3]; 00709 int index, totpart; 00710 00711 edit= psys->edit; 00712 psmd= psys_get_modifier(ob, psys); 00713 totpart= psys->totpart; 00714 00715 if(!psmd->dm) 00716 return; 00717 00718 tree= BLI_kdtree_new(totpart); 00719 00720 /* insert particles into kd tree */ 00721 LOOP_PARTICLES { 00722 key = pa->hair; 00723 psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat); 00724 VECCOPY(co, key->co); 00725 mul_m4_v3(mat, co); 00726 BLI_kdtree_insert(tree, p, co, NULL); 00727 } 00728 00729 BLI_kdtree_balance(tree); 00730 00731 /* lookup particles and set in mirror cache */ 00732 if(!edit->mirror_cache) 00733 edit->mirror_cache= MEM_callocN(sizeof(int)*totpart, "PE mirror cache"); 00734 00735 LOOP_PARTICLES { 00736 key = pa->hair; 00737 psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat); 00738 VECCOPY(co, key->co); 00739 mul_m4_v3(mat, co); 00740 co[0]= -co[0]; 00741 00742 index= BLI_kdtree_find_nearest(tree, co, NULL, &nearest); 00743 00744 /* this needs a custom threshold still, duplicated for editmode mirror */ 00745 if(index != -1 && index != p && (nearest.dist <= 0.0002f)) 00746 edit->mirror_cache[p]= index; 00747 else 00748 edit->mirror_cache[p]= -1; 00749 } 00750 00751 /* make sure mirrors are in two directions */ 00752 LOOP_PARTICLES { 00753 if(edit->mirror_cache[p]) { 00754 index= edit->mirror_cache[p]; 00755 if(edit->mirror_cache[index] != p) 00756 edit->mirror_cache[p]= -1; 00757 } 00758 } 00759 00760 BLI_kdtree_free(tree); 00761 } 00762 00763 static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa) 00764 { 00765 HairKey *hkey, *mhkey; 00766 PTCacheEditPoint *point, *mpoint; 00767 PTCacheEditKey *key, *mkey; 00768 PTCacheEdit *edit; 00769 float mat[4][4], mmat[4][4], immat[4][4]; 00770 int i, mi, k; 00771 00772 edit= psys->edit; 00773 i= pa - psys->particles; 00774 00775 /* find mirrored particle if needed */ 00776 if(!mpa) { 00777 if(!edit->mirror_cache) 00778 PE_update_mirror_cache(ob, psys); 00779 00780 if(!edit->mirror_cache) 00781 return; /* something went wrong! */ 00782 00783 mi= edit->mirror_cache[i]; 00784 if(mi == -1) 00785 return; 00786 mpa= psys->particles + mi; 00787 } 00788 else 00789 mi= mpa - psys->particles; 00790 00791 point = edit->points + i; 00792 mpoint = edit->points + mi; 00793 00794 /* make sure they have the same amount of keys */ 00795 if(pa->totkey != mpa->totkey) { 00796 if(mpa->hair) MEM_freeN(mpa->hair); 00797 if(mpoint->keys) MEM_freeN(mpoint->keys); 00798 00799 mpa->hair= MEM_dupallocN(pa->hair); 00800 mpa->totkey= pa->totkey; 00801 mpoint->keys= MEM_dupallocN(point->keys); 00802 mpoint->totkey= point->totkey; 00803 00804 mhkey= mpa->hair; 00805 mkey= mpoint->keys; 00806 for(k=0; k<mpa->totkey; k++, mkey++, mhkey++) { 00807 mkey->co= mhkey->co; 00808 mkey->time= &mhkey->time; 00809 mkey->flag &= ~PEK_SELECT; 00810 } 00811 } 00812 00813 /* mirror positions and tags */ 00814 psys_mat_hair_to_orco(ob, dm, psys->part->from, pa, mat); 00815 psys_mat_hair_to_orco(ob, dm, psys->part->from, mpa, mmat); 00816 invert_m4_m4(immat, mmat); 00817 00818 hkey=pa->hair; 00819 mhkey=mpa->hair; 00820 key= point->keys; 00821 mkey= mpoint->keys; 00822 for(k=0; k<pa->totkey; k++, hkey++, mhkey++, key++, mkey++) { 00823 VECCOPY(mhkey->co, hkey->co); 00824 mul_m4_v3(mat, mhkey->co); 00825 mhkey->co[0]= -mhkey->co[0]; 00826 mul_m4_v3(immat, mhkey->co); 00827 00828 if(key->flag & PEK_TAG) 00829 mkey->flag |= PEK_TAG; 00830 00831 mkey->length = key->length; 00832 } 00833 00834 if(point->flag & PEP_TAG) 00835 mpoint->flag |= PEP_TAG; 00836 if(point->flag & PEP_EDIT_RECALC) 00837 mpoint->flag |= PEP_EDIT_RECALC; 00838 } 00839 00840 static void PE_apply_mirror(Object *ob, ParticleSystem *psys) 00841 { 00842 PTCacheEdit *edit; 00843 ParticleSystemModifierData *psmd; 00844 POINT_P; 00845 00846 if(!psys) 00847 return; 00848 00849 edit= psys->edit; 00850 psmd= psys_get_modifier(ob, psys); 00851 00852 if(!psmd->dm) 00853 return; 00854 00855 if(!edit->mirror_cache) 00856 PE_update_mirror_cache(ob, psys); 00857 00858 if(!edit->mirror_cache) 00859 return; /* something went wrong */ 00860 00861 /* we delay settings the PARS_EDIT_RECALC for mirrored particles 00862 * to avoid doing mirror twice */ 00863 LOOP_POINTS { 00864 if(point->flag & PEP_EDIT_RECALC) { 00865 PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL); 00866 00867 if(edit->mirror_cache[p] != -1) 00868 edit->points[edit->mirror_cache[p]].flag &= ~PEP_EDIT_RECALC; 00869 } 00870 } 00871 00872 LOOP_POINTS { 00873 if(point->flag & PEP_EDIT_RECALC) 00874 if(edit->mirror_cache[p] != -1) 00875 edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC; 00876 } 00877 } 00878 00879 /************************************************/ 00880 /* Edit Calculation */ 00881 /************************************************/ 00882 /* tries to stop edited particles from going through the emitter's surface */ 00883 static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit) 00884 { 00885 ParticleEditSettings *pset= PE_settings(scene); 00886 ParticleSystem *psys; 00887 ParticleSystemModifierData *psmd; 00888 POINT_P; KEY_K; 00889 int index; 00890 float *vec, *nor, dvec[3], dot, dist_1st=0.0f; 00891 float hairimat[4][4], hairmat[4][4]; 00892 00893 if(edit==NULL || edit->psys==NULL || (pset->flag & PE_DEFLECT_EMITTER)==0 || (edit->psys->flag & PSYS_GLOBAL_HAIR)) 00894 return; 00895 00896 psys = edit->psys; 00897 psmd = psys_get_modifier(ob,psys); 00898 00899 if(!psmd->dm) 00900 return; 00901 00902 LOOP_EDITED_POINTS { 00903 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles + p, hairmat); 00904 00905 LOOP_KEYS { 00906 mul_m4_v3(hairmat, key->co); 00907 } 00908 00909 LOOP_KEYS { 00910 if(k==0) { 00911 dist_1st = len_v3v3((key+1)->co, key->co); 00912 dist_1st *= 0.75f * pset->emitterdist; 00913 } 00914 else { 00915 index= BLI_kdtree_find_nearest(edit->emitter_field,key->co,NULL,NULL); 00916 00917 vec=edit->emitter_cosnos +index*6; 00918 nor=vec+3; 00919 00920 sub_v3_v3v3(dvec, key->co, vec); 00921 00922 dot=dot_v3v3(dvec,nor); 00923 VECCOPY(dvec,nor); 00924 00925 if(dot>0.0f) { 00926 if(dot<dist_1st) { 00927 normalize_v3(dvec); 00928 mul_v3_fl(dvec,dist_1st-dot); 00929 add_v3_v3(key->co, dvec); 00930 } 00931 } 00932 else { 00933 normalize_v3(dvec); 00934 mul_v3_fl(dvec,dist_1st-dot); 00935 add_v3_v3(key->co, dvec); 00936 } 00937 if(k==1) 00938 dist_1st*=1.3333f; 00939 } 00940 } 00941 00942 invert_m4_m4(hairimat,hairmat); 00943 00944 LOOP_KEYS { 00945 mul_m4_v3(hairimat, key->co); 00946 } 00947 } 00948 } 00949 /* force set distances between neighbouring keys */ 00950 static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit) 00951 { 00952 00953 ParticleEditSettings *pset=PE_settings(scene); 00954 POINT_P; KEY_K; 00955 float dv1[3]; 00956 00957 if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0) 00958 return; 00959 00960 if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR) 00961 return; 00962 00963 LOOP_EDITED_POINTS { 00964 LOOP_KEYS { 00965 if(k) { 00966 sub_v3_v3v3(dv1, key->co, (key - 1)->co); 00967 normalize_v3(dv1); 00968 mul_v3_fl(dv1, (key - 1)->length); 00969 add_v3_v3v3(key->co, (key - 1)->co, dv1); 00970 } 00971 } 00972 } 00973 } 00974 /* try to find a nice solution to keep distances between neighbouring keys */ 00975 static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit) 00976 { 00977 ParticleEditSettings *pset=PE_settings(scene); 00978 POINT_P; 00979 PTCacheEditKey *key; 00980 int j, k; 00981 float tlen; 00982 float dv0[3]= {0.0f, 0.0f, 0.0f}; 00983 float dv1[3]= {0.0f, 0.0f, 0.0f}; 00984 float dv2[3]= {0.0f, 0.0f, 0.0f}; 00985 00986 if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0) 00987 return; 00988 00989 if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR) 00990 return; 00991 00992 LOOP_EDITED_POINTS { 00993 for(j=1; j<point->totkey; j++) { 00994 float mul= 1.0f / (float)point->totkey; 00995 00996 if(pset->flag & PE_LOCK_FIRST) { 00997 key= point->keys + 1; 00998 k= 1; 00999 dv1[0]= dv1[1]= dv1[2]= 0.0; 01000 } 01001 else { 01002 key= point->keys; 01003 k= 0; 01004 dv0[0]= dv0[1]= dv0[2]= 0.0; 01005 } 01006 01007 for(; k<point->totkey; k++, key++) { 01008 if(k) { 01009 sub_v3_v3v3(dv0, (key - 1)->co, key->co); 01010 tlen= normalize_v3(dv0); 01011 mul_v3_fl(dv0, (mul * (tlen - (key - 1)->length))); 01012 } 01013 01014 if(k < point->totkey - 1) { 01015 sub_v3_v3v3(dv2, (key + 1)->co, key->co); 01016 tlen= normalize_v3(dv2); 01017 mul_v3_fl(dv2, mul * (tlen - key->length)); 01018 } 01019 01020 if(k) { 01021 add_v3_v3((key-1)->co, dv1); 01022 } 01023 01024 VECADD(dv1,dv0,dv2); 01025 } 01026 } 01027 } 01028 } 01029 /* set current distances to be kept between neighbouting keys */ 01030 static void recalc_lengths(PTCacheEdit *edit) 01031 { 01032 POINT_P; KEY_K; 01033 01034 if(edit==0) 01035 return; 01036 01037 LOOP_EDITED_POINTS { 01038 key= point->keys; 01039 for(k=0; k<point->totkey-1; k++, key++) { 01040 key->length= len_v3v3(key->co, (key + 1)->co); 01041 } 01042 } 01043 } 01044 01045 /* calculate a tree for finding nearest emitter's vertice */ 01046 static void recalc_emitter_field(Object *ob, ParticleSystem *psys) 01047 { 01048 DerivedMesh *dm=psys_get_modifier(ob,psys)->dm; 01049 PTCacheEdit *edit= psys->edit; 01050 float *vec, *nor; 01051 int i, totface /*, totvert*/; 01052 01053 if(!dm) 01054 return; 01055 01056 if(edit->emitter_cosnos) 01057 MEM_freeN(edit->emitter_cosnos); 01058 01059 BLI_kdtree_free(edit->emitter_field); 01060 01061 totface=dm->getNumFaces(dm); 01062 /*totvert=dm->getNumVerts(dm);*/ /*UNSUED*/ 01063 01064 edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float),"emitter cosnos"); 01065 01066 edit->emitter_field= BLI_kdtree_new(totface); 01067 01068 vec=edit->emitter_cosnos; 01069 nor=vec+3; 01070 01071 for(i=0; i<totface; i++, vec+=6, nor+=6) { 01072 MFace *mface=dm->getFaceData(dm,i,CD_MFACE); 01073 MVert *mvert; 01074 01075 mvert=dm->getVertData(dm,mface->v1,CD_MVERT); 01076 VECCOPY(vec,mvert->co); 01077 VECCOPY(nor,mvert->no); 01078 01079 mvert=dm->getVertData(dm,mface->v2,CD_MVERT); 01080 VECADD(vec,vec,mvert->co); 01081 VECADD(nor,nor,mvert->no); 01082 01083 mvert=dm->getVertData(dm,mface->v3,CD_MVERT); 01084 VECADD(vec,vec,mvert->co); 01085 VECADD(nor,nor,mvert->no); 01086 01087 if(mface->v4) { 01088 mvert=dm->getVertData(dm,mface->v4,CD_MVERT); 01089 VECADD(vec,vec,mvert->co); 01090 VECADD(nor,nor,mvert->no); 01091 01092 mul_v3_fl(vec,0.25); 01093 } 01094 else 01095 mul_v3_fl(vec,0.3333f); 01096 01097 normalize_v3(nor); 01098 01099 BLI_kdtree_insert(edit->emitter_field, i, vec, NULL); 01100 } 01101 01102 BLI_kdtree_balance(edit->emitter_field); 01103 } 01104 01105 static void PE_update_selection(Scene *scene, Object *ob, int useflag) 01106 { 01107 PTCacheEdit *edit= PE_get_current(scene, ob); 01108 HairKey *hkey; 01109 POINT_P; KEY_K; 01110 01111 /* flag all particles to be updated if not using flag */ 01112 if(!useflag) 01113 LOOP_POINTS 01114 point->flag |= PEP_EDIT_RECALC; 01115 01116 /* flush edit key flag to hair key flag to preserve selection 01117 * on save */ 01118 if(edit->psys) LOOP_POINTS { 01119 hkey = edit->psys->particles[p].hair; 01120 LOOP_KEYS { 01121 hkey->editflag= key->flag; 01122 hkey++; 01123 } 01124 } 01125 01126 psys_cache_edit_paths(scene, ob, edit, CFRA); 01127 01128 01129 /* disable update flag */ 01130 LOOP_POINTS 01131 point->flag &= ~PEP_EDIT_RECALC; 01132 } 01133 01134 static void update_world_cos(Object *ob, PTCacheEdit *edit) 01135 { 01136 ParticleSystem *psys = edit->psys; 01137 ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys); 01138 POINT_P; KEY_K; 01139 float hairmat[4][4]; 01140 01141 if(psys==0 || psys->edit==0 || psmd->dm==NULL) 01142 return; 01143 01144 LOOP_POINTS { 01145 if(!(psys->flag & PSYS_GLOBAL_HAIR)) 01146 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles+p, hairmat); 01147 01148 LOOP_KEYS { 01149 VECCOPY(key->world_co,key->co); 01150 if(!(psys->flag & PSYS_GLOBAL_HAIR)) 01151 mul_m4_v3(hairmat, key->world_co); 01152 } 01153 } 01154 } 01155 static void update_velocities(PTCacheEdit *edit) 01156 { 01157 /*TODO: get frs_sec properly */ 01158 float vec1[3], vec2[3], frs_sec, dfra; 01159 POINT_P; KEY_K; 01160 01161 /* hair doesn't use velocities */ 01162 if(edit->psys || !edit->points || !edit->points->keys->vel) 01163 return; 01164 01165 frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f; 01166 01167 LOOP_EDITED_POINTS { 01168 LOOP_KEYS { 01169 if(k==0) { 01170 dfra = *(key+1)->time - *key->time; 01171 01172 if(dfra <= 0.0f) 01173 continue; 01174 01175 VECSUB(key->vel, (key+1)->co, key->co); 01176 01177 if(point->totkey>2) { 01178 VECSUB(vec1, (key+1)->co, (key+2)->co); 01179 project_v3_v3v3(vec2, vec1, key->vel); 01180 VECSUB(vec2, vec1, vec2); 01181 VECADDFAC(key->vel, key->vel, vec2, 0.5f); 01182 } 01183 } 01184 else if(k==point->totkey-1) { 01185 dfra = *key->time - *(key-1)->time; 01186 01187 if(dfra <= 0.0f) 01188 continue; 01189 01190 VECSUB(key->vel, key->co, (key-1)->co); 01191 01192 if(point->totkey>2) { 01193 VECSUB(vec1, (key-2)->co, (key-1)->co); 01194 project_v3_v3v3(vec2, vec1, key->vel); 01195 VECSUB(vec2, vec1, vec2); 01196 VECADDFAC(key->vel, key->vel, vec2, 0.5f); 01197 } 01198 } 01199 else { 01200 dfra = *(key+1)->time - *(key-1)->time; 01201 01202 if(dfra <= 0.0f) 01203 continue; 01204 01205 VECSUB(key->vel, (key+1)->co, (key-1)->co); 01206 } 01207 mul_v3_fl(key->vel, frs_sec/dfra); 01208 } 01209 } 01210 } 01211 01212 void PE_update_object(Scene *scene, Object *ob, int useflag) 01213 { 01214 /* use this to do partial particle updates, not usable when adding or 01215 removing, then a full redo is necessary and calling this may crash */ 01216 ParticleEditSettings *pset= PE_settings(scene); 01217 PTCacheEdit *edit = PE_get_current(scene, ob); 01218 POINT_P; 01219 01220 if(!edit) 01221 return; 01222 01223 /* flag all particles to be updated if not using flag */ 01224 if(!useflag) 01225 LOOP_POINTS { 01226 point->flag |= PEP_EDIT_RECALC; 01227 } 01228 01229 /* do post process on particle edit keys */ 01230 pe_iterate_lengths(scene, edit); 01231 pe_deflect_emitter(scene, ob, edit); 01232 PE_apply_lengths(scene, edit); 01233 if(pe_x_mirror(ob)) 01234 PE_apply_mirror(ob,edit->psys); 01235 if(edit->psys) 01236 update_world_cos(ob, edit); 01237 if(pset->flag & PE_AUTO_VELOCITY) 01238 update_velocities(edit); 01239 PE_hide_keys_time(scene, edit, CFRA); 01240 01241 /* regenerate path caches */ 01242 psys_cache_edit_paths(scene, ob, edit, CFRA); 01243 01244 /* disable update flag */ 01245 LOOP_POINTS { 01246 point->flag &= ~PEP_EDIT_RECALC; 01247 } 01248 01249 if(edit->psys) 01250 edit->psys->flag &= ~PSYS_HAIR_UPDATED; 01251 } 01252 01253 /************************************************/ 01254 /* Edit Selections */ 01255 /************************************************/ 01256 01257 /*-----selection callbacks-----*/ 01258 01259 static void select_key(PEData *data, int point_index, int key_index) 01260 { 01261 PTCacheEdit *edit = data->edit; 01262 PTCacheEditPoint *point = edit->points + point_index; 01263 PTCacheEditKey *key = point->keys + key_index; 01264 01265 if(data->select) 01266 key->flag |= PEK_SELECT; 01267 else 01268 key->flag &= ~PEK_SELECT; 01269 01270 point->flag |= PEP_EDIT_RECALC; 01271 } 01272 01273 static void select_keys(PEData *data, int point_index, int UNUSED(key_index)) 01274 { 01275 PTCacheEdit *edit = data->edit; 01276 PTCacheEditPoint *point = edit->points + point_index; 01277 KEY_K; 01278 01279 LOOP_KEYS { 01280 if(data->select) 01281 key->flag |= PEK_SELECT; 01282 else 01283 key->flag &= ~PEK_SELECT; 01284 } 01285 01286 point->flag |= PEP_EDIT_RECALC; 01287 } 01288 01289 static void toggle_key_select(PEData *data, int point_index, int key_index) 01290 { 01291 PTCacheEdit *edit = data->edit; 01292 PTCacheEditPoint *point = edit->points + point_index; 01293 PTCacheEditKey *key = point->keys + key_index; 01294 01295 key->flag ^= PEK_SELECT; 01296 point->flag |= PEP_EDIT_RECALC; 01297 } 01298 01299 /************************ de select all operator ************************/ 01300 01301 static int select_all_exec(bContext *C, wmOperator *op) 01302 { 01303 Scene *scene= CTX_data_scene(C); 01304 Object *ob= CTX_data_active_object(C); 01305 PTCacheEdit *edit= PE_get_current(scene, ob); 01306 POINT_P; KEY_K; 01307 int action = RNA_enum_get(op->ptr, "action"); 01308 01309 if (action == SEL_TOGGLE) { 01310 action = SEL_SELECT; 01311 LOOP_VISIBLE_POINTS { 01312 LOOP_SELECTED_KEYS { 01313 action = SEL_DESELECT; 01314 break; 01315 } 01316 01317 if (action == SEL_DESELECT) 01318 break; 01319 } 01320 } 01321 01322 LOOP_VISIBLE_POINTS { 01323 LOOP_VISIBLE_KEYS { 01324 switch (action) { 01325 case SEL_SELECT: 01326 if ((key->flag & PEK_SELECT) == 0) { 01327 key->flag |= PEK_SELECT; 01328 point->flag |= PEP_EDIT_RECALC; 01329 } 01330 break; 01331 case SEL_DESELECT: 01332 if (key->flag & PEK_SELECT) { 01333 key->flag &= ~PEK_SELECT; 01334 point->flag |= PEP_EDIT_RECALC; 01335 } 01336 break; 01337 case SEL_INVERT: 01338 if ((key->flag & PEK_SELECT) == 0) { 01339 key->flag |= PEK_SELECT; 01340 point->flag |= PEP_EDIT_RECALC; 01341 } else { 01342 key->flag &= ~PEK_SELECT; 01343 point->flag |= PEP_EDIT_RECALC; 01344 } 01345 break; 01346 } 01347 } 01348 } 01349 01350 PE_update_selection(scene, ob, 1); 01351 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); 01352 01353 return OPERATOR_FINISHED; 01354 } 01355 01356 void PARTICLE_OT_select_all(wmOperatorType *ot) 01357 { 01358 /* identifiers */ 01359 ot->name= "Selection of all particles"; 01360 ot->idname= "PARTICLE_OT_select_all"; 01361 01362 /* api callbacks */ 01363 ot->exec= select_all_exec; 01364 ot->poll= PE_poll; 01365 01366 /* flags */ 01367 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01368 01369 WM_operator_properties_select_all(ot); 01370 } 01371 01372 /************************ pick select operator ************************/ 01373 01374 int PE_mouse_particles(bContext *C, const int mval[2], int extend) 01375 { 01376 PEData data; 01377 Scene *scene= CTX_data_scene(C); 01378 Object *ob= CTX_data_active_object(C); 01379 PTCacheEdit *edit= PE_get_current(scene, ob); 01380 POINT_P; KEY_K; 01381 01382 if(!PE_start_edit(edit)) 01383 return OPERATOR_CANCELLED; 01384 01385 if(!extend) { 01386 LOOP_VISIBLE_POINTS { 01387 LOOP_SELECTED_KEYS { 01388 key->flag &= ~PEK_SELECT; 01389 point->flag |= PEP_EDIT_RECALC; 01390 } 01391 } 01392 } 01393 01394 PE_set_view3d_data(C, &data); 01395 data.mval= mval; 01396 data.rad= 75.0f; 01397 01398 for_mouse_hit_keys(&data, toggle_key_select, 1); /* nearest only */ 01399 01400 PE_update_selection(scene, ob, 1); 01401 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); 01402 01403 return OPERATOR_FINISHED; 01404 } 01405 01406 /************************ select first operator ************************/ 01407 01408 static void select_root(PEData *data, int point_index) 01409 { 01410 if (data->edit->points[point_index].flag & PEP_HIDE) 01411 return; 01412 01413 data->edit->points[point_index].keys->flag |= PEK_SELECT; 01414 data->edit->points[point_index].flag |= PEP_EDIT_RECALC; /* redraw selection only */ 01415 } 01416 01417 static int select_roots_exec(bContext *C, wmOperator *UNUSED(op)) 01418 { 01419 PEData data; 01420 01421 PE_set_data(C, &data); 01422 foreach_point(&data, select_root); 01423 01424 PE_update_selection(data.scene, data.ob, 1); 01425 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); 01426 01427 return OPERATOR_FINISHED; 01428 } 01429 01430 void PARTICLE_OT_select_roots(wmOperatorType *ot) 01431 { 01432 /* identifiers */ 01433 ot->name= "Select Roots"; 01434 ot->idname= "PARTICLE_OT_select_roots"; 01435 01436 /* api callbacks */ 01437 ot->exec= select_roots_exec; 01438 ot->poll= PE_poll; 01439 01440 /* flags */ 01441 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01442 } 01443 01444 /************************ select last operator ************************/ 01445 01446 static void select_tip(PEData *data, int point_index) 01447 { 01448 PTCacheEditPoint *point = data->edit->points + point_index; 01449 01450 if (point->flag & PEP_HIDE) 01451 return; 01452 01453 point->keys[point->totkey - 1].flag |= PEK_SELECT; 01454 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */ 01455 } 01456 01457 static int select_tips_exec(bContext *C, wmOperator *UNUSED(op)) 01458 { 01459 PEData data; 01460 01461 PE_set_data(C, &data); 01462 foreach_point(&data, select_tip); 01463 01464 PE_update_selection(data.scene, data.ob, 1); 01465 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); 01466 01467 return OPERATOR_FINISHED; 01468 } 01469 01470 void PARTICLE_OT_select_tips(wmOperatorType *ot) 01471 { 01472 /* identifiers */ 01473 ot->name= "Select Tips"; 01474 ot->idname= "PARTICLE_OT_select_tips"; 01475 01476 /* api callbacks */ 01477 ot->exec= select_tips_exec; 01478 ot->poll= PE_poll; 01479 01480 /* flags */ 01481 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01482 } 01483 01484 /************************ select linked operator ************************/ 01485 01486 static int select_linked_exec(bContext *C, wmOperator *op) 01487 { 01488 PEData data; 01489 int mval[2]; 01490 int location[2]; 01491 01492 RNA_int_get_array(op->ptr, "location", location); 01493 mval[0]= location[0]; 01494 mval[1]= location[1]; 01495 01496 PE_set_view3d_data(C, &data); 01497 data.mval= mval; 01498 data.rad=75.0f; 01499 data.select= !RNA_boolean_get(op->ptr, "deselect"); 01500 01501 for_mouse_hit_keys(&data, select_keys, 1); /* nearest only */ 01502 PE_update_selection(data.scene, data.ob, 1); 01503 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); 01504 01505 return OPERATOR_FINISHED; 01506 } 01507 01508 static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event) 01509 { 01510 RNA_int_set_array(op->ptr, "location", event->mval); 01511 return select_linked_exec(C, op); 01512 } 01513 01514 void PARTICLE_OT_select_linked(wmOperatorType *ot) 01515 { 01516 /* identifiers */ 01517 ot->name= "Select Linked"; 01518 ot->idname= "PARTICLE_OT_select_linked"; 01519 01520 /* api callbacks */ 01521 ot->exec= select_linked_exec; 01522 ot->invoke= select_linked_invoke; 01523 ot->poll= PE_poll_view3d; 01524 01525 /* flags */ 01526 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01527 01528 /* properties */ 01529 RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them."); 01530 RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384); 01531 } 01532 01533 /************************ border select operator ************************/ 01534 void PE_deselect_all_visible(PTCacheEdit *edit) 01535 { 01536 POINT_P; KEY_K; 01537 01538 LOOP_VISIBLE_POINTS { 01539 LOOP_SELECTED_KEYS { 01540 key->flag &= ~PEK_SELECT; 01541 point->flag |= PEP_EDIT_RECALC; 01542 } 01543 } 01544 } 01545 01546 int PE_border_select(bContext *C, rcti *rect, int select, int extend) 01547 { 01548 Scene *scene= CTX_data_scene(C); 01549 Object *ob= CTX_data_active_object(C); 01550 PTCacheEdit *edit= PE_get_current(scene, ob); 01551 PEData data; 01552 01553 if(!PE_start_edit(edit)) 01554 return OPERATOR_CANCELLED; 01555 01556 if (extend == 0 && select) 01557 PE_deselect_all_visible(edit); 01558 01559 PE_set_view3d_data(C, &data); 01560 data.rect= rect; 01561 data.select= select; 01562 01563 for_mouse_hit_keys(&data, select_key, 0); 01564 01565 PE_update_selection(scene, ob, 1); 01566 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); 01567 01568 return OPERATOR_FINISHED; 01569 } 01570 01571 /************************ circle select operator ************************/ 01572 01573 int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad) 01574 { 01575 Scene *scene= CTX_data_scene(C); 01576 Object *ob= CTX_data_active_object(C); 01577 PTCacheEdit *edit= PE_get_current(scene, ob); 01578 PEData data; 01579 01580 if(!PE_start_edit(edit)) 01581 return OPERATOR_FINISHED; 01582 01583 PE_set_view3d_data(C, &data); 01584 data.mval= mval; 01585 data.rad= rad; 01586 data.select= selecting; 01587 01588 for_mouse_hit_keys(&data, select_key, 0); 01589 01590 PE_update_selection(scene, ob, 1); 01591 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); 01592 01593 return OPERATOR_FINISHED; 01594 } 01595 01596 /************************ lasso select operator ************************/ 01597 01598 int PE_lasso_select(bContext *C, int mcords[][2], short moves, short extend, short select) 01599 { 01600 Scene *scene= CTX_data_scene(C); 01601 Object *ob= CTX_data_active_object(C); 01602 ARegion *ar= CTX_wm_region(C); 01603 ParticleEditSettings *pset= PE_settings(scene); 01604 PTCacheEdit *edit = PE_get_current(scene, ob); 01605 ParticleSystem *psys = edit->psys; 01606 ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); 01607 POINT_P; KEY_K; 01608 float co[3], mat[4][4]= MAT4_UNITY; 01609 int vertco[2]; 01610 01611 PEData data; 01612 01613 if(!PE_start_edit(edit)) 01614 return OPERATOR_CANCELLED; 01615 01616 if (extend == 0 && select) 01617 PE_deselect_all_visible(edit); 01618 01619 /* only for depths */ 01620 PE_set_view3d_data(C, &data); 01621 01622 LOOP_VISIBLE_POINTS { 01623 if(edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR)) 01624 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + p, mat); 01625 01626 if(pset->selectmode==SCE_SELECT_POINT) { 01627 LOOP_KEYS { 01628 VECCOPY(co, key->co); 01629 mul_m4_v3(mat, co); 01630 project_int(ar, co, vertco); 01631 if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1]) && key_test_depth(&data, co)) { 01632 if(select && !(key->flag & PEK_SELECT)) { 01633 key->flag |= PEK_SELECT; 01634 point->flag |= PEP_EDIT_RECALC; 01635 } 01636 else if(key->flag & PEK_SELECT) { 01637 key->flag &= ~PEK_SELECT; 01638 point->flag |= PEP_EDIT_RECALC; 01639 } 01640 } 01641 } 01642 } 01643 else if(pset->selectmode==SCE_SELECT_END) { 01644 key= point->keys + point->totkey - 1; 01645 01646 VECCOPY(co, key->co); 01647 mul_m4_v3(mat, co); 01648 project_int(ar, co,vertco); 01649 if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1]) && key_test_depth(&data, co)) { 01650 if(select && !(key->flag & PEK_SELECT)) { 01651 key->flag |= PEK_SELECT; 01652 point->flag |= PEP_EDIT_RECALC; 01653 } 01654 else if(key->flag & PEK_SELECT) { 01655 key->flag &= ~PEK_SELECT; 01656 point->flag |= PEP_EDIT_RECALC; 01657 } 01658 } 01659 } 01660 } 01661 01662 PE_update_selection(scene, ob, 1); 01663 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); 01664 01665 return OPERATOR_FINISHED; 01666 } 01667 01668 /*************************** hide operator **************************/ 01669 01670 static int hide_exec(bContext *C, wmOperator *op) 01671 { 01672 Object *ob= CTX_data_active_object(C); 01673 Scene *scene= CTX_data_scene(C); 01674 PTCacheEdit *edit= PE_get_current(scene, ob); 01675 POINT_P; KEY_K; 01676 01677 if(RNA_enum_get(op->ptr, "unselected")) { 01678 LOOP_UNSELECTED_POINTS { 01679 point->flag |= PEP_HIDE; 01680 point->flag |= PEP_EDIT_RECALC; 01681 01682 LOOP_KEYS 01683 key->flag &= ~PEK_SELECT; 01684 } 01685 } 01686 else { 01687 LOOP_SELECTED_POINTS { 01688 point->flag |= PEP_HIDE; 01689 point->flag |= PEP_EDIT_RECALC; 01690 01691 LOOP_KEYS 01692 key->flag &= ~PEK_SELECT; 01693 } 01694 } 01695 01696 PE_update_selection(scene, ob, 1); 01697 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); 01698 01699 return OPERATOR_FINISHED; 01700 } 01701 01702 void PARTICLE_OT_hide(wmOperatorType *ot) 01703 { 01704 /* identifiers */ 01705 ot->name= "Hide Selected"; 01706 ot->idname= "PARTICLE_OT_hide"; 01707 01708 /* api callbacks */ 01709 ot->exec= hide_exec; 01710 ot->poll= PE_poll; 01711 01712 /* flags */ 01713 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01714 01715 /* props */ 01716 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected."); 01717 } 01718 01719 /*************************** reveal operator **************************/ 01720 01721 static int reveal_exec(bContext *C, wmOperator *UNUSED(op)) 01722 { 01723 Object *ob= CTX_data_active_object(C); 01724 Scene *scene= CTX_data_scene(C); 01725 PTCacheEdit *edit= PE_get_current(scene, ob); 01726 POINT_P; KEY_K; 01727 01728 LOOP_POINTS { 01729 if(point->flag & PEP_HIDE) { 01730 point->flag &= ~PEP_HIDE; 01731 point->flag |= PEP_EDIT_RECALC; 01732 01733 LOOP_KEYS 01734 key->flag |= PEK_SELECT; 01735 } 01736 } 01737 01738 PE_update_selection(scene, ob, 1); 01739 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); 01740 01741 return OPERATOR_FINISHED; 01742 } 01743 01744 void PARTICLE_OT_reveal(wmOperatorType *ot) 01745 { 01746 /* identifiers */ 01747 ot->name= "Reveal"; 01748 ot->idname= "PARTICLE_OT_reveal"; 01749 01750 /* api callbacks */ 01751 ot->exec= reveal_exec; 01752 ot->poll= PE_poll; 01753 01754 /* flags */ 01755 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01756 } 01757 01758 /************************ select less operator ************************/ 01759 01760 static void select_less_keys(PEData *data, int point_index) 01761 { 01762 PTCacheEdit *edit= data->edit; 01763 PTCacheEditPoint *point = edit->points + point_index; 01764 KEY_K; 01765 01766 LOOP_SELECTED_KEYS { 01767 if(k==0) { 01768 if(((key+1)->flag&PEK_SELECT)==0) 01769 key->flag |= PEK_TAG; 01770 } 01771 else if(k==point->totkey-1) { 01772 if(((key-1)->flag&PEK_SELECT)==0) 01773 key->flag |= PEK_TAG; 01774 } 01775 else { 01776 if((((key-1)->flag & (key+1)->flag) & PEK_SELECT)==0) 01777 key->flag |= PEK_TAG; 01778 } 01779 } 01780 01781 LOOP_KEYS { 01782 if(key->flag&PEK_TAG) { 01783 key->flag &= ~(PEK_TAG|PEK_SELECT); 01784 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */ 01785 } 01786 } 01787 } 01788 01789 static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) 01790 { 01791 PEData data; 01792 01793 PE_set_data(C, &data); 01794 foreach_point(&data, select_less_keys); 01795 01796 PE_update_selection(data.scene, data.ob, 1); 01797 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); 01798 01799 return OPERATOR_FINISHED; 01800 } 01801 01802 void PARTICLE_OT_select_less(wmOperatorType *ot) 01803 { 01804 /* identifiers */ 01805 ot->name= "Select Less"; 01806 ot->idname= "PARTICLE_OT_select_less"; 01807 01808 /* api callbacks */ 01809 ot->exec= select_less_exec; 01810 ot->poll= PE_poll; 01811 01812 /* flags */ 01813 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01814 } 01815 01816 /************************ select more operator ************************/ 01817 01818 static void select_more_keys(PEData *data, int point_index) 01819 { 01820 PTCacheEdit *edit= data->edit; 01821 PTCacheEditPoint *point = edit->points + point_index; 01822 KEY_K; 01823 01824 LOOP_KEYS { 01825 if(key->flag & PEK_SELECT) continue; 01826 01827 if(k==0) { 01828 if((key+1)->flag&PEK_SELECT) 01829 key->flag |= PEK_TAG; 01830 } 01831 else if(k==point->totkey-1) { 01832 if((key-1)->flag&PEK_SELECT) 01833 key->flag |= PEK_TAG; 01834 } 01835 else { 01836 if(((key-1)->flag | (key+1)->flag) & PEK_SELECT) 01837 key->flag |= PEK_TAG; 01838 } 01839 } 01840 01841 LOOP_KEYS { 01842 if(key->flag&PEK_TAG) { 01843 key->flag &= ~PEK_TAG; 01844 key->flag |= PEK_SELECT; 01845 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */ 01846 } 01847 } 01848 } 01849 01850 static int select_more_exec(bContext *C, wmOperator *UNUSED(op)) 01851 { 01852 PEData data; 01853 01854 PE_set_data(C, &data); 01855 foreach_point(&data, select_more_keys); 01856 01857 PE_update_selection(data.scene, data.ob, 1); 01858 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); 01859 01860 return OPERATOR_FINISHED; 01861 } 01862 01863 void PARTICLE_OT_select_more(wmOperatorType *ot) 01864 { 01865 /* identifiers */ 01866 ot->name= "Select More"; 01867 ot->idname= "PARTICLE_OT_select_more"; 01868 01869 /* api callbacks */ 01870 ot->exec= select_more_exec; 01871 ot->poll= PE_poll; 01872 01873 /* flags */ 01874 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01875 } 01876 01877 static int select_inverse_exec(bContext *C, wmOperator *UNUSED(op)) 01878 { 01879 PEData data; 01880 PTCacheEdit *edit; 01881 POINT_P; KEY_K; 01882 01883 PE_set_data(C, &data); 01884 01885 edit= PE_get_current(data.scene, data.ob); 01886 01887 LOOP_VISIBLE_POINTS { 01888 LOOP_KEYS { 01889 key->flag ^= PEK_SELECT; 01890 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */ 01891 } 01892 } 01893 01894 PE_update_selection(data.scene, data.ob, 1); 01895 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); 01896 01897 return OPERATOR_FINISHED; 01898 } 01899 01900 void PARTICLE_OT_select_inverse(wmOperatorType *ot) 01901 { 01902 /* identifiers */ 01903 ot->name= "Select Inverse"; 01904 ot->idname= "PARTICLE_OT_select_inverse"; 01905 01906 /* api callbacks */ 01907 ot->exec= select_inverse_exec; 01908 ot->poll= PE_poll; 01909 01910 /* flags */ 01911 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01912 } 01913 01914 /************************ rekey operator ************************/ 01915 01916 static void rekey_particle(PEData *data, int pa_index) 01917 { 01918 PTCacheEdit *edit= data->edit; 01919 ParticleSystem *psys= edit->psys; 01920 ParticleSimulationData sim= {0}; 01921 ParticleData *pa= psys->particles + pa_index; 01922 PTCacheEditPoint *point = edit->points + pa_index; 01923 ParticleKey state; 01924 HairKey *key, *new_keys, *okey; 01925 PTCacheEditKey *ekey; 01926 float dval, sta, end; 01927 int k; 01928 01929 sim.scene= data->scene; 01930 sim.ob= data->ob; 01931 sim.psys= edit->psys; 01932 01933 pa->flag |= PARS_REKEY; 01934 01935 key= new_keys= MEM_callocN(data->totrekey * sizeof(HairKey),"Hair re-key keys"); 01936 01937 okey = pa->hair; 01938 /* root and tip stay the same */ 01939 VECCOPY(key->co, okey->co); 01940 VECCOPY((key + data->totrekey - 1)->co, (okey + pa->totkey - 1)->co); 01941 01942 sta= key->time= okey->time; 01943 end= (key + data->totrekey - 1)->time= (okey + pa->totkey - 1)->time; 01944 dval= (end - sta) / (float)(data->totrekey - 1); 01945 01946 /* interpolate new keys from old ones */ 01947 for(k=1,key++; k<data->totrekey-1; k++,key++) { 01948 state.time= (float)k / (float)(data->totrekey-1); 01949 psys_get_particle_on_path(&sim, pa_index, &state, 0); 01950 VECCOPY(key->co, state.co); 01951 key->time= sta + k * dval; 01952 } 01953 01954 /* replace keys */ 01955 if(pa->hair) 01956 MEM_freeN(pa->hair); 01957 pa->hair= new_keys; 01958 01959 point->totkey=pa->totkey=data->totrekey; 01960 01961 01962 if(point->keys) 01963 MEM_freeN(point->keys); 01964 ekey= point->keys= MEM_callocN(pa->totkey * sizeof(PTCacheEditKey),"Hair re-key edit keys"); 01965 01966 for(k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) { 01967 ekey->co= key->co; 01968 ekey->time= &key->time; 01969 ekey->flag |= PEK_SELECT; 01970 if(!(psys->flag & PSYS_GLOBAL_HAIR)) 01971 ekey->flag |= PEK_USE_WCO; 01972 } 01973 01974 pa->flag &= ~PARS_REKEY; 01975 point->flag |= PEP_EDIT_RECALC; 01976 } 01977 01978 static int rekey_exec(bContext *C, wmOperator *op) 01979 { 01980 PEData data; 01981 01982 PE_set_data(C, &data); 01983 01984 data.dval= 1.0f / (float)(data.totrekey-1); 01985 data.totrekey= RNA_int_get(op->ptr, "keys"); 01986 01987 foreach_selected_point(&data, rekey_particle); 01988 01989 recalc_lengths(data.edit); 01990 PE_update_object(data.scene, data.ob, 1); 01991 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob); 01992 01993 return OPERATOR_FINISHED; 01994 } 01995 01996 void PARTICLE_OT_rekey(wmOperatorType *ot) 01997 { 01998 /* identifiers */ 01999 ot->name= "Rekey"; 02000 ot->idname= "PARTICLE_OT_rekey"; 02001 02002 /* api callbacks */ 02003 ot->exec= rekey_exec; 02004 ot->invoke= WM_operator_props_popup; 02005 ot->poll= PE_poll; 02006 02007 /* flags */ 02008 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02009 02010 /* properties */ 02011 RNA_def_int(ot->srna, "keys", 2, 2, INT_MAX, "Number of Keys", "", 2, 100); 02012 } 02013 02014 static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float path_time) 02015 { 02016 PTCacheEdit *edit= PE_get_current(scene, ob); 02017 ParticleSystem *psys; 02018 ParticleSimulationData sim= {0}; 02019 ParticleData *pa; 02020 ParticleKey state; 02021 HairKey *new_keys, *key; 02022 PTCacheEditKey *ekey; 02023 int k; 02024 02025 if(!edit || !edit->psys) return; 02026 02027 psys = edit->psys; 02028 02029 sim.scene= scene; 02030 sim.ob= ob; 02031 sim.psys= psys; 02032 02033 pa= psys->particles + pa_index; 02034 02035 pa->flag |= PARS_REKEY; 02036 02037 key= new_keys= MEM_dupallocN(pa->hair); 02038 02039 /* interpolate new keys from old ones (roots stay the same) */ 02040 for(k=1, key++; k < pa->totkey; k++, key++) { 02041 state.time= path_time * (float)k / (float)(pa->totkey-1); 02042 psys_get_particle_on_path(&sim, pa_index, &state, 0); 02043 VECCOPY(key->co, state.co); 02044 } 02045 02046 /* replace hair keys */ 02047 if(pa->hair) 02048 MEM_freeN(pa->hair); 02049 pa->hair= new_keys; 02050 02051 /* update edit pointers */ 02052 for(k=0, key=pa->hair, ekey=edit->points[pa_index].keys; k<pa->totkey; k++, key++, ekey++) { 02053 ekey->co= key->co; 02054 ekey->time= &key->time; 02055 } 02056 02057 pa->flag &= ~PARS_REKEY; 02058 } 02059 02060 /************************* utilities **************************/ 02061 02062 static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror) 02063 { 02064 PTCacheEdit *edit = psys->edit; 02065 ParticleData *pa, *npa=0, *new_pars=0; 02066 POINT_P; 02067 PTCacheEditPoint *npoint=0, *new_points=0; 02068 ParticleSystemModifierData *psmd; 02069 int i, new_totpart= psys->totpart, removed= 0; 02070 02071 if(mirror) { 02072 /* mirror tags */ 02073 psmd= psys_get_modifier(ob, psys); 02074 02075 LOOP_TAGGED_POINTS { 02076 PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL); 02077 } 02078 } 02079 02080 LOOP_TAGGED_POINTS { 02081 new_totpart--; 02082 removed++; 02083 } 02084 02085 if(new_totpart != psys->totpart) { 02086 if(new_totpart) { 02087 npa= new_pars= MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array"); 02088 npoint= new_points= MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array"); 02089 02090 if(ELEM(NULL, new_pars, new_points)) { 02091 /* allocation error! */ 02092 if(new_pars) 02093 MEM_freeN(new_pars); 02094 if(new_points) 02095 MEM_freeN(new_points); 02096 return 0; 02097 } 02098 } 02099 02100 pa= psys->particles; 02101 point= edit->points; 02102 for(i=0; i<psys->totpart; i++, pa++, point++) { 02103 if(point->flag & PEP_TAG) { 02104 if(point->keys) 02105 MEM_freeN(point->keys); 02106 if(pa->hair) 02107 MEM_freeN(pa->hair); 02108 } 02109 else { 02110 memcpy(npa, pa, sizeof(ParticleData)); 02111 memcpy(npoint, point, sizeof(PTCacheEditPoint)); 02112 npa++; 02113 npoint++; 02114 } 02115 } 02116 02117 if(psys->particles) MEM_freeN(psys->particles); 02118 psys->particles= new_pars; 02119 02120 if(edit->points) MEM_freeN(edit->points); 02121 edit->points= new_points; 02122 02123 if(edit->mirror_cache) { 02124 MEM_freeN(edit->mirror_cache); 02125 edit->mirror_cache= NULL; 02126 } 02127 02128 if(psys->child) { 02129 MEM_freeN(psys->child); 02130 psys->child= NULL; 02131 psys->totchild=0; 02132 } 02133 02134 edit->totpoint= psys->totpart= new_totpart; 02135 } 02136 02137 return removed; 02138 } 02139 02140 static void remove_tagged_keys(Object *ob, ParticleSystem *psys) 02141 { 02142 PTCacheEdit *edit= psys->edit; 02143 ParticleData *pa; 02144 HairKey *hkey, *nhkey, *new_hkeys=0; 02145 POINT_P; KEY_K; 02146 PTCacheEditKey *nkey, *new_keys; 02147 ParticleSystemModifierData *psmd; 02148 short new_totkey; 02149 02150 if(pe_x_mirror(ob)) { 02151 /* mirror key tags */ 02152 psmd= psys_get_modifier(ob, psys); 02153 02154 LOOP_POINTS { 02155 LOOP_TAGGED_KEYS { 02156 PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL); 02157 break; 02158 } 02159 } 02160 } 02161 02162 LOOP_POINTS { 02163 new_totkey= point->totkey; 02164 LOOP_TAGGED_KEYS { 02165 new_totkey--; 02166 } 02167 /* we can't have elements with less than two keys*/ 02168 if(new_totkey < 2) 02169 point->flag |= PEP_TAG; 02170 } 02171 remove_tagged_particles(ob, psys, pe_x_mirror(ob)); 02172 02173 LOOP_POINTS { 02174 pa = psys->particles + p; 02175 new_totkey= pa->totkey; 02176 02177 LOOP_TAGGED_KEYS { 02178 new_totkey--; 02179 } 02180 02181 if(new_totkey != pa->totkey) { 02182 nhkey= new_hkeys= MEM_callocN(new_totkey*sizeof(HairKey), "HairKeys"); 02183 nkey= new_keys= MEM_callocN(new_totkey*sizeof(PTCacheEditKey), "particle edit keys"); 02184 02185 hkey= pa->hair; 02186 LOOP_KEYS { 02187 while(key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) { 02188 key++; 02189 hkey++; 02190 } 02191 02192 if(hkey < pa->hair + pa->totkey) { 02193 VECCOPY(nhkey->co, hkey->co); 02194 nhkey->editflag = hkey->editflag; 02195 nhkey->time= hkey->time; 02196 nhkey->weight= hkey->weight; 02197 02198 nkey->co= nhkey->co; 02199 nkey->time= &nhkey->time; 02200 /* these can be copied from old edit keys */ 02201 nkey->flag = key->flag; 02202 nkey->ftime = key->ftime; 02203 nkey->length = key->length; 02204 VECCOPY(nkey->world_co, key->world_co); 02205 } 02206 nkey++; 02207 nhkey++; 02208 hkey++; 02209 } 02210 02211 if(pa->hair) 02212 MEM_freeN(pa->hair); 02213 02214 if(point->keys) 02215 MEM_freeN(point->keys); 02216 02217 pa->hair= new_hkeys; 02218 point->keys= new_keys; 02219 02220 point->totkey= pa->totkey= new_totkey; 02221 02222 /* flag for recalculating length */ 02223 point->flag |= PEP_EDIT_RECALC; 02224 } 02225 } 02226 } 02227 02228 /************************ subdivide opertor *********************/ 02229 02230 /* works like normal edit mode subdivide, inserts keys between neighbouring selected keys */ 02231 static void subdivide_particle(PEData *data, int pa_index) 02232 { 02233 PTCacheEdit *edit= data->edit; 02234 ParticleSystem *psys= edit->psys; 02235 ParticleSimulationData sim= {0}; 02236 ParticleData *pa= psys->particles + pa_index; 02237 PTCacheEditPoint *point = edit->points + pa_index; 02238 ParticleKey state; 02239 HairKey *key, *nkey, *new_keys; 02240 PTCacheEditKey *ekey, *nekey, *new_ekeys; 02241 02242 int k; 02243 short totnewkey=0; 02244 float endtime; 02245 02246 sim.scene= data->scene; 02247 sim.ob= data->ob; 02248 sim.psys= edit->psys; 02249 02250 for(k=0, ekey=point->keys; k<pa->totkey-1; k++,ekey++) { 02251 if(ekey->flag&PEK_SELECT && (ekey+1)->flag&PEK_SELECT) 02252 totnewkey++; 02253 } 02254 02255 if(totnewkey==0) return; 02256 02257 pa->flag |= PARS_REKEY; 02258 02259 nkey= new_keys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(HairKey)),"Hair subdivide keys"); 02260 nekey= new_ekeys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(PTCacheEditKey)),"Hair subdivide edit keys"); 02261 02262 key = pa->hair; 02263 endtime= key[pa->totkey-1].time; 02264 02265 for(k=0, ekey=point->keys; k<pa->totkey-1; k++, key++, ekey++) { 02266 02267 memcpy(nkey,key,sizeof(HairKey)); 02268 memcpy(nekey,ekey,sizeof(PTCacheEditKey)); 02269 02270 nekey->co= nkey->co; 02271 nekey->time= &nkey->time; 02272 02273 nkey++; 02274 nekey++; 02275 02276 if(ekey->flag & PEK_SELECT && (ekey+1)->flag & PEK_SELECT) { 02277 nkey->time= (key->time + (key+1)->time)*0.5f; 02278 state.time= (endtime != 0.0f)? nkey->time/endtime: 0.0f; 02279 psys_get_particle_on_path(&sim, pa_index, &state, 0); 02280 VECCOPY(nkey->co, state.co); 02281 02282 nekey->co= nkey->co; 02283 nekey->time= &nkey->time; 02284 nekey->flag |= PEK_SELECT; 02285 if(!(psys->flag & PSYS_GLOBAL_HAIR)) 02286 nekey->flag |= PEK_USE_WCO; 02287 02288 nekey++; 02289 nkey++; 02290 } 02291 } 02292 /*tip still not copied*/ 02293 memcpy(nkey,key,sizeof(HairKey)); 02294 memcpy(nekey,ekey,sizeof(PTCacheEditKey)); 02295 02296 nekey->co= nkey->co; 02297 nekey->time= &nkey->time; 02298 02299 if(pa->hair) 02300 MEM_freeN(pa->hair); 02301 pa->hair= new_keys; 02302 02303 if(point->keys) 02304 MEM_freeN(point->keys); 02305 point->keys= new_ekeys; 02306 02307 point->totkey = pa->totkey = pa->totkey + totnewkey; 02308 point->flag |= PEP_EDIT_RECALC; 02309 pa->flag &= ~PARS_REKEY; 02310 } 02311 02312 static int subdivide_exec(bContext *C, wmOperator *UNUSED(op)) 02313 { 02314 PEData data; 02315 02316 PE_set_data(C, &data); 02317 foreach_point(&data, subdivide_particle); 02318 02319 recalc_lengths(data.edit); 02320 PE_update_object(data.scene, data.ob, 1); 02321 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob); 02322 02323 return OPERATOR_FINISHED; 02324 } 02325 02326 void PARTICLE_OT_subdivide(wmOperatorType *ot) 02327 { 02328 /* identifiers */ 02329 ot->name= "Subdivide"; 02330 ot->idname= "PARTICLE_OT_subdivide"; 02331 02332 /* api callbacks */ 02333 ot->exec= subdivide_exec; 02334 ot->poll= PE_poll; 02335 02336 /* flags */ 02337 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02338 } 02339 02340 /************************ remove doubles opertor *********************/ 02341 02342 static int remove_doubles_exec(bContext *C, wmOperator *op) 02343 { 02344 Scene *scene= CTX_data_scene(C); 02345 Object *ob= CTX_data_active_object(C); 02346 PTCacheEdit *edit= PE_get_current(scene, ob); 02347 ParticleSystem *psys = edit->psys; 02348 ParticleSystemModifierData *psmd; 02349 KDTree *tree; 02350 KDTreeNearest nearest[10]; 02351 POINT_P; 02352 float mat[4][4], co[3], threshold= RNA_float_get(op->ptr, "threshold"); 02353 int n, totn, removed, totremoved; 02354 02355 if(psys->flag & PSYS_GLOBAL_HAIR) 02356 return OPERATOR_CANCELLED; 02357 02358 edit= psys->edit; 02359 psmd= psys_get_modifier(ob, psys); 02360 totremoved= 0; 02361 02362 do { 02363 removed= 0; 02364 02365 tree=BLI_kdtree_new(psys->totpart); 02366 02367 /* insert particles into kd tree */ 02368 LOOP_SELECTED_POINTS { 02369 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat); 02370 VECCOPY(co, point->keys->co); 02371 mul_m4_v3(mat, co); 02372 BLI_kdtree_insert(tree, p, co, NULL); 02373 } 02374 02375 BLI_kdtree_balance(tree); 02376 02377 /* tag particles to be removed */ 02378 LOOP_SELECTED_POINTS { 02379 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat); 02380 VECCOPY(co, point->keys->co); 02381 mul_m4_v3(mat, co); 02382 02383 totn= BLI_kdtree_find_n_nearest(tree,10,co,NULL,nearest); 02384 02385 for(n=0; n<totn; n++) { 02386 /* this needs a custom threshold still */ 02387 if(nearest[n].index > p && nearest[n].dist < threshold) { 02388 if(!(point->flag & PEP_TAG)) { 02389 point->flag |= PEP_TAG; 02390 removed++; 02391 } 02392 } 02393 } 02394 } 02395 02396 BLI_kdtree_free(tree); 02397 02398 /* remove tagged particles - don't do mirror here! */ 02399 remove_tagged_particles(ob, psys, 0); 02400 totremoved += removed; 02401 } while(removed); 02402 02403 if(totremoved == 0) 02404 return OPERATOR_CANCELLED; 02405 02406 BKE_reportf(op->reports, RPT_INFO, "Remove %d double particles.", totremoved); 02407 02408 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02409 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); 02410 02411 return OPERATOR_FINISHED; 02412 } 02413 02414 void PARTICLE_OT_remove_doubles(wmOperatorType *ot) 02415 { 02416 /* identifiers */ 02417 ot->name= "Remove Doubles"; 02418 ot->idname= "PARTICLE_OT_remove_doubles"; 02419 02420 /* api callbacks */ 02421 ot->exec= remove_doubles_exec; 02422 ot->poll= PE_poll; 02423 02424 /* flags */ 02425 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02426 02427 /* properties */ 02428 RNA_def_float(ot->srna, "threshold", 0.0002f, 0.0f, FLT_MAX, "Threshold", "Threshold distance withing which particles are removed", 0.00001f, 0.1f); 02429 } 02430 02431 02432 static int weight_set_exec(bContext *C, wmOperator *op) 02433 { 02434 Scene *scene= CTX_data_scene(C); 02435 ParticleEditSettings *pset= PE_settings(scene); 02436 Object *ob= CTX_data_active_object(C); 02437 PTCacheEdit *edit= PE_get_current(scene, ob); 02438 ParticleSystem *psys = edit->psys; 02439 POINT_P; 02440 KEY_K; 02441 HairKey *hkey; 02442 float weight; 02443 ParticleBrushData *brush= &pset->brush[pset->brushtype]; 02444 float factor= RNA_float_get(op->ptr, "factor"); 02445 02446 weight= brush->strength; 02447 edit= psys->edit; 02448 02449 LOOP_SELECTED_POINTS { 02450 ParticleData *pa= psys->particles + p; 02451 02452 LOOP_SELECTED_KEYS { 02453 hkey= pa->hair + k; 02454 hkey->weight= interpf(weight, hkey->weight, factor); 02455 } 02456 } 02457 02458 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02459 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); 02460 02461 return OPERATOR_FINISHED; 02462 } 02463 02464 void PARTICLE_OT_weight_set(wmOperatorType *ot) 02465 { 02466 /* identifiers */ 02467 ot->name= "Weight Set"; 02468 ot->idname= "PARTICLE_OT_weight_set"; 02469 02470 /* api callbacks */ 02471 ot->exec= weight_set_exec; 02472 ot->poll= PE_poll; 02473 02474 /* flags */ 02475 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02476 02477 RNA_def_float(ot->srna, "factor", 1, 0, 1, "Factor", "", 0, 1); 02478 } 02479 02480 /************************ cursor drawing *******************************/ 02481 02482 static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)) 02483 { 02484 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C)); 02485 ParticleBrushData *brush; 02486 02487 if(pset->brushtype < 0) 02488 return; 02489 02490 brush= &pset->brush[pset->brushtype]; 02491 02492 if(brush) { 02493 glPushMatrix(); 02494 02495 glTranslatef((float)x, (float)y, 0.0f); 02496 02497 glColor4ub(255, 255, 255, 128); 02498 glEnable(GL_LINE_SMOOTH ); 02499 glEnable(GL_BLEND); 02500 glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size, 40); 02501 glDisable(GL_BLEND); 02502 glDisable(GL_LINE_SMOOTH ); 02503 02504 glPopMatrix(); 02505 } 02506 } 02507 02508 static void toggle_particle_cursor(bContext *C, int enable) 02509 { 02510 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C)); 02511 02512 if(pset->paintcursor && !enable) { 02513 WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor); 02514 pset->paintcursor = NULL; 02515 } 02516 else if(enable) 02517 pset->paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), PE_poll_view3d, brush_drawcursor, NULL); 02518 } 02519 02520 /*************************** delete operator **************************/ 02521 02522 enum { DEL_PARTICLE, DEL_KEY }; 02523 02524 static EnumPropertyItem delete_type_items[]= { 02525 {DEL_PARTICLE, "PARTICLE", 0, "Particle", ""}, 02526 {DEL_KEY, "KEY", 0, "Key", ""}, 02527 {0, NULL, 0, NULL, NULL}}; 02528 02529 static void set_delete_particle(PEData *data, int pa_index) 02530 { 02531 PTCacheEdit *edit= data->edit; 02532 02533 edit->points[pa_index].flag |= PEP_TAG; 02534 } 02535 02536 static void set_delete_particle_key(PEData *data, int pa_index, int key_index) 02537 { 02538 PTCacheEdit *edit= data->edit; 02539 02540 edit->points[pa_index].keys[key_index].flag |= PEK_TAG; 02541 } 02542 02543 static int delete_exec(bContext *C, wmOperator *op) 02544 { 02545 PEData data; 02546 int type= RNA_enum_get(op->ptr, "type"); 02547 02548 PE_set_data(C, &data); 02549 02550 if(type == DEL_KEY) { 02551 foreach_selected_key(&data, set_delete_particle_key); 02552 remove_tagged_keys(data.ob, data.edit->psys); 02553 recalc_lengths(data.edit); 02554 } 02555 else if(type == DEL_PARTICLE) { 02556 foreach_selected_point(&data, set_delete_particle); 02557 remove_tagged_particles(data.ob, data.edit->psys, pe_x_mirror(data.ob)); 02558 recalc_lengths(data.edit); 02559 } 02560 02561 DAG_id_tag_update(&data.ob->id, OB_RECALC_DATA); 02562 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob); 02563 02564 return OPERATOR_FINISHED; 02565 } 02566 02567 void PARTICLE_OT_delete(wmOperatorType *ot) 02568 { 02569 /* identifiers */ 02570 ot->name= "Delete"; 02571 ot->idname= "PARTICLE_OT_delete"; 02572 02573 /* api callbacks */ 02574 ot->exec= delete_exec; 02575 ot->invoke= WM_menu_invoke; 02576 ot->poll= PE_hair_poll; 02577 02578 /* flags */ 02579 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02580 02581 /* properties */ 02582 ot->prop= RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PARTICLE, "Type", "Delete a full particle or only keys."); 02583 } 02584 02585 /*************************** mirror operator **************************/ 02586 02587 static void PE_mirror_x(Scene *scene, Object *ob, int tagged) 02588 { 02589 Mesh *me= (Mesh*)(ob->data); 02590 ParticleSystemModifierData *psmd; 02591 PTCacheEdit *edit= PE_get_current(scene, ob); 02592 ParticleSystem *psys = edit->psys; 02593 ParticleData *pa, *newpa, *new_pars; 02594 PTCacheEditPoint *newpoint, *new_points; 02595 POINT_P; KEY_K; 02596 HairKey *hkey; 02597 int *mirrorfaces; 02598 int rotation, totpart, newtotpart; 02599 02600 if(psys->flag & PSYS_GLOBAL_HAIR) 02601 return; 02602 02603 psmd= psys_get_modifier(ob, psys); 02604 if(!psmd->dm) 02605 return; 02606 02607 mirrorfaces= mesh_get_x_mirror_faces(ob, NULL); 02608 02609 if(!edit->mirror_cache) 02610 PE_update_mirror_cache(ob, psys); 02611 02612 totpart= psys->totpart; 02613 newtotpart= psys->totpart; 02614 LOOP_VISIBLE_POINTS { 02615 pa = psys->particles + p; 02616 if(!tagged) { 02617 if(point_is_selected(point)) { 02618 if(edit->mirror_cache[p] != -1) { 02619 /* already has a mirror, don't need to duplicate */ 02620 PE_mirror_particle(ob, psmd->dm, psys, pa, NULL); 02621 continue; 02622 } 02623 else 02624 point->flag |= PEP_TAG; 02625 } 02626 } 02627 02628 if((point->flag & PEP_TAG) && mirrorfaces[pa->num*2] != -1) 02629 newtotpart++; 02630 } 02631 02632 if(newtotpart != psys->totpart) { 02633 /* allocate new arrays and copy existing */ 02634 new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new"); 02635 new_points= MEM_callocN(newtotpart*sizeof(PTCacheEditPoint), "PTCacheEditPoint new"); 02636 02637 if(psys->particles) { 02638 memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData)); 02639 MEM_freeN(psys->particles); 02640 } 02641 psys->particles= new_pars; 02642 02643 if(edit->points) { 02644 memcpy(new_points, edit->points, totpart*sizeof(PTCacheEditPoint)); 02645 MEM_freeN(edit->points); 02646 } 02647 edit->points= new_points; 02648 02649 if(edit->mirror_cache) { 02650 MEM_freeN(edit->mirror_cache); 02651 edit->mirror_cache= NULL; 02652 } 02653 02654 edit->totpoint= psys->totpart= newtotpart; 02655 02656 /* create new elements */ 02657 newpa= psys->particles + totpart; 02658 newpoint= edit->points + totpart; 02659 02660 for(p=0, point=edit->points; p<totpart; p++, point++) { 02661 pa = psys->particles + p; 02662 02663 if(point->flag & PEP_HIDE) 02664 continue; 02665 if(!(point->flag & PEP_TAG) || mirrorfaces[pa->num*2] == -1) 02666 continue; 02667 02668 /* duplicate */ 02669 *newpa= *pa; 02670 *newpoint= *point; 02671 if(pa->hair) newpa->hair= MEM_dupallocN(pa->hair); 02672 if(point->keys) newpoint->keys= MEM_dupallocN(point->keys); 02673 02674 /* rotate weights according to vertex index rotation */ 02675 rotation= mirrorfaces[pa->num*2+1]; 02676 newpa->fuv[0]= pa->fuv[2]; 02677 newpa->fuv[1]= pa->fuv[1]; 02678 newpa->fuv[2]= pa->fuv[0]; 02679 newpa->fuv[3]= pa->fuv[3]; 02680 while(rotation-- > 0) 02681 if(me->mface[pa->num].v4) 02682 SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3]) 02683 else 02684 SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2]) 02685 02686 /* assign face inddex */ 02687 newpa->num= mirrorfaces[pa->num*2]; 02688 newpa->num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,newpa->num,newpa->fuv, NULL); 02689 02690 /* update edit key pointers */ 02691 key= newpoint->keys; 02692 for(k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, key++) { 02693 key->co= hkey->co; 02694 key->time= &hkey->time; 02695 } 02696 02697 /* map key positions as mirror over x axis */ 02698 PE_mirror_particle(ob, psmd->dm, psys, pa, newpa); 02699 02700 newpa++; 02701 newpoint++; 02702 } 02703 } 02704 02705 LOOP_POINTS { 02706 point->flag &= ~PEP_TAG; 02707 } 02708 02709 MEM_freeN(mirrorfaces); 02710 } 02711 02712 static int mirror_exec(bContext *C, wmOperator *UNUSED(op)) 02713 { 02714 Scene *scene= CTX_data_scene(C); 02715 Object *ob= CTX_data_active_object(C); 02716 PTCacheEdit *edit= PE_get_current(scene, ob); 02717 02718 PE_mirror_x(scene, ob, 0); 02719 02720 update_world_cos(ob, edit); 02721 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); 02722 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02723 02724 return OPERATOR_FINISHED; 02725 } 02726 02727 void PARTICLE_OT_mirror(wmOperatorType *ot) 02728 { 02729 /* identifiers */ 02730 ot->name= "Mirror"; 02731 ot->idname= "PARTICLE_OT_mirror"; 02732 02733 /* api callbacks */ 02734 ot->exec= mirror_exec; 02735 ot->poll= PE_poll; 02736 02737 /* flags */ 02738 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02739 } 02740 02741 /************************* brush edit callbacks ********************/ 02742 02743 static void brush_comb(PEData *data, float UNUSED(mat[][4]), float imat[][4], int point_index, int key_index, PTCacheEditKey *key) 02744 { 02745 ParticleEditSettings *pset= PE_settings(data->scene); 02746 float cvec[3], fac; 02747 02748 if(pset->flag & PE_LOCK_FIRST && key_index == 0) return; 02749 02750 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->combfac); 02751 02752 VECCOPY(cvec,data->dvec); 02753 mul_mat3_m4_v3(imat,cvec); 02754 mul_v3_fl(cvec, fac); 02755 VECADD(key->co, key->co, cvec); 02756 02757 (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC; 02758 } 02759 02760 static void brush_cut(PEData *data, int pa_index) 02761 { 02762 PTCacheEdit *edit = data->edit; 02763 ARegion *ar= data->vc.ar; 02764 Object *ob= data->ob; 02765 ParticleEditSettings *pset= PE_settings(data->scene); 02766 ParticleCacheKey *key= edit->pathcache[pa_index]; 02767 float rad2, cut_time= 1.0; 02768 float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv; 02769 int k, cut, keys= (int)pow(2.0, (double)pset->draw_step); 02770 int vertco[2]; 02771 02772 /* blunt scissors */ 02773 if(BLI_frand() > data->cutfac) return; 02774 02775 /* don't cut hidden */ 02776 if(edit->points[pa_index].flag & PEP_HIDE) 02777 return; 02778 02779 rad2= data->rad * data->rad; 02780 02781 cut=0; 02782 02783 project_int_noclip(ar, key->co, vertco); 02784 x0= (float)vertco[0]; 02785 x1= (float)vertco[1]; 02786 02787 o0= (float)data->mval[0]; 02788 o1= (float)data->mval[1]; 02789 02790 xo0= x0 - o0; 02791 xo1= x1 - o1; 02792 02793 /* check if root is inside circle */ 02794 if(xo0*xo0 + xo1*xo1 < rad2 && key_test_depth(data, key->co)) { 02795 cut_time= -1.0f; 02796 cut= 1; 02797 } 02798 else { 02799 /* calculate path time closest to root that was inside the circle */ 02800 for(k=1, key++; k<=keys; k++, key++) { 02801 project_int_noclip(ar, key->co, vertco); 02802 02803 if(key_test_depth(data, key->co) == 0) { 02804 x0= (float)vertco[0]; 02805 x1= (float)vertco[1]; 02806 02807 xo0= x0 - o0; 02808 xo1= x1 - o1; 02809 continue; 02810 } 02811 02812 v0= (float)vertco[0] - x0; 02813 v1= (float)vertco[1] - x1; 02814 02815 dv= v0*v0 + v1*v1; 02816 02817 d= (v0*xo1 - v1*xo0); 02818 02819 d= dv * rad2 - d*d; 02820 02821 if(d > 0.0f) { 02822 d= sqrt(d); 02823 02824 cut_time= -(v0*xo0 + v1*xo1 + d); 02825 02826 if(cut_time > 0.0f) { 02827 cut_time /= dv; 02828 02829 if(cut_time < 1.0f) { 02830 cut_time += (float)(k-1); 02831 cut_time /= (float)keys; 02832 cut= 1; 02833 break; 02834 } 02835 } 02836 } 02837 02838 x0= (float)vertco[0]; 02839 x1= (float)vertco[1]; 02840 02841 xo0= x0 - o0; 02842 xo1= x1 - o1; 02843 } 02844 } 02845 02846 if(cut) { 02847 if(cut_time < 0.0f) { 02848 edit->points[pa_index].flag |= PEP_TAG; 02849 } 02850 else { 02851 rekey_particle_to_time(data->scene, ob, pa_index, cut_time); 02852 edit->points[pa_index].flag |= PEP_EDIT_RECALC; 02853 } 02854 } 02855 } 02856 02857 static void brush_length(PEData *data, int point_index) 02858 { 02859 PTCacheEdit *edit= data->edit; 02860 PTCacheEditPoint *point = edit->points + point_index; 02861 KEY_K; 02862 float dvec[3],pvec[3] = {0.0f, 0.0f, 0.0f}; 02863 02864 LOOP_KEYS { 02865 if(k==0) { 02866 VECCOPY(pvec,key->co); 02867 } 02868 else { 02869 VECSUB(dvec,key->co,pvec); 02870 VECCOPY(pvec,key->co); 02871 mul_v3_fl(dvec,data->growfac); 02872 VECADD(key->co,(key-1)->co,dvec); 02873 } 02874 } 02875 02876 point->flag |= PEP_EDIT_RECALC; 02877 } 02878 02879 static void brush_puff(PEData *data, int point_index) 02880 { 02881 PTCacheEdit *edit = data->edit; 02882 ParticleSystem *psys = edit->psys; 02883 PTCacheEditPoint *point = edit->points + point_index; 02884 KEY_K; 02885 float mat[4][4], imat[4][4]; 02886 02887 float lastco[3], rootco[3] = {0.0f, 0.0f, 0.0f}, co[3], nor[3], kco[3], dco[3], ofs[3] = {0.0f, 0.0f, 0.0f}, fac=0.0f, length=0.0f; 02888 int puff_volume = 0; 02889 int change= 0; 02890 02891 { 02892 ParticleEditSettings *pset= PE_settings(data->scene); 02893 ParticleBrushData *brush= &pset->brush[pset->brushtype]; 02894 puff_volume = brush->flag & PE_BRUSH_DATA_PUFF_VOLUME; 02895 } 02896 02897 if(psys && !(psys->flag & PSYS_GLOBAL_HAIR)) { 02898 psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, psys->particles + point_index, mat); 02899 invert_m4_m4(imat,mat); 02900 } 02901 else { 02902 unit_m4(mat); 02903 unit_m4(imat); 02904 } 02905 02906 LOOP_KEYS { 02907 if(k==0) { 02908 /* find root coordinate and normal on emitter */ 02909 VECCOPY(co, key->co); 02910 mul_m4_v3(mat, co); 02911 mul_v3_m4v3(kco, data->ob->imat, co); /* use 'kco' as the object space version of worldspace 'co', ob->imat is set before calling */ 02912 02913 point_index= BLI_kdtree_find_nearest(edit->emitter_field, kco, NULL, NULL); 02914 if(point_index == -1) return; 02915 02916 VECCOPY(rootco, co); 02917 copy_v3_v3(nor, &edit->emitter_cosnos[point_index*6+3]); 02918 mul_mat3_m4_v3(data->ob->obmat, nor); /* normal into worldspace */ 02919 02920 normalize_v3(nor); 02921 length= 0.0f; 02922 02923 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->pufffac); 02924 fac *= 0.025f; 02925 if(data->invert) 02926 fac= -fac; 02927 } 02928 else { 02929 /* compute position as if hair was standing up straight. 02930 * */ 02931 VECCOPY(lastco, co); 02932 VECCOPY(co, key->co); 02933 mul_m4_v3(mat, co); 02934 length += len_v3v3(lastco, co); 02935 if((data->select==0 || (key->flag & PEK_SELECT)) && !(key->flag & PEK_HIDE)) { 02936 VECADDFAC(kco, rootco, nor, length); 02937 02938 /* blend between the current and straight position */ 02939 VECSUB(dco, kco, co); 02940 VECADDFAC(co, co, dco, fac); 02941 02942 /* re-use dco to compare before and after translation and add to the offset */ 02943 VECCOPY(dco, key->co); 02944 02945 mul_v3_m4v3(key->co, imat, co); 02946 02947 if(puff_volume) { 02948 /* accumulate the total distance moved to apply to unselected 02949 * keys that come after */ 02950 ofs[0] += key->co[0] - dco[0]; 02951 ofs[1] += key->co[1] - dco[1]; 02952 ofs[2] += key->co[2] - dco[2]; 02953 } 02954 change = 1; 02955 } 02956 else { 02957 02958 if(puff_volume) { 02959 #if 0 02960 /* this is simple but looks bad, adds annoying kinks */ 02961 add_v3_v3(key->co, ofs); 02962 #else 02963 /* translate (not rotate) the rest of the hair if its not selected */ 02964 if(ofs[0] || ofs[1] || ofs[2]) { 02965 #if 0 /* kindof works but looks worse then whats below */ 02966 02967 /* Move the unselected point on a vector based on the 02968 * hair direction and the offset */ 02969 float c1[3], c2[3]; 02970 VECSUB(dco, lastco, co); 02971 mul_mat3_m4_v3(imat, dco); /* into particle space */ 02972 02973 /* move the point allong a vector perpendicular to the 02974 * hairs direction, reduces odd kinks, */ 02975 cross_v3_v3v3(c1, ofs, dco); 02976 cross_v3_v3v3(c2, c1, dco); 02977 normalize_v3(c2); 02978 mul_v3_fl(c2, len_v3(ofs)); 02979 add_v3_v3(key->co, c2); 02980 #else 02981 /* Move the unselected point on a vector based on the 02982 * the normal of the closest geometry */ 02983 float oco[3], onor[3]; 02984 VECCOPY(oco, key->co); 02985 mul_m4_v3(mat, oco); 02986 mul_v3_m4v3(kco, data->ob->imat, oco); /* use 'kco' as the object space version of worldspace 'co', ob->imat is set before calling */ 02987 02988 point_index= BLI_kdtree_find_nearest(edit->emitter_field, kco, NULL, NULL); 02989 if(point_index != -1) { 02990 copy_v3_v3(onor, &edit->emitter_cosnos[point_index*6+3]); 02991 mul_mat3_m4_v3(data->ob->obmat, onor); /* normal into worldspace */ 02992 mul_mat3_m4_v3(imat, onor); /* worldspace into particle space */ 02993 normalize_v3(onor); 02994 02995 02996 mul_v3_fl(onor, len_v3(ofs)); 02997 add_v3_v3(key->co, onor); 02998 } 02999 #endif 03000 } 03001 #endif 03002 } 03003 } 03004 } 03005 } 03006 03007 if(change) 03008 point->flag |= PEP_EDIT_RECALC; 03009 } 03010 03011 03012 static void brush_weight(PEData *data, float UNUSED(mat[][4]), float UNUSED(imat[][4]), int point_index, int key_index, PTCacheEditKey *UNUSED(key)) 03013 { 03014 /* roots have full weight allways */ 03015 if(key_index) { 03016 PTCacheEdit *edit = data->edit; 03017 ParticleSystem *psys = edit->psys; 03018 03019 ParticleData *pa= psys->particles + point_index; 03020 pa->hair[key_index].weight = data->weightfac; 03021 03022 (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC; 03023 } 03024 } 03025 03026 static void brush_smooth_get(PEData *data, float mat[][4], float UNUSED(imat[][4]), int UNUSED(point_index), int key_index, PTCacheEditKey *key) 03027 { 03028 if(key_index) { 03029 float dvec[3]; 03030 03031 sub_v3_v3v3(dvec,key->co,(key-1)->co); 03032 mul_mat3_m4_v3(mat,dvec); 03033 VECADD(data->vec,data->vec,dvec); 03034 data->tot++; 03035 } 03036 } 03037 03038 static void brush_smooth_do(PEData *data, float UNUSED(mat[][4]), float imat[][4], int point_index, int key_index, PTCacheEditKey *key) 03039 { 03040 float vec[3], dvec[3]; 03041 03042 if(key_index) { 03043 VECCOPY(vec,data->vec); 03044 mul_mat3_m4_v3(imat,vec); 03045 03046 sub_v3_v3v3(dvec,key->co,(key-1)->co); 03047 03048 VECSUB(dvec,vec,dvec); 03049 mul_v3_fl(dvec,data->smoothfac); 03050 03051 VECADD(key->co,key->co,dvec); 03052 } 03053 03054 (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC; 03055 } 03056 03057 /* convert from triangle barycentric weights to quad mean value weights */ 03058 static void intersect_dm_quad_weights(float *v1, float *v2, float *v3, float *v4, float *w) 03059 { 03060 float co[3], vert[4][3]; 03061 03062 VECCOPY(vert[0], v1); 03063 VECCOPY(vert[1], v2); 03064 VECCOPY(vert[2], v3); 03065 VECCOPY(vert[3], v4); 03066 03067 co[0]= v1[0]*w[0] + v2[0]*w[1] + v3[0]*w[2] + v4[0]*w[3]; 03068 co[1]= v1[1]*w[0] + v2[1]*w[1] + v3[1]*w[2] + v4[1]*w[3]; 03069 co[2]= v1[2]*w[0] + v2[2]*w[1] + v3[2]*w[2] + v4[2]*w[3]; 03070 03071 interp_weights_poly_v3( w,vert, 4, co); 03072 } 03073 03074 /* check intersection with a derivedmesh */ 03075 static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm, float *vert_cos, float *co1, float* co2, float *min_d, int *min_face, float *min_w, 03076 float *face_minmax, float *pa_minmax, float radius, float *ipoint) 03077 { 03078 MFace *mface=0; 03079 MVert *mvert=0; 03080 int i, totface, intersect=0; 03081 float cur_d, cur_uv[2], v1[3], v2[3], v3[3], v4[3], min[3], max[3], p_min[3],p_max[3]; 03082 float cur_ipoint[3]; 03083 03084 if(dm==0){ 03085 psys_disable_all(ob); 03086 03087 dm=mesh_get_derived_final(scene, ob, 0); 03088 if(dm==0) 03089 dm=mesh_get_derived_deform(scene, ob, 0); 03090 03091 psys_enable_all(ob); 03092 03093 if(dm==0) 03094 return 0; 03095 } 03096 03097 03098 03099 if(pa_minmax==0){ 03100 INIT_MINMAX(p_min,p_max); 03101 DO_MINMAX(co1,p_min,p_max); 03102 DO_MINMAX(co2,p_min,p_max); 03103 } 03104 else{ 03105 VECCOPY(p_min,pa_minmax); 03106 VECCOPY(p_max,pa_minmax+3); 03107 } 03108 03109 totface=dm->getNumFaces(dm); 03110 mface=dm->getFaceDataArray(dm,CD_MFACE); 03111 mvert=dm->getVertDataArray(dm,CD_MVERT); 03112 03113 /* lets intersect the faces */ 03114 for(i=0; i<totface; i++,mface++){ 03115 if(vert_cos){ 03116 VECCOPY(v1,vert_cos+3*mface->v1); 03117 VECCOPY(v2,vert_cos+3*mface->v2); 03118 VECCOPY(v3,vert_cos+3*mface->v3); 03119 if(mface->v4) 03120 VECCOPY(v4,vert_cos+3*mface->v4) 03121 } 03122 else{ 03123 VECCOPY(v1,mvert[mface->v1].co); 03124 VECCOPY(v2,mvert[mface->v2].co); 03125 VECCOPY(v3,mvert[mface->v3].co); 03126 if(mface->v4) 03127 VECCOPY(v4,mvert[mface->v4].co) 03128 } 03129 03130 if(face_minmax==0){ 03131 INIT_MINMAX(min,max); 03132 DO_MINMAX(v1,min,max); 03133 DO_MINMAX(v2,min,max); 03134 DO_MINMAX(v3,min,max); 03135 if(mface->v4) 03136 DO_MINMAX(v4,min,max) 03137 if(isect_aabb_aabb_v3(min,max,p_min,p_max)==0) 03138 continue; 03139 } 03140 else{ 03141 VECCOPY(min, face_minmax+6*i); 03142 VECCOPY(max, face_minmax+6*i+3); 03143 if(isect_aabb_aabb_v3(min,max,p_min,p_max)==0) 03144 continue; 03145 } 03146 03147 if(radius>0.0f){ 03148 if(isect_sweeping_sphere_tri_v3(co1, co2, radius, v2, v3, v1, &cur_d, cur_ipoint)){ 03149 if(cur_d<*min_d){ 03150 *min_d=cur_d; 03151 VECCOPY(ipoint,cur_ipoint); 03152 *min_face=i; 03153 intersect=1; 03154 } 03155 } 03156 if(mface->v4){ 03157 if(isect_sweeping_sphere_tri_v3(co1, co2, radius, v4, v1, v3, &cur_d, cur_ipoint)){ 03158 if(cur_d<*min_d){ 03159 *min_d=cur_d; 03160 VECCOPY(ipoint,cur_ipoint); 03161 *min_face=i; 03162 intersect=1; 03163 } 03164 } 03165 } 03166 } 03167 else{ 03168 if(isect_line_tri_v3(co1, co2, v1, v2, v3, &cur_d, cur_uv)){ 03169 if(cur_d<*min_d){ 03170 *min_d=cur_d; 03171 min_w[0]= 1.0f - cur_uv[0] - cur_uv[1]; 03172 min_w[1]= cur_uv[0]; 03173 min_w[2]= cur_uv[1]; 03174 min_w[3]= 0.0f; 03175 if(mface->v4) 03176 intersect_dm_quad_weights(v1, v2, v3, v4, min_w); 03177 *min_face=i; 03178 intersect=1; 03179 } 03180 } 03181 if(mface->v4){ 03182 if(isect_line_tri_v3(co1, co2, v1, v3, v4, &cur_d, cur_uv)){ 03183 if(cur_d<*min_d){ 03184 *min_d=cur_d; 03185 min_w[0]= 1.0f - cur_uv[0] - cur_uv[1]; 03186 min_w[1]= 0.0f; 03187 min_w[2]= cur_uv[0]; 03188 min_w[3]= cur_uv[1]; 03189 intersect_dm_quad_weights(v1, v2, v3, v4, min_w); 03190 *min_face=i; 03191 intersect=1; 03192 } 03193 } 03194 } 03195 } 03196 } 03197 return intersect; 03198 } 03199 03200 static int brush_add(PEData *data, short number) 03201 { 03202 Scene *scene= data->scene; 03203 Object *ob= data->ob; 03204 PTCacheEdit *edit = data->edit; 03205 ParticleSystem *psys= edit->psys; 03206 ParticleData *add_pars= MEM_callocN(number*sizeof(ParticleData),"ParticleData add"); 03207 ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys); 03208 ParticleSimulationData sim= {0}; 03209 ParticleEditSettings *pset= PE_settings(scene); 03210 int i, k, n= 0, totpart= psys->totpart; 03211 float mco[2]; 03212 short dmx= 0, dmy= 0; 03213 float co1[3], co2[3], min_d, imat[4][4]; 03214 float framestep, timestep; 03215 short size= pset->brush[PE_BRUSH_ADD].size; 03216 short size2= size*size; 03217 DerivedMesh *dm=0; 03218 invert_m4_m4(imat,ob->obmat); 03219 03220 if(psys->flag & PSYS_GLOBAL_HAIR) 03221 return 0; 03222 03223 BLI_srandom(psys->seed+data->mval[0]+data->mval[1]); 03224 03225 sim.scene= scene; 03226 sim.ob= ob; 03227 sim.psys= psys; 03228 sim.psmd= psmd; 03229 03230 timestep= psys_get_timestep(&sim); 03231 03232 /* painting onto the deformed mesh, could be an option? */ 03233 if(psmd->dm->deformedOnly) 03234 dm= psmd->dm; 03235 else 03236 dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); 03237 03238 for(i=0; i<number; i++) { 03239 if(number>1) { 03240 dmx=dmy=size; 03241 while(dmx*dmx+dmy*dmy>size2) { 03242 dmx=(short)((2.0f*BLI_frand()-1.0f)*size); 03243 dmy=(short)((2.0f*BLI_frand()-1.0f)*size); 03244 } 03245 } 03246 03247 mco[0]= data->mval[0] + dmx; 03248 mco[1]= data->mval[1] + dmy; 03249 ED_view3d_win_to_segment_clip(data->vc.ar, data->vc.v3d, mco, co1, co2); 03250 03251 mul_m4_v3(imat,co1); 03252 mul_m4_v3(imat,co2); 03253 min_d=2.0; 03254 03255 /* warning, returns the derived mesh face */ 03256 if(particle_intersect_dm(scene, ob,dm,0,co1,co2,&min_d,&add_pars[n].num,add_pars[n].fuv,0,0,0,0)) { 03257 add_pars[n].num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,add_pars[n].num,add_pars[n].fuv,NULL); 03258 n++; 03259 } 03260 } 03261 if(n) { 03262 int newtotpart=totpart+n; 03263 float hairmat[4][4], cur_co[3]; 03264 KDTree *tree=0; 03265 ParticleData *pa, *new_pars= MEM_callocN(newtotpart*sizeof(ParticleData),"ParticleData new"); 03266 PTCacheEditPoint *point, *new_points= MEM_callocN(newtotpart*sizeof(PTCacheEditPoint),"PTCacheEditPoint array new"); 03267 PTCacheEditKey *key; 03268 HairKey *hkey; 03269 03270 /* save existing elements */ 03271 memcpy(new_pars, psys->particles, totpart * sizeof(ParticleData)); 03272 memcpy(new_points, edit->points, totpart * sizeof(PTCacheEditPoint)); 03273 03274 /* change old arrays to new ones */ 03275 if(psys->particles) MEM_freeN(psys->particles); 03276 psys->particles= new_pars; 03277 03278 if(edit->points) MEM_freeN(edit->points); 03279 edit->points= new_points; 03280 03281 if(edit->mirror_cache) { 03282 MEM_freeN(edit->mirror_cache); 03283 edit->mirror_cache= NULL; 03284 } 03285 03286 /* create tree for interpolation */ 03287 if(pset->flag & PE_INTERPOLATE_ADDED && psys->totpart) { 03288 tree=BLI_kdtree_new(psys->totpart); 03289 03290 for(i=0, pa=psys->particles; i<totpart; i++, pa++) { 03291 psys_particle_on_dm(psmd->dm,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,cur_co,0,0,0,0,0); 03292 BLI_kdtree_insert(tree, i, cur_co, NULL); 03293 } 03294 03295 BLI_kdtree_balance(tree); 03296 } 03297 03298 edit->totpoint= psys->totpart= newtotpart; 03299 03300 /* create new elements */ 03301 pa= psys->particles + totpart; 03302 point= edit->points + totpart; 03303 03304 for(i=totpart; i<newtotpart; i++, pa++, point++) { 03305 memcpy(pa, add_pars + i - totpart, sizeof(ParticleData)); 03306 pa->hair= MEM_callocN(pset->totaddkey * sizeof(HairKey), "BakeKey key add"); 03307 key= point->keys= MEM_callocN(pset->totaddkey * sizeof(PTCacheEditKey), "PTCacheEditKey add"); 03308 point->totkey= pa->totkey= pset->totaddkey; 03309 03310 for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++) { 03311 key->co= hkey->co; 03312 key->time= &hkey->time; 03313 03314 if(!(psys->flag & PSYS_GLOBAL_HAIR)) 03315 key->flag |= PEK_USE_WCO; 03316 } 03317 03318 pa->size= 1.0f; 03319 initialize_particle(&sim, pa,i); 03320 reset_particle(&sim, pa, 0.0, 1.0); 03321 point->flag |= PEP_EDIT_RECALC; 03322 if(pe_x_mirror(ob)) 03323 point->flag |= PEP_TAG; /* signal for duplicate */ 03324 03325 framestep= pa->lifetime/(float)(pset->totaddkey-1); 03326 03327 if(tree) { 03328 ParticleData *ppa; 03329 HairKey *thkey; 03330 ParticleKey key3[3]; 03331 KDTreeNearest ptn[3]; 03332 int w, maxw; 03333 float maxd, totw=0.0, weight[3]; 03334 03335 psys_particle_on_dm(psmd->dm,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,0,0); 03336 maxw= BLI_kdtree_find_n_nearest(tree,3,co1,NULL,ptn); 03337 03338 maxd= ptn[maxw-1].dist; 03339 03340 for(w=0; w<maxw; w++) { 03341 weight[w]= (float)pow(2.0, (double)(-6.0f * ptn[w].dist / maxd)); 03342 totw += weight[w]; 03343 } 03344 for(;w<3; w++) { 03345 weight[w]= 0.0f; 03346 } 03347 03348 for(w=0; w<maxw; w++) 03349 weight[w] /= totw; 03350 03351 ppa= psys->particles+ptn[0].index; 03352 03353 for(k=0; k<pset->totaddkey; k++) { 03354 thkey= (HairKey*)pa->hair + k; 03355 thkey->time= pa->time + k * framestep; 03356 03357 key3[0].time= thkey->time/ 100.0f; 03358 psys_get_particle_on_path(&sim, ptn[0].index, key3, 0); 03359 mul_v3_fl(key3[0].co, weight[0]); 03360 03361 /* TODO: interpolatint the weight would be nicer */ 03362 thkey->weight= (ppa->hair+MIN2(k, ppa->totkey-1))->weight; 03363 03364 if(maxw>1) { 03365 key3[1].time= key3[0].time; 03366 psys_get_particle_on_path(&sim, ptn[1].index, &key3[1], 0); 03367 mul_v3_fl(key3[1].co, weight[1]); 03368 VECADD(key3[0].co, key3[0].co, key3[1].co); 03369 03370 if(maxw>2) { 03371 key3[2].time= key3[0].time; 03372 psys_get_particle_on_path(&sim, ptn[2].index, &key3[2], 0); 03373 mul_v3_fl(key3[2].co, weight[2]); 03374 VECADD(key3[0].co, key3[0].co, key3[2].co); 03375 } 03376 } 03377 03378 if(k==0) 03379 VECSUB(co1, pa->state.co, key3[0].co); 03380 03381 VECADD(thkey->co, key3[0].co, co1); 03382 03383 thkey->time= key3[0].time; 03384 } 03385 } 03386 else { 03387 for(k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) { 03388 VECADDFAC(hkey->co, pa->state.co, pa->state.vel, k * framestep * timestep); 03389 hkey->time += k * framestep; 03390 hkey->weight = 1.f - (float)k/(float)(pset->totaddkey-1); 03391 } 03392 } 03393 for(k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) { 03394 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); 03395 invert_m4_m4(imat,hairmat); 03396 mul_m4_v3(imat, hkey->co); 03397 } 03398 } 03399 03400 if(tree) 03401 BLI_kdtree_free(tree); 03402 } 03403 if(add_pars) 03404 MEM_freeN(add_pars); 03405 03406 if(!psmd->dm->deformedOnly) 03407 dm->release(dm); 03408 03409 return n; 03410 } 03411 03412 /************************* brush edit operator ********************/ 03413 03414 typedef struct BrushEdit { 03415 Scene *scene; 03416 Object *ob; 03417 PTCacheEdit *edit; 03418 03419 int first; 03420 int lastmouse[2]; 03421 03422 /* optional cached view settings to avoid setting on every mousemove */ 03423 PEData data; 03424 } BrushEdit; 03425 03426 static int brush_edit_init(bContext *C, wmOperator *op) 03427 { 03428 Scene *scene= CTX_data_scene(C); 03429 Object *ob= CTX_data_active_object(C); 03430 ParticleEditSettings *pset= PE_settings(scene); 03431 PTCacheEdit *edit= PE_get_current(scene, ob); 03432 ARegion *ar= CTX_wm_region(C); 03433 BrushEdit *bedit; 03434 03435 if(pset->brushtype < 0) 03436 return 0; 03437 03438 initgrabz(ar->regiondata, ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2]); 03439 03440 bedit= MEM_callocN(sizeof(BrushEdit), "BrushEdit"); 03441 bedit->first= 1; 03442 op->customdata= bedit; 03443 03444 bedit->scene= scene; 03445 bedit->ob= ob; 03446 bedit->edit= edit; 03447 03448 /* cache view depths and settings for re-use */ 03449 PE_set_view3d_data(C, &bedit->data); 03450 03451 return 1; 03452 } 03453 03454 static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) 03455 { 03456 BrushEdit *bedit= op->customdata; 03457 Scene *scene= bedit->scene; 03458 Object *ob= bedit->ob; 03459 PTCacheEdit *edit= bedit->edit; 03460 ParticleEditSettings *pset= PE_settings(scene); 03461 ParticleSystemModifierData *psmd= edit->psys ? psys_get_modifier(ob, edit->psys) : NULL; 03462 ParticleBrushData *brush= &pset->brush[pset->brushtype]; 03463 ARegion *ar= CTX_wm_region(C); 03464 float vec[3], mousef[2]; 03465 int mval[2]; 03466 int flip, mouse[2], removed= 0, added=0, selected= 0, tot_steps= 1, step= 1; 03467 float dx, dy, dmax; 03468 int lock_root = pset->flag & PE_LOCK_FIRST; 03469 03470 if(!PE_start_edit(edit)) 03471 return; 03472 03473 RNA_float_get_array(itemptr, "mouse", mousef); 03474 mouse[0] = mousef[0]; 03475 mouse[1] = mousef[1]; 03476 flip= RNA_boolean_get(itemptr, "pen_flip"); 03477 03478 if(bedit->first) { 03479 bedit->lastmouse[0]= mouse[0]; 03480 bedit->lastmouse[1]= mouse[1]; 03481 } 03482 03483 dx= mouse[0] - bedit->lastmouse[0]; 03484 dy= mouse[1] - bedit->lastmouse[1]; 03485 03486 mval[0]= mouse[0]; 03487 mval[1]= mouse[1]; 03488 03489 03490 /* disable locking temporatily for disconnected hair */ 03491 if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR) 03492 pset->flag &= ~PE_LOCK_FIRST; 03493 03494 if(((pset->brushtype == PE_BRUSH_ADD) ? 03495 (sqrt(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0)) 03496 || bedit->first) { 03497 PEData data= bedit->data; 03498 03499 view3d_operator_needs_opengl(C); 03500 selected= (short)count_selected_keys(scene, edit); 03501 03502 dmax = MAX2(fabs(dx), fabs(dy)); 03503 tot_steps = dmax/(0.2f * brush->size) + 1; 03504 03505 dx /= (float)tot_steps; 03506 dy /= (float)tot_steps; 03507 03508 for(step = 1; step<=tot_steps; step++) { 03509 mval[0] = bedit->lastmouse[0] + step*dx; 03510 mval[1] = bedit->lastmouse[1] + step*dy; 03511 03512 switch(pset->brushtype) { 03513 case PE_BRUSH_COMB: 03514 { 03515 float mval_f[2]; 03516 data.mval= mval; 03517 data.rad= (float)brush->size; 03518 03519 data.combfac= (brush->strength - 0.5f) * 2.0f; 03520 if(data.combfac < 0.0f) 03521 data.combfac= 1.0f - 9.0f * data.combfac; 03522 else 03523 data.combfac= 1.0f - data.combfac; 03524 03525 invert_m4_m4(ob->imat, ob->obmat); 03526 03527 mval_f[0]= dx; 03528 mval_f[1]= dy; 03529 ED_view3d_win_to_delta(ar, mval_f, vec); 03530 data.dvec= vec; 03531 03532 foreach_mouse_hit_key(&data, brush_comb, selected); 03533 break; 03534 } 03535 case PE_BRUSH_CUT: 03536 { 03537 if(edit->psys && edit->pathcache) { 03538 data.mval= mval; 03539 data.rad= (float)brush->size; 03540 data.cutfac= brush->strength; 03541 03542 if(selected) 03543 foreach_selected_point(&data, brush_cut); 03544 else 03545 foreach_point(&data, brush_cut); 03546 03547 removed= remove_tagged_particles(ob, edit->psys, pe_x_mirror(ob)); 03548 if(pset->flag & PE_KEEP_LENGTHS) 03549 recalc_lengths(edit); 03550 } 03551 else 03552 removed= 0; 03553 03554 break; 03555 } 03556 case PE_BRUSH_LENGTH: 03557 { 03558 data.mval= mval; 03559 03560 data.rad= (float)brush->size; 03561 data.growfac= brush->strength / 50.0f; 03562 03563 if(brush->invert ^ flip) 03564 data.growfac= 1.0f - data.growfac; 03565 else 03566 data.growfac= 1.0f + data.growfac; 03567 03568 foreach_mouse_hit_point(&data, brush_length, selected); 03569 03570 if(pset->flag & PE_KEEP_LENGTHS) 03571 recalc_lengths(edit); 03572 break; 03573 } 03574 case PE_BRUSH_PUFF: 03575 { 03576 if(edit->psys) { 03577 data.dm= psmd->dm; 03578 data.mval= mval; 03579 data.rad= (float)brush->size; 03580 data.select= selected; 03581 03582 data.pufffac= (brush->strength - 0.5f) * 2.0f; 03583 if(data.pufffac < 0.0f) 03584 data.pufffac= 1.0f - 9.0f * data.pufffac; 03585 else 03586 data.pufffac= 1.0f - data.pufffac; 03587 03588 data.invert= (brush->invert ^ flip); 03589 invert_m4_m4(ob->imat, ob->obmat); 03590 03591 foreach_mouse_hit_point(&data, brush_puff, selected); 03592 } 03593 break; 03594 } 03595 case PE_BRUSH_ADD: 03596 { 03597 if(edit->psys && edit->psys->part->from==PART_FROM_FACE) { 03598 data.mval= mval; 03599 03600 added= brush_add(&data, brush->count); 03601 03602 if(pset->flag & PE_KEEP_LENGTHS) 03603 recalc_lengths(edit); 03604 } 03605 else 03606 added= 0; 03607 break; 03608 } 03609 case PE_BRUSH_SMOOTH: 03610 { 03611 data.mval= mval; 03612 data.rad= (float)brush->size; 03613 03614 data.vec[0]= data.vec[1]= data.vec[2]= 0.0f; 03615 data.tot= 0; 03616 03617 data.smoothfac= brush->strength; 03618 03619 invert_m4_m4(ob->imat, ob->obmat); 03620 03621 foreach_mouse_hit_key(&data, brush_smooth_get, selected); 03622 03623 if(data.tot) { 03624 mul_v3_fl(data.vec, 1.0f / (float)data.tot); 03625 foreach_mouse_hit_key(&data, brush_smooth_do, selected); 03626 } 03627 03628 break; 03629 } 03630 case PE_BRUSH_WEIGHT: 03631 { 03632 if(edit->psys) { 03633 data.dm= psmd->dm; 03634 data.mval= mval; 03635 data.rad= (float)brush->size; 03636 03637 data.weightfac = brush->strength; /* note that this will never be zero */ 03638 03639 foreach_mouse_hit_key(&data, brush_weight, selected); 03640 } 03641 03642 break; 03643 } 03644 } 03645 if((pset->flag & PE_KEEP_LENGTHS)==0) 03646 recalc_lengths(edit); 03647 03648 if(ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_CUT) && (added || removed)) { 03649 if(pset->brushtype == PE_BRUSH_ADD && pe_x_mirror(ob)) 03650 PE_mirror_x(scene, ob, 1); 03651 03652 update_world_cos(ob,edit); 03653 psys_free_path_cache(NULL, edit); 03654 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 03655 } 03656 else 03657 PE_update_object(scene, ob, 1); 03658 } 03659 03660 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); 03661 03662 bedit->lastmouse[0]= mouse[0]; 03663 bedit->lastmouse[1]= mouse[1]; 03664 bedit->first= 0; 03665 } 03666 03667 pset->flag |= lock_root; 03668 } 03669 03670 static void brush_edit_exit(wmOperator *op) 03671 { 03672 BrushEdit *bedit= op->customdata; 03673 03674 MEM_freeN(bedit); 03675 } 03676 03677 static int brush_edit_exec(bContext *C, wmOperator *op) 03678 { 03679 if(!brush_edit_init(C, op)) 03680 return OPERATOR_CANCELLED; 03681 03682 RNA_BEGIN(op->ptr, itemptr, "stroke") { 03683 brush_edit_apply(C, op, &itemptr); 03684 } 03685 RNA_END; 03686 03687 brush_edit_exit(op); 03688 03689 return OPERATOR_FINISHED; 03690 } 03691 03692 static void brush_edit_apply_event(bContext *C, wmOperator *op, wmEvent *event) 03693 { 03694 PointerRNA itemptr; 03695 float mouse[2]; 03696 03697 VECCOPY2D(mouse, event->mval); 03698 03699 /* fill in stroke */ 03700 RNA_collection_add(op->ptr, "stroke", &itemptr); 03701 03702 RNA_float_set_array(&itemptr, "mouse", mouse); 03703 RNA_boolean_set(&itemptr, "pen_flip", event->shift != 0); // XXX hardcoded 03704 03705 /* apply */ 03706 brush_edit_apply(C, op, &itemptr); 03707 } 03708 03709 static int brush_edit_invoke(bContext *C, wmOperator *op, wmEvent *event) 03710 { 03711 if(!brush_edit_init(C, op)) 03712 return OPERATOR_CANCELLED; 03713 03714 brush_edit_apply_event(C, op, event); 03715 03716 WM_event_add_modal_handler(C, op); 03717 03718 return OPERATOR_RUNNING_MODAL; 03719 } 03720 03721 static int brush_edit_modal(bContext *C, wmOperator *op, wmEvent *event) 03722 { 03723 switch(event->type) { 03724 case LEFTMOUSE: 03725 case MIDDLEMOUSE: 03726 case RIGHTMOUSE: // XXX hardcoded 03727 brush_edit_exit(op); 03728 return OPERATOR_FINISHED; 03729 case MOUSEMOVE: 03730 brush_edit_apply_event(C, op, event); 03731 break; 03732 } 03733 03734 return OPERATOR_RUNNING_MODAL; 03735 } 03736 03737 static int brush_edit_cancel(bContext *UNUSED(C), wmOperator *op) 03738 { 03739 brush_edit_exit(op); 03740 03741 return OPERATOR_CANCELLED; 03742 } 03743 03744 void PARTICLE_OT_brush_edit(wmOperatorType *ot) 03745 { 03746 /* identifiers */ 03747 ot->name= "Brush Edit"; 03748 ot->idname= "PARTICLE_OT_brush_edit"; 03749 03750 /* api callbacks */ 03751 ot->exec= brush_edit_exec; 03752 ot->invoke= brush_edit_invoke; 03753 ot->modal= brush_edit_modal; 03754 ot->cancel= brush_edit_cancel; 03755 ot->poll= PE_poll_view3d; 03756 03757 /* flags */ 03758 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; 03759 03760 /* properties */ 03761 RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); 03762 } 03763 03764 /*********************** undo ***************************/ 03765 03766 static void free_PTCacheUndo(PTCacheUndo *undo) 03767 { 03768 PTCacheEditPoint *point; 03769 int i; 03770 03771 for(i=0, point=undo->points; i<undo->totpoint; i++, point++) { 03772 if(undo->particles && (undo->particles + i)->hair) 03773 MEM_freeN((undo->particles + i)->hair); 03774 if(point->keys) 03775 MEM_freeN(point->keys); 03776 } 03777 if(undo->points) 03778 MEM_freeN(undo->points); 03779 03780 if(undo->particles) 03781 MEM_freeN(undo->particles); 03782 03783 BKE_ptcache_free_mem(&undo->mem_cache); 03784 } 03785 03786 static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) 03787 { 03788 PTCacheEditPoint *point; 03789 int i; 03790 03791 undo->totpoint= edit->totpoint; 03792 03793 if(edit->psys) { 03794 ParticleData *pa; 03795 03796 pa= undo->particles= MEM_dupallocN(edit->psys->particles); 03797 03798 for(i=0; i<edit->totpoint; i++, pa++) 03799 pa->hair= MEM_dupallocN(pa->hair); 03800 03801 undo->psys_flag = edit->psys->flag; 03802 } 03803 else { 03804 PTCacheMem *pm; 03805 03806 BLI_duplicatelist(&undo->mem_cache, &edit->pid.cache->mem_cache); 03807 pm = undo->mem_cache.first; 03808 03809 for(; pm; pm=pm->next) { 03810 for(i=0; i<BPHYS_TOT_DATA; i++) 03811 pm->data[i] = MEM_dupallocN(pm->data[i]); 03812 } 03813 } 03814 03815 point= undo->points = MEM_dupallocN(edit->points); 03816 undo->totpoint = edit->totpoint; 03817 03818 for(i=0; i<edit->totpoint; i++, point++) { 03819 point->keys= MEM_dupallocN(point->keys); 03820 /* no need to update edit key->co & key->time pointers here */ 03821 } 03822 } 03823 03824 static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo) 03825 { 03826 ParticleSystem *psys = edit->psys; 03827 ParticleData *pa; 03828 HairKey *hkey; 03829 POINT_P; KEY_K; 03830 03831 LOOP_POINTS { 03832 if(psys && psys->particles[p].hair) 03833 MEM_freeN(psys->particles[p].hair); 03834 03835 if(point->keys) 03836 MEM_freeN(point->keys); 03837 } 03838 if(psys && psys->particles) 03839 MEM_freeN(psys->particles); 03840 if(edit->points) 03841 MEM_freeN(edit->points); 03842 if(edit->mirror_cache) { 03843 MEM_freeN(edit->mirror_cache); 03844 edit->mirror_cache= NULL; 03845 } 03846 03847 edit->points= MEM_dupallocN(undo->points); 03848 edit->totpoint = undo->totpoint; 03849 03850 LOOP_POINTS { 03851 point->keys= MEM_dupallocN(point->keys); 03852 } 03853 03854 if(psys) { 03855 psys->particles= MEM_dupallocN(undo->particles); 03856 03857 psys->totpart= undo->totpoint; 03858 03859 LOOP_POINTS { 03860 pa = psys->particles + p; 03861 hkey= pa->hair = MEM_dupallocN(pa->hair); 03862 03863 LOOP_KEYS { 03864 key->co= hkey->co; 03865 key->time= &hkey->time; 03866 hkey++; 03867 } 03868 } 03869 03870 psys->flag = undo->psys_flag; 03871 } 03872 else { 03873 PTCacheMem *pm; 03874 int i; 03875 03876 BKE_ptcache_free_mem(&edit->pid.cache->mem_cache); 03877 03878 BLI_duplicatelist(&edit->pid.cache->mem_cache, &undo->mem_cache); 03879 03880 pm = edit->pid.cache->mem_cache.first; 03881 03882 for(; pm; pm=pm->next) { 03883 for(i=0; i<BPHYS_TOT_DATA; i++) 03884 pm->data[i] = MEM_dupallocN(pm->data[i]); 03885 03886 BKE_ptcache_mem_pointers_init(pm); 03887 03888 LOOP_POINTS { 03889 LOOP_KEYS { 03890 if((int)key->ftime == (int)pm->frame) { 03891 key->co = pm->cur[BPHYS_DATA_LOCATION]; 03892 key->vel = pm->cur[BPHYS_DATA_VELOCITY]; 03893 key->rot = pm->cur[BPHYS_DATA_ROTATION]; 03894 key->time = &key->ftime; 03895 } 03896 } 03897 BKE_ptcache_mem_pointers_incr(pm); 03898 } 03899 } 03900 } 03901 } 03902 03903 void PE_undo_push(Scene *scene, const char *str) 03904 { 03905 PTCacheEdit *edit= PE_get_current(scene, OBACT); 03906 PTCacheUndo *undo; 03907 int nr; 03908 03909 if(!edit) return; 03910 03911 /* remove all undos after (also when curundo==NULL) */ 03912 while(edit->undo.last != edit->curundo) { 03913 undo= edit->undo.last; 03914 BLI_remlink(&edit->undo, undo); 03915 free_PTCacheUndo(undo); 03916 MEM_freeN(undo); 03917 } 03918 03919 /* make new */ 03920 edit->curundo= undo= MEM_callocN(sizeof(PTCacheUndo), "particle undo file"); 03921 strncpy(undo->name, str, 64-1); 03922 BLI_addtail(&edit->undo, undo); 03923 03924 /* and limit amount to the maximum */ 03925 nr= 0; 03926 undo= edit->undo.last; 03927 while(undo) { 03928 nr++; 03929 if(nr==U.undosteps) break; 03930 undo= undo->prev; 03931 } 03932 if(undo) { 03933 while(edit->undo.first!=undo) { 03934 PTCacheUndo *first= edit->undo.first; 03935 BLI_remlink(&edit->undo, first); 03936 free_PTCacheUndo(first); 03937 MEM_freeN(first); 03938 } 03939 } 03940 03941 /* copy */ 03942 make_PTCacheUndo(edit,edit->curundo); 03943 } 03944 03945 void PE_undo_step(Scene *scene, int step) 03946 { 03947 PTCacheEdit *edit= PE_get_current(scene, OBACT); 03948 03949 if(!edit) return; 03950 03951 if(step==0) { 03952 get_PTCacheUndo(edit,edit->curundo); 03953 } 03954 else if(step==1) { 03955 03956 if(edit->curundo==NULL || edit->curundo->prev==NULL); 03957 else { 03958 if(G.f & G_DEBUG) printf("undo %s\n", edit->curundo->name); 03959 edit->curundo= edit->curundo->prev; 03960 get_PTCacheUndo(edit, edit->curundo); 03961 } 03962 } 03963 else { 03964 /* curundo has to remain current situation! */ 03965 03966 if(edit->curundo==NULL || edit->curundo->next==NULL); 03967 else { 03968 get_PTCacheUndo(edit, edit->curundo->next); 03969 edit->curundo= edit->curundo->next; 03970 if(G.f & G_DEBUG) printf("redo %s\n", edit->curundo->name); 03971 } 03972 } 03973 03974 DAG_id_tag_update(&OBACT->id, OB_RECALC_DATA); 03975 } 03976 03977 int PE_undo_valid(Scene *scene) 03978 { 03979 PTCacheEdit *edit= PE_get_current(scene, OBACT); 03980 03981 if(edit) { 03982 return (edit->undo.last != edit->undo.first); 03983 } 03984 return 0; 03985 } 03986 03987 static void PTCacheUndo_clear(PTCacheEdit *edit) 03988 { 03989 PTCacheUndo *undo; 03990 03991 if(edit==0) return; 03992 03993 undo= edit->undo.first; 03994 while(undo) { 03995 free_PTCacheUndo(undo); 03996 undo= undo->next; 03997 } 03998 BLI_freelistN(&edit->undo); 03999 edit->curundo= NULL; 04000 } 04001 04002 void PE_undo(Scene *scene) 04003 { 04004 PE_undo_step(scene, 1); 04005 } 04006 04007 void PE_redo(Scene *scene) 04008 { 04009 PE_undo_step(scene, -1); 04010 } 04011 04012 void PE_undo_number(Scene *scene, int nr) 04013 { 04014 PTCacheEdit *edit= PE_get_current(scene, OBACT); 04015 PTCacheUndo *undo; 04016 int a=0; 04017 04018 for(undo= edit->undo.first; undo; undo= undo->next, a++) { 04019 if(a==nr) break; 04020 } 04021 edit->curundo= undo; 04022 PE_undo_step(scene, 0); 04023 } 04024 04025 04026 /* get name of undo item, return null if no item with this index */ 04027 /* if active pointer, set it to 1 if true */ 04028 char *PE_undo_get_name(Scene *scene, int nr, int *active) 04029 { 04030 PTCacheEdit *edit= PE_get_current(scene, OBACT); 04031 PTCacheUndo *undo; 04032 04033 if(active) *active= 0; 04034 04035 if(edit) { 04036 undo= BLI_findlink(&edit->undo, nr); 04037 if(undo) { 04038 if(active && undo==edit->curundo) 04039 *active= 1; 04040 return undo->name; 04041 } 04042 } 04043 return NULL; 04044 } 04045 04046 /************************ utilities ******************************/ 04047 04048 int PE_minmax(Scene *scene, float *min, float *max) 04049 { 04050 Object *ob= OBACT; 04051 PTCacheEdit *edit= PE_get_current(scene, ob); 04052 ParticleSystem *psys; 04053 ParticleSystemModifierData *psmd = NULL; 04054 POINT_P; KEY_K; 04055 float co[3], mat[4][4]; 04056 int ok= 0; 04057 04058 if(!edit) return ok; 04059 04060 if((psys = edit->psys)) 04061 psmd= psys_get_modifier(ob, psys); 04062 else 04063 unit_m4(mat); 04064 04065 LOOP_VISIBLE_POINTS { 04066 if(psys) 04067 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles+p, mat); 04068 04069 LOOP_SELECTED_KEYS { 04070 VECCOPY(co, key->co); 04071 mul_m4_v3(mat, co); 04072 DO_MINMAX(co, min, max); 04073 ok= 1; 04074 } 04075 } 04076 04077 if(!ok) { 04078 minmax_object(ob, min, max); 04079 ok= 1; 04080 } 04081 04082 return ok; 04083 } 04084 04085 /************************ particle edit toggle operator ************************/ 04086 04087 /* initialize needed data for bake edit */ 04088 static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys) 04089 { 04090 PTCacheEdit *edit= (psys)? psys->edit : cache->edit; 04091 ParticleSystemModifierData *psmd= (psys)? psys_get_modifier(ob, psys): NULL; 04092 POINT_P; KEY_K; 04093 ParticleData *pa = NULL; 04094 HairKey *hkey; 04095 int totpoint; 04096 04097 /* no psmd->dm happens in case particle system modifier is not enabled */ 04098 if(!(psys && psmd && psmd->dm) && !cache) 04099 return; 04100 04101 if(cache && cache->flag & PTCACHE_DISK_CACHE) 04102 return; 04103 04104 if(psys == NULL && cache->mem_cache.first == NULL) 04105 return; 04106 04107 if(!edit) { 04108 totpoint = psys ? psys->totpart : (int)((PTCacheMem*)cache->mem_cache.first)->totpoint; 04109 04110 edit= MEM_callocN(sizeof(PTCacheEdit), "PE_create_particle_edit"); 04111 edit->points=MEM_callocN(totpoint*sizeof(PTCacheEditPoint),"PTCacheEditPoints"); 04112 edit->totpoint = totpoint; 04113 04114 if(psys && !cache) { 04115 psys->edit= edit; 04116 edit->psys = psys; 04117 04118 psys->free_edit= PE_free_ptcache_edit; 04119 04120 edit->pathcache = NULL; 04121 edit->pathcachebufs.first = edit->pathcachebufs.last = NULL; 04122 04123 pa = psys->particles; 04124 LOOP_POINTS { 04125 point->totkey = pa->totkey; 04126 point->keys= MEM_callocN(point->totkey*sizeof(PTCacheEditKey),"ParticleEditKeys"); 04127 point->flag |= PEP_EDIT_RECALC; 04128 04129 hkey = pa->hair; 04130 LOOP_KEYS { 04131 key->co= hkey->co; 04132 key->time= &hkey->time; 04133 key->flag= hkey->editflag; 04134 if(!(psys->flag & PSYS_GLOBAL_HAIR)) { 04135 key->flag |= PEK_USE_WCO; 04136 hkey->editflag |= PEK_USE_WCO; 04137 } 04138 04139 hkey++; 04140 } 04141 pa++; 04142 } 04143 update_world_cos(ob, edit); 04144 } 04145 else { 04146 PTCacheMem *pm; 04147 int totframe=0; 04148 04149 cache->edit= edit; 04150 cache->free_edit= PE_free_ptcache_edit; 04151 edit->psys = NULL; 04152 04153 for(pm=cache->mem_cache.first; pm; pm=pm->next) 04154 totframe++; 04155 04156 for(pm=cache->mem_cache.first; pm; pm=pm->next) { 04157 LOOP_POINTS { 04158 if(BKE_ptcache_mem_pointers_seek(p, pm) == 0) 04159 continue; 04160 04161 if(!point->totkey) { 04162 key = point->keys = MEM_callocN(totframe*sizeof(PTCacheEditKey),"ParticleEditKeys"); 04163 point->flag |= PEP_EDIT_RECALC; 04164 } 04165 else 04166 key = point->keys + point->totkey; 04167 04168 key->co = pm->cur[BPHYS_DATA_LOCATION]; 04169 key->vel = pm->cur[BPHYS_DATA_VELOCITY]; 04170 key->rot = pm->cur[BPHYS_DATA_ROTATION]; 04171 key->ftime = (float)pm->frame; 04172 key->time = &key->ftime; 04173 BKE_ptcache_mem_pointers_incr(pm); 04174 04175 point->totkey++; 04176 } 04177 } 04178 psys = NULL; 04179 } 04180 04181 UI_GetThemeColor3ubv(TH_EDGE_SELECT, edit->sel_col); 04182 UI_GetThemeColor3ubv(TH_WIRE, edit->nosel_col); 04183 04184 recalc_lengths(edit); 04185 if(psys && !cache) 04186 recalc_emitter_field(ob, psys); 04187 PE_update_object(scene, ob, 1); 04188 04189 PTCacheUndo_clear(edit); 04190 PE_undo_push(scene, "Original"); 04191 } 04192 } 04193 04194 static int particle_edit_toggle_poll(bContext *C) 04195 { 04196 Scene *scene= CTX_data_scene(C); 04197 Object *ob= CTX_data_active_object(C); 04198 04199 if(!scene || !ob || ob->id.lib) 04200 return 0; 04201 04202 return (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) || modifiers_findByType(ob, eModifierType_Softbody)); 04203 } 04204 04205 static int particle_edit_toggle_exec(bContext *C, wmOperator *UNUSED(op)) 04206 { 04207 Scene *scene= CTX_data_scene(C); 04208 Object *ob= CTX_data_active_object(C); 04209 04210 if(!(ob->mode & OB_MODE_PARTICLE_EDIT)) { 04211 PTCacheEdit *edit; 04212 ob->mode |= OB_MODE_PARTICLE_EDIT; 04213 edit= PE_create_current(scene, ob); 04214 04215 /* mesh may have changed since last entering editmode. 04216 * note, this may have run before if the edit data was just created, so could avoid this and speed up a little */ 04217 if(edit && edit->psys) 04218 recalc_emitter_field(ob, edit->psys); 04219 04220 toggle_particle_cursor(C, 1); 04221 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_PARTICLE, NULL); 04222 } 04223 else { 04224 ob->mode &= ~OB_MODE_PARTICLE_EDIT; 04225 toggle_particle_cursor(C, 0); 04226 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL); 04227 } 04228 04229 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 04230 04231 return OPERATOR_FINISHED; 04232 } 04233 04234 void PARTICLE_OT_particle_edit_toggle(wmOperatorType *ot) 04235 { 04236 /* identifiers */ 04237 ot->name= "Particle Edit Toggle"; 04238 ot->idname= "PARTICLE_OT_particle_edit_toggle"; 04239 04240 /* api callbacks */ 04241 ot->exec= particle_edit_toggle_exec; 04242 ot->poll= particle_edit_toggle_poll; 04243 04244 /* flags */ 04245 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 04246 } 04247 04248 04249 /************************ set editable operator ************************/ 04250 04251 static int clear_edited_exec(bContext *C, wmOperator *UNUSED(op)) 04252 { 04253 Object *ob= CTX_data_active_object(C); 04254 ParticleSystem *psys = psys_get_current(ob); 04255 04256 if(psys->edit) { 04257 if(psys->edit->edited || 1) { // XXX okee("Lose changes done in particle mode?")) 04258 PE_free_ptcache_edit(psys->edit); 04259 04260 psys->edit = NULL; 04261 psys->free_edit = NULL; 04262 04263 psys->recalc |= PSYS_RECALC_RESET; 04264 psys->flag &= ~PSYS_GLOBAL_HAIR; 04265 psys->flag &= ~PSYS_EDITED; 04266 04267 psys_reset(psys, PSYS_RESET_DEPSGRAPH); 04268 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); 04269 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 04270 } 04271 } 04272 else { /* some operation might have protected hair from editing so let's clear the flag */ 04273 psys->recalc |= PSYS_RECALC_RESET; 04274 psys->flag &= ~PSYS_GLOBAL_HAIR; 04275 psys->flag &= ~PSYS_EDITED; 04276 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); 04277 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 04278 } 04279 04280 return OPERATOR_FINISHED; 04281 } 04282 04283 void PARTICLE_OT_edited_clear(wmOperatorType *ot) 04284 { 04285 /* identifiers */ 04286 ot->name= "Clear Edited"; 04287 ot->idname= "PARTICLE_OT_edited_clear"; 04288 04289 /* api callbacks */ 04290 ot->exec= clear_edited_exec; 04291 ot->poll= particle_edit_toggle_poll; 04292 04293 /* flags */ 04294 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 04295 } 04296