Cleanup: typo in last commit
[blender.git] / source / blender / modifiers / intern / MOD_uvproject.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software  Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup modifiers
22  */
23
24 /* UV Project modifier: Generates UVs projected from an object */
25
26 #include "BLI_utildefines.h"
27
28 #include "BLI_math.h"
29 #include "BLI_uvproject.h"
30
31 #include "DNA_mesh_types.h"
32 #include "DNA_meshdata_types.h"
33 #include "DNA_camera_types.h"
34 #include "DNA_object_types.h"
35
36 #include "BKE_camera.h"
37 #include "BKE_library_query.h"
38 #include "BKE_material.h"
39 #include "BKE_mesh.h"
40
41 #include "MOD_modifiertypes.h"
42
43 #include "MEM_guardedalloc.h"
44
45 #include "DEG_depsgraph.h"
46 #include "DEG_depsgraph_build.h"
47 #include "DEG_depsgraph_query.h"
48
49 static void initData(ModifierData *md)
50 {
51   UVProjectModifierData *umd = (UVProjectModifierData *)md;
52
53   umd->num_projectors = 1;
54   umd->aspectx = umd->aspecty = 1.0f;
55   umd->scalex = umd->scaley = 1.0f;
56 }
57
58 static void requiredDataMask(Object *UNUSED(ob),
59                              ModifierData *UNUSED(md),
60                              CustomData_MeshMasks *r_cddata_masks)
61 {
62   /* ask for UV coordinates */
63   r_cddata_masks->lmask |= CD_MLOOPUV;
64 }
65
66 static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
67 {
68   UVProjectModifierData *umd = (UVProjectModifierData *)md;
69   int i;
70
71   for (i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i) {
72     walk(userData, ob, &umd->projectors[i], IDWALK_CB_NOP);
73   }
74 }
75
76 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
77 {
78 #if 0
79   UVProjectModifierData *umd = (UVProjectModifierData *)md;
80 #endif
81
82   foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
83 }
84
85 static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
86 {
87   UVProjectModifierData *umd = (UVProjectModifierData *)md;
88   bool do_add_own_transform = false;
89   for (int i = 0; i < umd->num_projectors; ++i) {
90     if (umd->projectors[i] != NULL) {
91       DEG_add_object_relation(
92           ctx->node, umd->projectors[i], DEG_OB_COMP_TRANSFORM, "UV Project Modifier");
93       do_add_own_transform = true;
94     }
95   }
96   if (do_add_own_transform) {
97     DEG_add_modifier_to_transform_relation(ctx->node, "UV Project Modifier");
98   }
99 }
100
101 typedef struct Projector {
102   Object *ob;          /* object this projector is derived from */
103   float projmat[4][4]; /* projection matrix */
104   float normal[3];     /* projector normal in world space */
105   void *uci;           /* optional uv-project info (panorama projection) */
106 } Projector;
107
108 static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
109                                   const ModifierEvalContext *UNUSED(ctx),
110                                   Object *ob,
111                                   Mesh *mesh)
112 {
113   float(*coords)[3], (*co)[3];
114   MLoopUV *mloop_uv;
115   int i, numVerts, numPolys, numLoops;
116   MPoly *mpoly, *mp;
117   MLoop *mloop;
118   Projector projectors[MOD_UVPROJECT_MAXPROJECTORS];
119   int num_projectors = 0;
120   char uvname[MAX_CUSTOMDATA_LAYER_NAME];
121   float aspx = umd->aspectx ? umd->aspectx : 1.0f;
122   float aspy = umd->aspecty ? umd->aspecty : 1.0f;
123   float scax = umd->scalex ? umd->scalex : 1.0f;
124   float scay = umd->scaley ? umd->scaley : 1.0f;
125   int free_uci = 0;
126
127   for (i = 0; i < umd->num_projectors; ++i) {
128     if (umd->projectors[i] != NULL) {
129       projectors[num_projectors++].ob = umd->projectors[i];
130     }
131   }
132
133   if (num_projectors == 0) {
134     return mesh;
135   }
136
137   /* make sure there are UV Maps available */
138
139   if (!CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) {
140     return mesh;
141   }
142
143   /* make sure we're using an existing layer */
144   CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, umd->uvlayer_name, uvname);
145
146   /* calculate a projection matrix and normal for each projector */
147   for (i = 0; i < num_projectors; ++i) {
148     float tmpmat[4][4];
149     float offsetmat[4][4];
150     Camera *cam = NULL;
151     /* calculate projection matrix */
152     invert_m4_m4(projectors[i].projmat, projectors[i].ob->obmat);
153
154     projectors[i].uci = NULL;
155
156     if (projectors[i].ob->type == OB_CAMERA) {
157       cam = (Camera *)projectors[i].ob->data;
158       if (cam->type == CAM_PANO) {
159         projectors[i].uci = BLI_uvproject_camera_info(projectors[i].ob, NULL, aspx, aspy);
160         BLI_uvproject_camera_info_scale(projectors[i].uci, scax, scay);
161         free_uci = 1;
162       }
163       else {
164         CameraParams params;
165
166         /* setup parameters */
167         BKE_camera_params_init(&params);
168         BKE_camera_params_from_object(&params, projectors[i].ob);
169
170         /* compute matrix, viewplane, .. */
171         BKE_camera_params_compute_viewplane(&params, 1, 1, aspx, aspy);
172
173         /* scale the view-plane */
174         params.viewplane.xmin *= scax;
175         params.viewplane.xmax *= scax;
176         params.viewplane.ymin *= scay;
177         params.viewplane.ymax *= scay;
178
179         BKE_camera_params_compute_matrix(&params);
180         mul_m4_m4m4(tmpmat, params.winmat, projectors[i].projmat);
181       }
182     }
183     else {
184       copy_m4_m4(tmpmat, projectors[i].projmat);
185     }
186
187     unit_m4(offsetmat);
188     mul_mat3_m4_fl(offsetmat, 0.5);
189     offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5;
190
191     mul_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat);
192
193     /* calculate worldspace projector normal (for best projector test) */
194     projectors[i].normal[0] = 0;
195     projectors[i].normal[1] = 0;
196     projectors[i].normal[2] = 1;
197     mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal);
198   }
199
200   numPolys = mesh->totpoly;
201   numLoops = mesh->totloop;
202
203   /* make sure we are not modifying the original UV map */
204   mloop_uv = CustomData_duplicate_referenced_layer_named(
205       &mesh->ldata, CD_MLOOPUV, uvname, numLoops);
206
207   coords = BKE_mesh_vert_coords_alloc(mesh, &numVerts);
208
209   /* convert coords to world space */
210   for (i = 0, co = coords; i < numVerts; ++i, ++co) {
211     mul_m4_v3(ob->obmat, *co);
212   }
213
214   /* if only one projector, project coords to UVs */
215   if (num_projectors == 1 && projectors[0].uci == NULL) {
216     for (i = 0, co = coords; i < numVerts; ++i, ++co) {
217       mul_project_m4_v3(projectors[0].projmat, *co);
218     }
219   }
220
221   mpoly = mesh->mpoly;
222   mloop = mesh->mloop;
223
224   /* apply coords as UVs */
225   for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) {
226     if (num_projectors == 1) {
227       if (projectors[0].uci) {
228         unsigned int fidx = mp->totloop - 1;
229         do {
230           unsigned int lidx = mp->loopstart + fidx;
231           unsigned int vidx = mloop[lidx].v;
232           BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci);
233         } while (fidx--);
234       }
235       else {
236         /* apply transformed coords as UVs */
237         unsigned int fidx = mp->totloop - 1;
238         do {
239           unsigned int lidx = mp->loopstart + fidx;
240           unsigned int vidx = mloop[lidx].v;
241           copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]);
242         } while (fidx--);
243       }
244     }
245     else {
246       /* multiple projectors, select the closest to face normal direction */
247       float face_no[3];
248       int j;
249       Projector *best_projector;
250       float best_dot;
251
252       /* get the untransformed face normal */
253       BKE_mesh_calc_poly_normal_coords(
254           mp, mloop + mp->loopstart, (const float(*)[3])coords, face_no);
255
256       /* find the projector which the face points at most directly
257        * (projector normal with largest dot product is best)
258        */
259       best_dot = dot_v3v3(projectors[0].normal, face_no);
260       best_projector = &projectors[0];
261
262       for (j = 1; j < num_projectors; ++j) {
263         float tmp_dot = dot_v3v3(projectors[j].normal, face_no);
264         if (tmp_dot > best_dot) {
265           best_dot = tmp_dot;
266           best_projector = &projectors[j];
267         }
268       }
269
270       if (best_projector->uci) {
271         unsigned int fidx = mp->totloop - 1;
272         do {
273           unsigned int lidx = mp->loopstart + fidx;
274           unsigned int vidx = mloop[lidx].v;
275           BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci);
276         } while (fidx--);
277       }
278       else {
279         unsigned int fidx = mp->totloop - 1;
280         do {
281           unsigned int lidx = mp->loopstart + fidx;
282           unsigned int vidx = mloop[lidx].v;
283           mul_v2_project_m4_v3(mloop_uv[lidx].uv, best_projector->projmat, coords[vidx]);
284         } while (fidx--);
285       }
286     }
287   }
288
289   MEM_freeN(coords);
290
291   if (free_uci) {
292     int j;
293     for (j = 0; j < num_projectors; ++j) {
294       if (projectors[j].uci) {
295         MEM_freeN(projectors[j].uci);
296       }
297     }
298   }
299
300   /* Mark tessellated CD layers as dirty. */
301   mesh->runtime.cd_dirty_vert |= CD_MASK_TESSLOOPNORMAL;
302
303   return mesh;
304 }
305
306 static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
307 {
308   Mesh *result;
309   UVProjectModifierData *umd = (UVProjectModifierData *)md;
310
311   result = uvprojectModifier_do(umd, ctx, ctx->object, mesh);
312
313   return result;
314 }
315
316 ModifierTypeInfo modifierType_UVProject = {
317     /* name */ "UVProject",
318     /* structName */ "UVProjectModifierData",
319     /* structSize */ sizeof(UVProjectModifierData),
320     /* type */ eModifierTypeType_NonGeometrical,
321     /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
322         eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode,
323
324     /* copyData */ modifier_copyData_generic,
325
326     /* deformVerts */ NULL,
327     /* deformMatrices */ NULL,
328     /* deformVertsEM */ NULL,
329     /* deformMatricesEM */ NULL,
330     /* applyModifier */ applyModifier,
331
332     /* initData */ initData,
333     /* requiredDataMask */ requiredDataMask,
334     /* freeData */ NULL,
335     /* isDisabled */ NULL,
336     /* updateDepsgraph */ updateDepsgraph,
337     /* dependsOnTime */ NULL,
338     /* dependsOnNormals */ NULL,
339     /* foreachObjectLink */ foreachObjectLink,
340     /* foreachIDLink */ foreachIDLink,
341     /* foreachTexLink */ NULL,
342     /* freeRuntimeData */ NULL,
343 };