TexFace to Material Settings big patch
[blender.git] / source / blender / modifiers / intern / MOD_uvproject.c
1 /*
2 * $Id$
3 *
4 * ***** BEGIN GPL LICENSE BLOCK *****
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software  Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 * The Original Code is Copyright (C) 2005 by the Blender Foundation.
21 * All rights reserved.
22 *
23 * Contributor(s): Daniel Dunbar
24 *                 Ton Roosendaal,
25 *                 Ben Batt,
26 *                 Brecht Van Lommel,
27 *                 Campbell Barton
28 *
29 * ***** END GPL LICENSE BLOCK *****
30 *
31 */
32
33 /** \file blender/modifiers/intern/MOD_uvproject.c
34  *  \ingroup modifiers
35  */
36
37
38 /* UV Project modifier: Generates UVs projected from an object */
39
40 #include "DNA_meshdata_types.h"
41 #include "DNA_camera_types.h"
42 #include "DNA_object_types.h"
43
44 #include "BLI_math.h"
45 #include "BLI_string.h"
46 #include "BLI_uvproject.h"
47 #include "BLI_utildefines.h"
48
49
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 layers available */
174
175         if(!CustomData_has_layer(&dm->faceData, CD_MTFACE)) return dm;
176
177         /* make sure we're using an existing layer */
178         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 scale= (cam->type == CAM_PERSP) ? cam->clipsta * 32.0f / cam->lens : cam->ortho_scale;
200                                 float xmax, xmin, ymax, ymin;
201
202                                 if(aspect > 1.0f) {
203                                         xmax = 0.5f * scale;
204                                         ymax = xmax / aspect;
205                                 } else {
206                                         ymax = 0.5f * scale;
207                                         xmax = ymax * aspect;
208                                 }
209                                 xmin = -xmax;
210                                 ymin = -ymax;
211
212                                 /* scale the matrix */
213                                 xmin *= scax;
214                                 xmax *= scax;
215                                 ymin *= scay;
216                                 ymax *= scay;
217
218                                 if(cam->type == CAM_PERSP) {
219                                         float perspmat[4][4];
220                                         perspective_m4( perspmat,xmin, xmax, ymin, ymax, cam->clipsta, cam->clipend);
221                                         mul_m4_m4m4(tmpmat, projectors[i].projmat, perspmat);
222                                 } else { /* if(cam->type == CAM_ORTHO) */
223                                         float orthomat[4][4];
224                                         orthographic_m4( orthomat,xmin, xmax, ymin, ymax, cam->clipsta, cam->clipend);
225                                         mul_m4_m4m4(tmpmat, projectors[i].projmat, orthomat);
226                                 }
227                         }
228                 } else {
229                         copy_m4_m4(tmpmat, projectors[i].projmat);
230                 }
231
232                 unit_m4(offsetmat);
233                 mul_mat3_m4_fl(offsetmat, 0.5);
234                 offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5;
235                 
236                 if (cam) {
237                         if (aspx == aspy) { 
238                                 offsetmat[3][0] -= cam->shiftx;
239                                 offsetmat[3][1] -= cam->shifty;
240                         } else if (aspx < aspy)  {
241                                 offsetmat[3][0] -=(cam->shiftx * aspy/aspx);
242                                 offsetmat[3][1] -= cam->shifty;
243                         } else {
244                                 offsetmat[3][0] -= cam->shiftx;
245                                 offsetmat[3][1] -=(cam->shifty * aspx/aspy);
246                         }
247                 }
248                 
249                 mul_m4_m4m4(projectors[i].projmat, tmpmat, offsetmat);
250
251                 /* calculate worldspace projector normal (for best projector test) */
252                 projectors[i].normal[0] = 0;
253                 projectors[i].normal[1] = 0;
254                 projectors[i].normal[2] = 1;
255                 mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal);
256         }
257
258         /* make sure we are not modifying the original UV layer */
259         tface = CustomData_duplicate_referenced_layer_named(&dm->faceData,
260                         CD_MTFACE, uvname);
261
262         
263         numVerts = dm->getNumVerts(dm);
264
265         coords = MEM_callocN(sizeof(*coords) * numVerts,
266                                  "uvprojectModifier_do coords");
267         dm->getVertCos(dm, coords);
268
269         /* convert coords to world space */
270         for(i = 0, co = coords; i < numVerts; ++i, ++co)
271                 mul_m4_v3(ob->obmat, *co);
272         
273         /* if only one projector, project coords to UVs */
274         if(num_projectors == 1 && projectors[0].uci==NULL)
275                 for(i = 0, co = coords; i < numVerts; ++i, ++co)
276                         mul_project_m4_v3(projectors[0].projmat, *co);
277
278         mface = dm->getFaceArray(dm);
279         numFaces = dm->getNumFaces(dm);
280
281         /* apply coords as UVs, and apply image if tfaces are new */
282         for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tface) {
283                 if(override_image || !image || tface->tpage == image) {
284                         if(num_projectors == 1) {
285                                 if(projectors[0].uci) {
286                                         project_from_camera(tface->uv[0], coords[mf->v1], projectors[0].uci);
287                                         project_from_camera(tface->uv[1], coords[mf->v2], projectors[0].uci);
288                                         project_from_camera(tface->uv[2], coords[mf->v3], projectors[0].uci);
289                                         if(mf->v3)
290                                                 project_from_camera(tface->uv[3], coords[mf->v4], projectors[0].uci);
291                                 }
292                                 else {
293                                         /* apply transformed coords as UVs */
294                                         tface->uv[0][0] = coords[mf->v1][0];
295                                         tface->uv[0][1] = coords[mf->v1][1];
296                                         tface->uv[1][0] = coords[mf->v2][0];
297                                         tface->uv[1][1] = coords[mf->v2][1];
298                                         tface->uv[2][0] = coords[mf->v3][0];
299                                         tface->uv[2][1] = coords[mf->v3][1];
300                                         if(mf->v4) {
301                                                 tface->uv[3][0] = coords[mf->v4][0];
302                                                 tface->uv[3][1] = coords[mf->v4][1];
303                                         }
304                                 }
305                         } else {
306                                 /* multiple projectors, select the closest to face normal
307                                 * direction
308                                 */
309                                 float co1[3], co2[3], co3[3], co4[3];
310                                 float face_no[3];
311                                 int j;
312                                 Projector *best_projector;
313                                 float best_dot;
314
315                                 copy_v3_v3(co1, coords[mf->v1]);
316                                 copy_v3_v3(co2, coords[mf->v2]);
317                                 copy_v3_v3(co3, coords[mf->v3]);
318
319                                 /* get the untransformed face normal */
320                                 if(mf->v4) {
321                                         copy_v3_v3(co4, coords[mf->v4]);
322                                         normal_quad_v3(face_no, co1, co2, co3, co4);
323                                 } else { 
324                                         normal_tri_v3(face_no, co1, co2, co3);
325                                 }
326
327                                 /* find the projector which the face points at most directly
328                                 * (projector normal with largest dot product is best)
329                                 */
330                                 best_dot = dot_v3v3(projectors[0].normal, face_no);
331                                 best_projector = &projectors[0];
332
333                                 for(j = 1; j < num_projectors; ++j) {
334                                         float tmp_dot = dot_v3v3(projectors[j].normal,
335                                                         face_no);
336                                         if(tmp_dot > best_dot) {
337                                                 best_dot = tmp_dot;
338                                                 best_projector = &projectors[j];
339                                         }
340                                 }
341
342                                 if(best_projector->uci) {
343                                         project_from_camera(tface->uv[0], coords[mf->v1], best_projector->uci);
344                                         project_from_camera(tface->uv[1], coords[mf->v2], best_projector->uci);
345                                         project_from_camera(tface->uv[2], coords[mf->v3], best_projector->uci);
346                                         if(mf->v3)
347                                                 project_from_camera(tface->uv[3], coords[mf->v4], best_projector->uci);
348                                 }
349                                 else {
350                                         mul_project_m4_v3(best_projector->projmat, co1);
351                                         mul_project_m4_v3(best_projector->projmat, co2);
352                                         mul_project_m4_v3(best_projector->projmat, co3);
353                                         if(mf->v4)
354                                                 mul_project_m4_v3(best_projector->projmat, co4);
355
356                                         /* apply transformed coords as UVs */
357                                         tface->uv[0][0] = co1[0];
358                                         tface->uv[0][1] = co1[1];
359                                         tface->uv[1][0] = co2[0];
360                                         tface->uv[1][1] = co2[1];
361                                         tface->uv[2][0] = co3[0];
362                                         tface->uv[2][1] = co3[1];
363                                         if(mf->v4) {
364                                                 tface->uv[3][0] = co4[0];
365                                                 tface->uv[3][1] = co4[1];
366                                         }
367                                 }
368                         }
369                 }
370
371                 if(override_image) {
372                         tface->tpage = image;
373                 }
374         }
375
376         MEM_freeN(coords);
377         
378         if(free_uci) {
379                 int j;
380                 for(j = 0; j < num_projectors; ++j) {
381                         if(projectors[j].uci) {
382                                 MEM_freeN(projectors[j].uci);
383                         }
384                 }
385         }
386         return dm;
387 }
388
389 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
390                                                 DerivedMesh *derivedData,
391                                                 int UNUSED(useRenderParams),
392                                                 int UNUSED(isFinalCalc))
393 {
394         DerivedMesh *result;
395         UVProjectModifierData *umd = (UVProjectModifierData*) md;
396
397         result = uvprojectModifier_do(umd, ob, derivedData);
398
399         return result;
400 }
401
402 static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
403                                                 struct EditMesh *UNUSED(editData),
404                                                 DerivedMesh *derivedData)
405 {
406         return applyModifier(md, ob, derivedData, 0, 1);
407 }
408
409
410 ModifierTypeInfo modifierType_UVProject = {
411         /* name */              "UVProject",
412         /* structName */        "UVProjectModifierData",
413         /* structSize */        sizeof(UVProjectModifierData),
414         /* type */              eModifierTypeType_Nonconstructive,
415         /* flags */             eModifierTypeFlag_AcceptsMesh
416                                                         | eModifierTypeFlag_SupportsMapping
417                                                         | eModifierTypeFlag_SupportsEditmode
418                                                         | eModifierTypeFlag_EnableInEditmode,
419
420         /* copyData */          copyData,
421         /* deformVerts */       NULL,
422         /* deformMatrices */    NULL,
423         /* deformVertsEM */     NULL,
424         /* deformMatricesEM */  NULL,
425         /* applyModifier */     applyModifier,
426         /* applyModifierEM */   applyModifierEM,
427         /* initData */          initData,
428         /* requiredDataMask */  requiredDataMask,
429         /* freeData */          NULL,
430         /* isDisabled */        NULL,
431         /* updateDepgraph */    updateDepgraph,
432         /* dependsOnTime */     NULL,
433         /* dependsOnNormals */  NULL,
434         /* foreachObjectLink */ foreachObjectLink,
435         /* foreachIDLink */     foreachIDLink,
436         /* foreachTexLink */    NULL,
437 };