2011-02-23 10:52:22 +00:00
|
|
|
/*
|
2009-01-07 19:23:22 +00:00
|
|
|
* ***** 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,
|
2010-02-12 13:34:04 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2009-01-07 19:23:22 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): none yet.
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
2011-02-27 20:29:51 +00:00
|
|
|
/** \file blender/editors/sculpt_paint/paint_vertex.c
|
|
|
|
* \ingroup edsculpt
|
|
|
|
*/
|
|
|
|
|
2009-01-07 19:23:22 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
2009-11-10 20:43:45 +00:00
|
|
|
#include "BLI_math.h"
|
2009-08-30 21:30:07 +00:00
|
|
|
#include "BLI_memarena.h"
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2010-08-16 05:46:10 +00:00
|
|
|
#include "IMB_imbuf.h"
|
|
|
|
#include "IMB_imbuf_types.h"
|
|
|
|
|
2009-01-07 19:23:22 +00:00
|
|
|
#include "DNA_armature_types.h"
|
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
#include "DNA_particle_types.h"
|
2010-08-10 05:41:51 +00:00
|
|
|
#include "DNA_scene_types.h"
|
2010-08-04 04:01:27 +00:00
|
|
|
#include "DNA_brush_types.h"
|
2010-08-10 05:41:51 +00:00
|
|
|
#include "DNA_object_types.h"
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2009-01-25 21:02:52 +00:00
|
|
|
#include "RNA_access.h"
|
2009-08-20 05:13:07 +00:00
|
|
|
#include "RNA_define.h"
|
2011-05-25 10:07:59 +00:00
|
|
|
#include "RNA_enum_types.h"
|
2009-01-25 21:02:52 +00:00
|
|
|
|
2010-08-10 05:41:51 +00:00
|
|
|
#include "BKE_DerivedMesh.h"
|
2010-01-18 16:21:23 +00:00
|
|
|
#include "BKE_action.h"
|
2009-03-11 00:43:08 +00:00
|
|
|
#include "BKE_brush.h"
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
#include "BKE_context.h"
|
2009-01-07 19:23:22 +00:00
|
|
|
#include "BKE_depsgraph.h"
|
|
|
|
#include "BKE_deform.h"
|
|
|
|
#include "BKE_mesh.h"
|
|
|
|
#include "BKE_modifier.h"
|
|
|
|
#include "BKE_object.h"
|
2012-09-05 02:51:55 +00:00
|
|
|
#include "BKE_object_deform.h"
|
2009-08-17 02:49:31 +00:00
|
|
|
#include "BKE_paint.h"
|
2011-05-25 10:07:59 +00:00
|
|
|
#include "BKE_report.h"
|
2009-01-07 19:23:22 +00:00
|
|
|
|
|
|
|
#include "WM_api.h"
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
#include "WM_types.h"
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-10-29 16:26:18 +00:00
|
|
|
#include "GPU_buffers.h"
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2010-01-26 11:11:53 +00:00
|
|
|
#include "ED_armature.h"
|
2009-01-07 19:23:22 +00:00
|
|
|
#include "ED_mesh.h"
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
#include "ED_screen.h"
|
2009-01-07 19:23:22 +00:00
|
|
|
#include "ED_view3d.h"
|
|
|
|
|
2013-06-26 18:40:55 +00:00
|
|
|
#include "paint_intern.h" /* own include */
|
2009-08-20 05:13:07 +00:00
|
|
|
|
2012-02-23 09:23:29 +00:00
|
|
|
/* check if we can do partial updates and have them draw realtime
|
2012-02-08 11:52:44 +00:00
|
|
|
* (without rebuilding the 'derivedFinal') */
|
|
|
|
static int vertex_paint_use_fast_update_check(Object *ob)
|
|
|
|
{
|
|
|
|
DerivedMesh *dm = ob->derivedFinal;
|
|
|
|
|
|
|
|
if (dm) {
|
2012-05-05 16:03:57 +00:00
|
|
|
Mesh *me = BKE_mesh_from_object(ob);
|
2012-02-08 11:52:44 +00:00
|
|
|
if (me && me->mcol) {
|
|
|
|
return (me->mcol == CustomData_get_layer(&dm->faceData, CD_MCOL));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if the polygons from the mesh and the 'derivedFinal' match
|
2012-03-18 07:38:51 +00:00
|
|
|
* we can assume that no modifiers are applied and that its worth adding tessellated faces
|
2012-02-08 11:52:44 +00:00
|
|
|
* so 'vertex_paint_use_fast_update_check()' returns TRUE */
|
2012-10-29 16:26:18 +00:00
|
|
|
static int vertex_paint_use_tessface_check(Object *ob, Mesh *me)
|
2012-02-08 11:52:44 +00:00
|
|
|
{
|
|
|
|
DerivedMesh *dm = ob->derivedFinal;
|
2009-01-25 21:02:52 +00:00
|
|
|
|
2012-10-29 16:26:18 +00:00
|
|
|
if (me && dm) {
|
|
|
|
return (me->mpoly == CustomData_get_layer(&dm->polyData, CD_MPOLY));
|
2012-02-08 11:52:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2012-10-29 16:26:18 +00:00
|
|
|
static void update_tessface_data(Object *ob, Mesh *me)
|
|
|
|
{
|
|
|
|
if (vertex_paint_use_tessface_check(ob, me)) {
|
|
|
|
/* assume if these exist, that they are up to date & valid */
|
|
|
|
if (!me->mcol || !me->mface) {
|
|
|
|
/* should always be true */
|
|
|
|
/* XXX Why this clearing? tessface_calc will reset it anyway! */
|
2012-11-09 09:33:28 +00:00
|
|
|
#if 0
|
|
|
|
if (me->mcol) {
|
|
|
|
memset(me->mcol, 255, 4 * sizeof(MCol) * me->totface);
|
|
|
|
}
|
|
|
|
#endif
|
2012-10-29 16:26:18 +00:00
|
|
|
|
|
|
|
/* create tessfaces because they will be used for drawing & fast updates */
|
|
|
|
BKE_mesh_tessface_calc(me); /* does own call to update pointers */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (me->totface) {
|
|
|
|
/* this wont be used, theres no need to keep it */
|
|
|
|
BKE_mesh_tessface_clear(me);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2012-02-08 11:52:44 +00:00
|
|
|
/* polling - retrieve whether cursor should be set or operator should be done */
|
2009-08-22 02:27:37 +00:00
|
|
|
|
|
|
|
/* Returns true if vertex paint mode is active */
|
|
|
|
int vertex_paint_mode_poll(bContext *C)
|
2009-01-25 21:02:52 +00:00
|
|
|
{
|
2009-08-15 20:36:15 +00:00
|
|
|
Object *ob = CTX_data_active_object(C);
|
|
|
|
|
2011-12-30 09:23:06 +00:00
|
|
|
return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totpoly;
|
2009-08-22 02:27:37 +00:00
|
|
|
}
|
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
int vertex_paint_poll(bContext *C)
|
2009-08-22 02:27:37 +00:00
|
|
|
{
|
2012-03-24 06:38:07 +00:00
|
|
|
if (vertex_paint_mode_poll(C) &&
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
BKE_paint_brush(&CTX_data_tool_settings(C)->vpaint->paint))
|
2012-03-28 03:47:33 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
ScrArea *sa = CTX_wm_area(C);
|
2012-09-23 05:33:23 +00:00
|
|
|
if (sa && sa->spacetype == SPACE_VIEW3D) {
|
2012-03-24 11:27:52 +00:00
|
|
|
ARegion *ar = CTX_wm_region(C);
|
|
|
|
if (ar->regiontype == RGN_TYPE_WINDOW)
|
2009-01-25 21:02:52 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2012-03-28 03:47:33 +00:00
|
|
|
}
|
2009-01-25 21:02:52 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-01-26 11:11:53 +00:00
|
|
|
int weight_paint_mode_poll(bContext *C)
|
|
|
|
{
|
|
|
|
Object *ob = CTX_data_active_object(C);
|
|
|
|
|
2011-12-30 09:23:06 +00:00
|
|
|
return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totpoly;
|
2010-01-26 11:11:53 +00:00
|
|
|
}
|
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
int weight_paint_poll(bContext *C)
|
2009-01-25 21:02:52 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
Object *ob = CTX_data_active_object(C);
|
2011-03-22 14:04:47 +00:00
|
|
|
ScrArea *sa;
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
if ((ob != NULL) &&
|
|
|
|
(ob->mode & OB_MODE_WEIGHT_PAINT) &&
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
(BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) &&
|
2012-03-24 11:27:52 +00:00
|
|
|
(sa = CTX_wm_area(C)) &&
|
|
|
|
(sa->spacetype == SPACE_VIEW3D))
|
|
|
|
{
|
|
|
|
ARegion *ar = CTX_wm_region(C);
|
|
|
|
if (ar->regiontype == RGN_TYPE_WINDOW) {
|
2011-03-22 14:04:47 +00:00
|
|
|
return 1;
|
2009-01-25 21:02:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
static VPaint *new_vpaint(int wpaint)
|
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
VPaint *vp = MEM_callocN(sizeof(VPaint), "VPaint");
|
2009-01-10 14:19:14 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
vp->flag = VP_AREA + VP_SPRAY;
|
2009-01-10 14:19:14 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (wpaint)
|
2012-03-24 11:27:52 +00:00
|
|
|
vp->flag = VP_AREA;
|
2009-03-11 00:43:08 +00:00
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
return vp;
|
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2010-02-06 15:50:53 +00:00
|
|
|
static int *get_indexarray(Mesh *me)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
return MEM_mallocN(sizeof(int) * (me->totpoly + 1), "vertexpaint");
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
|
2009-11-01 00:06:53 +00:00
|
|
|
unsigned int vpaint_get_current_col(VPaint *vp)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
Brush *brush = BKE_paint_brush(&vp->paint);
|
2012-03-17 21:11:28 +00:00
|
|
|
unsigned char col[4];
|
|
|
|
rgb_float_to_uchar(col, brush->rgb);
|
2012-03-18 07:38:51 +00:00
|
|
|
col[3] = 255; /* alpha isn't used, could even be removed to speedup paint a little */
|
2012-03-17 21:11:28 +00:00
|
|
|
return *(unsigned int *)col;
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
|
2013-04-25 14:29:19 +00:00
|
|
|
static void do_shared_vertex_tesscol(Mesh *me, bool *mfacetag)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
|
|
|
/* if no mcol: do not do */
|
|
|
|
/* if tface: only the involved faces, otherwise all */
|
2012-12-22 14:25:34 +00:00
|
|
|
const int use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL);
|
2009-01-07 19:23:22 +00:00
|
|
|
MFace *mface;
|
|
|
|
int a;
|
|
|
|
short *scolmain, *scol;
|
|
|
|
char *mcol;
|
2013-04-25 14:29:19 +00:00
|
|
|
bool *mftag;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
if (me->mcol == NULL || me->totvert == 0 || me->totface == 0) return;
|
|
|
|
|
|
|
|
scolmain = MEM_callocN(4 * sizeof(short) * me->totvert, "colmain");
|
|
|
|
|
|
|
|
mface = me->mface;
|
|
|
|
mcol = (char *)me->mcol;
|
|
|
|
for (a = me->totface; a > 0; a--, mface++, mcol += 16) {
|
2012-04-30 21:46:58 +00:00
|
|
|
if ((use_face_sel == FALSE) || (mface->flag & ME_FACE_SEL)) {
|
2012-03-24 11:27:52 +00:00
|
|
|
scol = scolmain + 4 * mface->v1;
|
|
|
|
scol[0]++; scol[1] += mcol[1]; scol[2] += mcol[2]; scol[3] += mcol[3];
|
|
|
|
scol = scolmain + 4 * mface->v2;
|
|
|
|
scol[0]++; scol[1] += mcol[5]; scol[2] += mcol[6]; scol[3] += mcol[7];
|
|
|
|
scol = scolmain + 4 * mface->v3;
|
|
|
|
scol[0]++; scol[1] += mcol[9]; scol[2] += mcol[10]; scol[3] += mcol[11];
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mface->v4) {
|
2012-03-24 11:27:52 +00:00
|
|
|
scol = scolmain + 4 * mface->v4;
|
|
|
|
scol[0]++; scol[1] += mcol[13]; scol[2] += mcol[14]; scol[3] += mcol[15];
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
a = me->totvert;
|
|
|
|
scol = scolmain;
|
2012-03-24 06:38:07 +00:00
|
|
|
while (a--) {
|
2012-03-24 11:27:52 +00:00
|
|
|
if (scol[0] > 1) {
|
2013-04-25 14:16:22 +00:00
|
|
|
scol[1] = divide_round_i(scol[1], scol[0]);
|
|
|
|
scol[2] = divide_round_i(scol[2], scol[0]);
|
|
|
|
scol[3] = divide_round_i(scol[3], scol[0]);
|
2012-03-24 11:27:52 +00:00
|
|
|
}
|
|
|
|
scol += 4;
|
|
|
|
}
|
2012-04-30 21:46:58 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
mface = me->mface;
|
|
|
|
mcol = (char *)me->mcol;
|
2013-04-25 14:29:19 +00:00
|
|
|
mftag = mfacetag;
|
|
|
|
for (a = me->totface; a > 0; a--, mface++, mcol += 16, mftag += 4) {
|
2012-05-06 22:12:26 +00:00
|
|
|
if ((use_face_sel == FALSE) || (mface->flag & ME_FACE_SEL)) {
|
2013-04-25 14:29:19 +00:00
|
|
|
if (mftag[0]) {
|
|
|
|
scol = scolmain + 4 * mface->v1;
|
|
|
|
mcol[1] = scol[1]; mcol[2] = scol[2]; mcol[3] = scol[3];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mftag[1]) {
|
|
|
|
scol = scolmain + 4 * mface->v2;
|
|
|
|
mcol[5] = scol[1]; mcol[6] = scol[2]; mcol[7] = scol[3];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mftag[2]) {
|
|
|
|
scol = scolmain + 4 * mface->v3;
|
|
|
|
mcol[9] = scol[1]; mcol[10] = scol[2]; mcol[11] = scol[3];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mface->v4 && mftag[3]) {
|
2012-03-24 11:27:52 +00:00
|
|
|
scol = scolmain + 4 * mface->v4;
|
|
|
|
mcol[13] = scol[1]; mcol[14] = scol[2]; mcol[15] = scol[3];
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(scolmain);
|
2009-09-05 06:10:30 +00:00
|
|
|
}
|
|
|
|
|
2013-04-25 14:29:19 +00:00
|
|
|
static void do_shared_vertexcol(Mesh *me, bool *mlooptag, bool *mfacetag, int do_tessface)
|
2009-09-05 06:10:30 +00:00
|
|
|
{
|
2012-12-22 14:25:34 +00:00
|
|
|
const int use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL);
|
2012-04-30 21:46:58 +00:00
|
|
|
MPoly *mp;
|
2013-04-25 14:16:22 +00:00
|
|
|
int (*scol)[4];
|
2012-04-30 21:46:58 +00:00
|
|
|
int i, j, has_shared = 0;
|
2009-09-05 06:10:30 +00:00
|
|
|
|
|
|
|
/* if no mloopcol: do not do */
|
|
|
|
/* if mtexpoly: only the involved faces, otherwise all */
|
|
|
|
|
2013-03-22 05:34:10 +00:00
|
|
|
if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) return;
|
2009-09-05 06:10:30 +00:00
|
|
|
|
2013-04-25 14:16:22 +00:00
|
|
|
scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol");
|
2009-09-05 06:10:30 +00:00
|
|
|
|
2012-04-30 21:46:58 +00:00
|
|
|
for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
|
|
|
|
if ((use_face_sel == FALSE) || (mp->flag & ME_FACE_SEL)) {
|
2012-05-23 21:39:39 +00:00
|
|
|
MLoop *ml = me->mloop + mp->loopstart;
|
|
|
|
MLoopCol *lcol = me->mloopcol + mp->loopstart;
|
2012-04-30 21:46:58 +00:00
|
|
|
for (j = 0; j < mp->totloop; j++, ml++, lcol++) {
|
|
|
|
scol[ml->v][0] += lcol->r;
|
|
|
|
scol[ml->v][1] += lcol->g;
|
|
|
|
scol[ml->v][2] += lcol->b;
|
2013-04-25 14:16:22 +00:00
|
|
|
scol[ml->v][3] += 1;
|
2012-04-30 21:46:58 +00:00
|
|
|
has_shared = 1;
|
|
|
|
}
|
2009-09-05 06:10:30 +00:00
|
|
|
}
|
|
|
|
}
|
2012-04-30 21:46:58 +00:00
|
|
|
|
2011-10-29 13:25:18 +00:00
|
|
|
if (has_shared) {
|
2012-03-24 11:27:52 +00:00
|
|
|
for (i = 0; i < me->totvert; i++) {
|
2013-04-25 14:16:22 +00:00
|
|
|
if (scol[i][3] != 0) {
|
|
|
|
scol[i][0] = divide_round_i(scol[i][0], scol[i][3]);
|
|
|
|
scol[i][1] = divide_round_i(scol[i][1], scol[i][3]);
|
|
|
|
scol[i][2] = divide_round_i(scol[i][2], scol[i][3]);
|
2012-04-30 21:46:58 +00:00
|
|
|
}
|
2011-10-29 13:25:18 +00:00
|
|
|
}
|
2012-04-30 21:46:58 +00:00
|
|
|
|
|
|
|
for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
|
|
|
|
if ((use_face_sel == FALSE) || (mp->flag & ME_FACE_SEL)) {
|
2012-05-23 21:39:39 +00:00
|
|
|
MLoop *ml = me->mloop + mp->loopstart;
|
|
|
|
MLoopCol *lcol = me->mloopcol + mp->loopstart;
|
2012-04-30 21:46:58 +00:00
|
|
|
for (j = 0; j < mp->totloop; j++, ml++, lcol++) {
|
2013-04-25 14:29:19 +00:00
|
|
|
if (mlooptag[mp->loopstart + j]) {
|
|
|
|
lcol->r = scol[ml->v][0];
|
|
|
|
lcol->g = scol[ml->v][1];
|
|
|
|
lcol->b = scol[ml->v][2];
|
|
|
|
}
|
2012-04-30 21:46:58 +00:00
|
|
|
}
|
|
|
|
}
|
2011-10-29 13:25:18 +00:00
|
|
|
}
|
2009-09-05 06:10:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(scol);
|
|
|
|
|
2012-02-08 11:52:44 +00:00
|
|
|
if (has_shared && do_tessface) {
|
2013-04-25 14:29:19 +00:00
|
|
|
do_shared_vertex_tesscol(me, mfacetag);
|
2011-10-29 13:25:18 +00:00
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
|
2013-04-27 19:00:26 +00:00
|
|
|
static bool make_vertexcol(Object *ob) /* single ob */
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
|
|
|
Mesh *me;
|
2013-04-27 19:00:26 +00:00
|
|
|
|
|
|
|
if ((ob->id.lib) ||
|
|
|
|
((me = BKE_mesh_from_object(ob)) == NULL) ||
|
|
|
|
(me->totpoly == 0) ||
|
|
|
|
(me->edit_btmesh))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
|
|
|
|
/* copies from shadedisplist to mcol */
|
2012-12-17 15:17:51 +00:00
|
|
|
if (!me->mloopcol && me->totloop) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!me->mcol) {
|
2012-01-18 08:43:27 +00:00
|
|
|
CustomData_add_layer(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface);
|
|
|
|
}
|
|
|
|
if (!me->mloopcol) {
|
2012-10-21 05:46:41 +00:00
|
|
|
CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop);
|
2012-01-18 08:43:27 +00:00
|
|
|
}
|
2013-03-17 19:55:10 +00:00
|
|
|
BKE_mesh_update_customdata_pointers(me, true);
|
2011-12-04 23:13:28 +00:00
|
|
|
}
|
2009-09-01 16:05:33 +00:00
|
|
|
|
2012-10-29 16:26:18 +00:00
|
|
|
update_tessface_data(ob, me);
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2011-01-03 12:41:16 +00:00
|
|
|
DAG_id_tag_update(&me->id, 0);
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2013-04-27 19:00:26 +00:00
|
|
|
return (me->mloopcol != NULL);
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
|
2011-05-31 03:48:27 +00:00
|
|
|
/* mirror_vgroup is set to -1 when invalid */
|
2011-12-30 02:16:07 +00:00
|
|
|
static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
|
2011-05-31 03:48:27 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active);
|
2011-05-31 03:48:27 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (defgroup) {
|
2011-05-31 03:48:27 +00:00
|
|
|
int mirrdef;
|
|
|
|
char name[MAXBONENAME];
|
|
|
|
|
|
|
|
flip_side_name(name, defgroup->name, FALSE);
|
2012-12-28 01:36:00 +00:00
|
|
|
mirrdef = defgroup_name_index(ob, name);
|
|
|
|
if (mirrdef == -1) {
|
2013-07-04 03:56:18 +00:00
|
|
|
if (BKE_defgroup_new(ob, name)) {
|
2012-12-28 01:36:00 +00:00
|
|
|
mirrdef = BLI_countlist(&ob->defbase) - 1;
|
2011-05-31 03:48:27 +00:00
|
|
|
}
|
|
|
|
}
|
2012-12-28 01:36:00 +00:00
|
|
|
|
|
|
|
/* curdef should never be NULL unless this is
|
|
|
|
* a lamp and ED_vgroup_add_name fails */
|
|
|
|
return mirrdef;
|
2011-05-31 03:48:27 +00:00
|
|
|
}
|
|
|
|
|
2011-10-06 04:33:00 +00:00
|
|
|
return -1;
|
2011-05-31 03:48:27 +00:00
|
|
|
}
|
|
|
|
|
2012-12-22 01:08:42 +00:00
|
|
|
static void free_vpaint_prev(VPaint *vp)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
2012-03-24 06:38:07 +00:00
|
|
|
if (vp->vpaint_prev) {
|
2009-01-07 19:23:22 +00:00
|
|
|
MEM_freeN(vp->vpaint_prev);
|
2012-03-24 11:27:52 +00:00
|
|
|
vp->vpaint_prev = NULL;
|
2012-12-22 01:08:42 +00:00
|
|
|
vp->tot = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_wpaint_prev(VPaint *vp)
|
|
|
|
{
|
|
|
|
if (vp->wpaint_prev) {
|
2012-12-28 09:06:48 +00:00
|
|
|
BKE_defvert_array_free(vp->wpaint_prev, vp->tot);
|
2012-12-22 01:08:42 +00:00
|
|
|
vp->wpaint_prev = NULL;
|
|
|
|
vp->tot = 0;
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
2012-12-22 01:08:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void copy_vpaint_prev(VPaint *vp, unsigned int *lcol, int tot)
|
|
|
|
{
|
|
|
|
free_vpaint_prev(vp);
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
vp->tot = tot;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
if (lcol == NULL || tot == 0) return;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
vp->vpaint_prev = MEM_mallocN(sizeof(int) * tot, "vpaint_prev");
|
|
|
|
memcpy(vp->vpaint_prev, lcol, sizeof(int) * tot);
|
2009-01-07 19:23:22 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
static void copy_wpaint_prev(VPaint *wp, MDeformVert *dverts, int dcount)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
2012-12-22 01:08:42 +00:00
|
|
|
free_wpaint_prev(wp);
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (dverts && dcount) {
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
wp->wpaint_prev = MEM_mallocN(sizeof(MDeformVert) * dcount, "wpaint prev");
|
2009-01-10 14:19:14 +00:00
|
|
|
wp->tot = dcount;
|
2012-12-28 09:06:48 +00:00
|
|
|
BKE_defvert_array_copy(wp->wpaint_prev, dverts, dcount);
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-27 19:00:26 +00:00
|
|
|
bool ED_vpaint_fill(Object *ob, unsigned int paintcol)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
|
|
|
Mesh *me;
|
2009-08-30 21:30:07 +00:00
|
|
|
MPoly *mp;
|
2013-04-27 19:00:26 +00:00
|
|
|
int i, j;
|
|
|
|
bool selected;
|
2011-11-10 06:06:35 +00:00
|
|
|
|
2013-04-27 19:00:26 +00:00
|
|
|
if (((me = BKE_mesh_from_object(ob)) == NULL) ||
|
|
|
|
(me->mloopcol == NULL && (make_vertexcol(ob) == false)))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2013-04-27 19:00:26 +00:00
|
|
|
selected = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2009-08-30 21:30:07 +00:00
|
|
|
mp = me->mpoly;
|
2012-03-24 11:27:52 +00:00
|
|
|
for (i = 0; i < me->totpoly; i++, mp++) {
|
2013-04-27 19:00:26 +00:00
|
|
|
MLoopCol *lcol = me->mloopcol + mp->loopstart;
|
|
|
|
|
|
|
|
if (selected && !(mp->flag & ME_FACE_SEL))
|
2009-08-30 21:30:07 +00:00
|
|
|
continue;
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
for (j = 0; j < mp->totloop; j++, lcol++) {
|
|
|
|
*(int *)lcol = paintcol;
|
2009-08-30 21:30:07 +00:00
|
|
|
}
|
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-02-08 11:52:44 +00:00
|
|
|
/* remove stale me->mcol, will be added later */
|
2012-02-12 19:11:09 +00:00
|
|
|
BKE_mesh_tessface_clear(me);
|
2012-02-08 11:52:44 +00:00
|
|
|
|
2011-01-03 12:41:16 +00:00
|
|
|
DAG_id_tag_update(&me->id, 0);
|
2013-04-27 19:00:26 +00:00
|
|
|
|
|
|
|
return true;
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* fills in the selected faces with the current weight and vertex group */
|
2013-04-27 19:00:26 +00:00
|
|
|
bool ED_wpaint_fill(VPaint *wp, Object *ob, float paintweight)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
Mesh *me = ob->data;
|
2012-04-03 23:40:24 +00:00
|
|
|
MPoly *mp;
|
2012-01-13 08:18:22 +00:00
|
|
|
MDeformWeight *dw, *dw_prev;
|
2012-03-24 11:27:52 +00:00
|
|
|
int vgroup_active, vgroup_mirror = -1;
|
2011-11-02 00:51:21 +00:00
|
|
|
unsigned int index;
|
2013-06-28 17:13:09 +00:00
|
|
|
const bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
|
2009-11-01 00:06:53 +00:00
|
|
|
|
2011-11-02 00:51:21 +00:00
|
|
|
/* mutually exclusive, could be made into a */
|
2012-03-24 11:27:52 +00:00
|
|
|
const short paint_selmode = ME_EDIT_PAINT_SEL_MODE(me);
|
2010-02-06 15:50:53 +00:00
|
|
|
|
2013-04-27 19:00:26 +00:00
|
|
|
if (me->totpoly == 0 || me->dvert == NULL || !me->mpoly) {
|
|
|
|
return false;
|
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2011-12-30 02:16:07 +00:00
|
|
|
vgroup_active = ob->actdef - 1;
|
2011-05-31 03:48:27 +00:00
|
|
|
|
2011-10-06 04:33:00 +00:00
|
|
|
/* if mirror painting, find the other group */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (me->editflag & ME_EDIT_MIRROR_X) {
|
2012-03-24 11:27:52 +00:00
|
|
|
vgroup_mirror = wpaint_mirror_vgroup_ensure(ob, vgroup_active);
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
copy_wpaint_prev(wp, me->dvert, me->totvert);
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-04-03 23:40:24 +00:00
|
|
|
for (index = 0, mp = me->mpoly; index < me->totpoly; index++, mp++) {
|
|
|
|
unsigned int fidx = mp->totloop - 1;
|
2011-09-19 17:53:37 +00:00
|
|
|
|
2012-04-03 23:40:24 +00:00
|
|
|
if ((paint_selmode == SCE_SELECT_FACE) && !(mp->flag & ME_FACE_SEL)) {
|
2011-11-02 00:51:21 +00:00
|
|
|
continue;
|
|
|
|
}
|
2011-09-19 17:53:37 +00:00
|
|
|
|
2011-11-02 00:51:21 +00:00
|
|
|
do {
|
2012-04-03 23:40:24 +00:00
|
|
|
unsigned int vidx = me->mloop[mp->loopstart + fidx].v;
|
2011-09-19 17:53:37 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!me->dvert[vidx].flag) {
|
|
|
|
if ((paint_selmode == SCE_SELECT_VERTEX) && !(me->mvert[vidx].flag & SELECT)) {
|
2011-11-02 00:51:21 +00:00
|
|
|
continue;
|
|
|
|
}
|
2011-07-18 17:38:17 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
dw = defvert_verify_index(&me->dvert[vidx], vgroup_active);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (dw) {
|
2012-03-24 11:27:52 +00:00
|
|
|
dw_prev = defvert_verify_index(wp->wpaint_prev + vidx, vgroup_active);
|
|
|
|
dw_prev->weight = dw->weight; /* set the undo weight */
|
|
|
|
dw->weight = paintweight;
|
2011-11-02 00:51:21 +00:00
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
if (me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */
|
2013-06-28 17:13:09 +00:00
|
|
|
int j = mesh_get_x_mirror_vert(ob, vidx, topology);
|
2012-03-24 11:27:52 +00:00
|
|
|
if (j >= 0) {
|
2011-11-02 00:51:21 +00:00
|
|
|
/* copy, not paint again */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (vgroup_mirror != -1) {
|
2012-03-24 11:27:52 +00:00
|
|
|
dw = defvert_verify_index(me->dvert + j, vgroup_mirror);
|
|
|
|
dw_prev = defvert_verify_index(wp->wpaint_prev + j, vgroup_mirror);
|
2012-03-24 06:38:07 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-03-24 11:27:52 +00:00
|
|
|
dw = defvert_verify_index(me->dvert + j, vgroup_active);
|
|
|
|
dw_prev = defvert_verify_index(wp->wpaint_prev + j, vgroup_active);
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
2012-03-24 11:27:52 +00:00
|
|
|
dw_prev->weight = dw->weight; /* set the undo weight */
|
|
|
|
dw->weight = paintweight;
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-03-24 11:27:52 +00:00
|
|
|
me->dvert[vidx].flag = 1;
|
2011-11-02 00:51:21 +00:00
|
|
|
}
|
2011-09-19 17:53:37 +00:00
|
|
|
|
2011-11-02 00:51:21 +00:00
|
|
|
} while (fidx--);
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
2011-09-19 17:53:37 +00:00
|
|
|
|
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
MDeformVert *dv = me->dvert;
|
|
|
|
for (index = me->totvert; index != 0; index--, dv++) {
|
|
|
|
dv->flag = 0;
|
2011-09-19 17:53:37 +00:00
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
2011-11-02 00:51:21 +00:00
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
copy_wpaint_prev(wp, NULL, 0);
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2011-01-03 12:41:16 +00:00
|
|
|
DAG_id_tag_update(&me->id, 0);
|
2013-04-27 19:00:26 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ED_vpaint_smooth(Object *ob)
|
|
|
|
{
|
|
|
|
Mesh *me;
|
|
|
|
MPoly *mp;
|
|
|
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
bool *mlooptag;
|
|
|
|
bool selected;
|
|
|
|
|
|
|
|
if (((me = BKE_mesh_from_object(ob)) == NULL) ||
|
|
|
|
(me->mloopcol == NULL && (make_vertexcol(ob) == false)))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
selected = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
|
|
|
|
|
|
|
|
mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
|
|
|
|
|
|
|
|
/* simply tag loops of selected faces */
|
|
|
|
mp = me->mpoly;
|
|
|
|
for (i = 0; i < me->totpoly; i++, mp++) {
|
|
|
|
MLoop *ml = me->mloop + mp->loopstart;
|
|
|
|
int ml_index = mp->loopstart;
|
|
|
|
|
|
|
|
if (selected && !(mp->flag & ME_FACE_SEL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = 0; j < mp->totloop; j++, ml_index++, ml++) {
|
|
|
|
mlooptag[ml_index] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove stale me->mcol, will be added later */
|
|
|
|
BKE_mesh_tessface_clear(me);
|
|
|
|
|
|
|
|
do_shared_vertexcol(me, mlooptag, NULL, false);
|
|
|
|
|
|
|
|
MEM_freeN(mlooptag);
|
|
|
|
|
|
|
|
DAG_id_tag_update(&me->id, 0);
|
|
|
|
|
|
|
|
return true;
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
|
2012-03-03 16:31:46 +00:00
|
|
|
/* XXX: should be re-implemented as a vertex/weight paint 'color correct' operator */
|
|
|
|
#if 0
|
2009-01-07 19:23:22 +00:00
|
|
|
void vpaint_dogamma(Scene *scene)
|
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
VPaint *vp = scene->toolsettings->vpaint;
|
2009-01-07 19:23:22 +00:00
|
|
|
Mesh *me;
|
|
|
|
Object *ob;
|
|
|
|
float igam, fac;
|
|
|
|
int a, temp;
|
2009-01-26 09:13:15 +00:00
|
|
|
unsigned char *cp, gamtab[256];
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
ob = OBACT;
|
2012-05-05 16:03:57 +00:00
|
|
|
me = BKE_mesh_from_object(ob);
|
2009-08-15 20:36:15 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!(ob->mode & OB_MODE_VERTEX_PAINT)) return;
|
2012-03-24 11:27:52 +00:00
|
|
|
if (me == 0 || me->mcol == 0 || me->totface == 0) return;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
igam = 1.0 / vp->gamma;
|
|
|
|
for (a = 0; a < 256; a++) {
|
2011-12-30 09:23:06 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
fac = ((float)a) / 255.0;
|
2012-03-28 03:47:33 +00:00
|
|
|
fac = vp->mul * pow(fac, igam);
|
2011-12-30 09:23:06 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
temp = 255.9 * fac;
|
2011-12-30 09:23:06 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
if (temp <= 0) gamtab[a] = 0;
|
|
|
|
else if (temp >= 255) gamtab[a] = 255;
|
|
|
|
else gamtab[a] = temp;
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
a = 4 * me->totface;
|
|
|
|
cp = (unsigned char *)me->mcol;
|
2012-03-24 06:38:07 +00:00
|
|
|
while (a--) {
|
2011-12-30 09:23:06 +00:00
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
cp[1] = gamtab[cp[1]];
|
|
|
|
cp[2] = gamtab[cp[2]];
|
|
|
|
cp[3] = gamtab[cp[3]];
|
2011-12-30 09:23:06 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
cp += 4;
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
2012-03-03 16:31:46 +00:00
|
|
|
#endif
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-20 08:42:26 +00:00
|
|
|
BLI_INLINE unsigned int mcol_blend(unsigned int col1, unsigned int col2, int fac)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
2012-03-17 21:11:28 +00:00
|
|
|
unsigned char *cp1, *cp2, *cp;
|
2009-01-07 19:23:22 +00:00
|
|
|
int mfac;
|
2012-03-17 21:11:28 +00:00
|
|
|
unsigned int col = 0;
|
|
|
|
|
|
|
|
if (fac == 0) {
|
|
|
|
return col1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fac >= 255) {
|
|
|
|
return col2;
|
|
|
|
}
|
|
|
|
|
|
|
|
mfac = 255 - fac;
|
|
|
|
|
|
|
|
cp1 = (unsigned char *)&col1;
|
|
|
|
cp2 = (unsigned char *)&col2;
|
|
|
|
cp = (unsigned char *)&col;
|
|
|
|
|
2013-04-25 14:16:22 +00:00
|
|
|
cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255);
|
|
|
|
cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255);
|
|
|
|
cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255);
|
2012-03-17 21:11:28 +00:00
|
|
|
cp[3] = 255;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
|
|
|
return col;
|
|
|
|
}
|
|
|
|
|
2012-03-20 08:42:26 +00:00
|
|
|
BLI_INLINE unsigned int mcol_add(unsigned int col1, unsigned int col2, int fac)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
2012-03-17 21:11:28 +00:00
|
|
|
unsigned char *cp1, *cp2, *cp;
|
2009-01-07 19:23:22 +00:00
|
|
|
int temp;
|
2012-03-17 21:11:28 +00:00
|
|
|
unsigned int col = 0;
|
|
|
|
|
|
|
|
if (fac == 0) {
|
|
|
|
return col1;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp1 = (unsigned char *)&col1;
|
|
|
|
cp2 = (unsigned char *)&col2;
|
|
|
|
cp = (unsigned char *)&col;
|
|
|
|
|
2013-04-25 14:16:22 +00:00
|
|
|
temp = cp1[0] + divide_round_i((fac * cp2[0]), 255);
|
2012-03-17 21:11:28 +00:00
|
|
|
cp[0] = (temp > 254) ? 255 : temp;
|
2013-04-25 14:16:22 +00:00
|
|
|
temp = cp1[1] + divide_round_i((fac * cp2[1]), 255);
|
2012-03-17 21:11:28 +00:00
|
|
|
cp[1] = (temp > 254) ? 255 : temp;
|
2013-04-25 14:16:22 +00:00
|
|
|
temp = cp1[2] + divide_round_i((fac * cp2[2]), 255);
|
2012-03-17 21:11:28 +00:00
|
|
|
cp[2] = (temp > 254) ? 255 : temp;
|
|
|
|
cp[3] = 255;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
|
|
|
return col;
|
|
|
|
}
|
|
|
|
|
2012-03-20 08:42:26 +00:00
|
|
|
BLI_INLINE unsigned int mcol_sub(unsigned int col1, unsigned int col2, int fac)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
2012-03-17 21:11:28 +00:00
|
|
|
unsigned char *cp1, *cp2, *cp;
|
2009-01-07 19:23:22 +00:00
|
|
|
int temp;
|
2012-03-17 21:11:28 +00:00
|
|
|
unsigned int col = 0;
|
|
|
|
|
|
|
|
if (fac == 0) {
|
|
|
|
return col1;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp1 = (unsigned char *)&col1;
|
|
|
|
cp2 = (unsigned char *)&col2;
|
|
|
|
cp = (unsigned char *)&col;
|
|
|
|
|
2013-04-25 14:16:22 +00:00
|
|
|
temp = cp1[0] - divide_round_i((fac * cp2[0]), 255);
|
2012-12-14 12:00:59 +00:00
|
|
|
cp[0] = (temp < 0) ? 0 : temp;
|
2013-04-25 14:16:22 +00:00
|
|
|
temp = cp1[1] - divide_round_i((fac * cp2[1]), 255);
|
2012-12-14 12:00:59 +00:00
|
|
|
cp[1] = (temp < 0) ? 0 : temp;
|
2013-04-25 14:16:22 +00:00
|
|
|
temp = cp1[2] - divide_round_i((fac * cp2[2]), 255);
|
2012-12-14 12:00:59 +00:00
|
|
|
cp[2] = (temp < 0) ? 0 : temp;
|
2012-03-17 21:11:28 +00:00
|
|
|
cp[3] = 255;
|
|
|
|
|
2009-01-07 19:23:22 +00:00
|
|
|
return col;
|
|
|
|
}
|
|
|
|
|
2012-03-20 08:42:26 +00:00
|
|
|
BLI_INLINE unsigned int mcol_mul(unsigned int col1, unsigned int col2, int fac)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
2012-03-17 21:11:28 +00:00
|
|
|
unsigned char *cp1, *cp2, *cp;
|
2009-01-07 19:23:22 +00:00
|
|
|
int mfac;
|
2012-03-17 21:11:28 +00:00
|
|
|
unsigned int col = 0;
|
|
|
|
|
|
|
|
if (fac == 0) {
|
|
|
|
return col1;
|
|
|
|
}
|
|
|
|
|
|
|
|
mfac = 255 - fac;
|
|
|
|
|
|
|
|
cp1 = (unsigned char *)&col1;
|
|
|
|
cp2 = (unsigned char *)&col2;
|
|
|
|
cp = (unsigned char *)&col;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
|
|
|
/* first mul, then blend the fac */
|
2013-04-25 16:35:57 +00:00
|
|
|
cp[0] = divide_round_i(mfac * cp1[0] * 255 + fac * cp2[0] * cp1[0], 255 * 255);
|
|
|
|
cp[1] = divide_round_i(mfac * cp1[1] * 255 + fac * cp2[1] * cp1[1], 255 * 255);
|
|
|
|
cp[2] = divide_round_i(mfac * cp1[2] * 255 + fac * cp2[2] * cp1[2], 255 * 255);
|
2012-03-17 21:11:28 +00:00
|
|
|
cp[3] = 255;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
|
|
|
return col;
|
|
|
|
}
|
|
|
|
|
2012-03-20 08:42:26 +00:00
|
|
|
BLI_INLINE unsigned int mcol_lighten(unsigned int col1, unsigned int col2, int fac)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
2012-03-17 21:11:28 +00:00
|
|
|
unsigned char *cp1, *cp2, *cp;
|
2009-01-07 19:23:22 +00:00
|
|
|
int mfac;
|
2012-03-17 21:11:28 +00:00
|
|
|
unsigned int col = 0;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-17 21:11:28 +00:00
|
|
|
if (fac == 0) {
|
|
|
|
return col1;
|
|
|
|
}
|
|
|
|
else if (fac >= 255) {
|
|
|
|
return col2;
|
|
|
|
}
|
|
|
|
|
|
|
|
mfac = 255 - fac;
|
|
|
|
|
|
|
|
cp1 = (unsigned char *)&col1;
|
|
|
|
cp2 = (unsigned char *)&col2;
|
|
|
|
cp = (unsigned char *)&col;
|
|
|
|
|
|
|
|
/* See if are lighter, if so mix, else don't do anything.
|
2012-03-03 16:31:46 +00:00
|
|
|
* if the paint col is darker then the original, then ignore */
|
2012-03-17 21:11:28 +00:00
|
|
|
if (rgb_to_grayscale_byte(cp1) > rgb_to_grayscale_byte(cp2)) {
|
2009-01-07 19:23:22 +00:00
|
|
|
return col1;
|
2012-03-17 21:11:28 +00:00
|
|
|
}
|
|
|
|
|
2013-04-25 14:16:22 +00:00
|
|
|
cp[0] = divide_round_i(mfac * cp1[0] + fac * cp2[0], 255);
|
|
|
|
cp[1] = divide_round_i(mfac * cp1[1] + fac * cp2[1], 255);
|
|
|
|
cp[2] = divide_round_i(mfac * cp1[2] + fac * cp2[2], 255);
|
2012-03-17 21:11:28 +00:00
|
|
|
cp[3] = 255;
|
|
|
|
|
2009-01-07 19:23:22 +00:00
|
|
|
return col;
|
|
|
|
}
|
|
|
|
|
2012-03-20 08:42:26 +00:00
|
|
|
BLI_INLINE unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fac)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
2012-03-17 21:11:28 +00:00
|
|
|
unsigned char *cp1, *cp2, *cp;
|
2009-01-07 19:23:22 +00:00
|
|
|
int mfac;
|
2012-03-17 21:11:28 +00:00
|
|
|
unsigned int col = 0;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-17 21:11:28 +00:00
|
|
|
if (fac == 0) {
|
|
|
|
return col1;
|
|
|
|
}
|
|
|
|
else if (fac >= 255) {
|
|
|
|
return col2;
|
|
|
|
}
|
|
|
|
|
|
|
|
mfac = 255 - fac;
|
|
|
|
|
|
|
|
cp1 = (unsigned char *)&col1;
|
|
|
|
cp2 = (unsigned char *)&col2;
|
|
|
|
cp = (unsigned char *)&col;
|
|
|
|
|
|
|
|
/* See if were darker, if so mix, else don't do anything.
|
2012-03-03 16:31:46 +00:00
|
|
|
* if the paint col is brighter then the original, then ignore */
|
2012-03-17 21:11:28 +00:00
|
|
|
if (rgb_to_grayscale_byte(cp1) < rgb_to_grayscale_byte(cp2)) {
|
2009-01-07 19:23:22 +00:00
|
|
|
return col1;
|
2012-03-17 21:11:28 +00:00
|
|
|
}
|
|
|
|
|
2013-04-25 14:16:22 +00:00
|
|
|
cp[0] = divide_round_i((mfac * cp1[0] + fac * cp2[0]), 255);
|
|
|
|
cp[1] = divide_round_i((mfac * cp1[1] + fac * cp2[1]), 255);
|
|
|
|
cp[2] = divide_round_i((mfac * cp1[2] + fac * cp2[2]), 255);
|
2012-03-17 21:11:28 +00:00
|
|
|
cp[3] = 255;
|
2009-01-07 19:23:22 +00:00
|
|
|
return col;
|
|
|
|
}
|
|
|
|
|
2012-01-15 06:29:08 +00:00
|
|
|
/* wpaint has 'wpaint_blend_tool' */
|
|
|
|
static unsigned int vpaint_blend_tool(const int tool, const unsigned int col,
|
2012-01-15 07:15:15 +00:00
|
|
|
const unsigned int paintcol, const int alpha_i)
|
2012-01-15 06:29:08 +00:00
|
|
|
{
|
|
|
|
switch (tool) {
|
|
|
|
case PAINT_BLEND_MIX:
|
2012-01-22 04:30:11 +00:00
|
|
|
case PAINT_BLEND_BLUR: return mcol_blend(col, paintcol, alpha_i);
|
|
|
|
case PAINT_BLEND_ADD: return mcol_add(col, paintcol, alpha_i);
|
|
|
|
case PAINT_BLEND_SUB: return mcol_sub(col, paintcol, alpha_i);
|
|
|
|
case PAINT_BLEND_MUL: return mcol_mul(col, paintcol, alpha_i);
|
|
|
|
case PAINT_BLEND_LIGHTEN: return mcol_lighten(col, paintcol, alpha_i);
|
|
|
|
case PAINT_BLEND_DARKEN: return mcol_darken(col, paintcol, alpha_i);
|
2012-01-15 06:29:08 +00:00
|
|
|
default:
|
|
|
|
BLI_assert(0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* wpaint has 'wpaint_blend' */
|
2012-01-15 07:46:59 +00:00
|
|
|
static unsigned int vpaint_blend(VPaint *vp, unsigned int col, unsigned int colorig, const
|
|
|
|
unsigned int paintcol, const int alpha_i,
|
|
|
|
/* pre scaled from [0-1] --> [0-255] */
|
|
|
|
const int brush_alpha_value_i)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
Brush *brush = BKE_paint_brush(&vp->paint);
|
2012-01-15 06:29:08 +00:00
|
|
|
const int tool = brush->vertexpaint_tool;
|
|
|
|
|
2012-01-15 07:46:59 +00:00
|
|
|
col = vpaint_blend_tool(tool, col, paintcol, alpha_i);
|
2009-01-07 19:23:22 +00:00
|
|
|
|
|
|
|
/* if no spray, clip color adding with colorig & orig alpha */
|
2012-03-24 11:27:52 +00:00
|
|
|
if ((vp->flag & VP_SPRAY) == 0) {
|
2012-01-15 06:29:08 +00:00
|
|
|
unsigned int testcol, a;
|
2009-01-07 19:23:22 +00:00
|
|
|
char *cp, *ct, *co;
|
|
|
|
|
2012-01-15 07:46:59 +00:00
|
|
|
testcol = vpaint_blend_tool(tool, colorig, paintcol, brush_alpha_value_i);
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
cp = (char *)&col;
|
|
|
|
ct = (char *)&testcol;
|
|
|
|
co = (char *)&colorig;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
for (a = 0; a < 4; a++) {
|
2012-03-28 03:47:33 +00:00
|
|
|
if (ct[a] < co[a]) {
|
|
|
|
if (cp[a] < ct[a]) cp[a] = ct[a];
|
|
|
|
else if (cp[a] > co[a]) cp[a] = co[a];
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-03-28 03:47:33 +00:00
|
|
|
if (cp[a] < co[a]) cp[a] = co[a];
|
|
|
|
else if (cp[a] > ct[a]) cp[a] = ct[a];
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-01-15 07:46:59 +00:00
|
|
|
|
|
|
|
return col;
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x, int y, float size)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
|
|
|
struct ImBuf *ibuf;
|
2012-03-24 11:27:52 +00:00
|
|
|
int a, tot = 0, index;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-04 04:35:12 +00:00
|
|
|
/* brecht: disabled this because it obviously fails for
|
2012-03-03 16:31:46 +00:00
|
|
|
* brushes with size > 64, why is this here? */
|
2012-04-21 12:51:47 +00:00
|
|
|
/*if (size > 64.0) size = 64.0;*/
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
ibuf = view3d_read_backbuf(vc, x - size, y - size, x + size, y + size);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ibuf) {
|
2012-03-24 11:27:52 +00:00
|
|
|
unsigned int *rt = ibuf->rect;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
memset(indexar, 0, sizeof(int) * (totface + 1));
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
size = ibuf->x * ibuf->y;
|
2012-03-24 06:38:07 +00:00
|
|
|
while (size--) {
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (*rt) {
|
2012-03-24 11:27:52 +00:00
|
|
|
index = WM_framebuffer_to_index(*rt);
|
|
|
|
if (index > 0 && index <= totface)
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
indexar[index] = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rt++;
|
|
|
|
}
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
for (a = 1; a <= totface; a++) {
|
|
|
|
if (indexar[a]) indexar[tot++] = a;
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
IMB_freeImBuf(ibuf);
|
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
|
|
|
|
return tot;
|
|
|
|
}
|
|
|
|
|
2011-12-30 05:16:28 +00:00
|
|
|
/* whats _dl mean? */
|
2013-03-14 03:42:17 +00:00
|
|
|
static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co[3],
|
|
|
|
const float mval[2], const float brush_size_pressure, float rgba[4])
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
2013-03-14 05:59:34 +00:00
|
|
|
float co_ss[2]; /* screenspace */
|
2012-10-05 03:57:56 +00:00
|
|
|
|
2013-01-01 14:20:59 +00:00
|
|
|
if (ED_view3d_project_float_object(vc->ar,
|
2013-03-14 05:59:34 +00:00
|
|
|
co, co_ss,
|
2012-12-25 14:09:51 +00:00
|
|
|
V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
|
|
|
|
{
|
2012-10-05 03:57:56 +00:00
|
|
|
float delta[2];
|
|
|
|
float dist_squared;
|
2013-03-31 00:38:50 +00:00
|
|
|
float factor = 1.0;
|
2012-10-05 03:57:56 +00:00
|
|
|
|
2013-03-14 05:59:34 +00:00
|
|
|
sub_v2_v2v2(delta, mval, co_ss);
|
2012-10-05 03:57:56 +00:00
|
|
|
dist_squared = dot_v2v2(delta, delta); /* len squared */
|
|
|
|
if (dist_squared <= brush_size_pressure * brush_size_pressure) {
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
Brush *brush = BKE_paint_brush(&vp->paint);
|
2012-10-05 03:57:56 +00:00
|
|
|
const float dist = sqrtf(dist_squared);
|
2013-03-14 03:47:20 +00:00
|
|
|
if (brush->mtex.tex && rgba) {
|
2013-03-14 05:59:34 +00:00
|
|
|
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
|
2013-03-14 03:42:17 +00:00
|
|
|
BKE_brush_sample_tex_3D(vc->scene, brush, co, rgba, 0, NULL);
|
2013-03-14 05:59:34 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */
|
|
|
|
BKE_brush_sample_tex_3D(vc->scene, brush, co_ss_3d, rgba, 0, NULL);
|
|
|
|
}
|
2013-03-31 00:38:50 +00:00
|
|
|
factor = rgba[3];
|
2013-03-14 03:42:17 +00:00
|
|
|
}
|
2013-03-31 03:28:46 +00:00
|
|
|
return factor * BKE_brush_curve_strength_clamp(brush, dist, brush_size_pressure);
|
2012-10-05 03:57:56 +00:00
|
|
|
}
|
2011-12-30 03:50:04 +00:00
|
|
|
}
|
2013-03-14 05:52:30 +00:00
|
|
|
if (rgba)
|
2013-03-14 03:47:20 +00:00
|
|
|
zero_v4(rgba);
|
2012-10-05 03:57:56 +00:00
|
|
|
return 0.0f;
|
2011-12-30 03:50:04 +00:00
|
|
|
}
|
|
|
|
|
2013-03-14 03:47:20 +00:00
|
|
|
static float calc_vp_alpha_col_dl(VPaint *vp, ViewContext *vc,
|
2012-12-15 16:13:27 +00:00
|
|
|
float vpimat[3][3], const DMCoNo *v_co_no,
|
2011-12-30 05:16:28 +00:00
|
|
|
const float mval[2],
|
2013-03-14 03:42:17 +00:00
|
|
|
const float brush_size_pressure, const float brush_alpha_pressure, float rgba[4])
|
2011-12-30 05:16:28 +00:00
|
|
|
{
|
2013-03-14 03:42:17 +00:00
|
|
|
float strength = calc_vp_strength_col_dl(vp, vc, v_co_no->co, mval, brush_size_pressure, rgba);
|
2011-12-30 03:50:04 +00:00
|
|
|
|
2011-12-30 05:16:28 +00:00
|
|
|
if (strength > 0.0f) {
|
2012-03-24 11:27:52 +00:00
|
|
|
float alpha = brush_alpha_pressure * strength;
|
2011-12-30 03:50:04 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (vp->flag & VP_NORMALS) {
|
2011-12-30 05:16:28 +00:00
|
|
|
float dvec[3];
|
2011-12-30 03:50:04 +00:00
|
|
|
|
|
|
|
/* transpose ! */
|
2012-12-15 16:13:27 +00:00
|
|
|
dvec[2] = dot_v3v3(vpimat[2], v_co_no->no);
|
2011-12-30 03:50:04 +00:00
|
|
|
if (dvec[2] > 0.0f) {
|
2012-12-15 16:13:27 +00:00
|
|
|
dvec[0] = dot_v3v3(vpimat[0], v_co_no->no);
|
|
|
|
dvec[1] = dot_v3v3(vpimat[1], v_co_no->no);
|
2011-12-30 03:50:04 +00:00
|
|
|
|
2011-12-30 05:16:28 +00:00
|
|
|
alpha *= dvec[2] / len_v3(dvec);
|
2011-12-30 03:50:04 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return 0.0f;
|
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
2011-12-30 03:50:04 +00:00
|
|
|
|
|
|
|
return alpha;
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
2011-12-30 05:16:28 +00:00
|
|
|
|
|
|
|
return 0.0f;
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-22 04:30:11 +00:00
|
|
|
|
2012-03-20 08:42:26 +00:00
|
|
|
BLI_INLINE float wval_blend(const float weight, const float paintval, const float alpha)
|
2012-01-22 04:30:11 +00:00
|
|
|
{
|
2013-02-25 03:45:56 +00:00
|
|
|
const float talpha = min_ff(alpha, 1.0f); /* blending with values over 1 doesn't make sense */
|
|
|
|
return (paintval * talpha) + (weight * (1.0f - talpha));
|
2012-01-22 04:30:11 +00:00
|
|
|
}
|
2012-03-20 08:42:26 +00:00
|
|
|
BLI_INLINE float wval_add(const float weight, const float paintval, const float alpha)
|
2012-01-22 04:30:11 +00:00
|
|
|
{
|
|
|
|
return weight + (paintval * alpha);
|
|
|
|
}
|
2012-03-20 08:42:26 +00:00
|
|
|
BLI_INLINE float wval_sub(const float weight, const float paintval, const float alpha)
|
2012-01-22 04:30:11 +00:00
|
|
|
{
|
|
|
|
return weight - (paintval * alpha);
|
|
|
|
}
|
2012-03-20 08:42:26 +00:00
|
|
|
BLI_INLINE float wval_mul(const float weight, const float paintval, const float alpha)
|
2012-03-28 03:47:33 +00:00
|
|
|
{ /* first mul, then blend the fac */
|
2012-01-22 04:30:11 +00:00
|
|
|
return ((1.0f - alpha) + (alpha * paintval)) * weight;
|
|
|
|
}
|
2012-03-20 08:42:26 +00:00
|
|
|
BLI_INLINE float wval_lighten(const float weight, const float paintval, const float alpha)
|
2012-01-22 04:30:11 +00:00
|
|
|
{
|
|
|
|
return (weight < paintval) ? wval_blend(weight, paintval, alpha) : weight;
|
|
|
|
}
|
2012-03-20 08:42:26 +00:00
|
|
|
BLI_INLINE float wval_darken(const float weight, const float paintval, const float alpha)
|
2012-01-22 04:30:11 +00:00
|
|
|
{
|
|
|
|
return (weight > paintval) ? wval_blend(weight, paintval, alpha) : weight;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-15 06:29:08 +00:00
|
|
|
/* vpaint has 'vpaint_blend_tool' */
|
2012-01-15 07:15:15 +00:00
|
|
|
/* result is not clamped from [0-1] */
|
2012-01-15 06:29:08 +00:00
|
|
|
static float wpaint_blend_tool(const int tool,
|
|
|
|
/* dw->weight */
|
|
|
|
const float weight,
|
|
|
|
const float paintval, const float alpha)
|
|
|
|
{
|
|
|
|
switch (tool) {
|
|
|
|
case PAINT_BLEND_MIX:
|
2012-01-22 04:30:11 +00:00
|
|
|
case PAINT_BLEND_BLUR: return wval_blend(weight, paintval, alpha);
|
|
|
|
case PAINT_BLEND_ADD: return wval_add(weight, paintval, alpha);
|
|
|
|
case PAINT_BLEND_SUB: return wval_sub(weight, paintval, alpha);
|
|
|
|
case PAINT_BLEND_MUL: return wval_mul(weight, paintval, alpha);
|
|
|
|
case PAINT_BLEND_LIGHTEN: return wval_lighten(weight, paintval, alpha);
|
|
|
|
case PAINT_BLEND_DARKEN: return wval_darken(weight, paintval, alpha);
|
2012-01-15 06:29:08 +00:00
|
|
|
default:
|
|
|
|
BLI_assert(0);
|
|
|
|
return 0.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* vpaint has 'vpaint_blend' */
|
2012-01-15 07:46:59 +00:00
|
|
|
static float wpaint_blend(VPaint *wp, float weight, float weight_prev,
|
|
|
|
const float alpha, float paintval,
|
|
|
|
const float brush_alpha_value,
|
|
|
|
const short do_flip, const short do_multipaint_totsel)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
Brush *brush = BKE_paint_brush(&wp->paint);
|
2010-01-20 08:30:40 +00:00
|
|
|
int tool = brush->vertexpaint_tool;
|
2011-12-30 05:16:28 +00:00
|
|
|
|
2012-01-15 07:46:59 +00:00
|
|
|
if (do_flip) {
|
2012-03-28 03:47:33 +00:00
|
|
|
switch (tool) {
|
2012-01-15 06:29:08 +00:00
|
|
|
case PAINT_BLEND_MIX:
|
2009-11-20 01:39:27 +00:00
|
|
|
paintval = 1.f - paintval; break;
|
2012-01-15 06:29:08 +00:00
|
|
|
case PAINT_BLEND_ADD:
|
2012-03-24 11:27:52 +00:00
|
|
|
tool = PAINT_BLEND_SUB; break;
|
2012-01-15 06:29:08 +00:00
|
|
|
case PAINT_BLEND_SUB:
|
2012-03-24 11:27:52 +00:00
|
|
|
tool = PAINT_BLEND_ADD; break;
|
2012-01-15 06:29:08 +00:00
|
|
|
case PAINT_BLEND_LIGHTEN:
|
2012-03-24 11:27:52 +00:00
|
|
|
tool = PAINT_BLEND_DARKEN; break;
|
2012-01-15 06:29:08 +00:00
|
|
|
case PAINT_BLEND_DARKEN:
|
2012-03-24 11:27:52 +00:00
|
|
|
tool = PAINT_BLEND_LIGHTEN; break;
|
2009-11-20 01:39:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-15 07:46:59 +00:00
|
|
|
weight = wpaint_blend_tool(tool, weight, paintval, alpha);
|
2012-01-15 06:29:08 +00:00
|
|
|
|
|
|
|
/* delay clamping until the end so multi-paint can function when the active group is at the limits */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (do_multipaint_totsel == FALSE) {
|
2012-01-15 07:46:59 +00:00
|
|
|
CLAMP(weight, 0.0f, 1.0f);
|
2011-09-18 17:10:28 +00:00
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
|
|
|
|
/* if no spray, clip result with orig weight & orig alpha */
|
2012-01-15 06:29:08 +00:00
|
|
|
if ((wp->flag & VP_SPRAY) == 0) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (do_multipaint_totsel == FALSE) {
|
2012-01-15 07:46:59 +00:00
|
|
|
float testw = wpaint_blend_tool(tool, weight_prev, paintval, brush_alpha_value);
|
2012-01-15 07:15:15 +00:00
|
|
|
|
2011-09-18 17:10:28 +00:00
|
|
|
CLAMP(testw, 0.0f, 1.0f);
|
2012-01-15 07:46:59 +00:00
|
|
|
if (testw < weight_prev) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (weight < testw) weight = testw;
|
|
|
|
else if (weight > weight_prev) weight = weight_prev;
|
2011-06-29 18:20:39 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-01-15 07:46:59 +00:00
|
|
|
if (weight > testw) weight = testw;
|
|
|
|
else if (weight < weight_prev) weight = weight_prev;
|
2011-06-29 18:20:39 +00:00
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
2012-01-15 07:46:59 +00:00
|
|
|
|
|
|
|
return weight;
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------- */
|
|
|
|
|
2011-05-25 10:07:59 +00:00
|
|
|
|
|
|
|
/* sets wp->weight to the closest weight value to vertex */
|
|
|
|
/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */
|
2013-03-13 09:03:46 +00:00
|
|
|
static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
|
|
|
ViewContext vc;
|
2011-05-25 10:07:59 +00:00
|
|
|
Mesh *me;
|
2012-03-24 11:27:52 +00:00
|
|
|
short change = FALSE;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2011-05-25 10:07:59 +00:00
|
|
|
view3d_set_viewcontext(C, &vc);
|
2012-05-05 16:03:57 +00:00
|
|
|
me = BKE_mesh_from_object(vc.obact);
|
2011-05-25 10:07:59 +00:00
|
|
|
|
|
|
|
if (me && me->dvert && vc.v3d && vc.rv3d) {
|
2012-12-22 14:25:34 +00:00
|
|
|
const int use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
|
2012-09-07 05:54:54 +00:00
|
|
|
int v_idx_best = -1;
|
|
|
|
unsigned int index;
|
2011-05-25 10:07:59 +00:00
|
|
|
|
|
|
|
view3d_operator_needs_opengl(C);
|
2013-01-30 02:27:13 +00:00
|
|
|
ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d);
|
2011-05-25 10:07:59 +00:00
|
|
|
|
2012-09-07 05:54:54 +00:00
|
|
|
if (use_vert_sel) {
|
2012-12-23 01:54:11 +00:00
|
|
|
if (ED_mesh_pick_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, TRUE)) {
|
2012-09-07 05:54:54 +00:00
|
|
|
v_idx_best = index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2012-12-23 01:54:11 +00:00
|
|
|
if (ED_mesh_pick_face_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
|
2012-09-07 05:54:54 +00:00
|
|
|
v_idx_best = index;
|
|
|
|
}
|
2012-12-23 01:54:11 +00:00
|
|
|
else if (ED_mesh_pick_face(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
|
2012-09-07 05:54:54 +00:00
|
|
|
/* this relies on knowning the internal worksings of ED_mesh_pick_face_vert() */
|
2011-05-25 10:07:59 +00:00
|
|
|
BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations");
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
2012-09-07 05:54:54 +00:00
|
|
|
}
|
2009-08-30 21:30:07 +00:00
|
|
|
|
2012-09-07 05:54:54 +00:00
|
|
|
if (v_idx_best != -1) { /* should always be valid */
|
|
|
|
ToolSettings *ts = vc.scene->toolsettings;
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
|
2012-09-07 05:54:54 +00:00
|
|
|
const int vgroup_active = vc.obact->actdef - 1;
|
|
|
|
float vgroup_weight = defvert_find_weight(&me->dvert[v_idx_best], vgroup_active);
|
|
|
|
BKE_brush_weight_set(vc.scene, brush, vgroup_weight);
|
|
|
|
change = TRUE;
|
2011-05-25 10:07:59 +00:00
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
2011-05-25 10:07:59 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (change) {
|
2011-05-25 10:07:59 +00:00
|
|
|
/* not really correct since the brush didnt change, but redraws the toolbar */
|
2012-03-28 03:47:33 +00:00
|
|
|
WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL); /* ts->wpaint->paint.brush */
|
2011-05-25 10:07:59 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return OPERATOR_CANCELLED;
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-25 10:07:59 +00:00
|
|
|
void PAINT_OT_weight_sample(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Weight Paint Sample Weight";
|
|
|
|
ot->idname = "PAINT_OT_weight_sample";
|
2012-05-05 17:10:51 +00:00
|
|
|
ot->description = "Use the mouse to sample a weight in the 3D view";
|
2011-05-25 10:07:59 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = weight_sample_invoke;
|
|
|
|
ot->poll = weight_paint_mode_poll;
|
2011-05-25 10:07:59 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = OPTYPE_UNDO;
|
2011-05-25 10:07:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* samples cursor location, and gives menu with vertex groups to activate */
|
2012-09-07 02:18:04 +00:00
|
|
|
static int weight_paint_sample_enum_itemf__helper(const MDeformVert *dvert, const int defbase_tot, int *groups)
|
|
|
|
{
|
|
|
|
/* this func fills in used vgroup's */
|
|
|
|
int found = FALSE;
|
|
|
|
int i = dvert->totweight;
|
|
|
|
MDeformWeight *dw;
|
|
|
|
for (dw = dvert->dw; i > 0; dw++, i--) {
|
|
|
|
if (dw->def_nr < defbase_tot) {
|
|
|
|
groups[dw->def_nr] = TRUE;
|
|
|
|
found = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return found;
|
|
|
|
}
|
2011-05-31 03:48:27 +00:00
|
|
|
static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
|
2011-05-25 10:07:59 +00:00
|
|
|
{
|
|
|
|
if (C) {
|
2012-03-24 11:27:52 +00:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (win && win->eventstate) {
|
2011-05-25 10:07:59 +00:00
|
|
|
ViewContext vc;
|
|
|
|
Mesh *me;
|
|
|
|
|
|
|
|
view3d_set_viewcontext(C, &vc);
|
2012-05-05 16:03:57 +00:00
|
|
|
me = BKE_mesh_from_object(vc.obact);
|
2011-05-25 10:07:59 +00:00
|
|
|
|
2012-09-07 02:18:04 +00:00
|
|
|
if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) {
|
|
|
|
const int defbase_tot = BLI_countlist(&vc.obact->defbase);
|
2012-12-22 14:25:34 +00:00
|
|
|
const int use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
|
2012-09-07 02:18:04 +00:00
|
|
|
int *groups = MEM_callocN(defbase_tot * sizeof(int), "groups");
|
|
|
|
int found = FALSE;
|
|
|
|
unsigned int index;
|
|
|
|
|
2012-09-06 23:41:03 +00:00
|
|
|
int mval[2] = {win->eventstate->x - vc.ar->winrct.xmin,
|
|
|
|
win->eventstate->y - vc.ar->winrct.ymin};
|
2011-05-25 10:07:59 +00:00
|
|
|
|
|
|
|
view3d_operator_needs_opengl(C);
|
2013-01-30 02:27:13 +00:00
|
|
|
ED_view3d_init_mats_rv3d(vc.obact, vc.rv3d);
|
2011-05-25 10:07:59 +00:00
|
|
|
|
2012-09-07 02:18:04 +00:00
|
|
|
if (use_vert_sel) {
|
2012-12-23 01:54:11 +00:00
|
|
|
if (ED_mesh_pick_vert(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, TRUE)) {
|
2012-09-07 02:18:04 +00:00
|
|
|
MDeformVert *dvert = &me->dvert[index];
|
|
|
|
found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2012-12-23 01:54:11 +00:00
|
|
|
if (ED_mesh_pick_face(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
|
2012-09-07 02:18:04 +00:00
|
|
|
MPoly *mp = &me->mpoly[index];
|
2012-04-03 23:40:24 +00:00
|
|
|
unsigned int fidx = mp->totloop - 1;
|
2011-05-25 10:07:59 +00:00
|
|
|
|
|
|
|
do {
|
2012-09-07 02:18:04 +00:00
|
|
|
MDeformVert *dvert = &me->dvert[me->mloop[mp->loopstart + fidx].v];
|
|
|
|
found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
|
2011-05-25 10:07:59 +00:00
|
|
|
} while (fidx--);
|
2012-09-07 02:18:04 +00:00
|
|
|
}
|
|
|
|
}
|
2011-05-25 10:07:59 +00:00
|
|
|
|
2012-09-07 02:18:04 +00:00
|
|
|
if (found == FALSE) {
|
|
|
|
MEM_freeN(groups);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
EnumPropertyItem *item = NULL, item_tmp = {0};
|
|
|
|
int totitem = 0;
|
|
|
|
int i = 0;
|
|
|
|
bDeformGroup *dg;
|
|
|
|
for (dg = vc.obact->defbase.first; dg && i < defbase_tot; i++, dg = dg->next) {
|
|
|
|
if (groups[i]) {
|
|
|
|
item_tmp.identifier = item_tmp.name = dg->name;
|
|
|
|
item_tmp.value = i;
|
|
|
|
RNA_enum_item_add(&item, &totitem, &item_tmp);
|
2011-05-25 10:07:59 +00:00
|
|
|
}
|
2012-09-07 02:18:04 +00:00
|
|
|
}
|
2011-05-25 10:07:59 +00:00
|
|
|
|
2012-09-07 02:18:04 +00:00
|
|
|
RNA_enum_item_end(&item, &totitem);
|
|
|
|
*free = 1;
|
2011-05-25 10:07:59 +00:00
|
|
|
|
2012-09-07 02:18:04 +00:00
|
|
|
MEM_freeN(groups);
|
|
|
|
return item;
|
2011-05-25 10:07:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return DummyRNA_NULL_items;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int weight_sample_group_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
int type = RNA_enum_get(op->ptr, "group");
|
2011-05-25 10:07:59 +00:00
|
|
|
ViewContext vc;
|
|
|
|
view3d_set_viewcontext(C, &vc);
|
|
|
|
|
2011-12-17 01:13:02 +00:00
|
|
|
BLI_assert(type + 1 >= 0);
|
2012-03-24 11:27:52 +00:00
|
|
|
vc.obact->actdef = type + 1;
|
2011-05-25 10:07:59 +00:00
|
|
|
|
|
|
|
DAG_id_tag_update(&vc.obact->id, OB_RECALC_DATA);
|
2012-03-28 03:47:33 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, vc.obact);
|
2011-05-25 10:07:59 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2011-05-31 03:48:27 +00:00
|
|
|
/* TODO, we could make this a menu into OBJECT_OT_vertex_group_set_active rather than its own operator */
|
2011-05-25 10:07:59 +00:00
|
|
|
void PAINT_OT_weight_sample_group(wmOperatorType *ot)
|
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
PropertyRNA *prop = NULL;
|
2011-05-25 10:07:59 +00:00
|
|
|
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Weight Paint Sample Group";
|
|
|
|
ot->idname = "PAINT_OT_weight_sample_group";
|
2012-05-05 17:10:51 +00:00
|
|
|
ot->description = "Select one of the vertex groups available under current mouse position";
|
2011-05-25 10:07:59 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = weight_sample_group_exec;
|
|
|
|
ot->invoke = WM_menu_invoke;
|
|
|
|
ot->poll = weight_paint_mode_poll;
|
2011-05-25 10:07:59 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->flag = OPTYPE_UNDO;
|
2011-05-25 10:07:59 +00:00
|
|
|
|
|
|
|
/* keyingset to use (dynamic enum) */
|
2012-03-24 11:27:52 +00:00
|
|
|
prop = RNA_def_enum(ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
|
2011-05-25 10:07:59 +00:00
|
|
|
RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf);
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->prop = prop;
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
|
2013-05-15 15:52:48 +00:00
|
|
|
static void do_weight_paint_normalize_all(MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap)
|
2009-10-30 02:09:52 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
float sum = 0.0f, fac;
|
|
|
|
unsigned int i, tot = 0;
|
2012-01-13 02:25:15 +00:00
|
|
|
MDeformWeight *dw;
|
2009-10-30 02:09:52 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
|
2012-01-13 05:52:34 +00:00
|
|
|
if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
|
|
|
|
tot++;
|
|
|
|
sum += dw->weight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((tot == 0) || (sum == 1.0f)) {
|
2009-10-30 02:09:52 +00:00
|
|
|
return;
|
2012-01-13 05:52:34 +00:00
|
|
|
}
|
2009-10-30 02:09:52 +00:00
|
|
|
|
2012-01-13 05:52:34 +00:00
|
|
|
if (sum != 0.0f) {
|
2012-03-24 11:27:52 +00:00
|
|
|
fac = 1.0f / sum;
|
2009-10-30 02:09:52 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
|
2012-01-13 05:52:34 +00:00
|
|
|
if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
|
2012-03-28 03:47:33 +00:00
|
|
|
dw->weight *= fac;
|
2012-01-13 05:52:34 +00:00
|
|
|
}
|
2009-10-30 02:09:52 +00:00
|
|
|
}
|
|
|
|
}
|
2012-01-13 05:52:34 +00:00
|
|
|
else {
|
|
|
|
/* hrmf, not a factor in this case */
|
|
|
|
fac = 1.0f / tot;
|
2009-10-30 02:09:52 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
|
2012-01-13 05:52:34 +00:00
|
|
|
if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
|
|
|
|
dw->weight = fac;
|
|
|
|
}
|
2009-10-30 02:09:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-13 05:52:34 +00:00
|
|
|
/* same as function above except it normalizes against the active vgroup which remains unchanged
|
|
|
|
*
|
|
|
|
* note that the active is just the group which is unchanged, it can be any,
|
|
|
|
* can also be -1 to normalize all but in that case call 'do_weight_paint_normalize_all' */
|
2013-05-15 15:52:48 +00:00
|
|
|
static void do_weight_paint_normalize_all_active(MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap,
|
2012-01-13 05:52:34 +00:00
|
|
|
const int vgroup_active)
|
2011-06-07 17:59:38 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
float sum = 0.0f, fac;
|
|
|
|
unsigned int i, tot = 0;
|
2012-01-13 05:52:34 +00:00
|
|
|
MDeformWeight *dw;
|
|
|
|
float act_weight = 0.0f;
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
|
2012-01-13 05:52:34 +00:00
|
|
|
if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
|
|
|
|
if (dw->def_nr != vgroup_active) {
|
2012-01-13 02:25:15 +00:00
|
|
|
sum += dw->weight;
|
2012-01-13 05:52:34 +00:00
|
|
|
tot++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
act_weight = dw->weight;
|
2012-01-13 02:25:15 +00:00
|
|
|
}
|
2009-10-30 02:09:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-13 05:52:34 +00:00
|
|
|
if ((tot == 0) || (sum + act_weight == 1.0f)) {
|
2011-06-07 17:59:38 +00:00
|
|
|
return;
|
2011-10-06 01:29:32 +00:00
|
|
|
}
|
2011-06-07 17:59:38 +00:00
|
|
|
|
2012-01-13 05:52:34 +00:00
|
|
|
if (sum != 0.0f) {
|
|
|
|
fac = (1.0f / sum) * (1.0f - act_weight);
|
2011-10-06 01:29:32 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
|
2012-01-13 05:52:34 +00:00
|
|
|
if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
|
|
|
|
if (dw->def_nr != vgroup_active) {
|
|
|
|
dw->weight *= fac;
|
|
|
|
|
|
|
|
/* paranoid but possibly with float error */
|
|
|
|
CLAMP(dw->weight, 0.0f, 1.0f);
|
2011-12-09 07:18:04 +00:00
|
|
|
}
|
2011-10-06 01:29:32 +00:00
|
|
|
}
|
|
|
|
}
|
2012-01-13 05:52:34 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* corner case where we need to scale all weights evenly because they're all zero */
|
2011-06-07 17:59:38 +00:00
|
|
|
|
2012-01-13 05:52:34 +00:00
|
|
|
/* hrmf, not a factor in this case */
|
|
|
|
fac = (1.0f - act_weight) / tot;
|
2011-06-07 17:59:38 +00:00
|
|
|
|
2012-01-13 05:52:34 +00:00
|
|
|
/* paranoid but possibly with float error */
|
|
|
|
CLAMP(fac, 0.0f, 1.0f);
|
2011-06-07 17:59:38 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
|
2012-01-13 05:52:34 +00:00
|
|
|
if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
|
|
|
|
if (dw->def_nr != vgroup_active) {
|
|
|
|
dw->weight = fac;
|
2011-12-09 07:18:04 +00:00
|
|
|
}
|
2011-10-06 01:29:32 +00:00
|
|
|
}
|
2011-06-07 17:59:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-09-18 17:10:28 +00:00
|
|
|
|
2011-06-01 15:45:09 +00:00
|
|
|
/*
|
2012-03-03 16:31:46 +00:00
|
|
|
* See if the current deform vertex has a locked group
|
|
|
|
*/
|
2011-12-09 07:18:04 +00:00
|
|
|
static char has_locked_group(MDeformVert *dvert, const int defbase_tot,
|
2013-05-15 15:52:48 +00:00
|
|
|
const bool *bone_groups, const bool *lock_flags)
|
2011-06-01 15:45:09 +00:00
|
|
|
{
|
|
|
|
int i;
|
2011-12-09 07:18:04 +00:00
|
|
|
MDeformWeight *dw;
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
|
2011-12-09 07:18:04 +00:00
|
|
|
if (dw->def_nr < defbase_tot) {
|
2011-12-30 11:31:48 +00:00
|
|
|
if (bone_groups[dw->def_nr] && lock_flags[dw->def_nr] && dw->weight > 0.0f) {
|
2011-12-09 07:18:04 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
2011-06-01 15:45:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
2011-09-18 17:10:28 +00:00
|
|
|
|
2013-05-15 15:52:48 +00:00
|
|
|
static bool has_locked_group_selected(int defbase_tot, const bool *defbase_sel, const bool *lock_flags)
|
2011-09-19 16:41:29 +00:00
|
|
|
{
|
2011-06-14 19:11:01 +00:00
|
|
|
int i;
|
2012-03-24 06:38:07 +00:00
|
|
|
for (i = 0; i < defbase_tot; i++) {
|
|
|
|
if (defbase_sel[i] && lock_flags[i]) {
|
2013-05-15 15:52:48 +00:00
|
|
|
return true;
|
2011-06-14 19:11:01 +00:00
|
|
|
}
|
|
|
|
}
|
2013-05-15 15:52:48 +00:00
|
|
|
return false;
|
2011-06-14 19:11:01 +00:00
|
|
|
}
|
2011-06-16 19:05:05 +00:00
|
|
|
|
2011-09-18 17:10:28 +00:00
|
|
|
|
2011-09-14 05:25:43 +00:00
|
|
|
#if 0 /* UNUSED */
|
2013-05-15 15:52:48 +00:00
|
|
|
static int has_unselected_unlocked_bone_group(int defbase_tot, bool *defbase_sel, int selected,
|
|
|
|
const bool *lock_flags, const bool *vgroup_validmap)
|
2011-09-19 16:41:29 +00:00
|
|
|
{
|
2011-06-14 19:11:01 +00:00
|
|
|
int i;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (defbase_tot == selected) {
|
2011-06-14 19:11:01 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
for (i = 0; i < defbase_tot; i++) {
|
|
|
|
if (vgroup_validmap[i] && !defbase_sel[i] && !lock_flags[i]) {
|
2011-06-14 19:11:01 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
2011-09-14 05:25:43 +00:00
|
|
|
#endif
|
2011-06-16 19:05:05 +00:00
|
|
|
|
2011-09-18 17:10:28 +00:00
|
|
|
|
2013-05-15 15:52:48 +00:00
|
|
|
static void multipaint_selection(MDeformVert *dvert, const int defbase_tot, float change, const bool *defbase_sel)
|
2011-09-19 16:41:29 +00:00
|
|
|
{
|
2011-06-01 15:45:09 +00:00
|
|
|
int i;
|
|
|
|
MDeformWeight *dw;
|
2011-06-21 19:20:42 +00:00
|
|
|
float val;
|
2011-09-19 16:41:29 +00:00
|
|
|
/* make sure they are all at most 1 after the change */
|
2012-03-24 06:38:07 +00:00
|
|
|
for (i = 0; i < defbase_tot; i++) {
|
|
|
|
if (defbase_sel[i]) {
|
2011-06-16 19:05:05 +00:00
|
|
|
dw = defvert_find_index(dvert, i);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (dw && dw->weight) {
|
2011-06-21 19:20:42 +00:00
|
|
|
val = dw->weight * change;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (val > 1) {
|
2011-09-19 16:41:29 +00:00
|
|
|
/* TODO: when the change is reduced, you need to recheck
|
|
|
|
* the earlier values to make sure they are not 0
|
|
|
|
* (precision error) */
|
2012-03-24 11:27:52 +00:00
|
|
|
change = 1.0f / dw->weight;
|
2011-06-16 19:05:05 +00:00
|
|
|
}
|
2011-09-19 16:41:29 +00:00
|
|
|
/* the value should never reach zero while multi-painting if it
|
|
|
|
* was nonzero beforehand */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (val <= 0) {
|
2011-06-29 18:20:39 +00:00
|
|
|
return;
|
|
|
|
}
|
2011-06-16 19:05:05 +00:00
|
|
|
}
|
2011-06-01 15:45:09 +00:00
|
|
|
}
|
|
|
|
}
|
2011-09-19 16:41:29 +00:00
|
|
|
/* apply the valid change */
|
2012-03-24 06:38:07 +00:00
|
|
|
for (i = 0; i < defbase_tot; i++) {
|
|
|
|
if (defbase_sel[i]) {
|
2011-06-16 19:05:05 +00:00
|
|
|
dw = defvert_find_index(dvert, i);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (dw && dw->weight) {
|
2011-06-16 19:05:05 +00:00
|
|
|
dw->weight = dw->weight * change;
|
|
|
|
}
|
2011-06-07 17:59:38 +00:00
|
|
|
}
|
2011-06-16 19:05:05 +00:00
|
|
|
}
|
|
|
|
}
|
2011-09-18 17:10:28 +00:00
|
|
|
|
2011-09-19 16:41:29 +00:00
|
|
|
/* move all change onto valid, unchanged groups. If there is change left over,
|
|
|
|
* then return it.
|
|
|
|
* assumes there are valid groups to shift weight onto */
|
2011-12-09 07:18:04 +00:00
|
|
|
static float redistribute_change(MDeformVert *ndv, const int defbase_tot,
|
|
|
|
char *change_status, const char change_me, int changeto,
|
|
|
|
float totchange, float total_valid,
|
|
|
|
char do_auto_normalize)
|
2011-09-19 16:41:29 +00:00
|
|
|
{
|
2011-06-16 19:05:05 +00:00
|
|
|
float was_change;
|
|
|
|
float change;
|
|
|
|
float oldval;
|
|
|
|
MDeformWeight *ndw;
|
|
|
|
int i;
|
|
|
|
do {
|
2011-09-19 16:41:29 +00:00
|
|
|
/* assume there is no change until you see one */
|
2011-06-16 19:05:05 +00:00
|
|
|
was_change = FALSE;
|
2011-09-19 16:41:29 +00:00
|
|
|
/* change each group by the same amount each time */
|
2012-03-24 11:27:52 +00:00
|
|
|
change = totchange / total_valid;
|
2012-03-24 06:38:07 +00:00
|
|
|
for (i = 0; i < ndv->totweight && total_valid && totchange; i++) {
|
2012-03-24 11:27:52 +00:00
|
|
|
ndw = (ndv->dw + i);
|
2011-12-09 07:18:04 +00:00
|
|
|
|
|
|
|
/* ignore anything outside the value range */
|
|
|
|
if (ndw->def_nr < defbase_tot) {
|
|
|
|
|
|
|
|
/* change only the groups with a valid status */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (change_status[ndw->def_nr] == change_me) {
|
2011-12-09 07:18:04 +00:00
|
|
|
oldval = ndw->weight;
|
|
|
|
/* if auto normalize is active, don't worry about upper bounds */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (do_auto_normalize == FALSE && ndw->weight + change > 1) {
|
2012-03-24 11:27:52 +00:00
|
|
|
totchange -= 1.0f - ndw->weight;
|
|
|
|
ndw->weight = 1.0f;
|
2011-12-09 07:18:04 +00:00
|
|
|
/* stop the changes to this group */
|
|
|
|
change_status[ndw->def_nr] = changeto;
|
|
|
|
total_valid--;
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (ndw->weight + change < 0) { /* check the lower bound */
|
2011-12-09 07:18:04 +00:00
|
|
|
totchange -= ndw->weight;
|
|
|
|
ndw->weight = 0;
|
|
|
|
change_status[ndw->def_nr] = changeto;
|
|
|
|
total_valid--;
|
|
|
|
}
|
2012-03-28 03:47:33 +00:00
|
|
|
else { /* a perfectly valid change occurred to ndw->weight */
|
2011-12-09 07:18:04 +00:00
|
|
|
totchange -= change;
|
|
|
|
ndw->weight += change;
|
|
|
|
}
|
|
|
|
/* see if there was a change */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (oldval != ndw->weight) {
|
2011-12-09 07:18:04 +00:00
|
|
|
was_change = TRUE;
|
|
|
|
}
|
2011-06-14 19:11:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-09-19 16:41:29 +00:00
|
|
|
/* don't go again if there was no change, if there is no valid group,
|
|
|
|
* or there is no change left */
|
2012-03-24 06:38:07 +00:00
|
|
|
} while (was_change && total_valid && totchange);
|
2011-09-19 16:41:29 +00:00
|
|
|
/* left overs */
|
2011-06-16 19:05:05 +00:00
|
|
|
return totchange;
|
2011-05-27 19:13:54 +00:00
|
|
|
}
|
2013-05-15 15:52:48 +00:00
|
|
|
static float get_mp_change(MDeformVert *odv, const int defbase_tot, const bool *defbase_sel, float brush_change);
|
2011-09-19 16:41:29 +00:00
|
|
|
/* observe the changes made to the weights of groups.
|
|
|
|
* make sure all locked groups on the vertex have the same deformation
|
|
|
|
* by moving the changes made to groups onto other unlocked groups */
|
2011-12-09 07:18:04 +00:00
|
|
|
static void enforce_locks(MDeformVert *odv, MDeformVert *ndv,
|
2013-05-15 15:52:48 +00:00
|
|
|
const int defbase_tot, const bool *defbase_sel,
|
|
|
|
const bool *lock_flags, const bool *vgroup_validmap,
|
2011-12-09 07:18:04 +00:00
|
|
|
char do_auto_normalize, char do_multipaint)
|
2011-09-19 05:06:21 +00:00
|
|
|
{
|
2011-06-16 19:05:05 +00:00
|
|
|
float totchange = 0.0f;
|
|
|
|
float totchange_allowed = 0.0f;
|
|
|
|
float left_over;
|
2011-07-18 17:38:17 +00:00
|
|
|
|
2011-06-16 19:05:05 +00:00
|
|
|
int total_valid = 0;
|
|
|
|
int total_changed = 0;
|
2011-09-19 17:53:37 +00:00
|
|
|
unsigned int i;
|
2011-06-16 19:05:05 +00:00
|
|
|
MDeformWeight *ndw;
|
|
|
|
MDeformWeight *odw;
|
2011-11-29 02:23:59 +00:00
|
|
|
|
2013-03-17 10:26:23 +00:00
|
|
|
// float changed_sum = 0.0f; // UNUSED
|
2011-11-29 02:23:59 +00:00
|
|
|
|
2011-06-16 19:05:05 +00:00
|
|
|
char *change_status;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!lock_flags || !has_locked_group(ndv, defbase_tot, vgroup_validmap, lock_flags)) {
|
2011-06-16 19:05:05 +00:00
|
|
|
return;
|
2011-06-08 19:05:17 +00:00
|
|
|
}
|
2011-09-19 16:41:29 +00:00
|
|
|
/* record if a group was changed, unlocked and not changed, or locked */
|
2012-03-24 11:27:52 +00:00
|
|
|
change_status = MEM_callocN(sizeof(char) * defbase_tot, "unlocked_unchanged");
|
2011-06-16 19:05:05 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
for (i = 0; i < defbase_tot; i++) {
|
2011-06-16 19:05:05 +00:00
|
|
|
ndw = defvert_find_index(ndv, i);
|
|
|
|
odw = defvert_find_index(odv, i);
|
2011-09-19 16:41:29 +00:00
|
|
|
/* the weights are zero, so we can assume a lot */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!ndw || !odw) {
|
2011-11-29 06:50:18 +00:00
|
|
|
if (!lock_flags[i] && vgroup_validmap[i]) {
|
2011-06-16 19:05:05 +00:00
|
|
|
defvert_verify_index(odv, i);
|
|
|
|
defvert_verify_index(ndv, i);
|
|
|
|
total_valid++;
|
2011-09-19 16:41:29 +00:00
|
|
|
change_status[i] = 1; /* can be altered while redistributing */
|
2011-06-08 19:05:17 +00:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2011-09-19 16:41:29 +00:00
|
|
|
/* locked groups should not be changed */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (lock_flags[i]) {
|
2011-06-16 19:05:05 +00:00
|
|
|
ndw->weight = odw->weight;
|
2011-09-19 02:43:03 +00:00
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (ndw->weight != odw->weight) { /* changed groups are handled here */
|
2011-09-19 02:43:03 +00:00
|
|
|
totchange += ndw->weight - odw->weight;
|
2013-03-17 10:26:23 +00:00
|
|
|
// changed_sum += ndw->weight; // UNUSED
|
2011-09-19 16:41:29 +00:00
|
|
|
change_status[i] = 2; /* was altered already */
|
2011-06-16 19:05:05 +00:00
|
|
|
total_changed++;
|
2011-09-19 16:41:29 +00:00
|
|
|
} /* unchanged, unlocked bone groups are handled here */
|
2011-11-29 06:50:18 +00:00
|
|
|
else if (vgroup_validmap[i]) {
|
2011-06-16 19:05:05 +00:00
|
|
|
totchange_allowed += ndw->weight;
|
|
|
|
total_valid++;
|
2011-09-19 16:41:29 +00:00
|
|
|
change_status[i] = 1; /* can be altered while redistributing */
|
2011-06-10 19:47:53 +00:00
|
|
|
}
|
|
|
|
}
|
2011-09-19 16:41:29 +00:00
|
|
|
/* if there was any change, redistribute it */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (total_changed) {
|
2011-09-19 16:41:29 +00:00
|
|
|
/* auto normalize will allow weights to temporarily go above 1 in redistribution */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (vgroup_validmap && total_changed < 0 && total_valid) {
|
2011-06-21 19:20:42 +00:00
|
|
|
totchange_allowed = total_valid;
|
|
|
|
}
|
2012-03-24 11:27:52 +00:00
|
|
|
/* the way you modify the unlocked + unchanged groups is different depending
|
2011-11-10 02:09:58 +00:00
|
|
|
* on whether or not you are painting the weight(s) up or down */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (totchange < 0) {
|
2011-11-10 02:09:58 +00:00
|
|
|
totchange_allowed = total_valid - totchange_allowed;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
totchange_allowed *= -1;
|
|
|
|
}
|
2011-09-19 16:41:29 +00:00
|
|
|
/* there needs to be change allowed, or you should not bother */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (totchange_allowed) {
|
2011-06-16 19:05:05 +00:00
|
|
|
left_over = 0;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (fabsf(totchange_allowed) < fabsf(totchange)) {
|
2011-09-19 16:41:29 +00:00
|
|
|
/* this amount goes back onto the changed, unlocked weights */
|
2011-09-19 02:43:03 +00:00
|
|
|
left_over = fabsf(fabsf(totchange) - fabsf(totchange_allowed));
|
2012-03-24 06:38:07 +00:00
|
|
|
if (totchange > 0) {
|
2011-06-16 19:05:05 +00:00
|
|
|
left_over *= -1;
|
|
|
|
}
|
2011-09-19 02:43:03 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-09-19 16:41:29 +00:00
|
|
|
/* all of the change will be permitted */
|
2011-06-16 19:05:05 +00:00
|
|
|
totchange_allowed = -totchange;
|
|
|
|
}
|
2011-09-19 16:41:29 +00:00
|
|
|
/* move the weight evenly between the allowed groups, move excess back onto the used groups based on the change */
|
2011-12-09 07:18:04 +00:00
|
|
|
totchange_allowed = redistribute_change(ndv, defbase_tot, change_status, 1, -1, totchange_allowed, total_valid, do_auto_normalize);
|
2011-06-16 19:05:05 +00:00
|
|
|
left_over += totchange_allowed;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (left_over) {
|
2011-11-29 02:23:59 +00:00
|
|
|
/* more than one nonzero weights were changed with the same ratio with multipaint, so keep them changed that way! */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (total_changed > 1 && do_multipaint) {
|
2011-12-09 07:18:04 +00:00
|
|
|
float undo_change = get_mp_change(ndv, defbase_tot, defbase_sel, left_over);
|
|
|
|
multipaint_selection(ndv, defbase_tot, undo_change, defbase_sel);
|
2012-10-21 05:46:41 +00:00
|
|
|
}
|
2011-11-29 02:23:59 +00:00
|
|
|
/* or designatedw is still -1 put weight back as evenly as possible */
|
2011-06-16 19:05:05 +00:00
|
|
|
else {
|
2011-12-09 07:18:04 +00:00
|
|
|
redistribute_change(ndv, defbase_tot, change_status, 2, -2, left_over, total_changed, do_auto_normalize);
|
2011-06-16 19:05:05 +00:00
|
|
|
}
|
|
|
|
}
|
2011-09-19 02:43:03 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-09-19 16:41:29 +00:00
|
|
|
/* reset the weights */
|
2012-03-24 11:27:52 +00:00
|
|
|
MDeformWeight *dw_old = odv->dw;
|
|
|
|
MDeformWeight *dw_new = ndv->dw;
|
2011-09-19 17:53:37 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
for (i = odv->totweight; i != 0; i--, dw_old++, dw_new++) {
|
|
|
|
dw_new->weight = dw_old->weight;
|
2011-06-14 19:11:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-06-16 19:05:05 +00:00
|
|
|
|
|
|
|
MEM_freeN(change_status);
|
2011-06-10 19:47:53 +00:00
|
|
|
}
|
2011-09-18 17:10:28 +00:00
|
|
|
|
2011-09-19 16:41:29 +00:00
|
|
|
/* multi-paint's initial, potential change is computed here based on the user's stroke */
|
2013-05-15 15:52:48 +00:00
|
|
|
static float get_mp_change(MDeformVert *odv, const int defbase_tot, const bool *defbase_sel, float brush_change)
|
2011-09-19 16:41:29 +00:00
|
|
|
{
|
2011-06-29 18:20:39 +00:00
|
|
|
float selwsum = 0.0f;
|
2011-09-19 17:53:37 +00:00
|
|
|
unsigned int i;
|
2012-03-24 11:27:52 +00:00
|
|
|
MDeformWeight *dw = odv->dw;
|
2011-09-19 17:53:37 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
for (i = odv->totweight; i != 0; i--, dw++) {
|
2011-12-09 07:18:04 +00:00
|
|
|
if (dw->def_nr < defbase_tot) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (defbase_sel[dw->def_nr]) {
|
2011-12-09 07:18:04 +00:00
|
|
|
selwsum += dw->weight;
|
|
|
|
}
|
2011-06-29 18:20:39 +00:00
|
|
|
}
|
2011-06-16 19:05:05 +00:00
|
|
|
}
|
2012-03-24 11:27:52 +00:00
|
|
|
if (selwsum && selwsum + brush_change > 0) {
|
|
|
|
return (selwsum + brush_change) / selwsum;
|
2011-06-29 18:20:39 +00:00
|
|
|
}
|
|
|
|
return 0.0f;
|
2011-06-21 19:20:42 +00:00
|
|
|
}
|
2011-09-18 17:10:28 +00:00
|
|
|
|
2011-09-19 16:41:29 +00:00
|
|
|
/* change the weights back to the wv's weights
|
|
|
|
* it assumes you already have the correct pointer index */
|
2011-12-14 21:08:08 +00:00
|
|
|
static void defvert_reset_to_prev(MDeformVert *dv_prev, MDeformVert *dv)
|
2011-09-19 16:41:29 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
MDeformWeight *dw = dv->dw;
|
2011-12-14 21:08:08 +00:00
|
|
|
MDeformWeight *dw_prev;
|
2011-09-19 17:53:37 +00:00
|
|
|
unsigned int i;
|
2012-03-24 11:27:52 +00:00
|
|
|
for (i = dv->totweight; i != 0; i--, dw++) {
|
|
|
|
dw_prev = defvert_find_index(dv_prev, dw->def_nr);
|
2011-09-19 02:43:03 +00:00
|
|
|
/* if there was no w when there is a d, then the old weight was 0 */
|
2011-12-14 21:08:08 +00:00
|
|
|
dw->weight = dw_prev ? dw_prev->weight : 0.0f;
|
2011-06-08 19:05:17 +00:00
|
|
|
}
|
2011-06-29 18:20:39 +00:00
|
|
|
}
|
2011-09-18 17:10:28 +00:00
|
|
|
|
2011-09-19 16:41:29 +00:00
|
|
|
static void clamp_weights(MDeformVert *dvert)
|
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
MDeformWeight *dw = dvert->dw;
|
2011-09-19 17:53:37 +00:00
|
|
|
unsigned int i;
|
2012-03-24 11:27:52 +00:00
|
|
|
for (i = dvert->totweight; i != 0; i--, dw++) {
|
2011-09-19 17:53:37 +00:00
|
|
|
CLAMP(dw->weight, 0.0f, 1.0f);
|
2011-06-21 19:20:42 +00:00
|
|
|
}
|
2011-06-08 19:05:17 +00:00
|
|
|
}
|
2011-09-18 17:10:28 +00:00
|
|
|
|
2011-09-19 05:06:21 +00:00
|
|
|
/* struct to avoid passing many args each call to do_weight_paint_vertex()
|
|
|
|
* this _could_ be made a part of the operators 'WPaintData' struct, or at
|
|
|
|
* least a member, but for now keep its own struct, initialized on every
|
|
|
|
* paint stroke update - campbell */
|
2011-09-19 04:53:11 +00:00
|
|
|
typedef struct WeightPaintInfo {
|
|
|
|
|
|
|
|
int defbase_tot;
|
|
|
|
|
|
|
|
/* both must add up to 'defbase_tot' */
|
|
|
|
int defbase_tot_sel;
|
|
|
|
int defbase_tot_unsel;
|
|
|
|
|
2011-12-30 02:16:07 +00:00
|
|
|
int vgroup_active; /* (ob->actdef - 1) */
|
2011-09-19 04:53:11 +00:00
|
|
|
int vgroup_mirror; /* mirror group or -1 */
|
|
|
|
|
2013-05-15 15:52:48 +00:00
|
|
|
const bool *lock_flags; /* boolean array for locked bones,
|
2011-12-09 06:05:58 +00:00
|
|
|
* length of defbase_tot */
|
2013-05-15 15:52:48 +00:00
|
|
|
const bool *defbase_sel; /* boolean array for selected bones,
|
2011-12-09 06:05:58 +00:00
|
|
|
* length of defbase_tot, cant be const because of how its passed */
|
2011-09-19 04:53:11 +00:00
|
|
|
|
2013-05-15 15:52:48 +00:00
|
|
|
const bool *vgroup_validmap; /* same as WeightPaintData.vgroup_validmap,
|
2011-12-09 07:18:04 +00:00
|
|
|
* only added here for convenience */
|
2011-09-19 04:53:11 +00:00
|
|
|
|
|
|
|
char do_flip;
|
|
|
|
char do_multipaint;
|
2011-09-19 15:11:01 +00:00
|
|
|
char do_auto_normalize;
|
2012-01-15 06:29:08 +00:00
|
|
|
|
2012-05-05 00:58:22 +00:00
|
|
|
float brush_alpha_value; /* result of BKE_brush_alpha_get() */
|
2011-09-19 04:53:11 +00:00
|
|
|
} WeightPaintInfo;
|
|
|
|
|
2011-06-16 19:05:05 +00:00
|
|
|
/* fresh start to make multi-paint and locking modular */
|
2011-09-19 04:53:11 +00:00
|
|
|
/* returns TRUE if it thinks you need to reset the weights due to
|
2011-12-09 07:18:04 +00:00
|
|
|
* normalizing while multi-painting
|
|
|
|
*
|
|
|
|
* note: this assumes dw->def_nr range has been checked by the caller
|
|
|
|
*/
|
2011-09-19 05:06:21 +00:00
|
|
|
static int apply_mp_locks_normalize(Mesh *me, const WeightPaintInfo *wpi,
|
2011-09-19 17:53:37 +00:00
|
|
|
const unsigned int index,
|
2011-09-19 04:53:11 +00:00
|
|
|
MDeformWeight *dw, MDeformWeight *tdw,
|
|
|
|
float change, float oldChange,
|
|
|
|
float oldw, float neww)
|
2011-09-19 02:43:03 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
MDeformVert *dv = &me->dvert[index];
|
|
|
|
MDeformVert dv_test = {NULL};
|
2011-07-07 17:59:15 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
dv_test.dw = MEM_dupallocN(dv->dw);
|
2011-09-19 04:53:11 +00:00
|
|
|
dv_test.flag = dv->flag;
|
|
|
|
dv_test.totweight = dv->totweight;
|
2011-09-19 02:43:03 +00:00
|
|
|
/* do not multi-paint if a locked group is selected or the active group is locked
|
|
|
|
* !lock_flags[dw->def_nr] helps if nothing is selected, but active group is locked */
|
2012-09-09 00:00:21 +00:00
|
|
|
if ((wpi->lock_flags == NULL) ||
|
2013-05-15 15:52:48 +00:00
|
|
|
((wpi->lock_flags[dw->def_nr] == false) && /* def_nr range has to be checked for by caller */
|
|
|
|
has_locked_group_selected(wpi->defbase_tot, wpi->defbase_sel, wpi->lock_flags) == false))
|
2011-09-19 16:41:29 +00:00
|
|
|
{
|
2012-03-24 06:38:07 +00:00
|
|
|
if (wpi->do_multipaint && wpi->defbase_tot_sel > 1) {
|
2012-03-24 11:27:52 +00:00
|
|
|
if (change && change != 1) {
|
2011-12-09 07:18:04 +00:00
|
|
|
multipaint_selection(dv, wpi->defbase_tot, change, wpi->defbase_sel);
|
2011-06-29 18:20:39 +00:00
|
|
|
}
|
2011-09-19 02:43:03 +00:00
|
|
|
}
|
|
|
|
else { /* this lets users paint normally, but don't let them paint locked groups */
|
2011-06-14 19:11:01 +00:00
|
|
|
dw->weight = neww;
|
2011-06-08 19:05:17 +00:00
|
|
|
}
|
|
|
|
}
|
2011-09-19 04:53:11 +00:00
|
|
|
clamp_weights(dv);
|
2011-06-21 19:20:42 +00:00
|
|
|
|
2011-11-29 02:23:59 +00:00
|
|
|
enforce_locks(&dv_test, dv, wpi->defbase_tot, wpi->defbase_sel, wpi->lock_flags, wpi->vgroup_validmap, wpi->do_auto_normalize, wpi->do_multipaint);
|
2011-06-16 19:05:05 +00:00
|
|
|
|
2012-01-13 02:25:15 +00:00
|
|
|
if (wpi->do_auto_normalize) {
|
2012-01-13 05:52:34 +00:00
|
|
|
/* XXX - should we pass the active group? - currently '-1' */
|
2012-01-13 02:25:15 +00:00
|
|
|
do_weight_paint_normalize_all(dv, wpi->defbase_tot, wpi->vgroup_validmap);
|
|
|
|
}
|
2011-07-21 16:25:07 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (oldChange && wpi->do_multipaint && wpi->defbase_tot_sel > 1) {
|
|
|
|
if (tdw->weight != oldw) {
|
|
|
|
if (neww > oldw) {
|
|
|
|
if (tdw->weight <= oldw) {
|
2012-01-25 20:18:12 +00:00
|
|
|
MEM_freeN(dv_test.dw);
|
2011-07-21 16:25:07 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
2011-09-19 02:43:03 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (tdw->weight >= oldw) {
|
2012-01-25 20:18:12 +00:00
|
|
|
MEM_freeN(dv_test.dw);
|
2011-07-21 16:25:07 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-01-25 20:18:12 +00:00
|
|
|
MEM_freeN(dv_test.dw);
|
2011-07-21 16:25:07 +00:00
|
|
|
return FALSE;
|
2011-06-08 19:05:17 +00:00
|
|
|
}
|
2011-06-16 19:05:05 +00:00
|
|
|
|
2011-09-19 02:43:03 +00:00
|
|
|
/* within the current dvert index, get the dw that is selected and has a weight
|
|
|
|
* above 0, this helps multi-paint */
|
2013-05-15 15:52:48 +00:00
|
|
|
static int get_first_selected_nonzero_weight(MDeformVert *dvert, const int defbase_tot, const bool *defbase_sel)
|
2011-09-19 16:41:29 +00:00
|
|
|
{
|
2011-06-29 18:20:39 +00:00
|
|
|
int i;
|
2012-03-24 11:27:52 +00:00
|
|
|
MDeformWeight *dw = dvert->dw;
|
|
|
|
for (i = 0; i < dvert->totweight; i++, dw++) {
|
2011-12-09 07:18:04 +00:00
|
|
|
if (dw->def_nr < defbase_tot) {
|
|
|
|
if (defbase_sel[dw->def_nr] && dw->weight > 0.0f) {
|
|
|
|
return i;
|
|
|
|
}
|
2011-06-29 18:20:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
2011-09-18 17:10:28 +00:00
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
static void do_weight_paint_vertex(
|
|
|
|
/* vars which remain the same for every vert */
|
|
|
|
VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
|
|
|
|
/* vars which change on each stroke */
|
|
|
|
const unsigned int index, float alpha, float paintweight
|
|
|
|
)
|
2009-01-07 19:23:22 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
Mesh *me = ob->data;
|
|
|
|
MDeformVert *dv = &me->dvert[index];
|
2013-06-28 17:13:09 +00:00
|
|
|
bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
|
2011-09-18 17:10:28 +00:00
|
|
|
|
2012-01-13 08:18:22 +00:00
|
|
|
MDeformWeight *dw, *dw_prev;
|
2011-05-27 19:13:54 +00:00
|
|
|
|
2012-01-13 02:17:29 +00:00
|
|
|
/* mirror vars */
|
|
|
|
int index_mirr;
|
|
|
|
int vgroup_mirr;
|
|
|
|
|
2012-01-13 05:52:34 +00:00
|
|
|
MDeformVert *dv_mirr;
|
|
|
|
MDeformWeight *dw_mirr;
|
2011-05-27 19:13:54 +00:00
|
|
|
|
2012-01-15 07:46:59 +00:00
|
|
|
const short do_multipaint_totsel = (wpi->do_multipaint && wpi->defbase_tot_sel > 1);
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (wp->flag & VP_ONLYVGROUP) {
|
2012-03-24 11:27:52 +00:00
|
|
|
dw = defvert_find_index(dv, wpi->vgroup_active);
|
|
|
|
dw_prev = defvert_find_index(wp->wpaint_prev + index, wpi->vgroup_active);
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-03-24 11:27:52 +00:00
|
|
|
dw = defvert_verify_index(dv, wpi->vgroup_active);
|
|
|
|
dw_prev = defvert_verify_index(wp->wpaint_prev + index, wpi->vgroup_active);
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
2011-10-06 03:57:03 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
if (dw == NULL || dw_prev == NULL) {
|
2009-01-07 19:23:22 +00:00
|
|
|
return;
|
2011-10-06 03:57:03 +00:00
|
|
|
}
|
2009-10-30 02:09:52 +00:00
|
|
|
|
2012-01-13 05:52:34 +00:00
|
|
|
|
2012-01-13 02:17:29 +00:00
|
|
|
/* from now on we can check if mirrors enabled if this var is -1 and not bother with the flag */
|
|
|
|
if (me->editflag & ME_EDIT_MIRROR_X) {
|
2013-06-28 17:13:09 +00:00
|
|
|
index_mirr = mesh_get_x_mirror_vert(ob, index, topology);
|
2012-01-13 02:17:29 +00:00
|
|
|
vgroup_mirr = (wpi->vgroup_mirror != -1) ? wpi->vgroup_mirror : wpi->vgroup_active;
|
2012-01-13 05:52:34 +00:00
|
|
|
|
|
|
|
/* another possible error - mirror group _and_ active group are the same (which is fine),
|
|
|
|
* but we also are painting onto a center vertex - this would paint the same weight twice */
|
|
|
|
if (index_mirr == index && vgroup_mirr == wpi->vgroup_active) {
|
|
|
|
index_mirr = vgroup_mirr = -1;
|
|
|
|
}
|
2012-01-13 02:17:29 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-01-13 05:52:34 +00:00
|
|
|
index_mirr = vgroup_mirr = -1;
|
2012-01-13 02:17:29 +00:00
|
|
|
}
|
|
|
|
|
2012-01-13 05:52:34 +00:00
|
|
|
|
|
|
|
/* get the mirror def vars */
|
|
|
|
if (index_mirr != -1) {
|
|
|
|
dv_mirr = &me->dvert[index_mirr];
|
|
|
|
if (wp->flag & VP_ONLYVGROUP) {
|
|
|
|
dw_mirr = defvert_find_index(dv_mirr, vgroup_mirr);
|
|
|
|
|
|
|
|
if (dw_mirr == NULL) {
|
|
|
|
index_mirr = vgroup_mirr = -1;
|
|
|
|
dv_mirr = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2012-01-14 18:52:34 +00:00
|
|
|
if (index != index_mirr) {
|
|
|
|
dw_mirr = defvert_verify_index(dv_mirr, vgroup_mirr);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* dv and dv_mirr are the same */
|
|
|
|
int totweight_prev = dv_mirr->totweight;
|
|
|
|
int dw_offset = (int)(dw - dv_mirr->dw);
|
|
|
|
dw_mirr = defvert_verify_index(dv_mirr, vgroup_mirr);
|
|
|
|
|
|
|
|
/* if we added another, get our old one back */
|
|
|
|
if (totweight_prev != dv_mirr->totweight) {
|
|
|
|
dw = &dv_mirr->dw[dw_offset];
|
|
|
|
}
|
|
|
|
}
|
2012-01-13 05:52:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dv_mirr = NULL;
|
|
|
|
dw_mirr = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-19 04:53:11 +00:00
|
|
|
/* TODO: De-duplicate the simple weight paint - jason */
|
|
|
|
/* ... or not, since its <10 SLOC - campbell */
|
2011-09-19 02:43:03 +00:00
|
|
|
|
|
|
|
/* If there are no locks or multipaint,
|
|
|
|
* then there is no need to run the more complicated checks */
|
2012-09-09 00:00:21 +00:00
|
|
|
if ((do_multipaint_totsel == FALSE) &&
|
|
|
|
(wpi->lock_flags == NULL || has_locked_group(dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags) == FALSE))
|
2011-09-19 16:41:29 +00:00
|
|
|
{
|
2012-01-15 07:46:59 +00:00
|
|
|
dw->weight = wpaint_blend(wp, dw->weight, dw_prev->weight, alpha, paintweight,
|
|
|
|
wpi->brush_alpha_value, wpi->do_flip, FALSE);
|
2011-09-18 17:10:28 +00:00
|
|
|
|
2012-01-13 05:52:34 +00:00
|
|
|
/* WATCH IT: take care of the ordering of applying mirror -> normalize,
|
|
|
|
* can give wrong results [#26193], least confusing if normalize is done last */
|
2012-01-13 02:17:29 +00:00
|
|
|
|
2012-01-13 05:52:34 +00:00
|
|
|
/* apply mirror */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (index_mirr != -1) {
|
2012-01-13 02:17:29 +00:00
|
|
|
/* copy, not paint again */
|
|
|
|
dw_mirr->weight = dw->weight;
|
2011-09-18 17:10:28 +00:00
|
|
|
}
|
2011-10-06 04:06:47 +00:00
|
|
|
|
2012-01-13 05:52:34 +00:00
|
|
|
/* apply normalize */
|
2012-01-13 02:25:15 +00:00
|
|
|
if (wpi->do_auto_normalize) {
|
2012-01-13 05:52:34 +00:00
|
|
|
/* note on normalize - this used to be applied after painting and normalize all weights,
|
|
|
|
* in some ways this is good because there is feedback where the more weights involved would
|
2012-03-03 11:45:08 +00:00
|
|
|
* 'resist' so you couldn't instantly zero out other weights by painting 1.0 on the active.
|
2012-01-13 05:52:34 +00:00
|
|
|
*
|
|
|
|
* However this gave a problem since applying mirror, then normalize both verts
|
|
|
|
* the resulting weight wont match on both sides.
|
|
|
|
*
|
|
|
|
* If this 'resisting', slower normalize is nicer, we could call
|
|
|
|
* do_weight_paint_normalize_all() and only use...
|
|
|
|
* do_weight_paint_normalize_all_active() when normalizing the mirror vertex.
|
|
|
|
* - campbell
|
|
|
|
*/
|
|
|
|
do_weight_paint_normalize_all_active(dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->vgroup_active);
|
|
|
|
|
|
|
|
if (index_mirr != -1) {
|
|
|
|
/* only normalize if this is not a center vertex, else we get a conflict, normalizing twice */
|
|
|
|
if (index != index_mirr) {
|
|
|
|
do_weight_paint_normalize_all_active(dv_mirr, wpi->defbase_tot, wpi->vgroup_validmap, vgroup_mirr);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* this case accounts for...
|
|
|
|
* - painting onto a center vertex of a mesh
|
|
|
|
* - x mirror is enabled
|
|
|
|
* - auto normalize is enabled
|
|
|
|
* - the group you are painting onto has a L / R version
|
|
|
|
*
|
2012-03-03 11:45:08 +00:00
|
|
|
* We want L/R vgroups to have the same weight but this cant be if both are over 0.5,
|
2012-01-13 05:52:34 +00:00
|
|
|
* We _could_ have special check for that, but this would need its own normalize function which
|
|
|
|
* holds 2 groups from changing at once.
|
|
|
|
*
|
|
|
|
* So! just balance out the 2 weights, it keeps them equal and everything normalized.
|
|
|
|
*
|
2012-05-20 21:23:26 +00:00
|
|
|
* While it wont hit the desired weight immediately as the user waggles their mouse,
|
2012-01-13 05:52:34 +00:00
|
|
|
* constant painting and re-normalizing will get there. this is also just simpler logic.
|
|
|
|
* - campbell */
|
|
|
|
dw_mirr->weight = dw->weight = (dw_mirr->weight + dw->weight) * 0.5f;
|
|
|
|
}
|
|
|
|
}
|
2012-01-13 02:25:15 +00:00
|
|
|
}
|
2011-09-19 02:43:03 +00:00
|
|
|
}
|
2011-09-19 04:53:11 +00:00
|
|
|
else {
|
|
|
|
/* use locks and/or multipaint */
|
2011-09-18 17:10:28 +00:00
|
|
|
float oldw;
|
|
|
|
float neww;
|
2012-06-03 10:33:28 +00:00
|
|
|
/* float testw = 0; */ /* UNUSED */
|
2012-05-31 17:22:52 +00:00
|
|
|
float observedChange = 0;
|
2011-09-18 17:10:28 +00:00
|
|
|
float change = 0;
|
|
|
|
float oldChange = 0;
|
|
|
|
int i;
|
2012-01-13 08:18:22 +00:00
|
|
|
MDeformWeight *tdw = NULL, *tdw_prev;
|
2012-03-24 11:27:52 +00:00
|
|
|
MDeformVert dv_copy = {NULL};
|
2009-10-30 02:09:52 +00:00
|
|
|
|
2011-09-18 17:10:28 +00:00
|
|
|
oldw = dw->weight;
|
2012-01-15 07:46:59 +00:00
|
|
|
neww = wpaint_blend(wp, dw->weight, dw_prev->weight, alpha, paintweight,
|
|
|
|
wpi->brush_alpha_value, wpi->do_flip, do_multipaint_totsel);
|
2011-09-18 17:10:28 +00:00
|
|
|
|
2011-09-19 16:41:29 +00:00
|
|
|
/* setup multi-paint */
|
2012-05-31 17:22:52 +00:00
|
|
|
observedChange = neww - oldw;
|
|
|
|
if (do_multipaint_totsel && observedChange) {
|
2012-03-24 11:27:52 +00:00
|
|
|
dv_copy.dw = MEM_dupallocN(dv->dw);
|
2011-10-06 03:57:03 +00:00
|
|
|
dv_copy.flag = dv->flag;
|
|
|
|
dv_copy.totweight = dv->totweight;
|
2011-09-18 17:10:28 +00:00
|
|
|
tdw = dw;
|
2012-01-13 08:18:22 +00:00
|
|
|
tdw_prev = dw_prev;
|
2012-05-31 17:22:52 +00:00
|
|
|
change = get_mp_change(&wp->wpaint_prev[index], wpi->defbase_tot, wpi->defbase_sel, observedChange);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (change) {
|
|
|
|
if (!tdw->weight) {
|
2011-12-09 07:18:04 +00:00
|
|
|
i = get_first_selected_nonzero_weight(dv, wpi->defbase_tot, wpi->defbase_sel);
|
2012-03-24 11:27:52 +00:00
|
|
|
if (i >= 0) {
|
2011-10-06 03:57:03 +00:00
|
|
|
tdw = &(dv->dw[i]);
|
2012-01-13 08:18:22 +00:00
|
|
|
tdw_prev = defvert_verify_index(&wp->wpaint_prev[index], tdw->def_nr);
|
2011-09-18 14:54:41 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-09-18 17:10:28 +00:00
|
|
|
change = 0;
|
|
|
|
}
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (change && tdw_prev->weight && tdw_prev->weight * change) {
|
|
|
|
if (tdw->weight != tdw_prev->weight) {
|
2012-03-24 11:27:52 +00:00
|
|
|
oldChange = tdw->weight / tdw_prev->weight;
|
2012-06-03 10:33:28 +00:00
|
|
|
/* testw = tdw_prev->weight * change; */ /* UNUSED */
|
2012-05-31 17:22:52 +00:00
|
|
|
if (observedChange > 0) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (change > oldChange) {
|
2011-09-19 05:06:21 +00:00
|
|
|
/* reset the weights and use the new change */
|
2012-03-24 11:27:52 +00:00
|
|
|
defvert_reset_to_prev(wp->wpaint_prev + index, dv);
|
2011-09-18 17:10:28 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-09-19 05:06:21 +00:00
|
|
|
/* the old change was more significant, so set
|
|
|
|
* the change to 0 so that it will not do another multi-paint */
|
2011-09-18 17:10:28 +00:00
|
|
|
change = 0;
|
|
|
|
}
|
2011-09-18 14:54:41 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (change < oldChange) {
|
2012-03-24 11:27:52 +00:00
|
|
|
defvert_reset_to_prev(wp->wpaint_prev + index, dv);
|
2011-09-18 17:10:28 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
change = 0;
|
|
|
|
}
|
2011-06-29 18:20:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-09-18 17:10:28 +00:00
|
|
|
else {
|
|
|
|
change = 0;
|
|
|
|
}
|
2011-09-18 14:54:41 +00:00
|
|
|
}
|
2011-09-18 17:10:28 +00:00
|
|
|
}
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (apply_mp_locks_normalize(me, wpi, index, dw, tdw, change, oldChange, oldw, neww)) {
|
2011-12-14 21:08:08 +00:00
|
|
|
defvert_reset_to_prev(&dv_copy, dv);
|
2011-09-18 17:10:28 +00:00
|
|
|
change = 0;
|
|
|
|
oldChange = 0;
|
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
if (dv_copy.dw) {
|
2012-01-25 20:18:12 +00:00
|
|
|
MEM_freeN(dv_copy.dw);
|
2011-09-18 17:10:28 +00:00
|
|
|
}
|
2011-11-10 06:06:35 +00:00
|
|
|
#if 0
|
2011-10-06 03:57:03 +00:00
|
|
|
/* dv may have been altered greatly */
|
|
|
|
dw = defvert_find_index(dv, vgroup);
|
2011-11-10 06:06:35 +00:00
|
|
|
#else
|
2012-05-20 21:23:26 +00:00
|
|
|
dw = NULL; /* UNUSED after assignment, set to NULL to ensure we don't
|
2012-03-28 03:47:33 +00:00
|
|
|
* use again, we thats needed un-ifdef the line above */
|
2011-11-10 06:06:35 +00:00
|
|
|
(void)dw; /* quiet warnigns */
|
|
|
|
#endif
|
2011-09-18 17:10:28 +00:00
|
|
|
|
2012-01-13 02:17:29 +00:00
|
|
|
/* x mirror painting */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (index_mirr != -1) {
|
2012-01-13 02:17:29 +00:00
|
|
|
/* copy, not paint again */
|
|
|
|
|
|
|
|
/* dw_mirr->weight = dw->weight; */ /* TODO, explain the logic in not assigning weight! - campbell */
|
|
|
|
apply_mp_locks_normalize(me, wpi, index_mirr, dw_mirr, tdw, change, oldChange, oldw, neww);
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
/* *************** set wpaint operator ****************** */
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
static int set_wpaint(bContext *C, wmOperator *UNUSED(op)) /* toggle */
|
2009-01-10 14:19:14 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
Object *ob = CTX_data_active_object(C);
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
VPaint *wp = scene->toolsettings->wpaint;
|
2009-01-10 14:19:14 +00:00
|
|
|
Mesh *me;
|
|
|
|
|
2012-05-05 16:03:57 +00:00
|
|
|
me = BKE_mesh_from_object(ob);
|
2012-03-24 11:27:52 +00:00
|
|
|
if (ob->id.lib || me == NULL) return OPERATOR_PASS_THROUGH;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ob->mode & OB_MODE_WEIGHT_PAINT) ob->mode &= ~OB_MODE_WEIGHT_PAINT;
|
2009-08-15 21:46:25 +00:00
|
|
|
else ob->mode |= OB_MODE_WEIGHT_PAINT;
|
2009-01-10 14:19:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Weightpaint works by overriding colors in mesh,
|
2012-03-03 16:31:46 +00:00
|
|
|
* so need to make sure we recalc on enter and
|
|
|
|
* exit (exit needs doing regardless because we
|
|
|
|
* should redeform).
|
|
|
|
*/
|
2011-01-03 12:41:16 +00:00
|
|
|
DAG_id_tag_update(&me->id, 0);
|
2009-01-10 14:19:14 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ob->mode & OB_MODE_WEIGHT_PAINT) {
|
2009-01-10 14:19:14 +00:00
|
|
|
Object *par;
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
if (wp == NULL)
|
|
|
|
wp = scene->toolsettings->wpaint = new_vpaint(1);
|
2009-03-11 00:43:08 +00:00
|
|
|
|
2012-07-25 13:44:59 +00:00
|
|
|
BKE_paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT);
|
2009-10-22 23:22:05 +00:00
|
|
|
paint_cursor_start(C, weight_paint_poll);
|
2009-01-10 14:19:14 +00:00
|
|
|
|
2011-10-28 14:31:15 +00:00
|
|
|
mesh_octree_table(ob, NULL, NULL, 's');
|
2009-01-10 14:19:14 +00:00
|
|
|
|
|
|
|
/* verify if active weight group is also active bone */
|
2012-03-24 11:27:52 +00:00
|
|
|
par = modifiers_isDeformedByArmature(ob);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (par && (par->mode & OB_MODE_POSE)) {
|
2012-03-24 11:27:52 +00:00
|
|
|
bArmature *arm = par->data;
|
2009-11-09 21:03:54 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (arm->act_bone)
|
2009-11-09 21:03:54 +00:00
|
|
|
ED_vgroup_select_by_name(ob, arm->act_bone->name);
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
2009-01-10 14:19:14 +00:00
|
|
|
else {
|
2011-10-28 14:31:15 +00:00
|
|
|
mesh_octree_table(NULL, NULL, NULL, 'e');
|
|
|
|
mesh_mirrtopo_table(NULL, 'e');
|
2012-12-22 14:20:27 +00:00
|
|
|
|
2012-12-22 14:25:34 +00:00
|
|
|
if (me->editflag & ME_EDIT_PAINT_VERT_SEL) {
|
2012-12-22 14:20:27 +00:00
|
|
|
BKE_mesh_flush_select_from_verts(me);
|
|
|
|
}
|
2012-12-22 14:25:34 +00:00
|
|
|
else if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
|
2012-12-22 14:20:27 +00:00
|
|
|
BKE_mesh_flush_select_from_polys(me);
|
|
|
|
}
|
2009-01-10 14:19:14 +00:00
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2009-02-01 13:24:19 +00:00
|
|
|
/* for switching to/from mode */
|
|
|
|
static int paint_poll_test(bContext *C)
|
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
Object *ob = CTX_data_active_object(C);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (CTX_data_edit_object(C))
|
2009-02-01 13:24:19 +00:00
|
|
|
return 0;
|
2012-03-24 11:27:52 +00:00
|
|
|
if (CTX_data_active_object(C) == NULL)
|
2009-02-01 13:24:19 +00:00
|
|
|
return 0;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!ob->data || ((ID *)ob->data)->lib)
|
2011-12-12 18:25:52 +00:00
|
|
|
return 0;
|
2009-02-01 13:24:19 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
void PAINT_OT_weight_paint_toggle(wmOperatorType *ot)
|
2009-01-10 14:19:14 +00:00
|
|
|
{
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Weight Paint Mode";
|
|
|
|
ot->idname = "PAINT_OT_weight_paint_toggle";
|
2012-05-05 17:10:51 +00:00
|
|
|
ot->description = "Toggle weight paint mode in 3D view";
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = set_wpaint;
|
|
|
|
ot->poll = paint_poll_test;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
2012-03-28 03:47:33 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2009-01-31 19:40:40 +00:00
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
/* ************ weight paint operator ********** */
|
|
|
|
|
|
|
|
struct WPaintData {
|
|
|
|
ViewContext vc;
|
|
|
|
int *indexar;
|
2011-12-30 02:16:07 +00:00
|
|
|
int vgroup_active;
|
2009-01-10 14:19:14 +00:00
|
|
|
int vgroup_mirror;
|
2013-06-26 18:40:55 +00:00
|
|
|
|
|
|
|
void *vp_handle;
|
2012-12-15 16:13:27 +00:00
|
|
|
DMCoNo *vertexcosnos;
|
2013-06-26 18:40:55 +00:00
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
float wpimat[3][3];
|
2012-12-28 01:36:00 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
/* variables for auto normalize */
|
2013-05-15 15:52:48 +00:00
|
|
|
const bool *vgroup_validmap; /* stores if vgroups tie to deforming bones or not */
|
|
|
|
const bool *lock_flags;
|
2011-09-19 15:11:01 +00:00
|
|
|
int defbase_tot;
|
2009-01-10 14:19:14 +00:00
|
|
|
};
|
|
|
|
|
2012-12-28 01:36:00 +00:00
|
|
|
/* ensure we have data on wpaint start, add if needed */
|
2013-06-19 07:45:36 +00:00
|
|
|
static bool wpaint_ensure_data(bContext *C, wmOperator *op)
|
2009-01-10 14:19:14 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
Object *ob = CTX_data_active_object(C);
|
2012-12-28 01:36:00 +00:00
|
|
|
Mesh *me = BKE_mesh_from_object(ob);
|
2011-12-30 07:55:15 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (scene->obedit) {
|
2011-12-30 11:37:54 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2012-12-28 01:36:00 +00:00
|
|
|
|
|
|
|
if (me == NULL || me->totpoly == 0) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
/* if nothing was added yet, we make dverts and a vertex deform group */
|
2010-12-17 16:04:05 +00:00
|
|
|
if (!me->dvert) {
|
2009-09-16 17:43:09 +00:00
|
|
|
ED_vgroup_data_create(&me->id);
|
2012-03-28 03:47:33 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
|
2010-12-17 16:04:05 +00:00
|
|
|
}
|
2011-10-06 02:19:04 +00:00
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
/* this happens on a Bone select, when no vgroup existed yet */
|
2011-12-30 02:16:07 +00:00
|
|
|
if (ob->actdef <= 0) {
|
2009-01-10 14:19:14 +00:00
|
|
|
Object *modob;
|
2012-03-24 06:38:07 +00:00
|
|
|
if ((modob = modifiers_isDeformedByArmature(ob))) {
|
2012-03-24 11:27:52 +00:00
|
|
|
Bone *actbone = ((bArmature *)modob->data)->act_bone;
|
2012-03-24 06:38:07 +00:00
|
|
|
if (actbone) {
|
2012-05-05 16:03:57 +00:00
|
|
|
bPoseChannel *pchan = BKE_pose_channel_find_name(modob->pose, actbone->name);
|
2010-01-18 16:21:23 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (pchan) {
|
2012-03-24 11:27:52 +00:00
|
|
|
bDeformGroup *dg = defgroup_find_name(ob, pchan->name);
|
|
|
|
if (dg == NULL) {
|
2012-03-28 03:47:33 +00:00
|
|
|
dg = ED_vgroup_add_name(ob, pchan->name); /* sets actdef */
|
2011-12-07 09:13:15 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-12-17 01:13:02 +00:00
|
|
|
int actdef = 1 + BLI_findindex(&ob->defbase, dg);
|
|
|
|
BLI_assert(actdef >= 0);
|
2012-03-24 11:27:52 +00:00
|
|
|
ob->actdef = actdef;
|
2011-12-07 09:13:15 +00:00
|
|
|
}
|
2010-01-18 16:21:23 +00:00
|
|
|
}
|
2009-01-10 14:19:14 +00:00
|
|
|
}
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
}
|
|
|
|
}
|
2012-03-24 11:27:52 +00:00
|
|
|
if (ob->defbase.first == NULL) {
|
2009-09-16 17:43:09 +00:00
|
|
|
ED_vgroup_add(ob);
|
2010-01-18 16:21:23 +00:00
|
|
|
}
|
2011-10-06 02:19:04 +00:00
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
/* ensure we don't try paint onto an invalid group */
|
2011-12-30 02:16:07 +00:00
|
|
|
if (ob->actdef <= 0) {
|
2011-12-30 11:37:54 +00:00
|
|
|
BKE_report(op->reports, RPT_WARNING, "No active vertex group for painting, aborting");
|
|
|
|
return FALSE;
|
2011-12-30 02:16:07 +00:00
|
|
|
}
|
|
|
|
|
2012-12-28 01:36:00 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNUSED(mouse[2]))
|
|
|
|
{
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
struct PaintStroke *stroke = op->customdata;
|
|
|
|
ToolSettings *ts = scene->toolsettings;
|
|
|
|
VPaint *wp = ts->wpaint;
|
|
|
|
Object *ob = CTX_data_active_object(C);
|
|
|
|
Mesh *me = BKE_mesh_from_object(ob);
|
|
|
|
struct WPaintData *wpd;
|
|
|
|
|
|
|
|
float mat[4][4], imat[4][4];
|
|
|
|
|
|
|
|
if (wpaint_ensure_data(C, op) == FALSE) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2012-10-12 14:35:10 +00:00
|
|
|
{
|
|
|
|
/* check if we are attempting to paint onto a locked vertex group,
|
|
|
|
* and other options disallow it from doing anything useful */
|
|
|
|
bDeformGroup *dg = BLI_findlink(&ob->defbase, (ob->actdef - 1));
|
|
|
|
if (dg->flag & DG_LOCK_WEIGHT) {
|
|
|
|
BKE_report(op->reports, RPT_WARNING, "Active group is locked, aborting");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2011-12-30 07:55:15 +00:00
|
|
|
}
|
|
|
|
|
2011-12-30 02:16:07 +00:00
|
|
|
/* ALLOCATIONS! no return after this line */
|
|
|
|
/* make mode data storage */
|
2012-03-24 11:27:52 +00:00
|
|
|
wpd = MEM_callocN(sizeof(struct WPaintData), "WPaintData");
|
2011-12-30 02:16:07 +00:00
|
|
|
paint_stroke_set_mode_data(stroke, wpd);
|
|
|
|
view3d_set_viewcontext(C, &wpd->vc);
|
|
|
|
|
|
|
|
wpd->vgroup_active = ob->actdef - 1;
|
|
|
|
wpd->vgroup_mirror = -1;
|
|
|
|
|
|
|
|
/* set up auto-normalize, and generate map for detecting which
|
2012-03-24 11:27:52 +00:00
|
|
|
* vgroups affect deform bones */
|
2011-12-30 02:16:07 +00:00
|
|
|
wpd->defbase_tot = BLI_countlist(&ob->defbase);
|
2012-09-05 02:51:55 +00:00
|
|
|
wpd->lock_flags = BKE_objdef_lock_flags_get(ob, wpd->defbase_tot);
|
2011-12-30 02:16:07 +00:00
|
|
|
if (ts->auto_normalize || ts->multipaint || wpd->lock_flags) {
|
2012-09-05 02:51:55 +00:00
|
|
|
wpd->vgroup_validmap = BKE_objdef_validmap_get(ob, wpd->defbase_tot);
|
2011-12-30 02:16:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* painting on subsurfs should give correct points too, this returns me->totvert amount */
|
2013-06-26 18:40:55 +00:00
|
|
|
wpd->vp_handle = ED_vpaint_proj_handle_create(scene, ob, &wpd->vertexcosnos);
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
wpd->indexar = get_indexarray(me);
|
2011-12-30 02:16:07 +00:00
|
|
|
copy_wpaint_prev(wp, me->dvert, me->totvert);
|
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
/* imat for normals */
|
2013-05-26 18:36:25 +00:00
|
|
|
mul_m4_m4m4(mat, wpd->vc.rv3d->viewmat, ob->obmat);
|
2009-11-10 20:43:45 +00:00
|
|
|
invert_m4_m4(imat, mat);
|
|
|
|
copy_m3_m4(wpd->wpimat, imat);
|
2011-12-30 02:16:07 +00:00
|
|
|
|
2009-01-10 14:19:14 +00:00
|
|
|
/* if mirror painting, find the other group */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (me->editflag & ME_EDIT_MIRROR_X) {
|
2011-12-30 02:16:07 +00:00
|
|
|
wpd->vgroup_mirror = wpaint_mirror_vgroup_ensure(ob, wpd->vgroup_active);
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
}
|
2013-01-17 04:24:22 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
UnifiedPaintSettings *ups = &ts->unified_paint_settings;
|
|
|
|
ups->draw_pressure = true;
|
|
|
|
}
|
2009-01-10 14:19:14 +00:00
|
|
|
|
2011-12-30 11:37:54 +00:00
|
|
|
return TRUE;
|
2009-08-20 15:25:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
|
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
|
|
VPaint *wp = ts->wpaint;
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
Brush *brush = BKE_paint_brush(&wp->paint);
|
2012-03-24 11:27:52 +00:00
|
|
|
struct WPaintData *wpd = paint_stroke_mode_data(stroke);
|
2009-12-20 10:50:40 +00:00
|
|
|
ViewContext *vc;
|
|
|
|
Object *ob;
|
|
|
|
Mesh *me;
|
2009-08-20 15:25:12 +00:00
|
|
|
float mat[4][4];
|
2011-01-12 03:41:12 +00:00
|
|
|
float paintweight;
|
2009-12-20 10:50:40 +00:00
|
|
|
int *indexar;
|
2011-12-30 04:38:45 +00:00
|
|
|
float totw;
|
2011-09-19 17:53:37 +00:00
|
|
|
unsigned int index, totindex;
|
2009-11-20 01:39:27 +00:00
|
|
|
float alpha;
|
2011-12-30 03:50:04 +00:00
|
|
|
float mval[2];
|
2013-01-01 12:51:08 +00:00
|
|
|
bool use_vert_sel;
|
|
|
|
bool use_face_sel;
|
|
|
|
bool use_depth;
|
2012-12-25 14:03:28 +00:00
|
|
|
|
|
|
|
MDeformWeight *(*dw_func)(MDeformVert *, const int) =
|
|
|
|
(brush->vertexpaint_tool == PAINT_BLEND_BLUR) ?
|
|
|
|
((wp->flag & VP_ONLYVGROUP) ?
|
|
|
|
(MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index :
|
|
|
|
defvert_verify_index) : NULL;
|
2011-07-18 17:38:17 +00:00
|
|
|
|
2011-12-30 03:50:04 +00:00
|
|
|
const float pressure = RNA_float_get(itemptr, "pressure");
|
2012-05-05 00:58:22 +00:00
|
|
|
const float brush_size_pressure = BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f);
|
|
|
|
const float brush_alpha_value = BKE_brush_alpha_get(scene, brush);
|
|
|
|
const float brush_alpha_pressure = brush_alpha_value * (BKE_brush_use_alpha_pressure(scene, brush) ? pressure : 1.0f);
|
2011-12-30 03:50:04 +00:00
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
/* intentionally don't initialize as NULL, make sure we initialize all members below */
|
2011-09-19 04:53:11 +00:00
|
|
|
WeightPaintInfo wpi;
|
|
|
|
|
2009-12-20 10:50:40 +00:00
|
|
|
/* cannot paint if there is no stroke data */
|
|
|
|
if (wpd == NULL) {
|
2011-09-19 16:41:29 +00:00
|
|
|
/* XXX: force a redraw here, since even though we can't paint,
|
|
|
|
* at least view won't freeze until stroke ends */
|
2009-12-20 10:50:40 +00:00
|
|
|
ED_region_tag_redraw(CTX_wm_region(C));
|
|
|
|
return;
|
|
|
|
}
|
2013-01-01 14:20:59 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
vc = &wpd->vc;
|
|
|
|
ob = vc->obact;
|
|
|
|
me = ob->data;
|
|
|
|
indexar = wpd->indexar;
|
2009-12-20 10:50:40 +00:00
|
|
|
|
2009-08-20 15:25:12 +00:00
|
|
|
view3d_operator_needs_opengl(C);
|
2013-01-30 02:27:13 +00:00
|
|
|
ED_view3d_init_mats_rv3d(ob, vc->rv3d);
|
|
|
|
|
2009-08-20 15:25:12 +00:00
|
|
|
/* load projection matrix */
|
2013-05-26 18:36:25 +00:00
|
|
|
mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
|
2009-08-20 15:25:12 +00:00
|
|
|
|
|
|
|
RNA_float_get_array(itemptr, "mouse", mval);
|
2012-09-05 03:45:32 +00:00
|
|
|
|
2011-09-19 04:53:11 +00:00
|
|
|
/* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */
|
2012-03-24 11:27:52 +00:00
|
|
|
wpi.defbase_tot = wpd->defbase_tot;
|
2012-09-05 03:45:32 +00:00
|
|
|
wpi.defbase_sel = BKE_objdef_selected_get(ob, wpi.defbase_tot, &wpi.defbase_tot_sel);
|
|
|
|
if (wpi.defbase_tot_sel == 0 && ob->actdef > 0) {
|
|
|
|
wpi.defbase_tot_sel = 1;
|
|
|
|
}
|
2011-12-09 06:05:58 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
wpi.defbase_tot_unsel = wpi.defbase_tot - wpi.defbase_tot_sel;
|
|
|
|
wpi.vgroup_active = wpd->vgroup_active;
|
|
|
|
wpi.vgroup_mirror = wpd->vgroup_mirror;
|
|
|
|
wpi.lock_flags = wpd->lock_flags;
|
|
|
|
wpi.vgroup_validmap = wpd->vgroup_validmap;
|
|
|
|
wpi.do_flip = RNA_boolean_get(itemptr, "pen_flip");
|
|
|
|
wpi.do_multipaint = (ts->multipaint != 0);
|
|
|
|
wpi.do_auto_normalize = ((ts->auto_normalize != 0) && (wpi.vgroup_validmap != NULL));
|
|
|
|
wpi.brush_alpha_value = brush_alpha_value;
|
2011-09-19 04:53:11 +00:00
|
|
|
/* *** done setting up WeightPaintInfo *** */
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
swap_m4m4(wpd->vc.rv3d->persmat, mat);
|
2011-09-14 12:44:21 +00:00
|
|
|
|
2012-12-22 14:25:34 +00:00
|
|
|
use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
|
2013-01-01 12:51:08 +00:00
|
|
|
use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
|
2013-06-13 17:11:09 +00:00
|
|
|
use_depth = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
|
2011-09-14 12:44:21 +00:00
|
|
|
|
2009-08-20 15:25:12 +00:00
|
|
|
/* which faces are involved */
|
2013-01-01 11:47:47 +00:00
|
|
|
if (use_depth) {
|
2012-12-25 14:03:28 +00:00
|
|
|
if (wp->flag & VP_AREA) {
|
2013-07-01 08:25:27 +00:00
|
|
|
char editflag_prev = me->editflag;
|
|
|
|
|
2012-12-25 14:03:28 +00:00
|
|
|
/* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */
|
|
|
|
me->editflag &= ~ME_EDIT_PAINT_VERT_SEL;
|
2013-07-01 08:25:27 +00:00
|
|
|
if (use_vert_sel) {
|
|
|
|
/* Ugly x2, we need this so hidden faces don't draw */
|
|
|
|
me->editflag |= ME_EDIT_PAINT_FACE_SEL;
|
|
|
|
}
|
2012-12-25 14:03:28 +00:00
|
|
|
totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure);
|
2013-07-01 08:25:27 +00:00
|
|
|
me->editflag = editflag_prev;
|
2012-12-25 14:03:28 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
indexar[0] = view3d_sample_backbuf(vc, mval[0], mval[1]);
|
|
|
|
if (indexar[0]) totindex = 1;
|
|
|
|
else totindex = 0;
|
|
|
|
}
|
2012-09-18 04:55:52 +00:00
|
|
|
|
2013-01-01 12:51:08 +00:00
|
|
|
if (use_face_sel && me->mpoly) {
|
2012-12-25 14:03:28 +00:00
|
|
|
for (index = 0; index < totindex; index++) {
|
|
|
|
if (indexar[index] && indexar[index] <= me->totpoly) {
|
|
|
|
MPoly *mpoly = ((MPoly *)me->mpoly) + (indexar[index] - 1);
|
|
|
|
|
|
|
|
if ((mpoly->flag & ME_FACE_SEL) == 0) {
|
|
|
|
indexar[index] = 0;
|
|
|
|
}
|
2009-08-20 15:25:12 +00:00
|
|
|
}
|
2012-03-24 11:27:52 +00:00
|
|
|
}
|
2009-08-20 15:25:12 +00:00
|
|
|
}
|
|
|
|
}
|
2012-12-25 14:03:28 +00:00
|
|
|
else {
|
|
|
|
indexar = NULL;
|
|
|
|
}
|
2012-03-24 11:27:52 +00:00
|
|
|
|
2013-06-26 18:40:55 +00:00
|
|
|
/* incase we have modifiers */
|
|
|
|
ED_vpaint_proj_handle_update(wpd->vp_handle, vc->ar, mval);
|
|
|
|
|
2009-08-20 15:25:12 +00:00
|
|
|
/* make sure each vertex gets treated only once */
|
|
|
|
/* and calculate filter weight */
|
2012-03-24 11:27:52 +00:00
|
|
|
totw = 0.0f;
|
2012-01-15 06:29:08 +00:00
|
|
|
if (brush->vertexpaint_tool == PAINT_BLEND_BLUR)
|
2012-03-24 11:27:52 +00:00
|
|
|
paintweight = 0.0f;
|
2009-08-20 15:25:12 +00:00
|
|
|
else
|
2012-05-05 00:58:22 +00:00
|
|
|
paintweight = BKE_brush_weight_get(scene, brush);
|
2012-12-25 14:03:28 +00:00
|
|
|
|
|
|
|
#define WP_BLUR_ACCUM(v_idx_var) \
|
|
|
|
{ \
|
|
|
|
const unsigned int vidx = v_idx_var; \
|
2013-03-14 03:42:17 +00:00
|
|
|
const float fac = calc_vp_strength_col_dl(wp, vc, wpd->vertexcosnos[vidx].co, mval, brush_size_pressure, NULL); \
|
2012-12-25 14:03:28 +00:00
|
|
|
if (fac > 0.0f) { \
|
|
|
|
MDeformWeight *dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); \
|
|
|
|
paintweight += dw ? (dw->weight * fac) : 0.0f; \
|
|
|
|
totw += fac; \
|
|
|
|
} \
|
|
|
|
} (void)0
|
|
|
|
|
|
|
|
|
2013-01-01 11:47:47 +00:00
|
|
|
if (use_depth) {
|
2012-12-25 14:03:28 +00:00
|
|
|
for (index = 0; index < totindex; index++) {
|
|
|
|
if (indexar[index] && indexar[index] <= me->totpoly) {
|
|
|
|
MPoly *mpoly = me->mpoly + (indexar[index] - 1);
|
|
|
|
MLoop *ml = me->mloop + mpoly->loopstart;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (use_vert_sel) {
|
|
|
|
for (i = 0; i < mpoly->totloop; i++, ml++) {
|
|
|
|
me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT);
|
|
|
|
}
|
2011-09-22 16:09:27 +00:00
|
|
|
}
|
2012-12-25 14:03:28 +00:00
|
|
|
else {
|
|
|
|
for (i = 0; i < mpoly->totloop; i++, ml++) {
|
|
|
|
me->dvert[ml->v].flag = 1;
|
|
|
|
}
|
2011-09-22 16:09:27 +00:00
|
|
|
}
|
2012-12-25 14:03:28 +00:00
|
|
|
|
|
|
|
if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
|
|
|
|
ml = me->mloop + mpoly->loopstart;
|
|
|
|
for (i = 0; i < mpoly->totloop; i++, ml++) {
|
|
|
|
WP_BLUR_ACCUM(ml->v);
|
2011-09-22 16:09:27 +00:00
|
|
|
}
|
2009-08-20 15:25:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-12-25 14:03:28 +00:00
|
|
|
else {
|
|
|
|
const unsigned int totvert = me->totvert;
|
|
|
|
unsigned int i;
|
|
|
|
|
2013-01-01 12:51:08 +00:00
|
|
|
/* in the case of face selection we need to flush */
|
|
|
|
if (use_vert_sel || use_face_sel) {
|
|
|
|
for (i = 0; i < totvert; i++) {
|
|
|
|
me->dvert[i].flag = me->mvert[i].flag & SELECT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (i = 0; i < totvert; i++) {
|
|
|
|
me->dvert[i].flag = SELECT;
|
|
|
|
}
|
2012-12-25 14:03:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
|
|
|
|
for (i = 0; i < totvert; i++) {
|
|
|
|
WP_BLUR_ACCUM(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef WP_BLUR_ACCUM
|
|
|
|
|
|
|
|
|
2012-01-15 06:29:08 +00:00
|
|
|
if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
|
2011-12-30 04:38:45 +00:00
|
|
|
paintweight /= totw;
|
|
|
|
}
|
|
|
|
|
2012-12-25 14:03:28 +00:00
|
|
|
#define WP_PAINT(v_idx_var) \
|
|
|
|
{ \
|
|
|
|
unsigned int vidx = v_idx_var; \
|
|
|
|
if (me->dvert[vidx].flag) { \
|
2013-03-14 03:47:20 +00:00
|
|
|
alpha = calc_vp_alpha_col_dl(wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \
|
2013-03-14 03:42:17 +00:00
|
|
|
mval, brush_size_pressure, brush_alpha_pressure, NULL); \
|
2012-12-25 14:03:28 +00:00
|
|
|
if (alpha) { \
|
|
|
|
do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); \
|
|
|
|
} \
|
|
|
|
me->dvert[vidx].flag = 0; \
|
|
|
|
} \
|
|
|
|
} (void)0
|
|
|
|
|
2013-01-01 11:47:47 +00:00
|
|
|
if (use_depth) {
|
2012-12-25 14:03:28 +00:00
|
|
|
for (index = 0; index < totindex; index++) {
|
2009-08-31 15:57:13 +00:00
|
|
|
|
2012-12-25 14:03:28 +00:00
|
|
|
if (indexar[index] && indexar[index] <= me->totpoly) {
|
|
|
|
MPoly *mpoly = me->mpoly + (indexar[index] - 1);
|
|
|
|
MLoop *ml = me->mloop + mpoly->loopstart;
|
|
|
|
int i;
|
2012-01-18 08:43:27 +00:00
|
|
|
|
2012-12-25 14:03:28 +00:00
|
|
|
for (i = 0; i < mpoly->totloop; i++, ml++) {
|
|
|
|
WP_PAINT(ml->v);
|
2009-08-20 15:25:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-12-25 14:03:28 +00:00
|
|
|
else {
|
|
|
|
const unsigned int totvert = me->totvert;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < totvert; i++) {
|
|
|
|
WP_PAINT(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#undef WP_PAINT
|
2011-09-19 04:53:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* *** free wpi members */
|
2011-12-09 06:05:58 +00:00
|
|
|
MEM_freeN((void *)wpi.defbase_sel);
|
2012-12-25 14:03:28 +00:00
|
|
|
/* *** done freeing wpi members */
|
2011-09-19 04:53:11 +00:00
|
|
|
|
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
swap_m4m4(vc->rv3d->persmat, mat);
|
2012-12-25 14:03:28 +00:00
|
|
|
|
2013-01-17 04:24:22 +00:00
|
|
|
{
|
|
|
|
UnifiedPaintSettings *ups = &ts->unified_paint_settings;
|
|
|
|
ups->pressure_value = pressure;
|
|
|
|
}
|
|
|
|
|
2011-01-03 12:41:16 +00:00
|
|
|
DAG_id_tag_update(ob->data, 0);
|
2009-08-20 15:25:12 +00:00
|
|
|
ED_region_tag_redraw(vc->ar);
|
|
|
|
}
|
|
|
|
|
2012-05-03 04:11:53 +00:00
|
|
|
static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
|
2009-08-20 15:25:12 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
|
|
Object *ob = CTX_data_active_object(C);
|
|
|
|
struct WPaintData *wpd = paint_stroke_mode_data(stroke);
|
2009-08-20 15:25:12 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (wpd) {
|
2013-06-26 18:40:55 +00:00
|
|
|
ED_vpaint_proj_handle_free(wpd->vp_handle);
|
2009-12-20 10:50:40 +00:00
|
|
|
MEM_freeN(wpd->indexar);
|
|
|
|
|
|
|
|
if (wpd->vgroup_validmap)
|
2011-12-09 06:05:58 +00:00
|
|
|
MEM_freeN((void *)wpd->vgroup_validmap);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (wpd->lock_flags)
|
2011-12-09 06:05:58 +00:00
|
|
|
MEM_freeN((void *)wpd->lock_flags);
|
2011-09-19 15:11:01 +00:00
|
|
|
|
2009-12-20 10:50:40 +00:00
|
|
|
MEM_freeN(wpd);
|
|
|
|
}
|
2009-08-20 15:25:12 +00:00
|
|
|
|
|
|
|
/* frees prev buffer */
|
|
|
|
copy_wpaint_prev(ts->wpaint, NULL, 0);
|
|
|
|
|
|
|
|
/* and particles too */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ob->particlesystem.first) {
|
2009-08-20 15:25:12 +00:00
|
|
|
ParticleSystem *psys;
|
|
|
|
int i;
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
|
|
|
|
for (i = 0; i < PSYS_TOT_VG; i++) {
|
|
|
|
if (psys->vgroup[i] == ob->actdef) {
|
2009-08-20 15:25:12 +00:00
|
|
|
psys->recalc |= PSYS_RECALC_RESET;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-01-17 04:24:22 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
UnifiedPaintSettings *ups = &ts->unified_paint_settings;
|
|
|
|
ups->draw_pressure = false;
|
|
|
|
}
|
|
|
|
|
2011-01-03 12:41:16 +00:00
|
|
|
DAG_id_tag_update(ob->data, 0);
|
2012-06-04 15:13:36 +00:00
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
|
2009-08-20 15:25:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2009-08-20 15:25:12 +00:00
|
|
|
{
|
2012-10-06 00:42:30 +00:00
|
|
|
int retval;
|
|
|
|
|
2009-10-27 19:53:34 +00:00
|
|
|
op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start,
|
2013-05-15 14:37:05 +00:00
|
|
|
wpaint_stroke_update_step, NULL,
|
2011-12-09 07:18:04 +00:00
|
|
|
wpaint_stroke_done, event->type);
|
2009-01-10 14:19:14 +00:00
|
|
|
|
|
|
|
/* add modal handler */
|
2009-10-22 23:22:05 +00:00
|
|
|
WM_event_add_modal_handler(C, op);
|
2009-08-21 00:46:36 +00:00
|
|
|
|
2012-10-06 00:42:30 +00:00
|
|
|
retval = op->type->modal(C, op, event);
|
|
|
|
OPERATOR_RETVAL_CHECK(retval);
|
|
|
|
BLI_assert(retval == OPERATOR_RUNNING_MODAL);
|
2009-01-10 14:19:14 +00:00
|
|
|
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
}
|
|
|
|
|
2013-05-15 22:55:30 +00:00
|
|
|
static int wpaint_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start,
|
|
|
|
wpaint_stroke_update_step, NULL,
|
|
|
|
wpaint_stroke_done, 0);
|
|
|
|
|
|
|
|
/* frees op->customdata */
|
|
|
|
paint_stroke_exec(C, op);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2011-06-06 11:04:54 +00:00
|
|
|
static int wpaint_cancel(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
paint_stroke_cancel(C, op);
|
|
|
|
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
void PAINT_OT_weight_paint(wmOperatorType *ot)
|
2009-01-10 14:19:14 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Weight Paint";
|
|
|
|
ot->idname = "PAINT_OT_weight_paint";
|
2012-05-05 17:10:51 +00:00
|
|
|
ot->description = "Paint a stroke in the current vertex group's weights";
|
2009-01-10 14:19:14 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = wpaint_invoke;
|
|
|
|
ot->modal = paint_stroke_modal;
|
2013-05-15 22:55:30 +00:00
|
|
|
ot->exec = wpaint_exec;
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->poll = weight_paint_poll;
|
|
|
|
ot->cancel = wpaint_cancel;
|
2009-01-10 14:19:14 +00:00
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
2013-05-15 22:55:30 +00:00
|
|
|
ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
|
2009-08-20 15:25:12 +00:00
|
|
|
|
|
|
|
RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
}
|
|
|
|
|
2012-12-28 09:00:05 +00:00
|
|
|
static int weight_paint_set_exec(bContext *C, wmOperator *op)
|
2009-11-01 00:06:53 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
struct Scene *scene = CTX_data_scene(C);
|
2009-11-01 00:06:53 +00:00
|
|
|
Object *obact = CTX_data_active_object(C);
|
2012-05-02 16:05:25 +00:00
|
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
|
2012-05-05 00:58:22 +00:00
|
|
|
float vgroup_weight = BKE_brush_weight_get(scene, brush);
|
2009-11-01 00:06:53 +00:00
|
|
|
|
2012-12-28 09:00:05 +00:00
|
|
|
if (wpaint_ensure_data(C, op) == FALSE) {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
2013-04-27 19:00:26 +00:00
|
|
|
if (ED_wpaint_fill(scene->toolsettings->wpaint, obact, vgroup_weight)) {
|
|
|
|
ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
2009-11-01 00:06:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PAINT_OT_weight_set(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Set Weight";
|
|
|
|
ot->idname = "PAINT_OT_weight_set";
|
2012-05-05 17:10:51 +00:00
|
|
|
ot->description = "Fill the active vertex group with the current paint weight";
|
2009-11-01 00:06:53 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = weight_paint_set_exec;
|
|
|
|
ot->poll = mask_paint_poll; /* it was facemask_paint_poll */
|
2009-11-01 00:06:53 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-03-28 03:47:33 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2009-11-01 00:06:53 +00:00
|
|
|
}
|
|
|
|
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
/* ************ set / clear vertex paint mode ********** */
|
|
|
|
|
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
static int set_vpaint(bContext *C, wmOperator *op) /* toggle */
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
Object *ob = CTX_data_active_object(C);
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
VPaint *vp = scene->toolsettings->vpaint;
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
Mesh *me;
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-05-05 16:03:57 +00:00
|
|
|
me = BKE_mesh_from_object(ob);
|
2009-02-10 15:38:00 +00:00
|
|
|
|
2012-05-05 14:03:12 +00:00
|
|
|
if (me == NULL || BKE_object_obdata_is_libdata(ob)) {
|
2009-08-15 20:36:15 +00:00
|
|
|
ob->mode &= ~OB_MODE_VERTEX_PAINT;
|
2009-07-25 13:40:59 +00:00
|
|
|
return OPERATOR_PASS_THROUGH;
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
if (me && me->mloopcol == NULL) {
|
|
|
|
make_vertexcol(ob);
|
|
|
|
}
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
|
|
|
/* toggle: end vpaint */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (ob->mode & OB_MODE_VERTEX_PAINT) {
|
2009-01-10 14:19:14 +00:00
|
|
|
|
2009-08-15 20:36:15 +00:00
|
|
|
ob->mode &= ~OB_MODE_VERTEX_PAINT;
|
2012-12-22 14:20:27 +00:00
|
|
|
|
2012-12-22 14:25:34 +00:00
|
|
|
if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
|
2012-12-22 14:20:27 +00:00
|
|
|
BKE_mesh_flush_select_from_polys(me);
|
|
|
|
}
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
}
|
|
|
|
else {
|
2009-08-15 20:36:15 +00:00
|
|
|
ob->mode |= OB_MODE_VERTEX_PAINT;
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
/* Turn off weight painting */
|
2009-08-15 21:46:25 +00:00
|
|
|
if (ob->mode & OB_MODE_WEIGHT_PAINT)
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
set_wpaint(C, op);
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
if (vp == NULL)
|
|
|
|
vp = scene->toolsettings->vpaint = new_vpaint(0);
|
2009-01-10 14:19:14 +00:00
|
|
|
|
2009-10-22 23:22:05 +00:00
|
|
|
paint_cursor_start(C, vertex_paint_poll);
|
2009-08-17 02:49:31 +00:00
|
|
|
|
2012-07-25 13:44:59 +00:00
|
|
|
BKE_paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT);
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
}
|
|
|
|
|
2013-01-20 14:50:50 +00:00
|
|
|
/* update modifier stack for mapping requirements */
|
|
|
|
DAG_id_tag_update(&me->id, 0);
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Vertex Paint Mode";
|
|
|
|
ot->idname = "PAINT_OT_vertex_paint_toggle";
|
2012-05-05 17:10:51 +00:00
|
|
|
ot->description = "Toggle the vertex paint mode in 3D view";
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = set_vpaint;
|
|
|
|
ot->poll = paint_poll_test;
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
2012-03-28 03:47:33 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
|
|
|
|
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
|
|
|
/* ********************** vertex paint operator ******************* */
|
|
|
|
|
|
|
|
/* Implementation notes:
|
2012-03-03 16:31:46 +00:00
|
|
|
*
|
|
|
|
* Operator->invoke()
|
|
|
|
* - validate context (add mcol)
|
|
|
|
* - create customdata storage
|
|
|
|
* - call paint once (mouse click)
|
|
|
|
* - add modal handler
|
|
|
|
*
|
|
|
|
* Operator->modal()
|
|
|
|
* - for every mousemove, apply vertex paint
|
|
|
|
* - exit on mouse release, free customdata
|
|
|
|
* (return OPERATOR_FINISHED also removes handler and operator)
|
|
|
|
*
|
|
|
|
* For future:
|
|
|
|
* - implement a stroke event (or mousemove with past positons)
|
|
|
|
* - revise whether op->customdata should be added in object, in set_vpaint
|
|
|
|
*/
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
2012-06-10 15:20:10 +00:00
|
|
|
typedef struct PolyFaceMap {
|
|
|
|
struct PolyFaceMap *next, *prev;
|
2009-08-30 21:30:07 +00:00
|
|
|
int facenr;
|
2012-06-10 15:20:10 +00:00
|
|
|
} PolyFaceMap;
|
2009-08-30 21:30:07 +00:00
|
|
|
|
2009-09-16 17:43:09 +00:00
|
|
|
typedef struct VPaintData {
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
ViewContext vc;
|
|
|
|
unsigned int paintcol;
|
|
|
|
int *indexar;
|
2013-06-26 18:40:55 +00:00
|
|
|
|
|
|
|
struct VertProjHandle *vp_handle;
|
2012-12-15 16:13:27 +00:00
|
|
|
DMCoNo *vertexcosnos;
|
2013-06-26 18:40:55 +00:00
|
|
|
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
float vpimat[3][3];
|
2012-02-08 11:52:44 +00:00
|
|
|
|
2013-04-25 14:29:19 +00:00
|
|
|
/* modify 'me->mcol' directly, since the derived mesh is drawing from this
|
|
|
|
* array, otherwise we need to refresh the modifier stack */
|
2012-02-08 11:52:44 +00:00
|
|
|
int use_fast_update;
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
/* mpoly -> mface mapping */
|
2012-02-08 11:52:44 +00:00
|
|
|
MemArena *polyfacemap_arena;
|
2009-08-30 21:30:07 +00:00
|
|
|
ListBase *polyfacemap;
|
2013-03-14 03:42:17 +00:00
|
|
|
|
2013-04-25 14:29:19 +00:00
|
|
|
/* loops tagged as having been painted, to apply shared vertex color
|
|
|
|
* blending only to modified loops */
|
|
|
|
bool *mlooptag;
|
|
|
|
bool *mfacetag;
|
|
|
|
|
2013-03-14 03:42:17 +00:00
|
|
|
bool is_texbrush;
|
2009-09-16 17:43:09 +00:00
|
|
|
} VPaintData;
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
2011-11-15 02:05:32 +00:00
|
|
|
static void vpaint_build_poly_facemap(struct VPaintData *vd, Mesh *me)
|
2009-08-30 21:30:07 +00:00
|
|
|
{
|
|
|
|
MFace *mf;
|
2012-06-10 15:20:10 +00:00
|
|
|
PolyFaceMap *e;
|
2009-08-30 21:30:07 +00:00
|
|
|
int *origIndex;
|
|
|
|
int i;
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
vd->polyfacemap_arena = BLI_memarena_new(1 << 13, "vpaint tmp");
|
2012-02-08 11:52:44 +00:00
|
|
|
BLI_memarena_use_calloc(vd->polyfacemap_arena);
|
2009-08-30 21:30:07 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
vd->polyfacemap = BLI_memarena_alloc(vd->polyfacemap_arena, sizeof(ListBase) * me->totpoly);
|
2009-08-30 21:30:07 +00:00
|
|
|
|
2012-10-30 19:20:17 +00:00
|
|
|
origIndex = CustomData_get_layer(&me->fdata, CD_ORIGINDEX);
|
2009-08-30 21:30:07 +00:00
|
|
|
mf = me->mface;
|
|
|
|
|
|
|
|
if (!origIndex)
|
|
|
|
return;
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
for (i = 0; i < me->totface; i++, mf++, origIndex++) {
|
2009-08-30 21:30:07 +00:00
|
|
|
if (*origIndex == ORIGINDEX_NONE)
|
|
|
|
continue;
|
|
|
|
|
2012-06-10 15:20:10 +00:00
|
|
|
e = BLI_memarena_alloc(vd->polyfacemap_arena, sizeof(PolyFaceMap));
|
2009-08-30 21:30:07 +00:00
|
|
|
e->facenr = i;
|
|
|
|
|
|
|
|
BLI_addtail(&vd->polyfacemap[*origIndex], e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-21 23:32:46 +00:00
|
|
|
static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float UNUSED(mouse[2]))
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
2009-08-20 05:13:07 +00:00
|
|
|
struct PaintStroke *stroke = op->customdata;
|
2012-03-24 11:27:52 +00:00
|
|
|
VPaint *vp = ts->vpaint;
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
Brush *brush = BKE_paint_brush(&vp->paint);
|
2009-08-20 05:13:07 +00:00
|
|
|
struct VPaintData *vpd;
|
2012-03-24 11:27:52 +00:00
|
|
|
Object *ob = CTX_data_active_object(C);
|
2009-08-20 05:13:07 +00:00
|
|
|
Mesh *me;
|
|
|
|
float mat[4][4], imat[4][4];
|
|
|
|
|
|
|
|
/* context checks could be a poll() */
|
2012-05-05 16:03:57 +00:00
|
|
|
me = BKE_mesh_from_object(ob);
|
2012-03-24 11:27:52 +00:00
|
|
|
if (me == NULL || me->totpoly == 0)
|
2009-08-30 21:30:07 +00:00
|
|
|
return OPERATOR_PASS_THROUGH;
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
if (me->mloopcol == NULL)
|
2009-11-01 00:06:53 +00:00
|
|
|
make_vertexcol(ob);
|
2012-03-24 11:27:52 +00:00
|
|
|
if (me->mloopcol == NULL)
|
2009-08-30 21:30:07 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2012-10-29 16:26:18 +00:00
|
|
|
|
|
|
|
/* Update tessface data if needed
|
|
|
|
* Added here too because e.g. switching to/from edit mode would remove tessface data,
|
|
|
|
* yet "fast_update" could still be used! */
|
|
|
|
update_tessface_data(ob, me);
|
|
|
|
|
2009-08-20 05:13:07 +00:00
|
|
|
/* make mode data storage */
|
2012-03-24 11:27:52 +00:00
|
|
|
vpd = MEM_callocN(sizeof(struct VPaintData), "VPaintData");
|
2009-08-20 05:13:07 +00:00
|
|
|
paint_stroke_set_mode_data(stroke, vpd);
|
|
|
|
view3d_set_viewcontext(C, &vpd->vc);
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
2013-06-26 18:40:55 +00:00
|
|
|
vpd->vp_handle = ED_vpaint_proj_handle_create(vpd->vc.scene, ob, &vpd->vertexcosnos);
|
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
vpd->indexar = get_indexarray(me);
|
|
|
|
vpd->paintcol = vpaint_get_current_col(vp);
|
2012-02-08 11:52:44 +00:00
|
|
|
|
2013-03-14 03:42:17 +00:00
|
|
|
vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) &&
|
|
|
|
brush->mtex.tex;
|
2012-02-08 11:52:44 +00:00
|
|
|
|
|
|
|
/* are we painting onto a modified mesh?,
|
|
|
|
* if not we can skip face map trickyness */
|
|
|
|
if (vertex_paint_use_fast_update_check(ob)) {
|
|
|
|
vpaint_build_poly_facemap(vpd, me);
|
|
|
|
vpd->use_fast_update = TRUE;
|
2012-10-29 16:26:18 +00:00
|
|
|
/* printf("Fast update!\n");*/
|
2012-02-08 11:52:44 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
vpd->use_fast_update = FALSE;
|
2012-10-29 16:26:18 +00:00
|
|
|
/* printf("No fast update!\n");*/
|
2012-02-08 11:52:44 +00:00
|
|
|
}
|
|
|
|
|
2013-04-25 14:29:19 +00:00
|
|
|
/* to keep tracked of modified loops for shared vertex color blending */
|
|
|
|
if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
|
2013-04-25 16:35:57 +00:00
|
|
|
vpd->mlooptag = MEM_mallocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
|
2013-04-25 14:29:19 +00:00
|
|
|
if (vpd->use_fast_update)
|
2013-04-25 16:35:57 +00:00
|
|
|
vpd->mfacetag = MEM_mallocN(sizeof(bool) * me->totface * 4, "VPaintData mfacetag");
|
2013-04-25 14:29:19 +00:00
|
|
|
}
|
|
|
|
|
2009-08-20 05:13:07 +00:00
|
|
|
/* for filtering */
|
2009-08-30 21:30:07 +00:00
|
|
|
copy_vpaint_prev(vp, (unsigned int *)me->mloopcol, me->totloop);
|
2009-08-20 05:13:07 +00:00
|
|
|
|
|
|
|
/* some old cruft to sort out later */
|
2013-05-26 18:36:25 +00:00
|
|
|
mul_m4_m4m4(mat, vpd->vc.rv3d->viewmat, ob->obmat);
|
2009-11-10 20:43:45 +00:00
|
|
|
invert_m4_m4(imat, mat);
|
|
|
|
copy_m3_m4(vpd->vpimat, imat);
|
2009-08-20 05:13:07 +00:00
|
|
|
|
2013-01-17 04:24:22 +00:00
|
|
|
{
|
|
|
|
UnifiedPaintSettings *ups = &ts->unified_paint_settings;
|
|
|
|
ups->draw_pressure = true;
|
|
|
|
}
|
|
|
|
|
2009-08-20 05:13:07 +00:00
|
|
|
return 1;
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
}
|
|
|
|
|
2012-12-15 16:31:25 +00:00
|
|
|
static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Mesh *me,
|
2012-01-15 10:48:39 +00:00
|
|
|
const unsigned int index, const float mval[2],
|
2012-04-16 10:02:52 +00:00
|
|
|
const float brush_size_pressure, const float brush_alpha_pressure)
|
2012-01-15 10:48:39 +00:00
|
|
|
{
|
|
|
|
ViewContext *vc = &vpd->vc;
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
Brush *brush = BKE_paint_brush(&vp->paint);
|
2012-03-24 11:27:52 +00:00
|
|
|
MPoly *mpoly = &me->mpoly[index];
|
2012-01-15 10:48:39 +00:00
|
|
|
MFace *mf;
|
|
|
|
MCol *mc;
|
|
|
|
MLoop *ml;
|
|
|
|
MLoopCol *mlc;
|
2012-06-10 15:20:10 +00:00
|
|
|
PolyFaceMap *e;
|
2012-03-24 11:27:52 +00:00
|
|
|
unsigned int *lcol = ((unsigned int *)me->mloopcol) + mpoly->loopstart;
|
|
|
|
unsigned int *lcolorig = ((unsigned int *)vp->vpaint_prev) + mpoly->loopstart;
|
2013-04-25 14:29:19 +00:00
|
|
|
bool *mlooptag = (vpd->mlooptag) ? vpd->mlooptag + mpoly->loopstart : NULL;
|
|
|
|
bool *mftag;
|
2012-01-15 10:48:39 +00:00
|
|
|
float alpha;
|
|
|
|
int i, j;
|
2013-04-25 14:16:22 +00:00
|
|
|
int totloop = mpoly->totloop;
|
2012-01-15 10:48:39 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
int brush_alpha_pressure_i = (int)(brush_alpha_pressure * 255.0f);
|
2012-01-15 10:48:39 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
|
2012-01-15 10:48:39 +00:00
|
|
|
unsigned int blend[4] = {0};
|
|
|
|
unsigned int tcol;
|
|
|
|
char *col;
|
|
|
|
|
2013-04-25 14:16:22 +00:00
|
|
|
for (j = 0; j < totloop; j++) {
|
2012-01-15 10:48:39 +00:00
|
|
|
col = (char *)(lcol + j);
|
|
|
|
blend[0] += col[0];
|
|
|
|
blend[1] += col[1];
|
|
|
|
blend[2] += col[2];
|
|
|
|
blend[3] += col[3];
|
|
|
|
}
|
|
|
|
|
2013-04-25 14:16:22 +00:00
|
|
|
blend[0] = divide_round_i(blend[0], totloop);
|
|
|
|
blend[1] = divide_round_i(blend[1], totloop);
|
|
|
|
blend[2] = divide_round_i(blend[2], totloop);
|
|
|
|
blend[3] = divide_round_i(blend[3], totloop);
|
2012-01-15 10:48:39 +00:00
|
|
|
col = (char *)&tcol;
|
|
|
|
col[0] = blend[0];
|
|
|
|
col[1] = blend[1];
|
|
|
|
col[2] = blend[2];
|
|
|
|
col[3] = blend[3];
|
|
|
|
|
|
|
|
vpd->paintcol = *((unsigned int *)col);
|
|
|
|
}
|
|
|
|
|
|
|
|
ml = me->mloop + mpoly->loopstart;
|
2013-04-25 14:16:22 +00:00
|
|
|
for (i = 0; i < totloop; i++, ml++) {
|
2013-03-14 03:42:17 +00:00
|
|
|
float rgba[4];
|
|
|
|
unsigned int paintcol;
|
2013-03-14 03:47:20 +00:00
|
|
|
alpha = calc_vp_alpha_col_dl(vp, vc, vpd->vpimat,
|
2012-12-15 16:13:27 +00:00
|
|
|
&vpd->vertexcosnos[ml->v], mval,
|
2013-03-14 03:42:17 +00:00
|
|
|
brush_size_pressure, brush_alpha_pressure, rgba);
|
|
|
|
|
|
|
|
if (vpd->is_texbrush) {
|
|
|
|
float rgba_br[3];
|
|
|
|
rgb_uchar_to_float(rgba_br, (const unsigned char *)&vpd->paintcol);
|
|
|
|
mul_v3_v3(rgba_br, rgba);
|
|
|
|
rgb_float_to_uchar((unsigned char *)&paintcol, rgba_br);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
paintcol = vpd->paintcol;
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (alpha > 0.0f) {
|
2012-03-24 11:27:52 +00:00
|
|
|
const int alpha_i = (int)(alpha * 255.0f);
|
2013-03-14 03:42:17 +00:00
|
|
|
lcol[i] = vpaint_blend(vp, lcol[i], lcolorig[i], paintcol, alpha_i, brush_alpha_pressure_i);
|
2013-04-25 14:29:19 +00:00
|
|
|
|
|
|
|
if (mlooptag) mlooptag[i] = 1;
|
2012-01-15 10:48:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-08 11:52:44 +00:00
|
|
|
if (vpd->use_fast_update) {
|
2012-03-02 16:05:54 +00:00
|
|
|
/* update vertex colors for tessellations incrementally,
|
|
|
|
* rather then regenerating the tessellation altogether */
|
2012-02-08 11:52:44 +00:00
|
|
|
for (e = vpd->polyfacemap[index].first; e; e = e->next) {
|
2012-09-18 04:55:52 +00:00
|
|
|
mf = &me->mface[e->facenr];
|
|
|
|
mc = &me->mcol[e->facenr * 4];
|
2013-04-25 14:29:19 +00:00
|
|
|
mftag = &vpd->mfacetag[e->facenr * 4];
|
2012-02-08 11:52:44 +00:00
|
|
|
|
|
|
|
ml = me->mloop + mpoly->loopstart;
|
|
|
|
mlc = me->mloopcol + mpoly->loopstart;
|
2013-04-25 14:16:22 +00:00
|
|
|
for (j = 0; j < totloop; j++, ml++, mlc++) {
|
2012-10-29 16:26:18 +00:00
|
|
|
if (ml->v == mf->v1) {
|
|
|
|
MESH_MLOOPCOL_TO_MCOL(mlc, mc + 0);
|
2013-04-25 14:29:19 +00:00
|
|
|
if (mlooptag) mftag[0] = mlooptag[j];
|
2012-10-29 16:26:18 +00:00
|
|
|
}
|
|
|
|
else if (ml->v == mf->v2) {
|
|
|
|
MESH_MLOOPCOL_TO_MCOL(mlc, mc + 1);
|
2013-04-25 14:29:19 +00:00
|
|
|
if (mlooptag) mftag[1] = mlooptag[j];
|
2012-10-29 16:26:18 +00:00
|
|
|
}
|
|
|
|
else if (ml->v == mf->v3) {
|
|
|
|
MESH_MLOOPCOL_TO_MCOL(mlc, mc + 2);
|
2013-04-25 14:29:19 +00:00
|
|
|
if (mlooptag) mftag[2] = mlooptag[j];
|
2012-10-29 16:26:18 +00:00
|
|
|
}
|
|
|
|
else if (mf->v4 && ml->v == mf->v4) {
|
|
|
|
MESH_MLOOPCOL_TO_MCOL(mlc, mc + 3);
|
2013-04-25 14:29:19 +00:00
|
|
|
if (mlooptag) mftag[3] = mlooptag[j];
|
2012-10-29 16:26:18 +00:00
|
|
|
}
|
2012-02-08 11:52:44 +00:00
|
|
|
}
|
2012-01-15 10:48:39 +00:00
|
|
|
}
|
2012-02-08 11:52:44 +00:00
|
|
|
}
|
2012-01-15 10:48:39 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-08-20 05:13:07 +00:00
|
|
|
static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
2009-08-20 05:13:07 +00:00
|
|
|
struct VPaintData *vpd = paint_stroke_mode_data(stroke);
|
2012-03-24 11:27:52 +00:00
|
|
|
VPaint *vp = ts->vpaint;
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
Brush *brush = BKE_paint_brush(&vp->paint);
|
2012-03-24 11:27:52 +00:00
|
|
|
ViewContext *vc = &vpd->vc;
|
|
|
|
Object *ob = vc->obact;
|
|
|
|
Mesh *me = ob->data;
|
2009-08-19 21:24:52 +00:00
|
|
|
float mat[4][4];
|
2012-03-24 11:27:52 +00:00
|
|
|
int *indexar = vpd->indexar;
|
2012-04-16 10:02:52 +00:00
|
|
|
int totindex, index;
|
2011-12-30 03:50:04 +00:00
|
|
|
float mval[2];
|
|
|
|
|
|
|
|
const float pressure = RNA_float_get(itemptr, "pressure");
|
2012-05-05 00:58:22 +00:00
|
|
|
const float brush_size_pressure = BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f);
|
|
|
|
const float brush_alpha_pressure = BKE_brush_alpha_get(scene, brush) * (BKE_brush_use_alpha_pressure(scene, brush) ? pressure : 1.0f);
|
2009-08-20 05:13:07 +00:00
|
|
|
|
|
|
|
RNA_float_get_array(itemptr, "mouse", mval);
|
2011-11-16 17:09:41 +00:00
|
|
|
|
2009-08-19 21:24:52 +00:00
|
|
|
view3d_operator_needs_opengl(C);
|
2013-01-30 02:27:13 +00:00
|
|
|
ED_view3d_init_mats_rv3d(ob, vc->rv3d);
|
|
|
|
|
2009-08-19 21:24:52 +00:00
|
|
|
/* load projection matrix */
|
2013-05-26 18:36:25 +00:00
|
|
|
mul_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat);
|
2009-08-20 05:13:07 +00:00
|
|
|
|
2009-08-19 21:24:52 +00:00
|
|
|
/* which faces are involved */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (vp->flag & VP_AREA) {
|
2012-03-24 11:27:52 +00:00
|
|
|
totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure);
|
2009-08-19 21:24:52 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-03-24 11:27:52 +00:00
|
|
|
indexar[0] = view3d_sample_backbuf(vc, mval[0], mval[1]);
|
|
|
|
if (indexar[0]) totindex = 1;
|
|
|
|
else totindex = 0;
|
2009-08-19 21:24:52 +00:00
|
|
|
}
|
2009-11-01 00:06:53 +00:00
|
|
|
|
2012-12-22 14:25:34 +00:00
|
|
|
if ((me->editflag & ME_EDIT_PAINT_FACE_SEL) && me->mpoly) {
|
2012-03-24 11:27:52 +00:00
|
|
|
for (index = 0; index < totindex; index++) {
|
|
|
|
if (indexar[index] && indexar[index] <= me->totpoly) {
|
|
|
|
MPoly *mpoly = ((MPoly *)me->mpoly) + (indexar[index] - 1);
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
if ((mpoly->flag & ME_FACE_SEL) == 0)
|
|
|
|
indexar[index] = 0;
|
2012-09-18 04:55:52 +00:00
|
|
|
}
|
2009-08-19 21:24:52 +00:00
|
|
|
}
|
|
|
|
}
|
2009-09-16 17:43:09 +00:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
swap_m4m4(vc->rv3d->persmat, mat);
|
2009-09-16 17:43:09 +00:00
|
|
|
|
2013-06-26 18:40:55 +00:00
|
|
|
/* incase we have modifiers */
|
|
|
|
ED_vpaint_proj_handle_update(vpd->vp_handle, vc->ar, mval);
|
|
|
|
|
2013-04-25 14:29:19 +00:00
|
|
|
/* clear modified tag for blur tool */
|
2013-04-25 16:35:57 +00:00
|
|
|
if (vpd->mlooptag)
|
|
|
|
memset(vpd->mlooptag, 0, sizeof(bool) * me->totloop);
|
2013-04-25 14:29:19 +00:00
|
|
|
if (vpd->mfacetag)
|
2013-04-25 16:35:57 +00:00
|
|
|
memset(vpd->mfacetag, 0, sizeof(bool) * me->totface * 4);
|
2013-04-25 14:29:19 +00:00
|
|
|
|
2012-03-24 11:27:52 +00:00
|
|
|
for (index = 0; index < totindex; index++) {
|
|
|
|
if (indexar[index] && indexar[index] <= me->totpoly) {
|
2012-12-15 16:31:25 +00:00
|
|
|
vpaint_paint_poly(vp, vpd, me, indexar[index] - 1, mval, brush_size_pressure, brush_alpha_pressure);
|
2009-08-19 21:24:52 +00:00
|
|
|
}
|
|
|
|
}
|
2009-08-30 21:30:07 +00:00
|
|
|
|
2009-11-23 14:41:22 +00:00
|
|
|
swap_m4m4(vc->rv3d->persmat, mat);
|
2012-01-18 08:43:27 +00:00
|
|
|
|
2011-10-29 13:25:18 +00:00
|
|
|
/* was disabled because it is slow, but necessary for blur */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
|
2012-02-08 11:52:44 +00:00
|
|
|
int do_tessface = vpd->use_fast_update;
|
2013-04-25 14:29:19 +00:00
|
|
|
do_shared_vertexcol(me, vpd->mlooptag, vpd->mfacetag, do_tessface);
|
2011-10-29 13:25:18 +00:00
|
|
|
}
|
2009-09-05 06:10:30 +00:00
|
|
|
|
2013-01-17 04:24:22 +00:00
|
|
|
{
|
|
|
|
UnifiedPaintSettings *ups = &ts->unified_paint_settings;
|
|
|
|
ups->pressure_value = pressure;
|
|
|
|
}
|
|
|
|
|
2012-02-08 11:52:44 +00:00
|
|
|
ED_region_tag_redraw(vc->ar);
|
|
|
|
|
|
|
|
if (vpd->use_fast_update == FALSE) {
|
|
|
|
/* recalculate modifier stack to get new colors, slow,
|
|
|
|
* avoid this if we can! */
|
|
|
|
DAG_id_tag_update(ob->data, 0);
|
|
|
|
}
|
2012-10-29 16:26:18 +00:00
|
|
|
else if (!GPU_buffer_legacy(ob->derivedFinal)) {
|
|
|
|
/* If using new VBO drawing, mark mcol as dirty to force colors gpu buffer refresh! */
|
|
|
|
ob->derivedFinal->dirty |= DM_DIRTY_MCOL_UPDATE_DRAW;
|
|
|
|
}
|
2009-08-19 21:24:52 +00:00
|
|
|
}
|
|
|
|
|
2012-05-03 04:11:53 +00:00
|
|
|
static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
|
2009-08-19 21:24:52 +00:00
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
|
|
struct VPaintData *vpd = paint_stroke_mode_data(stroke);
|
2012-06-04 15:13:36 +00:00
|
|
|
ViewContext *vc = &vpd->vc;
|
|
|
|
Object *ob = vc->obact;
|
2009-08-19 21:24:52 +00:00
|
|
|
|
2013-06-26 18:40:55 +00:00
|
|
|
ED_vpaint_proj_handle_free(vpd->vp_handle);
|
2009-08-20 05:13:07 +00:00
|
|
|
MEM_freeN(vpd->indexar);
|
|
|
|
|
|
|
|
/* frees prev buffer */
|
|
|
|
copy_vpaint_prev(ts->vpaint, NULL, 0);
|
2012-02-08 11:52:44 +00:00
|
|
|
|
|
|
|
if (vpd->polyfacemap_arena) {
|
|
|
|
BLI_memarena_free(vpd->polyfacemap_arena);
|
|
|
|
}
|
2009-08-30 21:30:07 +00:00
|
|
|
|
2013-04-25 14:29:19 +00:00
|
|
|
if (vpd->mlooptag)
|
|
|
|
MEM_freeN(vpd->mlooptag);
|
|
|
|
|
|
|
|
if (vpd->mfacetag)
|
|
|
|
MEM_freeN(vpd->mfacetag);
|
|
|
|
|
2013-01-17 04:24:22 +00:00
|
|
|
{
|
|
|
|
UnifiedPaintSettings *ups = &ts->unified_paint_settings;
|
|
|
|
ups->draw_pressure = false;
|
|
|
|
}
|
|
|
|
|
2012-06-04 15:13:36 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
|
|
|
|
|
2009-08-20 05:13:07 +00:00
|
|
|
MEM_freeN(vpd);
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
{
|
2012-10-06 00:42:30 +00:00
|
|
|
int retval;
|
|
|
|
|
2009-10-27 19:53:34 +00:00
|
|
|
op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start,
|
2013-05-15 14:37:05 +00:00
|
|
|
vpaint_stroke_update_step, NULL,
|
2012-03-28 03:47:33 +00:00
|
|
|
vpaint_stroke_done, event->type);
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
/* add modal handler */
|
2009-10-22 23:22:05 +00:00
|
|
|
WM_event_add_modal_handler(C, op);
|
2009-08-21 00:46:36 +00:00
|
|
|
|
2012-10-06 00:42:30 +00:00
|
|
|
retval = op->type->modal(C, op, event);
|
|
|
|
OPERATOR_RETVAL_CHECK(retval);
|
|
|
|
BLI_assert(retval == OPERATOR_RUNNING_MODAL);
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
|
|
}
|
2009-01-07 19:23:22 +00:00
|
|
|
|
2013-05-15 22:55:30 +00:00
|
|
|
static int vpaint_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start,
|
|
|
|
vpaint_stroke_update_step, NULL,
|
|
|
|
vpaint_stroke_done, 0);
|
|
|
|
|
|
|
|
/* frees op->customdata */
|
|
|
|
paint_stroke_exec(C, op);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2011-06-06 11:04:54 +00:00
|
|
|
static int vpaint_cancel(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
paint_stroke_cancel(C, op);
|
|
|
|
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
2009-02-19 23:53:40 +00:00
|
|
|
void PAINT_OT_vertex_paint(wmOperatorType *ot)
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Vertex Paint";
|
|
|
|
ot->idname = "PAINT_OT_vertex_paint";
|
2012-05-05 17:10:51 +00:00
|
|
|
ot->description = "Paint a stroke in the active vertex color layer";
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = vpaint_invoke;
|
|
|
|
ot->modal = paint_stroke_modal;
|
2013-05-15 22:55:30 +00:00
|
|
|
ot->exec = vpaint_exec;
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->poll = vertex_paint_poll;
|
|
|
|
ot->cancel = vpaint_cancel;
|
2.5
Vertex Paint back!
Added WM level "paint cursor" system, which manages a custom painting
cursor for tools or modes.
- Activate it with WM_paint_cursor_activate(). That function wants two
callbacks, a poll(C) to check whether there's a cursor in given context
and ARegion, and a draw(C, x, y) which gets called when appropriate.
- While paintcursor is active, the WM handles necessary redrawing events
for all regions, also to nicely clear the cursor on region exit.
- WM_paint_cursor_activate returns a handle, which you have to use to
end the paint cursor. This handle also means you can register as many
custom cursors as you want.
At the moment, vertex paint mode registers only a mousemove handler,
all other events are still normally handled. This is stuff for the
future todo.
2009-01-09 13:55:45 +00:00
|
|
|
|
2009-01-31 19:40:40 +00:00
|
|
|
/* flags */
|
2013-05-15 22:55:30 +00:00
|
|
|
ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
|
2009-08-20 05:13:07 +00:00
|
|
|
|
|
|
|
RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
|
2009-01-07 19:23:22 +00:00
|
|
|
}
|
|
|
|
|
2010-01-26 11:11:53 +00:00
|
|
|
/* ********************** weight from bones operator ******************* */
|
|
|
|
|
|
|
|
static int weight_from_bones_poll(bContext *C)
|
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
Object *ob = CTX_data_active_object(C);
|
2010-01-26 11:11:53 +00:00
|
|
|
|
|
|
|
return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int weight_from_bones_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
Object *ob = CTX_data_active_object(C);
|
|
|
|
Object *armob = modifiers_isDeformedByArmature(ob);
|
|
|
|
Mesh *me = ob->data;
|
|
|
|
int type = RNA_enum_get(op->ptr, "type");
|
2010-01-26 11:11:53 +00:00
|
|
|
|
2010-10-11 00:15:49 +00:00
|
|
|
create_vgroups_from_armature(op->reports, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X));
|
2010-01-26 11:11:53 +00:00
|
|
|
|
2011-01-03 12:41:16 +00:00
|
|
|
DAG_id_tag_update(&me->id, 0);
|
2012-03-28 03:47:33 +00:00
|
|
|
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
|
2010-01-26 11:11:53 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PAINT_OT_weight_from_bones(wmOperatorType *ot)
|
|
|
|
{
|
2012-03-24 11:27:52 +00:00
|
|
|
static EnumPropertyItem type_items[] = {
|
2012-07-04 15:04:38 +00:00
|
|
|
{ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights from bones"},
|
2010-02-11 02:03:18 +00:00
|
|
|
{ARM_GROUPS_ENVELOPE, "ENVELOPES", 0, "From Envelopes", "Weights from envelopes with user defined radius"},
|
2010-01-26 11:11:53 +00:00
|
|
|
{0, NULL, 0, NULL, NULL}};
|
|
|
|
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Weight from Bones";
|
|
|
|
ot->idname = "PAINT_OT_weight_from_bones";
|
2012-05-06 15:03:31 +00:00
|
|
|
ot->description = "Set the weights of the groups matching the attached armature's selected bones, "
|
|
|
|
"using the distance between the vertices and the bones";
|
2010-01-26 11:11:53 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = weight_from_bones_exec;
|
|
|
|
ot->invoke = WM_menu_invoke;
|
|
|
|
ot->poll = weight_from_bones_poll;
|
2010-01-26 11:11:53 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-03-28 03:47:33 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2010-01-26 11:11:53 +00:00
|
|
|
|
|
|
|
/* properties */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights");
|
2010-01-26 11:11:53 +00:00
|
|
|
}
|
2012-12-22 08:19:27 +00:00
|
|
|
|
|
|
|
/* *** VGroups Gradient *** */
|
|
|
|
typedef struct DMGradient_vertStore {
|
|
|
|
float sco[2];
|
|
|
|
float weight_orig;
|
|
|
|
enum {
|
|
|
|
VGRAD_STORE_NOP = 0,
|
|
|
|
VGRAD_STORE_DW_EXIST = (1 << 0)
|
|
|
|
} flag;
|
|
|
|
} DMGradient_vertStore;
|
|
|
|
|
|
|
|
typedef struct DMGradient_userData {
|
|
|
|
struct ARegion *ar;
|
|
|
|
Scene *scene;
|
|
|
|
Mesh *me;
|
|
|
|
Brush *brush;
|
|
|
|
const float *sco_start; /* [2] */
|
|
|
|
const float *sco_end; /* [2] */
|
|
|
|
float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */
|
|
|
|
int def_nr;
|
|
|
|
short is_init;
|
|
|
|
DMGradient_vertStore *vert_cache;
|
|
|
|
|
|
|
|
/* options */
|
|
|
|
short use_select;
|
|
|
|
short type;
|
|
|
|
float weightpaint;
|
|
|
|
} DMGradient_userData;
|
|
|
|
|
|
|
|
static void gradientVert__mapFunc(void *userData, int index, const float co[3],
|
|
|
|
const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
|
|
|
|
{
|
|
|
|
DMGradient_userData *grad_data = userData;
|
|
|
|
Mesh *me = grad_data->me;
|
|
|
|
|
|
|
|
if (grad_data->use_select == FALSE || (me->mvert[index].flag & SELECT)) {
|
|
|
|
DMGradient_vertStore *vs = &grad_data->vert_cache[index];
|
|
|
|
|
|
|
|
/* run first pass only, could be split into its own mapFunc
|
|
|
|
* the screen coords of the verts need to be cached because
|
|
|
|
* updating the mesh may move them about (entering feedback loop) */
|
|
|
|
if (grad_data->is_init) {
|
2013-01-01 14:20:59 +00:00
|
|
|
if (ED_view3d_project_float_object(grad_data->ar,
|
2012-12-22 08:19:27 +00:00
|
|
|
co, vs->sco,
|
2013-01-01 14:20:59 +00:00
|
|
|
V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
|
2012-12-22 08:19:27 +00:00
|
|
|
{
|
|
|
|
/* ok */
|
|
|
|
MDeformVert *dv = &me->dvert[index];
|
|
|
|
MDeformWeight *dw;
|
|
|
|
dw = defvert_find_index(dv, grad_data->def_nr);
|
|
|
|
if (dw) {
|
|
|
|
vs->weight_orig = dw->weight;
|
2012-12-22 09:37:37 +00:00
|
|
|
vs->flag = VGRAD_STORE_DW_EXIST;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
vs->weight_orig = 0.0f;
|
|
|
|
vs->flag = VGRAD_STORE_NOP;
|
2012-12-22 08:19:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* no go */
|
|
|
|
copy_v2_fl(vs->sco, FLT_MAX);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* end init */
|
|
|
|
|
|
|
|
if (vs->sco[0] != FLT_MAX) {
|
|
|
|
float alpha;
|
|
|
|
|
|
|
|
if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) {
|
|
|
|
alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end);
|
|
|
|
}
|
|
|
|
else {
|
2013-01-04 02:13:29 +00:00
|
|
|
BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL);
|
|
|
|
alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div;
|
2012-12-22 08:19:27 +00:00
|
|
|
}
|
|
|
|
/* no need to clamp 'alpha' yet */
|
|
|
|
|
|
|
|
/* adjust weight */
|
|
|
|
alpha = BKE_brush_curve_strength_clamp(grad_data->brush, alpha, 1.0f);
|
|
|
|
|
|
|
|
if (alpha != 0.0f) {
|
|
|
|
MDeformVert *dv = &me->dvert[index];
|
|
|
|
MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr);
|
|
|
|
// dw->weight = alpha; // testing
|
|
|
|
int tool = grad_data->brush->vertexpaint_tool;
|
|
|
|
float testw;
|
|
|
|
|
|
|
|
/* init if we just added */
|
|
|
|
testw = wpaint_blend_tool(tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha);
|
|
|
|
CLAMP(testw, 0.0f, 1.0f);
|
|
|
|
dw->weight = testw;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
MDeformVert *dv = &me->dvert[index];
|
|
|
|
if (vs->flag & VGRAD_STORE_DW_EXIST) {
|
|
|
|
/* normally we NULL check, but in this case we know it exists */
|
|
|
|
MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
|
|
|
|
dw->weight = vs->weight_orig;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* wasn't originally existing, remove */
|
|
|
|
MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
|
|
|
|
if (dw) {
|
|
|
|
defvert_remove_group(dv, dw);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
2012-12-22 08:19:27 +00:00
|
|
|
{
|
|
|
|
int ret = WM_gesture_straightline_modal(C, op, event);
|
|
|
|
|
|
|
|
if (ret & OPERATOR_RUNNING_MODAL) {
|
|
|
|
if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* XXX, hardcoded */
|
|
|
|
/* generally crap! redo! */
|
|
|
|
WM_gesture_straightline_cancel(C, op);
|
|
|
|
ret &= ~OPERATOR_RUNNING_MODAL;
|
|
|
|
ret |= OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret & OPERATOR_CANCELLED) {
|
|
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
|
|
VPaint *wp = ts->wpaint;
|
|
|
|
Object *ob = CTX_data_active_object(C);
|
|
|
|
Mesh *me = ob->data;
|
2013-02-14 02:21:12 +00:00
|
|
|
if (wp->wpaint_prev) {
|
|
|
|
BKE_defvert_array_free_elems(me->dvert, me->totvert);
|
|
|
|
BKE_defvert_array_copy(me->dvert, wp->wpaint_prev, me->totvert);
|
|
|
|
free_wpaint_prev(wp);
|
|
|
|
}
|
2012-12-22 08:19:27 +00:00
|
|
|
|
|
|
|
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
|
|
|
|
}
|
|
|
|
else if (ret & OPERATOR_FINISHED) {
|
|
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
|
|
VPaint *wp = ts->wpaint;
|
|
|
|
free_wpaint_prev(wp);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
wmGesture *gesture = op->customdata;
|
2013-02-11 06:58:38 +00:00
|
|
|
DMGradient_vertStore *vert_cache;
|
2012-12-22 08:19:27 +00:00
|
|
|
struct ARegion *ar = CTX_wm_region(C);
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
Object *ob = CTX_data_active_object(C);
|
|
|
|
Mesh *me = ob->data;
|
|
|
|
int x_start = RNA_int_get(op->ptr, "xstart");
|
|
|
|
int y_start = RNA_int_get(op->ptr, "ystart");
|
|
|
|
int x_end = RNA_int_get(op->ptr, "xend");
|
|
|
|
int y_end = RNA_int_get(op->ptr, "yend");
|
|
|
|
float sco_start[2] = {x_start, y_start};
|
|
|
|
float sco_end[2] = {x_end, y_end};
|
2013-02-11 06:58:38 +00:00
|
|
|
const bool is_interactive = (gesture != NULL);
|
2012-12-22 08:19:27 +00:00
|
|
|
DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
|
|
|
|
|
|
|
|
DMGradient_userData data = {0};
|
|
|
|
|
2013-02-11 06:58:38 +00:00
|
|
|
if (is_interactive) {
|
|
|
|
if (gesture->userdata == NULL) {
|
|
|
|
VPaint *wp = scene->toolsettings->wpaint;
|
2012-12-22 08:19:27 +00:00
|
|
|
|
2013-02-11 06:58:38 +00:00
|
|
|
gesture->userdata = MEM_mallocN(sizeof(DMGradient_vertStore) * me->totvert, __func__);
|
|
|
|
data.is_init = true;
|
2012-12-22 08:19:27 +00:00
|
|
|
|
2013-02-11 06:58:38 +00:00
|
|
|
copy_wpaint_prev(wp, me->dvert, me->totvert);
|
2012-12-22 08:19:27 +00:00
|
|
|
|
2013-02-11 06:58:38 +00:00
|
|
|
/* on init only, convert face -> vert sel */
|
|
|
|
if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
|
|
|
|
BKE_mesh_flush_select_from_polys(me);
|
|
|
|
}
|
2012-12-22 08:19:27 +00:00
|
|
|
}
|
|
|
|
|
2013-02-11 06:58:38 +00:00
|
|
|
vert_cache = gesture->userdata;
|
|
|
|
}
|
|
|
|
else {
|
2013-06-19 07:45:36 +00:00
|
|
|
if (wpaint_ensure_data(C, op) == FALSE) {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
2013-02-11 06:58:38 +00:00
|
|
|
data.is_init = true;
|
|
|
|
vert_cache = MEM_mallocN(sizeof(DMGradient_vertStore) * me->totvert, __func__);
|
2012-12-22 08:19:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
data.ar = ar;
|
|
|
|
data.scene = scene;
|
|
|
|
data.me = ob->data;
|
|
|
|
data.sco_start = sco_start;
|
|
|
|
data.sco_end = sco_end;
|
|
|
|
data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end);
|
|
|
|
data.def_nr = ob->actdef - 1;
|
2012-12-22 14:25:34 +00:00
|
|
|
data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL));
|
2013-02-11 06:58:38 +00:00
|
|
|
data.vert_cache = vert_cache;
|
2012-12-22 08:19:27 +00:00
|
|
|
data.type = RNA_enum_get(op->ptr, "type");
|
|
|
|
|
|
|
|
{
|
|
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
|
|
VPaint *wp = ts->wpaint;
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
struct Brush *brush = BKE_paint_brush(&wp->paint);
|
2012-12-22 08:19:27 +00:00
|
|
|
data.brush = brush;
|
|
|
|
data.weightpaint = BKE_brush_weight_get(scene, brush);
|
|
|
|
}
|
|
|
|
|
2013-05-02 02:39:30 +00:00
|
|
|
ED_view3d_init_mats_rv3d(ob, ar->regiondata);
|
|
|
|
|
2012-12-22 08:19:27 +00:00
|
|
|
dm->foreachMappedVert(dm, gradientVert__mapFunc, &data);
|
|
|
|
|
|
|
|
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
|
|
|
|
|
2013-02-11 06:58:38 +00:00
|
|
|
if (is_interactive == false) {
|
|
|
|
MEM_freeN(vert_cache);
|
|
|
|
}
|
|
|
|
|
2012-12-22 08:19:27 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2012-12-22 08:19:27 +00:00
|
|
|
{
|
2012-12-28 01:36:00 +00:00
|
|
|
int ret;
|
|
|
|
|
2012-12-28 09:00:05 +00:00
|
|
|
if (wpaint_ensure_data(C, op) == FALSE) {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
2012-12-28 01:36:00 +00:00
|
|
|
ret = WM_gesture_straightline_invoke(C, op, event);
|
2012-12-22 08:19:27 +00:00
|
|
|
if (ret & OPERATOR_RUNNING_MODAL) {
|
|
|
|
struct ARegion *ar = CTX_wm_region(C);
|
|
|
|
if (ar->regiontype == RGN_TYPE_WINDOW) {
|
|
|
|
if (event->type == LEFTMOUSE && event->val == KM_PRESS) { /* TODO, hardcoded, extend WM_gesture_straightline_ */
|
|
|
|
wmGesture *gesture = op->customdata;
|
|
|
|
gesture->mode = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PAINT_OT_weight_gradient(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* defined in DNA_space_types.h */
|
|
|
|
static EnumPropertyItem gradient_types[] = {
|
|
|
|
{WPAINT_GRADIENT_TYPE_LINEAR, "LINEAR", 0, "Linear", ""},
|
|
|
|
{WPAINT_GRADIENT_TYPE_RADIAL, "RADIAL", 0, "Radial", ""},
|
|
|
|
{0, NULL, 0, NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Weight Gradient";
|
|
|
|
ot->idname = "PAINT_OT_weight_gradient";
|
|
|
|
ot->description = "Sample a line and show it in Scope panels";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->invoke = paint_weight_gradient_invoke;
|
|
|
|
ot->modal = paint_weight_gradient_modal;
|
|
|
|
ot->exec = paint_weight_gradient_exec;
|
|
|
|
ot->poll = weight_paint_poll;
|
|
|
|
ot->cancel = WM_gesture_straightline_cancel;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
|
|
|
|
prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", "");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
|
|
|
|
WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
|
|
|
|
}
|