Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / sculpt_paint / paint_vertex_proj.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2013 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/sculpt_paint/paint_vertex_proj.c
28  *  \ingroup edsculpt
29  *
30  * Utility functions for getting vertex locations while painting
31  * (since they may be instanced multiple times in a DerivedMesh)
32  */
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BLI_math.h"
37 #include "BLI_listbase.h"
38
39 #include "DNA_mesh_types.h"
40 #include "DNA_object_types.h"
41
42 #include "BKE_DerivedMesh.h"
43 #include "BKE_context.h"
44
45 #include "DEG_depsgraph.h"
46
47 #include "ED_screen.h"
48 #include "ED_view3d.h"
49
50 #include "paint_intern.h"  /* own include */
51
52
53 /* Opaque Structs for internal use */
54
55 /* stored while painting */
56 struct VertProjHandle {
57         DMCoNo *vcosnos;
58
59         bool use_update;
60
61         /* use for update */
62         float *dists_sq;
63
64         Object *ob;
65         Scene *scene;
66 };
67
68 /* only for passing to the callbacks */
69 struct VertProjUpdate {
70         struct VertProjHandle *vp_handle;
71
72         /* runtime */
73         ARegion *ar;
74         const float *mval_fl;
75 };
76
77
78 /* -------------------------------------------------------------------- */
79 /* Internal Init */
80
81 static void vpaint_proj_dm_map_cosnos_init__map_cb(
82         void *userData, int index, const float co[3],
83         const float no_f[3], const short no_s[3])
84 {
85         struct VertProjHandle *vp_handle = userData;
86         DMCoNo *co_no = &vp_handle->vcosnos[index];
87
88         /* check if we've been here before (normal should not be 0) */
89         if (!is_zero_v3(co_no->no)) {
90                 /* remember that multiple dm verts share the same source vert */
91                 vp_handle->use_update = true;
92                 return;
93         }
94
95         copy_v3_v3(co_no->co, co);
96         if (no_f) {
97                 copy_v3_v3(co_no->no, no_f);
98         }
99         else {
100                 normal_short_to_float_v3(co_no->no, no_s);
101         }
102 }
103
104 static void vpaint_proj_dm_map_cosnos_init(
105         const struct EvaluationContext *eval_ctx, Scene *scene, Object *ob,
106         struct VertProjHandle *vp_handle)
107 {
108         Mesh *me = ob->data;
109         DerivedMesh *dm;
110
111         dm = mesh_get_derived_final(eval_ctx, scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX);
112
113         if (dm->foreachMappedVert) {
114                 memset(vp_handle->vcosnos, 0, sizeof(DMCoNo) * me->totvert);
115                 dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_init__map_cb, vp_handle, DM_FOREACH_USE_NORMAL);
116         }
117         else {
118                 DMCoNo *v_co_no = vp_handle->vcosnos;
119                 int a;
120                 for (a = 0; a < me->totvert; a++, v_co_no++) {
121                         dm->getVertCo(dm, a, v_co_no->co);
122                         dm->getVertNo(dm, a, v_co_no->no);
123                 }
124         }
125
126         dm->release(dm);
127 }
128
129
130 /* -------------------------------------------------------------------- */
131 /* Internal Update */
132
133 /* Same as init but take mouse location into account */
134
135 static void vpaint_proj_dm_map_cosnos_update__map_cb(
136         void *userData, int index, const float co[3],
137         const float no_f[3], const short no_s[3])
138 {
139         struct VertProjUpdate *vp_update = userData;
140         struct VertProjHandle *vp_handle = vp_update->vp_handle;
141
142         DMCoNo *co_no = &vp_handle->vcosnos[index];
143
144         /* find closest vertex */
145         {
146                 /* first find distance to this vertex */
147                 float co_ss[2];  /* screenspace */
148
149                 if (ED_view3d_project_float_object(
150                             vp_update->ar,
151                             co, co_ss,
152                             V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
153                 {
154                         const float dist_sq = len_squared_v2v2(vp_update->mval_fl, co_ss);
155                         if (dist_sq > vp_handle->dists_sq[index]) {
156                                 /* bail out! */
157                                 return;
158                         }
159
160                         vp_handle->dists_sq[index] = dist_sq;
161                 }
162                 else if (vp_handle->dists_sq[index] != FLT_MAX) {
163                         /* already initialized & couldn't project this 'co' */
164                         return;
165                 }
166         }
167         /* continue with regular functionality */
168
169         copy_v3_v3(co_no->co, co);
170         if (no_f) {
171                 copy_v3_v3(co_no->no, no_f);
172         }
173         else {
174                 normal_short_to_float_v3(co_no->no, no_s);
175         }
176 }
177
178 static void vpaint_proj_dm_map_cosnos_update(
179         const struct EvaluationContext *eval_ctx, struct VertProjHandle *vp_handle,
180         ARegion *ar, const float mval_fl[2])
181 {
182         struct VertProjUpdate vp_update = {vp_handle, ar, mval_fl};
183
184         Scene *scene = vp_handle->scene;
185         Object *ob = vp_handle->ob;
186         Mesh *me = ob->data;
187         DerivedMesh *dm;
188
189         /* quick sanity check - we shouldn't have to run this if there are no modifiers */
190         BLI_assert(BLI_listbase_is_empty(&ob->modifiers) == false);
191
192         dm = mesh_get_derived_final(eval_ctx, scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX);
193
194         /* highly unlikely this will become unavailable once painting starts (perhaps with animated modifiers) */
195         if (LIKELY(dm->foreachMappedVert)) {
196                 copy_vn_fl(vp_handle->dists_sq, me->totvert, FLT_MAX);
197
198                 dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_update__map_cb, &vp_update, DM_FOREACH_USE_NORMAL);
199         }
200
201         dm->release(dm);
202 }
203
204
205 /* -------------------------------------------------------------------- */
206 /* Public Functions */
207
208 struct VertProjHandle *ED_vpaint_proj_handle_create(
209         const struct EvaluationContext *eval_ctx, Scene *scene, Object *ob,
210         DMCoNo **r_vcosnos)
211 {
212         struct VertProjHandle *vp_handle = MEM_mallocN(sizeof(struct VertProjHandle), __func__);
213         Mesh *me = ob->data;
214
215         /* setup the handle */
216         vp_handle->vcosnos = MEM_mallocN(sizeof(DMCoNo) * me->totvert, "vertexcosnos map");
217         vp_handle->use_update = false;
218
219         /* sets 'use_update' if needed */
220         vpaint_proj_dm_map_cosnos_init(eval_ctx, scene, ob, vp_handle);
221
222         if (vp_handle->use_update) {
223                 vp_handle->dists_sq = MEM_mallocN(sizeof(float) * me->totvert, __func__);
224
225                 vp_handle->ob = ob;
226                 vp_handle->scene = scene;
227         }
228         else {
229                 vp_handle->dists_sq = NULL;
230
231                 vp_handle->ob = NULL;
232                 vp_handle->scene = NULL;
233         }
234
235         *r_vcosnos = vp_handle->vcosnos;
236         return vp_handle;
237 }
238
239 void  ED_vpaint_proj_handle_update(
240         const struct EvaluationContext *eval_ctx, struct VertProjHandle *vp_handle,
241         ARegion *ar, const float mval_fl[2])
242 {
243         if (vp_handle->use_update) {
244                 vpaint_proj_dm_map_cosnos_update(eval_ctx, vp_handle, ar, mval_fl);
245         }
246 }
247
248 void  ED_vpaint_proj_handle_free(struct VertProjHandle *vp_handle)
249 {
250         if (vp_handle->use_update) {
251                 MEM_freeN(vp_handle->dists_sq);
252         }
253
254         MEM_freeN(vp_handle->vcosnos);
255         MEM_freeN(vp_handle);
256 }