This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/editors/sculpt_paint/paint_vertex_proj.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);
}