2012-01-19 02:06:09 +00:00
|
|
|
/*
|
|
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is Copyright (C) 2009 by Nicholas Bishop
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Contributor(s): Jason Wilkins, Tom Musgrove.
|
|
|
|
|
*
|
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** \file blender/editors/sculpt_paint/paint_cursor.c
|
|
|
|
|
* \ingroup edsculpt
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
|
|
#include "BLI_math.h"
|
2012-08-21 20:34:05 +00:00
|
|
|
#include "BLI_rect.h"
|
2016-01-17 17:16:57 +01:00
|
|
|
#include "BLI_task.h"
|
2012-01-19 02:06:09 +00:00
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
|
|
|
|
|
|
#include "DNA_brush_types.h"
|
2013-05-30 02:16:22 +00:00
|
|
|
#include "DNA_customdata_types.h"
|
2012-01-19 02:06:09 +00:00
|
|
|
#include "DNA_color_types.h"
|
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
|
#include "DNA_screen_types.h"
|
|
|
|
|
#include "DNA_userdef_types.h"
|
2017-10-05 17:35:46 +11:00
|
|
|
#include "DNA_view3d_types.h"
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
#include "BKE_brush.h"
|
|
|
|
|
#include "BKE_context.h"
|
2014-07-21 12:02:05 +02:00
|
|
|
#include "BKE_curve.h"
|
2013-01-21 08:49:42 +00:00
|
|
|
#include "BKE_image.h"
|
2014-03-27 12:09:50 +02:00
|
|
|
#include "BKE_node.h"
|
2012-01-19 02:06:09 +00:00
|
|
|
#include "BKE_paint.h"
|
2013-04-12 21:58:18 +00:00
|
|
|
#include "BKE_colortools.h"
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
|
|
|
|
|
|
#include "BIF_gl.h"
|
|
|
|
|
#include "BIF_glutil.h"
|
|
|
|
|
|
2014-04-13 17:20:06 +03:00
|
|
|
#include "IMB_imbuf_types.h"
|
|
|
|
|
|
2012-01-19 02:06:09 +00:00
|
|
|
#include "ED_view3d.h"
|
|
|
|
|
|
2015-12-05 22:11:31 +01:00
|
|
|
#include "GPU_basic_shader.h"
|
2015-11-28 01:20:28 +01:00
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
#include "UI_resources.h"
|
|
|
|
|
|
2012-01-19 02:06:09 +00:00
|
|
|
#include "paint_intern.h"
|
|
|
|
|
/* still needed for sculpt_stroke_get_location, should be
|
2012-03-03 16:31:46 +00:00
|
|
|
* removed eventually (TODO) */
|
2012-01-19 02:06:09 +00:00
|
|
|
#include "sculpt_intern.h"
|
|
|
|
|
|
|
|
|
|
/* TODOs:
|
2012-03-03 16:31:46 +00:00
|
|
|
*
|
|
|
|
|
* Some of the cursor drawing code is doing non-draw stuff
|
|
|
|
|
* (e.g. updating the brush rake angle). This should be cleaned up
|
|
|
|
|
* still.
|
|
|
|
|
*
|
|
|
|
|
* There is also some ugliness with sculpt-specific code.
|
2012-01-19 02:06:09 +00:00
|
|
|
*/
|
|
|
|
|
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
typedef struct TexSnapshot {
|
2013-04-22 20:46:18 +00:00
|
|
|
GLuint overlay_texture;
|
2012-01-19 02:06:09 +00:00
|
|
|
int winx;
|
|
|
|
|
int winy;
|
2013-04-22 20:46:18 +00:00
|
|
|
int old_size;
|
2013-04-30 21:17:21 +00:00
|
|
|
float old_zoom;
|
2013-04-22 20:46:18 +00:00
|
|
|
bool old_col;
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
} TexSnapshot;
|
|
|
|
|
|
2013-10-09 16:00:15 +00:00
|
|
|
typedef struct CursorSnapshot {
|
|
|
|
|
GLuint overlay_texture;
|
|
|
|
|
int size;
|
|
|
|
|
int zoom;
|
|
|
|
|
} CursorSnapshot;
|
|
|
|
|
|
|
|
|
|
static TexSnapshot primary_snap = {0};
|
|
|
|
|
static TexSnapshot secondary_snap = {0};
|
|
|
|
|
static CursorSnapshot cursor_snap = {0};
|
|
|
|
|
|
|
|
|
|
/* delete overlay cursor textures to preserve memory and invalidate all overlay flags */
|
2013-10-10 17:28:01 +00:00
|
|
|
void paint_cursor_delete_textures(void)
|
2013-10-09 16:00:15 +00:00
|
|
|
{
|
2013-10-12 00:08:33 +00:00
|
|
|
if (primary_snap.overlay_texture)
|
|
|
|
|
glDeleteTextures(1, &primary_snap.overlay_texture);
|
|
|
|
|
if (secondary_snap.overlay_texture)
|
|
|
|
|
glDeleteTextures(1, &secondary_snap.overlay_texture);
|
|
|
|
|
if (cursor_snap.overlay_texture)
|
|
|
|
|
glDeleteTextures(1, &cursor_snap.overlay_texture);
|
2013-10-09 16:00:15 +00:00
|
|
|
|
|
|
|
|
memset(&primary_snap, 0, sizeof(TexSnapshot));
|
|
|
|
|
memset(&secondary_snap, 0, sizeof(TexSnapshot));
|
2013-10-09 16:53:35 +00:00
|
|
|
memset(&cursor_snap, 0, sizeof(CursorSnapshot));
|
2013-10-09 16:00:15 +00:00
|
|
|
|
|
|
|
|
BKE_paint_invalidate_overlay_all();
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
static int same_tex_snap(TexSnapshot *snap, MTex *mtex, ViewContext *vc, bool col, float zoom)
|
2012-01-19 02:06:09 +00:00
|
|
|
{
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
return (/* make brush smaller shouldn't cause a resample */
|
|
|
|
|
//(mtex->brush_map_mode != MTEX_MAP_MODE_VIEW ||
|
|
|
|
|
//(BKE_brush_size_get(vc->scene, brush) <= snap->BKE_brush_size_get)) &&
|
2012-03-28 03:47:33 +00:00
|
|
|
|
2013-04-13 00:43:49 +00:00
|
|
|
(mtex->brush_map_mode != MTEX_MAP_MODE_TILED ||
|
2013-04-23 05:29:06 +00:00
|
|
|
(vc->ar->winx == snap->winx &&
|
|
|
|
|
vc->ar->winy == snap->winy)) &&
|
2013-04-30 21:17:21 +00:00
|
|
|
(mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL ||
|
|
|
|
|
snap->old_zoom == zoom) &&
|
2013-04-23 05:29:06 +00:00
|
|
|
snap->old_col == col
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
);
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
static void make_tex_snap(TexSnapshot *snap, ViewContext *vc, float zoom)
|
2012-01-19 02:06:09 +00:00
|
|
|
{
|
2013-04-22 20:46:18 +00:00
|
|
|
snap->old_zoom = zoom;
|
2012-01-19 02:06:09 +00:00
|
|
|
snap->winx = vc->ar->winx;
|
|
|
|
|
snap->winy = vc->ar->winy;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-17 17:16:57 +01:00
|
|
|
typedef struct LoadTexData {
|
|
|
|
|
Brush *br;
|
|
|
|
|
ViewContext *vc;
|
|
|
|
|
|
|
|
|
|
MTex *mtex;
|
|
|
|
|
GLubyte *buffer;
|
|
|
|
|
bool col;
|
|
|
|
|
|
|
|
|
|
struct ImagePool *pool;
|
|
|
|
|
int size;
|
|
|
|
|
float rotation;
|
|
|
|
|
float radius;
|
|
|
|
|
} LoadTexData;
|
|
|
|
|
|
2018-01-05 16:33:13 +01:00
|
|
|
static void load_tex_task_cb_ex(void *userdata, const int j, const ParallelRangeTLS *tls)
|
2016-01-17 17:16:57 +01:00
|
|
|
{
|
|
|
|
|
LoadTexData *data = userdata;
|
|
|
|
|
Brush *br = data->br;
|
|
|
|
|
ViewContext *vc = data->vc;
|
|
|
|
|
|
|
|
|
|
MTex *mtex = data->mtex;
|
|
|
|
|
GLubyte *buffer = data->buffer;
|
|
|
|
|
const bool col = data->col;
|
|
|
|
|
|
|
|
|
|
struct ImagePool *pool = data->pool;
|
|
|
|
|
const int size = data->size;
|
|
|
|
|
const float rotation = data->rotation;
|
|
|
|
|
const float radius = data->radius;
|
|
|
|
|
|
|
|
|
|
bool convert_to_linear = false;
|
|
|
|
|
struct ColorSpace *colorspace = NULL;
|
|
|
|
|
|
2016-01-25 16:55:08 +01:00
|
|
|
if (mtex->tex && mtex->tex->type == TEX_IMAGE && mtex->tex->ima) {
|
2016-01-17 17:16:57 +01:00
|
|
|
ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(mtex->tex->ima, &mtex->tex->iuser, pool);
|
|
|
|
|
/* For consistency, sampling always returns color in linear space */
|
|
|
|
|
if (tex_ibuf && tex_ibuf->rect_float == NULL) {
|
|
|
|
|
convert_to_linear = true;
|
|
|
|
|
colorspace = tex_ibuf->rect_colorspace;
|
|
|
|
|
}
|
|
|
|
|
BKE_image_pool_release_ibuf(mtex->tex->ima, tex_ibuf, pool);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
|
// largely duplicated from tex_strength
|
|
|
|
|
|
|
|
|
|
int index = j * size + i;
|
|
|
|
|
|
|
|
|
|
float x = (float)i / size;
|
|
|
|
|
float y = (float)j / size;
|
|
|
|
|
float len;
|
|
|
|
|
|
|
|
|
|
if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
|
|
|
|
|
x *= vc->ar->winx / radius;
|
|
|
|
|
y *= vc->ar->winy / radius;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
x = (x - 0.5f) * 2.0f;
|
|
|
|
|
y = (y - 0.5f) * 2.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len = sqrtf(x * x + y * y);
|
|
|
|
|
|
|
|
|
|
if (ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL) || len <= 1.0f) {
|
|
|
|
|
/* it is probably worth optimizing for those cases where the texture is not rotated by skipping the calls to
|
|
|
|
|
* atan2, sqrtf, sin, and cos. */
|
|
|
|
|
if (mtex->tex && (rotation > 0.001f || rotation < -0.001f)) {
|
|
|
|
|
const float angle = atan2f(y, x) + rotation;
|
|
|
|
|
|
|
|
|
|
x = len * cosf(angle);
|
|
|
|
|
y = len * sinf(angle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (col) {
|
|
|
|
|
float rgba[4];
|
|
|
|
|
|
2018-01-05 16:33:13 +01:00
|
|
|
paint_get_tex_pixel_col(mtex, x, y, rgba, pool, tls->thread_id, convert_to_linear, colorspace);
|
2016-01-17 17:16:57 +01:00
|
|
|
|
|
|
|
|
buffer[index * 4] = rgba[0] * 255;
|
|
|
|
|
buffer[index * 4 + 1] = rgba[1] * 255;
|
|
|
|
|
buffer[index * 4 + 2] = rgba[2] * 255;
|
|
|
|
|
buffer[index * 4 + 3] = rgba[3] * 255;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2018-01-05 16:33:13 +01:00
|
|
|
float avg = paint_get_tex_pixel(mtex, x, y, pool, tls->thread_id);
|
2016-01-17 17:16:57 +01:00
|
|
|
|
|
|
|
|
avg += br->texture_sample_bias;
|
|
|
|
|
|
|
|
|
|
/* clamp to avoid precision overflow */
|
|
|
|
|
CLAMP(avg, 0.0f, 1.0f);
|
|
|
|
|
buffer[index] = 255 - (GLubyte)(255 * avg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (col) {
|
|
|
|
|
buffer[index * 4] = 0;
|
|
|
|
|
buffer[index * 4 + 1] = 0;
|
|
|
|
|
buffer[index * 4 + 2] = 0;
|
|
|
|
|
buffer[index * 4 + 3] = 0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
buffer[index] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool primary)
|
2012-01-19 02:06:09 +00:00
|
|
|
{
|
2013-10-09 16:00:15 +00:00
|
|
|
bool init;
|
2013-04-22 20:46:18 +00:00
|
|
|
TexSnapshot *target;
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
MTex *mtex = (primary) ? &br->mtex : &br->mask_mtex;
|
2017-10-17 13:43:10 +11:00
|
|
|
eOverlayControlFlags overlay_flags = BKE_paint_get_overlay_flags();
|
2012-03-28 03:47:33 +00:00
|
|
|
GLubyte *buffer = NULL;
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
int size;
|
2016-01-17 17:16:57 +01:00
|
|
|
bool refresh;
|
2017-10-17 13:43:10 +11:00
|
|
|
eOverlayControlFlags invalid = (primary) ? (overlay_flags & PAINT_INVALID_OVERLAY_TEXTURE_PRIMARY) :
|
2016-01-17 17:16:57 +01:00
|
|
|
(overlay_flags & PAINT_INVALID_OVERLAY_TEXTURE_SECONDARY);
|
2013-04-22 20:46:18 +00:00
|
|
|
|
|
|
|
|
target = (primary) ? &primary_snap : &secondary_snap;
|
2013-10-09 16:00:15 +00:00
|
|
|
|
2012-01-19 02:06:09 +00:00
|
|
|
refresh =
|
2013-04-22 20:46:18 +00:00
|
|
|
!target->overlay_texture ||
|
|
|
|
|
(invalid != 0) ||
|
|
|
|
|
!same_tex_snap(target, mtex, vc, col, zoom);
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2013-10-09 16:00:15 +00:00
|
|
|
init = (target->overlay_texture != 0);
|
|
|
|
|
|
2012-01-19 02:06:09 +00:00
|
|
|
if (refresh) {
|
2013-01-21 08:49:42 +00:00
|
|
|
struct ImagePool *pool = NULL;
|
2013-03-31 00:38:50 +00:00
|
|
|
/* stencil is rotated later */
|
2016-01-17 17:16:57 +01:00
|
|
|
const float rotation = (mtex->brush_map_mode != MTEX_MAP_MODE_STENCIL) ? -mtex->rot : 0.0f;
|
|
|
|
|
const float radius = BKE_brush_size_get(vc->scene, br) * zoom;
|
2013-01-21 08:49:42 +00:00
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
make_tex_snap(target, vc, zoom);
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
|
2012-05-05 00:58:22 +00:00
|
|
|
int s = BKE_brush_size_get(vc->scene, br);
|
2012-01-19 02:06:09 +00:00
|
|
|
int r = 1;
|
|
|
|
|
|
|
|
|
|
for (s >>= 1; s > 0; s >>= 1)
|
|
|
|
|
r++;
|
|
|
|
|
|
2012-03-28 03:47:33 +00:00
|
|
|
size = (1 << r);
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
if (size < 256)
|
|
|
|
|
size = 256;
|
|
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
if (size < target->old_size)
|
|
|
|
|
size = target->old_size;
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
2016-01-17 17:16:57 +01:00
|
|
|
else {
|
2012-01-19 02:06:09 +00:00
|
|
|
size = 512;
|
2016-01-17 17:16:57 +01:00
|
|
|
}
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
if (target->old_size != size) {
|
|
|
|
|
if (target->overlay_texture) {
|
|
|
|
|
glDeleteTextures(1, &target->overlay_texture);
|
|
|
|
|
target->overlay_texture = 0;
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-09 16:00:15 +00:00
|
|
|
init = false;
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
target->old_size = size;
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
2013-03-31 00:38:50 +00:00
|
|
|
if (col)
|
|
|
|
|
buffer = MEM_mallocN(sizeof(GLubyte) * size * size * 4, "load_tex");
|
|
|
|
|
else
|
|
|
|
|
buffer = MEM_mallocN(sizeof(GLubyte) * size * size, "load_tex");
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2013-04-23 11:02:36 +00:00
|
|
|
pool = BKE_image_pool_new();
|
2013-01-21 08:49:42 +00:00
|
|
|
|
2014-03-27 12:09:50 +02:00
|
|
|
if (mtex->tex && mtex->tex->nodetree)
|
|
|
|
|
ntreeTexBeginExecTree(mtex->tex->nodetree); /* has internal flag to detect it only does it once */
|
|
|
|
|
|
2016-01-17 17:16:57 +01:00
|
|
|
LoadTexData data = {
|
|
|
|
|
.br = br, .vc = vc, .mtex = mtex, .buffer = buffer, .col = col,
|
|
|
|
|
.pool = pool, .size = size, .rotation = rotation, .radius = radius,
|
|
|
|
|
};
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2016-01-17 17:16:57 +01:00
|
|
|
BLI_task_parallel_range_ex(0, size, &data, NULL, 0, load_tex_task_cb_ex, true, false);
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2014-03-27 12:09:50 +02:00
|
|
|
if (mtex->tex && mtex->tex->nodetree)
|
|
|
|
|
ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
|
|
|
|
|
|
2013-01-21 08:49:42 +00:00
|
|
|
if (pool)
|
|
|
|
|
BKE_image_pool_free(pool);
|
|
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
if (!target->overlay_texture)
|
|
|
|
|
glGenTextures(1, &target->overlay_texture);
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2013-04-22 20:46:18 +00:00
|
|
|
size = target->old_size;
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, target->overlay_texture);
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
if (refresh) {
|
2015-12-08 01:19:08 -05:00
|
|
|
GLenum format = col ? GL_RGBA : GL_ALPHA;
|
|
|
|
|
GLenum internalformat = col ? GL_RGBA8 : GL_ALPHA8;
|
|
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
if (!init || (target->old_col != col)) {
|
2015-12-08 22:52:51 +11:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, size, size, 0, format, GL_UNSIGNED_BYTE, buffer);
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2013-03-31 00:38:50 +00:00
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, format, GL_UNSIGNED_BYTE, buffer);
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (buffer)
|
|
|
|
|
MEM_freeN(buffer);
|
2013-03-31 00:38:50 +00:00
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
target->old_col = col;
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-05 22:11:31 +01:00
|
|
|
GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
|
2015-02-18 11:59:55 +01:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
BKE_paint_reset_overlay_invalid(invalid);
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
|
2012-01-19 02:06:09 +00:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-05 16:33:13 +01:00
|
|
|
static void load_tex_cursor_task_cb(void *userdata, const int j, const ParallelRangeTLS *UNUSED(tls))
|
2016-01-17 17:16:57 +01:00
|
|
|
{
|
|
|
|
|
LoadTexData *data = userdata;
|
|
|
|
|
Brush *br = data->br;
|
|
|
|
|
|
|
|
|
|
GLubyte *buffer = data->buffer;
|
|
|
|
|
|
|
|
|
|
const int size = data->size;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
|
// largely duplicated from tex_strength
|
|
|
|
|
|
|
|
|
|
const int index = j * size + i;
|
|
|
|
|
const float x = (((float)i / size) - 0.5f) * 2.0f;
|
|
|
|
|
const float y = (((float)j / size) - 0.5f) * 2.0f;
|
|
|
|
|
const float len = sqrtf(x * x + y * y);
|
|
|
|
|
|
|
|
|
|
if (len <= 1.0f) {
|
|
|
|
|
float avg = BKE_brush_curve_strength_clamped(br, len, 1.0f); /* Falloff curve */
|
|
|
|
|
|
|
|
|
|
buffer[index] = 255 - (GLubyte)(255 * avg);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
buffer[index] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
|
|
|
|
|
{
|
2013-10-09 16:00:15 +00:00
|
|
|
bool init;
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2017-10-17 13:43:10 +11:00
|
|
|
eOverlayControlFlags overlay_flags = BKE_paint_get_overlay_flags();
|
2013-04-22 20:46:18 +00:00
|
|
|
GLubyte *buffer = NULL;
|
|
|
|
|
|
|
|
|
|
int size;
|
2016-01-17 17:16:57 +01:00
|
|
|
const bool refresh =
|
2013-10-09 16:00:15 +00:00
|
|
|
!cursor_snap.overlay_texture ||
|
2013-04-22 20:46:18 +00:00
|
|
|
(overlay_flags & PAINT_INVALID_OVERLAY_CURVE) ||
|
2013-10-09 16:00:15 +00:00
|
|
|
cursor_snap.zoom != zoom;
|
|
|
|
|
|
|
|
|
|
init = (cursor_snap.overlay_texture != 0);
|
2013-04-22 20:46:18 +00:00
|
|
|
|
|
|
|
|
if (refresh) {
|
|
|
|
|
int s, r;
|
|
|
|
|
|
2013-10-09 16:00:15 +00:00
|
|
|
cursor_snap.zoom = zoom;
|
2013-04-22 20:46:18 +00:00
|
|
|
|
|
|
|
|
s = BKE_brush_size_get(vc->scene, br);
|
|
|
|
|
r = 1;
|
|
|
|
|
|
|
|
|
|
for (s >>= 1; s > 0; s >>= 1)
|
|
|
|
|
r++;
|
|
|
|
|
|
|
|
|
|
size = (1 << r);
|
|
|
|
|
|
|
|
|
|
if (size < 256)
|
|
|
|
|
size = 256;
|
|
|
|
|
|
2013-10-09 16:00:15 +00:00
|
|
|
if (size < cursor_snap.size)
|
|
|
|
|
size = cursor_snap.size;
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2013-10-09 16:00:15 +00:00
|
|
|
if (cursor_snap.size != size) {
|
|
|
|
|
if (cursor_snap.overlay_texture) {
|
|
|
|
|
glDeleteTextures(1, &cursor_snap.overlay_texture);
|
|
|
|
|
cursor_snap.overlay_texture = 0;
|
2013-04-22 20:46:18 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-09 16:00:15 +00:00
|
|
|
init = false;
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2013-10-09 16:00:15 +00:00
|
|
|
cursor_snap.size = size;
|
2013-04-22 20:46:18 +00:00
|
|
|
}
|
|
|
|
|
buffer = MEM_mallocN(sizeof(GLubyte) * size * size, "load_tex");
|
|
|
|
|
|
|
|
|
|
curvemapping_initialize(br->curve);
|
|
|
|
|
|
2016-01-17 17:16:57 +01:00
|
|
|
LoadTexData data = {
|
|
|
|
|
.br = br, .buffer = buffer, .size = size,
|
|
|
|
|
};
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2016-01-17 17:16:57 +01:00
|
|
|
BLI_task_parallel_range(0, size, &data, load_tex_cursor_task_cb, true);
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2013-10-09 16:00:15 +00:00
|
|
|
if (!cursor_snap.overlay_texture)
|
|
|
|
|
glGenTextures(1, &cursor_snap.overlay_texture);
|
2013-04-22 20:46:18 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2013-10-09 16:00:15 +00:00
|
|
|
size = cursor_snap.size;
|
2013-04-22 20:46:18 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-09 16:00:15 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, cursor_snap.overlay_texture);
|
2013-04-22 20:46:18 +00:00
|
|
|
|
|
|
|
|
if (refresh) {
|
|
|
|
|
if (!init) {
|
2015-12-08 01:19:08 -05:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, size, size, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);
|
2013-04-22 20:46:18 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (buffer)
|
|
|
|
|
MEM_freeN(buffer);
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-05 22:11:31 +01:00
|
|
|
GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
|
2013-04-22 20:46:18 +00:00
|
|
|
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
|
|
2015-02-18 11:59:55 +01:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
2013-04-22 20:46:18 +00:00
|
|
|
|
|
|
|
|
BKE_paint_reset_overlay_invalid(PAINT_INVALID_OVERLAY_CURVE);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-01-19 02:06:09 +00:00
|
|
|
static int project_brush_radius(ViewContext *vc,
|
2012-03-28 03:47:33 +00:00
|
|
|
float radius,
|
|
|
|
|
const float location[3])
|
2012-01-19 02:06:09 +00:00
|
|
|
{
|
|
|
|
|
float view[3], nonortho[3], ortho[3], offset[3], p1[2], p2[2];
|
|
|
|
|
|
|
|
|
|
ED_view3d_global_to_vector(vc->rv3d, location, view);
|
|
|
|
|
|
2012-07-06 23:56:59 +00:00
|
|
|
/* create a vector that is not orthogonal to view */
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
if (fabsf(view[0]) < 0.1f) {
|
|
|
|
|
nonortho[0] = view[0] + 1.0f;
|
|
|
|
|
nonortho[1] = view[1];
|
|
|
|
|
nonortho[2] = view[2];
|
|
|
|
|
}
|
|
|
|
|
else if (fabsf(view[1]) < 0.1f) {
|
|
|
|
|
nonortho[0] = view[0];
|
|
|
|
|
nonortho[1] = view[1] + 1.0f;
|
|
|
|
|
nonortho[2] = view[2];
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
nonortho[0] = view[0];
|
|
|
|
|
nonortho[1] = view[1];
|
|
|
|
|
nonortho[2] = view[2] + 1.0f;
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-06 23:56:59 +00:00
|
|
|
/* get a vector in the plane of the view */
|
2012-01-19 02:06:09 +00:00
|
|
|
cross_v3_v3v3(ortho, nonortho, view);
|
|
|
|
|
normalize_v3(ortho);
|
|
|
|
|
|
2012-07-06 23:56:59 +00:00
|
|
|
/* make a point on the surface of the brush tagent to the view */
|
2012-01-19 02:06:09 +00:00
|
|
|
mul_v3_fl(ortho, radius);
|
|
|
|
|
add_v3_v3v3(offset, location, ortho);
|
|
|
|
|
|
2012-07-06 23:56:59 +00:00
|
|
|
/* project the center of the brush, and the tangent point to the view onto the screen */
|
2012-10-07 14:00:18 +00:00
|
|
|
if ((ED_view3d_project_float_global(vc->ar, location, p1, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
|
|
|
|
|
(ED_view3d_project_float_global(vc->ar, offset, p2, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
|
2012-10-05 03:20:14 +00:00
|
|
|
{
|
|
|
|
|
/* the distance between these points is the size of the projected brush in pixels */
|
|
|
|
|
return len_v2v2(p1, p2);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_assert(0); /* assert because the code that sets up the vectors should disallow this */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
2014-10-07 13:58:35 +02:00
|
|
|
static bool sculpt_get_brush_geometry(
|
|
|
|
|
bContext *C, ViewContext *vc,
|
|
|
|
|
int x, int y, int *pixel_radius,
|
2015-11-24 21:40:18 +01:00
|
|
|
float location[3], UnifiedPaintSettings *ups)
|
2012-01-19 02:06:09 +00:00
|
|
|
{
|
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
Paint *paint = BKE_paint_get_active_from_context(C);
|
2013-03-04 22:55:53 +00:00
|
|
|
float mouse[2];
|
2015-11-24 21:40:18 +01:00
|
|
|
bool hit = false;
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2013-03-04 22:55:53 +00:00
|
|
|
mouse[0] = x;
|
|
|
|
|
mouse[1] = y;
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2015-11-26 11:08:25 +11:00
|
|
|
if (vc->obact->sculpt && vc->obact->sculpt->pbvh) {
|
2015-11-24 21:40:18 +01:00
|
|
|
if (!ups->stroke_active) {
|
|
|
|
|
hit = sculpt_stroke_get_location(C, location, mouse);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
hit = ups->last_hit;
|
|
|
|
|
copy_v3_v3(location, ups->last_location);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hit) {
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
Brush *brush = BKE_paint_brush(paint);
|
2015-11-24 21:40:18 +01:00
|
|
|
|
2012-01-19 02:06:09 +00:00
|
|
|
*pixel_radius =
|
2015-11-24 21:40:18 +01:00
|
|
|
project_brush_radius(vc,
|
|
|
|
|
BKE_brush_unprojected_radius_get(scene, brush),
|
|
|
|
|
location);
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
if (*pixel_radius == 0)
|
2012-05-05 00:58:22 +00:00
|
|
|
*pixel_radius = BKE_brush_size_get(scene, brush);
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
mul_m4_v3(vc->obact->obmat, location);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2012-03-28 03:47:33 +00:00
|
|
|
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
Brush *brush = BKE_paint_brush(&sd->paint);
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2012-05-05 00:58:22 +00:00
|
|
|
*pixel_radius = BKE_brush_size_get(scene, brush);
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Draw an overlay that shows what effect the brush's texture will
|
2012-03-03 16:31:46 +00:00
|
|
|
* have on brush strength */
|
2013-04-22 20:46:18 +00:00
|
|
|
static void paint_draw_tex_overlay(UnifiedPaintSettings *ups, Brush *brush,
|
|
|
|
|
ViewContext *vc, int x, int y, float zoom, bool col, bool primary)
|
2012-01-19 02:06:09 +00:00
|
|
|
{
|
|
|
|
|
rctf quad;
|
|
|
|
|
/* check for overlay mode */
|
2013-03-31 00:38:50 +00:00
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
MTex *mtex = (primary) ? &brush->mtex : &brush->mask_mtex;
|
|
|
|
|
bool valid = (primary) ? (brush->overlay_flags & BRUSH_OVERLAY_PRIMARY) != 0 :
|
|
|
|
|
(brush->overlay_flags & BRUSH_OVERLAY_SECONDARY) != 0;
|
|
|
|
|
int overlay_alpha = (primary) ? brush->texture_overlay_alpha : brush->mask_overlay_alpha;
|
|
|
|
|
|
2013-04-23 11:02:36 +00:00
|
|
|
if (!(mtex->tex) || !((mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) ||
|
2013-04-22 20:46:18 +00:00
|
|
|
(valid &&
|
2014-01-12 22:05:24 +11:00
|
|
|
ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_TILED))))
|
2012-04-28 06:31:57 +00:00
|
|
|
{
|
2012-01-19 02:06:09 +00:00
|
|
|
return;
|
2012-04-28 06:31:57 +00:00
|
|
|
}
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
if (load_tex(brush, vc, zoom, col, primary)) {
|
2012-01-19 02:06:09 +00:00
|
|
|
glEnable(GL_BLEND);
|
|
|
|
|
|
|
|
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
|
glDepthFunc(GL_ALWAYS);
|
|
|
|
|
|
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
|
|
|
glPushMatrix();
|
|
|
|
|
glLoadIdentity();
|
|
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
|
2012-01-19 02:06:09 +00:00
|
|
|
/* brush rotation */
|
|
|
|
|
glTranslatef(0.5, 0.5, 0);
|
2014-12-26 23:51:27 +01:00
|
|
|
glRotatef((double)RAD2DEGF((primary) ? ups->brush_rotation : ups->brush_rotation_sec),
|
2012-03-28 03:47:33 +00:00
|
|
|
0.0, 0.0, 1.0);
|
2012-01-19 02:06:09 +00:00
|
|
|
glTranslatef(-0.5f, -0.5f, 0);
|
|
|
|
|
|
|
|
|
|
/* scale based on tablet pressure */
|
2013-12-09 22:36:33 +02:00
|
|
|
if (primary && ups->stroke_active && BKE_brush_use_size_pressure(vc->scene, brush)) {
|
2012-01-19 02:06:09 +00:00
|
|
|
glTranslatef(0.5f, 0.5f, 0);
|
2014-04-13 18:14:45 +03:00
|
|
|
glScalef(1.0f / ups->size_pressure_value, 1.0f / ups->size_pressure_value, 1);
|
2012-01-19 02:06:09 +00:00
|
|
|
glTranslatef(-0.5f, -0.5f, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-16 03:20:36 +00:00
|
|
|
if (ups->draw_anchored) {
|
|
|
|
|
const float *aim = ups->anchored_initial_mouse;
|
2013-03-13 03:46:22 +00:00
|
|
|
quad.xmin = aim[0] - ups->anchored_size;
|
|
|
|
|
quad.ymin = aim[1] - ups->anchored_size;
|
|
|
|
|
quad.xmax = aim[0] + ups->anchored_size;
|
|
|
|
|
quad.ymax = aim[1] + ups->anchored_size;
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2013-03-30 09:57:35 +00:00
|
|
|
const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
|
2012-01-19 02:06:09 +00:00
|
|
|
quad.xmin = x - radius;
|
|
|
|
|
quad.ymin = y - radius;
|
|
|
|
|
quad.xmax = x + radius;
|
|
|
|
|
quad.ymax = y + radius;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-04-22 20:46:18 +00:00
|
|
|
else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
|
2012-01-19 02:06:09 +00:00
|
|
|
quad.xmin = 0;
|
|
|
|
|
quad.ymin = 0;
|
2012-09-15 11:48:20 +00:00
|
|
|
quad.xmax = BLI_rcti_size_x(&vc->ar->winrct);
|
|
|
|
|
quad.ymax = BLI_rcti_size_y(&vc->ar->winrct);
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
2013-04-17 11:16:53 +00:00
|
|
|
/* Stencil code goes here */
|
|
|
|
|
else {
|
2013-04-23 00:06:22 +00:00
|
|
|
if (primary) {
|
|
|
|
|
quad.xmin = -brush->stencil_dimension[0];
|
|
|
|
|
quad.ymin = -brush->stencil_dimension[1];
|
|
|
|
|
quad.xmax = brush->stencil_dimension[0];
|
|
|
|
|
quad.ymax = brush->stencil_dimension[1];
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
quad.xmin = -brush->mask_stencil_dimension[0];
|
|
|
|
|
quad.ymin = -brush->mask_stencil_dimension[1];
|
|
|
|
|
quad.xmax = brush->mask_stencil_dimension[0];
|
|
|
|
|
quad.ymax = brush->mask_stencil_dimension[1];
|
|
|
|
|
}
|
2013-03-31 00:38:50 +00:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
|
glPushMatrix();
|
2013-04-23 00:06:22 +00:00
|
|
|
if (primary)
|
2015-09-20 18:11:25 +02:00
|
|
|
glTranslate2fv(brush->stencil_pos);
|
2013-04-23 00:06:22 +00:00
|
|
|
else
|
2015-09-20 18:11:25 +02:00
|
|
|
glTranslate2fv(brush->mask_stencil_pos);
|
2013-04-22 20:46:18 +00:00
|
|
|
glRotatef(RAD2DEGF(mtex->rot), 0, 0, 1);
|
2013-03-31 00:38:50 +00:00
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
|
|
|
}
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2013-03-31 00:38:50 +00:00
|
|
|
/* set quad color. Colored overlay does not get blending */
|
2015-01-24 03:10:23 +11:00
|
|
|
if (col) {
|
|
|
|
|
glColor4f(1.0, 1.0, 1.0, overlay_alpha / 100.0f);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
glColor4f(UNPACK3(U.sculpt_paint_overlay_col), overlay_alpha / 100.0f);
|
|
|
|
|
}
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
/* draw textured quad */
|
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
|
glTexCoord2f(0, 0);
|
|
|
|
|
glVertex2f(quad.xmin, quad.ymin);
|
|
|
|
|
glTexCoord2f(1, 0);
|
|
|
|
|
glVertex2f(quad.xmax, quad.ymin);
|
|
|
|
|
glTexCoord2f(1, 1);
|
|
|
|
|
glVertex2f(quad.xmax, quad.ymax);
|
|
|
|
|
glTexCoord2f(0, 1);
|
|
|
|
|
glVertex2f(quad.xmin, quad.ymax);
|
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
|
|
glPopMatrix();
|
2013-03-31 00:38:50 +00:00
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) {
|
2013-03-31 00:38:50 +00:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
|
glPopMatrix();
|
|
|
|
|
}
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
2013-04-22 20:46:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Draw an overlay that shows what effect the brush's texture will
|
|
|
|
|
* have on brush strength */
|
|
|
|
|
static void paint_draw_cursor_overlay(UnifiedPaintSettings *ups, Brush *brush,
|
2013-04-23 05:29:06 +00:00
|
|
|
ViewContext *vc, int x, int y, float zoom)
|
2013-04-22 20:46:18 +00:00
|
|
|
{
|
|
|
|
|
rctf quad;
|
|
|
|
|
/* check for overlay mode */
|
|
|
|
|
|
2013-04-23 05:29:06 +00:00
|
|
|
if (!(brush->overlay_flags & BRUSH_OVERLAY_CURSOR)) {
|
2013-04-22 20:46:18 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (load_tex_cursor(brush, vc, zoom)) {
|
2013-09-16 13:03:28 +00:00
|
|
|
bool do_pop = false;
|
|
|
|
|
float center[2];
|
2013-04-22 20:46:18 +00:00
|
|
|
glEnable(GL_BLEND);
|
|
|
|
|
|
|
|
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
|
glDepthFunc(GL_ALWAYS);
|
|
|
|
|
|
|
|
|
|
if (ups->draw_anchored) {
|
|
|
|
|
const float *aim = ups->anchored_initial_mouse;
|
2013-09-16 13:03:28 +00:00
|
|
|
copy_v2_v2(center, aim);
|
2013-04-22 20:46:18 +00:00
|
|
|
quad.xmin = aim[0] - ups->anchored_size;
|
|
|
|
|
quad.ymin = aim[1] - ups->anchored_size;
|
|
|
|
|
quad.xmax = aim[0] + ups->anchored_size;
|
|
|
|
|
quad.ymax = aim[1] + ups->anchored_size;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
|
2013-09-16 13:03:28 +00:00
|
|
|
center[0] = x;
|
|
|
|
|
center[1] = y;
|
|
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
quad.xmin = x - radius;
|
|
|
|
|
quad.ymin = y - radius;
|
|
|
|
|
quad.xmax = x + radius;
|
|
|
|
|
quad.ymax = y + radius;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-16 13:03:28 +00:00
|
|
|
/* scale based on tablet pressure */
|
2013-12-09 22:36:33 +02:00
|
|
|
if (ups->stroke_active && BKE_brush_use_size_pressure(vc->scene, brush)) {
|
2013-09-16 13:03:28 +00:00
|
|
|
do_pop = true;
|
|
|
|
|
glPushMatrix();
|
|
|
|
|
glLoadIdentity();
|
2015-09-20 18:11:25 +02:00
|
|
|
glTranslate2fv(center);
|
2014-04-13 18:14:45 +03:00
|
|
|
glScalef(ups->size_pressure_value, ups->size_pressure_value, 1);
|
2013-09-16 13:03:28 +00:00
|
|
|
glTranslatef(-center[0], -center[1], 0);
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
glColor4f(U.sculpt_paint_overlay_col[0],
|
|
|
|
|
U.sculpt_paint_overlay_col[1],
|
|
|
|
|
U.sculpt_paint_overlay_col[2],
|
|
|
|
|
brush->cursor_overlay_alpha / 100.0f);
|
|
|
|
|
|
|
|
|
|
/* draw textured quad */
|
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
|
glTexCoord2f(0, 0);
|
|
|
|
|
glVertex2f(quad.xmin, quad.ymin);
|
|
|
|
|
glTexCoord2f(1, 0);
|
|
|
|
|
glVertex2f(quad.xmax, quad.ymin);
|
|
|
|
|
glTexCoord2f(1, 1);
|
|
|
|
|
glVertex2f(quad.xmax, quad.ymax);
|
|
|
|
|
glTexCoord2f(0, 1);
|
|
|
|
|
glVertex2f(quad.xmin, quad.ymax);
|
|
|
|
|
glEnd();
|
2013-09-16 13:03:28 +00:00
|
|
|
|
|
|
|
|
if (do_pop)
|
|
|
|
|
glPopMatrix();
|
2013-04-22 20:46:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush,
|
2017-10-17 13:43:10 +11:00
|
|
|
ViewContext *vc, int x, int y, float zoom, ePaintMode mode)
|
2013-04-22 20:46:18 +00:00
|
|
|
{
|
|
|
|
|
/* color means that primary brush texture is colured and secondary is used for alpha/mask control */
|
2015-08-31 21:37:38 +03:00
|
|
|
bool col = ELEM(mode, ePaintTextureProjective, ePaintTexture2D, ePaintVertex) ? true : false;
|
2017-10-17 13:43:10 +11:00
|
|
|
eOverlayControlFlags flags = BKE_paint_get_overlay_flags();
|
2013-04-22 20:46:18 +00:00
|
|
|
/* save lots of GL state
|
|
|
|
|
* TODO: check on whether all of these are needed? */
|
|
|
|
|
glPushAttrib(GL_COLOR_BUFFER_BIT |
|
|
|
|
|
GL_CURRENT_BIT |
|
|
|
|
|
GL_DEPTH_BUFFER_BIT |
|
|
|
|
|
GL_ENABLE_BIT |
|
|
|
|
|
GL_LINE_BIT |
|
|
|
|
|
GL_POLYGON_BIT |
|
|
|
|
|
GL_STENCIL_BUFFER_BIT |
|
|
|
|
|
GL_TRANSFORM_BIT |
|
|
|
|
|
GL_VIEWPORT_BIT |
|
|
|
|
|
GL_TEXTURE_BIT);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* coloured overlay should be drawn separately */
|
|
|
|
|
if (col) {
|
2013-04-23 00:32:51 +00:00
|
|
|
if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY))
|
|
|
|
|
paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, true, true);
|
|
|
|
|
if (!(flags & PAINT_OVERLAY_OVERRIDE_SECONDARY))
|
|
|
|
|
paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, false);
|
|
|
|
|
if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR))
|
|
|
|
|
paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
|
2013-04-23 05:29:06 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2015-08-31 21:37:38 +03:00
|
|
|
if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY) && (mode != ePaintWeight))
|
2013-04-23 00:32:51 +00:00
|
|
|
paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, true);
|
|
|
|
|
if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR))
|
|
|
|
|
paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
|
2013-04-22 20:46:18 +00:00
|
|
|
}
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
glPopAttrib();
|
2015-12-05 22:11:31 +01:00
|
|
|
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
|
|
|
|
|
BLI_INLINE void draw_tri_point(float *co, float width, bool selected)
|
|
|
|
|
{
|
|
|
|
|
float w = width / 2.0f;
|
|
|
|
|
if (selected)
|
|
|
|
|
UI_ThemeColor4(TH_VERTEX_SELECT);
|
|
|
|
|
else
|
|
|
|
|
UI_ThemeColor4(TH_PAINT_CURVE_PIVOT);
|
|
|
|
|
|
|
|
|
|
glLineWidth(3.0);
|
|
|
|
|
|
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
|
glVertex2f(co[0], co[1] + w);
|
|
|
|
|
glVertex2f(co[0] - w, co[1] - w);
|
|
|
|
|
glVertex2f(co[0] + w, co[1] - w);
|
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
|
|
glColor4f(1.0, 1.0, 1.0, 0.5);
|
|
|
|
|
glLineWidth(1.0);
|
|
|
|
|
|
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
|
glVertex2f(co[0], co[1] + w);
|
|
|
|
|
glVertex2f(co[0] - w, co[1] - w);
|
|
|
|
|
glVertex2f(co[0] + w, co[1] - w);
|
|
|
|
|
glEnd();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BLI_INLINE void draw_rect_point(float *co, float width, bool selected)
|
|
|
|
|
{
|
|
|
|
|
float w = width / 2.0f;
|
|
|
|
|
if (selected)
|
|
|
|
|
UI_ThemeColor4(TH_VERTEX_SELECT);
|
|
|
|
|
else
|
|
|
|
|
UI_ThemeColor4(TH_PAINT_CURVE_HANDLE);
|
|
|
|
|
glLineWidth(3.0);
|
|
|
|
|
|
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
|
glVertex2f(co[0] + w, co[1] + w);
|
|
|
|
|
glVertex2f(co[0] - w, co[1] + w);
|
|
|
|
|
glVertex2f(co[0] - w, co[1] - w);
|
|
|
|
|
glVertex2f(co[0] + w, co[1] - w);
|
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
|
|
glColor4f(1.0, 1.0, 1.0, 0.5);
|
|
|
|
|
glLineWidth(1.0);
|
|
|
|
|
|
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
|
glVertex2f(co[0] + w, co[1] + w);
|
|
|
|
|
glVertex2f(co[0] - w, co[1] + w);
|
|
|
|
|
glVertex2f(co[0] - w, co[1] - w);
|
|
|
|
|
glVertex2f(co[0] + w, co[1] - w);
|
|
|
|
|
glEnd();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BLI_INLINE void draw_bezier_handle_lines(BezTriple *bez)
|
|
|
|
|
{
|
|
|
|
|
short line1[] = {0, 1};
|
|
|
|
|
short line2[] = {1, 2};
|
|
|
|
|
|
|
|
|
|
glVertexPointer(2, GL_FLOAT, 3 * sizeof(float), bez->vec);
|
|
|
|
|
glColor4f(0.0, 0.0, 0.0, 0.5);
|
|
|
|
|
glLineWidth(3.0);
|
|
|
|
|
glDrawArrays(GL_LINE_STRIP, 0, 3);
|
|
|
|
|
|
|
|
|
|
glLineWidth(1.0);
|
|
|
|
|
if (bez->f1 || bez->f2)
|
|
|
|
|
UI_ThemeColor4(TH_VERTEX_SELECT);
|
|
|
|
|
else
|
|
|
|
|
glColor4f(1.0, 1.0, 1.0, 0.5);
|
|
|
|
|
glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, line1);
|
|
|
|
|
if (bez->f3 || bez->f2)
|
|
|
|
|
UI_ThemeColor4(TH_VERTEX_SELECT);
|
|
|
|
|
else
|
|
|
|
|
glColor4f(1.0, 1.0, 1.0, 0.5);
|
|
|
|
|
glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, line2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void paint_draw_curve_cursor(Brush *brush)
|
|
|
|
|
{
|
|
|
|
|
if (brush->paint_curve && brush->paint_curve->points) {
|
|
|
|
|
int i;
|
|
|
|
|
PaintCurve *pc = brush->paint_curve;
|
|
|
|
|
PaintCurvePoint *cp = pc->points;
|
|
|
|
|
|
|
|
|
|
glEnable(GL_LINE_SMOOTH);
|
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
|
|
|
|
|
|
|
|
/* draw the bezier handles and the curve segment between the current and next point */
|
|
|
|
|
for (i = 0; i < pc->tot_points - 1; i++, cp++) {
|
|
|
|
|
int j;
|
|
|
|
|
PaintCurvePoint *cp_next = cp + 1;
|
|
|
|
|
float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
|
|
|
|
|
/* use color coding to distinguish handles vs curve segments */
|
|
|
|
|
draw_bezier_handle_lines(&cp->bez);
|
|
|
|
|
draw_tri_point(&cp->bez.vec[1][0], 10.0, cp->bez.f2);
|
|
|
|
|
draw_rect_point(&cp->bez.vec[0][0], 8.0, cp->bez.f1 || cp->bez.f2);
|
|
|
|
|
draw_rect_point(&cp->bez.vec[2][0], 8.0, cp->bez.f3 || cp->bez.f2);
|
|
|
|
|
|
|
|
|
|
for (j = 0; j < 2; j++)
|
|
|
|
|
BKE_curve_forward_diff_bezier(
|
|
|
|
|
cp->bez.vec[1][j],
|
|
|
|
|
cp->bez.vec[2][j],
|
|
|
|
|
cp_next->bez.vec[0][j],
|
|
|
|
|
cp_next->bez.vec[1][j],
|
|
|
|
|
data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
|
|
|
|
|
|
|
|
|
|
glVertexPointer(2, GL_FLOAT, 0, data);
|
|
|
|
|
glLineWidth(3.0);
|
|
|
|
|
glColor4f(0.0, 0.0, 0.0, 0.5);
|
|
|
|
|
glDrawArrays(GL_LINE_STRIP, 0, PAINT_CURVE_NUM_SEGMENTS + 1);
|
|
|
|
|
|
|
|
|
|
glLineWidth(1.0);
|
|
|
|
|
glColor4f(0.9, 0.9, 1.0, 0.5);
|
|
|
|
|
glDrawArrays(GL_LINE_STRIP, 0, PAINT_CURVE_NUM_SEGMENTS + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* draw last line segment */
|
|
|
|
|
draw_bezier_handle_lines(&cp->bez);
|
|
|
|
|
draw_tri_point(&cp->bez.vec[1][0], 10.0, cp->bez.f2);
|
|
|
|
|
draw_rect_point(&cp->bez.vec[0][0], 8.0, cp->bez.f1 || cp->bez.f2);
|
|
|
|
|
draw_rect_point(&cp->bez.vec[2][0], 8.0, cp->bez.f3 || cp->bez.f2);
|
|
|
|
|
|
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
|
glDisable(GL_LINE_SMOOTH);
|
|
|
|
|
glDisableClientState(GL_VERTEX_ARRAY);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-19 02:06:09 +00:00
|
|
|
/* Special actions taken when paint cursor goes over mesh */
|
|
|
|
|
/* TODO: sculpt only for now */
|
2013-01-16 03:20:36 +00:00
|
|
|
static void paint_cursor_on_hit(UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc,
|
2012-03-28 03:47:33 +00:00
|
|
|
const float location[3])
|
2012-01-19 02:06:09 +00:00
|
|
|
{
|
|
|
|
|
float unprojected_radius, projected_radius;
|
|
|
|
|
|
|
|
|
|
/* update the brush's cached 3D radius */
|
2012-05-05 00:58:22 +00:00
|
|
|
if (!BKE_brush_use_locked_size(vc->scene, brush)) {
|
2012-01-19 02:06:09 +00:00
|
|
|
/* get 2D brush radius */
|
2013-01-16 03:20:36 +00:00
|
|
|
if (ups->draw_anchored)
|
|
|
|
|
projected_radius = ups->anchored_size;
|
2012-01-19 02:06:09 +00:00
|
|
|
else {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (brush->flag & BRUSH_ANCHORED)
|
2012-01-19 02:06:09 +00:00
|
|
|
projected_radius = 8;
|
|
|
|
|
else
|
2012-05-05 00:58:22 +00:00
|
|
|
projected_radius = BKE_brush_size_get(vc->scene, brush);
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* convert brush radius from 2D to 3D */
|
|
|
|
|
unprojected_radius = paint_calc_object_space_radius(vc, location,
|
2012-03-28 03:47:33 +00:00
|
|
|
projected_radius);
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
/* scale 3D brush radius by pressure */
|
2013-12-09 22:36:33 +02:00
|
|
|
if (ups->stroke_active && BKE_brush_use_size_pressure(vc->scene, brush))
|
2014-04-13 18:14:45 +03:00
|
|
|
unprojected_radius *= ups->size_pressure_value;
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
/* set cached value in either Brush or UnifiedPaintSettings */
|
2012-05-05 00:58:22 +00:00
|
|
|
BKE_brush_unprojected_radius_set(vc->scene, brush, unprojected_radius);
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-17 13:43:10 +11:00
|
|
|
static bool ommit_cursor_drawing(Paint *paint, ePaintMode mode, Brush *brush)
|
2015-06-03 12:04:47 +02:00
|
|
|
{
|
|
|
|
|
if (paint->flags & PAINT_SHOW_BRUSH) {
|
2015-08-31 21:37:38 +03:00
|
|
|
if (ELEM(mode, ePaintTexture2D, ePaintTextureProjective) && brush->imagepaint_tool == PAINT_TOOL_FILL) {
|
2015-06-03 12:04:47 +02:00
|
|
|
return true;
|
2015-06-09 15:13:52 +02:00
|
|
|
}
|
|
|
|
|
return false;
|
2015-06-03 12:04:47 +02:00
|
|
|
}
|
2015-06-09 15:13:52 +02:00
|
|
|
return true;
|
2015-06-03 12:04:47 +02:00
|
|
|
}
|
|
|
|
|
|
2012-01-19 02:06:09 +00:00
|
|
|
static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
|
|
|
|
|
{
|
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
2013-01-16 03:20:36 +00:00
|
|
|
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
Paint *paint = BKE_paint_get_active_from_context(C);
|
|
|
|
|
Brush *brush = BKE_paint_brush(paint);
|
2017-10-17 13:43:10 +11:00
|
|
|
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
|
2012-01-19 02:06:09 +00:00
|
|
|
ViewContext vc;
|
|
|
|
|
float final_radius;
|
|
|
|
|
float translation[2];
|
|
|
|
|
float outline_alpha, *outline_col;
|
2013-03-29 14:02:28 +00:00
|
|
|
float zoomx, zoomy;
|
2015-06-03 12:04:47 +02:00
|
|
|
|
2012-01-19 02:06:09 +00:00
|
|
|
/* check that brush drawing is enabled */
|
2015-06-03 12:04:47 +02:00
|
|
|
if (ommit_cursor_drawing(paint, mode, brush))
|
2012-01-19 02:06:09 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* can't use stroke vc here because this will be called during
|
2012-03-03 16:31:46 +00:00
|
|
|
* mouse over too, not just during a stroke */
|
2012-01-19 02:06:09 +00:00
|
|
|
view3d_set_viewcontext(C, &vc);
|
|
|
|
|
|
2017-10-10 02:43:56 +11:00
|
|
|
if (vc.rv3d && (vc.rv3d->rflag & RV3D_NAVIGATING)) {
|
2017-10-05 17:35:46 +11:00
|
|
|
return;
|
|
|
|
|
}
|
2013-03-29 14:02:28 +00:00
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
/* skip everything and draw brush here */
|
|
|
|
|
if (brush->flag & BRUSH_CURVE) {
|
|
|
|
|
paint_draw_curve_cursor(brush);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-05 17:35:46 +11:00
|
|
|
get_imapaint_zoom(C, &zoomx, &zoomy);
|
|
|
|
|
zoomx = max_ff(zoomx, zoomy);
|
|
|
|
|
|
2013-03-29 14:02:28 +00:00
|
|
|
/* set various defaults */
|
|
|
|
|
translation[0] = x;
|
|
|
|
|
translation[1] = y;
|
|
|
|
|
outline_alpha = 0.5;
|
|
|
|
|
outline_col = brush->add_col;
|
2016-07-12 01:15:54 +10:00
|
|
|
final_radius = (BKE_brush_size_get(scene, brush) * zoomx);
|
2013-03-29 14:02:28 +00:00
|
|
|
|
2013-12-09 22:36:33 +02:00
|
|
|
/* don't calculate rake angles while a stroke is active because the rake variables are global and
|
|
|
|
|
* we may get interference with the stroke itself. For line strokes, such interference is visible */
|
2014-07-21 12:02:05 +02:00
|
|
|
if (!ups->stroke_active) {
|
2014-12-26 23:51:27 +01:00
|
|
|
paint_calculate_rake_rotation(ups, brush, translation);
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
2013-03-13 03:46:22 +00:00
|
|
|
|
|
|
|
|
/* draw overlay */
|
2013-04-23 00:32:51 +00:00
|
|
|
paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode);
|
2013-03-13 03:46:22 +00:00
|
|
|
|
2012-01-19 02:06:09 +00:00
|
|
|
/* TODO: as sculpt and other paint modes are unified, this
|
2012-03-03 16:31:46 +00:00
|
|
|
* special mode of drawing will go away */
|
2015-08-31 21:37:38 +03:00
|
|
|
if ((mode == ePaintSculpt) && vc.obact->sculpt) {
|
2012-01-19 02:06:09 +00:00
|
|
|
float location[3];
|
2014-10-07 13:58:35 +02:00
|
|
|
int pixel_radius;
|
|
|
|
|
bool hit;
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
/* test if brush is over the mesh */
|
2015-11-24 21:40:18 +01:00
|
|
|
hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2012-05-05 00:58:22 +00:00
|
|
|
if (BKE_brush_use_locked_size(scene, brush))
|
|
|
|
|
BKE_brush_size_set(scene, brush, pixel_radius);
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
/* check if brush is subtracting, use different color then */
|
|
|
|
|
/* TODO: no way currently to know state of pen flip or
|
2012-03-03 16:31:46 +00:00
|
|
|
* invert key modifier without starting a stroke */
|
2017-10-05 12:57:24 +11:00
|
|
|
if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
|
|
|
|
|
BKE_brush_sculpt_has_secondary_color(brush))
|
2012-04-28 06:31:57 +00:00
|
|
|
{
|
2012-01-19 02:06:09 +00:00
|
|
|
outline_col = brush->sub_col;
|
2012-04-28 06:31:57 +00:00
|
|
|
}
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
/* only do if brush is over the mesh */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (hit)
|
2013-01-16 03:20:36 +00:00
|
|
|
paint_cursor_on_hit(ups, brush, &vc, location);
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2014-07-21 12:02:05 +02:00
|
|
|
if (ups->draw_anchored) {
|
|
|
|
|
final_radius = ups->anchored_size;
|
|
|
|
|
translation[0] = ups->anchored_initial_mouse[0];
|
|
|
|
|
translation[1] = ups->anchored_initial_mouse[1];
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* make lines pretty */
|
2016-01-24 20:30:41 +11:00
|
|
|
glLineWidth(1.0f);
|
2012-01-19 02:06:09 +00:00
|
|
|
glEnable(GL_BLEND);
|
|
|
|
|
glEnable(GL_LINE_SMOOTH);
|
|
|
|
|
|
|
|
|
|
/* set brush color */
|
|
|
|
|
glColor4f(outline_col[0], outline_col[1], outline_col[2], outline_alpha);
|
|
|
|
|
|
|
|
|
|
/* draw brush outline */
|
2015-09-20 18:11:25 +02:00
|
|
|
glTranslate2fv(translation);
|
2013-01-16 19:22:15 +00:00
|
|
|
|
|
|
|
|
/* draw an inner brush */
|
2013-12-09 22:36:33 +02:00
|
|
|
if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
|
2013-01-16 23:37:47 +00:00
|
|
|
/* inner at full alpha */
|
2014-04-13 18:14:45 +03:00
|
|
|
glutil_draw_lined_arc(0.0, M_PI * 2.0, final_radius * ups->size_pressure_value, 40);
|
2013-01-16 23:37:47 +00:00
|
|
|
/* outer at half alpha */
|
|
|
|
|
glColor4f(outline_col[0], outline_col[1], outline_col[2], outline_alpha * 0.5f);
|
2013-01-16 19:22:15 +00:00
|
|
|
}
|
2012-03-28 03:47:33 +00:00
|
|
|
glutil_draw_lined_arc(0.0, M_PI * 2.0, final_radius, 40);
|
2012-01-19 02:06:09 +00:00
|
|
|
glTranslatef(-translation[0], -translation[1], 0);
|
|
|
|
|
|
|
|
|
|
/* restore GL state */
|
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
|
glDisable(GL_LINE_SMOOTH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Public API */
|
|
|
|
|
|
|
|
|
|
void paint_cursor_start(bContext *C, int (*poll)(bContext *C))
|
|
|
|
|
{
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
Paint *p = BKE_paint_get_active_from_context(C);
|
2012-01-19 02:06:09 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (p && !p->paint_cursor)
|
2012-01-19 02:06:09 +00:00
|
|
|
p->paint_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), poll, paint_draw_cursor, NULL);
|
Paint refactoring commit, non-disruptive (in theory :p)
* Fix precision overflow issue with overlay previews,
* Expose alpha mask mapping to UI (still not functional but coming soon).
* More overlay refactoring:
Overlay now does minimal checking for texture refresh.
Instead, we now have invalidation flags to set an aspect of the brush
overlay as invalid. This is necessary because this way we will be able to
separate and preview different brush attributes on the overlays, using
different textures:
These attributes/aspects are:
Primary texture (main texture for sculpt, vertex, imapaint)
Secondary texture (mask/alpha texture for imapaint)
Cursor texture (cursor texture. It involves brush strength and curves)
Modified the relevant RNA property update functions and C update callback
functions to call the relevant cursor invalidation functions instead
of checking every frame for multiple properties.
Properties that affect this are:
Image changes, if image is used by current brush,
Texture slot changes, similarly
Curve changes,
Object mode change invalidates the cursor
Paint tool change invalidates the cursor.
These changes give slightly more invalidation cases than simply
comparing the relevant properties each frame, but these do not occur in
performance critical moments and it's a much more elegant system than
adding more variables to check per frame each time we add something on
the system.
2013-04-12 17:21:31 +00:00
|
|
|
|
|
|
|
|
/* invalidate the paint cursors */
|
|
|
|
|
BKE_paint_invalidate_overlay_all();
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
2013-03-29 14:02:28 +00:00
|
|
|
|
|
|
|
|
void paint_cursor_start_explicit(Paint *p, wmWindowManager *wm, int (*poll)(bContext *C))
|
|
|
|
|
{
|
|
|
|
|
if (p && !p->paint_cursor)
|
|
|
|
|
p->paint_cursor = WM_paint_cursor_activate(wm, poll, paint_draw_cursor, NULL);
|
|
|
|
|
}
|