236 lines
7.0 KiB
C
236 lines
7.0 KiB
C
/*
|
|
* 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) 2013 Blender Foundation.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
/** \file
|
|
* \ingroup edsculpt
|
|
*
|
|
* Utility functions for getting vertex locations while painting
|
|
* (since they may be instanced multiple times in an evaluated mesh)
|
|
*/
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_math.h"
|
|
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "BKE_context.h"
|
|
#include "BKE_customdata.h"
|
|
#include "BKE_mesh_iterators.h"
|
|
#include "BKE_mesh_runtime.h"
|
|
|
|
#include "DEG_depsgraph.h"
|
|
#include "DEG_depsgraph_query.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 {
|
|
CoNo *vcosnos;
|
|
|
|
bool use_update;
|
|
|
|
/* use for update */
|
|
float *dists_sq;
|
|
|
|
Object *ob;
|
|
Scene *scene;
|
|
};
|
|
|
|
/* only for passing to the callbacks */
|
|
struct VertProjUpdate {
|
|
struct VertProjHandle *vp_handle;
|
|
|
|
/* runtime */
|
|
ARegion *region;
|
|
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;
|
|
CoNo *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(struct Depsgraph *depsgraph,
|
|
Scene *UNUSED(scene),
|
|
Object *ob,
|
|
struct VertProjHandle *vp_handle)
|
|
{
|
|
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
|
|
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
|
|
Mesh *me = ob->data;
|
|
|
|
CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH_ORIGINDEX;
|
|
Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &cddata_masks);
|
|
|
|
memset(vp_handle->vcosnos, 0, sizeof(*vp_handle->vcosnos) * me->totvert);
|
|
BKE_mesh_foreach_mapped_vert(
|
|
me_eval, vpaint_proj_dm_map_cosnos_init__map_cb, vp_handle, MESH_FOREACH_USE_NORMAL);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* 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;
|
|
|
|
CoNo *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->region, co, co_ss, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) ==
|
|
V3D_PROJ_RET_OK) {
|
|
const float dist_sq = len_squared_v2v2(vp_update->mval_fl, co_ss);
|
|
if (dist_sq > vp_handle->dists_sq[index]) {
|
|
/* bail out! */
|
|
return;
|
|
}
|
|
|
|
vp_handle->dists_sq[index] = dist_sq;
|
|
}
|
|
else if (vp_handle->dists_sq[index] != FLT_MAX) {
|
|
/* already initialized & couldn't project this 'co' */
|
|
return;
|
|
}
|
|
}
|
|
/* 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 Depsgraph *depsgraph,
|
|
struct VertProjHandle *vp_handle,
|
|
ARegion *region,
|
|
const float mval_fl[2])
|
|
{
|
|
struct VertProjUpdate vp_update = {vp_handle, region, mval_fl};
|
|
|
|
Object *ob = vp_handle->ob;
|
|
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
|
|
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
|
|
Mesh *me = ob->data;
|
|
|
|
CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH_ORIGINDEX;
|
|
Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &cddata_masks);
|
|
|
|
/* quick sanity check - we shouldn't have to run this if there are no modifiers */
|
|
BLI_assert(BLI_listbase_is_empty(&ob->modifiers) == false);
|
|
|
|
copy_vn_fl(vp_handle->dists_sq, me->totvert, FLT_MAX);
|
|
BKE_mesh_foreach_mapped_vert(
|
|
me_eval, vpaint_proj_dm_map_cosnos_update__map_cb, &vp_update, MESH_FOREACH_USE_NORMAL);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Public Functions */
|
|
|
|
struct VertProjHandle *ED_vpaint_proj_handle_create(struct Depsgraph *depsgraph,
|
|
Scene *scene,
|
|
Object *ob,
|
|
CoNo **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(CoNo) * me->totvert, "vertexcosnos map");
|
|
vp_handle->use_update = false;
|
|
|
|
/* sets 'use_update' if needed */
|
|
vpaint_proj_dm_map_cosnos_init(depsgraph, scene, ob, vp_handle);
|
|
|
|
if (vp_handle->use_update) {
|
|
vp_handle->dists_sq = MEM_mallocN(sizeof(float) * me->totvert, __func__);
|
|
|
|
vp_handle->ob = ob;
|
|
vp_handle->scene = scene;
|
|
}
|
|
else {
|
|
vp_handle->dists_sq = NULL;
|
|
|
|
vp_handle->ob = NULL;
|
|
vp_handle->scene = NULL;
|
|
}
|
|
|
|
*r_vcosnos = vp_handle->vcosnos;
|
|
return vp_handle;
|
|
}
|
|
|
|
void ED_vpaint_proj_handle_update(struct Depsgraph *depsgraph,
|
|
struct VertProjHandle *vp_handle,
|
|
ARegion *region,
|
|
const float mval_fl[2])
|
|
{
|
|
if (vp_handle->use_update) {
|
|
vpaint_proj_dm_map_cosnos_update(depsgraph, vp_handle, region, mval_fl);
|
|
}
|
|
}
|
|
|
|
void ED_vpaint_proj_handle_free(struct VertProjHandle *vp_handle)
|
|
{
|
|
if (vp_handle->use_update) {
|
|
MEM_freeN(vp_handle->dists_sq);
|
|
}
|
|
|
|
MEM_freeN(vp_handle->vcosnos);
|
|
MEM_freeN(vp_handle);
|
|
}
|