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:
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_utils.c')
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c322
1 files changed, 312 insertions, 10 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 25308f6595e..f34d0ff3f7b 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -35,23 +35,28 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
+#include "DNA_material_types.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
#include "BLI_math.h"
+#include "BLI_math_color.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BLI_rect.h"
#include "BLF_translation.h"
+#include "BKE_scene.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_material.h"
#include "BKE_image.h"
#include "BKE_paint.h"
#include "BKE_report.h"
+#include "BKE_image.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -67,6 +72,10 @@
#include "ED_view3d.h"
#include "ED_screen.h"
+#include "ED_uvedit.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
#include "BLI_sys_types.h"
#include "ED_mesh.h" /* for face mask functions */
@@ -205,6 +214,192 @@ void paint_get_tex_pixel_col(MTex *mtex, float u, float v, float rgba[4], struct
CLAMP(rgba[3], 0.0f, 1.0f);
}
+void paint_stroke_operator_properties(wmOperatorType *ot)
+{
+ static EnumPropertyItem stroke_mode_items[] = {
+ {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally"},
+ {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"},
+ {BRUSH_STROKE_SMOOTH, "SMOOTH", 0, "Smooth", "Switch brush to smooth mode for duration of stroke"},
+ {0}
+ };
+
+ RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+
+ RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL,
+ "Stroke Mode",
+ "Action taken when a paint stroke is made");
+
+}
+
+/* 3D Paint */
+
+static void imapaint_project(float matrix[4][4], const float co[3], float pco[4])
+{
+ copy_v3_v3(pco, co);
+ pco[3] = 1.0f;
+
+ mul_m4_v4(matrix, pco);
+}
+
+static void imapaint_tri_weights(float matrix[4][4], GLint view[4],
+ const float v1[3], const float v2[3], const float v3[3],
+ const float co[2], float w[3])
+{
+ float pv1[4], pv2[4], pv3[4], h[3], divw;
+ float wmat[3][3], invwmat[3][3];
+
+ /* compute barycentric coordinates */
+
+ /* project the verts */
+ imapaint_project(matrix, v1, pv1);
+ imapaint_project(matrix, v2, pv2);
+ imapaint_project(matrix, v3, pv3);
+
+ /* do inverse view mapping, see gluProject man page */
+ h[0] = (co[0] - view[0]) * 2.0f / view[2] - 1.0f;
+ h[1] = (co[1] - view[1]) * 2.0f / view[3] - 1.0f;
+ h[2] = 1.0f;
+
+ /* solve for (w1,w2,w3)/perspdiv in:
+ * h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3) */
+
+ wmat[0][0] = pv1[0]; wmat[1][0] = pv2[0]; wmat[2][0] = pv3[0];
+ wmat[0][1] = pv1[1]; wmat[1][1] = pv2[1]; wmat[2][1] = pv3[1];
+ wmat[0][2] = pv1[3]; wmat[1][2] = pv2[3]; wmat[2][2] = pv3[3];
+
+ invert_m3_m3(invwmat, wmat);
+ mul_m3_v3(invwmat, h);
+
+ copy_v3_v3(w, h);
+
+ /* w is still divided by perspdiv, make it sum to one */
+ divw = w[0] + w[1] + w[2];
+ if (divw != 0.0f) {
+ mul_v3_fl(w, 1.0f / divw);
+ }
+}
+
+/* compute uv coordinates of mouse in face */
+static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const int xy[2], float uv[2])
+{
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ MTFace *tf_base, *tf;
+ Material *ma;
+ TexPaintSlot *slot;
+ int numfaces = dm->getNumTessFaces(dm), a, findex;
+ float p[2], w[3], absw, minabsw;
+ MFace mf;
+ MVert mv[4];
+ float matrix[4][4], proj[4][4];
+ GLint view[4];
+
+ /* compute barycentric coordinates */
+
+ /* double lookup */
+ const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ if (index_mf_to_mpoly == NULL) {
+ index_mp_to_orig = NULL;
+ }
+
+ /* get the needed opengl matrices */
+ glGetIntegerv(GL_VIEWPORT, view);
+ glGetFloatv(GL_MODELVIEW_MATRIX, (float *)matrix);
+ glGetFloatv(GL_PROJECTION_MATRIX, (float *)proj);
+ view[0] = view[1] = 0;
+ mul_m4_m4m4(matrix, matrix, ob->obmat);
+ mul_m4_m4m4(matrix, proj, matrix);
+
+ minabsw = 1e10;
+ uv[0] = uv[1] = 0.0;
+
+ /* test all faces in the derivedmesh with the original index of the picked face */
+ for (a = 0; a < numfaces; a++) {
+ findex = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
+
+ if (findex == faceindex) {
+ dm->getTessFace(dm, a, &mf);
+
+ ma = dm->mat[mf.mat_nr];
+ slot = &ma->texpaintslot[ma->paint_active_slot];
+
+ dm->getVert(dm, mf.v1, &mv[0]);
+ dm->getVert(dm, mf.v2, &mv[1]);
+ dm->getVert(dm, mf.v3, &mv[2]);
+ if (mf.v4)
+ dm->getVert(dm, mf.v4, &mv[3]);
+
+ if (!(slot && slot->uvname && (tf_base = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, slot->uvname))))
+ tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE);
+
+ tf = &tf_base[a];
+
+ p[0] = xy[0];
+ p[1] = xy[1];
+
+ if (mf.v4) {
+ /* the triangle with the largest absolute values is the one
+ * with the most negative weights */
+ imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[3].co, p, w);
+ absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
+ if (absw < minabsw) {
+ uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[3][0] * w[2];
+ uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[3][1] * w[2];
+ minabsw = absw;
+ }
+
+ imapaint_tri_weights(matrix, view, mv[1].co, mv[2].co, mv[3].co, p, w);
+ absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
+ if (absw < minabsw) {
+ uv[0] = tf->uv[1][0] * w[0] + tf->uv[2][0] * w[1] + tf->uv[3][0] * w[2];
+ uv[1] = tf->uv[1][1] * w[0] + tf->uv[2][1] * w[1] + tf->uv[3][1] * w[2];
+ minabsw = absw;
+ }
+ }
+ else {
+ imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[2].co, p, w);
+ absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
+ if (absw < minabsw) {
+ uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[2][0] * w[2];
+ uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[2][1] * w[2];
+ minabsw = absw;
+ }
+ }
+ }
+ }
+
+ dm->release(dm);
+}
+
+/* returns 0 if not found, otherwise 1 */
+static int imapaint_pick_face(ViewContext *vc, const int mval[2], unsigned int *r_index, unsigned int totface)
+{
+ if (totface == 0)
+ return 0;
+
+ /* sample only on the exact position */
+ *r_index = view3d_sample_backbuf(vc, mval[0], mval[1]);
+
+ if ((*r_index) == 0 || (*r_index) > (unsigned int)totface) {
+ return 0;
+ }
+
+ (*r_index)--;
+
+ return 1;
+}
+
+
+static Image *imapaint_face_image(DerivedMesh *dm, int face_index)
+{
+ Image *ima;
+ MFace *mf = dm->getTessFaceArray(dm) + face_index;
+ Material *ma = dm->mat[mf->mat_nr];
+ ima = ma->texpaintslot[ma->paint_active_slot].ima;
+
+ return ima;
+}
+
/* Uses symm to selectively flip any axis of a coordinate. */
void flip_v3_v3(float out[3], const float in[3], const char symm)
{
@@ -223,25 +418,132 @@ void flip_v3_v3(float out[3], const float in[3], const char symm)
}
/* used for both 3d view and image window */
-void paint_sample_color(const bContext *C, ARegion *ar, int x, int y) /* frontbuf */
+void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_proj, bool use_palette)
{
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Palette *palette = BKE_paint_palette(paint);
+ PaletteColor *color;
Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
unsigned int col;
- const char *cp;
+ const unsigned char *cp;
CLAMP(x, 0, ar->winx);
CLAMP(y, 0, ar->winy);
- glReadBuffer(GL_FRONT);
- glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
- glReadBuffer(GL_BACK);
+ if (use_palette) {
+ if (!palette) {
+ palette = BKE_palette_add(CTX_data_main(C), "Palette");
+ BKE_paint_palette_set(paint, palette);
+ }
- cp = (char *)&col;
+ color = BKE_palette_color_add(palette);
+ }
+
+
+ if (CTX_wm_view3d(C) && texpaint_proj) {
+ /* first try getting a colour directly from the mesh faces if possible */
+ Object *ob = OBACT;
+ bool sample_success = false;
+ ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
+ bool use_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL);
+
+ if (ob) {
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+
+ ViewContext vc;
+ const int mval[2] = {x, y};
+ unsigned int faceindex;
+ unsigned int totface = dm->getNumTessFaces(dm);
+ MTFace *dm_mtface = dm->getTessFaceDataArray(dm, CD_MTFACE);
+
+ DM_update_materials(dm, ob);
+
+ if (dm_mtface) {
+ view3d_set_viewcontext(C, &vc);
+
+ view3d_operator_needs_opengl(C);
+
+ if (imapaint_pick_face(&vc, mval, &faceindex, totface)) {
+ Image *image;
+
+ if (use_material)
+ image = imapaint_face_image(dm, faceindex);
+ else
+ image = imapaint->canvas;
+
+ if (image) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+ if (ibuf && ibuf->rect) {
+ float uv[2];
+ float u, v;
+ imapaint_pick_uv(scene, ob, faceindex, mval, uv);
+ sample_success = true;
+
+ u = fmodf(uv[0], 1.0f);
+ v = fmodf(uv[1], 1.0f);
+
+ if (u < 0.0f) u += 1.0f;
+ if (v < 0.0f) v += 1.0f;
+
+ u = u * ibuf->x - 0.5f;
+ v = v * ibuf->y - 0.5f;
+
+ if (ibuf->rect_float) {
+ float rgba_f[4];
+ bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
+ straight_to_premul_v4(rgba_f);
+ if (use_palette) {
+ linearrgb_to_srgb_v3_v3(color->rgb, rgba_f);
+ }
+ else {
+ linearrgb_to_srgb_v3_v3(rgba_f, rgba_f);
+ BKE_brush_color_set(scene, br, rgba_f);
+ }
+ }
+ else {
+ unsigned char rgba[4];
+ bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
+ if (use_palette) {
+ rgb_uchar_to_float(color->rgb, rgba);
+ }
+ else {
+ float rgba_f[3];
+ rgb_uchar_to_float(rgba_f, rgba);
+ BKE_brush_color_set(scene, br, rgba_f);
+ }
+ }
+ }
+
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+ }
+ }
+ dm->release(dm);
+ }
+
+ if (!sample_success) {
+ glReadBuffer(GL_FRONT);
+ glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
+ glReadBuffer(GL_BACK);
+ }
+ else
+ return;
+ }
+ else {
+ glReadBuffer(GL_FRONT);
+ glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
+ glReadBuffer(GL_BACK);
+ }
+ cp = (unsigned char *)&col;
- if (br) {
- br->rgb[0] = cp[0] / 255.0f;
- br->rgb[1] = cp[1] / 255.0f;
- br->rgb[2] = cp[2] / 255.0f;
+ if (use_palette) {
+ rgb_uchar_to_float(color->rgb, cp);
+ }
+ else {
+ float rgba_f[3];
+ rgb_uchar_to_float(rgba_f, cp);
+ BKE_brush_color_set(scene, br, rgba_f);
}
}