Blender  V2.59
MOD_wave.c
Go to the documentation of this file.
00001 /*
00002 * $Id: MOD_wave.c 38300 2011-07-11 09:15:20Z blendix $
00003 *
00004 * ***** BEGIN GPL LICENSE BLOCK *****
00005 *
00006 * This program is free software; you can redistribute it and/or
00007 * modify it under the terms of the GNU General Public License
00008 * as published by the Free Software Foundation; either version 2
00009 * of the License, or (at your option) any later version.
00010 *
00011 * This program is distributed in the hope that it will be useful,
00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 * GNU General Public License for more details.
00015 *
00016 * You should have received a copy of the GNU General Public License
00017 * along with this program; if not, write to the Free Software  Foundation,
00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 *
00020 * The Original Code is Copyright (C) 2005 by the Blender Foundation.
00021 * All rights reserved.
00022 *
00023 * Contributor(s): Daniel Dunbar
00024 *                 Ton Roosendaal,
00025 *                 Ben Batt,
00026 *                 Brecht Van Lommel,
00027 *                 Campbell Barton
00028 *
00029 * ***** END GPL LICENSE BLOCK *****
00030 *
00031 */
00032 
00038 #include "BLI_math.h"
00039 
00040 #include "DNA_meshdata_types.h"
00041 #include "DNA_scene_types.h"
00042 #include "DNA_object_types.h"
00043 
00044 #include "BLI_utildefines.h"
00045 
00046 
00047 #include "BKE_DerivedMesh.h"
00048 #include "BKE_object.h"
00049 #include "BKE_deform.h"
00050 #include "BKE_scene.h"
00051 
00052 #include "depsgraph_private.h"
00053 
00054 #include "MEM_guardedalloc.h"
00055 #include "RE_shader_ext.h"
00056 
00057 #include "MOD_modifiertypes.h"
00058 #include "MOD_util.h"
00059 
00060 static void initData(ModifierData *md)
00061 {
00062         WaveModifierData *wmd = (WaveModifierData*) md; // whadya know, moved here from Iraq
00063 
00064         wmd->flag |= (MOD_WAVE_X | MOD_WAVE_Y | MOD_WAVE_CYCL
00065                         | MOD_WAVE_NORM_X | MOD_WAVE_NORM_Y | MOD_WAVE_NORM_Z);
00066 
00067         wmd->objectcenter = NULL;
00068         wmd->texture = NULL;
00069         wmd->map_object = NULL;
00070         wmd->height= 0.5f;
00071         wmd->width= 1.5f;
00072         wmd->speed= 0.25f;
00073         wmd->narrow= 1.5f;
00074         wmd->lifetime= 0.0f;
00075         wmd->damp= 10.0f;
00076         wmd->falloff= 0.0f;
00077         wmd->texmapping = MOD_WAV_MAP_LOCAL;
00078         wmd->defgrp_name[0] = 0;
00079 }
00080 
00081 static void copyData(ModifierData *md, ModifierData *target)
00082 {
00083         WaveModifierData *wmd = (WaveModifierData*) md;
00084         WaveModifierData *twmd = (WaveModifierData*) target;
00085 
00086         twmd->damp = wmd->damp;
00087         twmd->flag = wmd->flag;
00088         twmd->height = wmd->height;
00089         twmd->lifetime = wmd->lifetime;
00090         twmd->narrow = wmd->narrow;
00091         twmd->speed = wmd->speed;
00092         twmd->startx = wmd->startx;
00093         twmd->starty = wmd->starty;
00094         twmd->timeoffs = wmd->timeoffs;
00095         twmd->width = wmd->width;
00096         twmd->falloff = wmd->falloff;
00097         twmd->objectcenter = wmd->objectcenter;
00098         twmd->texture = wmd->texture;
00099         twmd->map_object = wmd->map_object;
00100         twmd->texmapping = wmd->texmapping;
00101         strncpy(twmd->defgrp_name, wmd->defgrp_name, 32);
00102 }
00103 
00104 static int dependsOnTime(ModifierData *UNUSED(md))
00105 {
00106         return 1;
00107 }
00108 
00109 static void foreachObjectLink(
00110                                            ModifierData *md, Object *ob,
00111         ObjectWalkFunc walk, void *userData)
00112 {
00113         WaveModifierData *wmd = (WaveModifierData*) md;
00114 
00115         walk(userData, ob, &wmd->objectcenter);
00116         walk(userData, ob, &wmd->map_object);
00117 }
00118 
00119 static void foreachIDLink(ModifierData *md, Object *ob,
00120                                            IDWalkFunc walk, void *userData)
00121 {
00122         WaveModifierData *wmd = (WaveModifierData*) md;
00123 
00124         walk(userData, ob, (ID **)&wmd->texture);
00125 
00126         foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
00127 }
00128 
00129 static void updateDepgraph(ModifierData *md, DagForest *forest,
00130                                                 Scene *UNUSED(scene),
00131                                                 Object *UNUSED(ob),
00132                                                 DagNode *obNode)
00133 {
00134         WaveModifierData *wmd = (WaveModifierData*) md;
00135 
00136         if(wmd->objectcenter) {
00137                 DagNode *curNode = dag_get_node(forest, wmd->objectcenter);
00138 
00139                 dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA,
00140                         "Wave Modifier");
00141         }
00142 
00143         if(wmd->map_object) {
00144                 DagNode *curNode = dag_get_node(forest, wmd->map_object);
00145 
00146                 dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA,
00147                         "Wave Modifer");
00148         }
00149 }
00150 
00151 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
00152 {
00153         WaveModifierData *wmd = (WaveModifierData *)md;
00154         CustomDataMask dataMask = 0;
00155 
00156 
00157         /* ask for UV coordinates if we need them */
00158         if(wmd->texture && wmd->texmapping == MOD_WAV_MAP_UV)
00159                 dataMask |= CD_MASK_MTFACE;
00160 
00161         /* ask for vertexgroups if we need them */
00162         if(wmd->defgrp_name[0])
00163                 dataMask |= CD_MASK_MDEFORMVERT;
00164 
00165         return dataMask;
00166 }
00167 
00168 static void wavemod_get_texture_coords(WaveModifierData *wmd, Object *ob,
00169                                            DerivedMesh *dm,
00170            float (*co)[3], float (*texco)[3],
00171                    int numVerts)
00172 {
00173         int i;
00174         int texmapping = wmd->texmapping;
00175 
00176         if(texmapping == MOD_WAV_MAP_OBJECT) {
00177                 if(wmd->map_object)
00178                         invert_m4_m4(wmd->map_object->imat, wmd->map_object->obmat);
00179                 else /* if there is no map object, default to local */
00180                         texmapping = MOD_WAV_MAP_LOCAL;
00181         }
00182 
00183         /* UVs need special handling, since they come from faces */
00184         if(texmapping == MOD_WAV_MAP_UV) {
00185                 if(CustomData_has_layer(&dm->faceData, CD_MTFACE)) {
00186                         MFace *mface = dm->getFaceArray(dm);
00187                         MFace *mf;
00188                         char *done = MEM_callocN(sizeof(*done) * numVerts,
00189                                         "get_texture_coords done");
00190                         int numFaces = dm->getNumFaces(dm);
00191                         char uvname[32];
00192                         MTFace *tf;
00193 
00194                         validate_layer_name(&dm->faceData, CD_MTFACE, wmd->uvlayer_name, uvname);
00195                         tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname);
00196 
00197                         /* verts are given the UV from the first face that uses them */
00198                         for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tf) {
00199                                 if(!done[mf->v1]) {
00200                                         texco[mf->v1][0] = tf->uv[0][0];
00201                                         texco[mf->v1][1] = tf->uv[0][1];
00202                                         texco[mf->v1][2] = 0;
00203                                         done[mf->v1] = 1;
00204                                 }
00205                                 if(!done[mf->v2]) {
00206                                         texco[mf->v2][0] = tf->uv[1][0];
00207                                         texco[mf->v2][1] = tf->uv[1][1];
00208                                         texco[mf->v2][2] = 0;
00209                                         done[mf->v2] = 1;
00210                                 }
00211                                 if(!done[mf->v3]) {
00212                                         texco[mf->v3][0] = tf->uv[2][0];
00213                                         texco[mf->v3][1] = tf->uv[2][1];
00214                                         texco[mf->v3][2] = 0;
00215                                         done[mf->v3] = 1;
00216                                 }
00217                                 if(!done[mf->v4]) {
00218                                         texco[mf->v4][0] = tf->uv[3][0];
00219                                         texco[mf->v4][1] = tf->uv[3][1];
00220                                         texco[mf->v4][2] = 0;
00221                                         done[mf->v4] = 1;
00222                                 }
00223                         }
00224 
00225                         /* remap UVs from [0, 1] to [-1, 1] */
00226                         for(i = 0; i < numVerts; ++i) {
00227                                 texco[i][0] = texco[i][0] * 2 - 1;
00228                                 texco[i][1] = texco[i][1] * 2 - 1;
00229                         }
00230 
00231                         MEM_freeN(done);
00232                         return;
00233                 } else /* if there are no UVs, default to local */
00234                         texmapping = MOD_WAV_MAP_LOCAL;
00235         }
00236 
00237         for(i = 0; i < numVerts; ++i, ++co, ++texco) {
00238                 switch(texmapping) {
00239                         case MOD_WAV_MAP_LOCAL:
00240                                 copy_v3_v3(*texco, *co);
00241                                 break;
00242                         case MOD_WAV_MAP_GLOBAL:
00243                                 mul_v3_m4v3(*texco, ob->obmat, *co);
00244                                 break;
00245                         case MOD_WAV_MAP_OBJECT:
00246                                 mul_v3_m4v3(*texco, ob->obmat, *co);
00247                                 mul_m4_v3(wmd->map_object->imat, *texco);
00248                                 break;
00249                 }
00250         }
00251 }
00252 
00253 static void waveModifier_do(WaveModifierData *md, 
00254                 Scene *scene, Object *ob, DerivedMesh *dm,
00255            float (*vertexCos)[3], int numVerts)
00256 {
00257         WaveModifierData *wmd = (WaveModifierData*) md;
00258         MVert *mvert = NULL;
00259         MDeformVert *dvert;
00260         int defgrp_index;
00261         float ctime = BKE_curframe(scene);
00262         float minfac =
00263                         (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow));
00264         float lifefac = wmd->height;
00265         float (*tex_co)[3] = NULL;
00266         const int wmd_axis= wmd->flag & (MOD_WAVE_X|MOD_WAVE_Y);
00267         const float falloff= wmd->falloff;
00268         float falloff_fac= 1.0f; /* when falloff == 0.0f this stays at 1.0f */
00269 
00270         if(wmd->flag & MOD_WAVE_NORM && ob->type == OB_MESH)
00271                 mvert = dm->getVertArray(dm);
00272 
00273         if(wmd->objectcenter){
00274                 float mat[4][4];
00275                 /* get the control object's location in local coordinates */
00276                 invert_m4_m4(ob->imat, ob->obmat);
00277                 mul_m4_m4m4(mat, wmd->objectcenter->obmat, ob->imat);
00278 
00279                 wmd->startx = mat[3][0];
00280                 wmd->starty = mat[3][1];
00281         }
00282 
00283         /* get the index of the deform group */
00284         modifier_get_vgroup(ob, dm, wmd->defgrp_name, &dvert, &defgrp_index);
00285 
00286         if(wmd->damp == 0) wmd->damp = 10.0f;
00287 
00288         if(wmd->lifetime != 0.0f) {
00289                 float x = ctime - wmd->timeoffs;
00290 
00291                 if(x > wmd->lifetime) {
00292                         lifefac = x - wmd->lifetime;
00293 
00294                         if(lifefac > wmd->damp) lifefac = 0.0;
00295                         else lifefac =
00296                                 (float)(wmd->height * (1.0f - sqrtf(lifefac / wmd->damp)));
00297                 }
00298         }
00299 
00300         if(wmd->texture) {
00301                 tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts,
00302                                          "waveModifier_do tex_co");
00303                 wavemod_get_texture_coords(wmd, ob, dm, vertexCos, tex_co, numVerts);
00304         }
00305 
00306         if(lifefac != 0.0f) {
00307                 /* avoid divide by zero checks within the loop */
00308                 float falloff_inv= falloff ? 1.0f / falloff : 1.0f;
00309                 int i;
00310 
00311                 for(i = 0; i < numVerts; i++) {
00312                         float *co = vertexCos[i];
00313                         float x = co[0] - wmd->startx;
00314                         float y = co[1] - wmd->starty;
00315                         float amplit= 0.0f;
00316                         float def_weight= 1.0f;
00317 
00318                         /* get weights */
00319                         if(dvert) {
00320                                 def_weight= defvert_find_weight(&dvert[i], defgrp_index);
00321 
00322                                 /* if this vert isn't in the vgroup, don't deform it */
00323                                 if(def_weight == 0.0f) {
00324                                         continue;
00325                                 }
00326                         }
00327 
00328                         switch(wmd_axis) {
00329                         case MOD_WAVE_X|MOD_WAVE_Y:
00330                                 amplit = sqrtf(x*x + y*y);
00331                                 break;
00332                         case MOD_WAVE_X:
00333                                 amplit = x;
00334                                 break;
00335                         case MOD_WAVE_Y:
00336                                 amplit = y;
00337                                 break;
00338                         }
00339 
00340                         /* this way it makes nice circles */
00341                         amplit -= (ctime - wmd->timeoffs) * wmd->speed;
00342 
00343                         if(wmd->flag & MOD_WAVE_CYCL) {
00344                                 amplit = (float)fmodf(amplit - wmd->width, 2.0f * wmd->width)
00345                                                 + wmd->width;
00346                         }
00347 
00348                         if(falloff != 0.0f) {
00349                                 float dist = 0.0f;
00350 
00351                                 switch(wmd_axis) {
00352                                 case MOD_WAVE_X|MOD_WAVE_Y:
00353                                         dist = sqrtf(x*x + y*y);
00354                                         break;
00355                                 case MOD_WAVE_X:
00356                                         dist = fabsf(x);
00357                                         break;
00358                                 case MOD_WAVE_Y:
00359                                         dist = fabsf(y);
00360                                         break;
00361                                 }
00362 
00363                                 falloff_fac = (1.0f - (dist * falloff_inv));
00364                                 CLAMP(falloff_fac, 0.0f, 1.0f);
00365                         }
00366 
00367                         /* GAUSSIAN */
00368                         if((falloff_fac != 0.0f) && (amplit > -wmd->width) && (amplit < wmd->width)) {
00369                                 amplit = amplit * wmd->narrow;
00370                                 amplit = (float)(1.0f / expf(amplit * amplit) - minfac);
00371 
00372                                 /*apply texture*/
00373                                 if(wmd->texture) {
00374                                         TexResult texres;
00375                                         texres.nor = NULL;
00376                                         get_texture_value(wmd->texture, tex_co[i], &texres);
00377                                         amplit *= texres.tin;
00378                                 }
00379 
00380                                 /*apply weight & falloff */
00381                                 amplit *= def_weight * falloff_fac;
00382 
00383                                 if(mvert) {
00384                                         /* move along normals */
00385                                         if(wmd->flag & MOD_WAVE_NORM_X) {
00386                                                 co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f;
00387                                         }
00388                                         if(wmd->flag & MOD_WAVE_NORM_Y) {
00389                                                 co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f;
00390                                         }
00391                                         if(wmd->flag & MOD_WAVE_NORM_Z) {
00392                                                 co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f;
00393                                         }
00394                                 }
00395                                 else {
00396                                         /* move along local z axis */
00397                                         co[2] += lifefac * amplit;
00398                                 }
00399                         }
00400                 }
00401         }
00402 
00403         if(wmd->texture) MEM_freeN(tex_co);
00404 }
00405 
00406 static void deformVerts(ModifierData *md, Object *ob,
00407                                                 DerivedMesh *derivedData,
00408                                                 float (*vertexCos)[3],
00409                                                 int numVerts,
00410                                                 int UNUSED(useRenderParams),
00411                                                 int UNUSED(isFinalCalc))
00412 {
00413         DerivedMesh *dm= derivedData;
00414         WaveModifierData *wmd = (WaveModifierData *)md;
00415 
00416         if(wmd->flag & MOD_WAVE_NORM)
00417                 dm= get_cddm(ob, NULL, dm, vertexCos);
00418         else if(wmd->texture || wmd->defgrp_name[0])
00419                 dm= get_dm(ob, NULL, dm, NULL, 0);
00420 
00421         waveModifier_do(wmd, md->scene, ob, dm, vertexCos, numVerts);
00422 
00423         if(dm != derivedData)
00424                 dm->release(dm);
00425 }
00426 
00427 static void deformVertsEM(
00428                                            ModifierData *md, Object *ob, struct EditMesh *editData,
00429            DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
00430 {
00431         DerivedMesh *dm= derivedData;
00432         WaveModifierData *wmd = (WaveModifierData *)md;
00433 
00434         if(wmd->flag & MOD_WAVE_NORM)
00435                 dm= get_cddm(ob, editData, dm, vertexCos);
00436         else if(wmd->texture || wmd->defgrp_name[0])
00437                 dm= get_dm(ob, editData, dm, NULL, 0);
00438 
00439         waveModifier_do(wmd, md->scene, ob, dm, vertexCos, numVerts);
00440 
00441         if(dm != derivedData)
00442                 dm->release(dm);
00443 }
00444 
00445 
00446 ModifierTypeInfo modifierType_Wave = {
00447         /* name */              "Wave",
00448         /* structName */        "WaveModifierData",
00449         /* structSize */        sizeof(WaveModifierData),
00450         /* type */              eModifierTypeType_OnlyDeform,
00451         /* flags */             eModifierTypeFlag_AcceptsCVs
00452                                                         | eModifierTypeFlag_SupportsEditmode,
00453         /* copyData */          copyData,
00454         /* deformVerts */       deformVerts,
00455         /* deformMatrices */    NULL,
00456         /* deformVertsEM */     deformVertsEM,
00457         /* deformMatricesEM */  NULL,
00458         /* applyModifier */     NULL,
00459         /* applyModifierEM */   NULL,
00460         /* initData */          initData,
00461         /* requiredDataMask */  requiredDataMask,
00462         /* freeData */          NULL,
00463         /* isDisabled */        NULL,
00464         /* updateDepgraph */    updateDepgraph,
00465         /* dependsOnTime */     dependsOnTime,
00466         /* dependsOnNormals */  NULL,
00467         /* foreachObjectLink */ foreachObjectLink,
00468         /* foreachIDLink */     foreachIDLink,
00469 };