Welcome to mirror list, hosted at ThFree Co, Russian Federation.

hair_undo.c « hair « editors « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: cb5ae43f5dd2812d271cf013524bc2463082c68a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/*
 * ***** 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) Blender Foundation
 * All rights reserved.
 *
 * The Original Code is: all of this file.
 *
 * Contributor(s): Lukas Toenne
 *
 * ***** END GPL LICENSE BLOCK *****
 */

/** \file blender/editors/hair/hair_undo.c
 *  \ingroup edhair
 */

#include <stdlib.h>

#include "MEM_guardedalloc.h"

#include "BLI_utildefines.h"

#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"

#include "BKE_context.h"
#include "BKE_DerivedMesh.h"
#include "BKE_editstrands.h"
#include "BKE_key.h"
#include "BKE_mesh.h"
#include "BKE_mesh_sample.h"

#include "ED_physics.h"
#include "ED_util.h"

#include "bmesh.h"

#include "hair_intern.h"

static void *strands_get_edit(bContext *C)
{
	Object *obact = CTX_data_active_object(C);
	const int mode_flag = OB_MODE_HAIR_EDIT;
	const bool is_mode_set = ((obact->mode & mode_flag) != 0);

	if (obact && is_mode_set) {
		BMEditStrands *edit = BKE_editstrands_from_object(obact);
		return edit;
	}
	return NULL;
}

typedef struct UndoStrands {
	Mesh me; /* Mesh supports all the customdata we need, easiest way to implement undo storage */
	int selectmode;

	/** \note
	 * this isn't a prefect solution, if you edit keys and change shapes this works well (fixing [#32442]),
	 * but editing shape keys, going into object mode, removing or changing their order,
	 * then go back into editmode and undo will give issues - where the old index will be out of sync
	 * with the new object index.
	 *
	 * There are a few ways this could be made to work but for now its a known limitation with mixing
	 * object and editmode operations - Campbell */
	int shapenr;
} UndoStrands;

/* undo simply makes copies of a bmesh */
static void *strands_edit_to_undo(void *editv, void *UNUSED(obdata))
{
	BMEditStrands *edit = editv;
	BMesh *bm = edit->base.bm;
//	Mesh *obme = obdata;
	struct BMeshToMeshParams params = {0};
	
	UndoStrands *undo = MEM_callocN(sizeof(UndoStrands), "undo Strands");
	
	/* make sure shape keys work */
//	um->me.key = obme->key ? BKE_key_copy_nolib(obme->key) : NULL;

	/* BM_mesh_validate(em->bm); */ /* for troubleshooting */

	params.cd_mask_extra = CD_MASK_STRANDS;
	BM_mesh_bm_to_me(bm, &undo->me, &params);

	undo->selectmode = bm->selectmode;
	undo->shapenr = bm->shapenr;

	return undo;
}

static void strands_undo_to_edit(void *undov, void *editv, void *UNUSED(obdata))
{
	UndoStrands *undo = undov;
	BMEditStrands *edit = editv, *edit_tmp;
	Object *ob = edit->base.ob;
	DerivedMesh *dm = edit->root_dm;
	BMesh *bm;
//	Key *key = ((Mesh *) obdata)->key;
	struct BMeshFromMeshParams params = {0};
	
	const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&undo->me);
	
	edit->base.bm->shapenr = undo->shapenr;
	
	bm = BM_mesh_create(&allocsize,
	                    &((struct BMeshCreateParams){.use_toolflags = false,}));
	params.cd_mask_extra = CD_MASK_STRANDS_BMESH;
	params.active_shapekey = undo->shapenr;
	BM_mesh_bm_from_me(bm, &undo->me, &params);
	
	/* note: have to create the new edit before freeing the old one,
	 * because it owns the root_dm and we have to copy it before
	 * it gets released when freeing the old edit.
	 */
	edit_tmp = BKE_editstrands_create(bm, dm);
	BKE_editstrands_free(edit);
	*edit = *edit_tmp;
	
	bm->selectmode = undo->selectmode;
	edit->base.ob = ob;
	
#if 0
	/* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens
	 *         if the active is a basis for any other. */
	if (key && (key->type == KEY_RELATIVE)) {
		/* Since we can't add, remove or reorder keyblocks in editmode, it's safe to assume
		 * shapenr from restored bmesh and keyblock indices are in sync. */
		const int kb_act_idx = ob->shapenr - 1;
		
		/* If it is, let's patch the current mesh key block to its restored value.
		 * Else, the offsets won't be computed and it won't matter. */
		if (BKE_keyblock_is_basis(key, kb_act_idx)) {
			KeyBlock *kb_act = BLI_findlink(&key->block, kb_act_idx);
			
			if (kb_act->totelem != undo->me.totvert) {
				/* The current mesh has some extra/missing verts compared to the undo, adjust. */
				MEM_SAFE_FREE(kb_act->data);
				kb_act->data = MEM_mallocN((size_t)(key->elemsize * bm->totvert), __func__);
				kb_act->totelem = undo->me.totvert;
			}
			
			BKE_keyblock_update_from_mesh(&undo->me, kb_act);
		}
	}
#endif

	ob->shapenr = undo->shapenr;
	
	MEM_freeN(edit_tmp);
}

static void strands_free_undo(void *undov)
{
	UndoStrands *undo = undov;
	
	if (undo->me.key) {
		BKE_key_free(undo->me.key);
		MEM_freeN(undo->me.key);
	}

	BKE_mesh_free(&undo->me);
	MEM_freeN(undo);
}

/* and this is all the undo system needs to know */
void undo_push_strands(bContext *C, const char *name)
{
	/* edit->ob gets out of date and crashes on mesh undo,
	 * this is an easy way to ensure its OK
	 * though we could investigate the matter further. */
	Object *obact = CTX_data_active_object(C);
	BMEditStrands *edit = BKE_editstrands_from_object(obact);
	edit->base.ob = obact;
	
	undo_editmode_push(C, name, CTX_data_active_object, strands_get_edit, strands_free_undo, strands_undo_to_edit, strands_edit_to_undo, NULL);
}