diff options
author | Campbell Barton <ideasman42@gmail.com> | 2013-06-26 22:40:55 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2013-06-26 22:40:55 +0400 |
commit | ca51930a90056aa3a65dcfc086ddd9ad19dcdf0f (patch) | |
tree | 8aab10f95727869b1e105a2ed9cb0a12f3cd84da /source/blender/editors/sculpt_paint/paint_vertex_proj.c | |
parent | 9c85cdceb2544740682490a07a3d3f77612f9691 (diff) |
fix [#33068] Can't paint weights of some vertices in some situations.
old limitation where you could only paint onto one side of a mirrored mesh (weight paint, vertex paint).
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_vertex_proj.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_vertex_proj.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_proj.c b/source/blender/editors/sculpt_paint/paint_vertex_proj.c new file mode 100644 index 00000000000..51734447d1d --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_vertex_proj.c @@ -0,0 +1,244 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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) 2009 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/sculpt_paint/paint_vertex_proj.c + * \ingroup edsculpt + * + * Utility functions for getting vertex locations while painting + * (since they may be instanced multiple times in a DerivedMesh) + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" + +#include "BKE_DerivedMesh.h" +#include "BKE_context.h" + +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "paint_intern.h" /* own include */ + + +/* Opaque Structs for internal use */ + +/* stored while painting */ +struct VertProjHandle { + DMCoNo *vcosnos; + + bool use_update; + + /* use for update */ + float *dists; + + Object *ob; + Scene *scene; +}; + +/* only for passing to the callbacks */ +struct VertProjUpdate { + struct VertProjHandle *vp_handle; + + /* runtime */ + ARegion *ar; + const float *mval_fl; +}; + + +/* -------------------------------------------------------------------- */ +/* Internal Init */ + +static void vpaint_proj_dm_map_cosnos_init__map_cb(void *userData, int index, const float co[3], + const float no_f[3], const short no_s[3]) +{ + struct VertProjHandle *vp_handle = userData; + DMCoNo *co_no = &vp_handle->vcosnos[index]; + + /* check if we've been here before (normal should not be 0) */ + if (!is_zero_v3(co_no->no)) { + /* remember that multiple dm verts share the same source vert */ + vp_handle->use_update = true; + return; + } + + copy_v3_v3(co_no->co, co); + if (no_f) { + copy_v3_v3(co_no->no, no_f); + } + else { + normal_short_to_float_v3(co_no->no, no_s); + } +} + +static void vpaint_proj_dm_map_cosnos_init(Scene *scene, Object *ob, + struct VertProjHandle *vp_handle) +{ + Mesh *me = ob->data; + DerivedMesh *dm; + + dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX); + + if (dm->foreachMappedVert) { + memset(vp_handle->vcosnos, 0, sizeof(DMCoNo) * me->totvert); + dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_init__map_cb, vp_handle); + } + else { + DMCoNo *v_co_no = vp_handle->vcosnos; + int a; + for (a = 0; a < me->totvert; a++, v_co_no++) { + dm->getVertCo(dm, a, v_co_no->co); + dm->getVertNo(dm, a, v_co_no->no); + } + } + + dm->release(dm); +} + + +/* -------------------------------------------------------------------- */ +/* Internal Update */ + +/* Same as init but take mouse location into account */ + +static void vpaint_proj_dm_map_cosnos_update__map_cb(void *userData, int index, const float co[3], + const float no_f[3], const short no_s[3]) +{ + struct VertProjUpdate *vp_update = userData; + struct VertProjHandle *vp_handle = vp_update->vp_handle; + + DMCoNo *co_no = &vp_handle->vcosnos[index]; + + /* find closest vertex */ + { + /* first find distance to this vertex */ + float co_ss[2]; /* screenspace */ + + if (ED_view3d_project_float_object(vp_update->ar, + co, co_ss, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + { + const float dist = len_squared_v2v2(vp_update->mval_fl, co_ss); + if (dist > vp_handle->dists[index]) { + /* bail out! */ + return; + } + + vp_handle->dists[index] = dist; + } + } + /* continue with regular functionality */ + + copy_v3_v3(co_no->co, co); + if (no_f) { + copy_v3_v3(co_no->no, no_f); + } + else { + normal_short_to_float_v3(co_no->no, no_s); + } +} + +static void vpaint_proj_dm_map_cosnos_update(struct VertProjHandle *vp_handle, + ARegion *ar, const float mval_fl[2]) +{ + struct VertProjUpdate vp_update = {vp_handle, ar, mval_fl}; + + Scene *scene = vp_handle->scene; + Object *ob = vp_handle->ob; + Mesh *me = ob->data; + DerivedMesh *dm; + + /* quick sanity check - we shouldn't have to run this if there are no modifiers */ + BLI_assert(ob->modifiers.first != NULL); + + dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX); + + /* highly unlikely this will become unavailable once painting starts (perhaps with animated modifiers) */ + if (LIKELY(dm->foreachMappedVert)) { + fill_vn_fl(vp_handle->dists, me->totvert, FLT_MAX); + + dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_update__map_cb, &vp_update); + } + + dm->release(dm); + + (void)mval_fl; +} + + +/* -------------------------------------------------------------------- */ +/* Public Functions */ + +struct VertProjHandle *ED_vpaint_proj_handle_create(Scene *scene, Object *ob, + DMCoNo **r_vcosnos) +{ + struct VertProjHandle *vp_handle = MEM_mallocN(sizeof(struct VertProjHandle), __func__); + Mesh *me = ob->data; + + /* setup the handle */ + vp_handle->vcosnos = MEM_mallocN(sizeof(DMCoNo) * me->totvert, "vertexcosnos map"); + vp_handle->use_update = false; + + /* sets 'use_update' if needed */ + vpaint_proj_dm_map_cosnos_init(scene, ob, vp_handle); + + if (vp_handle->use_update) { + vp_handle->dists = MEM_mallocN(sizeof(float) * me->totvert, __func__); + + vp_handle->ob = ob; + vp_handle->scene = scene; + } + else { + vp_handle->dists = NULL; + + vp_handle->ob = NULL; + vp_handle->scene = NULL; + } + + *r_vcosnos = vp_handle->vcosnos; + return vp_handle; +} + +void ED_vpaint_proj_handle_update(struct VertProjHandle *vp_handle, + ARegion *ar, const float mval_fl[2]) +{ + if (vp_handle->use_update) { + vpaint_proj_dm_map_cosnos_update(vp_handle, ar, mval_fl); + } +} + +void ED_vpaint_proj_handle_free(struct VertProjHandle *vp_handle) +{ + if (vp_handle->use_update) { + MEM_freeN(vp_handle->dists); + } + + MEM_freeN(vp_handle->vcosnos); + MEM_freeN(vp_handle); +} |