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