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