2012-01-19 02:06:09 +00:00
|
|
|
/*
|
|
|
|
|
* 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
|
2020-05-09 17:14:35 +10:00
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
2012-01-19 02:06:09 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is Copyright (C) 2009 by Nicholas Bishop
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*/
|
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup edsculpt
|
2012-01-19 02:06:09 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#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"
|
|
|
|
|
#include "DNA_color_types.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_customdata_types.h"
|
2012-01-19 02:06:09 +00:00
|
|
|
#include "DNA_object_types.h"
|
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
|
#include "DNA_screen_types.h"
|
2018-10-25 16:06:47 +11:00
|
|
|
#include "DNA_space_types.h"
|
2012-01-19 02:06:09 +00:00
|
|
|
#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"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BKE_colortools.h"
|
2012-01-19 02:06:09 +00:00
|
|
|
#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"
|
2019-08-30 16:27:31 +02:00
|
|
|
#include "BKE_object.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BKE_paint.h"
|
2012-01-19 02:06:09 +00:00
|
|
|
|
|
|
|
|
#include "WM_api.h"
|
2019-08-30 16:27:31 +02:00
|
|
|
#include "wm_cursors.h"
|
2012-01-19 02:06:09 +00:00
|
|
|
|
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"
|
|
|
|
|
|
2019-08-30 16:27:31 +02:00
|
|
|
#include "DEG_depsgraph.h"
|
|
|
|
|
|
2017-04-05 13:01:32 +02:00
|
|
|
#include "GPU_draw.h"
|
2017-03-03 17:21:34 -05:00
|
|
|
#include "GPU_immediate.h"
|
2017-04-05 18:30:14 +10:00
|
|
|
#include "GPU_immediate_util.h"
|
2017-03-21 00:09:40 -04:00
|
|
|
#include "GPU_matrix.h"
|
2018-06-27 19:07:23 -06:00
|
|
|
#include "GPU_state.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 {
|
2019-04-17 06:17:24 +02:00
|
|
|
GLuint overlay_texture;
|
|
|
|
|
int winx;
|
|
|
|
|
int winy;
|
|
|
|
|
int old_size;
|
|
|
|
|
float old_zoom;
|
|
|
|
|
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 {
|
2019-04-17 06:17:24 +02:00
|
|
|
GLuint overlay_texture;
|
|
|
|
|
int size;
|
|
|
|
|
int zoom;
|
2019-09-17 16:27:01 +02:00
|
|
|
int curve_preset;
|
2013-10-09 16:00:15 +00:00
|
|
|
} CursorSnapshot;
|
|
|
|
|
|
|
|
|
|
static TexSnapshot primary_snap = {0};
|
2019-04-17 06:17:24 +02:00
|
|
|
static TexSnapshot secondary_snap = {0};
|
|
|
|
|
static CursorSnapshot cursor_snap = {0};
|
2013-10-09 16:00:15 +00:00
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* 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
|
|
|
{
|
2019-04-22 09:19:45 +10:00
|
|
|
if (primary_snap.overlay_texture) {
|
2019-04-17 06:17:24 +02:00
|
|
|
glDeleteTextures(1, &primary_snap.overlay_texture);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
if (secondary_snap.overlay_texture) {
|
2019-04-17 06:17:24 +02:00
|
|
|
glDeleteTextures(1, &secondary_snap.overlay_texture);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
if (cursor_snap.overlay_texture) {
|
2019-04-17 06:17:24 +02:00
|
|
|
glDeleteTextures(1, &cursor_snap.overlay_texture);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
memset(&primary_snap, 0, sizeof(TexSnapshot));
|
|
|
|
|
memset(&secondary_snap, 0, sizeof(TexSnapshot));
|
|
|
|
|
memset(&cursor_snap, 0, sizeof(CursorSnapshot));
|
|
|
|
|
|
|
|
|
|
BKE_paint_invalidate_overlay_all();
|
2013-10-09 16:00:15 +00:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
{
|
2019-04-17 06:17:24 +02: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)) &&
|
|
|
|
|
|
|
|
|
|
(mtex->brush_map_mode != MTEX_MAP_MODE_TILED ||
|
2020-03-06 16:56:42 +01:00
|
|
|
(vc->region->winx == snap->winx && vc->region->winy == snap->winy)) &&
|
2019-04-17 06:17:24 +02:00
|
|
|
(mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL || snap->old_zoom == zoom) &&
|
|
|
|
|
snap->old_col == col);
|
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
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
snap->old_zoom = zoom;
|
2020-03-06 16:56:42 +01:00
|
|
|
snap->winx = vc->region->winx;
|
|
|
|
|
snap->winy = vc->region->winy;
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
2016-01-17 17:16:57 +01:00
|
|
|
typedef struct LoadTexData {
|
2019-04-17 06:17:24 +02:00
|
|
|
Brush *br;
|
|
|
|
|
ViewContext *vc;
|
2016-01-17 17:16:57 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
MTex *mtex;
|
|
|
|
|
GLubyte *buffer;
|
|
|
|
|
bool col;
|
2016-01-17 17:16:57 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
struct ImagePool *pool;
|
|
|
|
|
int size;
|
|
|
|
|
float rotation;
|
|
|
|
|
float radius;
|
2016-01-17 17:16:57 +01:00
|
|
|
} LoadTexData;
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static void load_tex_task_cb_ex(void *__restrict userdata,
|
|
|
|
|
const int j,
|
2019-07-30 14:56:47 +02:00
|
|
|
const TaskParallelTLS *__restrict tls)
|
2016-01-17 17:16:57 +01:00
|
|
|
{
|
2019-04-17 06:17:24 +02: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;
|
|
|
|
|
|
2020-04-30 07:59:23 +02:00
|
|
|
const int thread_id = BLI_task_parallel_thread_id(tls);
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (mtex->tex && mtex->tex->type == TEX_IMAGE && mtex->tex->ima) {
|
|
|
|
|
ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(mtex->tex->ima, &mtex->tex->iuser, pool);
|
2020-02-08 23:59:22 +01:00
|
|
|
/* For consistency, sampling always returns color in linear space. */
|
2019-04-17 06:17:24 +02:00
|
|
|
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++) {
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Largely duplicated from tex_strength. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
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) {
|
2020-03-06 16:56:42 +01:00
|
|
|
x *= vc->region->winx / radius;
|
|
|
|
|
y *= vc->region->winy / radius;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
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) {
|
2019-04-22 00:18:34 +10:00
|
|
|
/* It is probably worth optimizing for those cases where the texture is not rotated by
|
|
|
|
|
* skipping the calls to atan2, sqrtf, sin, and cos. */
|
2019-04-17 06:17:24 +02:00
|
|
|
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];
|
|
|
|
|
|
2020-04-30 07:59:23 +02:00
|
|
|
paint_get_tex_pixel_col(mtex, x, y, rgba, pool, thread_id, convert_to_linear, colorspace);
|
2019-04-17 06:17:24 +02: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 {
|
2020-04-30 07:59:23 +02:00
|
|
|
float avg = paint_get_tex_pixel(mtex, x, y, pool, thread_id);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
avg += br->texture_sample_bias;
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Clamp to avoid precision overflow. */
|
2019-04-17 06:17:24 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-01-17 17:16:57 +01:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
bool init;
|
|
|
|
|
TexSnapshot *target;
|
|
|
|
|
|
|
|
|
|
MTex *mtex = (primary) ? &br->mtex : &br->mask_mtex;
|
2020-01-08 12:59:48 +11:00
|
|
|
ePaintOverlayControlFlags overlay_flags = BKE_paint_get_overlay_flags();
|
2019-04-17 06:17:24 +02:00
|
|
|
GLubyte *buffer = NULL;
|
|
|
|
|
|
|
|
|
|
int size;
|
|
|
|
|
bool refresh;
|
2020-01-08 12:59:48 +11:00
|
|
|
ePaintOverlayControlFlags invalid =
|
|
|
|
|
((primary) ? (overlay_flags & PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY) :
|
|
|
|
|
(overlay_flags & PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY));
|
2019-04-17 06:17:24 +02:00
|
|
|
target = (primary) ? &primary_snap : &secondary_snap;
|
|
|
|
|
|
|
|
|
|
refresh = !target->overlay_texture || (invalid != 0) ||
|
|
|
|
|
!same_tex_snap(target, mtex, vc, col, zoom);
|
|
|
|
|
|
|
|
|
|
init = (target->overlay_texture != 0);
|
|
|
|
|
|
|
|
|
|
if (refresh) {
|
|
|
|
|
struct ImagePool *pool = NULL;
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Stencil is rotated later. */
|
2019-04-17 06:17:24 +02: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;
|
|
|
|
|
|
|
|
|
|
make_tex_snap(target, vc, zoom);
|
|
|
|
|
|
|
|
|
|
if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
|
|
|
|
|
int s = BKE_brush_size_get(vc->scene, br);
|
|
|
|
|
int r = 1;
|
|
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
for (s >>= 1; s > 0; s >>= 1) {
|
2019-04-17 06:17:24 +02:00
|
|
|
r++;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
size = (1 << r);
|
|
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (size < 256) {
|
2019-04-17 06:17:24 +02:00
|
|
|
size = 256;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (size < target->old_size) {
|
2019-04-17 06:17:24 +02:00
|
|
|
size = target->old_size;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
size = 512;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (target->old_size != size) {
|
|
|
|
|
if (target->overlay_texture) {
|
|
|
|
|
glDeleteTextures(1, &target->overlay_texture);
|
|
|
|
|
target->overlay_texture = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init = false;
|
|
|
|
|
|
|
|
|
|
target->old_size = size;
|
|
|
|
|
}
|
2019-04-22 09:19:45 +10:00
|
|
|
if (col) {
|
2019-04-17 06:17:24 +02:00
|
|
|
buffer = MEM_mallocN(sizeof(GLubyte) * size * size * 4, "load_tex");
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2019-04-17 06:17:24 +02:00
|
|
|
buffer = MEM_mallocN(sizeof(GLubyte) * size * size, "load_tex");
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
pool = BKE_image_pool_new();
|
|
|
|
|
|
|
|
|
|
if (mtex->tex && mtex->tex->nodetree) {
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Has internal flag to detect it only does it once. */
|
2019-04-17 06:17:24 +02:00
|
|
|
ntreeTexBeginExecTree(mtex->tex->nodetree);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LoadTexData data = {
|
|
|
|
|
.br = br,
|
|
|
|
|
.vc = vc,
|
|
|
|
|
.mtex = mtex,
|
|
|
|
|
.buffer = buffer,
|
|
|
|
|
.col = col,
|
|
|
|
|
.pool = pool,
|
|
|
|
|
.size = size,
|
|
|
|
|
.rotation = rotation,
|
|
|
|
|
.radius = radius,
|
|
|
|
|
};
|
|
|
|
|
|
2019-07-30 14:56:47 +02:00
|
|
|
TaskParallelSettings settings;
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_parallel_range_settings_defaults(&settings);
|
|
|
|
|
BLI_task_parallel_range(0, size, &data, load_tex_task_cb_ex, &settings);
|
|
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (mtex->tex && mtex->tex->nodetree) {
|
2019-04-17 06:17:24 +02:00
|
|
|
ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (pool) {
|
2019-04-17 06:17:24 +02:00
|
|
|
BKE_image_pool_free(pool);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (!target->overlay_texture) {
|
2019-04-17 06:17:24 +02:00
|
|
|
glGenTextures(1, &target->overlay_texture);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
size = target->old_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, target->overlay_texture);
|
|
|
|
|
|
|
|
|
|
if (refresh) {
|
|
|
|
|
GLenum format = col ? GL_RGBA : GL_RED;
|
|
|
|
|
GLenum internalformat = col ? GL_RGBA8 : GL_R8;
|
|
|
|
|
|
|
|
|
|
if (!init || (target->old_col != col)) {
|
|
|
|
|
glTexImage2D(
|
|
|
|
|
GL_TEXTURE_2D, 0, internalformat, size, size, 0, format, GL_UNSIGNED_BYTE, buffer);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, format, GL_UNSIGNED_BYTE, buffer);
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (buffer) {
|
2019-04-17 06:17:24 +02:00
|
|
|
MEM_freeN(buffer);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
target->old_col = col;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
|
|
|
|
|
|
if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BKE_paint_reset_overlay_invalid(invalid);
|
|
|
|
|
|
|
|
|
|
return 1;
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static void load_tex_cursor_task_cb(void *__restrict userdata,
|
|
|
|
|
const int j,
|
2019-07-30 14:56:47 +02:00
|
|
|
const TaskParallelTLS *__restrict UNUSED(tls))
|
2016-01-17 17:16:57 +01:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
LoadTexData *data = userdata;
|
|
|
|
|
Brush *br = data->br;
|
2016-01-17 17:16:57 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
GLubyte *buffer = data->buffer;
|
2016-01-17 17:16:57 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
const int size = data->size;
|
2016-01-17 17:16:57 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
for (int i = 0; i < size; i++) {
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Largely duplicated from tex_strength. */
|
2016-01-17 17:16:57 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
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);
|
2016-01-17 17:16:57 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (len <= 1.0f) {
|
2020-02-08 23:59:22 +01:00
|
|
|
|
|
|
|
|
/* Falloff curve. */
|
|
|
|
|
float avg = BKE_brush_curve_strength_clamped(br, len, 1.0f);
|
2016-01-17 17:16:57 +01:00
|
|
|
|
2019-10-05 20:58:19 +02:00
|
|
|
buffer[index] = (GLubyte)(255 * avg);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
buffer[index] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-01-17 17:16:57 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-22 20:46:18 +00:00
|
|
|
static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
|
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
bool init;
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2020-01-08 12:59:48 +11:00
|
|
|
ePaintOverlayControlFlags overlay_flags = BKE_paint_get_overlay_flags();
|
2019-04-17 06:17:24 +02:00
|
|
|
GLubyte *buffer = NULL;
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
int size;
|
|
|
|
|
const bool refresh = !cursor_snap.overlay_texture ||
|
2019-09-17 16:27:01 +02:00
|
|
|
(overlay_flags & PAINT_OVERLAY_INVALID_CURVE) || cursor_snap.zoom != zoom ||
|
|
|
|
|
cursor_snap.curve_preset != br->curve_preset;
|
2013-10-09 16:00:15 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
init = (cursor_snap.overlay_texture != 0);
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (refresh) {
|
|
|
|
|
int s, r;
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
cursor_snap.zoom = zoom;
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
s = BKE_brush_size_get(vc->scene, br);
|
|
|
|
|
r = 1;
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
for (s >>= 1; s > 0; s >>= 1) {
|
2019-04-17 06:17:24 +02:00
|
|
|
r++;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
size = (1 << r);
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (size < 256) {
|
2019-04-17 06:17:24 +02:00
|
|
|
size = 256;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (size < cursor_snap.size) {
|
2019-04-17 06:17:24 +02:00
|
|
|
size = cursor_snap.size;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-17 06:17:24 +02: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
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
init = false;
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
cursor_snap.size = size;
|
|
|
|
|
}
|
|
|
|
|
buffer = MEM_mallocN(sizeof(GLubyte) * size * size, "load_tex");
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-08-07 03:21:55 +10:00
|
|
|
BKE_curvemapping_initialize(br->curve);
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
LoadTexData data = {
|
|
|
|
|
.br = br,
|
|
|
|
|
.buffer = buffer,
|
|
|
|
|
.size = size,
|
|
|
|
|
};
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-07-30 14:56:47 +02:00
|
|
|
TaskParallelSettings settings;
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_parallel_range_settings_defaults(&settings);
|
|
|
|
|
BLI_task_parallel_range(0, size, &data, load_tex_cursor_task_cb, &settings);
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (!cursor_snap.overlay_texture) {
|
2019-04-17 06:17:24 +02:00
|
|
|
glGenTextures(1, &cursor_snap.overlay_texture);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
size = cursor_snap.size;
|
|
|
|
|
}
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, cursor_snap.overlay_texture);
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (refresh) {
|
|
|
|
|
if (!init) {
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, size, size, 0, GL_RED, GL_UNSIGNED_BYTE, buffer);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_RED, GL_UNSIGNED_BYTE, buffer);
|
|
|
|
|
}
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (buffer) {
|
2019-04-17 06:17:24 +02:00
|
|
|
MEM_freeN(buffer);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-17 06:17:24 +02: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
|
|
|
|
2019-04-17 06:17:24 +02: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
|
|
|
|
2019-09-17 16:27:01 +02:00
|
|
|
cursor_snap.curve_preset = br->curve_preset;
|
2019-04-17 06:17:24 +02:00
|
|
|
BKE_paint_reset_overlay_invalid(PAINT_OVERLAY_INVALID_CURVE);
|
2013-04-22 20:46:18 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return 1;
|
2013-04-22 20:46:18 +00:00
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static int project_brush_radius(ViewContext *vc, float radius, const float location[3])
|
2012-01-19 02:06:09 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
float view[3], nonortho[3], ortho[3], offset[3], p1[2], p2[2];
|
|
|
|
|
|
|
|
|
|
ED_view3d_global_to_vector(vc->rv3d, location, view);
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Create a vector that is not orthogonal to view. */
|
2019-04-17 06:17:24 +02: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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Get a vector in the plane of the view. */
|
2019-04-17 06:17:24 +02:00
|
|
|
cross_v3_v3v3(ortho, nonortho, view);
|
|
|
|
|
normalize_v3(ortho);
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Make a point on the surface of the brush tangent to the view. */
|
2019-04-17 06:17:24 +02:00
|
|
|
mul_v3_fl(ortho, radius);
|
|
|
|
|
add_v3_v3v3(offset, location, ortho);
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Project the center of the brush, and the tangent point to the view onto the screen. */
|
2020-03-06 16:56:42 +01:00
|
|
|
if ((ED_view3d_project_float_global(vc->region, location, p1, V3D_PROJ_TEST_NOP) ==
|
2019-04-17 06:17:24 +02:00
|
|
|
V3D_PROJ_RET_OK) &&
|
2020-03-06 16:56:42 +01:00
|
|
|
(ED_view3d_project_float_global(vc->region, offset, p2, V3D_PROJ_TEST_NOP) ==
|
|
|
|
|
V3D_PROJ_RET_OK)) {
|
2020-02-08 23:59:22 +01:00
|
|
|
/* The distance between these points is the size of the projected brush in pixels. */
|
2019-04-17 06:17:24 +02:00
|
|
|
return len_v2v2(p1, p2);
|
|
|
|
|
}
|
2020-07-03 16:09:51 +02:00
|
|
|
/* Assert because the code that sets up the vectors should disallow this. */
|
|
|
|
|
BLI_assert(0);
|
|
|
|
|
return 0;
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static bool sculpt_get_brush_geometry(bContext *C,
|
|
|
|
|
ViewContext *vc,
|
|
|
|
|
int x,
|
|
|
|
|
int y,
|
|
|
|
|
int *pixel_radius,
|
|
|
|
|
float location[3],
|
|
|
|
|
UnifiedPaintSettings *ups)
|
2012-01-19 02:06:09 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
|
Paint *paint = BKE_paint_get_active_from_context(C);
|
|
|
|
|
float mouse[2];
|
|
|
|
|
bool hit = false;
|
|
|
|
|
|
|
|
|
|
mouse[0] = x;
|
|
|
|
|
mouse[1] = y;
|
|
|
|
|
|
|
|
|
|
if (vc->obact->sculpt && vc->obact->sculpt->pbvh) {
|
|
|
|
|
if (!ups->stroke_active) {
|
2020-03-06 15:24:15 +01:00
|
|
|
hit = SCULPT_stroke_get_location(C, location, mouse);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
hit = ups->last_hit;
|
|
|
|
|
copy_v3_v3(location, ups->last_location);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hit) {
|
|
|
|
|
Brush *brush = BKE_paint_brush(paint);
|
|
|
|
|
|
|
|
|
|
*pixel_radius = project_brush_radius(
|
|
|
|
|
vc, BKE_brush_unprojected_radius_get(scene, brush), location);
|
|
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (*pixel_radius == 0) {
|
2019-04-17 06:17:24 +02:00
|
|
|
*pixel_radius = BKE_brush_size_get(scene, brush);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
mul_m4_v3(vc->obact->obmat, location);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
|
|
|
|
|
Brush *brush = BKE_paint_brush(&sd->paint);
|
|
|
|
|
|
|
|
|
|
*pixel_radius = BKE_brush_size_get(scene, brush);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hit;
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Draw an overlay that shows what effect the brush's texture will
|
2020-02-08 23:59:22 +01:00
|
|
|
* have on brush strength. */
|
2019-08-30 16:27:31 +02:00
|
|
|
static bool paint_draw_tex_overlay(UnifiedPaintSettings *ups,
|
2019-04-17 06:17:24 +02:00
|
|
|
Brush *brush,
|
|
|
|
|
ViewContext *vc,
|
|
|
|
|
int x,
|
|
|
|
|
int y,
|
|
|
|
|
float zoom,
|
|
|
|
|
bool col,
|
|
|
|
|
bool primary)
|
2012-01-19 02:06:09 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
rctf quad;
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Check for overlay mode. */
|
2019-04-17 06:17:24 +02: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;
|
|
|
|
|
|
|
|
|
|
if (!(mtex->tex) ||
|
|
|
|
|
!((mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) ||
|
|
|
|
|
(valid && ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_TILED)))) {
|
2019-08-30 16:27:31 +02:00
|
|
|
return false;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (load_tex(brush, vc, zoom, col, primary)) {
|
|
|
|
|
GPU_blend(true);
|
|
|
|
|
|
|
|
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
|
glDepthFunc(GL_ALWAYS);
|
|
|
|
|
|
|
|
|
|
if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
|
|
|
|
|
GPU_matrix_push();
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Brush rotation. */
|
2019-04-17 06:17:24 +02:00
|
|
|
GPU_matrix_translate_2f(x, y);
|
|
|
|
|
GPU_matrix_rotate_2d(-RAD2DEGF(primary ? ups->brush_rotation : ups->brush_rotation_sec));
|
|
|
|
|
GPU_matrix_translate_2f(-x, -y);
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Scale based on tablet pressure. */
|
2019-11-27 02:02:18 +01:00
|
|
|
if (primary && ups->stroke_active && BKE_brush_use_size_pressure(brush)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
const float scale = ups->size_pressure_value;
|
|
|
|
|
GPU_matrix_translate_2f(x, y);
|
|
|
|
|
GPU_matrix_scale_2f(scale, scale);
|
|
|
|
|
GPU_matrix_translate_2f(-x, -y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ups->draw_anchored) {
|
|
|
|
|
quad.xmin = ups->anchored_initial_mouse[0] - ups->anchored_size;
|
|
|
|
|
quad.ymin = ups->anchored_initial_mouse[1] - ups->anchored_size;
|
|
|
|
|
quad.xmax = ups->anchored_initial_mouse[0] + ups->anchored_size;
|
|
|
|
|
quad.ymax = ups->anchored_initial_mouse[1] + ups->anchored_size;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
|
|
|
|
|
quad.xmin = x - radius;
|
|
|
|
|
quad.ymin = y - radius;
|
|
|
|
|
quad.xmax = x + radius;
|
|
|
|
|
quad.ymax = y + radius;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
|
|
|
|
|
quad.xmin = 0;
|
|
|
|
|
quad.ymin = 0;
|
2020-03-06 16:56:42 +01:00
|
|
|
quad.xmax = BLI_rcti_size_x(&vc->region->winrct);
|
|
|
|
|
quad.ymax = BLI_rcti_size_y(&vc->region->winrct);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Stencil code goes here. */
|
2019-04-17 06:17:24 +02:00
|
|
|
else {
|
|
|
|
|
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];
|
|
|
|
|
}
|
|
|
|
|
GPU_matrix_push();
|
2019-04-22 09:19:45 +10:00
|
|
|
if (primary) {
|
2019-04-17 06:17:24 +02:00
|
|
|
GPU_matrix_translate_2fv(brush->stencil_pos);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2019-04-17 06:17:24 +02:00
|
|
|
GPU_matrix_translate_2fv(brush->mask_stencil_pos);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
GPU_matrix_rotate_2d(RAD2DEGF(mtex->rot));
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Set quad color. Colored overlay does not get blending. */
|
2019-04-17 06:17:24 +02:00
|
|
|
GPUVertFormat *format = immVertexFormat();
|
|
|
|
|
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
|
|
|
|
uint texCoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
|
|
|
|
|
|
|
|
|
if (col) {
|
|
|
|
|
immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
|
|
|
|
|
immUniformColor4f(1.0f, 1.0f, 1.0f, overlay_alpha * 0.01f);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_ALPHA_COLOR);
|
|
|
|
|
immUniformColor3fvAlpha(U.sculpt_paint_overlay_col, overlay_alpha * 0.01f);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Draw textured quad. */
|
2019-04-17 06:17:24 +02:00
|
|
|
immUniform1i("image", 0);
|
|
|
|
|
|
|
|
|
|
immBegin(GPU_PRIM_TRI_FAN, 4);
|
|
|
|
|
immAttr2f(texCoord, 0.0f, 0.0f);
|
|
|
|
|
immVertex2f(pos, quad.xmin, quad.ymin);
|
|
|
|
|
immAttr2f(texCoord, 1.0f, 0.0f);
|
|
|
|
|
immVertex2f(pos, quad.xmax, quad.ymin);
|
|
|
|
|
immAttr2f(texCoord, 1.0f, 1.0f);
|
|
|
|
|
immVertex2f(pos, quad.xmax, quad.ymax);
|
|
|
|
|
immAttr2f(texCoord, 0.0f, 1.0f);
|
|
|
|
|
immVertex2f(pos, quad.xmin, quad.ymax);
|
|
|
|
|
immEnd();
|
|
|
|
|
|
|
|
|
|
immUnbindProgram();
|
|
|
|
|
GPU_blend_set_func(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
|
|
|
|
|
if (ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_VIEW)) {
|
|
|
|
|
GPU_matrix_pop();
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-30 16:27:31 +02:00
|
|
|
return true;
|
2013-04-22 20:46:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Draw an overlay that shows what effect the brush's texture will
|
2020-02-08 23:59:22 +01:00
|
|
|
* have on brush strength. */
|
2019-08-30 16:27:31 +02:00
|
|
|
static bool paint_draw_cursor_overlay(
|
2019-04-17 06:17:24 +02:00
|
|
|
UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc, int x, int y, float zoom)
|
2013-04-22 20:46:18 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
rctf quad;
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Check for overlay mode. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
if (!(brush->overlay_flags & BRUSH_OVERLAY_CURSOR)) {
|
2019-08-30 16:27:31 +02:00
|
|
|
return false;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (load_tex_cursor(brush, vc, zoom)) {
|
|
|
|
|
bool do_pop = false;
|
|
|
|
|
float center[2];
|
|
|
|
|
GPU_blend(true);
|
|
|
|
|
|
|
|
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
|
glDepthFunc(GL_ALWAYS);
|
|
|
|
|
|
|
|
|
|
if (ups->draw_anchored) {
|
|
|
|
|
copy_v2_v2(center, ups->anchored_initial_mouse);
|
|
|
|
|
quad.xmin = ups->anchored_initial_mouse[0] - ups->anchored_size;
|
|
|
|
|
quad.ymin = ups->anchored_initial_mouse[1] - ups->anchored_size;
|
|
|
|
|
quad.xmax = ups->anchored_initial_mouse[0] + ups->anchored_size;
|
|
|
|
|
quad.ymax = ups->anchored_initial_mouse[1] + ups->anchored_size;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
|
|
|
|
|
center[0] = x;
|
|
|
|
|
center[1] = y;
|
|
|
|
|
|
|
|
|
|
quad.xmin = x - radius;
|
|
|
|
|
quad.ymin = y - radius;
|
|
|
|
|
quad.xmax = x + radius;
|
|
|
|
|
quad.ymax = y + radius;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Scale based on tablet pressure. */
|
2019-11-27 02:02:18 +01:00
|
|
|
if (ups->stroke_active && BKE_brush_use_size_pressure(brush)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
do_pop = true;
|
|
|
|
|
GPU_matrix_push();
|
|
|
|
|
GPU_matrix_translate_2fv(center);
|
|
|
|
|
GPU_matrix_scale_1f(ups->size_pressure_value);
|
|
|
|
|
GPU_matrix_translate_2f(-center[0], -center[1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GPUVertFormat *format = immVertexFormat();
|
|
|
|
|
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
|
|
|
|
uint texCoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
|
|
|
|
|
|
|
|
|
GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_ALPHA_COLOR);
|
|
|
|
|
|
|
|
|
|
immUniformColor3fvAlpha(U.sculpt_paint_overlay_col, brush->cursor_overlay_alpha * 0.01f);
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Draw textured quad. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Draw textured quad. */
|
2019-04-17 06:17:24 +02:00
|
|
|
immUniform1i("image", 0);
|
|
|
|
|
|
|
|
|
|
immBegin(GPU_PRIM_TRI_FAN, 4);
|
|
|
|
|
immAttr2f(texCoord, 0.0f, 0.0f);
|
|
|
|
|
immVertex2f(pos, quad.xmin, quad.ymin);
|
|
|
|
|
immAttr2f(texCoord, 1.0f, 0.0f);
|
|
|
|
|
immVertex2f(pos, quad.xmax, quad.ymin);
|
|
|
|
|
immAttr2f(texCoord, 1.0f, 1.0f);
|
|
|
|
|
immVertex2f(pos, quad.xmax, quad.ymax);
|
|
|
|
|
immAttr2f(texCoord, 0.0f, 1.0f);
|
|
|
|
|
immVertex2f(pos, quad.xmin, quad.ymax);
|
|
|
|
|
immEnd();
|
|
|
|
|
|
|
|
|
|
immUnbindProgram();
|
|
|
|
|
|
|
|
|
|
GPU_blend_set_func(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (do_pop) {
|
2019-04-17 06:17:24 +02:00
|
|
|
GPU_matrix_pop();
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-08-30 16:27:31 +02:00
|
|
|
return true;
|
2013-04-22 20:46:18 +00:00
|
|
|
}
|
|
|
|
|
|
2019-08-30 16:27:31 +02:00
|
|
|
static bool paint_draw_alpha_overlay(UnifiedPaintSettings *ups,
|
2019-04-17 06:17:24 +02:00
|
|
|
Brush *brush,
|
|
|
|
|
ViewContext *vc,
|
|
|
|
|
int x,
|
|
|
|
|
int y,
|
|
|
|
|
float zoom,
|
|
|
|
|
ePaintMode mode)
|
2013-04-22 20:46:18 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* Color means that primary brush texture is colored and
|
|
|
|
|
* secondary is used for alpha/mask control. */
|
|
|
|
|
bool col = ELEM(mode, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D, PAINT_MODE_VERTEX);
|
2019-08-30 16:27:31 +02:00
|
|
|
|
|
|
|
|
bool alpha_overlay_active = false;
|
|
|
|
|
|
2020-01-08 12:59:48 +11:00
|
|
|
ePaintOverlayControlFlags flags = BKE_paint_get_overlay_flags();
|
2019-04-17 06:17:24 +02:00
|
|
|
gpuPushAttr(GPU_DEPTH_BUFFER_BIT | GPU_BLEND_BIT);
|
|
|
|
|
|
|
|
|
|
/* Translate to region. */
|
|
|
|
|
GPU_matrix_push();
|
2020-03-06 16:56:42 +01:00
|
|
|
GPU_matrix_translate_2f(vc->region->winrct.xmin, vc->region->winrct.ymin);
|
|
|
|
|
x -= vc->region->winrct.xmin;
|
|
|
|
|
y -= vc->region->winrct.ymin;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-29 14:14:14 +10:00
|
|
|
/* Colored overlay should be drawn separately. */
|
2019-04-17 06:17:24 +02:00
|
|
|
if (col) {
|
2019-04-22 09:19:45 +10:00
|
|
|
if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY)) {
|
2019-08-30 16:27:31 +02:00
|
|
|
alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, true, true);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
if (!(flags & PAINT_OVERLAY_OVERRIDE_SECONDARY)) {
|
2019-08-30 16:27:31 +02:00
|
|
|
alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, false);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR)) {
|
2019-08-30 16:27:31 +02:00
|
|
|
alpha_overlay_active = paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2019-04-22 09:19:45 +10:00
|
|
|
if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY) && (mode != PAINT_MODE_WEIGHT)) {
|
2019-08-30 16:27:31 +02:00
|
|
|
alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, true);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR)) {
|
2019-08-30 16:27:31 +02:00
|
|
|
alpha_overlay_active = paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GPU_matrix_pop();
|
|
|
|
|
gpuPopAttr();
|
2019-08-30 16:27:31 +02:00
|
|
|
|
|
|
|
|
return alpha_overlay_active;
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
2020-07-13 11:27:09 +02:00
|
|
|
BLI_INLINE void draw_tri_point(uint pos,
|
|
|
|
|
const float sel_col[4],
|
|
|
|
|
const float pivot_col[4],
|
|
|
|
|
float *co,
|
|
|
|
|
float width,
|
|
|
|
|
bool selected)
|
2014-07-21 12:02:05 +02:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
immUniformColor4fv(selected ? sel_col : pivot_col);
|
|
|
|
|
|
|
|
|
|
GPU_line_width(3.0f);
|
|
|
|
|
|
|
|
|
|
float w = width / 2.0f;
|
2019-09-14 08:10:50 +10:00
|
|
|
const float tri[3][2] = {
|
2019-04-17 06:17:24 +02:00
|
|
|
{co[0], co[1] + w},
|
|
|
|
|
{co[0] - w, co[1] - w},
|
|
|
|
|
{co[0] + w, co[1] - w},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
immBegin(GPU_PRIM_LINE_LOOP, 3);
|
|
|
|
|
immVertex2fv(pos, tri[0]);
|
|
|
|
|
immVertex2fv(pos, tri[1]);
|
|
|
|
|
immVertex2fv(pos, tri[2]);
|
|
|
|
|
immEnd();
|
|
|
|
|
|
|
|
|
|
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
|
|
|
|
|
GPU_line_width(1.0f);
|
|
|
|
|
|
|
|
|
|
immBegin(GPU_PRIM_LINE_LOOP, 3);
|
|
|
|
|
immVertex2fv(pos, tri[0]);
|
|
|
|
|
immVertex2fv(pos, tri[1]);
|
|
|
|
|
immVertex2fv(pos, tri[2]);
|
|
|
|
|
immEnd();
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-13 11:27:09 +02:00
|
|
|
BLI_INLINE void draw_rect_point(uint pos,
|
|
|
|
|
const float sel_col[4],
|
|
|
|
|
const float handle_col[4],
|
|
|
|
|
const float *co,
|
|
|
|
|
float width,
|
|
|
|
|
bool selected)
|
2014-07-21 12:02:05 +02:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
immUniformColor4fv(selected ? sel_col : handle_col);
|
2017-04-16 12:25:42 -04:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
GPU_line_width(3.0f);
|
2017-03-23 01:33:34 -03:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
float w = width / 2.0f;
|
|
|
|
|
float minx = co[0] - w;
|
|
|
|
|
float miny = co[1] - w;
|
|
|
|
|
float maxx = co[0] + w;
|
|
|
|
|
float maxy = co[1] + w;
|
2017-03-23 01:33:34 -03:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
|
2017-03-23 01:33:34 -03:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
|
|
|
|
|
GPU_line_width(1.0f);
|
2017-03-23 01:33:34 -03:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-03 16:21:24 +11:00
|
|
|
BLI_INLINE void draw_bezier_handle_lines(uint pos, float sel_col[4], BezTriple *bez)
|
2014-07-21 12:02:05 +02:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
|
|
|
|
|
GPU_line_width(3.0f);
|
|
|
|
|
|
|
|
|
|
immBegin(GPU_PRIM_LINE_STRIP, 3);
|
|
|
|
|
immVertex2fv(pos, bez->vec[0]);
|
|
|
|
|
immVertex2fv(pos, bez->vec[1]);
|
|
|
|
|
immVertex2fv(pos, bez->vec[2]);
|
|
|
|
|
immEnd();
|
|
|
|
|
|
|
|
|
|
GPU_line_width(1.0f);
|
|
|
|
|
|
|
|
|
|
if (bez->f1 || bez->f2) {
|
|
|
|
|
immUniformColor4fv(sel_col);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
|
|
|
|
|
}
|
|
|
|
|
immBegin(GPU_PRIM_LINES, 2);
|
|
|
|
|
immVertex2fv(pos, bez->vec[0]);
|
|
|
|
|
immVertex2fv(pos, bez->vec[1]);
|
|
|
|
|
immEnd();
|
|
|
|
|
|
|
|
|
|
if (bez->f3 || bez->f2) {
|
|
|
|
|
immUniformColor4fv(sel_col);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
|
|
|
|
|
}
|
|
|
|
|
immBegin(GPU_PRIM_LINES, 2);
|
|
|
|
|
immVertex2fv(pos, bez->vec[1]);
|
|
|
|
|
immVertex2fv(pos, bez->vec[2]);
|
|
|
|
|
immEnd();
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
|
|
|
|
|
2018-10-16 21:36:22 -03:00
|
|
|
static void paint_draw_curve_cursor(Brush *brush, ViewContext *vc)
|
2014-07-21 12:02:05 +02:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
GPU_matrix_push();
|
2020-03-06 16:56:42 +01:00
|
|
|
GPU_matrix_translate_2f(vc->region->winrct.xmin, vc->region->winrct.ymin);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
if (brush->paint_curve && brush->paint_curve->points) {
|
|
|
|
|
int i;
|
|
|
|
|
PaintCurve *pc = brush->paint_curve;
|
|
|
|
|
PaintCurvePoint *cp = pc->points;
|
|
|
|
|
|
|
|
|
|
GPU_line_smooth(true);
|
|
|
|
|
GPU_blend(true);
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Draw the bezier handles and the curve segment between the current and next point. */
|
2019-04-17 06:17:24 +02:00
|
|
|
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
|
|
|
|
|
|
|
|
|
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
|
|
|
|
|
|
|
|
|
|
float selec_col[4], handle_col[4], pivot_col[4];
|
2019-07-16 20:31:23 +02:00
|
|
|
UI_GetThemeColorType4fv(TH_VERTEX_SELECT, SPACE_VIEW3D, selec_col);
|
|
|
|
|
UI_GetThemeColorType4fv(TH_PAINT_CURVE_HANDLE, SPACE_VIEW3D, handle_col);
|
|
|
|
|
UI_GetThemeColorType4fv(TH_PAINT_CURVE_PIVOT, SPACE_VIEW3D, pivot_col);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
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];
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Use color coding to distinguish handles vs curve segments. */
|
2019-04-17 06:17:24 +02:00
|
|
|
draw_bezier_handle_lines(pos, selec_col, &cp->bez);
|
|
|
|
|
draw_tri_point(pos, selec_col, pivot_col, &cp->bez.vec[1][0], 10.0f, cp->bez.f2);
|
|
|
|
|
draw_rect_point(
|
|
|
|
|
pos, selec_col, handle_col, &cp->bez.vec[0][0], 8.0f, cp->bez.f1 || cp->bez.f2);
|
|
|
|
|
draw_rect_point(
|
|
|
|
|
pos, selec_col, handle_col, &cp->bez.vec[2][0], 8.0f, cp->bez.f3 || cp->bez.f2);
|
|
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
for (j = 0; j < 2; j++) {
|
2019-04-17 06:17:24 +02:00
|
|
|
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]));
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
float(*v)[2] = (float(*)[2])data;
|
|
|
|
|
|
|
|
|
|
immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
|
|
|
|
|
GPU_line_width(3.0f);
|
|
|
|
|
immBegin(GPU_PRIM_LINE_STRIP, PAINT_CURVE_NUM_SEGMENTS + 1);
|
|
|
|
|
for (j = 0; j <= PAINT_CURVE_NUM_SEGMENTS; j++) {
|
|
|
|
|
immVertex2fv(pos, v[j]);
|
|
|
|
|
}
|
|
|
|
|
immEnd();
|
|
|
|
|
|
|
|
|
|
immUniformColor4f(0.9f, 0.9f, 1.0f, 0.5f);
|
|
|
|
|
GPU_line_width(1.0f);
|
|
|
|
|
immBegin(GPU_PRIM_LINE_STRIP, PAINT_CURVE_NUM_SEGMENTS + 1);
|
|
|
|
|
for (j = 0; j <= PAINT_CURVE_NUM_SEGMENTS; j++) {
|
|
|
|
|
immVertex2fv(pos, v[j]);
|
|
|
|
|
}
|
|
|
|
|
immEnd();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Draw last line segment. */
|
2019-04-17 06:17:24 +02:00
|
|
|
draw_bezier_handle_lines(pos, selec_col, &cp->bez);
|
|
|
|
|
draw_tri_point(pos, selec_col, pivot_col, &cp->bez.vec[1][0], 10.0f, cp->bez.f2);
|
|
|
|
|
draw_rect_point(
|
|
|
|
|
pos, selec_col, handle_col, &cp->bez.vec[0][0], 8.0f, cp->bez.f1 || cp->bez.f2);
|
|
|
|
|
draw_rect_point(
|
|
|
|
|
pos, selec_col, handle_col, &cp->bez.vec[2][0], 8.0f, cp->bez.f3 || cp->bez.f2);
|
|
|
|
|
|
|
|
|
|
GPU_blend(false);
|
|
|
|
|
GPU_line_smooth(false);
|
|
|
|
|
|
|
|
|
|
immUnbindProgram();
|
|
|
|
|
}
|
|
|
|
|
GPU_matrix_pop();
|
2014-07-21 12:02:05 +02:00
|
|
|
}
|
|
|
|
|
|
2012-01-19 02:06:09 +00:00
|
|
|
/* Special actions taken when paint cursor goes over mesh */
|
2020-02-08 23:59:22 +01:00
|
|
|
/* TODO: sculpt only for now. */
|
2019-04-17 06:17:24 +02:00
|
|
|
static void paint_cursor_on_hit(UnifiedPaintSettings *ups,
|
|
|
|
|
Brush *brush,
|
|
|
|
|
ViewContext *vc,
|
|
|
|
|
const float location[3])
|
2012-01-19 02:06:09 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
float unprojected_radius, projected_radius;
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Update the brush's cached 3D radius. */
|
2019-04-17 06:17:24 +02:00
|
|
|
if (!BKE_brush_use_locked_size(vc->scene, brush)) {
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Get 2D brush radius. */
|
2019-04-22 09:19:45 +10:00
|
|
|
if (ups->draw_anchored) {
|
2019-04-17 06:17:24 +02:00
|
|
|
projected_radius = ups->anchored_size;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
else {
|
2019-04-22 09:19:45 +10:00
|
|
|
if (brush->flag & BRUSH_ANCHORED) {
|
2019-04-17 06:17:24 +02:00
|
|
|
projected_radius = 8;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2019-04-17 06:17:24 +02:00
|
|
|
projected_radius = BKE_brush_size_get(vc->scene, brush);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Convert brush radius from 2D to 3D. */
|
2019-04-17 06:17:24 +02:00
|
|
|
unprojected_radius = paint_calc_object_space_radius(vc, location, projected_radius);
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Scale 3D brush radius by pressure. */
|
2019-11-27 02:02:18 +01:00
|
|
|
if (ups->stroke_active && BKE_brush_use_size_pressure(brush)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
unprojected_radius *= ups->size_pressure_value;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Set cached value in either Brush or UnifiedPaintSettings. */
|
2019-04-17 06:17:24 +02: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
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (paint->flags & PAINT_SHOW_BRUSH) {
|
|
|
|
|
if (ELEM(mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D) &&
|
|
|
|
|
brush->imagepaint_tool == PAINT_TOOL_FILL) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2015-06-03 12:04:47 +02:00
|
|
|
}
|
|
|
|
|
|
2020-02-08 20:04:42 +01:00
|
|
|
static void cursor_draw_point_screen_space(const uint gpuattr,
|
2020-03-06 16:56:42 +01:00
|
|
|
const ARegion *region,
|
2020-02-08 20:04:42 +01:00
|
|
|
const float true_location[3],
|
|
|
|
|
const float obmat[4][4],
|
|
|
|
|
const int size)
|
2019-08-30 16:27:31 +02:00
|
|
|
{
|
2019-08-30 19:33:15 +02:00
|
|
|
float translation_vertex_cursor[3], location[3];
|
2019-08-30 16:27:31 +02:00
|
|
|
copy_v3_v3(location, true_location);
|
|
|
|
|
mul_m4_v3(obmat, location);
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_project(region, location, translation_vertex_cursor);
|
2020-01-23 21:41:30 +01:00
|
|
|
/* Do not draw points behind the view. Z [near, far] is mapped to [-1, 1]. */
|
|
|
|
|
if (translation_vertex_cursor[2] <= 1.0f) {
|
|
|
|
|
imm_draw_circle_fill_3d(
|
|
|
|
|
gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], size, 10);
|
|
|
|
|
}
|
2019-08-30 16:27:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void cursor_draw_tiling_preview(const uint gpuattr,
|
2020-03-06 16:56:42 +01:00
|
|
|
const ARegion *region,
|
2019-09-14 08:10:50 +10:00
|
|
|
const float true_location[3],
|
2019-08-30 16:27:31 +02:00
|
|
|
Sculpt *sd,
|
|
|
|
|
Object *ob,
|
2020-02-08 20:04:42 +01:00
|
|
|
const float radius)
|
2019-08-30 16:27:31 +02:00
|
|
|
{
|
|
|
|
|
BoundBox *bb = BKE_object_boundbox_get(ob);
|
|
|
|
|
float orgLoc[3], location[3];
|
2020-02-08 20:04:42 +01:00
|
|
|
int tile_pass = 0;
|
2019-08-30 16:27:31 +02:00
|
|
|
int start[3];
|
|
|
|
|
int end[3];
|
|
|
|
|
int cur[3];
|
|
|
|
|
const float *bbMin = bb->vec[0];
|
|
|
|
|
const float *bbMax = bb->vec[6];
|
|
|
|
|
const float *step = sd->paint.tile_offset;
|
|
|
|
|
|
|
|
|
|
copy_v3_v3(orgLoc, true_location);
|
2020-02-08 20:04:42 +01:00
|
|
|
for (int dim = 0; dim < 3; dim++) {
|
2019-08-30 16:27:31 +02:00
|
|
|
if ((sd->paint.symmetry_flags & (PAINT_TILE_X << dim)) && step[dim] > 0) {
|
|
|
|
|
start[dim] = (bbMin[dim] - orgLoc[dim] - radius) / step[dim];
|
|
|
|
|
end[dim] = (bbMax[dim] - orgLoc[dim] + radius) / step[dim];
|
|
|
|
|
}
|
2019-09-07 21:08:20 +10:00
|
|
|
else {
|
2019-08-30 16:27:31 +02:00
|
|
|
start[dim] = end[dim] = 0;
|
2019-09-07 21:08:20 +10:00
|
|
|
}
|
2019-08-30 16:27:31 +02:00
|
|
|
}
|
|
|
|
|
copy_v3_v3_int(cur, start);
|
|
|
|
|
for (cur[0] = start[0]; cur[0] <= end[0]; cur[0]++) {
|
|
|
|
|
for (cur[1] = start[1]; cur[1] <= end[1]; cur[1]++) {
|
|
|
|
|
for (cur[2] = start[2]; cur[2] <= end[2]; cur[2]++) {
|
2019-09-07 21:08:20 +10:00
|
|
|
if (!cur[0] && !cur[1] && !cur[2]) {
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Skip tile at orgLoc, this was already handled before all others. */
|
2019-09-07 21:08:20 +10:00
|
|
|
continue;
|
|
|
|
|
}
|
2019-08-30 16:27:31 +02:00
|
|
|
tile_pass++;
|
2020-02-08 20:04:42 +01:00
|
|
|
for (int dim = 0; dim < 3; dim++) {
|
2019-08-30 16:27:31 +02:00
|
|
|
location[dim] = cur[dim] * step[dim] + orgLoc[dim];
|
|
|
|
|
}
|
2020-03-06 16:56:42 +01:00
|
|
|
cursor_draw_point_screen_space(gpuattr, region, location, ob->obmat, 3);
|
2019-08-30 16:27:31 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void cursor_draw_point_with_symmetry(const uint gpuattr,
|
2020-03-06 16:56:42 +01:00
|
|
|
const ARegion *region,
|
2019-08-30 16:27:31 +02:00
|
|
|
const float true_location[3],
|
|
|
|
|
Sculpt *sd,
|
|
|
|
|
Object *ob,
|
2020-02-08 20:04:42 +01:00
|
|
|
const float radius)
|
2019-08-30 16:27:31 +02:00
|
|
|
{
|
|
|
|
|
const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
|
|
|
|
|
float location[3], symm_rot_mat[4][4];
|
|
|
|
|
|
2019-09-08 00:12:26 +10:00
|
|
|
for (int i = 0; i <= symm; i++) {
|
2019-08-30 16:27:31 +02:00
|
|
|
if (i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Axis Symmetry. */
|
2019-08-30 16:27:31 +02:00
|
|
|
flip_v3_v3(location, true_location, (char)i);
|
2020-03-06 16:56:42 +01:00
|
|
|
cursor_draw_point_screen_space(gpuattr, region, location, ob->obmat, 3);
|
2019-08-30 16:27:31 +02:00
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Tiling. */
|
2020-03-06 16:56:42 +01:00
|
|
|
cursor_draw_tiling_preview(gpuattr, region, location, sd, ob, radius);
|
2019-08-30 16:27:31 +02:00
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Radial Symmetry. */
|
2019-08-30 16:27:31 +02:00
|
|
|
for (char raxis = 0; raxis < 3; raxis++) {
|
|
|
|
|
for (int r = 1; r < sd->radial_symm[raxis]; r++) {
|
|
|
|
|
float angle = 2 * M_PI * r / sd->radial_symm[(int)raxis];
|
|
|
|
|
flip_v3_v3(location, true_location, (char)i);
|
|
|
|
|
unit_m4(symm_rot_mat);
|
|
|
|
|
rotate_m4(symm_rot_mat, raxis + 'X', angle);
|
|
|
|
|
mul_m4_v3(symm_rot_mat, location);
|
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
cursor_draw_tiling_preview(gpuattr, region, location, sd, ob, radius);
|
|
|
|
|
cursor_draw_point_screen_space(gpuattr, region, location, ob->obmat, 3);
|
2019-08-30 16:27:31 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-09 22:23:54 +02:00
|
|
|
static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession *ss)
|
|
|
|
|
{
|
|
|
|
|
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.6f);
|
2019-09-17 12:15:21 +02:00
|
|
|
|
|
|
|
|
/* Cursor normally draws on top, but for this part we need depth tests. */
|
|
|
|
|
const bool depth_test = GPU_depth_test_enabled();
|
|
|
|
|
if (!depth_test) {
|
|
|
|
|
GPU_depth_test(true);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-09 22:23:54 +02:00
|
|
|
GPU_line_width(1.0f);
|
|
|
|
|
if (ss->preview_vert_index_count > 0) {
|
|
|
|
|
immBegin(GPU_PRIM_LINES, ss->preview_vert_index_count);
|
|
|
|
|
for (int i = 0; i < ss->preview_vert_index_count; i++) {
|
2020-03-06 15:24:15 +01:00
|
|
|
immVertex3fv(gpuattr, SCULPT_vertex_co_get(ss, ss->preview_vert_index_list[i]));
|
2019-09-09 22:23:54 +02:00
|
|
|
}
|
|
|
|
|
immEnd();
|
|
|
|
|
}
|
2019-09-17 12:15:21 +02:00
|
|
|
|
|
|
|
|
/* Restore depth test value. */
|
|
|
|
|
if (!depth_test) {
|
|
|
|
|
GPU_depth_test(false);
|
|
|
|
|
}
|
2019-09-09 22:23:54 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-15 17:35:31 +10:00
|
|
|
static void SCULPT_layer_brush_height_preview_draw(const uint gpuattr,
|
|
|
|
|
const Brush *brush,
|
|
|
|
|
const float obmat[4][4],
|
|
|
|
|
const float location[3],
|
|
|
|
|
const float normal[3],
|
|
|
|
|
const float rds,
|
|
|
|
|
const float line_width,
|
|
|
|
|
const float outline_col[3],
|
|
|
|
|
const float alpha)
|
2020-04-14 21:06:49 +02:00
|
|
|
{
|
|
|
|
|
float cursor_trans[4][4], cursor_rot[4][4];
|
|
|
|
|
float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
|
|
|
|
|
float quat[4];
|
|
|
|
|
float height_preview_trans[3];
|
|
|
|
|
copy_m4_m4(cursor_trans, obmat);
|
|
|
|
|
madd_v3_v3v3fl(height_preview_trans, location, normal, brush->height);
|
|
|
|
|
translate_m4(
|
|
|
|
|
cursor_trans, height_preview_trans[0], height_preview_trans[1], height_preview_trans[2]);
|
|
|
|
|
rotation_between_vecs_to_quat(quat, z_axis, normal);
|
|
|
|
|
quat_to_mat4(cursor_rot, quat);
|
|
|
|
|
GPU_matrix_mul(cursor_trans);
|
|
|
|
|
GPU_matrix_mul(cursor_rot);
|
|
|
|
|
|
|
|
|
|
GPU_line_width(line_width);
|
|
|
|
|
immUniformColor3fvAlpha(outline_col, alpha * 0.5f);
|
|
|
|
|
imm_draw_circle_wire_3d(gpuattr, 0, 0, rds, 80);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-18 12:28:12 +02:00
|
|
|
static bool paint_use_2d_cursor(ePaintMode mode)
|
|
|
|
|
{
|
|
|
|
|
if (mode >= PAINT_MODE_TEXTURE_3D) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-19 02:06:09 +00:00
|
|
|
static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
|
|
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
|
|
|
|
if (region && region->regiontype != RGN_TYPE_WINDOW) {
|
2019-10-25 01:25:23 +11:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
const wmWindowManager *wm = CTX_wm_manager(C);
|
2019-09-13 16:18:22 +02:00
|
|
|
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
|
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
|
|
|
|
|
Paint *paint = BKE_paint_get_active_from_context(C);
|
|
|
|
|
Brush *brush = BKE_paint_brush(paint);
|
|
|
|
|
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
|
|
|
|
|
|
2019-09-18 12:28:12 +02:00
|
|
|
/* 2d or 3d painting? */
|
|
|
|
|
const bool use_2d_cursor = paint_use_2d_cursor(mode);
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* check that brush drawing is enabled */
|
2019-04-22 09:19:45 +10:00
|
|
|
if (ommit_cursor_drawing(paint, mode, brush)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Can't use stroke vc here because this will be called during
|
|
|
|
|
* mouse over too, not just during a stroke. */
|
2019-04-17 06:17:24 +02:00
|
|
|
ViewContext vc;
|
2019-09-18 17:19:07 +02:00
|
|
|
ED_view3d_viewcontext_init(C, &vc, depsgraph);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
if (vc.rv3d && (vc.rv3d->rflag & RV3D_NAVIGATING)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Skip everything and draw brush here. */
|
2019-04-17 06:17:24 +02:00
|
|
|
if (brush->flag & BRUSH_CURVE) {
|
|
|
|
|
paint_draw_curve_cursor(brush, &vc);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float zoomx, zoomy;
|
|
|
|
|
get_imapaint_zoom(C, &zoomx, &zoomy);
|
|
|
|
|
zoomx = max_ff(zoomx, zoomy);
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Set various defaults. */
|
2019-04-17 06:17:24 +02:00
|
|
|
const float *outline_col = brush->add_col;
|
2019-12-30 16:41:20 +01:00
|
|
|
const float outline_alpha = brush->add_col[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
float translation[2] = {x, y};
|
|
|
|
|
float final_radius = (BKE_brush_size_get(scene, brush) * zoomx);
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Don't calculate rake angles while a stroke is active because the rake variables are global
|
2019-04-17 06:17:24 +02:00
|
|
|
* and we may get interference with the stroke itself.
|
2020-02-08 23:59:22 +01:00
|
|
|
* For line strokes, such interference is visible. */
|
2019-04-17 06:17:24 +02:00
|
|
|
if (!ups->stroke_active) {
|
|
|
|
|
paint_calculate_rake_rotation(ups, brush, translation);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Draw overlay. */
|
2019-09-26 14:12:08 +02:00
|
|
|
bool alpha_overlay_active = paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode);
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (ups->draw_anchored) {
|
|
|
|
|
final_radius = ups->anchored_size;
|
|
|
|
|
copy_v2_fl2(translation,
|
2020-03-06 16:56:42 +01:00
|
|
|
ups->anchored_initial_mouse[0] + region->winrct.xmin,
|
|
|
|
|
ups->anchored_initial_mouse[1] + region->winrct.ymin);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Make lines pretty. */
|
2019-08-30 16:27:31 +02:00
|
|
|
GPU_line_width(2.0f);
|
2020-02-08 23:59:22 +01:00
|
|
|
|
|
|
|
|
/* TODO: also set blend mode? */
|
|
|
|
|
GPU_blend(true);
|
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
GPU_line_smooth(true);
|
|
|
|
|
|
2019-09-18 12:28:12 +02:00
|
|
|
if (use_2d_cursor) {
|
|
|
|
|
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
|
|
|
|
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-09-18 12:28:12 +02:00
|
|
|
immUniformColor3fvAlpha(outline_col, outline_alpha);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Draw brush outline. */
|
2019-11-27 02:02:18 +01:00
|
|
|
if (ups->stroke_active && BKE_brush_use_size_pressure(brush)) {
|
2019-09-18 12:28:12 +02:00
|
|
|
imm_draw_circle_wire_2d(
|
|
|
|
|
pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Outer at half alpha. */
|
2019-09-26 14:17:25 +02:00
|
|
|
immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
|
2019-09-18 12:28:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GPU_line_width(1.0f);
|
|
|
|
|
imm_draw_circle_wire_2d(pos, translation[0], translation[1], final_radius, 40);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2020-02-08 23:59:22 +01:00
|
|
|
else {
|
|
|
|
|
/* 3D Painting. */
|
2019-09-18 12:28:12 +02:00
|
|
|
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
|
|
|
|
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
|
|
|
|
|
|
|
|
|
|
/* TODO: as sculpt and other paint modes are unified, this
|
2020-02-08 23:59:22 +01:00
|
|
|
* special mode of drawing will go away. */
|
2019-09-18 12:28:12 +02:00
|
|
|
Object *obact = vc.obact;
|
|
|
|
|
SculptSession *ss = obact ? obact->sculpt : NULL;
|
|
|
|
|
if ((mode == PAINT_MODE_SCULPT) && ss) {
|
|
|
|
|
float location[3];
|
|
|
|
|
int pixel_radius;
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Test if brush is over the mesh. */
|
2019-09-18 12:28:12 +02:00
|
|
|
bool hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
|
|
|
|
|
|
|
|
|
|
if (BKE_brush_use_locked_size(scene, brush)) {
|
|
|
|
|
BKE_brush_size_set(scene, brush, pixel_radius);
|
|
|
|
|
}
|
2019-08-30 16:27:31 +02:00
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Check if brush is subtracting, use different color then */
|
2019-09-18 12:28:12 +02:00
|
|
|
/* TODO: no way currently to know state of pen flip or
|
2020-02-08 23:59:22 +01:00
|
|
|
* invert key modifier without starting a stroke. */
|
2019-09-18 12:28:12 +02:00
|
|
|
if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
|
|
|
|
|
BKE_brush_sculpt_has_secondary_color(brush)) {
|
|
|
|
|
outline_col = brush->sub_col;
|
|
|
|
|
}
|
2019-08-30 16:27:31 +02:00
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Only do if brush is over the mesh. */
|
2019-09-18 12:28:12 +02:00
|
|
|
if (hit) {
|
|
|
|
|
paint_cursor_on_hit(ups, brush, &vc, location);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-30 16:27:31 +02:00
|
|
|
|
2019-09-18 12:28:12 +02:00
|
|
|
immUniformColor3fvAlpha(outline_col, outline_alpha);
|
2019-08-30 16:27:31 +02:00
|
|
|
|
2019-11-27 02:02:18 +01:00
|
|
|
if (ups->stroke_active && BKE_brush_use_size_pressure(brush) && mode != PAINT_MODE_SCULPT) {
|
2019-09-18 12:28:12 +02:00
|
|
|
imm_draw_circle_wire_3d(
|
|
|
|
|
pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Outer at half alpha. */
|
2019-09-18 12:28:12 +02:00
|
|
|
immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
|
2019-08-30 16:27:31 +02:00
|
|
|
}
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Only sculpt mode cursor for now. */
|
|
|
|
|
/* Disable for PBVH_GRIDS. */
|
2019-09-18 12:28:12 +02:00
|
|
|
bool is_multires = ss && ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS;
|
2019-09-23 23:06:11 +02:00
|
|
|
|
|
|
|
|
SculptCursorGeometryInfo gi;
|
2020-03-06 16:56:42 +01:00
|
|
|
float mouse[2] = {x - region->winrct.xmin, y - region->winrct.ymin};
|
2019-09-27 18:03:18 +02:00
|
|
|
int prev_active_vertex_index = -1;
|
2019-09-23 23:06:11 +02:00
|
|
|
bool is_cursor_over_mesh = false;
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Update the active vertex. */
|
2019-09-27 18:03:18 +02:00
|
|
|
if ((mode == PAINT_MODE_SCULPT) && ss && !ups->stroke_active) {
|
|
|
|
|
prev_active_vertex_index = ss->active_vertex_index;
|
2020-03-06 15:24:15 +01:00
|
|
|
is_cursor_over_mesh = SCULPT_cursor_geometry_info_update(
|
2019-10-15 09:54:41 +11:00
|
|
|
C, &gi, mouse, (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE));
|
2019-09-23 23:06:11 +02:00
|
|
|
}
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Use special paint crosshair cursor in all paint modes. */
|
2019-09-30 13:33:54 +02:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2019-09-30 16:38:40 -07:00
|
|
|
WM_cursor_set(win, WM_CURSOR_PAINT);
|
2019-09-23 23:06:11 +02:00
|
|
|
|
2019-10-15 09:54:41 +11:00
|
|
|
if ((mode == PAINT_MODE_SCULPT) && ss &&
|
|
|
|
|
(brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE)) {
|
2019-09-18 12:28:12 +02:00
|
|
|
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
|
2019-09-13 16:18:22 +02:00
|
|
|
|
2019-09-18 12:28:12 +02:00
|
|
|
if (!ups->stroke_active) {
|
|
|
|
|
bool update_previews = false;
|
2019-09-23 23:06:11 +02:00
|
|
|
if (is_cursor_over_mesh && !alpha_overlay_active) {
|
2019-08-30 16:27:31 +02:00
|
|
|
|
2019-09-18 12:28:12 +02:00
|
|
|
if (prev_active_vertex_index != ss->active_vertex_index) {
|
|
|
|
|
update_previews = true;
|
|
|
|
|
}
|
2019-08-30 16:27:31 +02:00
|
|
|
|
2019-09-18 12:28:12 +02:00
|
|
|
float rds;
|
|
|
|
|
if (!BKE_brush_use_locked_size(scene, brush)) {
|
|
|
|
|
rds = paint_calc_object_space_radius(
|
|
|
|
|
&vc, gi.location, BKE_brush_size_get(scene, brush));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
rds = BKE_brush_unprojected_radius_get(scene, brush);
|
|
|
|
|
}
|
2019-08-30 16:27:31 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
wmViewport(®ion->winrct);
|
2019-09-18 12:28:12 +02:00
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Draw 3D active vertex preview with symmetry. */
|
2019-09-18 12:28:12 +02:00
|
|
|
if (len_v3v3(gi.active_vertex_co, gi.location) < rds) {
|
2020-03-06 16:56:42 +01:00
|
|
|
cursor_draw_point_with_symmetry(pos, region, gi.active_vertex_co, sd, vc.obact, rds);
|
2019-09-13 16:18:22 +02:00
|
|
|
}
|
|
|
|
|
|
2020-01-07 16:46:56 +01:00
|
|
|
/* Draw pose brush origins. */
|
2019-09-30 16:33:04 +02:00
|
|
|
if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
|
2019-09-18 12:28:12 +02:00
|
|
|
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
|
2020-03-04 12:12:28 +01:00
|
|
|
|
|
|
|
|
/* Just after switching to the Pose Brush, the active vertex can be the same and the
|
|
|
|
|
* cursor won't be tagged to update, so always initialize the preview chain if it is
|
|
|
|
|
* null before drawing it. */
|
|
|
|
|
if (update_previews || !ss->pose_ik_chain_preview) {
|
Sculpt Vertex Colors: Initial implementation
Sculpt Vertex Colors is a painting system that runs inside sculpt mode, reusing all its tools and optimizations. This provides much better performance, easier to maintain code and more advanced features (new brush engine, filters, symmetry options, masks and face sets compatibility...). This is also the initial step for future features like vertex painting in Multires and brushes that can sculpt and paint at the same time.
This commit includes:
- SCULPT_UNDO_COLOR for undo support in sculpt mode
- SCULPT_UPDATE_COLOR and PBVH flags and rendering
- Sculpt Color API functions
- Sculpt capability for sculpt tools (only enabled in the Paint Brush for now)
- Rendering support in workbench (default to Sculpt Vertex Colors except in Vertex Paint)
- Conversion operator between MPropCol (Sculpt Vertex Colors) and MLoopCol (Vertex Paint)
- Remesher reprojection in the Voxel Remehser
- Paint Brush and Smear Brush with color smoothing in alt-smooth mode
- Parameters for the new brush engine (density, opacity, flow, wet paint mixing, tip scale) implemented in Sculpt Vertex Colors
- Color Filter
- Color picker (uses S shortcut, replaces smooth)
- Color selector in the top bar
Reviewed By: brecht
Maniphest Tasks: T72866
Differential Revision: https://developer.blender.org/D5975
2020-06-22 20:05:28 +02:00
|
|
|
BKE_sculpt_update_object_for_edit(depsgraph, vc.obact, true, false, false);
|
2020-01-07 16:46:56 +01:00
|
|
|
|
|
|
|
|
/* Free the previous pose brush preview. */
|
|
|
|
|
if (ss->pose_ik_chain_preview) {
|
2020-03-01 19:53:40 +01:00
|
|
|
SCULPT_pose_ik_chain_free(ss->pose_ik_chain_preview);
|
2020-01-07 16:46:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Generate a new pose brush preview from the current cursor location. */
|
2020-03-01 19:53:40 +01:00
|
|
|
ss->pose_ik_chain_preview = SCULPT_pose_ik_chain_init(
|
2020-01-07 16:46:56 +01:00
|
|
|
sd, vc.obact, ss, brush, gi.location, rds);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Draw the pose brush rotation origins. */
|
|
|
|
|
for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
|
|
|
|
|
cursor_draw_point_screen_space(pos,
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2020-01-07 16:46:56 +01:00
|
|
|
ss->pose_ik_chain_preview->segments[i].initial_orig,
|
|
|
|
|
vc.obact->obmat,
|
|
|
|
|
3);
|
2019-09-18 12:28:12 +02:00
|
|
|
}
|
2019-09-09 22:23:54 +02:00
|
|
|
}
|
2019-09-13 16:18:22 +02:00
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Draw 3D brush cursor. */
|
2019-09-18 12:28:12 +02:00
|
|
|
GPU_matrix_push_projection();
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
ED_view3d_draw_setup_view(wm,
|
|
|
|
|
CTX_wm_window(C),
|
2019-09-18 12:28:12 +02:00
|
|
|
CTX_data_depsgraph_pointer(C),
|
|
|
|
|
CTX_data_scene(C),
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2019-09-18 12:28:12 +02:00
|
|
|
CTX_wm_view3d(C),
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
float cursor_trans[4][4], cursor_rot[4][4];
|
|
|
|
|
float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
|
|
|
|
|
float quat[4];
|
|
|
|
|
|
|
|
|
|
copy_m4_m4(cursor_trans, vc.obact->obmat);
|
|
|
|
|
translate_m4(cursor_trans, gi.location[0], gi.location[1], gi.location[2]);
|
|
|
|
|
rotation_between_vecs_to_quat(quat, z_axis, gi.normal);
|
|
|
|
|
quat_to_mat4(cursor_rot, quat);
|
|
|
|
|
|
|
|
|
|
GPU_matrix_push();
|
|
|
|
|
GPU_matrix_mul(cursor_trans);
|
|
|
|
|
GPU_matrix_mul(cursor_rot);
|
|
|
|
|
immUniformColor3fvAlpha(outline_col, outline_alpha);
|
2019-09-26 17:51:21 +02:00
|
|
|
GPU_line_width(2.0f);
|
|
|
|
|
imm_draw_circle_wire_3d(pos, 0, 0, rds, 80);
|
2020-02-28 14:40:40 +01:00
|
|
|
|
2019-09-26 17:51:21 +02:00
|
|
|
GPU_line_width(1.0f);
|
|
|
|
|
immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
|
|
|
|
|
imm_draw_circle_wire_3d(pos, 0, 0, rds * clamp_f(brush->alpha, 0.0f, 1.0f), 80);
|
2019-09-18 12:28:12 +02:00
|
|
|
GPU_matrix_pop();
|
|
|
|
|
|
2020-02-28 14:40:40 +01:00
|
|
|
/* Cloth brush simulation areas. */
|
|
|
|
|
if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) {
|
|
|
|
|
GPU_matrix_push();
|
|
|
|
|
const float white[3] = {1.0f, 1.0f, 1.0f};
|
|
|
|
|
SCULPT_cloth_simulation_limits_draw(
|
|
|
|
|
pos, brush, vc.obact->obmat, gi.location, gi.normal, rds, 1.0f, white, 0.25f);
|
|
|
|
|
GPU_matrix_pop();
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-14 21:06:49 +02:00
|
|
|
/* Layer brush height. */
|
|
|
|
|
if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
|
|
|
|
|
GPU_matrix_push();
|
|
|
|
|
SCULPT_layer_brush_height_preview_draw(pos,
|
|
|
|
|
brush,
|
|
|
|
|
vc.obact->obmat,
|
|
|
|
|
gi.location,
|
|
|
|
|
gi.normal,
|
|
|
|
|
rds,
|
|
|
|
|
1.0f,
|
|
|
|
|
outline_col,
|
|
|
|
|
outline_alpha);
|
|
|
|
|
GPU_matrix_pop();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Update and draw dynamic mesh preview lines. */
|
2019-09-18 12:28:12 +02:00
|
|
|
GPU_matrix_push();
|
|
|
|
|
GPU_matrix_mul(vc.obact->obmat);
|
2019-10-01 14:38:25 +02:00
|
|
|
if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) &&
|
|
|
|
|
!is_multires) {
|
2019-10-07 17:27:56 +02:00
|
|
|
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->deform_modifiers_active) {
|
2020-03-06 15:24:15 +01:00
|
|
|
SCULPT_geometry_preview_lines_update(C, ss, rds);
|
2019-09-18 12:28:12 +02:00
|
|
|
sculpt_geometry_preview_lines_draw(pos, ss);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Draw pose brush line preview. */
|
2019-09-30 16:33:04 +02:00
|
|
|
if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
|
2019-09-18 12:28:12 +02:00
|
|
|
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
|
|
|
|
|
GPU_line_width(2.0f);
|
2020-01-07 16:46:56 +01:00
|
|
|
|
|
|
|
|
immBegin(GPU_PRIM_LINES, ss->pose_ik_chain_preview->tot_segments * 2);
|
|
|
|
|
for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
|
|
|
|
|
immVertex3fv(pos, ss->pose_ik_chain_preview->segments[i].initial_orig);
|
|
|
|
|
immVertex3fv(pos, ss->pose_ik_chain_preview->segments[i].initial_head);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-18 12:28:12 +02:00
|
|
|
immEnd();
|
|
|
|
|
}
|
2019-09-13 16:18:22 +02:00
|
|
|
|
2019-09-18 12:28:12 +02:00
|
|
|
GPU_matrix_pop();
|
2019-09-09 22:23:54 +02:00
|
|
|
|
2019-09-18 12:28:12 +02:00
|
|
|
GPU_matrix_pop_projection();
|
2019-08-30 16:27:31 +02:00
|
|
|
|
2019-09-18 12:28:12 +02:00
|
|
|
wmWindowViewport(win);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Draw default cursor when the mouse is not over the mesh or there are no supported
|
2020-02-08 23:59:22 +01:00
|
|
|
* overlays active. */
|
2019-09-18 12:28:12 +02:00
|
|
|
GPU_line_width(1.0f);
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Reduce alpha to increase the contrast when the cursor is over the mesh. */
|
2019-09-26 17:51:21 +02:00
|
|
|
immUniformColor3fvAlpha(outline_col, outline_alpha * 0.8);
|
|
|
|
|
imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 80);
|
|
|
|
|
immUniformColor3fvAlpha(outline_col, outline_alpha * 0.35f);
|
|
|
|
|
imm_draw_circle_wire_3d(pos,
|
|
|
|
|
translation[0],
|
|
|
|
|
translation[1],
|
|
|
|
|
final_radius * clamp_f(brush->alpha, 0.0f, 1.0f),
|
|
|
|
|
80);
|
2019-09-18 12:28:12 +02:00
|
|
|
}
|
2019-08-30 16:27:31 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2020-06-30 21:53:48 +02:00
|
|
|
if (vc.obact->sculpt->cache &&
|
|
|
|
|
!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(vc.obact->sculpt->cache)) {
|
2020-03-06 16:56:42 +01:00
|
|
|
wmViewport(®ion->winrct);
|
2019-09-18 12:28:12 +02:00
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Draw cached dynamic mesh preview lines. */
|
2019-10-01 14:38:25 +02:00
|
|
|
if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) &&
|
|
|
|
|
!is_multires) {
|
2019-10-07 17:27:56 +02:00
|
|
|
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->deform_modifiers_active) {
|
2019-09-18 12:28:12 +02:00
|
|
|
GPU_matrix_push_projection();
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
ED_view3d_draw_setup_view(wm,
|
|
|
|
|
CTX_wm_window(C),
|
2019-09-18 12:28:12 +02:00
|
|
|
CTX_data_depsgraph_pointer(C),
|
|
|
|
|
CTX_data_scene(C),
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2019-09-18 12:28:12 +02:00
|
|
|
CTX_wm_view3d(C),
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
|
|
|
|
GPU_matrix_push();
|
|
|
|
|
GPU_matrix_mul(vc.obact->obmat);
|
|
|
|
|
sculpt_geometry_preview_lines_draw(pos, ss);
|
|
|
|
|
GPU_matrix_pop();
|
|
|
|
|
GPU_matrix_pop_projection();
|
|
|
|
|
}
|
2019-09-09 22:23:54 +02:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 19:39:34 +01:00
|
|
|
if (brush->sculpt_tool == SCULPT_TOOL_MULTIPLANE_SCRAPE &&
|
2020-06-30 21:53:48 +02:00
|
|
|
brush->flag2 & BRUSH_MULTIPLANE_SCRAPE_PLANES_PREVIEW &&
|
|
|
|
|
!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
|
2019-11-06 19:39:34 +01:00
|
|
|
GPU_matrix_push_projection();
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
ED_view3d_draw_setup_view(wm,
|
|
|
|
|
CTX_wm_window(C),
|
2019-11-06 19:39:34 +01:00
|
|
|
CTX_data_depsgraph_pointer(C),
|
|
|
|
|
CTX_data_scene(C),
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2019-11-06 19:39:34 +01:00
|
|
|
CTX_wm_view3d(C),
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
|
|
|
|
GPU_matrix_push();
|
|
|
|
|
GPU_matrix_mul(vc.obact->obmat);
|
2020-03-06 16:00:33 +01:00
|
|
|
SCULPT_multiplane_scrape_preview_draw(pos, ss, outline_col, outline_alpha);
|
2019-11-06 19:39:34 +01:00
|
|
|
GPU_matrix_pop();
|
|
|
|
|
GPU_matrix_pop_projection();
|
2020-02-28 14:40:40 +01:00
|
|
|
}
|
|
|
|
|
|
2020-06-30 21:53:48 +02:00
|
|
|
if (brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
|
|
|
|
|
!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
|
2020-02-28 14:40:40 +01:00
|
|
|
GPU_matrix_push_projection();
|
VR: Initial Virtual Reality support - Milestone 1, Scene Inspection
NOTE: While most of the milestone 1 goals are there, a few smaller features and
improvements are still to be done.
Big picture of this milestone: Initial, OpenXR-based virtual reality support
for users and foundation for advanced use cases.
Maniphest Task: https://developer.blender.org/T71347
The tasks contains more information about this milestone.
To be clear: This is not a feature rich VR implementation, it's focused on the
initial scene inspection use case. We intentionally focused on that, further
features like controller support are part of the next milestone.
- How to use?
Instructions on how to use this are here:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/How_to_Test
These will be updated and moved to a more official place (likely the manual) soon.
Currently Windows Mixed Reality and Oculus devices are usable. Valve/HTC
headsets don't support the OpenXR standard yet and hence, do not work with this
implementation.
---------------
This is the C-side implementation of the features added for initial VR
support as per milestone 1. A "VR Scene Inspection" Add-on will be
committed separately, to expose the VR functionality in the UI. It also
adds some further features for milestone 1, namely a landmarking system
(stored view locations in the VR space)
Main additions/features:
* Support for rendering viewports to an HMD, with good performance.
* Option to sync the VR view perspective with a fully interactive,
regular 3D View (VR-Mirror).
* Option to disable positional tracking. Keeps the current position (calculated
based on the VR eye center pose) when enabled while a VR session is running.
* Some regular viewport settings for the VR view
* RNA/Python-API to query and set VR session state information.
* WM-XR: Layer tying Ghost-XR to the Blender specific APIs/data
* wmSurface API: drawable, non-window container (manages Ghost-OpenGL and GPU
context)
* DNA/RNA for management of VR session settings
* `--debug-xr` and `--debug-xr-time` commandline options
* Utility batch & config file for using the Oculus runtime on Windows.
* Most VR data is runtime only. The exception is user settings which are saved
to files (`XrSessionSettings`).
* VR support can be disabled through the `WITH_XR_OPENXR` compiler flag.
For architecture and code documentation, see
https://wiki.blender.org/wiki/Source/Interface/XR.
---------------
A few thank you's:
* A huge shoutout to Ray Molenkamp for his help during the project - it would
have not been that successful without him!
* Sebastian Koenig and Simeon Conzendorf for testing and feedback!
* The reviewers, especially Brecht Van Lommel!
* Dalai Felinto for pushing and managing me to get this done ;)
* The OpenXR working group for providing an open standard. I think we're the
first bigger application to adopt OpenXR. Congratulations to them and
ourselves :)
This project started as a Google Summer of Code 2019 project - "Core Support of
Virtual Reality Headsets through OpenXR" (see
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/).
Some further information, including ideas for further improvements can be found
in the final GSoC report:
https://wiki.blender.org/wiki/User:Severin/GSoC-2019/Final_Report
Differential Revisions: D6193, D7098
Reviewed by: Brecht Van Lommel, Jeroen Bakker
2020-03-17 20:20:55 +01:00
|
|
|
ED_view3d_draw_setup_view(CTX_wm_manager(C),
|
|
|
|
|
CTX_wm_window(C),
|
2020-02-28 14:40:40 +01:00
|
|
|
CTX_data_depsgraph_pointer(C),
|
|
|
|
|
CTX_data_scene(C),
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2020-02-28 14:40:40 +01:00
|
|
|
CTX_wm_view3d(C),
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
/* Plane falloff preview */
|
|
|
|
|
if (brush->cloth_force_falloff_type == BRUSH_CLOTH_FORCE_FALLOFF_PLANE) {
|
|
|
|
|
GPU_matrix_push();
|
|
|
|
|
GPU_matrix_mul(vc.obact->obmat);
|
|
|
|
|
SCULPT_cloth_plane_falloff_preview_draw(pos, ss, outline_col, outline_alpha);
|
|
|
|
|
GPU_matrix_pop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Display the simulation limits if sculpting outside them. */
|
|
|
|
|
/* This does not makes much sense of plane fallof as the fallof is infinte. */
|
|
|
|
|
else if (brush->cloth_force_falloff_type == BRUSH_CLOTH_FORCE_FALLOFF_RADIAL) {
|
|
|
|
|
if (len_v3v3(ss->cache->true_location, ss->cache->true_initial_location) >
|
|
|
|
|
ss->cache->radius * (1.0f + brush->cloth_sim_limit)) {
|
|
|
|
|
const float red[3] = {1.0f, 0.2f, 0.2f};
|
|
|
|
|
GPU_matrix_push();
|
|
|
|
|
SCULPT_cloth_simulation_limits_draw(pos,
|
|
|
|
|
brush,
|
|
|
|
|
vc.obact->obmat,
|
|
|
|
|
ss->cache->true_initial_location,
|
|
|
|
|
ss->cache->true_initial_normal,
|
|
|
|
|
ss->cache->radius,
|
|
|
|
|
2.0f,
|
|
|
|
|
red,
|
|
|
|
|
0.8f);
|
|
|
|
|
GPU_matrix_pop();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GPU_matrix_pop_projection();
|
2019-11-06 19:39:34 +01:00
|
|
|
}
|
|
|
|
|
|
2019-09-18 12:28:12 +02:00
|
|
|
wmWindowViewport(win);
|
|
|
|
|
}
|
2019-08-30 16:27:31 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-09-18 12:28:12 +02:00
|
|
|
else {
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Draw default cursor in unsupported modes. */
|
2019-09-18 12:28:12 +02:00
|
|
|
GPU_line_width(1.0f);
|
|
|
|
|
imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 40);
|
|
|
|
|
}
|
2019-08-30 16:27:31 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
|
immUnbindProgram();
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Restore GL state. */
|
2019-04-17 06:17:24 +02:00
|
|
|
GPU_blend(false);
|
|
|
|
|
GPU_line_smooth(false);
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Public API */
|
|
|
|
|
|
2020-06-04 20:17:05 +10:00
|
|
|
void paint_cursor_start(Paint *p, bool (*poll)(bContext *C))
|
2012-01-19 02:06:09 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (p && !p->paint_cursor) {
|
|
|
|
|
p->paint_cursor = WM_paint_cursor_activate(
|
2020-06-04 18:35:43 +10:00
|
|
|
SPACE_TYPE_ANY, RGN_TYPE_ANY, poll, paint_draw_cursor, NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2020-02-08 23:59:22 +01:00
|
|
|
/* Invalidate the paint cursors. */
|
2019-04-17 06:17:24 +02:00
|
|
|
BKE_paint_invalidate_overlay_all();
|
2012-01-19 02:06:09 +00:00
|
|
|
}
|