forked from bartvdbraak/blender
Project Paint: Add symmetry support
- Access from symmetry panel (as with sculpt) - Supports multiple axis at once. - Supports all brush types including clone.
This commit is contained in:
parent
43616918f3
commit
e2d60d180e
@ -1698,6 +1698,25 @@ class VIEW3D_PT_tools_imagepaint_external(Panel, View3DPaintPanel):
|
||||
col.operator("paint.project_image", text="Apply Camera Image")
|
||||
|
||||
|
||||
class VIEW3D_PT_tools_imagepaint_symmetry(Panel, View3DPaintPanel):
|
||||
bl_category = "Tools"
|
||||
bl_context = "imagepaint"
|
||||
bl_label = "Symmetry"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
toolsettings = context.tool_settings
|
||||
ipaint = toolsettings.image_paint
|
||||
|
||||
col = layout.column(align=True)
|
||||
row = col.row(align=True)
|
||||
row.prop(ipaint, "use_symmetry_x", text="X", toggle=True)
|
||||
row.prop(ipaint, "use_symmetry_y", text="Y", toggle=True)
|
||||
row.prop(ipaint, "use_symmetry_z", text="Z", toggle=True)
|
||||
|
||||
|
||||
class VIEW3D_PT_tools_projectpaint(View3DPaintPanel, Panel):
|
||||
bl_category = "Options"
|
||||
bl_context = "imagepaint"
|
||||
|
@ -219,6 +219,7 @@ void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], floa
|
||||
bool ED_view3d_win_to_segment(const struct ARegion *ar, struct View3D *v3d, const float mval[2],
|
||||
float r_ray_start[3], float r_ray_end[3], const bool do_clip);
|
||||
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]);
|
||||
void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d, float obmat[4][4], float pmat[4][4]);
|
||||
void ED_view3d_unproject(struct bglMats *mats, float out[3], const float x, const float y, const float z);
|
||||
|
||||
/* end */
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_math_bits.h"
|
||||
#include "BLI_math_color_blend.h"
|
||||
#include "BLI_memarena.h"
|
||||
#include "BLI_threads.h"
|
||||
@ -196,6 +197,29 @@ typedef struct ProjPaintImage {
|
||||
bool touch;
|
||||
} ProjPaintImage;
|
||||
|
||||
/**
|
||||
* Handle for stroke (operator customdata)
|
||||
*/
|
||||
typedef struct ProjStrokeHandle {
|
||||
/* Support for painting from multiple views at once,
|
||||
* currently used to impliment summetry painting,
|
||||
* we can assume at least the first is set while painting. */
|
||||
struct ProjPaintState *ps_views[8];
|
||||
int ps_views_tot;
|
||||
int symmetry_flags;
|
||||
|
||||
int orig_brush_size;
|
||||
|
||||
bool need_redraw;
|
||||
|
||||
/* trick to bypass regular paint and allow clone picking */
|
||||
bool is_clone_cursor_pick;
|
||||
|
||||
/* In ProjPaintState, only here for convenience */
|
||||
Scene *scene;
|
||||
Brush *brush;
|
||||
} ProjStrokeHandle;
|
||||
|
||||
/* Main projection painting struct passed to all projection painting functions */
|
||||
typedef struct ProjPaintState {
|
||||
View3D *v3d;
|
||||
@ -211,24 +235,14 @@ typedef struct ProjPaintState {
|
||||
|
||||
Brush *brush;
|
||||
short tool, blend, mode;
|
||||
int orig_brush_size;
|
||||
|
||||
float brush_size;
|
||||
Object *ob;
|
||||
/* for symmetry, we need to store modified object matrix */
|
||||
float obmat[4][4];
|
||||
float obmat_imat[4][4];
|
||||
/* end similarities with ImagePaintState */
|
||||
|
||||
DerivedMesh *dm;
|
||||
int dm_totface;
|
||||
int dm_totedge;
|
||||
int dm_totvert;
|
||||
int dm_release;
|
||||
|
||||
MVert *dm_mvert;
|
||||
MEdge *dm_medge;
|
||||
MFace *dm_mface;
|
||||
MTFace **dm_mtface;
|
||||
MTFace **dm_mtface_clone; /* other UV map, use for cloning between layers */
|
||||
MTFace *dm_mtface_stencil;
|
||||
|
||||
Image *stencil_ima;
|
||||
Image *canvas_ima;
|
||||
Image *clone_ima;
|
||||
@ -239,24 +253,16 @@ typedef struct ProjPaintState {
|
||||
LinkNode **bucketRect; /* screen sized 2D array, each pixel has a linked list of ProjPixel's */
|
||||
LinkNode **bucketFaces; /* bucketRect aligned array linkList of faces overlapping each bucket */
|
||||
unsigned char *bucketFlags; /* store if the bucks have been initialized */
|
||||
#ifndef PROJ_DEBUG_NOSEAMBLEED
|
||||
char *faceSeamFlags; /* store info about faces, if they are initialized etc*/
|
||||
char *faceWindingFlags; /* save the winding of the face in uv space, helps as an extra validation step for seam detection */
|
||||
float (*faceSeamUVs)[4][2]; /* expanded UVs for faces to use as seams */
|
||||
LinkNode **vertFaces; /* Only needed for when seam_bleed_px is enabled, use to find UV seams */
|
||||
#endif
|
||||
|
||||
char *vertFlags; /* store options per vert, now only store if the vert is pointing away from the view */
|
||||
int buckets_x; /* The size of the bucket grid, the grid span's screenMin/screenMax so you can paint outsize the screen or with 2 brushes at once */
|
||||
int buckets_y;
|
||||
|
||||
ProjPaintImage *projImages;
|
||||
|
||||
int pixel_sizeof; /* result of project_paint_pixel_sizeof(), constant per stroke */
|
||||
|
||||
int image_tot; /* size of projectImages array */
|
||||
|
||||
float (*screenCoords)[4]; /* verts projected into floating point screen space */
|
||||
float *cavities; /* cavity amount for vertices */
|
||||
float screenMin[2]; /* 2D bounds for mesh verts on the screen's plane (screenspace) */
|
||||
float screenMax[2];
|
||||
float screen_width; /* Calculated from screenMin & screenMax */
|
||||
@ -308,13 +314,51 @@ typedef struct ProjPaintState {
|
||||
int bucketMax[2];
|
||||
int context_bucket_x, context_bucket_y; /* must lock threads while accessing these */
|
||||
|
||||
/* redraw */
|
||||
bool need_redraw;
|
||||
|
||||
struct CurveMapping *cavity_curve;
|
||||
BlurKernel *blurkernel;
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Vars shared between multiple views (keep last) */
|
||||
/**
|
||||
* This data is owned by ``ProjStrokeHandle.ps_views[0]``,
|
||||
* all other views re-use the data.
|
||||
*/
|
||||
|
||||
#define PROJ_PAINT_STATE_SHARED_MEMCPY(ps_dst, ps_src) \
|
||||
MEMCPY_STRUCT_OFS(ps_dst, ps_src, is_shared_user)
|
||||
|
||||
#define PROJ_PAINT_STATE_SHARED_CLEAR(ps) \
|
||||
MEMSET_STRUCT_OFS(ps, 0, is_shared_user)
|
||||
|
||||
bool is_shared_user;
|
||||
|
||||
ProjPaintImage *projImages;
|
||||
float *cavities; /* cavity amount for vertices */
|
||||
|
||||
#ifndef PROJ_DEBUG_NOSEAMBLEED
|
||||
char *faceSeamFlags; /* store info about faces, if they are initialized etc*/
|
||||
char *faceWindingFlags; /* save the winding of the face in uv space, helps as an extra validation step for seam detection */
|
||||
float (*faceSeamUVs)[4][2]; /* expanded UVs for faces to use as seams */
|
||||
LinkNode **vertFaces; /* Only needed for when seam_bleed_px is enabled, use to find UV seams */
|
||||
#endif
|
||||
|
||||
SpinLock *tile_lock;
|
||||
|
||||
DerivedMesh *dm;
|
||||
int dm_totface;
|
||||
int dm_totedge;
|
||||
int dm_totvert;
|
||||
int dm_release;
|
||||
|
||||
MVert *dm_mvert;
|
||||
MEdge *dm_medge;
|
||||
MFace *dm_mface;
|
||||
MTFace *dm_mtface_stencil;
|
||||
|
||||
MTFace **dm_mtface;
|
||||
MTFace **dm_mtface_clone; /* other UV map, use for cloning between layers */
|
||||
} ProjPaintState;
|
||||
|
||||
typedef union pixelPointer {
|
||||
@ -3110,7 +3154,8 @@ static void proj_paint_state_non_cddm_init(ProjPaintState *ps)
|
||||
}
|
||||
}
|
||||
|
||||
static void proj_paint_state_viewport_init(ProjPaintState *ps)
|
||||
static void proj_paint_state_viewport_init(
|
||||
ProjPaintState *ps, const char symmetry_flag)
|
||||
{
|
||||
float mat[3][3];
|
||||
float viewmat[4][4];
|
||||
@ -3120,7 +3165,19 @@ static void proj_paint_state_viewport_init(ProjPaintState *ps)
|
||||
ps->viewDir[1] = 0.0f;
|
||||
ps->viewDir[2] = 1.0f;
|
||||
|
||||
invert_m4_m4(ps->ob->imat, ps->ob->obmat);
|
||||
copy_m4_m4(ps->obmat, ps->ob->obmat);
|
||||
|
||||
if (symmetry_flag) {
|
||||
int i;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if ((symmetry_flag >> i) & 1) {
|
||||
negate_v3(ps->obmat[i]);
|
||||
ps->is_flip_object = !ps->is_flip_object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
invert_m4_m4(ps->obmat_imat, ps->obmat);
|
||||
|
||||
if (ELEM(ps->source, PROJ_SRC_VIEW, PROJ_SRC_VIEW_FILL)) {
|
||||
/* normal drawing */
|
||||
@ -3130,7 +3187,7 @@ static void proj_paint_state_viewport_init(ProjPaintState *ps)
|
||||
copy_m4_m4(viewmat, ps->rv3d->viewmat);
|
||||
copy_m4_m4(viewinv, ps->rv3d->viewinv);
|
||||
|
||||
ED_view3d_ob_project_mat_get(ps->rv3d, ps->ob, ps->projectMat);
|
||||
ED_view3d_ob_project_mat_get_from_obmat(ps->rv3d, ps->obmat, ps->projectMat);
|
||||
|
||||
ps->is_ortho = ED_view3d_clip_range_get(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true);
|
||||
}
|
||||
@ -3183,16 +3240,15 @@ static void proj_paint_state_viewport_init(ProjPaintState *ps)
|
||||
}
|
||||
|
||||
/* same as #ED_view3d_ob_project_mat_get */
|
||||
mul_m4_m4m4(vmat, viewmat, ps->ob->obmat);
|
||||
mul_m4_m4m4(vmat, viewmat, ps->obmat);
|
||||
mul_m4_m4m4(ps->projectMat, winmat, vmat);
|
||||
}
|
||||
|
||||
|
||||
/* viewDir - object relative */
|
||||
invert_m4_m4(ps->ob->imat, ps->ob->obmat);
|
||||
copy_m3_m4(mat, viewinv);
|
||||
mul_m3_v3(mat, ps->viewDir);
|
||||
copy_m3_m4(mat, ps->ob->imat);
|
||||
copy_m3_m4(mat, ps->obmat_imat);
|
||||
mul_m3_v3(mat, ps->viewDir);
|
||||
normalize_v3(ps->viewDir);
|
||||
|
||||
@ -3202,9 +3258,9 @@ static void proj_paint_state_viewport_init(ProjPaintState *ps)
|
||||
|
||||
/* viewPos - object relative */
|
||||
copy_v3_v3(ps->viewPos, viewinv[3]);
|
||||
copy_m3_m4(mat, ps->ob->imat);
|
||||
copy_m3_m4(mat, ps->obmat_imat);
|
||||
mul_m3_v3(mat, ps->viewPos);
|
||||
add_v3_v3(ps->viewPos, ps->ob->imat[3]);
|
||||
add_v3_v3(ps->viewPos, ps->obmat_imat[3]);
|
||||
}
|
||||
|
||||
static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int diameter)
|
||||
@ -3351,12 +3407,14 @@ static void proj_paint_state_thread_init(ProjPaintState *ps, const bool reset_th
|
||||
if (reset_threads)
|
||||
ps->thread_tot = 1;
|
||||
|
||||
if (ps->is_shared_user == false) {
|
||||
if (ps->thread_tot > 1) {
|
||||
ps->tile_lock = MEM_mallocN(sizeof(SpinLock), "projpaint_tile_lock");
|
||||
BLI_spin_init(ps->tile_lock);
|
||||
}
|
||||
|
||||
image_undo_init_locks();
|
||||
}
|
||||
|
||||
for (a = 0; a < ps->thread_tot; a++) {
|
||||
ps->arena_mt[a] = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "project paint arena");
|
||||
@ -3714,7 +3772,8 @@ static void project_paint_prepare_all_faces(
|
||||
ProjPaintState *ps, MemArena *arena,
|
||||
const ProjPaintFaceLookup *face_lookup,
|
||||
ProjPaintLayerClone *layer_clone,
|
||||
MTFace *tf_base)
|
||||
MTFace *tf_base,
|
||||
const bool is_multi_view)
|
||||
{
|
||||
/* Image Vars - keep track of images we have used */
|
||||
LinkNode *image_LinkList = NULL;
|
||||
@ -3773,6 +3832,7 @@ static void project_paint_prepare_all_faces(
|
||||
ProjPaintFaceCoSS coSS;
|
||||
proj_paint_face_coSS_init(ps, mf, &coSS);
|
||||
|
||||
if (is_multi_view == false) {
|
||||
if (project_paint_flt_max_cull(ps, &coSS)) {
|
||||
continue;
|
||||
}
|
||||
@ -3784,10 +3844,10 @@ static void project_paint_prepare_all_faces(
|
||||
|
||||
#endif //PROJ_DEBUG_WINCLIP
|
||||
|
||||
|
||||
if (project_paint_backface_cull(ps, mf, &coSS)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (tpage_last != tpage) {
|
||||
|
||||
@ -3811,14 +3871,18 @@ static void project_paint_prepare_all_faces(
|
||||
}
|
||||
|
||||
/* build an array of images we use*/
|
||||
if (ps->is_shared_user == false) {
|
||||
project_paint_build_proj_ima(ps, arena, image_LinkList);
|
||||
}
|
||||
|
||||
/* we have built the array, discard the linked list */
|
||||
BLI_linklist_free(image_LinkList, NULL);
|
||||
}
|
||||
|
||||
/* run once per stroke before projection painting */
|
||||
static void project_paint_begin(ProjPaintState *ps)
|
||||
static void project_paint_begin(
|
||||
ProjPaintState *ps,
|
||||
const bool is_multi_view, const char symmetry_flag)
|
||||
{
|
||||
ProjPaintLayerClone layer_clone;
|
||||
ProjPaintFaceLookup face_lookup;
|
||||
@ -3839,9 +3903,11 @@ static void project_paint_begin(ProjPaintState *ps)
|
||||
ps->is_flip_object = (ps->ob->transflag & OB_NEG_SCALE) != 0;
|
||||
|
||||
/* paint onto the derived mesh */
|
||||
if (ps->is_shared_user == false) {
|
||||
if (!proj_paint_state_dm_init(ps)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
proj_paint_face_lookup_init(ps, &face_lookup);
|
||||
proj_paint_layer_clone_init(ps, &layer_clone);
|
||||
@ -3862,11 +3928,13 @@ static void project_paint_begin(ProjPaintState *ps)
|
||||
}
|
||||
|
||||
/* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
|
||||
if (ps->is_shared_user == false) {
|
||||
proj_paint_state_non_cddm_init(ps);
|
||||
|
||||
proj_paint_state_cavity_init(ps);
|
||||
}
|
||||
|
||||
proj_paint_state_viewport_init(ps);
|
||||
proj_paint_state_viewport_init(ps, symmetry_flag);
|
||||
|
||||
/* calculate vert screen coords
|
||||
* run this early so we can calculate the x/y resolution of our bucket rect */
|
||||
@ -3895,7 +3963,9 @@ static void project_paint_begin(ProjPaintState *ps)
|
||||
|
||||
ps->bucketFlags = MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
|
||||
#ifndef PROJ_DEBUG_NOSEAMBLEED
|
||||
if (ps->is_shared_user == false) {
|
||||
proj_paint_state_seam_bleed_init(ps);
|
||||
}
|
||||
#endif
|
||||
|
||||
proj_paint_state_thread_init(ps, reset_threads);
|
||||
@ -3903,7 +3973,7 @@ static void project_paint_begin(ProjPaintState *ps)
|
||||
|
||||
proj_paint_state_vert_flags_init(ps);
|
||||
|
||||
project_paint_prepare_all_faces(ps, arena, &face_lookup, &layer_clone, tf_base);
|
||||
project_paint_prepare_all_faces(ps, arena, &face_lookup, &layer_clone, tf_base, is_multi_view);
|
||||
}
|
||||
|
||||
static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
|
||||
@ -3912,7 +3982,7 @@ static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
|
||||
if (ps->tool == PAINT_TOOL_CLONE) {
|
||||
float projCo[4];
|
||||
copy_v3_v3(projCo, ED_view3d_cursor3d_get(ps->scene, ps->v3d));
|
||||
mul_m4_v3(ps->ob->imat, projCo);
|
||||
mul_m4_v3(ps->obmat_imat, projCo);
|
||||
|
||||
projCo[3] = 1.0f;
|
||||
mul_m4_v4(ps->projectMat, projCo);
|
||||
@ -3924,15 +3994,17 @@ static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
|
||||
static void project_paint_end(ProjPaintState *ps)
|
||||
{
|
||||
int a;
|
||||
ProjPaintImage *projIma;
|
||||
|
||||
image_undo_remove_masks();
|
||||
|
||||
/* dereference used image buffers */
|
||||
if (ps->is_shared_user == false) {
|
||||
ProjPaintImage *projIma;
|
||||
for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
|
||||
BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL);
|
||||
DAG_id_tag_update(&projIma->ima->id, 0);
|
||||
}
|
||||
}
|
||||
|
||||
BKE_image_release_ibuf(ps->reproject_image, ps->reproject_ibuf, NULL);
|
||||
|
||||
@ -3940,13 +4012,21 @@ static void project_paint_end(ProjPaintState *ps)
|
||||
MEM_freeN(ps->bucketRect);
|
||||
MEM_freeN(ps->bucketFaces);
|
||||
MEM_freeN(ps->bucketFlags);
|
||||
|
||||
if (ps->is_shared_user == false) {
|
||||
|
||||
/* must be set for non-shared */
|
||||
BLI_assert(ps->dm_mtface || ps->is_shared_user);
|
||||
if (ps->dm_mtface)
|
||||
MEM_freeN(ps->dm_mtface);
|
||||
|
||||
if (ps->do_layer_clone)
|
||||
MEM_freeN(ps->dm_mtface_clone);
|
||||
if (ps->thread_tot > 1) {
|
||||
BLI_spin_end(ps->tile_lock);
|
||||
MEM_freeN((void *)ps->tile_lock);
|
||||
}
|
||||
|
||||
image_undo_end_locks();
|
||||
|
||||
#ifndef PROJ_DEBUG_NOSEAMBLEED
|
||||
@ -3958,21 +4038,10 @@ static void project_paint_end(ProjPaintState *ps)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ps->blurkernel) {
|
||||
paint_delete_blur_kernel(ps->blurkernel);
|
||||
MEM_freeN(ps->blurkernel);
|
||||
}
|
||||
|
||||
if (ps->do_mask_cavity) {
|
||||
MEM_freeN(ps->cavities);
|
||||
}
|
||||
|
||||
if (ps->vertFlags) MEM_freeN(ps->vertFlags);
|
||||
|
||||
for (a = 0; a < ps->thread_tot; a++) {
|
||||
BLI_memarena_free(ps->arena_mt[a]);
|
||||
}
|
||||
|
||||
/* copy for subsurf/multires, so throw away */
|
||||
if (ps->dm->type != DM_TYPE_CDDM) {
|
||||
if (ps->dm_mvert) MEM_freeN(ps->dm_mvert);
|
||||
@ -3989,11 +4058,21 @@ static void project_paint_end(ProjPaintState *ps)
|
||||
ps->dm->release(ps->dm);
|
||||
}
|
||||
|
||||
if (ps->blurkernel) {
|
||||
paint_delete_blur_kernel(ps->blurkernel);
|
||||
MEM_freeN(ps->blurkernel);
|
||||
}
|
||||
|
||||
if (ps->vertFlags) MEM_freeN(ps->vertFlags);
|
||||
|
||||
for (a = 0; a < ps->thread_tot; a++) {
|
||||
BLI_memarena_free(ps->arena_mt[a]);
|
||||
}
|
||||
}
|
||||
|
||||
/* 1 = an undo, -1 is a redo. */
|
||||
static void partial_redraw_array_init(ImagePaintPartialRedraw *pr)
|
||||
static void partial_redraw_single_init(ImagePaintPartialRedraw *pr)
|
||||
{
|
||||
int tot = PROJ_BOUNDBOX_SQUARED;
|
||||
while (tot--) {
|
||||
pr->x1 = 10000000;
|
||||
pr->y1 = 10000000;
|
||||
|
||||
@ -4001,7 +4080,13 @@ static void partial_redraw_array_init(ImagePaintPartialRedraw *pr)
|
||||
pr->y2 = -1;
|
||||
|
||||
pr->enabled = 1;
|
||||
}
|
||||
|
||||
static void partial_redraw_array_init(ImagePaintPartialRedraw *pr)
|
||||
{
|
||||
int tot = PROJ_BOUNDBOX_SQUARED;
|
||||
while (tot--) {
|
||||
partial_redraw_single_init(pr);
|
||||
pr++;
|
||||
}
|
||||
}
|
||||
@ -4045,6 +4130,8 @@ static bool project_image_refresh_tagged(ProjPaintState *ps)
|
||||
imapaint_image_update(NULL, projIma->ima, projIma->ibuf, true);
|
||||
redraw = 1;
|
||||
}
|
||||
|
||||
partial_redraw_single_init(pr);
|
||||
}
|
||||
|
||||
projIma->touch = 0; /* clear for reuse */
|
||||
@ -4884,7 +4971,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
|
||||
}
|
||||
|
||||
ups->average_stroke_counter++;
|
||||
mul_m4_v3(ps->ob->obmat, world);
|
||||
mul_m4_v3(ps->obmat, world);
|
||||
add_v3_v3(ups->average_stroke_accum, world);
|
||||
ups->last_stroke_valid = true;
|
||||
}
|
||||
@ -4894,34 +4981,22 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
|
||||
}
|
||||
|
||||
|
||||
void paint_proj_stroke(const bContext *C, void *pps, const float prev_pos[2], const float pos[2], const bool eraser, float pressure, float distance, float size)
|
||||
static void paint_proj_stroke_ps(
|
||||
const bContext *UNUSED(C), void *ps_handle_p, const float prev_pos[2], const float pos[2],
|
||||
const bool eraser, float pressure, float distance, float size,
|
||||
/* extra view */
|
||||
ProjPaintState *ps
|
||||
)
|
||||
{
|
||||
ProjPaintState *ps = pps;
|
||||
ProjStrokeHandle *ps_handle = ps_handle_p;
|
||||
Brush *brush = ps->brush;
|
||||
Scene *scene = ps->scene;
|
||||
int a;
|
||||
|
||||
ps->brush_size = size;
|
||||
ps->blend = brush->blend;
|
||||
if (eraser)
|
||||
ps->blend = IMB_BLEND_ERASE_ALPHA;
|
||||
|
||||
/* clone gets special treatment here to avoid going through image initialization */
|
||||
if (ps->tool == PAINT_TOOL_CLONE && ps->mode == BRUSH_STROKE_INVERT) {
|
||||
View3D *v3d = ps->v3d;
|
||||
float *cursor = ED_view3d_cursor3d_get(scene, v3d);
|
||||
int mval_i[2] = {(int)pos[0], (int)pos[1]};
|
||||
|
||||
view3d_operator_needs_opengl(C);
|
||||
|
||||
if (!ED_view3d_autodist(scene, ps->ar, v3d, mval_i, cursor, false, NULL))
|
||||
return;
|
||||
|
||||
ED_region_tag_redraw(ps->ar);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* handle gradient and inverted stroke color here */
|
||||
if (ps->tool == PAINT_TOOL_DRAW) {
|
||||
paint_brush_color_get(scene, brush, false, ps->mode == BRUSH_STROKE_INVERT, distance, pressure, ps->paint_color, NULL);
|
||||
@ -4941,14 +5016,42 @@ void paint_proj_stroke(const bContext *C, void *pps, const float prev_pos[2], co
|
||||
}
|
||||
}
|
||||
|
||||
/* continue adding to existing partial redraw rects until redraw */
|
||||
if (!ps->need_redraw) {
|
||||
for (a = 0; a < ps->image_tot; a++)
|
||||
partial_redraw_array_init(ps->projImages[a].partRedrawRect);
|
||||
if (project_paint_op(ps, prev_pos, pos)) {
|
||||
ps_handle->need_redraw = true;
|
||||
project_image_refresh_tagged(ps);
|
||||
}
|
||||
}
|
||||
|
||||
if (project_paint_op(ps, prev_pos, pos))
|
||||
ps->need_redraw = true;
|
||||
|
||||
void paint_proj_stroke(
|
||||
const bContext *C, void *ps_handle_p, const float prev_pos[2], const float pos[2],
|
||||
const bool eraser, float pressure, float distance, float size)
|
||||
{
|
||||
int i;
|
||||
ProjStrokeHandle *ps_handle = ps_handle_p;
|
||||
|
||||
/* clone gets special treatment here to avoid going through image initialization */
|
||||
if (ps_handle->is_clone_cursor_pick) {
|
||||
Scene *scene = ps_handle->scene;
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
float *cursor = ED_view3d_cursor3d_get(scene, v3d);
|
||||
int mval_i[2] = {(int)pos[0], (int)pos[1]};
|
||||
|
||||
view3d_operator_needs_opengl(C);
|
||||
|
||||
if (!ED_view3d_autodist(scene, ar, v3d, mval_i, cursor, false, NULL))
|
||||
return;
|
||||
|
||||
ED_region_tag_redraw(ar);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < ps_handle->ps_views_tot; i++) {
|
||||
ProjPaintState *ps = ps_handle->ps_views[i];
|
||||
paint_proj_stroke_ps(C, ps_handle_p, prev_pos, pos, eraser, pressure, distance, size, ps);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5058,51 +5161,116 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
|
||||
|
||||
void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int mode)
|
||||
{
|
||||
ProjStrokeHandle *ps_handle;
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ToolSettings *settings = scene->toolsettings;
|
||||
int i;
|
||||
bool is_multi_view;
|
||||
char symmetry_flag_views[ARRAY_SIZE(ps_handle->ps_views)] = {0};
|
||||
|
||||
ps_handle = MEM_callocN(sizeof(ProjStrokeHandle), "ProjStrokeHandle");
|
||||
ps_handle->scene = scene;
|
||||
ps_handle->brush = BKE_paint_brush(&settings->imapaint.paint);
|
||||
|
||||
/* bypass regular stroke logic */
|
||||
if ((ps_handle->brush->imagepaint_tool == PAINT_TOOL_CLONE) &&
|
||||
(mode == BRUSH_STROKE_INVERT))
|
||||
{
|
||||
view3d_operator_needs_opengl(C);
|
||||
ps_handle->is_clone_cursor_pick = true;
|
||||
return ps_handle;
|
||||
}
|
||||
|
||||
ps_handle->orig_brush_size = BKE_brush_size_get(scene, ps_handle->brush);
|
||||
|
||||
ps_handle->symmetry_flags = settings->imapaint.paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
|
||||
ps_handle->ps_views_tot = 1 + (pow_i(2, count_bits_i(ps_handle->symmetry_flags)) - 1);
|
||||
is_multi_view = (ps_handle->ps_views_tot != 1);
|
||||
|
||||
for (i = 0; i < ps_handle->ps_views_tot; i++) {
|
||||
ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState");
|
||||
ps_handle->ps_views[i] = ps;
|
||||
}
|
||||
|
||||
if (ps_handle->symmetry_flags) {
|
||||
int index = 0;
|
||||
|
||||
int x = 0;
|
||||
do {
|
||||
int y = 0;
|
||||
do {
|
||||
int z = 0;
|
||||
do {
|
||||
symmetry_flag_views[index++] = (
|
||||
(x ? PAINT_SYMM_X : 0) |
|
||||
(y ? PAINT_SYMM_Y : 0) |
|
||||
(z ? PAINT_SYMM_Z : 0));
|
||||
BLI_assert(index <= ps_handle->ps_views_tot);
|
||||
} while ((z++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Z));
|
||||
} while ((y++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_Y));
|
||||
} while ((x++ == 0) && (ps_handle->symmetry_flags & PAINT_SYMM_X));
|
||||
BLI_assert(index == ps_handle->ps_views_tot);
|
||||
}
|
||||
|
||||
for (i = 0; i < ps_handle->ps_views_tot; i++) {
|
||||
ProjPaintState *ps = ps_handle->ps_views[i];
|
||||
|
||||
project_state_init(C, ob, ps, mode);
|
||||
|
||||
if (ps->tool == PAINT_TOOL_CLONE && mode == BRUSH_STROKE_INVERT) {
|
||||
view3d_operator_needs_opengl(C);
|
||||
return ps;
|
||||
}
|
||||
|
||||
paint_brush_init_tex(ps->brush);
|
||||
|
||||
ps->source = (ps->tool == PAINT_TOOL_FILL) ? PROJ_SRC_VIEW_FILL : PROJ_SRC_VIEW;
|
||||
|
||||
if (ps->ob == NULL || !(ps->ob->lay & ps->v3d->lay)) {
|
||||
MEM_freeN(ps);
|
||||
return NULL;
|
||||
ps_handle->ps_views_tot = i + 1;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
ps->orig_brush_size = BKE_brush_size_get(ps->scene, ps->brush);
|
||||
|
||||
/* Don't allow brush size below 2 */
|
||||
if (BKE_brush_size_get(ps->scene, ps->brush) < 2)
|
||||
BKE_brush_size_set(ps->scene, ps->brush, 2 * U.pixelsize);
|
||||
if (BKE_brush_size_get(scene, ps_handle->brush) < 2)
|
||||
BKE_brush_size_set(scene, ps_handle->brush, 2 * U.pixelsize);
|
||||
|
||||
/* allocate and initialize spatial data structures */
|
||||
project_paint_begin(ps);
|
||||
|
||||
if (ps->dm == NULL) {
|
||||
MEM_freeN(ps);
|
||||
return NULL;
|
||||
for (i = 0; i < ps_handle->ps_views_tot; i++) {
|
||||
ProjPaintState *ps = ps_handle->ps_views[i];
|
||||
|
||||
ps->source = (ps->tool == PAINT_TOOL_FILL) ? PROJ_SRC_VIEW_FILL : PROJ_SRC_VIEW;
|
||||
project_image_refresh_tagged(ps);
|
||||
|
||||
/* re-use! */
|
||||
if (i != 0) {
|
||||
ps->is_shared_user = true;
|
||||
PROJ_PAINT_STATE_SHARED_MEMCPY(ps, ps_handle->ps_views[0]);
|
||||
}
|
||||
|
||||
project_paint_begin(ps, is_multi_view, symmetry_flag_views[i]);
|
||||
|
||||
paint_proj_begin_clone(ps, mouse);
|
||||
|
||||
return ps;
|
||||
if (ps->dm == NULL) {
|
||||
goto fail;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void paint_proj_redraw(const bContext *C, void *pps, bool final)
|
||||
paint_brush_init_tex(ps_handle->brush);
|
||||
|
||||
return ps_handle;
|
||||
|
||||
|
||||
fail:
|
||||
for (i = 0; i < ps_handle->ps_views_tot; i++) {
|
||||
ProjPaintState *ps = ps_handle->ps_views[i];
|
||||
MEM_freeN(ps);
|
||||
}
|
||||
MEM_freeN(ps_handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void paint_proj_redraw(const bContext *C, void *ps_handle_p, bool final)
|
||||
{
|
||||
ProjPaintState *ps = pps;
|
||||
ProjStrokeHandle *ps_handle = ps_handle_p;
|
||||
|
||||
if (ps->need_redraw) {
|
||||
project_image_refresh_tagged(ps);
|
||||
|
||||
ps->need_redraw = false;
|
||||
if (ps_handle->need_redraw) {
|
||||
ps_handle->need_redraw = false;
|
||||
}
|
||||
else if (!final) {
|
||||
return;
|
||||
@ -5117,19 +5285,34 @@ void paint_proj_redraw(const bContext *C, void *pps, bool final)
|
||||
}
|
||||
}
|
||||
|
||||
void paint_proj_stroke_done(void *pps)
|
||||
void paint_proj_stroke_done(void *ps_handle_p)
|
||||
{
|
||||
ProjPaintState *ps = pps;
|
||||
if (ps->tool == PAINT_TOOL_CLONE && ps->mode == BRUSH_STROKE_INVERT) {
|
||||
MEM_freeN(ps);
|
||||
ProjStrokeHandle *ps_handle = ps_handle_p;
|
||||
Scene *scene = ps_handle->scene;
|
||||
int i;
|
||||
|
||||
if (ps_handle->is_clone_cursor_pick) {
|
||||
MEM_freeN(ps_handle);
|
||||
return;
|
||||
}
|
||||
BKE_brush_size_set(ps->scene, ps->brush, ps->orig_brush_size);
|
||||
|
||||
paint_brush_exit_tex(ps->brush);
|
||||
for (i = 1; i < ps_handle->ps_views_tot; i++) {
|
||||
PROJ_PAINT_STATE_SHARED_CLEAR(ps_handle->ps_views[i]);
|
||||
}
|
||||
|
||||
BKE_brush_size_set(scene, ps_handle->brush, ps_handle->orig_brush_size);
|
||||
|
||||
paint_brush_exit_tex(ps_handle->brush);
|
||||
|
||||
for (i = 0; i < ps_handle->ps_views_tot; i++) {
|
||||
ProjPaintState *ps;
|
||||
ps = ps_handle->ps_views[i];
|
||||
project_paint_end(ps);
|
||||
MEM_freeN(ps);
|
||||
|
||||
}
|
||||
|
||||
MEM_freeN(ps_handle);
|
||||
}
|
||||
/* use project paint to re-apply an image */
|
||||
static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
|
||||
@ -5209,7 +5392,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
|
||||
ED_image_undo_restore, ED_image_undo_free, NULL);
|
||||
|
||||
/* allocate and initialize spatial data structures */
|
||||
project_paint_begin(&ps);
|
||||
project_paint_begin(&ps, false, 0);
|
||||
|
||||
if (ps.dm == NULL) {
|
||||
BKE_brush_size_set(scene, ps.brush, orig_brush_size);
|
||||
|
@ -605,6 +605,14 @@ void ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, Object *ob, float pm
|
||||
mul_m4_m4m4(pmat, (float (*)[4])rv3d->winmat, vmat);
|
||||
}
|
||||
|
||||
void ED_view3d_ob_project_mat_get_from_obmat(const RegionView3D *rv3d, float obmat[4][4], float pmat[4][4])
|
||||
{
|
||||
float vmat[4][4];
|
||||
|
||||
mul_m4_m4m4(vmat, (float (*)[4])rv3d->viewmat, obmat);
|
||||
mul_m4_m4m4(pmat, (float (*)[4])rv3d->winmat, vmat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses window coordinates (x,y) and depth component z to find a point in
|
||||
* modelspace */
|
||||
|
Loading…
Reference in New Issue
Block a user