diff options
Diffstat (limited to 'source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c')
-rw-r--r-- | source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c new file mode 100644 index 00000000000..6990b41e6ce --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c @@ -0,0 +1,350 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + */ + +/** \file + * \ingroup modifiers + */ + +#include <stdio.h> +#include <string.h> /* For #MEMCPY_STRUCT_AFTER. */ + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "DNA_defaults.h" +#include "DNA_gpencil_modifier_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" + +#include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_lib_query.h" +#include "BKE_main.h" +#include "BKE_modifier.h" +#include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_shrinkwrap.h" + +#include "MEM_guardedalloc.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" + +#include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_ui_common.h" +#include "MOD_gpencil_util.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +static void initData(GpencilModifierData *md) +{ + ShrinkwrapGpencilModifierData *gpmd = (ShrinkwrapGpencilModifierData *)md; + + BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier)); + + MEMCPY_STRUCT_AFTER(gpmd, DNA_struct_default_get(ShrinkwrapGpencilModifierData), modifier); +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copydata_generic(md, target); +} + +static void deformStroke(GpencilModifierData *md, + Depsgraph *UNUSED(depsgraph), + Object *ob, + bGPDlayer *gpl, + bGPDframe *UNUSED(gpf), + bGPDstroke *gps) +{ + bGPdata *gpd = ob->data; + ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md; + const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname); + + if (!is_stroke_affected_by_modifier(ob, + mmd->layername, + mmd->material, + mmd->pass_index, + mmd->layer_pass, + 1, + gpl, + gps, + mmd->flag & GP_SHRINKWRAP_INVERT_LAYER, + mmd->flag & GP_SHRINKWRAP_INVERT_PASS, + mmd->flag & GP_SHRINKWRAP_INVERT_LAYERPASS, + mmd->flag & GP_SHRINKWRAP_INVERT_MATERIAL)) { + return; + } + + if ((mmd->cache_data == NULL) || (mmd->target == ob) || (mmd->aux_target == ob)) { + return; + } + + bGPDspoint *pt = gps->points; + float(*vert_coords)[3] = MEM_mallocN(sizeof(float[3]) * gps->totpoints, __func__); + int i; + /* Prepare array of points. */ + for (i = 0; i < gps->totpoints; i++, pt++) { + copy_v3_v3(vert_coords[i], &pt->x); + } + + shrinkwrapGpencilModifier_deform(mmd, ob, gps->dvert, def_nr, vert_coords, gps->totpoints); + + /* Apply deformed coordinates. */ + pt = gps->points; + for (i = 0; i < gps->totpoints; i++, pt++) { + copy_v3_v3(&pt->x, vert_coords[i]); + /* Smooth stroke. */ + if (mmd->smooth_factor > 0.0f) { + for (int r = 0; r < mmd->smooth_step; r++) { + BKE_gpencil_stroke_smooth_point(gps, i, mmd->smooth_factor, true); + } + } + } + + MEM_freeN(vert_coords); + + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gpd, gps); +} + +static void bakeModifier(Main *UNUSED(bmain), + Depsgraph *depsgraph, + GpencilModifierData *md, + Object *ob) +{ + ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md; + Scene *scene = DEG_get_evaluated_scene(depsgraph); + bGPdata *gpd = ob->data; + int oldframe = (int)DEG_get_ctime(depsgraph); + + if ((mmd->target == ob) || (mmd->aux_target == ob)) { + return; + } + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + /* Apply shrinkwrap effects on this frame. */ + CFRA = gpf->framenum; + BKE_scene_graph_update_for_newframe(depsgraph); + + /* Recalculate shrinkwrap data. */ + if (mmd->cache_data) { + BKE_shrinkwrap_free_tree(mmd->cache_data); + MEM_SAFE_FREE(mmd->cache_data); + } + Object *ob_target = DEG_get_evaluated_object(depsgraph, mmd->target); + Mesh *target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false); + mmd->cache_data = MEM_callocN(sizeof(ShrinkwrapTreeData), __func__); + if (BKE_shrinkwrap_init_tree( + mmd->cache_data, target, mmd->shrink_type, mmd->shrink_mode, false)) { + + /* Compute shrinkwrap effects on this frame. */ + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + deformStroke(md, depsgraph, ob, gpl, gpf, gps); + } + } + /* Free data. */ + if (mmd->cache_data) { + BKE_shrinkwrap_free_tree(mmd->cache_data); + MEM_SAFE_FREE(mmd->cache_data); + } + } + } + + /* Return frame state and DB to original state. */ + CFRA = oldframe; + BKE_scene_graph_update_for_newframe(depsgraph); +} + +static void freeData(GpencilModifierData *md) +{ + ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md; + if (mmd->cache_data) { + BKE_shrinkwrap_free_tree(mmd->cache_data); + MEM_SAFE_FREE(mmd->cache_data); + } +} + +static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams)) +{ + ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md; + + /* The object type check is only needed here in case we have a placeholder + * object assigned (because the library containing the mesh is missing). + * + * In other cases it should be impossible to have a type mismatch. + */ + if (!mmd->target || mmd->target->type != OB_MESH) { + return true; + } + if (mmd->aux_target && mmd->aux_target->type != OB_MESH) { + return true; + } + return false; +} + +static void updateDepsgraph(GpencilModifierData *md, + const ModifierUpdateDepsgraphContext *ctx, + const int UNUSED(mode)) +{ + ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md; + CustomData_MeshMasks mask = {0}; + + if (BKE_shrinkwrap_needs_normals(mmd->shrink_type, mmd->shrink_mode)) { + mask.vmask |= CD_MASK_NORMAL; + mask.lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL; + } + + if (mmd->target != NULL) { + DEG_add_object_relation(ctx->node, mmd->target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier"); + DEG_add_object_relation(ctx->node, mmd->target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier"); + DEG_add_customdata_mask(ctx->node, mmd->target, &mask); + if (mmd->shrink_type == MOD_SHRINKWRAP_TARGET_PROJECT) { + DEG_add_special_eval_flag(ctx->node, &mmd->target->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY); + } + } + if (mmd->aux_target != NULL) { + DEG_add_object_relation( + ctx->node, mmd->aux_target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier"); + DEG_add_object_relation( + ctx->node, mmd->aux_target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier"); + DEG_add_customdata_mask(ctx->node, mmd->aux_target, &mask); + if (mmd->shrink_type == MOD_SHRINKWRAP_TARGET_PROJECT) { + DEG_add_special_eval_flag( + ctx->node, &mmd->aux_target->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY); + } + } + DEG_add_modifier_to_transform_relation(ctx->node, "Shrinkwrap Modifier"); +} + +static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData) +{ + ShrinkwrapGpencilModifierData *mmd = (ShrinkwrapGpencilModifierData *)md; + + walk(userData, ob, (ID **)&mmd->target, IDWALK_CB_NOP); + walk(userData, ob, (ID **)&mmd->aux_target, IDWALK_CB_NOP); + walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER); +} + +static void panel_draw(const bContext *UNUSED(C), Panel *panel) +{ + uiLayout *row, *col; + uiLayout *layout = panel->layout; + int toggles_flag = UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE; + + PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL); + + uiLayoutSetPropSep(layout, true); + + int wrap_method = RNA_enum_get(ptr, "wrap_method"); + + uiItemR(layout, ptr, "wrap_method", 0, NULL, ICON_NONE); + + if (ELEM(wrap_method, + MOD_SHRINKWRAP_PROJECT, + MOD_SHRINKWRAP_NEAREST_SURFACE, + MOD_SHRINKWRAP_TARGET_PROJECT)) { + uiItemR(layout, ptr, "wrap_mode", 0, NULL, ICON_NONE); + } + + if (wrap_method == MOD_SHRINKWRAP_PROJECT) { + uiItemR(layout, ptr, "project_limit", 0, IFACE_("Limit"), ICON_NONE); + uiItemR(layout, ptr, "subsurf_levels", 0, NULL, ICON_NONE); + + col = uiLayoutColumn(layout, false); + row = uiLayoutRowWithHeading(col, true, IFACE_("Axis")); + uiItemR(row, ptr, "use_project_x", toggles_flag, NULL, ICON_NONE); + uiItemR(row, ptr, "use_project_y", toggles_flag, NULL, ICON_NONE); + uiItemR(row, ptr, "use_project_z", toggles_flag, NULL, ICON_NONE); + + uiItemR(col, ptr, "use_negative_direction", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_positive_direction", 0, NULL, ICON_NONE); + + uiItemR(layout, ptr, "cull_face", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + col = uiLayoutColumn(layout, false); + uiLayoutSetActive(col, + RNA_boolean_get(ptr, "use_negative_direction") && + RNA_enum_get(ptr, "cull_face") != 0); + uiItemR(col, ptr, "use_invert_cull", 0, NULL, ICON_NONE); + } + + uiItemR(layout, ptr, "target", 0, NULL, ICON_NONE); + if (wrap_method == MOD_SHRINKWRAP_PROJECT) { + uiItemR(layout, ptr, "auxiliary_target", 0, NULL, ICON_NONE); + } + uiItemR(layout, ptr, "offset", 0, NULL, ICON_NONE); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, ptr, "smooth_factor", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "smooth_step", 0, IFACE_("Repeat"), ICON_NONE); + + gpencil_modifier_panel_end(layout, ptr); +} + +static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel) +{ + gpencil_modifier_masking_panel_draw(panel, true, true); +} + +static void panelRegister(ARegionType *region_type) +{ + PanelType *panel_type = gpencil_modifier_panel_register( + region_type, eGpencilModifierType_Shrinkwrap, panel_draw); + gpencil_modifier_subpanel_register( + region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); +} + +GpencilModifierTypeInfo modifierType_Gpencil_Shrinkwrap = { + /* name */ "Shrinkwrap", + /* structName */ "ShrinkwrapGpencilModifierData", + /* structSize */ sizeof(ShrinkwrapGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ eGpencilModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformStroke */ deformStroke, + /* generateStrokes */ NULL, + /* bakeModifier */ bakeModifier, + /* remapTime */ NULL, + + /* initData */ initData, + /* freeData */ freeData, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* foreachIDLink */ foreachIDLink, + /* foreachTexLink */ NULL, + /* panelRegister */ panelRegister, +}; |