This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/editors/physics/particle_edit_undo.c

342 lines
7.5 KiB
C
Raw Normal View History

/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2007 by Janne Karhu.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/physics/particle_edit_undo.c
* \ingroup edphys
*/
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <assert.h>
#include "MEM_guardedalloc.h"
#include "DNA_scene_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BKE_global.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
2018-03-19 18:06:27 +01:00
#include "DEG_depsgraph.h"
#include "ED_particle.h"
#include "particle_edit_utildefines.h"
#include "physics_intern.h"
static void free_PTCacheUndo(PTCacheUndo *undo)
{
PTCacheEditPoint *point;
int i;
for (i=0, point=undo->points; i<undo->totpoint; i++, point++) {
if (undo->particles && (undo->particles + i)->hair)
MEM_freeN((undo->particles + i)->hair);
if (point->keys)
MEM_freeN(point->keys);
}
if (undo->points)
MEM_freeN(undo->points);
if (undo->particles)
MEM_freeN(undo->particles);
BKE_ptcache_free_mem(&undo->mem_cache);
}
static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
{
PTCacheEditPoint *point;
int i;
undo->totpoint= edit->totpoint;
if (edit->psys) {
ParticleData *pa;
pa= undo->particles= MEM_dupallocN(edit->psys->particles);
for (i=0; i<edit->totpoint; i++, pa++)
pa->hair= MEM_dupallocN(pa->hair);
undo->psys_flag = edit->psys->flag;
}
else {
PTCacheMem *pm;
BLI_duplicatelist(&undo->mem_cache, &edit->pid.cache->mem_cache);
pm = undo->mem_cache.first;
for (; pm; pm=pm->next) {
for (i=0; i<BPHYS_TOT_DATA; i++)
pm->data[i] = MEM_dupallocN(pm->data[i]);
}
}
point= undo->points = MEM_dupallocN(edit->points);
undo->totpoint = edit->totpoint;
for (i=0; i<edit->totpoint; i++, point++) {
point->keys= MEM_dupallocN(point->keys);
/* no need to update edit key->co & key->time pointers here */
}
}
static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
{
ParticleSystem *psys = edit->psys;
ParticleData *pa;
HairKey *hkey;
POINT_P; KEY_K;
LOOP_POINTS {
if (psys && psys->particles[p].hair)
MEM_freeN(psys->particles[p].hair);
if (point->keys)
MEM_freeN(point->keys);
}
if (psys && psys->particles)
MEM_freeN(psys->particles);
if (edit->points)
MEM_freeN(edit->points);
if (edit->mirror_cache) {
MEM_freeN(edit->mirror_cache);
edit->mirror_cache= NULL;
}
edit->points= MEM_dupallocN(undo->points);
edit->totpoint = undo->totpoint;
LOOP_POINTS {
point->keys= MEM_dupallocN(point->keys);
}
if (psys) {
psys->particles= MEM_dupallocN(undo->particles);
psys->totpart= undo->totpoint;
LOOP_POINTS {
pa = psys->particles + p;
hkey= pa->hair = MEM_dupallocN(pa->hair);
LOOP_KEYS {
key->co= hkey->co;
key->time= &hkey->time;
hkey++;
}
}
psys->flag = undo->psys_flag;
}
else {
PTCacheMem *pm;
int i;
BKE_ptcache_free_mem(&edit->pid.cache->mem_cache);
BLI_duplicatelist(&edit->pid.cache->mem_cache, &undo->mem_cache);
pm = edit->pid.cache->mem_cache.first;
for (; pm; pm=pm->next) {
for (i=0; i<BPHYS_TOT_DATA; i++)
pm->data[i] = MEM_dupallocN(pm->data[i]);
BKE_ptcache_mem_pointers_init(pm);
LOOP_POINTS {
LOOP_KEYS {
if ((int)key->ftime == (int)pm->frame) {
key->co = pm->cur[BPHYS_DATA_LOCATION];
key->vel = pm->cur[BPHYS_DATA_VELOCITY];
key->rot = pm->cur[BPHYS_DATA_ROTATION];
key->time = &key->ftime;
}
}
BKE_ptcache_mem_pointers_incr(pm);
}
}
}
}
2018-03-19 18:06:27 +01:00
void PE_undo_push(Scene *scene, ViewLayer *view_layer, const char *str)
{
2018-03-19 18:06:27 +01:00
PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
PTCacheUndo *undo;
int nr;
if (!edit) return;
/* remove all undos after (also when curundo==NULL) */
while (edit->undo.last != edit->curundo) {
undo= edit->undo.last;
BLI_remlink(&edit->undo, undo);
free_PTCacheUndo(undo);
MEM_freeN(undo);
}
/* make new */
edit->curundo= undo= MEM_callocN(sizeof(PTCacheUndo), "particle undo file");
BLI_strncpy(undo->name, str, sizeof(undo->name));
BLI_addtail(&edit->undo, undo);
2018-03-19 18:06:27 +01:00
/* and limit amount to the maximum */
nr= 0;
undo= edit->undo.last;
while (undo) {
nr++;
if (nr==U.undosteps) break;
undo= undo->prev;
}
if (undo) {
while (edit->undo.first != undo) {
PTCacheUndo *first= edit->undo.first;
BLI_remlink(&edit->undo, first);
free_PTCacheUndo(first);
MEM_freeN(first);
}
}
/* copy */
make_PTCacheUndo(edit, edit->curundo);
}
2018-03-19 18:06:27 +01:00
void PE_undo_step(Scene *scene, ViewLayer *view_layer, int step)
{
PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
if (!edit) return;
if (step==0) {
get_PTCacheUndo(edit, edit->curundo);
}
else if (step==1) {
2018-03-19 18:06:27 +01:00
if (edit->curundo==NULL || edit->curundo->prev==NULL) {
/* pass */
}
else {
if (G.debug & G_DEBUG) printf("undo %s\n", edit->curundo->name);
edit->curundo= edit->curundo->prev;
get_PTCacheUndo(edit, edit->curundo);
}
}
else {
/* curundo has to remain current situation! */
2018-03-19 18:06:27 +01:00
if (edit->curundo==NULL || edit->curundo->next==NULL) {
/* pass */
}
else {
get_PTCacheUndo(edit, edit->curundo->next);
edit->curundo= edit->curundo->next;
if (G.debug & G_DEBUG) printf("redo %s\n", edit->curundo->name);
}
}
2018-03-19 18:06:27 +01:00
DEG_id_tag_update(&OBACT(view_layer)->id, OB_RECALC_DATA);
}
2018-03-19 18:06:27 +01:00
bool PE_undo_is_valid(Scene *scene, ViewLayer *view_layer)
{
2018-03-19 18:06:27 +01:00
PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
if (edit) {
return (edit->undo.last != edit->undo.first);
}
return 0;
}
void PTCacheUndo_clear(PTCacheEdit *edit)
{
PTCacheUndo *undo;
if (edit==NULL) return;
2018-03-19 18:06:27 +01:00
undo= edit->undo.first;
while (undo) {
free_PTCacheUndo(undo);
undo= undo->next;
}
BLI_freelistN(&edit->undo);
edit->curundo= NULL;
}
2018-03-19 18:06:27 +01:00
void PE_undo(Scene *scene, ViewLayer *view_layer)
{
2018-03-19 18:06:27 +01:00
PE_undo_step(scene, view_layer, 1);
}
2018-03-19 18:06:27 +01:00
void PE_redo(Scene *scene, ViewLayer *view_layer)
{
2018-03-19 18:06:27 +01:00
PE_undo_step(scene, view_layer, -1);
}
2018-03-19 18:06:27 +01:00
void PE_undo_number(Scene *scene, ViewLayer *view_layer, int nr)
{
2018-03-19 18:06:27 +01:00
PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
PTCacheUndo *undo;
int a=0;
2018-03-19 18:06:27 +01:00
for (undo= edit->undo.first; undo; undo= undo->next, a++) {
if (a==nr) break;
}
edit->curundo= undo;
2018-03-19 18:06:27 +01:00
PE_undo_step(scene, view_layer, 0);
}
/* get name of undo item, return null if no item with this index */
/* if active pointer, set it to 1 if true */
2018-03-19 18:06:27 +01:00
const char *PE_undo_get_name(Scene *scene, ViewLayer *view_layer, int nr, bool *r_active)
{
2018-03-19 18:06:27 +01:00
PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
PTCacheUndo *undo;
2018-03-19 18:06:27 +01:00
if (r_active) *r_active = false;
2018-03-19 18:06:27 +01:00
if (edit) {
undo= BLI_findlink(&edit->undo, nr);
if (undo) {
if (r_active && (undo == edit->curundo)) {
*r_active = true;
}
return undo->name;
}
}
return NULL;
}