Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Eagar <joeedh@gmail.com>2009-08-26 14:27:04 +0400
committerJoseph Eagar <joeedh@gmail.com>2009-08-26 14:27:04 +0400
commitde7f08cc41c7087ecde096c89ee58f43ccb1cf91 (patch)
tree401ab2a2a7429c2caa63c3135341958155a86935 /source/blender/editors/sculpt_paint
parenta34ffefa0025d144826cd1bf7a136af743847f1b (diff)
parentd893b0f9ff5fc21277b9c24568e224961537c23c (diff)
merge with 2.5 at r22793
Diffstat (limited to 'source/blender/editors/sculpt_paint')
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c62
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h24
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c102
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c330
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c53
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c858
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c751
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_stroke.c274
8 files changed, 1277 insertions, 1177 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 1b33f340d5e..128455a8487 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -71,6 +71,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
+#include "BKE_paint.h"
#include "BKE_utildefines.h"
#include "BKE_DerivedMesh.h"
#include "BKE_report.h"
@@ -3706,7 +3707,7 @@ static void *do_projectpaint_thread(void *ph_v)
ProjPaintImage *last_projIma= NULL;
ImagePaintPartialRedraw *last_partial_redraw_cell;
- float rgba[4], alpha, dist_nosqrt;
+ float rgba[4], alpha, dist_nosqrt, dist;
float brush_size_sqared;
float falloff;
@@ -3720,6 +3721,7 @@ static void *do_projectpaint_thread(void *ph_v)
float co[2];
float mask = 1.0f; /* airbrush wont use mask */
unsigned short mask_short;
+ float size_half = ((float)ps->brush->size) * 0.5f;
LinkNode *smearPixels = NULL;
LinkNode *smearPixels_f = NULL;
@@ -3754,8 +3756,8 @@ static void *do_projectpaint_thread(void *ph_v)
dist_nosqrt = Vec2Lenf_nosqrt(projPixel->projCoSS, pos);
/*if (dist < s->brush->size) {*/ /* correct but uses a sqrtf */
- if (dist_nosqrt < brush_size_sqared) {
- falloff = brush_sample_falloff_noalpha(ps->brush, sqrtf(dist_nosqrt));
+ if (dist_nosqrt < brush_size_sqared && (dist=sqrtf(dist_nosqrt)) < size_half) {
+ falloff = brush_curve_strength(ps->brush, dist, size_half);
if (falloff > 0.0f) {
if (ps->is_texbrush) {
brush_sample_tex(ps->brush, projPixel->projCoSS, rgba);
@@ -4023,7 +4025,7 @@ static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, s
if(texpaint || (sima && sima->lock)) {
int w = imapaintpartial.x2 - imapaintpartial.x1;
int h = imapaintpartial.y2 - imapaintpartial.y1;
- GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h);
+ GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h, !texpaint);
}
}
@@ -4375,15 +4377,17 @@ static Brush *image_paint_brush(bContext *C)
Scene *scene= CTX_data_scene(C);
ToolSettings *settings= scene->toolsettings;
- return settings->imapaint.brush;
+ return paint_brush(&settings->imapaint.paint);
}
static int image_paint_poll(bContext *C)
{
+ Object *obact = CTX_data_active_object(C);
+
if(!image_paint_brush(C))
return 0;
- if((G.f & G_TEXTUREPAINT) && CTX_wm_region_view3d(C)) {
+ if((obact && obact->mode & OB_MODE_TEXTURE_PAINT) && CTX_wm_region_view3d(C)) {
return 1;
}
else {
@@ -4484,11 +4488,12 @@ static void paint_redraw(bContext *C, ImagePaintState *s, int final)
}
}
-static int paint_init(bContext *C, wmOperator *op)
+static int texture_paint_init(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
ToolSettings *settings= scene->toolsettings;
PaintOperation *pop;
+ Brush *brush;
pop= MEM_callocN(sizeof(PaintOperation), "PaintOperation");
pop->first= 1;
@@ -4516,10 +4521,11 @@ static int paint_init(bContext *C, wmOperator *op)
pop->ps.ar= CTX_wm_region(C);
/* intialize brush */
- if(!settings->imapaint.brush)
+ brush= paint_brush(&settings->imapaint.paint);
+ if(!brush)
return 0;
- pop->s.brush = settings->imapaint.brush;
+ pop->s.brush = brush;
pop->s.tool = settings->imapaint.tool;
if(pop->mode == PAINT_MODE_3D && (pop->s.tool == PAINT_TOOL_CLONE))
pop->s.tool = PAINT_TOOL_DRAW;
@@ -4607,11 +4613,13 @@ static int paint_init(bContext *C, wmOperator *op)
static void paint_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
{
PaintOperation *pop= op->customdata;
- float time;
+ float time, mousef[2];
float pressure;
int mouse[2], redraw;
- RNA_int_get_array(itemptr, "mouse", mouse);
+ RNA_float_get_array(itemptr, "mouse", mousef);
+ mouse[0] = mousef[0];
+ mouse[1] = mousef[1];
time= RNA_float_get(itemptr, "time");
pressure= RNA_float_get(itemptr, "pressure");
@@ -4670,7 +4678,7 @@ static void paint_exit(bContext *C, wmOperator *op)
static int paint_exec(bContext *C, wmOperator *op)
{
- if(!paint_init(C, op)) {
+ if(!texture_paint_init(C, op)) {
MEM_freeN(op->customdata);
return OPERATOR_CANCELLED;
}
@@ -4691,7 +4699,7 @@ static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event)
PaintOperation *pop= op->customdata;
wmTabletData *wmtab;
PointerRNA itemptr;
- float pressure;
+ float pressure, mousef[2];
double time;
int tablet, mouse[2];
@@ -4712,7 +4720,7 @@ static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event)
tablet= (wmtab->Active != EVT_TABLET_NONE);
pressure= wmtab->Pressure;
if(wmtab->Active == EVT_TABLET_ERASER)
- pop->s.blend= BRUSH_BLEND_ERASE_ALPHA;
+ pop->s.blend= IMB_BLEND_ERASE_ALPHA;
}
else
pressure= 1.0f;
@@ -4732,7 +4740,9 @@ static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event)
/* fill in stroke */
RNA_collection_add(op->ptr, "stroke", &itemptr);
- RNA_int_set_array(&itemptr, "mouse", mouse);
+ mousef[0] = mouse[0];
+ mousef[1] = mouse[1];
+ RNA_float_set_array(&itemptr, "mouse", mousef);
RNA_float_set(&itemptr, "time", (float)(time - pop->starttime));
RNA_float_set(&itemptr, "pressure", pressure);
@@ -4744,7 +4754,7 @@ static int paint_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
PaintOperation *pop;
- if(!paint_init(C, op)) {
+ if(!texture_paint_init(C, op)) {
MEM_freeN(op->customdata);
return OPERATOR_CANCELLED;
}
@@ -4872,7 +4882,7 @@ static int paint_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *eve
ToolSettings *ts = CTX_data_scene(C)->toolsettings;
get_imapaint_zoom(C, &zoom, &zoom);
toggle_paint_cursor(C, !ts->imapaint.paintcursor);
- brush_radial_control_invoke(op, ts->imapaint.brush, 0.5 * zoom);
+ brush_radial_control_invoke(op, paint_brush(&ts->imapaint.paint), 0.5 * zoom);
return WM_radial_control_invoke(C, op, event);
}
@@ -4891,7 +4901,7 @@ static int paint_radial_control_exec(bContext *C, wmOperator *op)
int ret;
char str[256];
get_imapaint_zoom(C, &zoom, &zoom);
- ret = brush_radial_control_exec(op, CTX_data_scene(C)->toolsettings->imapaint.brush, 2.0 / zoom);
+ ret = brush_radial_control_exec(op, paint_brush(&CTX_data_scene(C)->toolsettings->imapaint.paint), 2.0 / zoom);
WM_radial_control_string(op, str, 256);
return ret;
@@ -5144,13 +5154,13 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
me= get_mesh(ob);
- if(!(G.f & G_TEXTUREPAINT) && !me) {
+ if(!(ob->mode & OB_MODE_TEXTURE_PAINT) && !me) {
BKE_report(op->reports, RPT_ERROR, "Can only enter texture paint mode for mesh objects.");
return OPERATOR_CANCELLED;
}
- if(G.f & G_TEXTUREPAINT) {
- G.f &= ~G_TEXTUREPAINT;
+ if(ob->mode & OB_MODE_TEXTURE_PAINT) {
+ ob->mode &= ~OB_MODE_TEXTURE_PAINT;
if(U.glreslimit != 0)
GPU_free_images();
@@ -5159,13 +5169,13 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
toggle_paint_cursor(C, 0);
}
else {
- G.f |= G_TEXTUREPAINT;
+ ob->mode |= OB_MODE_TEXTURE_PAINT;
if(me->mtface==NULL)
me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT,
NULL, me->totface);
- brush_check_exists(&scene->toolsettings->imapaint.brush);
+ paint_init(&scene->toolsettings->imapaint.paint, PAINT_CURSOR_TEXTURE_PAINT);
if(U.glreslimit != 0)
GPU_free_images();
@@ -5200,13 +5210,13 @@ static int texture_paint_radial_control_invoke(bContext *C, wmOperator *op, wmEv
{
ToolSettings *ts = CTX_data_scene(C)->toolsettings;
toggle_paint_cursor(C, !ts->imapaint.paintcursor);
- brush_radial_control_invoke(op, ts->imapaint.brush, 0.5);
+ brush_radial_control_invoke(op, paint_brush(&ts->imapaint.paint), 0.5);
return WM_radial_control_invoke(C, op, event);
}
static int texture_paint_radial_control_exec(bContext *C, wmOperator *op)
{
- int ret = brush_radial_control_exec(op, CTX_data_scene(C)->toolsettings->imapaint.brush, 2);
+ int ret = brush_radial_control_exec(op, paint_brush(&CTX_data_scene(C)->toolsettings->imapaint.paint), 2);
char str[256];
WM_radial_control_string(op, str, 256);
@@ -5216,7 +5226,7 @@ static int texture_paint_radial_control_exec(bContext *C, wmOperator *op)
static int texture_paint_poll(bContext *C)
{
if(texture_paint_toggle_poll(C))
- if(G.f & G_TEXTUREPAINT)
+ if(CTX_data_active_object(C)->mode & OB_MODE_TEXTURE_PAINT)
return 1;
return 0;
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index b630975c934..ba1b57a1bef 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -29,14 +29,37 @@
#ifndef ED_PAINT_INTERN_H
#define ED_PAINT_INTERN_H
+struct bContext;
struct Scene;
struct Object;
struct Mesh;
+struct PaintStroke;
+struct PointerRNA;
struct ViewContext;
+struct wmEvent;
+struct wmOperator;
struct wmOperatorType;
struct ARegion;
+/* paint_stroke.c */
+typedef int (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
+typedef void (*StrokeUpdateStep)(struct bContext *C, struct PaintStroke *stroke, struct PointerRNA *itemptr);
+typedef void (*StrokeDone)(struct bContext *C, struct PaintStroke *stroke);
+
+struct PaintStroke *paint_stroke_new(bContext *C, StrokeTestStart test_start,
+ StrokeUpdateStep update_step, StrokeDone done);
+int paint_stroke_modal(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
+int paint_stroke_exec(struct bContext *C, struct wmOperator *op);
+struct ViewContext *paint_stroke_view_context(struct PaintStroke *stroke);
+void *paint_stroke_mode_data(struct PaintStroke *stroke);
+void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data);
+int paint_poll(bContext *C);
+void paint_cursor_start(struct bContext *C, int (*poll)(struct bContext *C));
+
/* paint_vertex.c */
+int vertex_paint_mode_poll(bContext *C);
+void clear_vpaint(Scene *scene, int selected);
+
void PAINT_OT_weight_paint_toggle(struct wmOperatorType *ot);
void PAINT_OT_weight_paint_radial_control(struct wmOperatorType *ot);
void PAINT_OT_weight_paint(struct wmOperatorType *ot);
@@ -59,6 +82,7 @@ int imapaint_pick_face(struct ViewContext *vc, struct Mesh *me, int *mval, unsig
void imapaint_pick_uv(struct Scene *scene, struct Object *ob, struct Mesh *mesh, unsigned int faceindex, int *xy, float *uv);
void paint_sample_color(struct Scene *scene, struct ARegion *ar, int x, int y);
+void BRUSH_OT_curve_preset(struct wmOperatorType *ot);
#endif /* ED_PAINT_INTERN_H */
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index e9263ddabf0..c38b36007e9 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -1,15 +1,116 @@
+/**
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "DNA_brush_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_paint.h"
#include "ED_sculpt.h"
+#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
#include "paint_intern.h"
+#include <string.h>
+
+/* Brush operators */
+static int brush_add_exec(bContext *C, wmOperator *op)
+{
+ /*int type = RNA_enum_get(op->ptr, "type");*/
+ Brush *br = NULL;
+
+ br = add_brush("Brush");
+
+ if(br)
+ paint_brush_set(paint_get_active(CTX_data_scene(C)), br);
+
+ return OPERATOR_FINISHED;
+}
+
+static EnumPropertyItem brush_type_items[] = {
+ {OB_MODE_SCULPT, "SCULPT", ICON_SCULPTMODE_HLT, "Sculpt", ""},
+ {OB_MODE_VERTEX_PAINT, "VERTEX_PAINT", ICON_VPAINT_HLT, "Vertex Paint", ""},
+ {OB_MODE_WEIGHT_PAINT, "WEIGHT_PAINT", ICON_WPAINT_HLT, "Weight Paint", ""},
+ {OB_MODE_TEXTURE_PAINT, "TEXTURE_PAINT", ICON_TPAINT_HLT, "Texture Paint", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+void BRUSH_OT_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Brush";
+ ot->idname= "BRUSH_OT_add";
+
+ /* api callbacks */
+ ot->exec= brush_add_exec;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "type", brush_type_items, OB_MODE_VERTEX_PAINT, "Type", "Which paint mode to create the brush for.");
+}
+
+static int vertex_color_set_exec(bContext *C, wmOperator *op)
+{
+ int selected = RNA_boolean_get(op->ptr, "selected");
+ Scene *scene = CTX_data_scene(C);
+
+ clear_vpaint(scene, selected);
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_vertex_color_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Set Vertex Colors";
+ ot->idname= "PAINT_OT_vertex_color_set";
+
+ /* api callbacks */
+ ot->exec= vertex_color_set_exec;
+ ot->poll= vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "selected", 0, "Type", "Only color selected faces.");
+}
+
/**************************** registration **********************************/
void ED_operatortypes_paint(void)
{
+ /* brush */
+ WM_operatortype_append(BRUSH_OT_add);
+ WM_operatortype_append(BRUSH_OT_curve_preset);
+
/* image */
WM_operatortype_append(PAINT_OT_texture_paint_toggle);
WM_operatortype_append(PAINT_OT_texture_paint_radial_control);
@@ -28,5 +129,6 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_vertex_paint_radial_control);
WM_operatortype_append(PAINT_OT_vertex_paint_toggle);
WM_operatortype_append(PAINT_OT_vertex_paint);
+ WM_operatortype_append(PAINT_OT_vertex_color_set);
}
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
new file mode 100644
index 00000000000..bd9ea50e0f8
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -0,0 +1,330 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2009 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "RNA_access.h"
+
+#include "BKE_context.h"
+#include "BKE_paint.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "BLI_arithb.h"
+
+#include "PIL_time.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "paint_intern.h"
+
+#include <float.h>
+#include <math.h>
+
+typedef struct PaintStroke {
+ void *mode_data;
+ void *smooth_stroke_cursor;
+ wmTimer *timer;
+
+ /* Cached values */
+ ViewContext vc;
+ bglMats mats;
+ Brush *brush;
+
+ float last_mouse_position[2];
+
+ /* Set whether any stroke step has yet occured
+ e.g. in sculpt mode, stroke doesn't start until cursor
+ passes over the mesh */
+ int stroke_started;
+
+ StrokeTestStart test_start;
+ StrokeUpdateStep update_step;
+ StrokeDone done;
+} PaintStroke;
+
+/*** Cursor ***/
+static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata)
+{
+ Brush *brush = paint_brush(paint_get_active(CTX_data_scene(C)));
+ PaintStroke *stroke = customdata;
+
+ glColor4ubv(paint_get_active(CTX_data_scene(C))->paint_cursor_col);
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+
+ if(stroke && brush && (brush->flag & BRUSH_SMOOTH_STROKE)) {
+ ARegion *ar = CTX_wm_region(C);
+ sdrawline(x, y, (int)stroke->last_mouse_position[0] - ar->winrct.xmin,
+ (int)stroke->last_mouse_position[1] - ar->winrct.ymin);
+ }
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+}
+
+static void paint_draw_cursor(bContext *C, int x, int y, void *customdata)
+{
+ Brush *brush = paint_brush(paint_get_active(CTX_data_scene(C)));
+
+ glColor4ubv(paint_get_active(CTX_data_scene(C))->paint_cursor_col);
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+
+ glTranslatef((float)x, (float)y, 0.0f);
+ glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size, 40);
+ glTranslatef((float)-x, (float)-y, 0.0f);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+}
+
+/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
+static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse[2])
+{
+ PointerRNA itemptr;
+ float cur_depth, pressure = 1;
+ float center[3];
+ PaintStroke *stroke = op->customdata;
+
+ cur_depth = read_cached_depth(&stroke->vc, mouse[0], mouse[1]);
+ view3d_unproject(&stroke->mats, center, mouse[0], mouse[1], cur_depth);
+
+ /* Tablet */
+ if(event->custom == EVT_DATA_TABLET) {
+ wmTabletData *wmtab= event->customdata;
+ if(wmtab->Active != EVT_TABLET_NONE)
+ pressure= wmtab->Pressure;
+ }
+
+ /* Add to stroke */
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+ RNA_float_set_array(&itemptr, "location", center);
+ RNA_float_set_array(&itemptr, "mouse", mouse);
+ RNA_boolean_set(&itemptr, "flip", event->shift);
+ RNA_float_set(&itemptr, "pressure", pressure);
+
+ stroke->last_mouse_position[0] = mouse[0];
+ stroke->last_mouse_position[1] = mouse[1];
+
+ stroke->update_step(C, stroke, &itemptr);
+}
+
+/* Returns zero if no sculpt changes should be made, non-zero otherwise */
+static int paint_smooth_stroke(PaintStroke *stroke, float output[2], wmEvent *event)
+{
+ output[0] = event->x;
+ output[1] = event->y;
+
+ if(stroke->brush->flag & BRUSH_SMOOTH_STROKE && stroke->brush->sculpt_tool != SCULPT_TOOL_GRAB) {
+ float u = stroke->brush->smooth_stroke_factor, v = 1.0 - u;
+ float dx = stroke->last_mouse_position[0] - event->x, dy = stroke->last_mouse_position[1] - event->y;
+
+ /* If the mouse is moving within the radius of the last move,
+ don't update the mouse position. This allows sharp turns. */
+ if(dx*dx + dy*dy < stroke->brush->smooth_stroke_radius * stroke->brush->smooth_stroke_radius)
+ return 0;
+
+ output[0] = event->x * v + stroke->last_mouse_position[0] * u;
+ output[1] = event->y * v + stroke->last_mouse_position[1] * u;
+ }
+
+ return 1;
+}
+
+/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
+static int paint_space_stroke_enabled(Brush *br)
+{
+ return (br->flag & BRUSH_SPACE) && !(br->flag & BRUSH_ANCHORED) && (br->sculpt_tool != SCULPT_TOOL_GRAB);
+}
+
+/* For brushes with stroke spacing enabled, moves mouse in steps
+ towards the final mouse location. */
+static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const float final_mouse[2])
+{
+ PaintStroke *stroke = op->customdata;
+ int cnt = 0;
+
+ if(paint_space_stroke_enabled(stroke->brush)) {
+ float mouse[2] = {stroke->last_mouse_position[0], stroke->last_mouse_position[1]};
+ float vec[2] = {final_mouse[0] - mouse[0], final_mouse[1] - mouse[1]};
+ float length, scale;
+ int steps = 0, i;
+
+ /* Normalize the vector between the last stroke dot and the goal */
+ length = sqrt(vec[0]*vec[0] + vec[1]*vec[1]);
+
+ if(length > FLT_EPSILON) {
+ scale = stroke->brush->spacing / length;
+ vec[0] *= scale;
+ vec[1] *= scale;
+
+ steps = (int)(length / stroke->brush->spacing);
+ for(i = 0; i < steps; ++i, ++cnt) {
+ mouse[0] += vec[0];
+ mouse[1] += vec[1];
+ paint_brush_stroke_add_step(C, op, event, mouse);
+ }
+ }
+ }
+
+ return cnt;
+}
+
+/**** Public API ****/
+
+PaintStroke *paint_stroke_new(bContext *C, StrokeTestStart test_start,
+ StrokeUpdateStep update_step, StrokeDone done)
+{
+ PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
+
+ stroke->brush = paint_brush(paint_get_active(CTX_data_scene(C)));
+ view3d_set_viewcontext(C, &stroke->vc);
+ view3d_get_transformation(&stroke->vc, stroke->vc.obact, &stroke->mats);
+
+ stroke->test_start = test_start;
+ stroke->update_step = update_step;
+ stroke->done = done;
+
+ return stroke;
+}
+
+int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ PaintStroke *stroke = op->customdata;
+ float mouse[2];
+
+ if(event->type == TIMER && (event->customdata != stroke->timer))
+ return OPERATOR_RUNNING_MODAL;
+
+ if(!stroke->stroke_started) {
+ stroke->last_mouse_position[0] = event->x;
+ stroke->last_mouse_position[1] = event->y;
+ stroke->stroke_started = stroke->test_start(C, op, event);
+
+ if(stroke->stroke_started) {
+ stroke->smooth_stroke_cursor =
+ WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_smooth_stroke, stroke);
+
+ if(stroke->brush->flag & BRUSH_AIRBRUSH)
+ stroke->timer = WM_event_add_window_timer(CTX_wm_window(C), TIMER, stroke->brush->rate);
+ }
+
+ ED_region_tag_redraw(ar);
+ }
+
+ if(stroke->stroke_started) {
+ if(paint_smooth_stroke(stroke, mouse, event)) {
+ if(paint_space_stroke_enabled(stroke->brush)) {
+ if(!paint_space_stroke(C, op, event, mouse))
+ ED_region_tag_redraw(ar);
+ }
+ else
+ paint_brush_stroke_add_step(C, op, event, mouse);
+ }
+ else
+ ED_region_tag_redraw(ar);
+ }
+
+ /* TODO: fix hardcoded event here */
+ if(event->type == LEFTMOUSE && event->val == 0) {
+ /* Exit stroke, free data */
+
+ if(stroke->smooth_stroke_cursor)
+ WM_paint_cursor_end(CTX_wm_manager(C), stroke->smooth_stroke_cursor);
+
+ if(stroke->timer)
+ WM_event_remove_window_timer(CTX_wm_window(C), stroke->timer);
+
+ stroke->done(C, stroke);
+ MEM_freeN(stroke);
+ return OPERATOR_FINISHED;
+ }
+ else
+ return OPERATOR_RUNNING_MODAL;
+}
+
+int paint_stroke_exec(bContext *C, wmOperator *op)
+{
+ PaintStroke *stroke = op->customdata;
+
+ RNA_BEGIN(op->ptr, itemptr, "stroke") {
+ stroke->update_step(C, stroke, &itemptr);
+ }
+ RNA_END;
+
+ MEM_freeN(stroke);
+ op->customdata = NULL;
+
+ return OPERATOR_FINISHED;
+}
+
+ViewContext *paint_stroke_view_context(PaintStroke *stroke)
+{
+ return &stroke->vc;
+}
+
+void *paint_stroke_mode_data(struct PaintStroke *stroke)
+{
+ return stroke->mode_data;
+}
+
+void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data)
+{
+ stroke->mode_data = mode_data;
+}
+
+int paint_poll(bContext *C)
+{
+ Paint *p = paint_get_active(CTX_data_scene(C));
+ Object *ob = CTX_data_active_object(C);
+
+ return p && ob && paint_brush(p) &&
+ CTX_wm_area(C)->spacetype == SPACE_VIEW3D &&
+ CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW;
+}
+
+void paint_cursor_start(bContext *C, int (*poll)(bContext *C))
+{
+ Paint *p = paint_get_active(CTX_data_scene(C));
+
+ if(p && !p->paint_cursor)
+ p->paint_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), poll, paint_draw_cursor, NULL);
+}
+
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 46d41c043bd..68c5232e249 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -5,21 +5,31 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
+
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
+#include "RNA_access.h"
+#include "RNA_define.h"
+
#include "BLI_arithb.h"
#include "BKE_brush.h"
+#include "BKE_context.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
+#include "BKE_paint.h"
+
#include "BKE_utildefines.h"
#include "BIF_gl.h"
#include "ED_view3d.h"
+#include "WM_api.h"
+#include "WM_types.h"
+
#include "paint_intern.h"
/* 3D Paint */
@@ -160,7 +170,7 @@ int imapaint_pick_face(ViewContext *vc, Mesh *me, int *mval, unsigned int *index
/* used for both 3d view and image window */
void paint_sample_color(Scene *scene, ARegion *ar, int x, int y) /* frontbuf */
{
- Brush **br = current_brush_source(scene);
+ Brush *br = paint_brush(paint_get_active(scene));
unsigned int col;
char *cp;
@@ -173,10 +183,43 @@ void paint_sample_color(Scene *scene, ARegion *ar, int x, int y) /* frontbuf */
cp = (char *)&col;
- if(br && *br) {
- (*br)->rgb[0]= cp[0]/255.0f;
- (*br)->rgb[1]= cp[1]/255.0f;
- (*br)->rgb[2]= cp[2]/255.0f;
+ if(br) {
+ br->rgb[0]= cp[0]/255.0f;
+ br->rgb[1]= cp[1]/255.0f;
+ br->rgb[2]= cp[2]/255.0f;
}
}
+static int brush_curve_preset_exec(bContext *C, wmOperator *op)
+{
+ Brush *br = paint_brush(paint_get_active(CTX_data_scene(C)));
+ brush_curve_preset(br, RNA_enum_get(op->ptr, "shape"));
+
+ return OPERATOR_FINISHED;
+}
+
+static int brush_curve_preset_poll(bContext *C)
+{
+ Brush *br = paint_brush(paint_get_active(CTX_data_scene(C)));
+
+ return br && br->curve;
+}
+
+void BRUSH_OT_curve_preset(wmOperatorType *ot)
+{
+ static EnumPropertyItem prop_shape_items[] = {
+ {BRUSH_PRESET_SHARP, "SHARP", 0, "Sharp", ""},
+ {BRUSH_PRESET_SMOOTH, "SMOOTH", 0, "Smooth", ""},
+ {BRUSH_PRESET_MAX, "MAX", 0, "Max", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ ot->name= "Preset";
+ ot->idname= "BRUSH_OT_curve_preset";
+
+ ot->exec= brush_curve_preset_exec;
+ ot->poll= brush_curve_preset_poll;
+
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "shape", prop_shape_items, BRUSH_PRESET_SHARP, "Mode", "");
+}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 812c41f430e..ee3d9e5baa1 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -62,6 +62,7 @@
#include "DNA_userdef_types.h"
#include "RNA_access.h"
+#include "RNA_define.h"
#include "BKE_armature.h"
#include "BKE_brush.h"
@@ -76,6 +77,7 @@
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
+#include "BKE_paint.h"
#include "BKE_utildefines.h"
#include "WM_api.h"
@@ -90,6 +92,8 @@
#include "ED_util.h"
#include "ED_view3d.h"
+#include "paint_intern.h"
+
/* vp->mode */
#define VP_MIX 0
#define VP_ADD 1
@@ -106,9 +110,19 @@ static void error() {}
/* polling - retrieve whether cursor should be set or operator should be done */
+
+/* Returns true if vertex paint mode is active */
+int vertex_paint_mode_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ return ob && ob->mode == OB_MODE_VERTEX_PAINT;
+}
+
static int vp_poll(bContext *C)
{
- if(G.f & G_VERTEXPAINT) {
+ if(vertex_paint_mode_poll(C) &&
+ paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) {
ScrArea *sa= CTX_wm_area(C);
if(sa->spacetype==SPACE_VIEW3D) {
ARegion *ar= CTX_wm_region(C);
@@ -121,7 +135,10 @@ static int vp_poll(bContext *C)
static int wp_poll(bContext *C)
{
- if(G.f & G_WEIGHTPAINT) {
+ Object *ob = CTX_data_active_object(C);
+
+ if(ob && ob->mode & OB_MODE_WEIGHT_PAINT &&
+ paint_brush(&CTX_data_tool_settings(C)->wpaint->paint)) {
ScrArea *sa= CTX_wm_area(C);
if(sa->spacetype==SPACE_VIEW3D) {
ARegion *ar= CTX_wm_region(C);
@@ -132,56 +149,6 @@ static int wp_poll(bContext *C)
return 0;
}
-
-/* Cursors */
-static void vp_drawcursor(bContext *C, int x, int y, void *customdata)
-{
- ToolSettings *ts= CTX_data_tool_settings(C);
-
- glTranslatef((float)x, (float)y, 0.0f);
-
- glColor4ub(255, 255, 255, 128);
- glEnable( GL_LINE_SMOOTH );
- glEnable(GL_BLEND);
- glutil_draw_lined_arc(0.0, M_PI*2.0, ts->vpaint->brush->size, 40);
- glDisable(GL_BLEND);
- glDisable( GL_LINE_SMOOTH );
-
- glTranslatef((float)-x, (float)-y, 0.0f);
-}
-
-static void wp_drawcursor(bContext *C, int x, int y, void *customdata)
-{
- ToolSettings *ts= CTX_data_tool_settings(C);
-
- glTranslatef((float)x, (float)y, 0.0f);
-
- glColor4ub(200, 200, 255, 128);
- glEnable( GL_LINE_SMOOTH );
- glEnable(GL_BLEND);
- glutil_draw_lined_arc(0.0, M_PI*2.0, ts->wpaint->brush->size, 40);
- glDisable(GL_BLEND);
- glDisable( GL_LINE_SMOOTH );
-
- glTranslatef((float)-x, (float)-y, 0.0f);
-}
-
-static void toggle_paint_cursor(bContext *C, int wpaint)
-{
- ToolSettings *ts = CTX_data_scene(C)->toolsettings;
- VPaint *vp = wpaint ? ts->wpaint : ts->vpaint;
-
- if(vp->paintcursor) {
- WM_paint_cursor_end(CTX_wm_manager(C), vp->paintcursor);
- vp->paintcursor = NULL;
- }
- else {
- vp->paintcursor = wpaint ?
- WM_paint_cursor_activate(CTX_wm_manager(C), wp_poll, wp_drawcursor, NULL) :
- WM_paint_cursor_activate(CTX_wm_manager(C), vp_poll, vp_drawcursor, NULL);
- }
-}
-
static VPaint *new_vpaint(int wpaint)
{
VPaint *vp= MEM_callocN(sizeof(VPaint), "VPaint");
@@ -232,7 +199,8 @@ unsigned int rgba_to_mcol(float r, float g, float b, float a)
static unsigned int vpaint_get_current_col(VPaint *vp)
{
- return rgba_to_mcol(vp->brush->rgb[0], vp->brush->rgb[1], vp->brush->rgb[2], 1.0f);
+ Brush *brush = paint_brush(&vp->paint);
+ return rgba_to_mcol(brush->rgb[0], brush->rgb[1], brush->rgb[2], 1.0f);
}
void do_shared_vertexcol(Mesh *me)
@@ -362,34 +330,7 @@ static void copy_wpaint_prev (VPaint *wp, MDeformVert *dverts, int dcount)
}
-void clear_vpaint(Scene *scene)
-{
- Mesh *me;
- Object *ob;
- unsigned int *to, paintcol;
- int a;
-
- if((G.f & G_VERTEXPAINT)==0) return;
-
- ob= OBACT;
- me= get_mesh(ob);
- if(!ob || ob->id.lib) return;
-
- if(me==0 || me->mcol==0 || me->totface==0) return;
-
- paintcol= vpaint_get_current_col(scene->toolsettings->vpaint);
-
- to= (unsigned int *)me->mcol;
- a= 4*me->totface;
- while(a--) {
- *to= paintcol;
- to++;
- }
- DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-
-}
-
-void clear_vpaint_selectedfaces(Scene *scene)
+void clear_vpaint(Scene *scene, int selected)
{
Mesh *me;
MFace *mf;
@@ -409,7 +350,7 @@ void clear_vpaint_selectedfaces(Scene *scene)
mf = me->mface;
mcol = (unsigned int*)me->mcol;
for (i = 0; i < me->totface; i++, mf++, mcol+=4) {
- if (mf->flag & ME_FACE_SEL) {
+ if (!selected || mf->flag & ME_FACE_SEL) {
mcol[0] = paintcol;
mcol[1] = paintcol;
mcol[2] = paintcol;
@@ -540,10 +481,10 @@ void vpaint_dogamma(Scene *scene)
int a, temp;
unsigned char *cp, gamtab[256];
- if((G.f & G_VERTEXPAINT)==0) return;
-
ob= OBACT;
me= get_mesh(ob);
+
+ if(!(ob->mode & OB_MODE_VERTEX_PAINT)) return;
if(me==0 || me->mcol==0 || me->totface==0) return;
igam= 1.0/vp->gamma;
@@ -721,6 +662,7 @@ static unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fac)
static void vpaint_blend(VPaint *vp, unsigned int *col, unsigned int *colorig, unsigned int paintcol, int alpha)
{
+ Brush *brush = paint_brush(&vp->paint);
if(vp->mode==VP_MIX || vp->mode==VP_BLUR) *col= mcol_blend( *col, paintcol, alpha);
else if(vp->mode==VP_ADD) *col= mcol_add( *col, paintcol, alpha);
@@ -734,7 +676,7 @@ static void vpaint_blend(VPaint *vp, unsigned int *col, unsigned int *colorig, u
unsigned int testcol=0, a;
char *cp, *ct, *co;
- alpha= (int)(255.0*vp->brush->alpha);
+ alpha= (int)(255.0*brush->alpha);
if(vp->mode==VP_MIX || vp->mode==VP_BLUR) testcol= mcol_blend( *colorig, paintcol, alpha);
else if(vp->mode==VP_ADD) testcol= mcol_add( *colorig, paintcol, alpha);
@@ -798,8 +740,9 @@ static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x
return tot;
}
-static int calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, float vpimat[][3], float *vert_nor, short *mval)
+static int calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, float vpimat[][3], float *vert_nor, float *mval)
{
+ Brush *brush = paint_brush(&vp->paint);
float fac, dx, dy;
int alpha;
short vertco[2];
@@ -810,14 +753,14 @@ static int calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, float vpimat[][3], floa
dy= mval[1]-vertco[1];
fac= sqrt(dx*dx + dy*dy);
- if(fac > vp->brush->size) return 0;
+ if(fac > brush->size) return 0;
if(vp->flag & VP_HARD)
alpha= 255;
else
- alpha= 255.0*vp->brush->alpha*(1.0-fac/vp->brush->size);
+ alpha= 255.0*brush->alpha*(1.0-fac/brush->size);
}
else {
- alpha= 255.0*vp->brush->alpha;
+ alpha= 255.0*brush->alpha;
}
if(vp->flag & VP_NORMALS) {
@@ -839,6 +782,7 @@ static int calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, float vpimat[][3], floa
static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float alpha, float paintval)
{
+ Brush *brush = paint_brush(&wp->paint);
if(dw==NULL || uw==NULL) return;
@@ -864,7 +808,7 @@ static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float
if((wp->flag & VP_SPRAY)==0) {
float testw=0.0f;
- alpha= wp->brush->alpha;
+ alpha= brush->alpha;
if(wp->mode==VP_MIX || wp->mode==VP_BLUR)
testw = paintval*alpha + uw->weight*(1.0-alpha);
else if(wp->mode==VP_ADD)
@@ -1092,12 +1036,12 @@ static int set_wpaint(bContext *C, wmOperator *op) /* toggle */
if(me && me->totface>=MAXINDEX) {
error("Maximum number of faces: %d", MAXINDEX-1);
- G.f &= ~G_WEIGHTPAINT;
+ ob->mode &= ~OB_MODE_WEIGHT_PAINT;
return OPERATOR_CANCELLED;
}
- if(G.f & G_WEIGHTPAINT) G.f &= ~G_WEIGHTPAINT;
- else G.f |= G_WEIGHTPAINT;
+ if(ob->mode & OB_MODE_WEIGHT_PAINT) ob->mode &= ~OB_MODE_WEIGHT_PAINT;
+ else ob->mode |= OB_MODE_WEIGHT_PAINT;
/* Weightpaint works by overriding colors in mesh,
@@ -1107,21 +1051,20 @@ static int set_wpaint(bContext *C, wmOperator *op) /* toggle */
*/
DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
- if(G.f & G_WEIGHTPAINT) {
+ if(ob->mode & OB_MODE_WEIGHT_PAINT) {
Object *par;
if(wp==NULL)
wp= scene->toolsettings->wpaint= new_vpaint(1);
- brush_check_exists(&wp->brush);
-
- toggle_paint_cursor(C, 1);
+ paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT);
+ paint_cursor_start(C, wp_poll);
mesh_octree_table(ob, NULL, NULL, 's');
/* verify if active weight group is also active bone */
par= modifiers_isDeformedByArmature(ob);
- if(par && (par->flag & OB_POSEMODE)) {
+ if(par && (par->mode & OB_MODE_POSE)) {
bPoseChannel *pchan;
for(pchan= par->pose->chanbase.first; pchan; pchan= pchan->next)
if(pchan->bone->flag & BONE_ACTIVE)
@@ -1131,9 +1074,6 @@ static int set_wpaint(bContext *C, wmOperator *op) /* toggle */
}
}
else {
- if(wp)
- toggle_paint_cursor(C, 1);
-
mesh_octree_table(ob, NULL, NULL, 'e');
}
@@ -1174,8 +1114,12 @@ void PAINT_OT_weight_paint_toggle(wmOperatorType *ot)
static int vpaint_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
- toggle_paint_cursor(C, 0);
- brush_radial_control_invoke(op, CTX_data_scene(C)->toolsettings->vpaint->brush, 1);
+ Paint *p = paint_get_active(CTX_data_scene(C));
+ Brush *brush = paint_brush(p);
+
+ WM_paint_cursor_end(CTX_wm_manager(C), p->paint_cursor);
+ p->paint_cursor = NULL;
+ brush_radial_control_invoke(op, brush, 1);
return WM_radial_control_invoke(C, op, event);
}
@@ -1183,19 +1127,24 @@ static int vpaint_radial_control_modal(bContext *C, wmOperator *op, wmEvent *eve
{
int ret = WM_radial_control_modal(C, op, event);
if(ret != OPERATOR_RUNNING_MODAL)
- toggle_paint_cursor(C, 0);
+ paint_cursor_start(C, vp_poll);
return ret;
}
static int vpaint_radial_control_exec(bContext *C, wmOperator *op)
{
- return brush_radial_control_exec(op, CTX_data_scene(C)->toolsettings->vpaint->brush, 1);
+ Brush *brush = paint_brush(&CTX_data_scene(C)->toolsettings->vpaint->paint);
+ return brush_radial_control_exec(op, brush, 1);
}
static int wpaint_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
- toggle_paint_cursor(C, 1);
- brush_radial_control_invoke(op, CTX_data_scene(C)->toolsettings->wpaint->brush, 1);
+ Paint *p = paint_get_active(CTX_data_scene(C));
+ Brush *brush = paint_brush(p);
+
+ WM_paint_cursor_end(CTX_wm_manager(C), p->paint_cursor);
+ p->paint_cursor = NULL;
+ brush_radial_control_invoke(op, brush, 1);
return WM_radial_control_invoke(C, op, event);
}
@@ -1203,13 +1152,14 @@ static int wpaint_radial_control_modal(bContext *C, wmOperator *op, wmEvent *eve
{
int ret = WM_radial_control_modal(C, op, event);
if(ret != OPERATOR_RUNNING_MODAL)
- toggle_paint_cursor(C, 1);
+ paint_cursor_start(C, wp_poll);
return ret;
}
static int wpaint_radial_control_exec(bContext *C, wmOperator *op)
{
- return brush_radial_control_exec(op, CTX_data_scene(C)->toolsettings->wpaint->brush, 1);
+ Brush *brush = paint_brush(&CTX_data_scene(C)->toolsettings->wpaint->paint);
+ return brush_radial_control_exec(op, brush, 1);
}
void PAINT_OT_weight_paint_radial_control(wmOperatorType *ot)
@@ -1254,206 +1204,10 @@ struct WPaintData {
float wpimat[3][3];
};
-static void wpaint_exit(bContext *C, wmOperator *op)
-{
- ToolSettings *ts= CTX_data_tool_settings(C);
- Object *ob= CTX_data_active_object(C);
- struct WPaintData *wpd= op->customdata;
-
- if(wpd->vertexcosnos)
- MEM_freeN(wpd->vertexcosnos);
- MEM_freeN(wpd->indexar);
-
- /* frees prev buffer */
- copy_wpaint_prev(ts->wpaint, NULL, 0);
-
- /* and particles too */
- if(ob->particlesystem.first) {
- ParticleSystem *psys;
- int i;
-
- for(psys= ob->particlesystem.first; psys; psys= psys->next) {
- for(i=0; i<PSYS_TOT_VG; i++) {
- if(psys->vgroup[i]==ob->actdef) {
- psys->recalc |= PSYS_RECALC_RESET;
- break;
- }
- }
- }
- }
-
- DAG_object_flush_update(CTX_data_scene(C), ob, OB_RECALC_DATA);
-
- MEM_freeN(wpd);
- op->customdata= NULL;
-}
-
-
-static int wpaint_modal(bContext *C, wmOperator *op, wmEvent *event)
-{
- ToolSettings *ts= CTX_data_tool_settings(C);
- VPaint *wp= ts->wpaint;
-
- switch(event->type) {
- case LEFTMOUSE:
- if(event->val==0) { /* release */
- wpaint_exit(C, op);
- return OPERATOR_FINISHED;
- }
- /* pass on, first press gets painted too */
-
- case MOUSEMOVE:
- {
- struct WPaintData *wpd= op->customdata;
- ViewContext *vc= &wpd->vc;
- Object *ob= vc->obact;
- Mesh *me= ob->data;
- float mat[4][4];
- float paintweight= ts->vgroup_weight;
- int *indexar= wpd->indexar;
- int totindex, index, alpha, totw;
- short mval[2];
-
- view3d_operator_needs_opengl(C);
-
- /* load projection matrix */
- wmMultMatrix(ob->obmat);
- wmGetSingleMatrix(mat);
- wmLoadMatrix(wpd->vc.rv3d->viewmat);
-
- MTC_Mat4SwapMat4(wpd->vc.rv3d->persmat, mat);
-
- mval[0]= event->x - vc->ar->winrct.xmin;
- mval[1]= event->y - vc->ar->winrct.ymin;
-
- /* which faces are involved */
- if(wp->flag & VP_AREA) {
- totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], wp->brush->size);
- }
- else {
- indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
- if(indexar[0]) totindex= 1;
- else totindex= 0;
- }
-
- if(wp->flag & VP_COLINDEX) {
- for(index=0; index<totindex; index++) {
- if(indexar[index] && indexar[index]<=me->totface) {
- MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
-
- if(mface->mat_nr!=ob->actcol-1) {
- indexar[index]= 0;
- }
- }
- }
- }
-
- if((G.f & G_FACESELECT) && me->mface) {
- for(index=0; index<totindex; index++) {
- if(indexar[index] && indexar[index]<=me->totface) {
- MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
-
- if((mface->flag & ME_FACE_SEL)==0) {
- indexar[index]= 0;
- }
- }
- }
- }
-
- /* make sure each vertex gets treated only once */
- /* and calculate filter weight */
- totw= 0;
- if(wp->mode==VP_BLUR)
- paintweight= 0.0f;
- else
- paintweight= ts->vgroup_weight;
-
- for(index=0; index<totindex; index++) {
- if(indexar[index] && indexar[index]<=me->totface) {
- MFace *mface= me->mface + (indexar[index]-1);
-
- (me->dvert+mface->v1)->flag= 1;
- (me->dvert+mface->v2)->flag= 1;
- (me->dvert+mface->v3)->flag= 1;
- if(mface->v4) (me->dvert+mface->v4)->flag= 1;
-
- if(wp->mode==VP_BLUR) {
- MDeformWeight *dw, *(*dw_func)(MDeformVert *, int) = verify_defweight;
-
- if(wp->flag & VP_ONLYVGROUP)
- dw_func= get_defweight;
-
- dw= dw_func(me->dvert+mface->v1, ob->actdef-1);
- if(dw) {paintweight+= dw->weight; totw++;}
- dw= dw_func(me->dvert+mface->v2, ob->actdef-1);
- if(dw) {paintweight+= dw->weight; totw++;}
- dw= dw_func(me->dvert+mface->v3, ob->actdef-1);
- if(dw) {paintweight+= dw->weight; totw++;}
- if(mface->v4) {
- dw= dw_func(me->dvert+mface->v4, ob->actdef-1);
- if(dw) {paintweight+= dw->weight; totw++;}
- }
- }
- }
- }
-
- if(wp->mode==VP_BLUR)
- paintweight/= (float)totw;
-
- for(index=0; index<totindex; index++) {
-
- if(indexar[index] && indexar[index]<=me->totface) {
- MFace *mface= me->mface + (indexar[index]-1);
-
- if((me->dvert+mface->v1)->flag) {
- alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v1, mval);
- if(alpha) {
- do_weight_paint_vertex(wp, ob, mface->v1, alpha, paintweight, wpd->vgroup_mirror);
- }
- (me->dvert+mface->v1)->flag= 0;
- }
-
- if((me->dvert+mface->v2)->flag) {
- alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v2, mval);
- if(alpha) {
- do_weight_paint_vertex(wp, ob, mface->v2, alpha, paintweight, wpd->vgroup_mirror);
- }
- (me->dvert+mface->v2)->flag= 0;
- }
-
- if((me->dvert+mface->v3)->flag) {
- alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v3, mval);
- if(alpha) {
- do_weight_paint_vertex(wp, ob, mface->v3, alpha, paintweight, wpd->vgroup_mirror);
- }
- (me->dvert+mface->v3)->flag= 0;
- }
-
- if((me->dvert+mface->v4)->flag) {
- if(mface->v4) {
- alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v4, mval);
- if(alpha) {
- do_weight_paint_vertex(wp, ob, mface->v4, alpha, paintweight, wpd->vgroup_mirror);
- }
- (me->dvert+mface->v4)->flag= 0;
- }
- }
- }
- }
-
- MTC_Mat4SwapMat4(vc->rv3d->persmat, mat);
-
- DAG_object_flush_update(vc->scene, ob, OB_RECALC_DATA);
- ED_region_tag_redraw(vc->ar);
- }
- }
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *event)
{
Scene *scene= CTX_data_scene(C);
+ struct PaintStroke *stroke = op->customdata;
ToolSettings *ts= CTX_data_tool_settings(C);
VPaint *wp= ts->wpaint;
Object *ob= CTX_data_active_object(C);
@@ -1462,7 +1216,6 @@ static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
float mat[4][4], imat[4][4];
if(scene->obedit) return OPERATOR_CANCELLED;
- // XXX if(multires_level1_test()) return;
me= get_mesh(ob);
if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH;
@@ -1471,8 +1224,9 @@ static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
if (!me->dvert)
create_dverts(&me->id);
- /* make customdata storage */
- op->customdata= wpd= MEM_callocN(sizeof(struct WPaintData), "WPaintData");
+ /* make mode data storage */
+ wpd= MEM_callocN(sizeof(struct WPaintData), "WPaintData");
+ paint_stroke_set_mode_data(stroke, wpd);
view3d_set_viewcontext(C, &wpd->vc);
wpd->vgroup_mirror= -1;
@@ -1544,11 +1298,203 @@ static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
}
- /* do paint once for click only paint */
- wpaint_modal(C, op, event);
+ return 1;
+}
+
+static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
+{
+ ToolSettings *ts= CTX_data_tool_settings(C);
+ VPaint *wp= ts->wpaint;
+ Brush *brush = paint_brush(&wp->paint);
+ struct WPaintData *wpd= paint_stroke_mode_data(stroke);
+ ViewContext *vc= &wpd->vc;
+ Object *ob= vc->obact;
+ Mesh *me= ob->data;
+ float mat[4][4];
+ float paintweight= ts->vgroup_weight;
+ int *indexar= wpd->indexar;
+ int totindex, index, alpha, totw;
+ float mval[2];
+
+ view3d_operator_needs_opengl(C);
+
+ /* load projection matrix */
+ wmMultMatrix(ob->obmat);
+ wmGetSingleMatrix(mat);
+ wmLoadMatrix(wpd->vc.rv3d->viewmat);
+
+ RNA_float_get_array(itemptr, "mouse", mval);
+ mval[0]-= vc->ar->winrct.xmin;
+ mval[1]-= vc->ar->winrct.ymin;
+
+ MTC_Mat4SwapMat4(wpd->vc.rv3d->persmat, mat);
+
+ /* which faces are involved */
+ if(wp->flag & VP_AREA) {
+ totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush->size);
+ }
+ else {
+ indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
+ if(indexar[0]) totindex= 1;
+ else totindex= 0;
+ }
+
+ if(wp->flag & VP_COLINDEX) {
+ for(index=0; index<totindex; index++) {
+ if(indexar[index] && indexar[index]<=me->totface) {
+ MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
+
+ if(mface->mat_nr!=ob->actcol-1) {
+ indexar[index]= 0;
+ }
+ }
+ }
+ }
+
+ if((G.f & G_FACESELECT) && me->mface) {
+ for(index=0; index<totindex; index++) {
+ if(indexar[index] && indexar[index]<=me->totface) {
+ MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
+
+ if((mface->flag & ME_FACE_SEL)==0) {
+ indexar[index]= 0;
+ }
+ }
+ }
+ }
+
+ /* make sure each vertex gets treated only once */
+ /* and calculate filter weight */
+ totw= 0;
+ if(wp->mode==VP_BLUR)
+ paintweight= 0.0f;
+ else
+ paintweight= ts->vgroup_weight;
+
+ for(index=0; index<totindex; index++) {
+ if(indexar[index] && indexar[index]<=me->totface) {
+ MFace *mface= me->mface + (indexar[index]-1);
+
+ (me->dvert+mface->v1)->flag= 1;
+ (me->dvert+mface->v2)->flag= 1;
+ (me->dvert+mface->v3)->flag= 1;
+ if(mface->v4) (me->dvert+mface->v4)->flag= 1;
+
+ if(wp->mode==VP_BLUR) {
+ MDeformWeight *dw, *(*dw_func)(MDeformVert *, int) = verify_defweight;
+
+ if(wp->flag & VP_ONLYVGROUP)
+ dw_func= get_defweight;
+
+ dw= dw_func(me->dvert+mface->v1, ob->actdef-1);
+ if(dw) {paintweight+= dw->weight; totw++;}
+ dw= dw_func(me->dvert+mface->v2, ob->actdef-1);
+ if(dw) {paintweight+= dw->weight; totw++;}
+ dw= dw_func(me->dvert+mface->v3, ob->actdef-1);
+ if(dw) {paintweight+= dw->weight; totw++;}
+ if(mface->v4) {
+ dw= dw_func(me->dvert+mface->v4, ob->actdef-1);
+ if(dw) {paintweight+= dw->weight; totw++;}
+ }
+ }
+ }
+ }
+
+ if(wp->mode==VP_BLUR)
+ paintweight/= (float)totw;
+
+ for(index=0; index<totindex; index++) {
+
+ if(indexar[index] && indexar[index]<=me->totface) {
+ MFace *mface= me->mface + (indexar[index]-1);
+
+ if((me->dvert+mface->v1)->flag) {
+ alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v1, mval);
+ if(alpha) {
+ do_weight_paint_vertex(wp, ob, mface->v1, alpha, paintweight, wpd->vgroup_mirror);
+ }
+ (me->dvert+mface->v1)->flag= 0;
+ }
+
+ if((me->dvert+mface->v2)->flag) {
+ alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v2, mval);
+ if(alpha) {
+ do_weight_paint_vertex(wp, ob, mface->v2, alpha, paintweight, wpd->vgroup_mirror);
+ }
+ (me->dvert+mface->v2)->flag= 0;
+ }
+
+ if((me->dvert+mface->v3)->flag) {
+ alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v3, mval);
+ if(alpha) {
+ do_weight_paint_vertex(wp, ob, mface->v3, alpha, paintweight, wpd->vgroup_mirror);
+ }
+ (me->dvert+mface->v3)->flag= 0;
+ }
+
+ if((me->dvert+mface->v4)->flag) {
+ if(mface->v4) {
+ alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v4, mval);
+ if(alpha) {
+ do_weight_paint_vertex(wp, ob, mface->v4, alpha, paintweight, wpd->vgroup_mirror);
+ }
+ (me->dvert+mface->v4)->flag= 0;
+ }
+ }
+ }
+ }
+
+ MTC_Mat4SwapMat4(vc->rv3d->persmat, mat);
+
+ DAG_object_flush_update(vc->scene, ob, OB_RECALC_DATA);
+ ED_region_tag_redraw(vc->ar);
+}
+
+static void wpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
+{
+ ToolSettings *ts= CTX_data_tool_settings(C);
+ Object *ob= CTX_data_active_object(C);
+ struct WPaintData *wpd= paint_stroke_mode_data(stroke);
+
+ if(wpd->vertexcosnos)
+ MEM_freeN(wpd->vertexcosnos);
+ MEM_freeN(wpd->indexar);
+
+ /* frees prev buffer */
+ copy_wpaint_prev(ts->wpaint, NULL, 0);
+
+ /* and particles too */
+ if(ob->particlesystem.first) {
+ ParticleSystem *psys;
+ int i;
+
+ for(psys= ob->particlesystem.first; psys; psys= psys->next) {
+ for(i=0; i<PSYS_TOT_VG; i++) {
+ if(psys->vgroup[i]==ob->actdef) {
+ psys->recalc |= PSYS_RECALC_RESET;
+ break;
+ }
+ }
+ }
+ }
+
+ DAG_object_flush_update(CTX_data_scene(C), ob, OB_RECALC_DATA);
+
+ MEM_freeN(wpd);
+}
+
+
+static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+
+ op->customdata = paint_stroke_new(C, wpaint_stroke_test_start,
+ wpaint_stroke_update_step,
+ wpaint_stroke_done);
/* add modal handler */
WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
+
+ op->type->modal(C, op, event);
return OPERATOR_RUNNING_MODAL;
}
@@ -1562,13 +1508,14 @@ void PAINT_OT_weight_paint(wmOperatorType *ot)
/* api callbacks */
ot->invoke= wpaint_invoke;
- ot->modal= wpaint_modal;
+ ot->modal= paint_stroke_modal;
/* ot->exec= vpaint_exec; <-- needs stroke property */
ot->poll= wp_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
-
+
+ RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
}
/* ************ set / clear vertex paint mode ********** */
@@ -1584,40 +1531,35 @@ static int set_vpaint(bContext *C, wmOperator *op) /* toggle */
me= get_mesh(ob);
if(me==NULL || object_data_is_libdata(ob)) {
- G.f &= ~G_VERTEXPAINT;
+ ob->mode &= ~OB_MODE_VERTEX_PAINT;
return OPERATOR_PASS_THROUGH;
}
if(me && me->totface>=MAXINDEX) {
error("Maximum number of faces: %d", MAXINDEX-1);
- G.f &= ~G_VERTEXPAINT;
+ ob->mode &= ~OB_MODE_VERTEX_PAINT;
return OPERATOR_FINISHED;
}
if(me && me->mcol==NULL) make_vertexcol(scene, 0);
/* toggle: end vpaint */
- if(G.f & G_VERTEXPAINT) {
+ if(ob->mode & OB_MODE_VERTEX_PAINT) {
- G.f &= ~G_VERTEXPAINT;
-
- if(vp) {
- toggle_paint_cursor(C, 0);
- vp->paintcursor= NULL;
- }
+ ob->mode &= ~OB_MODE_VERTEX_PAINT;
}
else {
-
- G.f |= G_VERTEXPAINT;
+ ob->mode |= OB_MODE_VERTEX_PAINT;
/* Turn off weight painting */
- if (G.f & G_WEIGHTPAINT)
+ if (ob->mode & OB_MODE_WEIGHT_PAINT)
set_wpaint(C, op);
if(vp==NULL)
vp= scene->toolsettings->vpaint= new_vpaint(0);
- toggle_paint_cursor(C, 0);
- brush_check_exists(&scene->toolsettings->vpaint->brush);
+ paint_cursor_start(C, vp_poll);
+
+ paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT);
}
if (me)
@@ -1676,177 +1618,175 @@ struct VPaintData {
float vpimat[3][3];
};
-static void vpaint_exit(bContext *C, wmOperator *op)
+static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *event)
{
ToolSettings *ts= CTX_data_tool_settings(C);
- struct VPaintData *vpd= op->customdata;
+ struct PaintStroke *stroke = op->customdata;
+ VPaint *vp= ts->vpaint;
+ struct VPaintData *vpd;
+ Object *ob= CTX_data_active_object(C);
+ Mesh *me;
+ float mat[4][4], imat[4][4];
+
+ /* context checks could be a poll() */
+ me= get_mesh(ob);
+ if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH;
- if(vpd->vertexcosnos)
- MEM_freeN(vpd->vertexcosnos);
- MEM_freeN(vpd->indexar);
+ if(me->mcol==NULL) make_vertexcol(CTX_data_scene(C), 0);
+ if(me->mcol==NULL) return OPERATOR_CANCELLED;
- /* frees prev buffer */
- copy_vpaint_prev(ts->vpaint, NULL, 0);
+ /* make mode data storage */
+ vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData");
+ paint_stroke_set_mode_data(stroke, vpd);
+ view3d_set_viewcontext(C, &vpd->vc);
- MEM_freeN(vpd);
- op->customdata= NULL;
+ vpd->vertexcosnos= mesh_get_mapped_verts_nors(vpd->vc.scene, ob);
+ vpd->indexar= get_indexarray();
+ vpd->paintcol= vpaint_get_current_col(vp);
+
+ /* for filtering */
+ copy_vpaint_prev(vp, (unsigned int *)me->mcol, me->totface);
+
+ /* some old cruft to sort out later */
+ Mat4MulMat4(mat, ob->obmat, vpd->vc.rv3d->viewmat);
+ Mat4Invert(imat, mat);
+ Mat3CpyMat4(vpd->vpimat, imat);
+
+ return 1;
}
-static int vpaint_modal(bContext *C, wmOperator *op, wmEvent *event)
+static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
ToolSettings *ts= CTX_data_tool_settings(C);
+ struct VPaintData *vpd = paint_stroke_mode_data(stroke);
VPaint *vp= ts->vpaint;
-
- switch(event->type) {
- case LEFTMOUSE:
- if(event->val==0) { /* release */
- vpaint_exit(C, op);
- return OPERATOR_FINISHED;
- }
- /* pass on, first press gets painted too */
-
- case MOUSEMOVE:
- {
- struct VPaintData *vpd= op->customdata;
- ViewContext *vc= &vpd->vc;
- Object *ob= vc->obact;
- Mesh *me= ob->data;
- float mat[4][4];
- int *indexar= vpd->indexar;
- int totindex, index;
- short mval[2];
+ Brush *brush = paint_brush(&vp->paint);
+ ViewContext *vc= &vpd->vc;
+ Object *ob= vc->obact;
+ Mesh *me= ob->data;
+ float mat[4][4];
+ int *indexar= vpd->indexar;
+ int totindex, index;
+ float mval[2];
+
+ RNA_float_get_array(itemptr, "mouse", mval);
- view3d_operator_needs_opengl(C);
+ view3d_operator_needs_opengl(C);
- /* load projection matrix */
- wmMultMatrix(ob->obmat);
- wmGetSingleMatrix(mat);
- wmLoadMatrix(vc->rv3d->viewmat);
+ /* load projection matrix */
+ wmMultMatrix(ob->obmat);
+ wmGetSingleMatrix(mat);
+ wmLoadMatrix(vc->rv3d->viewmat);
+
+ mval[0]-= vc->ar->winrct.xmin;
+ mval[1]-= vc->ar->winrct.ymin;
+
- mval[0]= event->x - vc->ar->winrct.xmin;
- mval[1]= event->y - vc->ar->winrct.ymin;
-
- /* which faces are involved */
- if(vp->flag & VP_AREA) {
- totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], vp->brush->size);
- }
- else {
- indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
- if(indexar[0]) totindex= 1;
- else totindex= 0;
- }
+ /* which faces are involved */
+ if(vp->flag & VP_AREA) {
+ totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush->size);
+ }
+ else {
+ indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
+ if(indexar[0]) totindex= 1;
+ else totindex= 0;
+ }
- MTC_Mat4SwapMat4(vc->rv3d->persmat, mat);
+ MTC_Mat4SwapMat4(vc->rv3d->persmat, mat);
- if(vp->flag & VP_COLINDEX) {
- for(index=0; index<totindex; index++) {
- if(indexar[index] && indexar[index]<=me->totface) {
- MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
+ if(vp->flag & VP_COLINDEX) {
+ for(index=0; index<totindex; index++) {
+ if(indexar[index] && indexar[index]<=me->totface) {
+ MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
- if(mface->mat_nr!=ob->actcol-1) {
- indexar[index]= 0;
- }
- }
+ if(mface->mat_nr!=ob->actcol-1) {
+ indexar[index]= 0;
}
- }
- if((G.f & G_FACESELECT) && me->mface) {
- for(index=0; index<totindex; index++) {
- if(indexar[index] && indexar[index]<=me->totface) {
- MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
+ }
+ }
+ }
+ if((G.f & G_FACESELECT) && me->mface) {
+ for(index=0; index<totindex; index++) {
+ if(indexar[index] && indexar[index]<=me->totface) {
+ MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
- if((mface->flag & ME_FACE_SEL)==0)
- indexar[index]= 0;
- }
- }
- }
+ if((mface->flag & ME_FACE_SEL)==0)
+ indexar[index]= 0;
+ }
+ }
+ }
- for(index=0; index<totindex; index++) {
+ for(index=0; index<totindex; index++) {
- if(indexar[index] && indexar[index]<=me->totface) {
- MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
- unsigned int *mcol= ( (unsigned int *)me->mcol) + 4*(indexar[index]-1);
- unsigned int *mcolorig= ( (unsigned int *)vp->vpaint_prev) + 4*(indexar[index]-1);
- int alpha;
+ if(indexar[index] && indexar[index]<=me->totface) {
+ MFace *mface= ((MFace *)me->mface) + (indexar[index]-1);
+ unsigned int *mcol= ( (unsigned int *)me->mcol) + 4*(indexar[index]-1);
+ unsigned int *mcolorig= ( (unsigned int *)vp->vpaint_prev) + 4*(indexar[index]-1);
+ int alpha;
- if(vp->mode==VP_BLUR) {
- unsigned int fcol1= mcol_blend( mcol[0], mcol[1], 128);
- if(mface->v4) {
- unsigned int fcol2= mcol_blend( mcol[2], mcol[3], 128);
- vpd->paintcol= mcol_blend( fcol1, fcol2, 128);
- }
- else {
- vpd->paintcol= mcol_blend( mcol[2], fcol1, 170);
- }
+ if(vp->mode==VP_BLUR) {
+ unsigned int fcol1= mcol_blend( mcol[0], mcol[1], 128);
+ if(mface->v4) {
+ unsigned int fcol2= mcol_blend( mcol[2], mcol[3], 128);
+ vpd->paintcol= mcol_blend( fcol1, fcol2, 128);
+ }
+ else {
+ vpd->paintcol= mcol_blend( mcol[2], fcol1, 170);
+ }
- }
+ }
- alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v1, mval);
- if(alpha) vpaint_blend(vp, mcol, mcolorig, vpd->paintcol, alpha);
+ alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v1, mval);
+ if(alpha) vpaint_blend(vp, mcol, mcolorig, vpd->paintcol, alpha);
- alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v2, mval);
- if(alpha) vpaint_blend(vp, mcol+1, mcolorig+1, vpd->paintcol, alpha);
+ alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v2, mval);
+ if(alpha) vpaint_blend(vp, mcol+1, mcolorig+1, vpd->paintcol, alpha);
- alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v3, mval);
- if(alpha) vpaint_blend(vp, mcol+2, mcolorig+2, vpd->paintcol, alpha);
+ alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v3, mval);
+ if(alpha) vpaint_blend(vp, mcol+2, mcolorig+2, vpd->paintcol, alpha);
- if(mface->v4) {
- alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v4, mval);
- if(alpha) vpaint_blend(vp, mcol+3, mcolorig+3, vpd->paintcol, alpha);
- }
- }
+ if(mface->v4) {
+ alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v4, mval);
+ if(alpha) vpaint_blend(vp, mcol+3, mcolorig+3, vpd->paintcol, alpha);
}
+ }
+ }
- MTC_Mat4SwapMat4(vc->rv3d->persmat, mat);
+ MTC_Mat4SwapMat4(vc->rv3d->persmat, mat);
- do_shared_vertexcol(me);
+ do_shared_vertexcol(me);
- ED_region_tag_redraw(vc->ar);
+ ED_region_tag_redraw(vc->ar);
- DAG_object_flush_update(vc->scene, ob, OB_RECALC_DATA);
- }
- break;
- }
-
- return OPERATOR_RUNNING_MODAL;
+ DAG_object_flush_update(vc->scene, ob, OB_RECALC_DATA);
}
-static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
{
ToolSettings *ts= CTX_data_tool_settings(C);
- VPaint *vp= ts->vpaint;
- struct VPaintData *vpd;
- Object *ob= CTX_data_active_object(C);
- Mesh *me;
- float mat[4][4], imat[4][4];
+ struct VPaintData *vpd= paint_stroke_mode_data(stroke);
- /* context checks could be a poll() */
- me= get_mesh(ob);
- if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH;
-
- if(me->mcol==NULL) make_vertexcol(CTX_data_scene(C), 0);
- if(me->mcol==NULL) return OPERATOR_CANCELLED;
-
- /* make customdata storage */
- op->customdata= vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData");
- view3d_set_viewcontext(C, &vpd->vc);
-
- vpd->vertexcosnos= mesh_get_mapped_verts_nors(vpd->vc.scene, ob);
- vpd->indexar= get_indexarray();
- vpd->paintcol= vpaint_get_current_col(vp);
+ if(vpd->vertexcosnos)
+ MEM_freeN(vpd->vertexcosnos);
+ MEM_freeN(vpd->indexar);
- /* for filtering */
- copy_vpaint_prev(vp, (unsigned int *)me->mcol, me->totface);
+ /* frees prev buffer */
+ copy_vpaint_prev(ts->vpaint, NULL, 0);
- /* some old cruft to sort out later */
- Mat4MulMat4(mat, ob->obmat, vpd->vc.rv3d->viewmat);
- Mat4Invert(imat, mat);
- Mat3CpyMat4(vpd->vpimat, imat);
+ MEM_freeN(vpd);
+}
+
+static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
- /* do paint once for click only paint */
- vpaint_modal(C, op, event);
+ op->customdata = paint_stroke_new(C, vpaint_stroke_test_start,
+ vpaint_stroke_update_step,
+ vpaint_stroke_done);
/* add modal handler */
WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
+
+ op->type->modal(C, op, event);
return OPERATOR_RUNNING_MODAL;
}
@@ -1859,11 +1799,13 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot)
/* api callbacks */
ot->invoke= vpaint_invoke;
- ot->modal= vpaint_modal;
+ ot->modal= paint_stroke_modal;
/* ot->exec= vpaint_exec; <-- needs stroke property */
ot->poll= vp_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
+
+ RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 8cca135d99d..ba48bebce78 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -64,6 +64,7 @@
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
+#include "BKE_paint.h"
#include "BKE_sculpt.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
@@ -79,6 +80,7 @@
#include "ED_space_api.h"
#include "ED_util.h"
#include "ED_view3d.h"
+#include "paint_intern.h"
#include "sculpt_intern.h"
#include "RNA_access.h"
@@ -124,29 +126,27 @@ typedef enum StrokeFlags {
*/
typedef struct StrokeCache {
/* Invariants */
- float radius;
+ float initial_radius;
float scale[3];
int flag;
float clip_tolerance[3];
- int initial_mouse[2];
+ float initial_mouse[2];
float depth;
/* Variants */
+ float radius;
float true_location[3];
float location[3];
float flip;
float pressure;
- int mouse[2];
+ float mouse[2];
/* The rest is temporary storage that isn't saved as a property */
int first_time; /* Beginning of stroke may do some things special */
- ViewContext vc;
bglMats *mats;
- float *layer_disps; /* Displacements for each vertex */
- float (*mesh_store)[3]; /* Copy of the mesh vertices' locations */
short (*orig_norms)[3]; /* Copy of the mesh vertices' normals */
float (*face_norms)[3]; /* Copy of the mesh faces' normals */
float rotation; /* Texture rotation (radians) for anchored and rake modes */
@@ -178,19 +178,6 @@ typedef struct ProjVert {
* Simple functions to get data from the GL
*/
-/* Uses window coordinates (x,y) and depth component z to find a point in
- modelspace */
-static void unproject(bglMats *mats, float out[3], const short x, const short y, const float z)
-{
- double ux, uy, uz;
-
- gluUnProject(x,y,z, mats->modelview, mats->projection,
- (GLint *)mats->viewport, &ux, &uy, &uz );
- out[0] = ux;
- out[1] = uy;
- out[2] = uz;
-}
-
/* Convert a point in model coordinates to 2D screen coordinates. */
static void projectf(bglMats *mats, const float v[3], float p[2])
{
@@ -215,36 +202,23 @@ static void project(bglMats *mats, const float v[3], short p[2])
*
*/
-/* Return modified brush size. Uses current tablet pressure (if available) to
- shrink the brush. Skipped for grab brush because only the first mouse down
- size is used, which is small if the user has just touched the pen to the
- tablet */
-static char brush_size(Sculpt *sd)
-{
- float size= sd->brush->size;
-
- if((sd->brush->sculpt_tool != SCULPT_TOOL_GRAB) && (sd->brush->flag & BRUSH_SIZE_PRESSURE))
- size *= sd->session->cache->pressure;
-
- return size;
-}
-
/* Return modified brush strength. Includes the direction of the brush, positive
values pull vertices, negative values push. Uses tablet pressure and a
special multiplier found experimentally to scale the strength factor. */
static float brush_strength(Sculpt *sd, StrokeCache *cache)
{
+ Brush *brush = paint_brush(&sd->paint);
/* Primary strength input; square it to make lower values more sensitive */
- float alpha = sd->brush->alpha * sd->brush->alpha;
+ float alpha = brush->alpha * brush->alpha;
- float dir= sd->brush->flag & BRUSH_DIR_IN ? -1 : 1;
+ float dir= brush->flag & BRUSH_DIR_IN ? -1 : 1;
float pressure= 1;
float flip= cache->flip ? -1:1;
- if(sd->brush->flag & BRUSH_ALPHA_PRESSURE)
+ if(brush->flag & BRUSH_ALPHA_PRESSURE)
pressure *= cache->pressure;
- switch(sd->brush->sculpt_tool){
+ switch(brush->sculpt_tool){
case SCULPT_TOOL_DRAW:
case SCULPT_TOOL_INFLATE:
case SCULPT_TOOL_CLAY:
@@ -263,7 +237,7 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache)
}
/* Handles clipping against a mirror modifier and SCULPT_LOCK axis flags */
-static void sculpt_clip(Sculpt *sd, float *co, const float val[3])
+static void sculpt_clip(Sculpt *sd, SculptSession *ss, float *co, const float val[3])
{
int i;
@@ -271,7 +245,7 @@ static void sculpt_clip(Sculpt *sd, float *co, const float val[3])
if(sd->flags & (SCULPT_LOCK_X << i))
continue;
- if((sd->session->cache->flag & (CLIP_X << i)) && (fabs(co[i]) <= sd->session->cache->clip_tolerance[i]))
+ if((ss->cache->flag & (CLIP_X << i)) && (fabs(co[i]) <= ss->cache->clip_tolerance[i]))
co[i]= 0.0f;
else
co[i]= val[i];
@@ -293,23 +267,24 @@ static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], cons
/* Currently only for the draw brush; finds average normal for all active
vertices */
-static void calc_area_normal(Sculpt *sd, float out[3], const ListBase* active_verts)
+static void calc_area_normal(Sculpt *sd, SculptSession *ss, float out[3], const ListBase* active_verts)
{
- StrokeCache *cache = sd->session->cache;
+ Brush *brush = paint_brush(&sd->paint);
+ StrokeCache *cache = ss->cache;
ActiveData *node = active_verts->first;
- const int view = 0; /* XXX: should probably be a flag, not number: sd->brush_type==SCULPT_TOOL_DRAW ? sculptmode_brush()->view : 0; */
+ const int view = 0; /* XXX: should probably be a flag, not number: brush_type==SCULPT_TOOL_DRAW ? sculptmode_brush()->view : 0; */
float out_flip[3];
float *out_dir = cache->view_normal_symmetry;
out[0]=out[1]=out[2] = out_flip[0]=out_flip[1]=out_flip[2] = 0;
- if(sd->brush->flag & BRUSH_ANCHORED) {
+ if(brush->flag & BRUSH_ANCHORED) {
for(; node; node = node->next)
add_norm_if(out_dir, out, out_flip, cache->orig_norms[node->Index]);
}
else {
for(; node; node = node->next)
- add_norm_if(out_dir, out, out_flip, sd->session->mvert[node->Index].no);
+ add_norm_if(out_dir, out, out_flip, ss->mvert[node->Index].no);
}
if (out[0]==0.0 && out[1]==0.0 && out[2]==0.0) {
@@ -332,7 +307,7 @@ static void do_draw_brush(Sculpt *sd, SculptSession *ss, const ListBase* active_
float area_normal[3];
ActiveData *node= active_verts->first;
- calc_area_normal(sd, area_normal, active_verts);
+ calc_area_normal(sd, ss, area_normal, active_verts);
while(node){
float *co= ss->mvert[node->Index].co;
@@ -341,7 +316,7 @@ static void do_draw_brush(Sculpt *sd, SculptSession *ss, const ListBase* active_
co[1]+area_normal[1]*ss->cache->radius*node->Fade*ss->cache->scale[1],
co[2]+area_normal[2]*ss->cache->radius*node->Fade*ss->cache->scale[2]};
- sculpt_clip(sd, co, val);
+ sculpt_clip(sd, ss, co, val);
node= node->next;
}
@@ -391,37 +366,37 @@ static void neighbor_average(SculptSession *ss, float avg[3], const int vert)
VecCopyf(avg, ss->mvert[vert].co);
}
-static void do_smooth_brush(Sculpt *s, const ListBase* active_verts)
+static void do_smooth_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts)
{
ActiveData *node= active_verts->first;
int i;
for(i = 0; i < 2; ++i) {
while(node){
- float *co= s->session->mvert[node->Index].co;
+ float *co= ss->mvert[node->Index].co;
float avg[3], val[3];
- neighbor_average(s->session, avg, node->Index);
+ neighbor_average(ss, avg, node->Index);
val[0] = co[0]+(avg[0]-co[0])*node->Fade;
val[1] = co[1]+(avg[1]-co[1])*node->Fade;
val[2] = co[2]+(avg[2]-co[2])*node->Fade;
- sculpt_clip(s, co, val);
+ sculpt_clip(s, ss, co, val);
node= node->next;
}
}
}
-static void do_pinch_brush(Sculpt *s, const ListBase* active_verts)
+static void do_pinch_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts)
{
ActiveData *node= active_verts->first;
while(node) {
- float *co= s->session->mvert[node->Index].co;
- const float val[3]= {co[0]+(s->session->cache->location[0]-co[0])*node->Fade,
- co[1]+(s->session->cache->location[1]-co[1])*node->Fade,
- co[2]+(s->session->cache->location[2]-co[2])*node->Fade};
- sculpt_clip(s, co, val);
+ float *co= ss->mvert[node->Index].co;
+ const float val[3]= {co[0]+(ss->cache->location[0]-co[0])*node->Fade,
+ co[1]+(ss->cache->location[1]-co[1])*node->Fade,
+ co[2]+(ss->cache->location[2]-co[2])*node->Fade};
+ sculpt_clip(s, ss, co, val);
node= node->next;
}
}
@@ -440,7 +415,7 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss)
VecCopyf(add, grab_delta);
VecMulf(add, node->Fade);
VecAddf(add, add, co);
- sculpt_clip(sd, co, add);
+ sculpt_clip(sd, ss, co, add);
node= node->next;
}
@@ -456,10 +431,10 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active
if(ss->cache->flip)
lim = -lim;
- calc_area_normal(sd, area_normal, active_verts);
+ calc_area_normal(sd, ss, area_normal, active_verts);
while(node){
- float *disp= &ss->cache->layer_disps[node->Index];
+ float *disp= &ss->layer_disps[node->Index];
float *co= ss->mvert[node->Index].co;
float val[3];
@@ -469,20 +444,19 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active
if((lim < 0 && *disp < lim) || (lim > 0 && *disp > lim))
*disp = lim;
- val[0] = ss->cache->mesh_store[node->Index][0]+area_normal[0] * *disp*ss->cache->scale[0];
- val[1] = ss->cache->mesh_store[node->Index][1]+area_normal[1] * *disp*ss->cache->scale[1];
- val[2] = ss->cache->mesh_store[node->Index][2]+area_normal[2] * *disp*ss->cache->scale[2];
+ val[0] = ss->mesh_co_orig[node->Index][0]+area_normal[0] * *disp*ss->cache->scale[0];
+ val[1] = ss->mesh_co_orig[node->Index][1]+area_normal[1] * *disp*ss->cache->scale[1];
+ val[2] = ss->mesh_co_orig[node->Index][2]+area_normal[2] * *disp*ss->cache->scale[2];
- sculpt_clip(sd, co, val);
+ sculpt_clip(sd, ss, co, val);
node= node->next;
}
}
-static void do_inflate_brush(Sculpt *s, const ListBase *active_verts)
+static void do_inflate_brush(Sculpt *s, SculptSession *ss, const ListBase *active_verts)
{
ActiveData *node= active_verts->first;
- SculptSession *ss = s->session;
float add[3];
while(node) {
@@ -498,7 +472,7 @@ static void do_inflate_brush(Sculpt *s, const ListBase *active_verts)
add[2]*= ss->cache->scale[2];
VecAddf(add, add, co);
- sculpt_clip(s, co, add);
+ sculpt_clip(s, ss, co, add);
node= node->next;
}
@@ -527,46 +501,86 @@ static void calc_flatten_center(SculptSession *ss, ActiveData *node, float co[3]
VecMulf(co, 1.0f / FLATTEN_SAMPLE_SIZE);
}
+/* Projects a point onto a plane along the plane's normal */
+static void point_plane_project(float intr[3], float co[3], float plane_normal[3], float plane_center[3])
+{
+ float p1[3], sub1[3], sub2[3];
+
+ /* Find the intersection between squash-plane and vertex (along the area normal) */
+ VecSubf(p1, co, plane_normal);
+ VecSubf(sub1, plane_center, p1);
+ VecSubf(sub2, co, p1);
+ VecSubf(intr, co, p1);
+ VecMulf(intr, Inpf(plane_normal, sub1) / Inpf(plane_normal, sub2));
+ VecAddf(intr, intr, p1);
+}
+
+static int plane_point_side(float co[3], float plane_normal[3], float plane_center[3], int flip)
+{
+ float delta[3];
+ float d;
+
+ VecSubf(delta, co, plane_center);
+ d = Inpf(plane_normal, delta);
+
+ if(flip)
+ d = -d;
+
+ return d <= 0.0f;
+}
+
static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase *active_verts, int clay)
{
ActiveData *node= active_verts->first;
/* area_normal and cntr define the plane towards which vertices are squashed */
float area_normal[3];
- float cntr[3];
+ float cntr[3], cntr2[3], bstr = 0;
+ int flip = 0;
- calc_area_normal(sd, area_normal, active_verts);
+ calc_area_normal(sd, ss, area_normal, active_verts);
calc_flatten_center(ss, node, cntr);
+ if(clay) {
+ bstr= brush_strength(sd, ss->cache);
+ /* Limit clay application to here */
+ cntr2[0]=cntr[0]+area_normal[0]*bstr*ss->cache->scale[0];
+ cntr2[1]=cntr[1]+area_normal[1]*bstr*ss->cache->scale[1];
+ cntr2[2]=cntr[2]+area_normal[2]*bstr*ss->cache->scale[2];
+ flip = bstr < 0;
+ }
+
while(node){
float *co= ss->mvert[node->Index].co;
- float p1[3], sub1[3], sub2[3], intr[3], val[3];
-
- /* Find the intersection between squash-plane and vertex (along the area normal) */
- VecSubf(p1, co, area_normal);
- VecSubf(sub1, cntr, p1);
- VecSubf(sub2, co, p1);
- VecSubf(intr, co, p1);
- VecMulf(intr, Inpf(area_normal, sub1) / Inpf(area_normal, sub2));
- VecAddf(intr, intr, p1);
-
- VecSubf(val, intr, co);
- VecMulf(val, fabs(node->Fade));
- VecAddf(val, val, co);
+ float intr[3], val[3];
- if(clay) {
- /* Clay brush displaces after flattening */
- float tmp[3];
- VecCopyf(tmp, area_normal);
- VecMulf(tmp, ss->cache->radius * node->Fade * 0.1);
- VecAddf(val, val, tmp);
- }
+ if(!clay || plane_point_side(co, area_normal, cntr2, flip)) {
+ /* Find the intersection between squash-plane and vertex (along the area normal) */
+ point_plane_project(intr, co, area_normal, cntr);
+
+ VecSubf(val, intr, co);
- sculpt_clip(sd, co, val);
+ if(clay) {
+ if(bstr > FLT_EPSILON)
+ VecMulf(val, node->Fade / bstr);
+ else
+ VecMulf(val, node->Fade);
+ /* Clay displacement */
+ val[0]+=area_normal[0] * ss->cache->scale[0]*node->Fade;
+ val[1]+=area_normal[1] * ss->cache->scale[1]*node->Fade;
+ val[2]+=area_normal[2] * ss->cache->scale[2]*node->Fade;
+ }
+ else
+ VecMulf(val, fabs(node->Fade));
+
+ VecAddf(val, val, co);
+
+ sculpt_clip(sd, ss, co, val);
+ }
node= node->next;
}
}
-
+
/* Uses symm to selectively flip any axis of a coordinate. */
static void flip_coord(float out[3], float in[3], const char symm)
{
@@ -622,35 +636,29 @@ static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float
}
/* Return a multiplier for brush strength on a particular vertex. */
-static float tex_strength(Sculpt *sd, float *point, const float len)
+static float tex_strength(Sculpt *sd, SculptSession *ss, float *point, const float len)
{
- SculptSession *ss= sd->session;
- Brush *br = sd->brush;
+ Brush *br = paint_brush(&sd->paint);
+ MTex *tex = NULL;
float avg= 1;
- if(br->texact==-1 || !br->mtex[br->texact])
+ if(br->texact >= 0)
+ tex = br->mtex[br->texact];
+
+ if(!tex) {
avg= 1;
- else if(br->tex_mode==BRUSH_TEX_3D) {
- /* Get strength by feeding the vertex location directly
- into a texture */
+ }
+ else if(tex->brush_map_mode == MTEX_MAP_MODE_3D) {
float jnk;
- const float factor= 0.01;
- MTex mtex;
- memset(&mtex,0,sizeof(MTex));
- mtex.tex= br->mtex[br->texact]->tex;
- mtex.projx= 1;
- mtex.projy= 2;
- mtex.projz= 3;
- VecCopyf(mtex.size, br->mtex[br->texact]->size);
- VecMulf(mtex.size, factor);
- if(!sd->texsep)
- mtex.size[1]= mtex.size[2]= mtex.size[0];
-
- externtex(&mtex,point,&avg,&jnk,&jnk,&jnk,&jnk);
+
+ /* Get strength by feeding the vertex
+ location directly into a texture */
+ externtex(tex, point, &avg,
+ &jnk, &jnk, &jnk, &jnk);
}
else if(ss->texcache) {
const float bsize= ss->cache->pixel_radius * 2;
- const float rot= sd->brush->rot + ss->cache->rotation;
+ const float rot= tex->rot + ss->cache->rotation;
int px, py;
float flip[3], point_2d[2];
@@ -663,9 +671,9 @@ static float tex_strength(Sculpt *sd, float *point, const float len)
/* For Tile and Drag modes, get the 2D screen coordinates of the
and scale them up or down to the texture size. */
- if(br->tex_mode==BRUSH_TEX_TILE) {
- const int sx= (const int)br->mtex[br->texact]->size[0];
- const int sy= (const int)sd->texsep ? br->mtex[br->texact]->size[1] : sx;
+ if(tex->brush_map_mode == MTEX_MAP_MODE_TILED) {
+ const int sx= (const int)tex->size[0];
+ const int sy= (const int)tex->size[1];
float fx= point_2d[0];
float fy= point_2d[1];
@@ -685,7 +693,8 @@ static float tex_strength(Sculpt *sd, float *point, const float len)
if(sy != 1)
py %= sy-1;
avg= get_texcache_pixel_bilinear(ss, ss->texcache_side*px/sx, ss->texcache_side*py/sy);
- } else {
+ }
+ else if(tex->brush_map_mode == MTEX_MAP_MODE_FIXED) {
float fx= (point_2d[0] - ss->cache->mouse[0]) / bsize;
float fy= (point_2d[1] - ss->cache->mouse[1]) / bsize;
@@ -699,7 +708,7 @@ static float tex_strength(Sculpt *sd, float *point, const float len)
}
}
- avg*= brush_curve_strength(sd->brush, len, ss->cache->radius); /* Falloff curve */
+ avg*= brush_curve_strength(br, len, ss->cache->radius); /* Falloff curve */
return avg;
}
@@ -737,9 +746,9 @@ static void sculpt_add_damaged_rect(SculptSession *ss)
}
}
-static void do_brush_action(Sculpt *sd, StrokeCache *cache)
+static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache)
{
- SculptSession *ss = sd->session;
+ Brush *brush = paint_brush(&sd->paint);
float av_dist;
ListBase active_verts={0,0};
ListBase *grab_active_verts = &ss->cache->grab_active_verts[ss->cache->symmetry];
@@ -748,7 +757,7 @@ static void do_brush_action(Sculpt *sd, StrokeCache *cache)
Mesh *me= NULL; /*XXX: get_mesh(OBACT); */
const float bstrength= brush_strength(sd, cache);
KeyBlock *keyblock= NULL; /*XXX: ob_get_keyblock(OBACT); */
- Brush *b = sd->brush;
+ Brush *b = brush;
int i;
sculpt_add_damaged_rect(ss);
@@ -768,7 +777,7 @@ static void do_brush_action(Sculpt *sd, StrokeCache *cache)
adata->Index = i;
/* Fade is used to store the final strength at which the brush
should modify a particular vertex. */
- adata->Fade= tex_strength(sd, vert, av_dist) * bstrength;
+ adata->Fade= tex_strength(sd, ss, vert, av_dist) * bstrength;
adata->dist = av_dist;
if(b->sculpt_tool == SCULPT_TOOL_GRAB && cache->first_time)
@@ -788,13 +797,13 @@ static void do_brush_action(Sculpt *sd, StrokeCache *cache)
do_draw_brush(sd, ss, &active_verts);
break;
case SCULPT_TOOL_SMOOTH:
- do_smooth_brush(sd, &active_verts);
+ do_smooth_brush(sd, ss, &active_verts);
break;
case SCULPT_TOOL_PINCH:
- do_pinch_brush(sd, &active_verts);
+ do_pinch_brush(sd, ss, &active_verts);
break;
case SCULPT_TOOL_INFLATE:
- do_inflate_brush(sd, &active_verts);
+ do_inflate_brush(sd, ss, &active_verts);
break;
case SCULPT_TOOL_GRAB:
do_grab_brush(sd, ss);
@@ -843,20 +852,21 @@ static void calc_brushdata_symm(StrokeCache *cache, const char symm)
cache->symmetry= symm;
}
-static void do_symmetrical_brush_actions(Sculpt *sd, StrokeCache *cache)
+static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss)
{
+ StrokeCache *cache = ss->cache;
const char symm = sd->flags & 7;
int i;
VecCopyf(cache->location, cache->true_location);
VecCopyf(cache->grab_delta_symmetry, cache->grab_delta);
cache->symmetry = 0;
- do_brush_action(sd, cache);
+ do_brush_action(sd, ss, cache);
for(i = 1; i <= symm; ++i) {
if(symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5))) {
calc_brushdata_symm(cache, i);
- do_brush_action(sd, cache);
+ do_brush_action(sd, ss, cache);
}
}
@@ -929,9 +939,9 @@ static void projverts_clear_inside(SculptSession *ss)
}
#endif
-static void sculpt_update_tex(Sculpt *sd)
+static void sculpt_update_tex(Sculpt *sd, SculptSession *ss)
{
- SculptSession *ss= sd->session;
+ Brush *brush = paint_brush(&sd->paint);
if(ss->texcache) {
MEM_freeN(ss->texcache);
@@ -939,9 +949,9 @@ static void sculpt_update_tex(Sculpt *sd)
}
/* Need to allocate a bigger buffer for bigger brush size */
- ss->texcache_side = sd->brush->size * 2;
+ ss->texcache_side = brush->size * 2;
if(!ss->texcache || ss->texcache_side > ss->texcache_actual) {
- ss->texcache = brush_gen_texture_cache(sd->brush, sd->brush->size);
+ ss->texcache = brush_gen_texture_cache(brush, brush->size);
ss->texcache_actual = ss->texcache_side;
}
}
@@ -992,8 +1002,8 @@ static struct MultiresModifierData *sculpt_multires_active(Object *ob)
static void sculpt_update_mesh_elements(bContext *C)
{
- SculptSession *ss = CTX_data_tool_settings(C)->sculpt->session;
Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
int oldtotvert = ss->totvert;
if((ss->multires = sculpt_multires_active(ob))) {
@@ -1026,54 +1036,20 @@ static void sculpt_update_mesh_elements(bContext *C)
static int sculpt_mode_poll(bContext *C)
{
- return G.f & G_SCULPTMODE;
+ Object *ob = CTX_data_active_object(C);
+ return ob && ob->mode & OB_MODE_SCULPT;
}
static int sculpt_poll(bContext *C)
{
- return G.f & G_SCULPTMODE && CTX_wm_area(C)->spacetype == SPACE_VIEW3D &&
- CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW;
-}
-
-/*** Sculpt Cursor ***/
-static void draw_paint_cursor(bContext *C, int x, int y, void *customdata)
-{
- Sculpt *sd= CTX_data_tool_settings(C)->sculpt;
-
- glColor4ub(255, 100, 100, 128);
- glEnable( GL_LINE_SMOOTH );
- glEnable(GL_BLEND);
-
- glTranslatef((float)x, (float)y, 0.0f);
- glutil_draw_lined_arc(0.0, M_PI*2.0, sd->brush->size, 40);
- glTranslatef((float)-x, (float)-y, 0.0f);
-
- if(sd->session && sd->session->cache && sd->brush && (sd->brush->flag & BRUSH_SMOOTH_STROKE)) {
- ARegion *ar = CTX_wm_region(C);
- sdrawline(x, y, sd->session->cache->mouse[0] - ar->winrct.xmin, sd->session->cache->mouse[1] - ar->winrct.ymin);
- }
-
- glDisable(GL_BLEND);
- glDisable( GL_LINE_SMOOTH );
-}
-
-static void toggle_paint_cursor(bContext *C)
-{
- Sculpt *s = CTX_data_scene(C)->toolsettings->sculpt;
-
- if(s->session->cursor) {
- WM_paint_cursor_end(CTX_wm_manager(C), s->session->cursor);
- s->session->cursor = NULL;
- }
- else {
- s->session->cursor =
- WM_paint_cursor_activate(CTX_wm_manager(C), sculpt_poll, draw_paint_cursor, NULL);
- }
+ return sculpt_mode_poll(C) && paint_poll(C);
}
static void sculpt_undo_push(bContext *C, Sculpt *sd)
{
- switch(sd->brush->sculpt_tool) {
+ Brush *brush = paint_brush(&sd->paint);
+
+ switch(brush->sculpt_tool) {
case SCULPT_TOOL_DRAW:
ED_undo_push(C, "Draw Brush"); break;
case SCULPT_TOOL_SMOOTH:
@@ -1093,36 +1069,15 @@ static void sculpt_undo_push(bContext *C, Sculpt *sd)
}
}
-static int sculpt_brush_curve_preset_exec(bContext *C, wmOperator *op)
-{
- brush_curve_preset(CTX_data_scene(C)->toolsettings->sculpt->brush, RNA_enum_get(op->ptr, "mode"));
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_brush_curve_preset(wmOperatorType *ot)
-{
- static EnumPropertyItem prop_mode_items[] = {
- {BRUSH_PRESET_SHARP, "SHARP", 0, "Sharp Curve", ""},
- {BRUSH_PRESET_SMOOTH, "SMOOTH", 0, "Smooth Curve", ""},
- {BRUSH_PRESET_MAX, "MAX", 0, "Max Curve", ""},
- {0, NULL, 0, NULL, NULL}};
-
- ot->name= "Preset";
- ot->idname= "SCULPT_OT_brush_curve_preset";
-
- ot->exec= sculpt_brush_curve_preset_exec;
- ot->poll= sculpt_mode_poll;
-
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_enum(ot->srna, "mode", prop_mode_items, BRUSH_PRESET_SHARP, "Mode", "");
-}
-
/**** Radial control ****/
static int sculpt_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
- toggle_paint_cursor(C);
- brush_radial_control_invoke(op, CTX_data_scene(C)->toolsettings->sculpt->brush, 1);
+ Paint *p = paint_get_active(CTX_data_scene(C));
+ Brush *brush = paint_brush(p);
+
+ WM_paint_cursor_end(CTX_wm_manager(C), p->paint_cursor);
+ p->paint_cursor = NULL;
+ brush_radial_control_invoke(op, brush, 1);
return WM_radial_control_invoke(C, op, event);
}
@@ -1130,13 +1085,15 @@ static int sculpt_radial_control_modal(bContext *C, wmOperator *op, wmEvent *eve
{
int ret = WM_radial_control_modal(C, op, event);
if(ret != OPERATOR_RUNNING_MODAL)
- toggle_paint_cursor(C);
+ paint_cursor_start(C, sculpt_poll);
return ret;
}
static int sculpt_radial_control_exec(bContext *C, wmOperator *op)
{
- return brush_radial_control_exec(op, CTX_data_scene(C)->toolsettings->sculpt->brush, 1);
+ Brush *brush = paint_brush(&CTX_data_tool_settings(C)->sculpt->paint);
+
+ return brush_radial_control_exec(op, brush, 1);
}
static void SCULPT_OT_radial_control(wmOperatorType *ot)
@@ -1162,7 +1119,7 @@ static float unproject_brush_radius(SculptSession *ss, float offset)
float brush_edge[3];
/* In anchored mode, brush size changes with mouse loc, otherwise it's fixed using the brush radius */
- unproject(ss->cache->mats, brush_edge, ss->cache->initial_mouse[0] + offset,
+ view3d_unproject(ss->cache->mats, brush_edge, ss->cache->initial_mouse[0] + offset,
ss->cache->initial_mouse[1], ss->cache->depth);
return VecLenf(ss->cache->true_location, brush_edge);
@@ -1170,31 +1127,32 @@ static float unproject_brush_radius(SculptSession *ss, float offset)
static void sculpt_cache_free(StrokeCache *cache)
{
- if(cache->layer_disps)
- MEM_freeN(cache->layer_disps);
- if(cache->mesh_store)
- MEM_freeN(cache->mesh_store);
+ int i;
if(cache->orig_norms)
MEM_freeN(cache->orig_norms);
if(cache->face_norms)
MEM_freeN(cache->face_norms);
if(cache->mats)
MEM_freeN(cache->mats);
+ for(i = 0; i < 8; ++i)
+ BLI_freelistN(&cache->grab_active_verts[i]);
MEM_freeN(cache);
}
/* Initialize the stroke cache invariants from operator properties */
-static void sculpt_update_cache_invariants(Sculpt *sd, bContext *C, wmOperator *op)
+static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bContext *C, wmOperator *op)
{
StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
+ Brush *brush = paint_brush(&sd->paint);
+ ViewContext *vc = paint_stroke_view_context(op->customdata);
int i;
- sd->session->cache = cache;
+ ss->cache = cache;
RNA_float_get_array(op->ptr, "scale", cache->scale);
cache->flag = RNA_int_get(op->ptr, "flag");
RNA_float_get_array(op->ptr, "clip_tolerance", cache->clip_tolerance);
- RNA_int_get_array(op->ptr, "initial_mouse", cache->initial_mouse);
+ RNA_float_get_array(op->ptr, "initial_mouse", cache->initial_mouse);
cache->depth = RNA_float_get(op->ptr, "depth");
cache->mouse[0] = cache->initial_mouse[0];
@@ -1202,70 +1160,88 @@ static void sculpt_update_cache_invariants(Sculpt *sd, bContext *C, wmOperator *
/* Truly temporary data that isn't stored in properties */
- view3d_set_viewcontext(C, &cache->vc);
-
cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats");
- view3d_get_transformation(&cache->vc, cache->vc.obact, cache->mats);
+ view3d_get_transformation(vc, vc->obact, cache->mats);
sculpt_update_mesh_elements(C);
- if(sd->brush->sculpt_tool == SCULPT_TOOL_LAYER)
- cache->layer_disps = MEM_callocN(sizeof(float) * sd->session->totvert, "layer brush displacements");
+ /* Initialize layer brush displacements */
+ if(brush->sculpt_tool == SCULPT_TOOL_LAYER &&
+ (!ss->layer_disps || !(brush->flag & BRUSH_PERSISTENT))) {
+ if(ss->layer_disps)
+ MEM_freeN(ss->layer_disps);
+ ss->layer_disps = MEM_callocN(sizeof(float) * ss->totvert, "layer brush displacements");
+ }
/* Make copies of the mesh vertex locations and normals for some tools */
- if(sd->brush->sculpt_tool == SCULPT_TOOL_LAYER || (sd->brush->flag & BRUSH_ANCHORED)) {
- cache->mesh_store= MEM_mallocN(sizeof(float) * 3 * sd->session->totvert, "sculpt mesh vertices copy");
- for(i = 0; i < sd->session->totvert; ++i)
- VecCopyf(cache->mesh_store[i], sd->session->mvert[i].co);
-
- if(sd->brush->flag & BRUSH_ANCHORED) {
- cache->orig_norms= MEM_mallocN(sizeof(short) * 3 * sd->session->totvert, "Sculpt orig norm");
- for(i = 0; i < sd->session->totvert; ++i) {
- cache->orig_norms[i][0] = sd->session->mvert[i].no[0];
- cache->orig_norms[i][1] = sd->session->mvert[i].no[1];
- cache->orig_norms[i][2] = sd->session->mvert[i].no[2];
+ if(brush->sculpt_tool == SCULPT_TOOL_LAYER || (brush->flag & BRUSH_ANCHORED)) {
+ if(brush->sculpt_tool != SCULPT_TOOL_LAYER ||
+ !ss->mesh_co_orig || !(brush->flag & BRUSH_PERSISTENT)) {
+ if(!ss->mesh_co_orig)
+ ss->mesh_co_orig= MEM_mallocN(sizeof(float) * 3 * ss->totvert,
+ "sculpt mesh vertices copy");
+ for(i = 0; i < ss->totvert; ++i)
+ VecCopyf(ss->mesh_co_orig[i], ss->mvert[i].co);
+ }
+
+ if(brush->flag & BRUSH_ANCHORED) {
+ cache->orig_norms= MEM_mallocN(sizeof(short) * 3 * ss->totvert, "Sculpt orig norm");
+ for(i = 0; i < ss->totvert; ++i) {
+ cache->orig_norms[i][0] = ss->mvert[i].no[0];
+ cache->orig_norms[i][1] = ss->mvert[i].no[1];
+ cache->orig_norms[i][2] = ss->mvert[i].no[2];
}
- if(sd->session->face_normals) {
- float *fn = sd->session->face_normals;
- cache->face_norms= MEM_mallocN(sizeof(float) * 3 * sd->session->totface, "Sculpt face norms");
- for(i = 0; i < sd->session->totface; ++i, fn += 3)
+ if(ss->face_normals) {
+ float *fn = ss->face_normals;
+ cache->face_norms= MEM_mallocN(sizeof(float) * 3 * ss->totface, "Sculpt face norms");
+ for(i = 0; i < ss->totface; ++i, fn += 3)
VecCopyf(cache->face_norms[i], fn);
}
}
}
- unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth);
- cache->radius = unproject_brush_radius(sd->session, brush_size(sd));
+ view3d_unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth);
+ cache->initial_radius = unproject_brush_radius(ss, brush->size);
cache->rotation = 0;
cache->first_time = 1;
}
/* Initialize the stroke cache variants from operator properties */
-static void sculpt_update_cache_variants(Sculpt *sd, PointerRNA *ptr)
+static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerRNA *ptr)
{
- StrokeCache *cache = sd->session->cache;
+ StrokeCache *cache = ss->cache;
+ Brush *brush = paint_brush(&sd->paint);
float grab_location[3];
+
int dx, dy;
- if(!(sd->brush->flag & BRUSH_ANCHORED))
+ if(!(brush->flag & BRUSH_ANCHORED))
RNA_float_get_array(ptr, "location", cache->true_location);
cache->flip = RNA_boolean_get(ptr, "flip");
- RNA_int_get_array(ptr, "mouse", cache->mouse);
+ RNA_float_get_array(ptr, "mouse", cache->mouse);
+ cache->pressure = RNA_float_get(ptr, "pressure");
/* Truly temporary data that isn't stored in properties */
cache->previous_pixel_radius = cache->pixel_radius;
- cache->pixel_radius = brush_size(sd);
+ cache->pixel_radius = brush->size;
+
+ if(brush->flag & BRUSH_SIZE_PRESSURE) {
+ cache->pixel_radius *= cache->pressure;
+ cache->radius = cache->initial_radius * cache->pressure;
+ }
+ else
+ cache->radius = cache->initial_radius;
- if(sd->brush->flag & BRUSH_ANCHORED) {
+ if(brush->flag & BRUSH_ANCHORED) {
dx = cache->mouse[0] - cache->initial_mouse[0];
dy = cache->mouse[1] - cache->initial_mouse[1];
cache->pixel_radius = sqrt(dx*dx + dy*dy);
- cache->radius = unproject_brush_radius(sd->session, cache->pixel_radius);
+ cache->radius = unproject_brush_radius(ss, cache->pixel_radius);
cache->rotation = atan2(dy, dx);
}
- else if(sd->brush->flag & BRUSH_RAKE) {
+ else if(brush->flag & BRUSH_RAKE) {
int update;
dx = cache->last_rake[0] - cache->mouse[0];
@@ -1284,8 +1260,8 @@ static void sculpt_update_cache_variants(Sculpt *sd, PointerRNA *ptr)
}
/* Find the grab delta */
- if(sd->brush->sculpt_tool == SCULPT_TOOL_GRAB) {
- unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth);
+ if(brush->sculpt_tool == SCULPT_TOOL_GRAB) {
+ view3d_unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth);
if(!cache->first_time)
VecSubf(cache->grab_delta, grab_location, cache->old_grab_location);
VecCopyf(cache->old_grab_location, grab_location);
@@ -1298,9 +1274,9 @@ static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmE
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob= CTX_data_active_object(C);
ModifierData *md;
- ViewContext vc;
float scale[3], clip_tolerance[3] = {0,0,0};
- int mouse[2], flag = 0;
+ float mouse[2];
+ int flag = 0;
/* Set scaling adjustment */
scale[0] = 1.0f / ob->size[0];
@@ -1327,42 +1303,39 @@ static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmE
/* Initial mouse location */
mouse[0] = event->x;
mouse[1] = event->y;
- RNA_int_set_array(op->ptr, "initial_mouse", mouse);
+ RNA_float_set_array(op->ptr, "initial_mouse", mouse);
/* Initial screen depth under the mouse */
- view3d_set_viewcontext(C, &vc);
- RNA_float_set(op->ptr, "depth", read_cached_depth(&vc, event->x, event->y));
+ RNA_float_set(op->ptr, "depth", read_cached_depth(paint_stroke_view_context(op->customdata), event->x, event->y));
- sculpt_update_cache_invariants(sd, C, op);
+ sculpt_update_cache_invariants(sd, ss, C, op);
}
-static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static void sculpt_brush_stroke_init(bContext *C)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ SculptSession *ss = CTX_data_active_object(C)->sculpt;
view3d_operator_needs_opengl(C);
/* TODO: Shouldn't really have to do this at the start of every
stroke, but sculpt would need some sort of notification when
changes are made to the texture. */
- sculpt_update_tex(sd);
+ sculpt_update_tex(sd, ss);
- /* add modal handler */
- WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
-
- return OPERATOR_RUNNING_MODAL;
+ sculpt_update_mesh_elements(C);
}
-static void sculpt_restore_mesh(Sculpt *sd)
+static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
{
- SculptSession *ss = sd->session;
StrokeCache *cache = ss->cache;
+ Brush *brush = paint_brush(&sd->paint);
int i;
/* Restore the mesh before continuing with anchored stroke */
- if((sd->brush->flag & BRUSH_ANCHORED) && cache->mesh_store) {
+ if((brush->flag & BRUSH_ANCHORED) && ss->mesh_co_orig) {
for(i = 0; i < ss->totvert; ++i) {
- VecCopyf(ss->mvert[i].co, cache->mesh_store[i]);
+ VecCopyf(ss->mvert[i].co, ss->mesh_co_orig[i]);
ss->mvert[i].no[0] = cache->orig_norms[i][0];
ss->mvert[i].no[1] = cache->orig_norms[i][1];
ss->mvert[i].no[2] = cache->orig_norms[i][2];
@@ -1374,8 +1347,8 @@ static void sculpt_restore_mesh(Sculpt *sd)
VecCopyf(fn, cache->face_norms[i]);
}
- if(sd->brush->sculpt_tool == SCULPT_TOOL_LAYER)
- memset(cache->layer_disps, 0, sizeof(float) * ss->totvert);
+ if(brush->sculpt_tool == SCULPT_TOOL_LAYER)
+ memset(ss->layer_disps, 0, sizeof(float) * ss->totvert);
}
}
@@ -1387,187 +1360,107 @@ static void sculpt_post_stroke_free(SculptSession *ss)
static void sculpt_flush_update(bContext *C)
{
- Sculpt *s = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
ARegion *ar = CTX_wm_region(C);
- MultiresModifierData *mmd = s->session->multires;
+ MultiresModifierData *mmd = ss->multires;
- calc_damaged_verts(s->session);
+ calc_damaged_verts(ss);
if(mmd) {
- if(mmd->undo_verts && mmd->undo_verts != s->session->mvert)
+ if(mmd->undo_verts && mmd->undo_verts != ss->mvert)
MEM_freeN(mmd->undo_verts);
- mmd->undo_verts = s->session->mvert;
- mmd->undo_verts_tot = s->session->totvert;
- multires_mark_as_modified(CTX_data_active_object(C));
+ mmd->undo_verts = ss->mvert;
+ mmd->undo_verts_tot = ss->totvert;
+ multires_mark_as_modified(ob);
}
ED_region_tag_redraw(ar);
}
-/* Returns zero if no sculpt changes should be made, non-zero otherwise */
-static int sculpt_smooth_stroke(Sculpt *s, int output[2], wmEvent *event)
+static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *event)
{
- output[0] = event->x;
- output[1] = event->y;
-
- if(s->brush->flag & BRUSH_SMOOTH_STROKE && s->brush->sculpt_tool != SCULPT_TOOL_GRAB) {
- StrokeCache *cache = s->session->cache;
- float u = .9, v = 1.0 - u;
- int dx = cache->mouse[0] - event->x, dy = cache->mouse[1] - event->y;
- int radius = 50;
-
- /* If the mouse is moving within the radius of the last move,
- don't update the mouse position. This allows sharp turns. */
- if(dx*dx + dy*dy < radius*radius)
- return 0;
-
- output[0] = event->x * v + cache->mouse[0] * u;
- output[1] = event->y * v + cache->mouse[1] * u;
- }
+ ViewContext vc;
+ float cur_depth;
- return 1;
-}
+ view3d_set_viewcontext(C, &vc);
+ cur_depth = read_cached_depth(&vc, event->x, event->y);
+
+ /* Don't start the stroke until a valid depth is found */
+ if(cur_depth < 1.0 - FLT_EPSILON) {
+ SculptSession *ss = CTX_data_active_object(C)->sculpt;
-/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
-int sculpt_space_stroke_enabled(Sculpt *s)
-{
- Brush *br = s->brush;
- return (br->flag & BRUSH_SPACE) && !(br->flag & BRUSH_ANCHORED) && (br->sculpt_tool != SCULPT_TOOL_GRAB);
+ sculpt_brush_stroke_init_properties(C, op, event, ss);
+ sculptmode_update_all_projverts(ss);
+
+ return 1;
+ }
+ else
+ return 0;
}
-/* Put the location of the next sculpt stroke dot into the stroke RNA and apply it to the mesh */
-static void sculpt_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, int mouse[2])
+static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- StrokeCache *cache = sd->session->cache;
- PointerRNA itemptr;
- float cur_depth;
- float center[3];
-
- cur_depth = read_cached_depth(&cache->vc, mouse[0], mouse[1]);
- unproject(sd->session->cache->mats, center, mouse[0], mouse[1], cur_depth);
-
- /* Add to stroke */
- RNA_collection_add(op->ptr, "stroke", &itemptr);
- RNA_float_set_array(&itemptr, "location", center);
- RNA_int_set_array(&itemptr, "mouse", mouse);
- RNA_boolean_set(&itemptr, "flip", event->shift);
- sculpt_update_cache_variants(sd, &itemptr);
-
- sculpt_restore_mesh(sd);
- do_symmetrical_brush_actions(sd, cache);
-}
+ SculptSession *ss = CTX_data_active_object(C)->sculpt;
-/* For brushes with stroke spacing enabled, moves mouse in steps
- towards the final mouse location. */
-static int sculpt_space_stroke(bContext *C, wmOperator *op, wmEvent *event, Sculpt *s, const int final_mouse[2])
-{
- StrokeCache *cache = s->session->cache;
- int cnt = 0;
-
- if(sculpt_space_stroke_enabled(s)) {
- float vec[2] = {final_mouse[0] - cache->mouse[0], final_mouse[1] - cache->mouse[1]};
- int mouse[2] = {cache->mouse[0], cache->mouse[1]};
- float length, scale;
- int steps = 0, i;
-
- /* Normalize the vector between the last stroke dot and the goal */
- length = sqrt(vec[0]*vec[0] + vec[1]*vec[1]);
-
- if(length > FLT_EPSILON) {
- scale = s->brush->spacing / length;
- vec[0] *= scale;
- vec[1] *= scale;
-
- steps = (int)(length / s->brush->spacing);
- for(i = 0; i < steps; ++i, ++cnt) {
- mouse[0] += vec[0];
- mouse[1] += vec[1];
- sculpt_brush_stroke_add_step(C, op, event, mouse);
- }
- }
- }
+ sculpt_update_cache_variants(sd, ss, itemptr);
+ sculpt_restore_mesh(sd, ss);
+ do_symmetrical_brush_actions(sd, ss);
- return cnt;
+ /* Cleanup */
+ sculpt_flush_update(C);
+ sculpt_post_stroke_free(ss);
}
-static int sculpt_brush_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
+static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke)
{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- ARegion *ar = CTX_wm_region(C);
- float cur_depth;
-
- sculpt_update_mesh_elements(C);
+ SculptSession *ss = CTX_data_active_object(C)->sculpt;
- if(!sd->session->cache) {
- ViewContext vc;
- view3d_set_viewcontext(C, &vc);
- cur_depth = read_cached_depth(&vc, event->x, event->y);
-
- /* Don't start the stroke until a valid depth is found */
- if(cur_depth < 1.0 - FLT_EPSILON) {
- sculpt_brush_stroke_init_properties(C, op, event, sd->session);
- sculptmode_update_all_projverts(sd->session);
- }
+ /* Finished */
+ if(ss->cache) {
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- ED_region_tag_redraw(ar);
+ request_depth_update(paint_stroke_view_context(stroke)->rv3d);
+ sculpt_cache_free(ss->cache);
+ ss->cache = NULL;
+ sculpt_undo_push(C, sd);
}
+}
- if(sd->session->cache) {
- int mouse[2];
-
- if(sculpt_smooth_stroke(sd, mouse, event)) {
- if(sculpt_space_stroke_enabled(sd)) {
- if(!sculpt_space_stroke(C, op, event, sd, mouse))
- ED_region_tag_redraw(ar);
- }
- else
- sculpt_brush_stroke_add_step(C, op, event, mouse);
-
- sculpt_flush_update(C);
- sculpt_post_stroke_free(sd->session);
- }
- else
- ED_region_tag_redraw(ar);
- }
+static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ sculpt_brush_stroke_init(C);
- /* Finished */
- if(event->type == LEFTMOUSE && event->val == 0) {
- if(sd->session->cache) {
- request_depth_update(sd->session->cache->vc.rv3d);
- sculpt_cache_free(sd->session->cache);
- sd->session->cache = NULL;
- sculpt_undo_push(C, sd);
- }
+ op->customdata = paint_stroke_new(C, sculpt_stroke_test_start,
+ sculpt_stroke_update_step,
+ sculpt_stroke_done);
- return OPERATOR_FINISHED;
- }
+ /* add modal handler */
+ WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
+ op->type->modal(C, op, event);
+
return OPERATOR_RUNNING_MODAL;
}
static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ SculptSession *ss = CTX_data_active_object(C)->sculpt;
- view3d_operator_needs_opengl(C);
- sculpt_update_cache_invariants(sd, C, op);
- sculptmode_update_all_projverts(sd->session);
- sculpt_update_tex(sd);
+ op->customdata = paint_stroke_new(C, sculpt_stroke_test_start, sculpt_stroke_update_step, sculpt_stroke_done);
- RNA_BEGIN(op->ptr, itemptr, "stroke") {
- sculpt_update_cache_variants(sd, &itemptr);
+ sculpt_brush_stroke_init(C);
- sculpt_restore_mesh(sd);
- do_symmetrical_brush_actions(sd, sd->session->cache);
+ sculpt_update_cache_invariants(sd, ss, C, op);
+ sculptmode_update_all_projverts(ss);
- sculpt_post_stroke_free(sd->session);
- }
- RNA_END;
+ paint_stroke_exec(C, op);
sculpt_flush_update(C);
- sculpt_cache_free(sd->session->cache);
+ sculpt_cache_free(ss->cache);
sculpt_undo_push(C, sd);
@@ -1584,7 +1477,7 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
/* api callbacks */
ot->invoke= sculpt_brush_stroke_invoke;
- ot->modal= sculpt_brush_stroke_modal;
+ ot->modal= paint_stroke_modal;
ot->exec= sculpt_brush_stroke_exec;
ot->poll= sculpt_poll;
@@ -1604,46 +1497,76 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
RNA_def_float_vector(ot->srna, "clip_tolerance", 3, NULL, 0.0f, FLT_MAX, "clip_tolerance", "", 0.0f, 1000.0f);
/* The initial 2D location of the mouse */
- RNA_def_int_vector(ot->srna, "initial_mouse", 2, NULL, INT_MIN, INT_MAX, "initial_mouse", "", INT_MIN, INT_MAX);
+ RNA_def_float_vector(ot->srna, "initial_mouse", 2, NULL, INT_MIN, INT_MAX, "initial_mouse", "", INT_MIN, INT_MAX);
/* The initial screen depth of the mouse */
RNA_def_float(ot->srna, "depth", 0.0f, 0.0f, FLT_MAX, "depth", "", 0.0f, FLT_MAX);
}
+/**** Reset the copy of the mesh that is being sculpted on (currently just for the layer brush) ****/
+
+static int sculpt_set_persistent_base(bContext *C, wmOperator *op)
+{
+ SculptSession *ss = CTX_data_active_object(C)->sculpt;
+
+ if(ss) {
+ if(ss->layer_disps)
+ MEM_freeN(ss->layer_disps);
+ ss->layer_disps = NULL;
+
+ if(ss->mesh_co_orig)
+ MEM_freeN(ss->mesh_co_orig);
+ ss->mesh_co_orig = NULL;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Set Persistent Base";
+ ot->idname= "SCULPT_OT_set_persistent_base";
+
+ /* api callbacks */
+ ot->exec= sculpt_set_persistent_base;
+ ot->poll= sculpt_mode_poll;
+
+ ot->flag= OPTYPE_REGISTER;
+}
+
/**** Toggle operator for turning sculpt mode on or off ****/
static int sculpt_toggle_mode(bContext *C, wmOperator *op)
{
ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
- if(G.f & G_SCULPTMODE) {
- multires_force_update(CTX_data_active_object(C));
+ if(ob->mode & OB_MODE_SCULPT) {
+ multires_force_update(ob);
/* Leave sculptmode */
- G.f &= ~G_SCULPTMODE;
-
- toggle_paint_cursor(C);
+ ob->mode &= ~OB_MODE_SCULPT;
- sculptsession_free(ts->sculpt);
+ free_sculptsession(&ob->sculpt);
}
else {
/* Enter sculptmode */
- G.f |= G_SCULPTMODE;
+ ob->mode |= OB_MODE_SCULPT;
/* Create persistent sculpt mode data */
if(!ts->sculpt)
ts->sculpt = MEM_callocN(sizeof(Sculpt), "sculpt mode data");
/* Create sculpt mode session data */
- if(ts->sculpt->session)
- MEM_freeN(ts->sculpt->session);
- ts->sculpt->session = MEM_callocN(sizeof(SculptSession), "sculpt session");
+ if(ob->sculpt)
+ free_sculptsession(&ob->sculpt);
+ ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
- toggle_paint_cursor(C);
-
- /* If there's no brush, create one */
- brush_check_exists(&ts->sculpt->brush);
+ paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT);
+
+ paint_cursor_start(C, sculpt_poll);
WM_event_add_notifier(C, NC_SCENE|ND_MODE, CTX_data_scene(C));
}
@@ -1669,5 +1592,5 @@ void ED_operatortypes_sculpt()
WM_operatortype_append(SCULPT_OT_radial_control);
WM_operatortype_append(SCULPT_OT_brush_stroke);
WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
- WM_operatortype_append(SCULPT_OT_brush_curve_preset);
+ WM_operatortype_append(SCULPT_OT_set_persistent_base);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_stroke.c b/source/blender/editors/sculpt_paint/sculpt_stroke.c
deleted file mode 100644
index 554ff580358..00000000000
--- a/source/blender/editors/sculpt_paint/sculpt_stroke.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2007 by Nicholas Bishop
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- *
- * Storage and manipulation of sculptmode brush strokes.
- *
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_listBase.h"
-#include "DNA_scene_types.h"
-
-#include "BKE_sculpt.h"
-#include "BLI_blenlib.h"
-#include "BIF_gl.h"
-
-#include "sculpt_intern.h"
-
-#include <math.h>
-
-/* Temporary storage of input stroke control points */
-typedef struct StrokePoint {
- struct StrokePoint *next, *prev;
- short x, y;
-} StrokePoint;
-typedef struct SculptStroke {
- short (*loc)[2];
- int max;
- int index;
- float length;
- ListBase final;
- StrokePoint *final_mem;
- float offset;
-} SculptStroke;
-
-SculptStroke *sculpt_stroke_new(const int max)
-{
- SculptStroke *stroke = MEM_callocN(sizeof(SculptStroke), "SculptStroke");
- stroke->loc = MEM_callocN(sizeof(short) * 4 * max, "SculptStroke.loc");
- stroke->max = max;
- stroke->index = -1;
- return stroke;
-}
-
-void sculpt_stroke_free(SculptStroke *stroke)
-{
- if(stroke) {
- if(stroke->loc) MEM_freeN(stroke->loc);
- if(stroke->final_mem) MEM_freeN(stroke->final_mem);
-
- MEM_freeN(stroke);
- }
-}
-
-void sculpt_stroke_add_point(SculptStroke *stroke, const short x, const short y)
-{
- const int next = stroke->index + 1;
-
- if(stroke->index == -1) {
- stroke->loc[0][0] = x;
- stroke->loc[0][1] = y;
- stroke->index = 0;
- }
- else if(next < stroke->max) {
- const int dx = x - stroke->loc[stroke->index][0];
- const int dy = y - stroke->loc[stroke->index][1];
- stroke->loc[next][0] = x;
- stroke->loc[next][1] = y;
- stroke->length += sqrt(dx*dx + dy*dy);
- stroke->index = next;
- }
-}
-
-static void sculpt_stroke_smooth(SculptStroke *stroke)
-{
- /* Apply smoothing (exclude the first and last points)*/
- StrokePoint *p = stroke->final.first;
- if(p && p->next && p->next->next) {
- for(p = p->next->next; p && p->next && p->next->next; p = p->next) {
- p->x = p->prev->prev->x*0.1 + p->prev->x*0.2 + p->x*0.4 + p->next->x*0.2 + p->next->next->x*0.1;
- p->y = p->prev->prev->y*0.1 + p->prev->y*0.2 + p->y*0.4 + p->next->y*0.2 + p->next->next->y*0.1;
- }
- }
-}
-
-static void sculpt_stroke_create_final(SculptStroke *stroke)
-{
- if(stroke) {
- StrokePoint *p, *pnext;
- int i;
-
- /* Copy loc into final */
- if(stroke->final_mem)
- MEM_freeN(stroke->final_mem);
- stroke->final_mem = MEM_callocN(sizeof(StrokePoint) * (stroke->index + 1) * 2, "SculptStroke.final");
- stroke->final.first = stroke->final.last = NULL;
- for(i = 0; i <= stroke->index; ++i) {
- p = &stroke->final_mem[i];
- p->x = stroke->loc[i][0];
- p->y = stroke->loc[i][1];
- BLI_addtail(&stroke->final, p);
- }
-
- /* Remove shortest edges */
- if(stroke->final.first) {
- for(p = ((StrokePoint*)stroke->final.first)->next; p && p->next; p = pnext) {
- const int dx = p->x - p->prev->x;
- const int dy = p->y - p->prev->y;
- const float len = sqrt(dx*dx + dy*dy);
- pnext = p->next;
- if(len < 10) {
- BLI_remlink(&stroke->final, p);
- }
- }
- }
-
- sculpt_stroke_smooth(stroke);
-
- /* Subdivide edges */
- for(p = stroke->final.first; p && p->next; p = pnext) {
- StrokePoint *np = &stroke->final_mem[i++];
-
- pnext = p->next;
- np->x = (p->x + p->next->x) / 2;
- np->y = (p->y + p->next->y) / 2;
- BLI_insertlink(&stroke->final, p, np);
- }
-
- sculpt_stroke_smooth(stroke);
- }
-}
-
-static float sculpt_stroke_seglen(StrokePoint *p1, StrokePoint *p2)
-{
- int dx = p2->x - p1->x;
- int dy = p2->y - p1->y;
- return sqrt(dx*dx + dy*dy);
-}
-
-static float sculpt_stroke_final_length(SculptStroke *stroke)
-{
- StrokePoint *p;
- float len = 0;
- for(p = stroke->final.first; p && p->next; ++p)
- len += sculpt_stroke_seglen(p, p->next);
- return len;
-}
-
-/* If partial is nonzero, cuts off apply after that length has been processed */
-static StrokePoint *sculpt_stroke_apply_generic(Sculpt *sd, SculptStroke *stroke, const int partial)
-{
- const int sdspace = 0; //XXX: sd->spacing;
- const short spacing = sdspace > 0 ? sdspace : 2;
- const int dots = sculpt_stroke_final_length(stroke) / spacing;
- int i;
- StrokePoint *p = stroke->final.first;
- float startloc = stroke->offset;
-
- for(i = 0; i < dots && p && p->next; ++i) {
- const float dotloc = spacing * i;
- short co[2];
- float len = sculpt_stroke_seglen(p, p->next);
- float u, v;
-
- /* Find edge containing dot */
- while(dotloc > startloc + len && p && p->next && p->next->next) {
- p = p->next;
- startloc += len;
- len = sculpt_stroke_seglen(p, p->next);
- }
-
- if(!p || !p->next || dotloc > startloc + len)
- break;
-
- if(partial && startloc > partial) {
- /* Calculate offset for next stroke segment */
- stroke->offset = startloc + len - dotloc;
- break;
- }
-
- u = (dotloc - startloc) / len;
- v = 1 - u;
-
- co[0] = p->x*v + p->next->x*u;
- co[1] = p->y*v + p->next->y*u;
-
- //do_symmetrical_brush_actions(sd, a, co, NULL);
- }
-
- return p ? p->next : NULL;
-}
-
-void sculpt_stroke_apply(Sculpt *sd, SculptStroke *stroke)
-{
- /* TODO: make these values user-modifiable? */
- const int partial_len = 100;
- const int min_len = 200;
-
- if(stroke) {
- sculpt_stroke_create_final(stroke);
-
- if(sculpt_stroke_final_length(stroke) > min_len) {
- StrokePoint *p = sculpt_stroke_apply_generic(sd, stroke, partial_len);
-
- /* Replace remaining values in stroke->loc with remaining stroke->final values */
- stroke->index = -1;
- stroke->length = 0;
- for(; p; p = p->next) {
- ++stroke->index;
- stroke->loc[stroke->index][0] = p->x;
- stroke->loc[stroke->index][1] = p->y;
- if(p->next) {
- stroke->length += sculpt_stroke_seglen(p, p->next);
- }
- }
- }
- }
-}
-
-void sculpt_stroke_apply_all(Sculpt *sd, SculptStroke *stroke)
-{
- sculpt_stroke_create_final(stroke);
-
- if(stroke) {
- sculpt_stroke_apply_generic(sd, stroke, 0);
- }
-}
-
-/* XXX: drawing goes elsewhere */
-void sculpt_stroke_draw(SculptStroke *stroke)
-{
- if(stroke) {
- StrokePoint *p;
-
- /* Draws the original stroke */
- /*glColor3f(1, 0, 0);
- glBegin(GL_LINE_STRIP);
- for(i = 0; i <= stroke->index; ++i)
- glVertex2s(stroke->loc[i][0], stroke->loc[i][1]);
- glEnd();*/
-
- /* Draws the smoothed stroke */
- glColor3f(0, 1, 0);
- glBegin(GL_LINE_STRIP);
- for(p = stroke->final.first; p; p = p->next)
- glVertex2s(p->x, p->y);
- glEnd();
- }
-}