svn merge ^/trunk/blender -r42761:42776
[blender-staging.git] / source / blender / modifiers / intern / MOD_uvproject.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) 2005 by the Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Daniel Dunbar
22  *                 Ton Roosendaal,
23  *                 Ben Batt,
24  *                 Brecht Van Lommel,
25  *                 Campbell Barton
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  *
29  */
30
31 /** \file blender/modifiers/intern/MOD_uvproject.c
32  *  \ingroup modifiers
33  */
34
35
36 /* UV Project modifier: Generates UVs projected from an object */
37
38 #include "DNA_meshdata_types.h"
39 #include "DNA_camera_types.h"
40 #include "DNA_object_types.h"
41 #include "DNA_scene_types.h"
42
43 #include "BLI_math.h"
44 #include "BLI_string.h"
45 #include "BLI_uvproject.h"
46 #include "BLI_utildefines.h"
47
48
49 #include "BKE_camera.h"
50 #include "BKE_DerivedMesh.h"
51
52 #include "MOD_modifiertypes.h"
53 #include "MOD_util.h"
54
55 #include "MEM_guardedalloc.h"
56 #include "depsgraph_private.h"
57
58 static void initData(ModifierData *md)
59 {
60         UVProjectModifierData *umd = (UVProjectModifierData*) md;
61         int i;
62
63         for(i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i)
64                 umd->projectors[i] = NULL;
65         umd->image = NULL;
66         umd->flags = 0;
67         umd->num_projectors = 1;
68         umd->aspectx = umd->aspecty = 1.0f;
69         umd->scalex = umd->scaley = 1.0f;
70 }
71
72 static void copyData(ModifierData *md, ModifierData *target)
73 {
74         UVProjectModifierData *umd = (UVProjectModifierData*) md;
75         UVProjectModifierData *tumd = (UVProjectModifierData*) target;
76         int i;
77
78         for(i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i)
79                 tumd->projectors[i] = umd->projectors[i];
80         tumd->image = umd->image;
81         tumd->flags = umd->flags;
82         tumd->num_projectors = umd->num_projectors;
83         tumd->aspectx = umd->aspectx;
84         tumd->aspecty = umd->aspecty;
85         tumd->scalex = umd->scalex;
86         tumd->scaley = umd->scaley;
87         BLI_strncpy(tumd->uvlayer_name, umd->uvlayer_name, sizeof(umd->uvlayer_name));
88 }
89
90 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md))
91 {
92         CustomDataMask dataMask = 0;
93
94         /* ask for UV coordinates */
95         dataMask |= CD_MASK_MTFACE;
96
97         return dataMask;
98 }
99
100 static void foreachObjectLink(ModifierData *md, Object *ob,
101                 ObjectWalkFunc walk, void *userData)
102 {
103         UVProjectModifierData *umd = (UVProjectModifierData*) md;
104         int i;
105
106         for(i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i)
107                 walk(userData, ob, &umd->projectors[i]);
108 }
109
110 static void foreachIDLink(ModifierData *md, Object *ob,
111                                                 IDWalkFunc walk, void *userData)
112 {
113         UVProjectModifierData *umd = (UVProjectModifierData*) md;
114
115         walk(userData, ob, (ID **)&umd->image);
116
117         foreachObjectLink(md, ob, (ObjectWalkFunc)walk,
118                                                 userData);
119 }
120
121 static void updateDepgraph(ModifierData *md, DagForest *forest,
122                                                 struct Scene *UNUSED(scene),
123                                                 Object *UNUSED(ob),
124                                                 DagNode *obNode)
125 {
126         UVProjectModifierData *umd = (UVProjectModifierData*) md;
127         int i;
128
129         for(i = 0; i < umd->num_projectors; ++i) {
130                 if(umd->projectors[i]) {
131                         DagNode *curNode = dag_get_node(forest, umd->projectors[i]);
132
133                         dag_add_relation(forest, curNode, obNode,
134                                          DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "UV Project Modifier");
135                 }
136         }
137 }
138
139 typedef struct Projector {
140         Object *ob;                             /* object this projector is derived from */
141         float projmat[4][4];    /* projection matrix */ 
142         float normal[3];                /* projector normal in world space */
143         void *uci;                              /* optional uv-project info (panorama projection) */
144 } Projector;
145
146 static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
147                                          Object *ob, DerivedMesh *dm)
148 {
149         float (*coords)[3], (*co)[3];
150         MTFace *tface;
151         int i, numVerts, numFaces;
152         Image *image = umd->image;
153         MFace *mface, *mf;
154         int override_image = ((umd->flags & MOD_UVPROJECT_OVERRIDEIMAGE) != 0);
155         Projector projectors[MOD_UVPROJECT_MAXPROJECTORS];
156         int num_projectors = 0;
157         float aspect;
158         char uvname[32];
159         float aspx= umd->aspectx ? umd->aspectx : 1.0f;
160         float aspy= umd->aspecty ? umd->aspecty : 1.0f;
161         float scax= umd->scalex ? umd->scalex : 1.0f;
162         float scay= umd->scaley ? umd->scaley : 1.0f;
163         int free_uci= 0;
164
165         aspect = aspx / aspy;
166
167         for(i = 0; i < umd->num_projectors; ++i)
168                 if(umd->projectors[i])
169                         projectors[num_projectors++].ob = umd->projectors[i];
170
171         if(num_projectors == 0) return dm;
172
173         /* make sure there are UV Maps available */
174
175         if(!CustomData_has_layer(&dm->faceData, CD_MTFACE)) return dm;
176
177         /* make sure we're using an existing layer */
178         CustomData_validate_layer_name(&dm->faceData, CD_MTFACE, umd->uvlayer_name, uvname);
179
180         /* calculate a projection matrix and normal for each projector */
181         for(i = 0; i < num_projectors; ++i) {
182                 float tmpmat[4][4];
183                 float offsetmat[4][4];
184                 Camera *cam = NULL;
185                 /* calculate projection matrix */
186                 invert_m4_m4(projectors[i].projmat, projectors[i].ob->obmat);
187
188                 projectors[i].uci= NULL;
189
190                 if(projectors[i].ob->type == OB_CAMERA) {
191                         
192                         cam = (Camera *)projectors[i].ob->data;
193                         if(cam->flag & CAM_PANORAMA) {
194                                 projectors[i].uci= project_camera_info(projectors[i].ob, NULL, aspx, aspy);
195                                 project_camera_info_scale(projectors[i].uci, scax, scay);
196                                 free_uci= 1;
197                         }
198                         else {
199                                 float sensor= camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
200                                 int sensor_fit= camera_sensor_fit(cam->sensor_fit, aspx, aspy);
201                                 float scale= (cam->type == CAM_PERSP) ? cam->clipsta * sensor / cam->lens : cam->ortho_scale;
202                                 float xmax, xmin, ymax, ymin;
203
204                                 if(sensor_fit==CAMERA_SENSOR_FIT_HOR) {
205                                         xmax = 0.5f * scale;
206                                         ymax = xmax / aspect;
207                                 }
208                                 else {
209                                         ymax = 0.5f * scale;
210                                         xmax = ymax * aspect;
211                                 }
212
213                                 xmin = -xmax;
214                                 ymin = -ymax;
215
216                                 /* scale the matrix */
217                                 xmin *= scax;
218                                 xmax *= scax;
219                                 ymin *= scay;
220                                 ymax *= scay;
221
222                                 if(cam->type == CAM_PERSP) {
223                                         float perspmat[4][4];
224                                         perspective_m4( perspmat,xmin, xmax, ymin, ymax, cam->clipsta, cam->clipend);
225                                         mult_m4_m4m4(tmpmat, perspmat, projectors[i].projmat);
226                                 } else { /* if(cam->type == CAM_ORTHO) */
227                                         float orthomat[4][4];
228                                         orthographic_m4( orthomat,xmin, xmax, ymin, ymax, cam->clipsta, cam->clipend);
229                                         mult_m4_m4m4(tmpmat, orthomat, projectors[i].projmat);
230                                 }
231                         }
232                 } else {
233                         copy_m4_m4(tmpmat, projectors[i].projmat);
234                 }
235
236                 unit_m4(offsetmat);
237                 mul_mat3_m4_fl(offsetmat, 0.5);
238                 offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5;
239                 
240                 if (cam) {
241                         if (aspx == aspy) { 
242                                 offsetmat[3][0] -= cam->shiftx;
243                                 offsetmat[3][1] -= cam->shifty;
244                         } else if (aspx < aspy)  {
245                                 offsetmat[3][0] -=(cam->shiftx * aspy/aspx);
246                                 offsetmat[3][1] -= cam->shifty;
247                         } else {
248                                 offsetmat[3][0] -= cam->shiftx;
249                                 offsetmat[3][1] -=(cam->shifty * aspx/aspy);
250                         }
251                 }
252                 
253                 mult_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat);
254
255                 /* calculate worldspace projector normal (for best projector test) */
256                 projectors[i].normal[0] = 0;
257                 projectors[i].normal[1] = 0;
258                 projectors[i].normal[2] = 1;
259                 mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal);
260         }
261
262         numFaces = dm->getNumTessFaces(dm);
263
264         /* make sure we are not modifying the original UV map */
265         tface = CustomData_duplicate_referenced_layer_named(&dm->faceData,
266                         CD_MTFACE, uvname, numFaces);
267
268         numVerts = dm->getNumVerts(dm);
269
270         coords = MEM_callocN(sizeof(*coords) * numVerts,
271                                  "uvprojectModifier_do coords");
272         dm->getVertCos(dm, coords);
273
274         /* convert coords to world space */
275         for(i = 0, co = coords; i < numVerts; ++i, ++co)
276                 mul_m4_v3(ob->obmat, *co);
277         
278         /* if only one projector, project coords to UVs */
279         if(num_projectors == 1 && projectors[0].uci==NULL)
280                 for(i = 0, co = coords; i < numVerts; ++i, ++co)
281                         mul_project_m4_v3(projectors[0].projmat, *co);
282
283         mface = dm->getTessFaceArray(dm);
284         numFaces = dm->getNumTessFaces(dm);
285
286         /* apply coords as UVs, and apply image if tfaces are new */
287         for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tface) {
288                 if(override_image || !image || tface->tpage == image) {
289                         if(num_projectors == 1) {
290                                 if(projectors[0].uci) {
291                                         project_from_camera(tface->uv[0], coords[mf->v1], projectors[0].uci);
292                                         project_from_camera(tface->uv[1], coords[mf->v2], projectors[0].uci);
293                                         project_from_camera(tface->uv[2], coords[mf->v3], projectors[0].uci);
294                                         if(mf->v4)
295                                                 project_from_camera(tface->uv[3], coords[mf->v4], projectors[0].uci);
296                                 }
297                                 else {
298                                         /* apply transformed coords as UVs */
299                                         copy_v2_v2(tface->uv[0], coords[mf->v1]);
300                                         copy_v2_v2(tface->uv[1], coords[mf->v2]);
301                                         copy_v2_v2(tface->uv[2], coords[mf->v3]);
302                                         if (mf->v4) {
303                                                 copy_v2_v2(tface->uv[3], coords[mf->v4]);
304                                         }
305                                 }
306                         } else {
307                                 /* multiple projectors, select the closest to face normal
308                                 * direction
309                                 */
310                                 float co1[3], co2[3], co3[3], co4[3];
311                                 float face_no[3];
312                                 int j;
313                                 Projector *best_projector;
314                                 float best_dot;
315
316                                 copy_v3_v3(co1, coords[mf->v1]);
317                                 copy_v3_v3(co2, coords[mf->v2]);
318                                 copy_v3_v3(co3, coords[mf->v3]);
319
320                                 /* get the untransformed face normal */
321                                 if(mf->v4) {
322                                         copy_v3_v3(co4, coords[mf->v4]);
323                                         normal_quad_v3(face_no, co1, co2, co3, co4);
324                                 } else { 
325                                         normal_tri_v3(face_no, co1, co2, co3);
326                                 }
327
328                                 /* find the projector which the face points at most directly
329                                 * (projector normal with largest dot product is best)
330                                 */
331                                 best_dot = dot_v3v3(projectors[0].normal, face_no);
332                                 best_projector = &projectors[0];
333
334                                 for(j = 1; j < num_projectors; ++j) {
335                                         float tmp_dot = dot_v3v3(projectors[j].normal,
336                                                         face_no);
337                                         if(tmp_dot > best_dot) {
338                                                 best_dot = tmp_dot;
339                                                 best_projector = &projectors[j];
340                                         }
341                                 }
342
343                                 if(best_projector->uci) {
344                                         project_from_camera(tface->uv[0], coords[mf->v1], best_projector->uci);
345                                         project_from_camera(tface->uv[1], coords[mf->v2], best_projector->uci);
346                                         project_from_camera(tface->uv[2], coords[mf->v3], best_projector->uci);
347                                         if(mf->v4)
348                                                 project_from_camera(tface->uv[3], coords[mf->v4], best_projector->uci);
349                                 }
350                                 else {
351                                         mul_project_m4_v3(best_projector->projmat, co1);
352                                         mul_project_m4_v3(best_projector->projmat, co2);
353                                         mul_project_m4_v3(best_projector->projmat, co3);
354                                         if(mf->v4)
355                                                 mul_project_m4_v3(best_projector->projmat, co4);
356
357                                         /* apply transformed coords as UVs */
358                                         copy_v2_v2(tface->uv[0], co1);
359                                         copy_v2_v2(tface->uv[1], co2);
360                                         copy_v2_v2(tface->uv[2], co3);
361                                         if (mf->v4) {
362                                                 copy_v2_v2(tface->uv[3], co4);
363                                         }
364                                 }
365                         }
366                 }
367
368                 if(override_image) {
369                         tface->tpage = image;
370                 }
371         }
372
373         MEM_freeN(coords);
374         
375         if(free_uci) {
376                 int j;
377                 for(j = 0; j < num_projectors; ++j) {
378                         if(projectors[j].uci) {
379                                 MEM_freeN(projectors[j].uci);
380                         }
381                 }
382         }
383         return dm;
384 }
385
386 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
387                                                 DerivedMesh *derivedData,
388                                                 int UNUSED(useRenderParams),
389                                                 int UNUSED(isFinalCalc))
390 {
391         DerivedMesh *result;
392         UVProjectModifierData *umd = (UVProjectModifierData*) md;
393
394         result = uvprojectModifier_do(umd, ob, derivedData);
395
396         return result;
397 }
398
399 static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
400                                                 struct BMEditMesh *UNUSED(editData),
401                                                 DerivedMesh *derivedData)
402 {
403         return applyModifier(md, ob, derivedData, 0, 1);
404 }
405
406
407 ModifierTypeInfo modifierType_UVProject = {
408         /* name */              "UVProject",
409         /* structName */        "UVProjectModifierData",
410         /* structSize */        sizeof(UVProjectModifierData),
411         /* type */              eModifierTypeType_NonGeometrical,
412         /* flags */             eModifierTypeFlag_AcceptsMesh
413                                                         | eModifierTypeFlag_SupportsMapping
414                                                         | eModifierTypeFlag_SupportsEditmode
415                                                         | eModifierTypeFlag_EnableInEditmode,
416
417         /* copyData */          copyData,
418         /* deformVerts */       NULL,
419         /* deformMatrices */    NULL,
420         /* deformVertsEM */     NULL,
421         /* deformMatricesEM */  NULL,
422         /* applyModifier */     applyModifier,
423         /* applyModifierEM */   applyModifierEM,
424         /* initData */          initData,
425         /* requiredDataMask */  requiredDataMask,
426         /* freeData */          NULL,
427         /* isDisabled */        NULL,
428         /* updateDepgraph */    updateDepgraph,
429         /* dependsOnTime */     NULL,
430         /* dependsOnNormals */  NULL,
431         /* foreachObjectLink */ foreachObjectLink,
432         /* foreachIDLink */     foreachIDLink,
433         /* foreachTexLink */    NULL,
434 };