248 lines
6.6 KiB
C
248 lines
6.6 KiB
C
/*
|
|
* ***** 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) 2013 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 "BLI_listbase.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_sq;
|
|
|
|
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, DM_FOREACH_USE_NORMAL);
|
|
}
|
|
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_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 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(BLI_listbase_is_empty(&ob->modifiers) == false);
|
|
|
|
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_sq, me->totvert, FLT_MAX);
|
|
|
|
dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_update__map_cb, &vp_update, DM_FOREACH_USE_NORMAL);
|
|
}
|
|
|
|
dm->release(dm);
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* 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_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 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_sq);
|
|
}
|
|
|
|
MEM_freeN(vp_handle->vcosnos);
|
|
MEM_freeN(vp_handle);
|
|
}
|